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);
464 Vector<FontDescriptionRun> CreateSingleFontDescription(
465 const CharacterRun& characterRun,
466 const std::string fontFamilyName,
467 const FontWeight weight,
468 const FontWidth width,
469 const FontSlant slant,
470 const PointSize26Dot6 size,
471 const bool familyDefined,
472 const bool weightDefined,
473 const bool widthDefined,
474 const bool slantDefined,
475 const bool sizeDefined)
478 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