Merge changes I90752dc1,If040eaa9,I50559f33 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) 2018 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
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Text
42 {
43
44 /**
45  * @brief Frees previously allocated bidirectional resources.
46  *
47  * @param[in] bidirectionalLineInfo Bidirectional info per line.
48  * @param[in] index Index to the first line with bidirectional info to be freed.
49  */
50 void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
51                                          uint32_t index )
52 {
53   // Free the allocated memory used to store the conversion table in the bidirectional line info run.
54   for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
55          endIt = bidirectionalLineInfo.End();
56        it != endIt;
57        ++it )
58   {
59     BidirectionalLineInfoRun& bidiLineInfo = *it;
60
61     free( bidiLineInfo.visualToLogicalMap );
62   }
63 }
64
65 /**
66  * @brief Clear all the model data except for LogicalModel::mText.
67  *
68  * @param[in] characterIndex Clear data starting from the index.
69  */
70 void ClearModelData( CharacterIndex characterIndex,
71                      LogicalModelPtr logicalModel,
72                      VisualModelPtr visualModel )
73 {
74   // n.b. This does not Clear the mText from mLogicalModel
75
76   // Frees previously allocated resources.
77   FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
78
79   logicalModel->mScriptRuns.Clear();
80   logicalModel->mFontRuns.Clear();
81   logicalModel->mWordBreakInfo.Clear();
82   logicalModel->mBidirectionalParagraphInfo.Clear();
83   logicalModel->mCharacterDirections.Clear();
84   logicalModel->mBidirectionalLineInfo.Clear();
85   visualModel->mGlyphs.Clear();
86   visualModel->mGlyphsToCharacters.Clear();
87   visualModel->mCharactersToGlyph.Clear();
88   visualModel->mCharactersPerGlyph.Clear();
89   visualModel->mGlyphsPerCharacter.Clear();
90   visualModel->mGlyphPositions.Clear();
91   visualModel->mLines.Clear();
92
93   visualModel->ClearCaches();
94 }
95
96 void CreateTextModel( const std::string& text,
97                       const Size& textArea,
98                       const Vector<FontDescriptionRun>& fontDescriptions,
99                       const LayoutOptions& options,
100                       Size& layoutSize,
101                       LogicalModelPtr& logicalModel,
102                       VisualModelPtr& visualModel,
103                       MetricsPtr& metrics )
104 {
105   logicalModel = LogicalModel::New();
106   visualModel = VisualModel::New();
107
108   // 1) Convert to utf32
109   Vector<Character>& utf32Characters = logicalModel->mText;
110   utf32Characters.Resize( text.size() );
111
112   const uint32_t numberOfCharacters = ( text.size() == 0) ? 0 :
113     Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( text.c_str() ),
114                                                    text.size(),
115                                                    &utf32Characters[0u] );
116   utf32Characters.Resize( numberOfCharacters );
117
118   // 2) Set the break and paragraph info.
119   Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
120   lineBreakInfo.Resize( numberOfCharacters );
121
122   SetLineBreakInfo( utf32Characters,
123                     0u,
124                     numberOfCharacters,
125                     lineBreakInfo );
126
127   if( 0u == numberOfCharacters )
128   {
129     // Nothing else to do if the number of characters is zero.
130     return;
131   }
132
133   // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
134   Vector<WordBreakInfo>& wordBreakInfo = logicalModel->mWordBreakInfo;
135   wordBreakInfo.Resize( numberOfCharacters );
136
137   SetWordBreakInfo( utf32Characters,
138                     0u,
139                     numberOfCharacters,
140                     wordBreakInfo );
141
142   // 3) Set the script info.
143   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
144
145   Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
146   multilanguageSupport.SetScripts( utf32Characters,
147                                    0u,
148                                    numberOfCharacters,
149                                    scripts );
150
151   // 4) Set the font info
152   Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
153   fontDescriptionRuns = fontDescriptions;
154   Vector<FontRun>& validFonts = logicalModel->mFontRuns;
155
156   // The default font description.
157   TextAbstraction::FontDescription fontDescription;
158
159   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
160   fontClient.SetDpi( 96u, 96u );
161
162   // Validates the fonts. If there is a character with no assigned font it sets a default one.
163   // After this call, fonts are validated.
164   multilanguageSupport.ValidateFonts( utf32Characters,
165                                       scripts,
166                                       fontDescriptionRuns,
167                                       fontDescription,
168                                       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
169                                       0u,
170                                       numberOfCharacters,
171                                       validFonts );
172
173   // 5) Set the bidirectional info per paragraph.
174   Vector<Character> mirroredUtf32Characters;
175   bool textMirrored = false;
176
177   // Reserve some space for the vector of paragraph's bidirectional info.
178   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
179
180   // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
181   SetBidirectionalInfo( utf32Characters,
182                         scripts,
183                         lineBreakInfo,
184                         0u,
185                         numberOfCharacters,
186                         bidirectionalInfo );
187
188   // Create the paragraph info.
189   logicalModel->CreateParagraphInfo( 0u,
190                                      numberOfCharacters );
191
192   // 6) Set character directions.
193   Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
194   if( 0u != bidirectionalInfo.Count() )
195   {
196     // Only set the character directions if there is right to left characters.
197     GetCharactersDirection( bidirectionalInfo,
198                             numberOfCharacters,
199                             0u,
200                             numberOfCharacters,
201                             characterDirections );
202
203
204     // This paragraph has right to left text. Some characters may need to be mirrored.
205     textMirrored = GetMirroredText( utf32Characters,
206                                     characterDirections,
207                                     bidirectionalInfo,
208                                     0u,
209                                     numberOfCharacters,
210                                     mirroredUtf32Characters );
211   }
212   else
213   {
214     // There is no right to left characters. Clear the directions vector.
215     characterDirections.Clear();
216   }
217
218   // 7) Shape the text.
219
220   Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
221   Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
222   Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
223   Vector<GlyphIndex> newParagraphGlyphs;
224
225   const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
226
227   ShapeText( textToShape,
228              lineBreakInfo,
229              scripts,
230              validFonts,
231              0u,
232              0u,
233              numberOfCharacters,
234              glyphs,
235              glyphsToCharactersMap,
236              charactersPerGlyph,
237              newParagraphGlyphs );
238
239   // Create the 'number of glyphs' per character and the glyph to character conversion tables.
240   visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters );
241   visualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters );
242
243   const Length numberOfGlyphs = glyphs.Count();
244
245   // 8) Get the glyph metrics
246   metrics = Metrics::New( fontClient );
247
248   GlyphInfo* glyphsBuffer = glyphs.Begin();
249   metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
250
251   // Update the width and advance of all new paragraph characters.
252   for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
253          endIt = newParagraphGlyphs.End();
254        it != endIt;
255        ++it )
256   {
257     const GlyphIndex index = *it;
258     GlyphInfo& glyph = *( glyphsBuffer + index );
259
260     glyph.xBearing = 0.f;
261     glyph.width = 0.f;
262     glyph.advance = 0.f;
263   }
264
265   // 9) Layout the text
266   Layout::Engine layoutEngine;
267   layoutEngine.SetMetrics( metrics );
268   layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
269
270   // Set the layout parameters.
271   const Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
272   const Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
273   float outlineWidth = visualModel->GetOutlineWidth();
274   Layout::Parameters layoutParameters( textArea,
275                                        utf32Characters.Begin(),
276                                        lineBreakInfo.Begin(),
277                                        wordBreakInfo.Begin(),
278                                        ( 0u != characterDirections.Count() ) ? characterDirections.Begin() : NULL,
279                                        glyphs.Begin(),
280                                        glyphsToCharactersMap.Begin(),
281                                        charactersPerGlyph.Begin(),
282                                        charactersToGlyph.Begin(),
283                                        glyphsPerCharacter.Begin(),
284                                        numberOfGlyphs,
285                                        Text::HorizontalAlignment::BEGIN,
286                                        Text::LineWrap::WORD,
287                                        outlineWidth );
288
289   Vector<LineRun>& lines = visualModel->mLines;
290
291   Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
292   glyphPositions.Resize( numberOfGlyphs );
293
294   layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( numberOfCharacters - 1u ) ) );
295
296   // The initial glyph and the number of glyphs to layout.
297   layoutParameters.startGlyphIndex = 0u;
298   layoutParameters.numberOfGlyphs = numberOfGlyphs;
299   layoutParameters.startLineIndex = 0u;
300   layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
301
302   layoutEngine.LayoutText( layoutParameters,
303                            glyphPositions,
304                            lines,
305                            layoutSize,
306                            false );
307
308   // 10) Reorder the lines
309   if( 0u != bidirectionalInfo.Count() )
310   {
311     Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = logicalModel->mBidirectionalLineInfo;
312
313     // Get the lines
314     const Length numberOfLines = lines.Count();
315
316     // Reorder the lines.
317     bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
318     ReorderLines( bidirectionalInfo,
319                   0u,
320                   numberOfCharacters,
321                   lines,
322                   bidirectionalLineInfo );
323
324     // Set the bidirectional info per line into the layout parameters.
325     layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
326     layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
327
328     if( options.reorder )
329     {
330       // Re-layout the text. Reorder those lines with right to left characters.
331       layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
332                                              0u,
333                                              numberOfCharacters,
334                                              glyphPositions );
335     }
336   }
337
338   if( options.align )
339   {
340     float alignmentOffset = 0.f;
341     layoutEngine.Align( textArea,
342                         0u,
343                         numberOfCharacters,
344                         Text::HorizontalAlignment::BEGIN,
345                         lines,
346                         alignmentOffset );
347   }
348 }
349
350 void ConfigureTextLabel( ControllerPtr controller )
351 {
352   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
353   fontClient.SetDpi( 93u, 93u );
354
355   // Set the text layout as multi-line.
356   controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
357
358   // Set cursor's width to zero.
359   controller->GetLayoutEngine().SetCursorWidth( 0 );
360
361   InputMethodContext inputMethodContext = InputMethodContext::New();
362   // Disables the text input.
363   controller->EnableTextInput( NULL, inputMethodContext );
364
365   // Disables the vertical scrolling.
366   controller->SetVerticalScrollEnabled( false );
367
368   // Disables the horizontal scrolling.
369   controller->SetHorizontalScrollEnabled( false );
370
371   // Enable the text elide.
372   controller->SetTextElideEnabled( true );
373 }
374
375 void ConfigureTextField( ControllerPtr controller )
376 {
377   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
378   fontClient.SetDpi( 93u, 93u );
379
380   // Creates a decorator.
381   Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
382                                                        *controller );
383
384   // Set the text layout as multi-line.
385   controller->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
386
387   InputMethodContext inputMethodContext = InputMethodContext::New();
388   // Enables the text input.
389   controller->EnableTextInput( decorator, inputMethodContext );
390
391   // Enables the vertical scrolling after the text input has been enabled.
392   controller->SetVerticalScrollEnabled( false );
393
394   // Disables the horizontal scrolling.
395   controller->SetHorizontalScrollEnabled( true );
396
397   // No maximum number of characters.
398   controller->SetMaximumNumberOfCharacters( 50u );
399
400   // Disable the text elide.
401   controller->SetTextElideEnabled( false );
402 }
403
404 void ConfigureTextEditor( ControllerPtr controller )
405 {
406   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
407   fontClient.SetDpi( 93u, 93u );
408
409   // Creates a decorator.
410   Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
411                                                        *controller );
412
413   // Set the text layout as multi-line.
414   controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
415
416   InputMethodContext inputMethodContext = InputMethodContext::New();
417   // Enables the text input.
418   controller->EnableTextInput( decorator, inputMethodContext );
419
420   // Enables the vertical scrolling after the text input has been enabled.
421   controller->SetVerticalScrollEnabled( true );
422
423   // Disables the horizontal scrolling.
424   controller->SetHorizontalScrollEnabled( false );
425
426   // No maximum number of characters.
427   controller->SetMaximumNumberOfCharacters( std::numeric_limits<Length>::max() );
428
429   // Disable the text elide.
430   controller->SetTextElideEnabled( false );
431 }
432
433 } // namespace Text
434
435 } // namespace Toolkit
436
437 } // namespace Dali