2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "toolkit-text-utils.h"
22 #include <dali/devel-api/text-abstraction/font-client.h>
26 #include <dali-toolkit/internal/text/bidirectional-support.h>
27 #include <dali-toolkit/internal/text/character-set-conversion.h>
28 #include <dali-toolkit/internal/text/hyphenator.h>
29 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
30 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
31 #include <dali-toolkit/internal/text/markup-processor.h>
32 #include <dali-toolkit/internal/text/multi-language-support.h>
33 #include <dali-toolkit/internal/text/segmentation.h>
34 #include <dali-toolkit/internal/text/shaper.h>
35 #include <dali-toolkit/internal/text/text-controller-impl.h>
44 * @brief Frees previously allocated bidirectional resources.
46 * @param[in] bidirectionalLineInfo Bidirectional info per line.
47 * @param[in] index Index to the first line with bidirectional info to be freed.
49 void FreeBidirectionalLineInfoResources(Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
52 // Free the allocated memory used to store the conversion table in the bidirectional line info run.
53 for(Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
54 endIt = bidirectionalLineInfo.End();
58 BidirectionalLineInfoRun& bidiLineInfo = *it;
60 free(bidiLineInfo.visualToLogicalMap);
65 * @brief Clear all the model data except for LogicalModel::mText.
67 * @param[in] characterIndex Clear data starting from the index.
69 void ClearModelData(CharacterIndex characterIndex,
70 LogicalModelPtr logicalModel,
71 VisualModelPtr visualModel)
73 // n.b. This does not Clear the mText from mLogicalModel
75 // Frees previously allocated resources.
76 FreeBidirectionalLineInfoResources(logicalModel->mBidirectionalLineInfo, 0u);
78 logicalModel->mScriptRuns.Clear();
79 logicalModel->mFontRuns.Clear();
80 logicalModel->mBidirectionalParagraphInfo.Clear();
81 logicalModel->mCharacterDirections.Clear();
82 logicalModel->mBidirectionalLineInfo.Clear();
83 visualModel->mGlyphs.Clear();
84 visualModel->mGlyphsToCharacters.Clear();
85 visualModel->mCharactersToGlyph.Clear();
86 visualModel->mCharactersPerGlyph.Clear();
87 visualModel->mGlyphsPerCharacter.Clear();
88 visualModel->mGlyphPositions.Clear();
89 visualModel->mLines.Clear();
91 visualModel->ClearCaches();
94 void CreateTextModel(const std::string& text,
96 const Vector<FontDescriptionRun>& fontDescriptions,
97 const LayoutOptions& options,
101 bool markupProcessorEnabled,
102 LineWrap::Mode wrapMode,
103 bool ellipsisEnabled,
104 DevelText::EllipsisPosition::Type ellipsisPosition,
106 float characterSpacing)
108 textModel = Model::New(); ///< Pointer to the text's model.
109 LogicalModelPtr logicalModel = textModel->mLogicalModel;
110 VisualModelPtr visualModel = textModel->mVisualModel;
112 MarkupProcessData markupProcessData(logicalModel->mColorRuns,
113 logicalModel->mFontDescriptionRuns,
114 logicalModel->mEmbeddedItems,
115 logicalModel->mAnchors,
116 logicalModel->mUnderlinedCharacterRuns,
117 logicalModel->mBackgroundColorRuns,
118 logicalModel->mStrikethroughCharacterRuns,
119 logicalModel->mBoundedParagraphRuns,
120 logicalModel->mCharacterSpacingCharacterRuns);
122 Length textSize = 0u;
123 const uint8_t* utf8 = NULL;
124 if(markupProcessorEnabled)
126 ProcessMarkupString(text, markupProcessData);
127 textSize = markupProcessData.markupProcessedText.size();
129 // This is a bit horrible but std::string returns a (signed) char*
130 utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
134 textSize = text.size();
136 // This is a bit horrible but std::string returns a (signed) char*
137 utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
141 textModel->mElideEnabled = ellipsisEnabled;
142 textModel->mVisualModel->SetTextElideEnabled(ellipsisEnabled);
143 textModel->mEllipsisPosition = ellipsisPosition;
144 textModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
146 // 1) Convert to utf32
147 Vector<Character>& utf32Characters = logicalModel->mText;
148 utf32Characters.Resize(textSize);
150 // Transform a text array encoded in utf8 into an array encoded in utf32.
151 // It returns the actual number of characters.
152 Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
153 utf32Characters.Resize(characterCount);
155 // 2) Set the break and paragraph info.
156 Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
157 lineBreakInfo.Resize(characterCount);
159 SetLineBreakInfo(utf32Characters,
164 if(0u == characterCount)
166 // Nothing else to do if the number of characters is zero.
170 textModel->mLineWrapMode = wrapMode;
172 if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
173 textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
175 CharacterIndex end = characterCount;
176 LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
178 for(CharacterIndex index = 0; index < end; index++)
180 CharacterIndex wordEnd = index;
181 while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
186 if((wordEnd + 1) == end) // add last char
191 Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
193 for(CharacterIndex i = 0; i < (wordEnd - index); i++)
197 *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
205 // 3) Set the script info.
206 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
208 Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
209 multilanguageSupport.SetScripts(utf32Characters,
214 // 4) Set the font info
215 Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
216 fontDescriptionRuns = fontDescriptions;
217 Vector<FontRun>& validFonts = logicalModel->mFontRuns;
219 // The default font description.
220 TextAbstraction::FontDescription fontDescription;
222 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
223 fontClient.SetDpi(96u, 96u);
225 // Validates the fonts. If there is a character with no assigned font it sets a default one.
226 // After this call, fonts are validated.
227 multilanguageSupport.ValidateFonts(utf32Characters,
231 TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
236 // 5) Set the bidirectional info per paragraph.
237 Vector<Character> mirroredUtf32Characters;
238 bool textMirrored = false;
240 // Reserve some space for the vector of paragraph's bidirectional info.
241 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
243 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
244 SetBidirectionalInfo(utf32Characters,
251 // Create the paragraph info.
252 logicalModel->CreateParagraphInfo(0u,
255 // 6) Set character directions.
256 Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
257 if(0u != bidirectionalInfo.Count())
259 // Only set the character directions if there is right to left characters.
260 GetCharactersDirection(bidirectionalInfo,
264 characterDirections);
266 // This paragraph has right to left text. Some characters may need to be mirrored.
267 textMirrored = GetMirroredText(utf32Characters,
272 mirroredUtf32Characters);
276 // There is no right to left characters. Clear the directions vector.
277 characterDirections.Clear();
280 // 7) Shape the text.
282 Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
283 Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
284 Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
285 Vector<GlyphIndex> newParagraphGlyphs;
287 const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
289 ShapeText(textToShape,
297 glyphsToCharactersMap,
301 // Create the 'number of glyphs' per character and the glyph to character conversion tables.
302 visualModel->CreateGlyphsPerCharacterTable(0u, 0u, characterCount);
303 visualModel->CreateCharacterToGlyphTable(0u, 0u, characterCount);
305 visualModel->SetCharacterSpacing(characterSpacing);
307 const Length numberOfGlyphs = glyphs.Count();
309 // 8) Get the glyph metrics
310 metrics = Metrics::New(fontClient);
312 GlyphInfo* glyphsBuffer = glyphs.Begin();
313 metrics->GetGlyphMetrics(glyphsBuffer, numberOfGlyphs);
315 // Update the width and advance of all new paragraph characters.
316 for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
317 endIt = newParagraphGlyphs.End();
321 const GlyphIndex index = *it;
322 GlyphInfo& glyph = *(glyphsBuffer + index);
324 glyph.xBearing = 0.f;
329 // 9) Layout the text
330 Layout::Engine layoutEngine;
331 layoutEngine.SetMetrics(metrics);
332 layoutEngine.SetLayout(Layout::Engine::MULTI_LINE_BOX);
333 layoutEngine.SetDefaultLineSpacing(lineSpacing);
335 // Set the layout parameters.
336 textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
337 textModel->mIgnoreSpacesAfterText = true;
338 Layout::Parameters layoutParameters(textArea,
341 Vector<LineRun>& lines = visualModel->mLines;
343 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
344 glyphPositions.Resize(numberOfGlyphs);
346 layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph(*(utf32Characters.Begin() + (characterCount - 1u)));
348 // The initial glyph and the number of glyphs to layout.
349 layoutParameters.startGlyphIndex = 0u;
350 layoutParameters.numberOfGlyphs = numberOfGlyphs;
351 layoutParameters.startLineIndex = 0u;
352 layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
354 bool isAutoScroll = false;
355 bool isAutoScrollMaxTextureExceeded = false;
356 layoutEngine.LayoutText(layoutParameters,
360 isAutoScrollMaxTextureExceeded,
365 float alignmentOffset = 0.f;
366 layoutEngine.Align(textArea,
369 Text::HorizontalAlignment::BEGIN,
372 Dali::LayoutDirection::LEFT_TO_RIGHT,
377 void ConfigureTextLabel(ControllerPtr controller)
379 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
380 fontClient.SetDpi(93u, 93u);
382 // Set the text layout as multi-line.
383 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
385 // Set cursor's width to zero.
386 controller->GetLayoutEngine().SetCursorWidth(0);
388 InputMethodContext inputMethodContext = InputMethodContext::New();
389 // Disables the text input.
390 controller->EnableTextInput(NULL, inputMethodContext);
392 // Disables the vertical scrolling.
393 controller->SetVerticalScrollEnabled(false);
395 // Disables the horizontal scrolling.
396 controller->SetHorizontalScrollEnabled(false);
398 // Enable the text elide.
399 controller->SetTextElideEnabled(true);
401 // Disable match system language direction
402 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
405 void ConfigureTextField(ControllerPtr controller)
407 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
408 fontClient.SetDpi(93u, 93u);
410 // Creates a decorator.
411 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
414 // Set the text layout as multi-line.
415 controller->GetLayoutEngine().SetLayout(Layout::Engine::SINGLE_LINE_BOX);
417 InputMethodContext inputMethodContext = InputMethodContext::New();
418 // Enables the text input.
419 controller->EnableTextInput(decorator, inputMethodContext);
421 // Enables the vertical scrolling after the text input has been enabled.
422 controller->SetVerticalScrollEnabled(false);
424 // Disables the horizontal scrolling.
425 controller->SetHorizontalScrollEnabled(true);
427 // No maximum number of characters.
428 controller->SetMaximumNumberOfCharacters(50u);
430 // Disable the text elide.
431 controller->SetTextElideEnabled(false);
433 // Disable match system language direction
434 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
437 void ConfigureTextEditor(ControllerPtr controller)
439 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
440 fontClient.SetDpi(93u, 93u);
442 // Creates a decorator.
443 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
446 // Set the text layout as multi-line.
447 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
449 InputMethodContext inputMethodContext = InputMethodContext::New();
450 // Enables the text input.
451 controller->EnableTextInput(decorator, inputMethodContext);
453 // Enables the vertical scrolling after the text input has been enabled.
454 controller->SetVerticalScrollEnabled(true);
456 // Disables the horizontal scrolling.
457 controller->SetHorizontalScrollEnabled(false);
459 // No maximum number of characters.
460 controller->SetMaximumNumberOfCharacters(std::numeric_limits<Length>::max());
462 // Disable the text elide.
463 controller->SetTextElideEnabled(false);
465 // Disable match system language direction
466 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
469 Vector<FontDescriptionRun> CreateSingleFontDescription(
470 const CharacterRun& characterRun,
471 const std::string fontFamilyName,
472 const FontWeight weight,
473 const FontWidth width,
474 const FontSlant slant,
475 const PointSize26Dot6 size,
476 const bool familyDefined,
477 const bool weightDefined,
478 const bool widthDefined,
479 const bool slantDefined,
480 const bool sizeDefined)
482 FontDescriptionRun fontDescriptionRun =
497 fontDescriptionRun.familyLength = fontFamilyName.size();
498 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
499 memcpy(fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength);
501 Vector<FontDescriptionRun> fontDescriptionRuns;
502 fontDescriptionRuns.PushBack(fontDescriptionRun);
504 return fontDescriptionRuns;
509 } // namespace Toolkit