Add a callback to get textfitted font size.
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / dali-toolkit-test-utils / toolkit-text-utils.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // FILE HEADER
19 #include "toolkit-text-utils.h"
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <dali/devel-api/text-abstraction/font-client.h>
24
25 // INTERNAL INCLUDES
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>
36
37 namespace Dali
38 {
39
40 namespace Toolkit
41 {
42
43 namespace Text
44 {
45
46 /**
47  * @brief Frees previously allocated bidirectional resources.
48  *
49  * @param[in] bidirectionalLineInfo Bidirectional info per line.
50  * @param[in] index Index to the first line with bidirectional info to be freed.
51  */
52 void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
53                                          uint32_t index )
54 {
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();
58        it != endIt;
59        ++it )
60   {
61     BidirectionalLineInfoRun& bidiLineInfo = *it;
62
63     free( bidiLineInfo.visualToLogicalMap );
64   }
65 }
66
67 /**
68  * @brief Clear all the model data except for LogicalModel::mText.
69  *
70  * @param[in] characterIndex Clear data starting from the index.
71  */
72 void ClearModelData( CharacterIndex characterIndex,
73                      LogicalModelPtr logicalModel,
74                      VisualModelPtr visualModel )
75 {
76   // n.b. This does not Clear the mText from mLogicalModel
77
78   // Frees previously allocated resources.
79   FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
80
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();
93
94   visualModel->ClearCaches();
95 }
96
97 void CreateTextModel( const std::string& text,
98                       const Size& textArea,
99                       const Vector<FontDescriptionRun>& fontDescriptions,
100                       const LayoutOptions& options,
101                       Size& layoutSize,
102                       ModelPtr& textModel,
103                       MetricsPtr& metrics,
104                       bool markupProcessorEnabled,
105                       LineWrap::Mode wrapMode,
106                       bool ellipsisEnabled,
107                       DevelText::EllipsisPosition::Type ellipsisPosition)
108 {
109   textModel = Model::New(); ///< Pointer to the text's model.
110   LogicalModelPtr logicalModel = textModel->mLogicalModel;
111   VisualModelPtr visualModel = textModel->mVisualModel;
112
113   MarkupProcessData markupProcessData( logicalModel->mColorRuns,
114                                        logicalModel->mFontDescriptionRuns,
115                                        logicalModel->mEmbeddedItems,
116                                        logicalModel->mAnchors,
117                                        logicalModel->mUnderlinedCharacterRuns,
118                                        logicalModel->mBackgroundColorRuns);
119
120   Length textSize = 0u;
121   const uint8_t* utf8 = NULL;
122   if( markupProcessorEnabled )
123   {
124     ProcessMarkupString( text, markupProcessData );
125     textSize = markupProcessData.markupProcessedText.size();
126
127     // This is a bit horrible but std::string returns a (signed) char*
128     utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
129   }
130   else
131   {
132     textSize = text.size();
133
134     // This is a bit horrible but std::string returns a (signed) char*
135     utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
136   }
137
138   //Ellipsis
139   textModel-> mElideEnabled = ellipsisEnabled;
140   textModel-> mVisualModel->SetTextElideEnabled(ellipsisEnabled);
141   textModel-> mEllipsisPosition = ellipsisPosition;
142   textModel-> mVisualModel->SetEllipsisPosition(ellipsisPosition);
143
144   // 1) Convert to utf32
145   Vector<Character>& utf32Characters = logicalModel->mText;
146   utf32Characters.Resize( textSize );
147
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 );
152
153   // 2) Set the break and paragraph info.
154   Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
155   lineBreakInfo.Resize( characterCount );
156
157   SetLineBreakInfo( utf32Characters,
158                     0u,
159                     characterCount,
160                     lineBreakInfo );
161
162   if( 0u == characterCount )
163   {
164     // Nothing else to do if the number of characters is zero.
165     return;
166   }
167
168   textModel->mLineWrapMode = wrapMode;
169
170   if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
171        textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
172   {
173     CharacterIndex end                 = characterCount;
174     LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
175
176     for(CharacterIndex index = 0; index < end; index++)
177     {
178       CharacterIndex wordEnd = index;
179       while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
180       {
181         wordEnd++;
182       }
183
184       if((wordEnd + 1) == end) // add last char
185       {
186         wordEnd++;
187       }
188
189       Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
190
191       for(CharacterIndex i = 0; i < (wordEnd - index); i++)
192       {
193         if(hyphens[i])
194         {
195           *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
196         }
197       }
198
199       index = wordEnd;
200     }
201   }
202
203   // 3) Set the script info.
204   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
205
206   Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
207   multilanguageSupport.SetScripts( utf32Characters,
208                                    0u,
209                                    characterCount,
210                                    scripts );
211
212   // 4) Set the font info
213   Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
214   fontDescriptionRuns = fontDescriptions;
215   Vector<FontRun>& validFonts = logicalModel->mFontRuns;
216
217   // The default font description.
218   TextAbstraction::FontDescription fontDescription;
219
220   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
221   fontClient.SetDpi( 96u, 96u );
222
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,
226                                       scripts,
227                                       fontDescriptionRuns,
228                                       fontDescription,
229                                       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
230                                       0u,
231                                       characterCount,
232                                       validFonts );
233
234   // 5) Set the bidirectional info per paragraph.
235   Vector<Character> mirroredUtf32Characters;
236   bool textMirrored = false;
237
238   // Reserve some space for the vector of paragraph's bidirectional info.
239   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
240
241   // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
242   SetBidirectionalInfo( utf32Characters,
243                         scripts,
244                         lineBreakInfo,
245                         0u,
246                         characterCount,
247                         bidirectionalInfo );
248
249   // Create the paragraph info.
250   logicalModel->CreateParagraphInfo( 0u,
251                                      characterCount );
252
253   // 6) Set character directions.
254   Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
255   if( 0u != bidirectionalInfo.Count() )
256   {
257     // Only set the character directions if there is right to left characters.
258     GetCharactersDirection( bidirectionalInfo,
259                             characterCount,
260                             0u,
261                             characterCount,
262                             characterDirections );
263
264
265     // This paragraph has right to left text. Some characters may need to be mirrored.
266     textMirrored = GetMirroredText( utf32Characters,
267                                     characterDirections,
268                                     bidirectionalInfo,
269                                     0u,
270                                     characterCount,
271                                     mirroredUtf32Characters );
272   }
273   else
274   {
275     // There is no right to left characters. Clear the directions vector.
276     characterDirections.Clear();
277   }
278
279   // 7) Shape the text.
280
281   Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
282   Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
283   Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
284   Vector<GlyphIndex> newParagraphGlyphs;
285
286   const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
287
288   ShapeText( textToShape,
289              lineBreakInfo,
290              scripts,
291              validFonts,
292              0u,
293              0u,
294              characterCount,
295              glyphs,
296              glyphsToCharactersMap,
297              charactersPerGlyph,
298              newParagraphGlyphs );
299
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 );
303
304   const Length numberOfGlyphs = glyphs.Count();
305
306   // 8) Get the glyph metrics
307   metrics = Metrics::New( fontClient );
308
309   GlyphInfo* glyphsBuffer = glyphs.Begin();
310   metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
311
312   // Update the width and advance of all new paragraph characters.
313   for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
314          endIt = newParagraphGlyphs.End();
315        it != endIt;
316        ++it )
317   {
318     const GlyphIndex index = *it;
319     GlyphInfo& glyph = *( glyphsBuffer + index );
320
321     glyph.xBearing = 0.f;
322     glyph.width = 0.f;
323     glyph.advance = 0.f;
324   }
325
326   // 9) Layout the text
327   Layout::Engine layoutEngine;
328   layoutEngine.SetMetrics( metrics );
329   layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
330
331   // Set the layout parameters.
332   textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
333   textModel->mIgnoreSpacesAfterText = true;
334   Layout::Parameters layoutParameters( textArea,
335                                        textModel );
336
337   Vector<LineRun>& lines = visualModel->mLines;
338
339   Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
340   glyphPositions.Resize( numberOfGlyphs );
341
342   layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
343
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();
349
350   bool isAutoScroll = false;
351   layoutEngine.LayoutText( layoutParameters,
352                            layoutSize,
353                            false,
354                            isAutoScroll,
355                            ellipsisPosition);
356
357   if( options.align )
358   {
359     float alignmentOffset = 0.f;
360     layoutEngine.Align( textArea,
361                         0u,
362                         characterCount,
363                         Text::HorizontalAlignment::BEGIN,
364                         lines,
365                         alignmentOffset,
366                         Dali::LayoutDirection::LEFT_TO_RIGHT,
367                         false );
368   }
369 }
370
371 void ConfigureTextLabel( ControllerPtr controller )
372 {
373   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
374   fontClient.SetDpi( 93u, 93u );
375
376   // Set the text layout as multi-line.
377   controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
378
379   // Set cursor's width to zero.
380   controller->GetLayoutEngine().SetCursorWidth( 0 );
381
382   InputMethodContext inputMethodContext = InputMethodContext::New();
383   // Disables the text input.
384   controller->EnableTextInput( NULL, inputMethodContext );
385
386   // Disables the vertical scrolling.
387   controller->SetVerticalScrollEnabled( false );
388
389   // Disables the horizontal scrolling.
390   controller->SetHorizontalScrollEnabled( false );
391
392   // Enable the text elide.
393   controller->SetTextElideEnabled( true );
394
395   // Disable match system language direction
396   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
397 }
398
399 void ConfigureTextField( ControllerPtr controller )
400 {
401   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
402   fontClient.SetDpi( 93u, 93u );
403
404   // Creates a decorator.
405   Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
406                                                        *controller );
407
408   // Set the text layout as multi-line.
409   controller->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
410
411   InputMethodContext inputMethodContext = InputMethodContext::New();
412   // Enables the text input.
413   controller->EnableTextInput( decorator, inputMethodContext );
414
415   // Enables the vertical scrolling after the text input has been enabled.
416   controller->SetVerticalScrollEnabled( false );
417
418   // Disables the horizontal scrolling.
419   controller->SetHorizontalScrollEnabled( true );
420
421   // No maximum number of characters.
422   controller->SetMaximumNumberOfCharacters( 50u );
423
424   // Disable the text elide.
425   controller->SetTextElideEnabled( false );
426
427   // Disable match system language direction
428   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
429 }
430
431 void ConfigureTextEditor( ControllerPtr controller )
432 {
433   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
434   fontClient.SetDpi( 93u, 93u );
435
436   // Creates a decorator.
437   Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
438                                                        *controller );
439
440   // Set the text layout as multi-line.
441   controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
442
443   InputMethodContext inputMethodContext = InputMethodContext::New();
444   // Enables the text input.
445   controller->EnableTextInput( decorator, inputMethodContext );
446
447   // Enables the vertical scrolling after the text input has been enabled.
448   controller->SetVerticalScrollEnabled( true );
449
450   // Disables the horizontal scrolling.
451   controller->SetHorizontalScrollEnabled( false );
452
453   // No maximum number of characters.
454   controller->SetMaximumNumberOfCharacters( std::numeric_limits<Length>::max() );
455
456   // Disable the text elide.
457   controller->SetTextElideEnabled( false );
458
459   // Disable match system language direction
460   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
461 }
462
463 } // namespace Text
464
465 } // namespace Toolkit
466
467 } // namespace Dali