2 * Copyright (c) 2021 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"
23 #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/layouts/layout-engine.h>
29 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
30 #include <dali-toolkit/internal/text/multi-language-support.h>
31 #include <dali-toolkit/internal/text/segmentation.h>
32 #include <dali-toolkit/internal/text/shaper.h>
33 #include <dali-toolkit/internal/text/text-controller-impl.h>
34 #include <dali-toolkit/internal/text/markup-processor.h>
35 #include <dali-toolkit/internal/text/hyphenator.h>
47 * @brief Frees previously allocated bidirectional resources.
49 * @param[in] bidirectionalLineInfo Bidirectional info per line.
50 * @param[in] index Index to the first line with bidirectional info to be freed.
52 void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
55 // Free the allocated memory used to store the conversion table in the bidirectional line info run.
56 for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
57 endIt = bidirectionalLineInfo.End();
61 BidirectionalLineInfoRun& bidiLineInfo = *it;
63 free( bidiLineInfo.visualToLogicalMap );
68 * @brief Clear all the model data except for LogicalModel::mText.
70 * @param[in] characterIndex Clear data starting from the index.
72 void ClearModelData( CharacterIndex characterIndex,
73 LogicalModelPtr logicalModel,
74 VisualModelPtr visualModel )
76 // n.b. This does not Clear the mText from mLogicalModel
78 // Frees previously allocated resources.
79 FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
81 logicalModel->mScriptRuns.Clear();
82 logicalModel->mFontRuns.Clear();
83 logicalModel->mBidirectionalParagraphInfo.Clear();
84 logicalModel->mCharacterDirections.Clear();
85 logicalModel->mBidirectionalLineInfo.Clear();
86 visualModel->mGlyphs.Clear();
87 visualModel->mGlyphsToCharacters.Clear();
88 visualModel->mCharactersToGlyph.Clear();
89 visualModel->mCharactersPerGlyph.Clear();
90 visualModel->mGlyphsPerCharacter.Clear();
91 visualModel->mGlyphPositions.Clear();
92 visualModel->mLines.Clear();
94 visualModel->ClearCaches();
97 void CreateTextModel( const std::string& text,
99 const Vector<FontDescriptionRun>& fontDescriptions,
100 const LayoutOptions& options,
104 bool markupProcessorEnabled,
105 LineWrap::Mode wrapMode,
106 bool ellipsisEnabled,
107 DevelText::EllipsisPosition::Type ellipsisPosition)
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);
120 Length textSize = 0u;
121 const uint8_t* utf8 = NULL;
122 if( markupProcessorEnabled )
124 ProcessMarkupString( text, markupProcessData );
125 textSize = markupProcessData.markupProcessedText.size();
127 // This is a bit horrible but std::string returns a (signed) char*
128 utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
132 textSize = text.size();
134 // This is a bit horrible but std::string returns a (signed) char*
135 utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
139 textModel-> mElideEnabled = ellipsisEnabled;
140 textModel-> mVisualModel->SetTextElideEnabled(ellipsisEnabled);
141 textModel-> mEllipsisPosition = ellipsisPosition;
142 textModel-> mVisualModel->SetEllipsisPosition(ellipsisPosition);
144 // 1) Convert to utf32
145 Vector<Character>& utf32Characters = logicalModel->mText;
146 utf32Characters.Resize( textSize );
148 // Transform a text array encoded in utf8 into an array encoded in utf32.
149 // It returns the actual number of characters.
150 Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
151 utf32Characters.Resize( characterCount );
153 // 2) Set the break and paragraph info.
154 Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
155 lineBreakInfo.Resize( characterCount );
157 SetLineBreakInfo( utf32Characters,
162 if( 0u == characterCount )
164 // Nothing else to do if the number of characters is zero.
168 textModel->mLineWrapMode = wrapMode;
170 if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
171 textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
173 CharacterIndex end = characterCount;
174 LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
176 for(CharacterIndex index = 0; index < end; index++)
178 CharacterIndex wordEnd = index;
179 while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
184 if((wordEnd + 1) == end) // add last char
189 Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
191 for(CharacterIndex i = 0; i < (wordEnd - index); i++)
195 *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
203 // 3) Set the script info.
204 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
206 Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
207 multilanguageSupport.SetScripts( utf32Characters,
212 // 4) Set the font info
213 Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
214 fontDescriptionRuns = fontDescriptions;
215 Vector<FontRun>& validFonts = logicalModel->mFontRuns;
217 // The default font description.
218 TextAbstraction::FontDescription fontDescription;
220 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
221 fontClient.SetDpi( 96u, 96u );
223 // Validates the fonts. If there is a character with no assigned font it sets a default one.
224 // After this call, fonts are validated.
225 multilanguageSupport.ValidateFonts( utf32Characters,
229 TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
234 // 5) Set the bidirectional info per paragraph.
235 Vector<Character> mirroredUtf32Characters;
236 bool textMirrored = false;
238 // Reserve some space for the vector of paragraph's bidirectional info.
239 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
241 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
242 SetBidirectionalInfo( utf32Characters,
249 // Create the paragraph info.
250 logicalModel->CreateParagraphInfo( 0u,
253 // 6) Set character directions.
254 Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
255 if( 0u != bidirectionalInfo.Count() )
257 // Only set the character directions if there is right to left characters.
258 GetCharactersDirection( bidirectionalInfo,
262 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,
298 newParagraphGlyphs );
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 const Length numberOfGlyphs = glyphs.Count();
306 // 8) Get the glyph metrics
307 metrics = Metrics::New( fontClient );
309 GlyphInfo* glyphsBuffer = glyphs.Begin();
310 metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
312 // Update the width and advance of all new paragraph characters.
313 for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
314 endIt = newParagraphGlyphs.End();
318 const GlyphIndex index = *it;
319 GlyphInfo& glyph = *( glyphsBuffer + index );
321 glyph.xBearing = 0.f;
326 // 9) Layout the text
327 Layout::Engine layoutEngine;
328 layoutEngine.SetMetrics( metrics );
329 layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
331 // Set the layout parameters.
332 textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
333 textModel->mIgnoreSpacesAfterText = true;
334 Layout::Parameters layoutParameters( textArea,
337 Vector<LineRun>& lines = visualModel->mLines;
339 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
340 glyphPositions.Resize( numberOfGlyphs );
342 layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
344 // The initial glyph and the number of glyphs to layout.
345 layoutParameters.startGlyphIndex = 0u;
346 layoutParameters.numberOfGlyphs = numberOfGlyphs;
347 layoutParameters.startLineIndex = 0u;
348 layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
350 bool isAutoScroll = false;
351 layoutEngine.LayoutText( layoutParameters,
359 float alignmentOffset = 0.f;
360 layoutEngine.Align( textArea,
363 Text::HorizontalAlignment::BEGIN,
366 Dali::LayoutDirection::LEFT_TO_RIGHT,
371 void ConfigureTextLabel( ControllerPtr controller )
373 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
374 fontClient.SetDpi( 93u, 93u );
376 // Set the text layout as multi-line.
377 controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
379 // Set cursor's width to zero.
380 controller->GetLayoutEngine().SetCursorWidth( 0 );
382 InputMethodContext inputMethodContext = InputMethodContext::New();
383 // Disables the text input.
384 controller->EnableTextInput( NULL, inputMethodContext );
386 // Disables the vertical scrolling.
387 controller->SetVerticalScrollEnabled( false );
389 // Disables the horizontal scrolling.
390 controller->SetHorizontalScrollEnabled( false );
392 // Enable the text elide.
393 controller->SetTextElideEnabled( true );
395 // Disable match system language direction
396 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
399 void ConfigureTextField( ControllerPtr controller )
401 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
402 fontClient.SetDpi( 93u, 93u );
404 // Creates a decorator.
405 Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
408 // Set the text layout as multi-line.
409 controller->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
411 InputMethodContext inputMethodContext = InputMethodContext::New();
412 // Enables the text input.
413 controller->EnableTextInput( decorator, inputMethodContext );
415 // Enables the vertical scrolling after the text input has been enabled.
416 controller->SetVerticalScrollEnabled( false );
418 // Disables the horizontal scrolling.
419 controller->SetHorizontalScrollEnabled( true );
421 // No maximum number of characters.
422 controller->SetMaximumNumberOfCharacters( 50u );
424 // Disable the text elide.
425 controller->SetTextElideEnabled( false );
427 // Disable match system language direction
428 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
431 void ConfigureTextEditor( ControllerPtr controller )
433 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
434 fontClient.SetDpi( 93u, 93u );
436 // Creates a decorator.
437 Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
440 // Set the text layout as multi-line.
441 controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
443 InputMethodContext inputMethodContext = InputMethodContext::New();
444 // Enables the text input.
445 controller->EnableTextInput( decorator, inputMethodContext );
447 // Enables the vertical scrolling after the text input has been enabled.
448 controller->SetVerticalScrollEnabled( true );
450 // Disables the horizontal scrolling.
451 controller->SetHorizontalScrollEnabled( false );
453 // No maximum number of characters.
454 controller->SetMaximumNumberOfCharacters( std::numeric_limits<Length>::max() );
456 // Disable the text elide.
457 controller->SetTextElideEnabled( false );
459 // Disable match system language direction
460 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
465 } // namespace Toolkit