Merge "Support Emoji sequences" into 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) 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
464 Vector<FontDescriptionRun> CreateSingleFontDescription(
465                     const CharacterRun&         characterRun,
466                     const std::string           fontFamilyName,
467                     const FontWeight            weight,
468                     const FontWidth             width,
469                     const FontSlant             slant,
470                     const PointSize26Dot6       size,
471                     const bool                  familyDefined,
472                     const bool                  weightDefined,
473                     const bool                  widthDefined,
474                     const bool                  slantDefined,
475                     const bool                  sizeDefined)
476 {
477
478   FontDescriptionRun fontDescriptionRun =
479   {
480     characterRun,
481     nullptr,
482     0u,
483     weight,
484     width,
485     slant,
486     size,
487     familyDefined,
488     weightDefined,
489     widthDefined,
490     slantDefined,
491     sizeDefined
492   };
493
494   fontDescriptionRun.familyLength = fontFamilyName.size();
495   fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
496   memcpy( fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength );
497
498   Vector<FontDescriptionRun> fontDescriptionRuns;
499   fontDescriptionRuns.PushBack(fontDescriptionRun);
500
501   return fontDescriptionRuns;
502 }
503
504 } // namespace Text
505
506 } // namespace Toolkit
507
508 } // namespace Dali