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 layoutEngine.LayoutText(layoutParameters,
363 float alignmentOffset = 0.f;
364 layoutEngine.Align(textArea,
367 Text::HorizontalAlignment::BEGIN,
370 Dali::LayoutDirection::LEFT_TO_RIGHT,
375 void ConfigureTextLabel(ControllerPtr controller)
377 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
378 fontClient.SetDpi(93u, 93u);
380 // Set the text layout as multi-line.
381 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
383 // Set cursor's width to zero.
384 controller->GetLayoutEngine().SetCursorWidth(0);
386 InputMethodContext inputMethodContext = InputMethodContext::New();
387 // Disables the text input.
388 controller->EnableTextInput(NULL, inputMethodContext);
390 // Disables the vertical scrolling.
391 controller->SetVerticalScrollEnabled(false);
393 // Disables the horizontal scrolling.
394 controller->SetHorizontalScrollEnabled(false);
396 // Enable the text elide.
397 controller->SetTextElideEnabled(true);
399 // Disable match system language direction
400 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
403 void ConfigureTextField(ControllerPtr controller)
405 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
406 fontClient.SetDpi(93u, 93u);
408 // Creates a decorator.
409 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
412 // Set the text layout as multi-line.
413 controller->GetLayoutEngine().SetLayout(Layout::Engine::SINGLE_LINE_BOX);
415 InputMethodContext inputMethodContext = InputMethodContext::New();
416 // Enables the text input.
417 controller->EnableTextInput(decorator, inputMethodContext);
419 // Enables the vertical scrolling after the text input has been enabled.
420 controller->SetVerticalScrollEnabled(false);
422 // Disables the horizontal scrolling.
423 controller->SetHorizontalScrollEnabled(true);
425 // No maximum number of characters.
426 controller->SetMaximumNumberOfCharacters(50u);
428 // Disable the text elide.
429 controller->SetTextElideEnabled(false);
431 // Disable match system language direction
432 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
435 void ConfigureTextEditor(ControllerPtr controller)
437 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
438 fontClient.SetDpi(93u, 93u);
440 // Creates a decorator.
441 Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
444 // Set the text layout as multi-line.
445 controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
447 InputMethodContext inputMethodContext = InputMethodContext::New();
448 // Enables the text input.
449 controller->EnableTextInput(decorator, inputMethodContext);
451 // Enables the vertical scrolling after the text input has been enabled.
452 controller->SetVerticalScrollEnabled(true);
454 // Disables the horizontal scrolling.
455 controller->SetHorizontalScrollEnabled(false);
457 // No maximum number of characters.
458 controller->SetMaximumNumberOfCharacters(std::numeric_limits<Length>::max());
460 // Disable the text elide.
461 controller->SetTextElideEnabled(false);
463 // Disable match system language direction
464 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
467 Vector<FontDescriptionRun> CreateSingleFontDescription(
468 const CharacterRun& characterRun,
469 const std::string fontFamilyName,
470 const FontWeight weight,
471 const FontWidth width,
472 const FontSlant slant,
473 const PointSize26Dot6 size,
474 const bool familyDefined,
475 const bool weightDefined,
476 const bool widthDefined,
477 const bool slantDefined,
478 const bool sizeDefined)
480 FontDescriptionRun fontDescriptionRun =
495 fontDescriptionRun.familyLength = fontFamilyName.size();
496 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
497 memcpy(fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength);
499 Vector<FontDescriptionRun> fontDescriptionRuns;
500 fontDescriptionRuns.PushBack(fontDescriptionRun);
502 return fontDescriptionRuns;
507 } // namespace Toolkit