2 * Copyright (c) 2023 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>
24 #include <cstring> ///< for memcpy
27 #include <dali-toolkit/internal/text/bidirectional-support.h>
28 #include <dali-toolkit/internal/text/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/hyphenator.h>
30 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/markup-processor/markup-processor.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/segmentation.h>
35 #include <dali-toolkit/internal/text/shaper.h>
36 #include <dali-toolkit/internal/text/controller/text-controller-impl.h>
45 * @brief Frees previously allocated bidirectional resources.
47 * @param[in] bidirectionalLineInfo Bidirectional info per line.
48 * @param[in] index Index to the first line with bidirectional info to be freed.
50 void FreeBidirectionalLineInfoResources(Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
53 // Free the allocated memory used to store the conversion table in the bidirectional line info run.
54 for(Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
55 endIt = bidirectionalLineInfo.End();
59 BidirectionalLineInfoRun& bidiLineInfo = *it;
61 free(bidiLineInfo.visualToLogicalMap);
66 * @brief Clear all the model data except for LogicalModel::mText.
68 * @param[in] characterIndex Clear data starting from the index.
70 void ClearModelData(CharacterIndex characterIndex,
71 LogicalModelPtr logicalModel,
72 VisualModelPtr visualModel)
74 // n.b. This does not Clear the mText from mLogicalModel
76 // Frees previously allocated resources.
77 FreeBidirectionalLineInfoResources(logicalModel->mBidirectionalLineInfo, 0u);
79 logicalModel->mScriptRuns.Clear();
80 logicalModel->mFontRuns.Clear();
81 logicalModel->mBidirectionalParagraphInfo.Clear();
82 logicalModel->mCharacterDirections.Clear();
83 logicalModel->mBidirectionalLineInfo.Clear();
84 visualModel->mGlyphs.Clear();
85 visualModel->mGlyphsToCharacters.Clear();
86 visualModel->mCharactersToGlyph.Clear();
87 visualModel->mCharactersPerGlyph.Clear();
88 visualModel->mGlyphsPerCharacter.Clear();
89 visualModel->mGlyphPositions.Clear();
90 visualModel->mLines.Clear();
92 visualModel->ClearCaches();
95 void CreateTextModel(const std::string& text,
97 const Vector<FontDescriptionRun>& fontDescriptions,
98 const LayoutOptions& options,
102 bool markupProcessorEnabled,
103 LineWrap::Mode wrapMode,
104 bool ellipsisEnabled,
105 DevelText::EllipsisPosition::Type ellipsisPosition,
107 float characterSpacing)
109 textModel = Model::New(); ///< Pointer to the text's model.
110 LogicalModelPtr logicalModel = textModel->mLogicalModel;
111 VisualModelPtr visualModel = textModel->mVisualModel;
113 MarkupProcessData markupProcessData(logicalModel->mColorRuns,
114 logicalModel->mFontDescriptionRuns,
115 logicalModel->mEmbeddedItems,
116 logicalModel->mAnchors,
117 logicalModel->mUnderlinedCharacterRuns,
118 logicalModel->mBackgroundColorRuns,
119 logicalModel->mStrikethroughCharacterRuns,
120 logicalModel->mBoundedParagraphRuns,
121 logicalModel->mCharacterSpacingCharacterRuns);
123 Length textSize = 0u;
124 const uint8_t* utf8 = NULL;
125 if(markupProcessorEnabled)
127 ProcessMarkupString(text, markupProcessData);
128 textSize = markupProcessData.markupProcessedText.size();
130 // This is a bit horrible but std::string returns a (signed) char*
131 utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
135 textSize = text.size();
137 // This is a bit horrible but std::string returns a (signed) char*
138 utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
142 textModel->mElideEnabled = ellipsisEnabled;
143 textModel->mVisualModel->SetTextElideEnabled(ellipsisEnabled);
144 textModel->mEllipsisPosition = ellipsisPosition;
145 textModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
147 // 1) Convert to utf32
148 Vector<Character>& utf32Characters = logicalModel->mText;
149 utf32Characters.Resize(textSize);
151 // Transform a text array encoded in utf8 into an array encoded in utf32.
152 // It returns the actual number of characters.
153 Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
154 utf32Characters.Resize(characterCount);
156 // 2) Set the break and paragraph info.
157 Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
158 lineBreakInfo.Resize(characterCount);
160 SetLineBreakInfo(utf32Characters,
165 if(0u == characterCount)
167 // Nothing else to do if the number of characters is zero.
171 textModel->mLineWrapMode = wrapMode;
173 if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
174 textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
176 CharacterIndex end = characterCount;
177 LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
179 for(CharacterIndex index = 0; index < end; index++)
181 CharacterIndex wordEnd = index;
182 while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
187 if((wordEnd + 1) == end) // add last char
192 Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
194 for(CharacterIndex i = 0; i < (wordEnd - index); i++)
198 *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
206 // 3) Set the script info.
207 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
209 Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
210 multilanguageSupport.SetScripts(utf32Characters,
215 // 4) Set the font info
216 Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
217 fontDescriptionRuns = fontDescriptions;
218 Vector<FontRun>& validFonts = logicalModel->mFontRuns;
220 // The default font description.
221 TextAbstraction::FontDescription fontDescription;
223 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
224 fontClient.SetDpi(96u, 96u);
226 // Validates the fonts. If there is a character with no assigned font it sets a default one.
227 // After this call, fonts are validated.
228 multilanguageSupport.ValidateFonts(utf32Characters,
232 TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
238 // 5) Set the bidirectional info per paragraph.
239 Vector<Character> mirroredUtf32Characters;
240 bool textMirrored = false;
242 // Reserve some space for the vector of paragraph's bidirectional info.
243 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
245 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
246 SetBidirectionalInfo(utf32Characters,
253 // Create the paragraph info.
254 logicalModel->CreateParagraphInfo(0u,
257 // 6) Set character directions.
258 Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
259 if(0u != bidirectionalInfo.Count())
261 // Only set the character directions if there is right to left characters.
262 GetCharactersDirection(bidirectionalInfo,
266 characterDirections);
268 // This paragraph has right to left text. Some characters may need to be mirrored.
269 textMirrored = GetMirroredText(utf32Characters,
274 mirroredUtf32Characters);
278 // There is no right to left characters. Clear the directions vector.
279 characterDirections.Clear();
282 // 7) Shape the text.
284 Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
285 Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
286 Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
287 Vector<GlyphIndex> newParagraphGlyphs;
289 const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
291 ShapeText(textToShape,
299 glyphsToCharactersMap,
303 // Create the 'number of glyphs' per character and the glyph to character conversion tables.
304 visualModel->CreateGlyphsPerCharacterTable(0u, 0u, characterCount);
305 visualModel->CreateCharacterToGlyphTable(0u, 0u, characterCount);
307 visualModel->SetCharacterSpacing(characterSpacing);
309 const Length numberOfGlyphs = glyphs.Count();
311 // 8) Get the glyph metrics
312 metrics = Metrics::New(fontClient);
314 GlyphInfo* glyphsBuffer = glyphs.Begin();
315 metrics->GetGlyphMetrics(glyphsBuffer, numberOfGlyphs);
317 // Update the width and advance of all new paragraph characters.
318 for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
319 endIt = newParagraphGlyphs.End();
323 const GlyphIndex index = *it;
324 GlyphInfo& glyph = *(glyphsBuffer + index);
326 glyph.xBearing = 0.f;
331 // 9) Layout the text
332 Layout::Engine layoutEngine;
333 layoutEngine.SetMetrics(metrics);
334 layoutEngine.SetLayout(Layout::Engine::MULTI_LINE_BOX);
335 layoutEngine.SetDefaultLineSpacing(lineSpacing);
337 // Set the layout parameters.
338 textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
339 textModel->mIgnoreSpacesAfterText = true;
340 Layout::Parameters layoutParameters(textArea,
343 Vector<LineRun>& lines = visualModel->mLines;
345 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
346 glyphPositions.Resize(numberOfGlyphs);
348 layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph(*(utf32Characters.Begin() + (characterCount - 1u)));
350 // The initial glyph and the number of glyphs to layout.
351 layoutParameters.startGlyphIndex = 0u;
352 layoutParameters.numberOfGlyphs = numberOfGlyphs;
353 layoutParameters.startLineIndex = 0u;
354 layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
356 bool isAutoScroll = false;
357 bool isAutoScrollMaxTextureExceeded = false;
358 bool isHiddenInputEnabled = false;
359 layoutEngine.LayoutText(layoutParameters,
363 isAutoScrollMaxTextureExceeded,
364 isHiddenInputEnabled,
369 float alignmentOffset = 0.f;
370 layoutEngine.Align(textArea,
373 Text::HorizontalAlignment::BEGIN,
376 Dali::LayoutDirection::LEFT_TO_RIGHT,
381 void ConfigureTextLabel(ControllerPtr controller)
383 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
384 fontClient.SetDpi(93u, 93u);
386 // Set the text layout as multi-line.
387 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
389 // Set cursor's width to zero.
390 controller->GetLayoutEngine().SetCursorWidth(0);
392 InputMethodContext inputMethodContext = InputMethodContext::New();
393 // Disables the text input.
394 controller->EnableTextInput(NULL, inputMethodContext);
396 // Disables the vertical scrolling.
397 controller->SetVerticalScrollEnabled(false);
399 // Disables the horizontal scrolling.
400 controller->SetHorizontalScrollEnabled(false);
402 // Enable the text elide.
403 controller->SetTextElideEnabled(true);
405 // Disable match system language direction
406 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
409 void ConfigureTextField(ControllerPtr controller)
411 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
412 fontClient.SetDpi(93u, 93u);
414 // Creates a decorator.
415 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
418 // Set the text layout as multi-line.
419 controller->GetLayoutEngine().SetLayout(Layout::Engine::SINGLE_LINE_BOX);
421 InputMethodContext inputMethodContext = InputMethodContext::New();
422 // Enables the text input.
423 controller->EnableTextInput(decorator, inputMethodContext);
425 // Enables the vertical scrolling after the text input has been enabled.
426 controller->SetVerticalScrollEnabled(false);
428 // Disables the horizontal scrolling.
429 controller->SetHorizontalScrollEnabled(true);
431 // No maximum number of characters.
432 controller->SetMaximumNumberOfCharacters(50u);
434 // Disable the text elide.
435 controller->SetTextElideEnabled(false);
437 // Disable match system language direction
438 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
441 void ConfigureTextEditor(ControllerPtr controller)
443 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
444 fontClient.SetDpi(93u, 93u);
446 // Creates a decorator.
447 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
450 // Set the text layout as multi-line.
451 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
453 InputMethodContext inputMethodContext = InputMethodContext::New();
454 // Enables the text input.
455 controller->EnableTextInput(decorator, inputMethodContext);
457 // Enables the vertical scrolling after the text input has been enabled.
458 controller->SetVerticalScrollEnabled(true);
460 // Disables the horizontal scrolling.
461 controller->SetHorizontalScrollEnabled(false);
463 // No maximum number of characters.
464 controller->SetMaximumNumberOfCharacters(std::numeric_limits<Length>::max());
466 // Disable the text elide.
467 controller->SetTextElideEnabled(false);
469 // Disable match system language direction
470 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
473 Vector<FontDescriptionRun> CreateSingleFontDescription(
474 const CharacterRun& characterRun,
475 const std::string fontFamilyName,
476 const FontWeight weight,
477 const FontWidth width,
478 const FontSlant slant,
479 const PointSize26Dot6 size,
480 const bool familyDefined,
481 const bool weightDefined,
482 const bool widthDefined,
483 const bool slantDefined,
484 const bool sizeDefined)
486 FontDescriptionRun fontDescriptionRun =
501 fontDescriptionRun.familyLength = fontFamilyName.size();
502 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
503 memcpy(fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength);
505 Vector<FontDescriptionRun> fontDescriptionRuns;
506 fontDescriptionRuns.PushBack(fontDescriptionRun);
508 return fontDescriptionRuns;
513 } // namespace Toolkit