1e745b13b73879bc277eacdef9b3b09bebdf424b
[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->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                       ModelPtr& textModel,
102                       MetricsPtr& metrics,
103                       bool markupProcessorEnabled )
104 {
105   textModel = Model::New(); ///< Pointer to the text's model.
106   LogicalModelPtr logicalModel = textModel->mLogicalModel;
107   VisualModelPtr visualModel = textModel->mVisualModel;
108
109   MarkupProcessData markupProcessData( logicalModel->mColorRuns,
110                                        logicalModel->mFontDescriptionRuns,
111                                        logicalModel->mEmbeddedItems,
112                                        logicalModel->mAnchors,
113                                        logicalModel->mUnderlinedCharacterRuns);
114
115   Length textSize = 0u;
116   const uint8_t* utf8 = NULL;
117   if( markupProcessorEnabled )
118   {
119     ProcessMarkupString( text, markupProcessData );
120     textSize = markupProcessData.markupProcessedText.size();
121
122     // This is a bit horrible but std::string returns a (signed) char*
123     utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
124   }
125   else
126   {
127     textSize = text.size();
128
129     // This is a bit horrible but std::string returns a (signed) char*
130     utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
131   }
132
133   // 1) Convert to utf32
134   Vector<Character>& utf32Characters = logicalModel->mText;
135   utf32Characters.Resize( textSize );
136
137   // Transform a text array encoded in utf8 into an array encoded in utf32.
138   // It returns the actual number of characters.
139   Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
140   utf32Characters.Resize( characterCount );
141
142   // 2) Set the break and paragraph info.
143   Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
144   lineBreakInfo.Resize( characterCount );
145
146   SetLineBreakInfo( utf32Characters,
147                     0u,
148                     characterCount,
149                     lineBreakInfo );
150
151   if( 0u == characterCount )
152   {
153     // Nothing else to do if the number of characters is zero.
154     return;
155   }
156
157   // 3) Set the script info.
158   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
159
160   Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
161   multilanguageSupport.SetScripts( utf32Characters,
162                                    0u,
163                                    characterCount,
164                                    scripts );
165
166   // 4) Set the font info
167   Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
168   fontDescriptionRuns = fontDescriptions;
169   Vector<FontRun>& validFonts = logicalModel->mFontRuns;
170
171   // The default font description.
172   TextAbstraction::FontDescription fontDescription;
173
174   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
175   fontClient.SetDpi( 96u, 96u );
176
177   // Validates the fonts. If there is a character with no assigned font it sets a default one.
178   // After this call, fonts are validated.
179   multilanguageSupport.ValidateFonts( utf32Characters,
180                                       scripts,
181                                       fontDescriptionRuns,
182                                       fontDescription,
183                                       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
184                                       0u,
185                                       characterCount,
186                                       validFonts );
187
188   // 5) Set the bidirectional info per paragraph.
189   Vector<Character> mirroredUtf32Characters;
190   bool textMirrored = false;
191
192   // Reserve some space for the vector of paragraph's bidirectional info.
193   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
194
195   // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
196   SetBidirectionalInfo( utf32Characters,
197                         scripts,
198                         lineBreakInfo,
199                         0u,
200                         characterCount,
201                         bidirectionalInfo );
202
203   // Create the paragraph info.
204   logicalModel->CreateParagraphInfo( 0u,
205                                      characterCount );
206
207   // 6) Set character directions.
208   Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
209   if( 0u != bidirectionalInfo.Count() )
210   {
211     // Only set the character directions if there is right to left characters.
212     GetCharactersDirection( bidirectionalInfo,
213                             characterCount,
214                             0u,
215                             characterCount,
216                             characterDirections );
217
218
219     // This paragraph has right to left text. Some characters may need to be mirrored.
220     textMirrored = GetMirroredText( utf32Characters,
221                                     characterDirections,
222                                     bidirectionalInfo,
223                                     0u,
224                                     characterCount,
225                                     mirroredUtf32Characters );
226   }
227   else
228   {
229     // There is no right to left characters. Clear the directions vector.
230     characterDirections.Clear();
231   }
232
233   // 7) Shape the text.
234
235   Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
236   Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
237   Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
238   Vector<GlyphIndex> newParagraphGlyphs;
239
240   const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
241
242   ShapeText( textToShape,
243              lineBreakInfo,
244              scripts,
245              validFonts,
246              0u,
247              0u,
248              characterCount,
249              glyphs,
250              glyphsToCharactersMap,
251              charactersPerGlyph,
252              newParagraphGlyphs );
253
254   // Create the 'number of glyphs' per character and the glyph to character conversion tables.
255   visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, characterCount );
256   visualModel->CreateCharacterToGlyphTable( 0u, 0u, characterCount );
257
258   const Length numberOfGlyphs = glyphs.Count();
259
260   // 8) Get the glyph metrics
261   metrics = Metrics::New( fontClient );
262
263   GlyphInfo* glyphsBuffer = glyphs.Begin();
264   metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
265
266   // Update the width and advance of all new paragraph characters.
267   for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
268          endIt = newParagraphGlyphs.End();
269        it != endIt;
270        ++it )
271   {
272     const GlyphIndex index = *it;
273     GlyphInfo& glyph = *( glyphsBuffer + index );
274
275     glyph.xBearing = 0.f;
276     glyph.width = 0.f;
277     glyph.advance = 0.f;
278   }
279
280   // 9) Layout the text
281   Layout::Engine layoutEngine;
282   layoutEngine.SetMetrics( metrics );
283   layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
284
285   // Set the layout parameters.
286   textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
287   textModel->mLineWrapMode = LineWrap::WORD;
288   textModel->mIgnoreSpacesAfterText = true;
289   textModel->mMatchSystemLanguageDirection = false;
290   Layout::Parameters layoutParameters( textArea,
291                                        textModel );
292
293   Vector<LineRun>& lines = visualModel->mLines;
294
295   Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
296   glyphPositions.Resize( numberOfGlyphs );
297
298   layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
299
300   // The initial glyph and the number of glyphs to layout.
301   layoutParameters.startGlyphIndex = 0u;
302   layoutParameters.numberOfGlyphs = numberOfGlyphs;
303   layoutParameters.startLineIndex = 0u;
304   layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
305
306   bool isAutoScroll = false;
307   layoutEngine.LayoutText( layoutParameters,
308                            layoutSize,
309                            false,
310                            isAutoScroll );
311
312   if( options.align )
313   {
314     float alignmentOffset = 0.f;
315     layoutEngine.Align( textArea,
316                         0u,
317                         characterCount,
318                         Text::HorizontalAlignment::BEGIN,
319                         lines,
320                         alignmentOffset,
321                         Dali::LayoutDirection::LEFT_TO_RIGHT,
322                         false );
323   }
324 }
325
326 void ConfigureTextLabel( ControllerPtr controller )
327 {
328   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
329   fontClient.SetDpi( 93u, 93u );
330
331   // Set the text layout as multi-line.
332   controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
333
334   // Set cursor's width to zero.
335   controller->GetLayoutEngine().SetCursorWidth( 0 );
336
337   InputMethodContext inputMethodContext = InputMethodContext::New();
338   // Disables the text input.
339   controller->EnableTextInput( NULL, inputMethodContext );
340
341   // Disables the vertical scrolling.
342   controller->SetVerticalScrollEnabled( false );
343
344   // Disables the horizontal scrolling.
345   controller->SetHorizontalScrollEnabled( false );
346
347   // Enable the text elide.
348   controller->SetTextElideEnabled( true );
349 }
350
351 void ConfigureTextField( ControllerPtr controller )
352 {
353   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
354   fontClient.SetDpi( 93u, 93u );
355
356   // Creates a decorator.
357   Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
358                                                        *controller );
359
360   // Set the text layout as multi-line.
361   controller->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
362
363   InputMethodContext inputMethodContext = InputMethodContext::New();
364   // Enables the text input.
365   controller->EnableTextInput( decorator, inputMethodContext );
366
367   // Enables the vertical scrolling after the text input has been enabled.
368   controller->SetVerticalScrollEnabled( false );
369
370   // Disables the horizontal scrolling.
371   controller->SetHorizontalScrollEnabled( true );
372
373   // No maximum number of characters.
374   controller->SetMaximumNumberOfCharacters( 50u );
375
376   // Disable the text elide.
377   controller->SetTextElideEnabled( false );
378 }
379
380 void ConfigureTextEditor( ControllerPtr controller )
381 {
382   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
383   fontClient.SetDpi( 93u, 93u );
384
385   // Creates a decorator.
386   Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
387                                                        *controller );
388
389   // Set the text layout as multi-line.
390   controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
391
392   InputMethodContext inputMethodContext = InputMethodContext::New();
393   // Enables the text input.
394   controller->EnableTextInput( decorator, inputMethodContext );
395
396   // Enables the vertical scrolling after the text input has been enabled.
397   controller->SetVerticalScrollEnabled( true );
398
399   // Disables the horizontal scrolling.
400   controller->SetHorizontalScrollEnabled( false );
401
402   // No maximum number of characters.
403   controller->SetMaximumNumberOfCharacters( std::numeric_limits<Length>::max() );
404
405   // Disable the text elide.
406   controller->SetTextElideEnabled( false );
407 }
408
409 } // namespace Text
410
411 } // namespace Toolkit
412
413 } // namespace Dali