Merge "TextController - Update the text model." into devel/master
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / 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/metrics.h>
29 #include <dali-toolkit/internal/text/multi-language-support.h>
30 #include <dali-toolkit/internal/text/segmentation.h>
31 #include <dali-toolkit/internal/text/shaper.h>
32 #include <dali-toolkit/internal/text/text-controller-impl.h>
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Text
41 {
42
43 /**
44  * @brief Frees previously allocated bidirectional resources.
45  *
46  * @param[in] bidirectionalLineInfo Bidirectional info per line.
47  * @param[in] index Index to the first line with bidirectional info to be freed.
48  */
49 void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
50                                          uint32_t index )
51 {
52   // Free the allocated memory used to store the conversion table in the bidirectional line info run.
53   for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
54          endIt = bidirectionalLineInfo.End();
55        it != endIt;
56        ++it )
57   {
58     BidirectionalLineInfoRun& bidiLineInfo = *it;
59
60     free( bidiLineInfo.visualToLogicalMap );
61   }
62 }
63
64 /**
65  * @brief Clear all the model data except for LogicalModel::mText.
66  *
67  * @param[in] characterIndex Clear data starting from the index.
68  */
69 void ClearModelData( CharacterIndex characterIndex,
70                      LogicalModelPtr logicalModel,
71                      VisualModelPtr visualModel )
72 {
73   // n.b. This does not Clear the mText from mLogicalModel
74
75   // Frees previously allocated resources.
76   FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
77
78   logicalModel->mScriptRuns.Clear();
79   logicalModel->mFontRuns.Clear();
80   logicalModel->mWordBreakInfo.Clear();
81   logicalModel->mBidirectionalParagraphInfo.Clear();
82   logicalModel->mCharacterDirections.Clear();
83   logicalModel->mBidirectionalLineInfo.Clear();
84   logicalModel->mLogicalToVisualMap.Clear();
85   logicalModel->mVisualToLogicalMap.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   visualModel->mColorRuns.Clear();
94
95   visualModel->ClearCaches();
96 }
97
98 void CreateTextModel( const std::string& text,
99                       const Size& textArea,
100                       const Vector<FontDescriptionRun>& fontDescriptions,
101                       const LayoutOptions& options,
102                       Size& layoutSize,
103                       LogicalModelPtr logicalModel,
104                       VisualModelPtr visualModel )
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 id.
154   FontDefaults fontDefaults;
155   fontDefaults.mFontDescription.family = "";
156   fontDefaults.familyDefined = true;
157   fontDefaults.mDefaultPointSize = 12.f;
158   fontDefaults.sizeDefined = true;
159
160   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
161   fontClient.SetDpi( 96u, 96u );
162
163   const FontId defaultFontId = fontDefaults.GetFontId( fontClient );
164
165   // Validates the fonts. If there is a character with no assigned font it sets a default one.
166   // After this call, fonts are validated.
167   multilanguageSupport.ValidateFonts( utf32Characters,
168                                       scripts,
169                                       fontDescriptionRuns,
170                                       defaultFontId,
171                                       0u,
172                                       numberOfCharacters,
173                                       validFonts );
174
175   // 5) Set the bidirectional info per paragraph.
176   Vector<Character> mirroredUtf32Characters;
177   bool textMirrored = false;
178
179   // Reserve some space for the vector of paragraph's bidirectional info.
180   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
181
182   // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
183   SetBidirectionalInfo( utf32Characters,
184                         scripts,
185                         lineBreakInfo,
186                         0u,
187                         numberOfCharacters,
188                         bidirectionalInfo );
189
190   // Create the paragraph info.
191   logicalModel->CreateParagraphInfo( 0u,
192                                      numberOfCharacters );
193
194   // 6) Set character directions.
195   Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
196   if( 0u != bidirectionalInfo.Count() )
197   {
198     // Only set the character directions if there is right to left characters.
199     GetCharactersDirection( bidirectionalInfo,
200                             numberOfCharacters,
201                             0u,
202                             numberOfCharacters,
203                             characterDirections );
204
205
206     // This paragraph has right to left text. Some characters may need to be mirrored.
207     textMirrored = GetMirroredText( utf32Characters,
208                                     characterDirections,
209                                     bidirectionalInfo,
210                                     0u,
211                                     numberOfCharacters,
212                                     mirroredUtf32Characters );
213   }
214   else
215   {
216     // There is no right to left characters. Clear the directions vector.
217     characterDirections.Clear();
218   }
219
220   // 7) Shape the text.
221
222   Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
223   Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
224   Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
225   Vector<GlyphIndex> newParagraphGlyphs;
226
227   const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
228
229   ShapeText( textToShape,
230              lineBreakInfo,
231              scripts,
232              validFonts,
233              0u,
234              0u,
235              numberOfCharacters,
236              glyphs,
237              glyphsToCharactersMap,
238              charactersPerGlyph,
239              newParagraphGlyphs );
240
241   // Create the 'number of glyphs' per character and the glyph to character conversion tables.
242   visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters );
243   visualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters );
244
245   const Length numberOfGlyphs = glyphs.Count();
246
247   // 8) Get the glyph metrics
248   MetricsPtr metrics = Metrics::New( fontClient );
249
250   GlyphInfo* glyphsBuffer = glyphs.Begin();
251   metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
252
253   // Update the width and advance of all new paragraph characters.
254   for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
255          endIt = newParagraphGlyphs.End();
256        it != endIt;
257        ++it )
258   {
259     const GlyphIndex index = *it;
260     GlyphInfo& glyph = *( glyphsBuffer + index );
261
262     glyph.xBearing = 0.f;
263     glyph.width = 0.f;
264     glyph.advance = 0.f;
265   }
266
267   // 9) Layout the text
268   LayoutEngine layoutEngine;
269   layoutEngine.SetMetrics( metrics );
270   layoutEngine.SetLayout( LayoutEngine::MULTI_LINE_BOX );
271
272   // Set the layout parameters.
273   const Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
274   const Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
275
276   LayoutParameters layoutParameters( textArea,
277                                      utf32Characters.Begin(),
278                                      lineBreakInfo.Begin(),
279                                      wordBreakInfo.Begin(),
280                                      ( 0u != characterDirections.Count() ) ? characterDirections.Begin() : NULL,
281                                      glyphs.Begin(),
282                                      glyphsToCharactersMap.Begin(),
283                                      charactersPerGlyph.Begin(),
284                                      charactersToGlyph.Begin(),
285                                      glyphsPerCharacter.Begin(),
286                                      numberOfGlyphs );
287
288   Vector<LineRun>& lines = visualModel->mLines;
289
290   Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
291   glyphPositions.Resize( numberOfGlyphs );
292
293   layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( numberOfCharacters - 1u ) ) );
294
295   // The initial glyph and the number of glyphs to layout.
296   layoutParameters.startGlyphIndex = 0u;
297   layoutParameters.numberOfGlyphs = numberOfGlyphs;
298   layoutParameters.startLineIndex = 0u;
299   layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
300
301   layoutEngine.LayoutText( layoutParameters,
302                            glyphPositions,
303                            lines,
304                            layoutSize );
305
306   // 10) Reorder the lines
307   if( 0u != bidirectionalInfo.Count() )
308   {
309     Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = logicalModel->mBidirectionalLineInfo;
310
311     // Get the lines
312     const Length numberOfLines = lines.Count();
313
314     // Reorder the lines.
315     bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
316     ReorderLines( bidirectionalInfo,
317                   0u,
318                   numberOfCharacters,
319                   lines,
320                   bidirectionalLineInfo );
321
322     // Set the bidirectional info per line into the layout parameters.
323     layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
324     layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
325
326     // Set the bidirectional info into the model.
327     logicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
328                                          layoutParameters.numberOfBidirectionalInfoRuns,
329                                          0u,
330                                          numberOfCharacters );
331
332     if( options.reorder )
333     {
334       // Re-layout the text. Reorder those lines with right to left characters.
335       layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
336                                              0u,
337                                              numberOfCharacters,
338                                              glyphPositions );
339     }
340   }
341
342   if( options.align )
343   {
344     layoutEngine.Align( textArea,
345                         0u,
346                         numberOfCharacters,
347                         lines );
348   }
349 }
350
351 } // namespace Text
352
353 } // namespace Toolkit
354
355 } // namespace Dali