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