cc0288cedbc9a6f23fe88fa9db4377b95df82a94
[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                       float lineSpacing)
109 {
110   textModel = Model::New(); ///< Pointer to the text's model.
111   LogicalModelPtr logicalModel = textModel->mLogicalModel;
112   VisualModelPtr visualModel = textModel->mVisualModel;
113
114   MarkupProcessData markupProcessData( logicalModel->mColorRuns,
115                                        logicalModel->mFontDescriptionRuns,
116                                        logicalModel->mEmbeddedItems,
117                                        logicalModel->mAnchors,
118                                        logicalModel->mUnderlinedCharacterRuns,
119                                        logicalModel->mBackgroundColorRuns);
120
121   Length textSize = 0u;
122   const uint8_t* utf8 = NULL;
123   if( markupProcessorEnabled )
124   {
125     ProcessMarkupString( text, markupProcessData );
126     textSize = markupProcessData.markupProcessedText.size();
127
128     // This is a bit horrible but std::string returns a (signed) char*
129     utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
130   }
131   else
132   {
133     textSize = text.size();
134
135     // This is a bit horrible but std::string returns a (signed) char*
136     utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
137   }
138
139   //Ellipsis
140   textModel-> mElideEnabled = ellipsisEnabled;
141   textModel-> mVisualModel->SetTextElideEnabled(ellipsisEnabled);
142   textModel-> mEllipsisPosition = ellipsisPosition;
143   textModel-> mVisualModel->SetEllipsisPosition(ellipsisPosition);
144
145   // 1) Convert to utf32
146   Vector<Character>& utf32Characters = logicalModel->mText;
147   utf32Characters.Resize( textSize );
148
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 );
153
154   // 2) Set the break and paragraph info.
155   Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
156   lineBreakInfo.Resize( characterCount );
157
158   SetLineBreakInfo( utf32Characters,
159                     0u,
160                     characterCount,
161                     lineBreakInfo );
162
163   if( 0u == characterCount )
164   {
165     // Nothing else to do if the number of characters is zero.
166     return;
167   }
168
169   textModel->mLineWrapMode = wrapMode;
170
171   if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
172        textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
173   {
174     CharacterIndex end                 = characterCount;
175     LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
176
177     for(CharacterIndex index = 0; index < end; index++)
178     {
179       CharacterIndex wordEnd = index;
180       while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
181       {
182         wordEnd++;
183       }
184
185       if((wordEnd + 1) == end) // add last char
186       {
187         wordEnd++;
188       }
189
190       Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
191
192       for(CharacterIndex i = 0; i < (wordEnd - index); i++)
193       {
194         if(hyphens[i])
195         {
196           *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
197         }
198       }
199
200       index = wordEnd;
201     }
202   }
203
204   // 3) Set the script info.
205   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
206
207   Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
208   multilanguageSupport.SetScripts( utf32Characters,
209                                    0u,
210                                    characterCount,
211                                    scripts );
212
213   // 4) Set the font info
214   Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
215   fontDescriptionRuns = fontDescriptions;
216   Vector<FontRun>& validFonts = logicalModel->mFontRuns;
217
218   // The default font description.
219   TextAbstraction::FontDescription fontDescription;
220
221   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
222   fontClient.SetDpi( 96u, 96u );
223
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,
227                                       scripts,
228                                       fontDescriptionRuns,
229                                       fontDescription,
230                                       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
231                                       0u,
232                                       characterCount,
233                                       validFonts );
234
235   // 5) Set the bidirectional info per paragraph.
236   Vector<Character> mirroredUtf32Characters;
237   bool textMirrored = false;
238
239   // Reserve some space for the vector of paragraph's bidirectional info.
240   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
241
242   // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
243   SetBidirectionalInfo( utf32Characters,
244                         scripts,
245                         lineBreakInfo,
246                         0u,
247                         characterCount,
248                         bidirectionalInfo );
249
250   // Create the paragraph info.
251   logicalModel->CreateParagraphInfo( 0u,
252                                      characterCount );
253
254   // 6) Set character directions.
255   Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
256   if( 0u != bidirectionalInfo.Count() )
257   {
258     // Only set the character directions if there is right to left characters.
259     GetCharactersDirection( bidirectionalInfo,
260                             characterCount,
261                             0u,
262                             characterCount,
263                             characterDirections );
264
265
266     // This paragraph has right to left text. Some characters may need to be mirrored.
267     textMirrored = GetMirroredText( utf32Characters,
268                                     characterDirections,
269                                     bidirectionalInfo,
270                                     0u,
271                                     characterCount,
272                                     mirroredUtf32Characters );
273   }
274   else
275   {
276     // There is no right to left characters. Clear the directions vector.
277     characterDirections.Clear();
278   }
279
280   // 7) Shape the text.
281
282   Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
283   Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
284   Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
285   Vector<GlyphIndex> newParagraphGlyphs;
286
287   const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
288
289   ShapeText( textToShape,
290              lineBreakInfo,
291              scripts,
292              validFonts,
293              0u,
294              0u,
295              characterCount,
296              glyphs,
297              glyphsToCharactersMap,
298              charactersPerGlyph,
299              newParagraphGlyphs );
300
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 );
304
305   const Length numberOfGlyphs = glyphs.Count();
306
307   // 8) Get the glyph metrics
308   metrics = Metrics::New( fontClient );
309
310   GlyphInfo* glyphsBuffer = glyphs.Begin();
311   metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
312
313   // Update the width and advance of all new paragraph characters.
314   for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
315          endIt = newParagraphGlyphs.End();
316        it != endIt;
317        ++it )
318   {
319     const GlyphIndex index = *it;
320     GlyphInfo& glyph = *( glyphsBuffer + index );
321
322     glyph.xBearing = 0.f;
323     glyph.width = 0.f;
324     glyph.advance = 0.f;
325   }
326
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);
332
333   // Set the layout parameters.
334   textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
335   textModel->mIgnoreSpacesAfterText = true;
336   Layout::Parameters layoutParameters( textArea,
337                                        textModel );
338
339   Vector<LineRun>& lines = visualModel->mLines;
340
341   Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
342   glyphPositions.Resize( numberOfGlyphs );
343
344   layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
345
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();
351
352   bool isAutoScroll = false;
353   layoutEngine.LayoutText( layoutParameters,
354                            layoutSize,
355                            false,
356                            isAutoScroll,
357                            ellipsisPosition);
358
359   if( options.align )
360   {
361     float alignmentOffset = 0.f;
362     layoutEngine.Align( textArea,
363                         0u,
364                         characterCount,
365                         Text::HorizontalAlignment::BEGIN,
366                         lines,
367                         alignmentOffset,
368                         Dali::LayoutDirection::LEFT_TO_RIGHT,
369                         false );
370   }
371 }
372
373 void ConfigureTextLabel( ControllerPtr controller )
374 {
375   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
376   fontClient.SetDpi( 93u, 93u );
377
378   // Set the text layout as multi-line.
379   controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
380
381   // Set cursor's width to zero.
382   controller->GetLayoutEngine().SetCursorWidth( 0 );
383
384   InputMethodContext inputMethodContext = InputMethodContext::New();
385   // Disables the text input.
386   controller->EnableTextInput( NULL, inputMethodContext );
387
388   // Disables the vertical scrolling.
389   controller->SetVerticalScrollEnabled( false );
390
391   // Disables the horizontal scrolling.
392   controller->SetHorizontalScrollEnabled( false );
393
394   // Enable the text elide.
395   controller->SetTextElideEnabled( true );
396
397   // Disable match system language direction
398   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
399 }
400
401 void ConfigureTextField( ControllerPtr controller )
402 {
403   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
404   fontClient.SetDpi( 93u, 93u );
405
406   // Creates a decorator.
407   Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
408                                                        *controller );
409
410   // Set the text layout as multi-line.
411   controller->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
412
413   InputMethodContext inputMethodContext = InputMethodContext::New();
414   // Enables the text input.
415   controller->EnableTextInput( decorator, inputMethodContext );
416
417   // Enables the vertical scrolling after the text input has been enabled.
418   controller->SetVerticalScrollEnabled( false );
419
420   // Disables the horizontal scrolling.
421   controller->SetHorizontalScrollEnabled( true );
422
423   // No maximum number of characters.
424   controller->SetMaximumNumberOfCharacters( 50u );
425
426   // Disable the text elide.
427   controller->SetTextElideEnabled( false );
428
429   // Disable match system language direction
430   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
431 }
432
433 void ConfigureTextEditor( ControllerPtr controller )
434 {
435   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
436   fontClient.SetDpi( 93u, 93u );
437
438   // Creates a decorator.
439   Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
440                                                        *controller );
441
442   // Set the text layout as multi-line.
443   controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
444
445   InputMethodContext inputMethodContext = InputMethodContext::New();
446   // Enables the text input.
447   controller->EnableTextInput( decorator, inputMethodContext );
448
449   // Enables the vertical scrolling after the text input has been enabled.
450   controller->SetVerticalScrollEnabled( true );
451
452   // Disables the horizontal scrolling.
453   controller->SetHorizontalScrollEnabled( false );
454
455   // No maximum number of characters.
456   controller->SetMaximumNumberOfCharacters( std::numeric_limits<Length>::max() );
457
458   // Disable the text elide.
459   controller->SetTextElideEnabled( false );
460
461   // Disable match system language direction
462   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
463 }
464
465
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)
478 {
479
480   FontDescriptionRun fontDescriptionRun =
481   {
482     characterRun,
483     nullptr,
484     0u,
485     weight,
486     width,
487     slant,
488     size,
489     familyDefined,
490     weightDefined,
491     widthDefined,
492     slantDefined,
493     sizeDefined
494   };
495
496   fontDescriptionRun.familyLength = fontFamilyName.size();
497   fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
498   memcpy( fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength );
499
500   Vector<FontDescriptionRun> fontDescriptionRuns;
501   fontDescriptionRuns.PushBack(fontDescriptionRun);
502
503   return fontDescriptionRuns;
504 }
505
506 } // namespace Text
507
508 } // namespace Toolkit
509
510 } // namespace Dali