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);
121 Length textSize = 0u;
122 const uint8_t* utf8 = NULL;
123 if(markupProcessorEnabled)
125 ProcessMarkupString(text, markupProcessData);
126 textSize = markupProcessData.markupProcessedText.size();
128 // This is a bit horrible but std::string returns a (signed) char*
129 utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
133 textSize = text.size();
135 // This is a bit horrible but std::string returns a (signed) char*
136 utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
140 textModel->mElideEnabled = ellipsisEnabled;
141 textModel->mVisualModel->SetTextElideEnabled(ellipsisEnabled);
142 textModel->mEllipsisPosition = ellipsisPosition;
143 textModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
145 // 1) Convert to utf32
146 Vector<Character>& utf32Characters = logicalModel->mText;
147 utf32Characters.Resize(textSize);
149 // Transform a text array encoded in utf8 into an array encoded in utf32.
150 // It returns the actual number of characters.
151 Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
152 utf32Characters.Resize(characterCount);
154 // 2) Set the break and paragraph info.
155 Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
156 lineBreakInfo.Resize(characterCount);
158 SetLineBreakInfo(utf32Characters,
163 if(0u == characterCount)
165 // Nothing else to do if the number of characters is zero.
169 textModel->mLineWrapMode = wrapMode;
171 if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
172 textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
174 CharacterIndex end = characterCount;
175 LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
177 for(CharacterIndex index = 0; index < end; index++)
179 CharacterIndex wordEnd = index;
180 while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
185 if((wordEnd + 1) == end) // add last char
190 Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
192 for(CharacterIndex i = 0; i < (wordEnd - index); i++)
196 *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
204 // 3) Set the script info.
205 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
207 Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
208 multilanguageSupport.SetScripts(utf32Characters,
213 // 4) Set the font info
214 Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
215 fontDescriptionRuns = fontDescriptions;
216 Vector<FontRun>& validFonts = logicalModel->mFontRuns;
218 // The default font description.
219 TextAbstraction::FontDescription fontDescription;
221 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
222 fontClient.SetDpi(96u, 96u);
224 // Validates the fonts. If there is a character with no assigned font it sets a default one.
225 // After this call, fonts are validated.
226 multilanguageSupport.ValidateFonts(utf32Characters,
230 TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
235 // 5) Set the bidirectional info per paragraph.
236 Vector<Character> mirroredUtf32Characters;
237 bool textMirrored = false;
239 // Reserve some space for the vector of paragraph's bidirectional info.
240 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
242 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
243 SetBidirectionalInfo(utf32Characters,
250 // Create the paragraph info.
251 logicalModel->CreateParagraphInfo(0u,
254 // 6) Set character directions.
255 Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
256 if(0u != bidirectionalInfo.Count())
258 // Only set the character directions if there is right to left characters.
259 GetCharactersDirection(bidirectionalInfo,
263 characterDirections);
265 // This paragraph has right to left text. Some characters may need to be mirrored.
266 textMirrored = GetMirroredText(utf32Characters,
271 mirroredUtf32Characters);
275 // There is no right to left characters. Clear the directions vector.
276 characterDirections.Clear();
279 // 7) Shape the text.
281 Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
282 Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
283 Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
284 Vector<GlyphIndex> newParagraphGlyphs;
286 const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
288 ShapeText(textToShape,
296 glyphsToCharactersMap,
300 // Create the 'number of glyphs' per character and the glyph to character conversion tables.
301 visualModel->CreateGlyphsPerCharacterTable(0u, 0u, characterCount);
302 visualModel->CreateCharacterToGlyphTable(0u, 0u, characterCount);
304 visualModel->SetCharacterSpacing(characterSpacing);
306 const Length numberOfGlyphs = glyphs.Count();
308 // 8) Get the glyph metrics
309 metrics = Metrics::New(fontClient);
311 GlyphInfo* glyphsBuffer = glyphs.Begin();
312 metrics->GetGlyphMetrics(glyphsBuffer, numberOfGlyphs);
314 // Update the width and advance of all new paragraph characters.
315 for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
316 endIt = newParagraphGlyphs.End();
320 const GlyphIndex index = *it;
321 GlyphInfo& glyph = *(glyphsBuffer + index);
323 glyph.xBearing = 0.f;
328 // 9) Layout the text
329 Layout::Engine layoutEngine;
330 layoutEngine.SetMetrics(metrics);
331 layoutEngine.SetLayout(Layout::Engine::MULTI_LINE_BOX);
332 layoutEngine.SetDefaultLineSpacing(lineSpacing);
334 // Set the layout parameters.
335 textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
336 textModel->mIgnoreSpacesAfterText = true;
337 Layout::Parameters layoutParameters(textArea,
340 Vector<LineRun>& lines = visualModel->mLines;
342 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
343 glyphPositions.Resize(numberOfGlyphs);
345 layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph(*(utf32Characters.Begin() + (characterCount - 1u)));
347 // The initial glyph and the number of glyphs to layout.
348 layoutParameters.startGlyphIndex = 0u;
349 layoutParameters.numberOfGlyphs = numberOfGlyphs;
350 layoutParameters.startLineIndex = 0u;
351 layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
353 bool isAutoScroll = false;
354 layoutEngine.LayoutText(layoutParameters,
362 float alignmentOffset = 0.f;
363 layoutEngine.Align(textArea,
366 Text::HorizontalAlignment::BEGIN,
369 Dali::LayoutDirection::LEFT_TO_RIGHT,
374 void ConfigureTextLabel(ControllerPtr controller)
376 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
377 fontClient.SetDpi(93u, 93u);
379 // Set the text layout as multi-line.
380 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
382 // Set cursor's width to zero.
383 controller->GetLayoutEngine().SetCursorWidth(0);
385 InputMethodContext inputMethodContext = InputMethodContext::New();
386 // Disables the text input.
387 controller->EnableTextInput(NULL, inputMethodContext);
389 // Disables the vertical scrolling.
390 controller->SetVerticalScrollEnabled(false);
392 // Disables the horizontal scrolling.
393 controller->SetHorizontalScrollEnabled(false);
395 // Enable the text elide.
396 controller->SetTextElideEnabled(true);
398 // Disable match system language direction
399 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
402 void ConfigureTextField(ControllerPtr controller)
404 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
405 fontClient.SetDpi(93u, 93u);
407 // Creates a decorator.
408 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
411 // Set the text layout as multi-line.
412 controller->GetLayoutEngine().SetLayout(Layout::Engine::SINGLE_LINE_BOX);
414 InputMethodContext inputMethodContext = InputMethodContext::New();
415 // Enables the text input.
416 controller->EnableTextInput(decorator, inputMethodContext);
418 // Enables the vertical scrolling after the text input has been enabled.
419 controller->SetVerticalScrollEnabled(false);
421 // Disables the horizontal scrolling.
422 controller->SetHorizontalScrollEnabled(true);
424 // No maximum number of characters.
425 controller->SetMaximumNumberOfCharacters(50u);
427 // Disable the text elide.
428 controller->SetTextElideEnabled(false);
430 // Disable match system language direction
431 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
434 void ConfigureTextEditor(ControllerPtr controller)
436 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
437 fontClient.SetDpi(93u, 93u);
439 // Creates a decorator.
440 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
443 // Set the text layout as multi-line.
444 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
446 InputMethodContext inputMethodContext = InputMethodContext::New();
447 // Enables the text input.
448 controller->EnableTextInput(decorator, inputMethodContext);
450 // Enables the vertical scrolling after the text input has been enabled.
451 controller->SetVerticalScrollEnabled(true);
453 // Disables the horizontal scrolling.
454 controller->SetHorizontalScrollEnabled(false);
456 // No maximum number of characters.
457 controller->SetMaximumNumberOfCharacters(std::numeric_limits<Length>::max());
459 // Disable the text elide.
460 controller->SetTextElideEnabled(false);
462 // Disable match system language direction
463 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
466 Vector<FontDescriptionRun> CreateSingleFontDescription(
467 const CharacterRun& characterRun,
468 const std::string fontFamilyName,
469 const FontWeight weight,
470 const FontWidth width,
471 const FontSlant slant,
472 const PointSize26Dot6 size,
473 const bool familyDefined,
474 const bool weightDefined,
475 const bool widthDefined,
476 const bool slantDefined,
477 const bool sizeDefined)
479 FontDescriptionRun fontDescriptionRun =
494 fontDescriptionRun.familyLength = fontFamilyName.size();
495 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
496 memcpy(fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength);
498 Vector<FontDescriptionRun> fontDescriptionRuns;
499 fontDescriptionRuns.PushBack(fontDescriptionRun);
501 return fontDescriptionRuns;
506 } // namespace Toolkit