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,
110 textModel = Model::New(); ///< Pointer to the text's model.
111 LogicalModelPtr logicalModel = textModel->mLogicalModel;
112 VisualModelPtr visualModel = textModel->mVisualModel;
114 MarkupProcessData markupProcessData( logicalModel->mColorRuns,
115 logicalModel->mFontDescriptionRuns,
116 logicalModel->mEmbeddedItems,
117 logicalModel->mAnchors,
118 logicalModel->mUnderlinedCharacterRuns,
119 logicalModel->mBackgroundColorRuns);
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 );
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,
299 newParagraphGlyphs );
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 const Length numberOfGlyphs = glyphs.Count();
307 // 8) Get the glyph metrics
308 metrics = Metrics::New( fontClient );
310 GlyphInfo* glyphsBuffer = glyphs.Begin();
311 metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
313 // Update the width and advance of all new paragraph characters.
314 for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
315 endIt = newParagraphGlyphs.End();
319 const GlyphIndex index = *it;
320 GlyphInfo& glyph = *( glyphsBuffer + index );
322 glyph.xBearing = 0.f;
327 // 9) Layout the text
328 Layout::Engine layoutEngine;
329 layoutEngine.SetMetrics( metrics );
330 layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
331 layoutEngine.SetDefaultLineSpacing(lineSpacing);
333 // Set the layout parameters.
334 textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
335 textModel->mIgnoreSpacesAfterText = true;
336 Layout::Parameters layoutParameters( textArea,
339 Vector<LineRun>& lines = visualModel->mLines;
341 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
342 glyphPositions.Resize( numberOfGlyphs );
344 layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
346 // The initial glyph and the number of glyphs to layout.
347 layoutParameters.startGlyphIndex = 0u;
348 layoutParameters.numberOfGlyphs = numberOfGlyphs;
349 layoutParameters.startLineIndex = 0u;
350 layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
352 bool isAutoScroll = false;
353 layoutEngine.LayoutText( layoutParameters,
361 float alignmentOffset = 0.f;
362 layoutEngine.Align( textArea,
365 Text::HorizontalAlignment::BEGIN,
368 Dali::LayoutDirection::LEFT_TO_RIGHT,
373 void ConfigureTextLabel( ControllerPtr controller )
375 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
376 fontClient.SetDpi( 93u, 93u );
378 // Set the text layout as multi-line.
379 controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
381 // Set cursor's width to zero.
382 controller->GetLayoutEngine().SetCursorWidth( 0 );
384 InputMethodContext inputMethodContext = InputMethodContext::New();
385 // Disables the text input.
386 controller->EnableTextInput( NULL, inputMethodContext );
388 // Disables the vertical scrolling.
389 controller->SetVerticalScrollEnabled( false );
391 // Disables the horizontal scrolling.
392 controller->SetHorizontalScrollEnabled( false );
394 // Enable the text elide.
395 controller->SetTextElideEnabled( true );
397 // Disable match system language direction
398 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
401 void ConfigureTextField( ControllerPtr controller )
403 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
404 fontClient.SetDpi( 93u, 93u );
406 // Creates a decorator.
407 Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
410 // Set the text layout as multi-line.
411 controller->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
413 InputMethodContext inputMethodContext = InputMethodContext::New();
414 // Enables the text input.
415 controller->EnableTextInput( decorator, inputMethodContext );
417 // Enables the vertical scrolling after the text input has been enabled.
418 controller->SetVerticalScrollEnabled( false );
420 // Disables the horizontal scrolling.
421 controller->SetHorizontalScrollEnabled( true );
423 // No maximum number of characters.
424 controller->SetMaximumNumberOfCharacters( 50u );
426 // Disable the text elide.
427 controller->SetTextElideEnabled( false );
429 // Disable match system language direction
430 controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
433 void ConfigureTextEditor( ControllerPtr controller )
435 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
436 fontClient.SetDpi( 93u, 93u );
438 // Creates a decorator.
439 Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
442 // Set the text layout as multi-line.
443 controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
445 InputMethodContext inputMethodContext = InputMethodContext::New();
446 // Enables the text input.
447 controller->EnableTextInput( decorator, inputMethodContext );
449 // Enables the vertical scrolling after the text input has been enabled.
450 controller->SetVerticalScrollEnabled( true );
452 // Disables the horizontal scrolling.
453 controller->SetHorizontalScrollEnabled( false );
455 // No maximum number of characters.
456 controller->SetMaximumNumberOfCharacters( std::numeric_limits<Length>::max() );
458 // Disable the text elide.
459 controller->SetTextElideEnabled( false );
461 // Disable match system language direction
462 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)
480 FontDescriptionRun fontDescriptionRun =
496 fontDescriptionRun.familyLength = fontFamilyName.size();
497 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
498 memcpy( fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength );
500 Vector<FontDescriptionRun> fontDescriptionRuns;
501 fontDescriptionRuns.PushBack(fontDescriptionRun);
503 return fontDescriptionRuns;
508 } // namespace Toolkit