Merge "TextField is re-laied out after its properties are changed." 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 #include <dali-toolkit/internal/text/markup-processor.h>
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Text
43 {
44
45 /**
46  * @brief Frees previously allocated bidirectional resources.
47  *
48  * @param[in] bidirectionalLineInfo Bidirectional info per line.
49  * @param[in] index Index to the first line with bidirectional info to be freed.
50  */
51 void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
52                                          uint32_t index )
53 {
54   // Free the allocated memory used to store the conversion table in the bidirectional line info run.
55   for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
56          endIt = bidirectionalLineInfo.End();
57        it != endIt;
58        ++it )
59   {
60     BidirectionalLineInfoRun& bidiLineInfo = *it;
61
62     free( bidiLineInfo.visualToLogicalMap );
63   }
64 }
65
66 /**
67  * @brief Clear all the model data except for LogicalModel::mText.
68  *
69  * @param[in] characterIndex Clear data starting from the index.
70  */
71 void ClearModelData( CharacterIndex characterIndex,
72                      LogicalModelPtr logicalModel,
73                      VisualModelPtr visualModel )
74 {
75   // n.b. This does not Clear the mText from mLogicalModel
76
77   // Frees previously allocated resources.
78   FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
79
80   logicalModel->mScriptRuns.Clear();
81   logicalModel->mFontRuns.Clear();
82   logicalModel->mWordBreakInfo.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                       LogicalModelPtr& logicalModel,
103                       VisualModelPtr& visualModel,
104                       MetricsPtr& metrics,
105                       bool markupProcessorEnabled )
106 {
107   logicalModel = LogicalModel::New();
108   visualModel = VisualModel::New();
109
110   MarkupProcessData markupProcessData( logicalModel->mColorRuns,
111                                        logicalModel->mFontDescriptionRuns,
112                                        logicalModel->mEmbeddedItems );
113
114   Length textSize = 0u;
115   const uint8_t* utf8 = NULL;
116   if( markupProcessorEnabled )
117   {
118     ProcessMarkupString( text, markupProcessData );
119     textSize = markupProcessData.markupProcessedText.size();
120
121     // This is a bit horrible but std::string returns a (signed) char*
122     utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
123   }
124   else
125   {
126     textSize = text.size();
127
128     // This is a bit horrible but std::string returns a (signed) char*
129     utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
130   }
131
132   // 1) Convert to utf32
133   Vector<Character>& utf32Characters = logicalModel->mText;
134   utf32Characters.Resize( textSize );
135
136   // Transform a text array encoded in utf8 into an array encoded in utf32.
137   // It returns the actual number of characters.
138   Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
139   utf32Characters.Resize( characterCount );
140
141   // 2) Set the break and paragraph info.
142   Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
143   lineBreakInfo.Resize( characterCount );
144
145   SetLineBreakInfo( utf32Characters,
146                     0u,
147                     characterCount,
148                     lineBreakInfo );
149
150   if( 0u == characterCount )
151   {
152     // Nothing else to do if the number of characters is zero.
153     return;
154   }
155
156   // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
157   Vector<WordBreakInfo>& wordBreakInfo = logicalModel->mWordBreakInfo;
158   wordBreakInfo.Resize( characterCount );
159
160   SetWordBreakInfo( utf32Characters,
161                     0u,
162                     characterCount,
163                     wordBreakInfo );
164
165   // 3) Set the script info.
166   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
167
168   Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
169   multilanguageSupport.SetScripts( utf32Characters,
170                                    0u,
171                                    characterCount,
172                                    scripts );
173
174   // 4) Set the font info
175   Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
176   fontDescriptionRuns = fontDescriptions;
177   Vector<FontRun>& validFonts = logicalModel->mFontRuns;
178
179   // The default font description.
180   TextAbstraction::FontDescription fontDescription;
181
182   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
183   fontClient.SetDpi( 96u, 96u );
184
185   // Validates the fonts. If there is a character with no assigned font it sets a default one.
186   // After this call, fonts are validated.
187   multilanguageSupport.ValidateFonts( utf32Characters,
188                                       scripts,
189                                       fontDescriptionRuns,
190                                       fontDescription,
191                                       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
192                                       0u,
193                                       characterCount,
194                                       validFonts );
195
196   // 5) Set the bidirectional info per paragraph.
197   Vector<Character> mirroredUtf32Characters;
198   bool textMirrored = false;
199
200   // Reserve some space for the vector of paragraph's bidirectional info.
201   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
202
203   // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
204   SetBidirectionalInfo( utf32Characters,
205                         scripts,
206                         lineBreakInfo,
207                         0u,
208                         characterCount,
209                         bidirectionalInfo );
210
211   // Create the paragraph info.
212   logicalModel->CreateParagraphInfo( 0u,
213                                      characterCount );
214
215   // 6) Set character directions.
216   Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
217   if( 0u != bidirectionalInfo.Count() )
218   {
219     // Only set the character directions if there is right to left characters.
220     GetCharactersDirection( bidirectionalInfo,
221                             characterCount,
222                             0u,
223                             characterCount,
224                             characterDirections );
225
226
227     // This paragraph has right to left text. Some characters may need to be mirrored.
228     textMirrored = GetMirroredText( utf32Characters,
229                                     characterDirections,
230                                     bidirectionalInfo,
231                                     0u,
232                                     characterCount,
233                                     mirroredUtf32Characters );
234   }
235   else
236   {
237     // There is no right to left characters. Clear the directions vector.
238     characterDirections.Clear();
239   }
240
241   // 7) Shape the text.
242
243   Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
244   Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
245   Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
246   Vector<GlyphIndex> newParagraphGlyphs;
247
248   const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
249
250   ShapeText( textToShape,
251              lineBreakInfo,
252              scripts,
253              validFonts,
254              0u,
255              0u,
256              characterCount,
257              glyphs,
258              glyphsToCharactersMap,
259              charactersPerGlyph,
260              newParagraphGlyphs );
261
262   // Create the 'number of glyphs' per character and the glyph to character conversion tables.
263   visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, characterCount );
264   visualModel->CreateCharacterToGlyphTable( 0u, 0u, characterCount );
265
266   const Length numberOfGlyphs = glyphs.Count();
267
268   // 8) Get the glyph metrics
269   metrics = Metrics::New( fontClient );
270
271   GlyphInfo* glyphsBuffer = glyphs.Begin();
272   metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
273
274   // Update the width and advance of all new paragraph characters.
275   for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
276          endIt = newParagraphGlyphs.End();
277        it != endIt;
278        ++it )
279   {
280     const GlyphIndex index = *it;
281     GlyphInfo& glyph = *( glyphsBuffer + index );
282
283     glyph.xBearing = 0.f;
284     glyph.width = 0.f;
285     glyph.advance = 0.f;
286   }
287
288   // 9) Layout the text
289   Layout::Engine layoutEngine;
290   layoutEngine.SetMetrics( metrics );
291   layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
292
293   // Set the layout parameters.
294   const Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
295   const Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
296   float outlineWidth = visualModel->GetOutlineWidth();
297   Layout::Parameters layoutParameters( textArea,
298                                        utf32Characters.Begin(),
299                                        lineBreakInfo.Begin(),
300                                        wordBreakInfo.Begin(),
301                                        ( 0u != characterDirections.Count() ) ? characterDirections.Begin() : NULL,
302                                        glyphs.Begin(),
303                                        glyphsToCharactersMap.Begin(),
304                                        charactersPerGlyph.Begin(),
305                                        charactersToGlyph.Begin(),
306                                        glyphsPerCharacter.Begin(),
307                                        numberOfGlyphs,
308                                        Text::HorizontalAlignment::BEGIN,
309                                        Text::LineWrap::WORD,
310                                        outlineWidth,
311                                        true,
312                                        false );
313
314   Vector<LineRun>& lines = visualModel->mLines;
315
316   Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
317   glyphPositions.Resize( numberOfGlyphs );
318
319   layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
320
321   // The initial glyph and the number of glyphs to layout.
322   layoutParameters.startGlyphIndex = 0u;
323   layoutParameters.numberOfGlyphs = numberOfGlyphs;
324   layoutParameters.startLineIndex = 0u;
325   layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
326
327   bool isAutoScroll = false;
328   layoutEngine.LayoutText( layoutParameters,
329                            glyphPositions,
330                            lines,
331                            layoutSize,
332                            false,
333                            isAutoScroll );
334
335   // 10) Reorder the lines
336   if( 0u != bidirectionalInfo.Count() )
337   {
338     Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = logicalModel->mBidirectionalLineInfo;
339
340     // Get the lines
341     const Length numberOfLines = lines.Count();
342
343     // Reorder the lines.
344     bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
345     ReorderLines( bidirectionalInfo,
346                   0u,
347                   characterCount,
348                   lines,
349                   bidirectionalLineInfo );
350
351     // Set the bidirectional info per line into the layout parameters.
352     layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
353     layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
354
355     if( options.reorder )
356     {
357       // Re-layout the text. Reorder those lines with right to left characters.
358       layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
359                                              0u,
360                                              characterCount,
361                                              glyphPositions );
362     }
363   }
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
404 void ConfigureTextField( 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::SINGLE_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( false );
422
423   // Disables the horizontal scrolling.
424   controller->SetHorizontalScrollEnabled( true );
425
426   // No maximum number of characters.
427   controller->SetMaximumNumberOfCharacters( 50u );
428
429   // Disable the text elide.
430   controller->SetTextElideEnabled( false );
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
462 } // namespace Text
463
464 } // namespace Toolkit
465
466 } // namespace Dali