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