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/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/controller/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 bool isHiddenInputEnabled = false;
357 layoutEngine.LayoutText(layoutParameters,
361 isAutoScrollMaxTextureExceeded,
362 isHiddenInputEnabled,
367 float alignmentOffset = 0.f;
368 layoutEngine.Align(textArea,
371 Text::HorizontalAlignment::BEGIN,
374 Dali::LayoutDirection::LEFT_TO_RIGHT,
379 void ConfigureTextLabel(ControllerPtr controller)
381 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
382 fontClient.SetDpi(93u, 93u);
384 // Set the text layout as multi-line.
385 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
387 // Set cursor's width to zero.
388 controller->GetLayoutEngine().SetCursorWidth(0);
390 InputMethodContext inputMethodContext = InputMethodContext::New();
391 // Disables the text input.
392 controller->EnableTextInput(NULL, inputMethodContext);
394 // Disables the vertical scrolling.
395 controller->SetVerticalScrollEnabled(false);
397 // Disables the horizontal scrolling.
398 controller->SetHorizontalScrollEnabled(false);
400 // Enable the text elide.
401 controller->SetTextElideEnabled(true);
403 // Disable match system language direction
404 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
407 void ConfigureTextField(ControllerPtr controller)
409 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
410 fontClient.SetDpi(93u, 93u);
412 // Creates a decorator.
413 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
416 // Set the text layout as multi-line.
417 controller->GetLayoutEngine().SetLayout(Layout::Engine::SINGLE_LINE_BOX);
419 InputMethodContext inputMethodContext = InputMethodContext::New();
420 // Enables the text input.
421 controller->EnableTextInput(decorator, inputMethodContext);
423 // Enables the vertical scrolling after the text input has been enabled.
424 controller->SetVerticalScrollEnabled(false);
426 // Disables the horizontal scrolling.
427 controller->SetHorizontalScrollEnabled(true);
429 // No maximum number of characters.
430 controller->SetMaximumNumberOfCharacters(50u);
432 // Disable the text elide.
433 controller->SetTextElideEnabled(false);
435 // Disable match system language direction
436 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
439 void ConfigureTextEditor(ControllerPtr controller)
441 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
442 fontClient.SetDpi(93u, 93u);
444 // Creates a decorator.
445 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
448 // Set the text layout as multi-line.
449 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
451 InputMethodContext inputMethodContext = InputMethodContext::New();
452 // Enables the text input.
453 controller->EnableTextInput(decorator, inputMethodContext);
455 // Enables the vertical scrolling after the text input has been enabled.
456 controller->SetVerticalScrollEnabled(true);
458 // Disables the horizontal scrolling.
459 controller->SetHorizontalScrollEnabled(false);
461 // No maximum number of characters.
462 controller->SetMaximumNumberOfCharacters(std::numeric_limits<Length>::max());
464 // Disable the text elide.
465 controller->SetTextElideEnabled(false);
467 // Disable match system language direction
468 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
471 Vector<FontDescriptionRun> CreateSingleFontDescription(
472 const CharacterRun& characterRun,
473 const std::string fontFamilyName,
474 const FontWeight weight,
475 const FontWidth width,
476 const FontSlant slant,
477 const PointSize26Dot6 size,
478 const bool familyDefined,
479 const bool weightDefined,
480 const bool widthDefined,
481 const bool slantDefined,
482 const bool sizeDefined)
484 FontDescriptionRun fontDescriptionRun =
499 fontDescriptionRun.familyLength = fontFamilyName.size();
500 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
501 memcpy(fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength);
503 Vector<FontDescriptionRun> fontDescriptionRuns;
504 fontDescriptionRuns.PushBack(fontDescriptionRun);
506 return fontDescriptionRuns;
511 } // namespace Toolkit