[dali_2.2.4] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / dali-toolkit-test-utils / toolkit-text-utils.cpp
1 /*
2  * Copyright (c) 2022 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 <dali/devel-api/text-abstraction/font-client.h>
23 #include <limits>
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/hyphenator.h>
29 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
30 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
31 #include <dali-toolkit/internal/text/markup-processor/markup-processor.h>
32 #include <dali-toolkit/internal/text/multi-language-support.h>
33 #include <dali-toolkit/internal/text/segmentation.h>
34 #include <dali-toolkit/internal/text/shaper.h>
35 #include <dali-toolkit/internal/text/controller/text-controller-impl.h>
36
37 namespace Dali
38 {
39 namespace Toolkit
40 {
41 namespace Text
42 {
43 /**
44  * @brief Frees previously allocated bidirectional resources.
45  *
46  * @param[in] bidirectionalLineInfo Bidirectional info per line.
47  * @param[in] index Index to the first line with bidirectional info to be freed.
48  */
49 void FreeBidirectionalLineInfoResources(Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
50                                         uint32_t                         index)
51 {
52   // Free the allocated memory used to store the conversion table in the bidirectional line info run.
53   for(Vector<BidirectionalLineInfoRun>::Iterator it    = bidirectionalLineInfo.Begin() + index,
54                                                  endIt = bidirectionalLineInfo.End();
55       it != endIt;
56       ++it)
57   {
58     BidirectionalLineInfoRun& bidiLineInfo = *it;
59
60     free(bidiLineInfo.visualToLogicalMap);
61   }
62 }
63
64 /**
65  * @brief Clear all the model data except for LogicalModel::mText.
66  *
67  * @param[in] characterIndex Clear data starting from the index.
68  */
69 void ClearModelData(CharacterIndex  characterIndex,
70                     LogicalModelPtr logicalModel,
71                     VisualModelPtr  visualModel)
72 {
73   // n.b. This does not Clear the mText from mLogicalModel
74
75   // Frees previously allocated resources.
76   FreeBidirectionalLineInfoResources(logicalModel->mBidirectionalLineInfo, 0u);
77
78   logicalModel->mScriptRuns.Clear();
79   logicalModel->mFontRuns.Clear();
80   logicalModel->mBidirectionalParagraphInfo.Clear();
81   logicalModel->mCharacterDirections.Clear();
82   logicalModel->mBidirectionalLineInfo.Clear();
83   visualModel->mGlyphs.Clear();
84   visualModel->mGlyphsToCharacters.Clear();
85   visualModel->mCharactersToGlyph.Clear();
86   visualModel->mCharactersPerGlyph.Clear();
87   visualModel->mGlyphsPerCharacter.Clear();
88   visualModel->mGlyphPositions.Clear();
89   visualModel->mLines.Clear();
90
91   visualModel->ClearCaches();
92 }
93
94 void CreateTextModel(const std::string&                text,
95                      const Size&                       textArea,
96                      const Vector<FontDescriptionRun>& fontDescriptions,
97                      const LayoutOptions&              options,
98                      Size&                             layoutSize,
99                      ModelPtr&                         textModel,
100                      MetricsPtr&                       metrics,
101                      bool                              markupProcessorEnabled,
102                      LineWrap::Mode                    wrapMode,
103                      bool                              ellipsisEnabled,
104                      DevelText::EllipsisPosition::Type ellipsisPosition,
105                      float                             lineSpacing,
106                      float                             characterSpacing)
107 {
108   textModel                    = Model::New(); ///< Pointer to the text's model.
109   LogicalModelPtr logicalModel = textModel->mLogicalModel;
110   VisualModelPtr  visualModel  = textModel->mVisualModel;
111
112   MarkupProcessData markupProcessData(logicalModel->mColorRuns,
113                                       logicalModel->mFontDescriptionRuns,
114                                       logicalModel->mEmbeddedItems,
115                                       logicalModel->mAnchors,
116                                       logicalModel->mUnderlinedCharacterRuns,
117                                       logicalModel->mBackgroundColorRuns,
118                                       logicalModel->mStrikethroughCharacterRuns,
119                                       logicalModel->mBoundedParagraphRuns,
120                                       logicalModel->mCharacterSpacingCharacterRuns);
121
122   Length         textSize = 0u;
123   const uint8_t* utf8     = NULL;
124   if(markupProcessorEnabled)
125   {
126     ProcessMarkupString(text, markupProcessData);
127     textSize = markupProcessData.markupProcessedText.size();
128
129     // This is a bit horrible but std::string returns a (signed) char*
130     utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
131   }
132   else
133   {
134     textSize = text.size();
135
136     // This is a bit horrible but std::string returns a (signed) char*
137     utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
138   }
139
140   //Ellipsis
141   textModel->mElideEnabled = ellipsisEnabled;
142   textModel->mVisualModel->SetTextElideEnabled(ellipsisEnabled);
143   textModel->mEllipsisPosition = ellipsisPosition;
144   textModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
145
146   // 1) Convert to utf32
147   Vector<Character>& utf32Characters = logicalModel->mText;
148   utf32Characters.Resize(textSize);
149
150   // Transform a text array encoded in utf8 into an array encoded in utf32.
151   // It returns the actual number of characters.
152   Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
153   utf32Characters.Resize(characterCount);
154
155   // 2) Set the break and paragraph info.
156   Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
157   lineBreakInfo.Resize(characterCount);
158
159   SetLineBreakInfo(utf32Characters,
160                    0u,
161                    characterCount,
162                    lineBreakInfo);
163
164   if(0u == characterCount)
165   {
166     // Nothing else to do if the number of characters is zero.
167     return;
168   }
169
170   textModel->mLineWrapMode = wrapMode;
171
172   if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
173      textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
174   {
175     CharacterIndex end                 = characterCount;
176     LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
177
178     for(CharacterIndex index = 0; index < end; index++)
179     {
180       CharacterIndex wordEnd = index;
181       while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
182       {
183         wordEnd++;
184       }
185
186       if((wordEnd + 1) == end) // add last char
187       {
188         wordEnd++;
189       }
190
191       Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
192
193       for(CharacterIndex i = 0; i < (wordEnd - index); i++)
194       {
195         if(hyphens[i])
196         {
197           *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
198         }
199       }
200
201       index = wordEnd;
202     }
203   }
204
205   // 3) Set the script info.
206   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
207
208   Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
209   multilanguageSupport.SetScripts(utf32Characters,
210                                   0u,
211                                   characterCount,
212                                   scripts);
213
214   // 4) Set the font info
215   Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
216   fontDescriptionRuns                             = fontDescriptions;
217   Vector<FontRun>& validFonts                     = logicalModel->mFontRuns;
218
219   // The default font description.
220   TextAbstraction::FontDescription fontDescription;
221
222   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
223   fontClient.SetDpi(96u, 96u);
224
225   // Validates the fonts. If there is a character with no assigned font it sets a default one.
226   // After this call, fonts are validated.
227   multilanguageSupport.ValidateFonts(utf32Characters,
228                                      scripts,
229                                      fontDescriptionRuns,
230                                      fontDescription,
231                                      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
232                                      0u,
233                                      characterCount,
234                                      validFonts);
235
236   // 5) Set the bidirectional info per paragraph.
237   Vector<Character> mirroredUtf32Characters;
238   bool              textMirrored = false;
239
240   // Reserve some space for the vector of paragraph's bidirectional info.
241   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
242
243   // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
244   SetBidirectionalInfo(utf32Characters,
245                        scripts,
246                        lineBreakInfo,
247                        0u,
248                        characterCount,
249                        bidirectionalInfo);
250
251   // Create the paragraph info.
252   logicalModel->CreateParagraphInfo(0u,
253                                     characterCount);
254
255   // 6) Set character directions.
256   Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
257   if(0u != bidirectionalInfo.Count())
258   {
259     // Only set the character directions if there is right to left characters.
260     GetCharactersDirection(bidirectionalInfo,
261                            characterCount,
262                            0u,
263                            characterCount,
264                            characterDirections);
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   visualModel->SetCharacterSpacing(characterSpacing);
306
307   const Length numberOfGlyphs = glyphs.Count();
308
309   // 8) Get the glyph metrics
310   metrics = Metrics::New(fontClient);
311
312   GlyphInfo* glyphsBuffer = glyphs.Begin();
313   metrics->GetGlyphMetrics(glyphsBuffer, numberOfGlyphs);
314
315   // Update the width and advance of all new paragraph characters.
316   for(Vector<GlyphIndex>::ConstIterator it    = newParagraphGlyphs.Begin(),
317                                         endIt = newParagraphGlyphs.End();
318       it != endIt;
319       ++it)
320   {
321     const GlyphIndex index = *it;
322     GlyphInfo&       glyph = *(glyphsBuffer + index);
323
324     glyph.xBearing = 0.f;
325     glyph.width    = 0.f;
326     glyph.advance  = 0.f;
327   }
328
329   // 9) Layout the text
330   Layout::Engine layoutEngine;
331   layoutEngine.SetMetrics(metrics);
332   layoutEngine.SetLayout(Layout::Engine::MULTI_LINE_BOX);
333   layoutEngine.SetDefaultLineSpacing(lineSpacing);
334
335   // Set the layout parameters.
336   textModel->mHorizontalAlignment   = Text::HorizontalAlignment::BEGIN;
337   textModel->mIgnoreSpacesAfterText = true;
338   Layout::Parameters layoutParameters(textArea,
339                                       textModel);
340
341   Vector<LineRun>& lines = visualModel->mLines;
342
343   Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
344   glyphPositions.Resize(numberOfGlyphs);
345
346   layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph(*(utf32Characters.Begin() + (characterCount - 1u)));
347
348   // The initial glyph and the number of glyphs to layout.
349   layoutParameters.startGlyphIndex        = 0u;
350   layoutParameters.numberOfGlyphs         = numberOfGlyphs;
351   layoutParameters.startLineIndex         = 0u;
352   layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
353
354   bool isAutoScroll                   = false;
355   bool isAutoScrollMaxTextureExceeded = false;
356   bool isHiddenInputEnabled           = false;
357   layoutEngine.LayoutText(layoutParameters,
358                           layoutSize,
359                           false,
360                           isAutoScroll,
361                           isAutoScrollMaxTextureExceeded,
362                           isHiddenInputEnabled,
363                           ellipsisPosition);
364
365   if(options.align)
366   {
367     float alignmentOffset = 0.f;
368     layoutEngine.Align(textArea,
369                        0u,
370                        characterCount,
371                        Text::HorizontalAlignment::BEGIN,
372                        lines,
373                        alignmentOffset,
374                        Dali::LayoutDirection::LEFT_TO_RIGHT,
375                        false);
376   }
377 }
378
379 void ConfigureTextLabel(ControllerPtr controller)
380 {
381   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
382   fontClient.SetDpi(93u, 93u);
383
384   // Set the text layout as multi-line.
385   controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
386
387   // Set cursor's width to zero.
388   controller->GetLayoutEngine().SetCursorWidth(0);
389
390   InputMethodContext inputMethodContext = InputMethodContext::New();
391   // Disables the text input.
392   controller->EnableTextInput(NULL, inputMethodContext);
393
394   // Disables the vertical scrolling.
395   controller->SetVerticalScrollEnabled(false);
396
397   // Disables the horizontal scrolling.
398   controller->SetHorizontalScrollEnabled(false);
399
400   // Enable the text elide.
401   controller->SetTextElideEnabled(true);
402
403   // Disable match system language direction
404   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
405 }
406
407 void ConfigureTextField(ControllerPtr controller)
408 {
409   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
410   fontClient.SetDpi(93u, 93u);
411
412   // Creates a decorator.
413   Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
414                                                       *controller);
415
416   // Set the text layout as multi-line.
417   controller->GetLayoutEngine().SetLayout(Layout::Engine::SINGLE_LINE_BOX);
418
419   InputMethodContext inputMethodContext = InputMethodContext::New();
420   // Enables the text input.
421   controller->EnableTextInput(decorator, inputMethodContext);
422
423   // Enables the vertical scrolling after the text input has been enabled.
424   controller->SetVerticalScrollEnabled(false);
425
426   // Disables the horizontal scrolling.
427   controller->SetHorizontalScrollEnabled(true);
428
429   // No maximum number of characters.
430   controller->SetMaximumNumberOfCharacters(50u);
431
432   // Disable the text elide.
433   controller->SetTextElideEnabled(false);
434
435   // Disable match system language direction
436   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
437 }
438
439 void ConfigureTextEditor(ControllerPtr controller)
440 {
441   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
442   fontClient.SetDpi(93u, 93u);
443
444   // Creates a decorator.
445   Text::DecoratorPtr decorator = Text::Decorator::New(*controller,
446                                                       *controller);
447
448   // Set the text layout as multi-line.
449   controller->GetLayoutEngine().SetLayout(Layout::Engine::MULTI_LINE_BOX);
450
451   InputMethodContext inputMethodContext = InputMethodContext::New();
452   // Enables the text input.
453   controller->EnableTextInput(decorator, inputMethodContext);
454
455   // Enables the vertical scrolling after the text input has been enabled.
456   controller->SetVerticalScrollEnabled(true);
457
458   // Disables the horizontal scrolling.
459   controller->SetHorizontalScrollEnabled(false);
460
461   // No maximum number of characters.
462   controller->SetMaximumNumberOfCharacters(std::numeric_limits<Length>::max());
463
464   // Disable the text elide.
465   controller->SetTextElideEnabled(false);
466
467   // Disable match system language direction
468   controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS);
469 }
470
471 Vector<FontDescriptionRun> CreateSingleFontDescription(
472   const CharacterRun&   characterRun,
473   const std::string     fontFamilyName,
474   const FontWeight      weight,
475   const FontWidth       width,
476   const FontSlant       slant,
477   const PointSize26Dot6 size,
478   const bool            familyDefined,
479   const bool            weightDefined,
480   const bool            widthDefined,
481   const bool            slantDefined,
482   const bool            sizeDefined)
483 {
484   FontDescriptionRun fontDescriptionRun =
485     {
486       characterRun,
487       nullptr,
488       0u,
489       weight,
490       width,
491       slant,
492       size,
493       familyDefined,
494       weightDefined,
495       widthDefined,
496       slantDefined,
497       sizeDefined};
498
499   fontDescriptionRun.familyLength = fontFamilyName.size();
500   fontDescriptionRun.familyName   = new char[fontDescriptionRun.familyLength];
501   memcpy(fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength);
502
503   Vector<FontDescriptionRun> fontDescriptionRuns;
504   fontDescriptionRuns.PushBack(fontDescriptionRun);
505
506   return fontDescriptionRuns;
507 }
508
509 } // namespace Text
510
511 } // namespace Toolkit
512
513 } // namespace Dali