2 * Copyright (c) 2018 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>
46 * @brief Frees previously allocated bidirectional resources.
48 * @param[in] bidirectionalLineInfo Bidirectional info per line.
49 * @param[in] index Index to the first line with bidirectional info to be freed.
51 void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
54 // Free the allocated memory used to store the conversion table in the bidirectional line info run.
55 for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
56 endIt = bidirectionalLineInfo.End();
60 BidirectionalLineInfoRun& bidiLineInfo = *it;
62 free( bidiLineInfo.visualToLogicalMap );
67 * @brief Clear all the model data except for LogicalModel::mText.
69 * @param[in] characterIndex Clear data starting from the index.
71 void ClearModelData( CharacterIndex characterIndex,
72 LogicalModelPtr logicalModel,
73 VisualModelPtr visualModel )
75 // n.b. This does not Clear the mText from mLogicalModel
77 // Frees previously allocated resources.
78 FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
80 logicalModel->mScriptRuns.Clear();
81 logicalModel->mFontRuns.Clear();
82 logicalModel->mWordBreakInfo.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,
102 LogicalModelPtr& logicalModel,
103 VisualModelPtr& visualModel,
105 bool markupProcessorEnabled )
107 logicalModel = LogicalModel::New();
108 visualModel = VisualModel::New();
110 MarkupProcessData markupProcessData( logicalModel->mColorRuns,
111 logicalModel->mFontDescriptionRuns,
112 logicalModel->mEmbeddedItems );
114 Length textSize = 0u;
115 const uint8_t* utf8 = NULL;
116 if( markupProcessorEnabled )
118 ProcessMarkupString( text, markupProcessData );
119 textSize = markupProcessData.markupProcessedText.size();
121 // This is a bit horrible but std::string returns a (signed) char*
122 utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
126 textSize = text.size();
128 // This is a bit horrible but std::string returns a (signed) char*
129 utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
132 // 1) Convert to utf32
133 Vector<Character>& utf32Characters = logicalModel->mText;
134 utf32Characters.Resize( textSize );
136 // Transform a text array encoded in utf8 into an array encoded in utf32.
137 // It returns the actual number of characters.
138 Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
139 utf32Characters.Resize( characterCount );
141 // 2) Set the break and paragraph info.
142 Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
143 lineBreakInfo.Resize( characterCount );
145 SetLineBreakInfo( utf32Characters,
150 if( 0u == characterCount )
152 // Nothing else to do if the number of characters is zero.
156 // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
157 Vector<WordBreakInfo>& wordBreakInfo = logicalModel->mWordBreakInfo;
158 wordBreakInfo.Resize( characterCount );
160 SetWordBreakInfo( utf32Characters,
165 // 3) Set the script info.
166 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
168 Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
169 multilanguageSupport.SetScripts( utf32Characters,
174 // 4) Set the font info
175 Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
176 fontDescriptionRuns = fontDescriptions;
177 Vector<FontRun>& validFonts = logicalModel->mFontRuns;
179 // The default font description.
180 TextAbstraction::FontDescription fontDescription;
182 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
183 fontClient.SetDpi( 96u, 96u );
185 // Validates the fonts. If there is a character with no assigned font it sets a default one.
186 // After this call, fonts are validated.
187 multilanguageSupport.ValidateFonts( utf32Characters,
191 TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
196 // 5) Set the bidirectional info per paragraph.
197 Vector<Character> mirroredUtf32Characters;
198 bool textMirrored = false;
200 // Reserve some space for the vector of paragraph's bidirectional info.
201 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
203 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
204 SetBidirectionalInfo( utf32Characters,
211 // Create the paragraph info.
212 logicalModel->CreateParagraphInfo( 0u,
215 // 6) Set character directions.
216 Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
217 if( 0u != bidirectionalInfo.Count() )
219 // Only set the character directions if there is right to left characters.
220 GetCharactersDirection( bidirectionalInfo,
224 characterDirections );
227 // This paragraph has right to left text. Some characters may need to be mirrored.
228 textMirrored = GetMirroredText( utf32Characters,
233 mirroredUtf32Characters );
237 // There is no right to left characters. Clear the directions vector.
238 characterDirections.Clear();
241 // 7) Shape the text.
243 Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
244 Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
245 Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
246 Vector<GlyphIndex> newParagraphGlyphs;
248 const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
250 ShapeText( textToShape,
258 glyphsToCharactersMap,
260 newParagraphGlyphs );
262 // Create the 'number of glyphs' per character and the glyph to character conversion tables.
263 visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, characterCount );
264 visualModel->CreateCharacterToGlyphTable( 0u, 0u, characterCount );
266 const Length numberOfGlyphs = glyphs.Count();
268 // 8) Get the glyph metrics
269 metrics = Metrics::New( fontClient );
271 GlyphInfo* glyphsBuffer = glyphs.Begin();
272 metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
274 // Update the width and advance of all new paragraph characters.
275 for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
276 endIt = newParagraphGlyphs.End();
280 const GlyphIndex index = *it;
281 GlyphInfo& glyph = *( glyphsBuffer + index );
283 glyph.xBearing = 0.f;
288 // 9) Layout the text
289 Layout::Engine layoutEngine;
290 layoutEngine.SetMetrics( metrics );
291 layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
293 // Set the layout parameters.
294 const Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
295 const Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
296 float outlineWidth = visualModel->GetOutlineWidth();
297 Layout::Parameters layoutParameters( textArea,
298 utf32Characters.Begin(),
299 lineBreakInfo.Begin(),
300 wordBreakInfo.Begin(),
301 ( 0u != characterDirections.Count() ) ? characterDirections.Begin() : NULL,
303 glyphsToCharactersMap.Begin(),
304 charactersPerGlyph.Begin(),
305 charactersToGlyph.Begin(),
306 glyphsPerCharacter.Begin(),
308 Text::HorizontalAlignment::BEGIN,
309 Text::LineWrap::WORD,
314 Vector<LineRun>& lines = visualModel->mLines;
316 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
317 glyphPositions.Resize( numberOfGlyphs );
319 layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
321 // The initial glyph and the number of glyphs to layout.
322 layoutParameters.startGlyphIndex = 0u;
323 layoutParameters.numberOfGlyphs = numberOfGlyphs;
324 layoutParameters.startLineIndex = 0u;
325 layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
327 bool isAutoScroll = false;
328 layoutEngine.LayoutText( layoutParameters,
335 // 10) Reorder the lines
336 if( 0u != bidirectionalInfo.Count() )
338 Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = logicalModel->mBidirectionalLineInfo;
341 const Length numberOfLines = lines.Count();
343 // Reorder the lines.
344 bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
345 ReorderLines( bidirectionalInfo,
349 bidirectionalLineInfo );
351 // Set the bidirectional info per line into the layout parameters.
352 layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
353 layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
355 if( options.reorder )
357 // Re-layout the text. Reorder those lines with right to left characters.
358 layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
367 float alignmentOffset = 0.f;
368 layoutEngine.Align( textArea,
371 Text::HorizontalAlignment::BEGIN,
374 Dali::LayoutDirection::LEFT_TO_RIGHT,
379 void ConfigureTextLabel( ControllerPtr controller )
381 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
382 fontClient.SetDpi( 93u, 93u );
384 // Set the text layout as multi-line.
385 controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
387 // Set cursor's width to zero.
388 controller->GetLayoutEngine().SetCursorWidth( 0 );
390 InputMethodContext inputMethodContext = InputMethodContext::New();
391 // Disables the text input.
392 controller->EnableTextInput( NULL, inputMethodContext );
394 // Disables the vertical scrolling.
395 controller->SetVerticalScrollEnabled( false );
397 // Disables the horizontal scrolling.
398 controller->SetHorizontalScrollEnabled( false );
400 // Enable the text elide.
401 controller->SetTextElideEnabled( true );
404 void ConfigureTextField( ControllerPtr controller )
406 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
407 fontClient.SetDpi( 93u, 93u );
409 // Creates a decorator.
410 Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
413 // Set the text layout as multi-line.
414 controller->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
416 InputMethodContext inputMethodContext = InputMethodContext::New();
417 // Enables the text input.
418 controller->EnableTextInput( decorator, inputMethodContext );
420 // Enables the vertical scrolling after the text input has been enabled.
421 controller->SetVerticalScrollEnabled( false );
423 // Disables the horizontal scrolling.
424 controller->SetHorizontalScrollEnabled( true );
426 // No maximum number of characters.
427 controller->SetMaximumNumberOfCharacters( 50u );
429 // Disable the text elide.
430 controller->SetTextElideEnabled( false );
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 );
464 } // namespace Toolkit