Merge "TextModel interface" into new_text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / visual-model.cpp
1 /*
2  * Copyright (c) 2015 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 // CLASS HEADER
19 #include <dali-toolkit/internal/text/visual-model.h>
20
21 // EXTERNAL INCLUDES
22 #include <memory.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/math/vector2.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/text/line-run.h>
28
29 namespace Dali
30 {
31
32 namespace Toolkit
33 {
34
35 namespace Text
36 {
37
38 /**
39  * @brief caches some temporary values of the GetNumberOfLines( glyphIndex, numberOfGlyphs ) operation
40  * as they are going to be used in the GetLinesOfGlyphRange() call.
41  */
42 struct GetLineCache
43 {
44   GlyphIndex glyphIndex;     ///< The glyph index.
45   Length     numberOfGlyphs; ///< The number of glyphs.
46   Length     firstLine;      ///< Index to the first line.
47   Length     numberOfLines;  ///< The number of lines.
48 };
49
50 struct VisualModel::Impl
51 {
52   Vector<GlyphInfo>      mGlyphs;             ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
53   Vector<CharacterIndex> mGlyphsToCharacters; ///< For each glyph, the index of the first character.
54   Vector<GlyphIndex>     mCharactersToGlyph;  ///< For each character, the index of the first glyph.
55   Vector<Length>         mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph.
56   Vector<Length>         mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped.
57   Vector<Vector2>        mGlyphPositions;     ///< For each glyph, the position.
58   Vector<LineRun>        mLines;              ///< The laid out lines.
59
60   Size                   mNaturalSize;        ///< Size of the text with no line wrapping.
61   Size                   mActualSize;         ///< Size of the laid-out text considering the layout properties set.
62
63   GetLineCache           mGetLineCache;       ///< Caches the GetNumberOfLines( glyphIndex, numberOfGlyphs ) operation.
64 };
65
66 VisualModelPtr VisualModel::New()
67 {
68   return VisualModelPtr( new VisualModel() );
69 }
70
71 void VisualModel::SetGlyphs( const GlyphInfo* glyphs,
72                              const CharacterIndex* characterIndices,
73                              const Length* charactersPerGlyph,
74                              Length numberOfGlyphs )
75 {
76   Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
77   Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
78   Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
79   Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
80   Vector<Length>& modelGlyphsPerCharacter = mImpl->mGlyphsPerCharacter;
81
82   if( 0u == numberOfGlyphs )
83   {
84     modelGlyphs.Clear();
85     modelGlyphsToCharacters.Clear();
86     modelCharactersToGlyph.Clear();
87     modelCharactersPerGlyph.Clear();
88     modelGlyphsPerCharacter.Clear();
89   }
90   else
91   {
92     if( NULL != glyphs )
93     {
94       modelGlyphs.Resize( numberOfGlyphs );
95       memcpy( modelGlyphs.Begin(), glyphs, numberOfGlyphs * sizeof( GlyphInfo ) );
96     }
97
98     if( NULL != characterIndices )
99     {
100       modelGlyphsToCharacters.Resize( numberOfGlyphs );
101       memcpy( modelGlyphsToCharacters.Begin(), characterIndices, numberOfGlyphs * sizeof( CharacterIndex ) );
102     }
103
104     if( NULL != charactersPerGlyph )
105     {
106       modelCharactersPerGlyph.Resize( numberOfGlyphs );
107       memcpy( modelCharactersPerGlyph.Begin(), charactersPerGlyph, numberOfGlyphs * sizeof( Length ) );
108
109       // Build the characters to glyph conversion table.
110
111       // 1) Reserve some space for the characters to avoid reallocations.
112       const Length numberOfCharacters = static_cast<Length> ( static_cast<float>( numberOfGlyphs ) * 1.3f );
113       modelCharactersToGlyph.Reserve( numberOfCharacters );
114       modelGlyphsPerCharacter.Reserve( numberOfCharacters );
115
116       // 2) Traverse the glyphs and set the glyph indices and the glyphs per character.
117
118       // The number of 'characters per glyph' equal to zero.
119       Length zeroCharactersPerGlyph = 0u;
120
121       // Index to the glyph.
122       GlyphIndex glyphIndex = 0u;
123       for( Vector<Length>::ConstIterator it = modelCharactersPerGlyph.Begin(),
124              endIt = modelCharactersPerGlyph.End();
125            it != endIt;
126            ++it, ++glyphIndex )
127       {
128         const Length numberOfCharacters = *it;
129
130         // Set the glyph indices.
131         for( Length index = 0u; index < numberOfCharacters; ++index )
132         {
133           modelCharactersToGlyph.PushBack( glyphIndex );
134         }
135
136         // Set the glyphs per character.
137         if( 0u == numberOfCharacters )
138         {
139           ++zeroCharactersPerGlyph;
140         }
141         else
142         {
143           const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharacters - 1u );
144           for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter ; ++zeroIndex )
145           {
146             modelGlyphsPerCharacter.PushBack( 0u );
147           }
148
149           modelGlyphsPerCharacter.PushBack( 1u + zeroCharactersPerGlyph );
150
151           zeroCharactersPerGlyph = 0u;
152         }
153       }
154     }
155   }
156 }
157
158 Length VisualModel::GetNumberOfGlyphs() const
159 {
160   return mImpl->mGlyphs.Count();
161 }
162
163 void VisualModel::GetGlyphs( GlyphInfo* glyphs,
164                              GlyphIndex glyphIndex,
165                              Length numberOfGlyphs ) const
166 {
167   const Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
168   memcpy( glyphs, modelGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
169 }
170
171 const GlyphInfo& VisualModel::GetGlyphInfo( GlyphIndex glyphIndex ) const
172 {
173   return mImpl->mGlyphs[glyphIndex];
174 }
175
176 void VisualModel::ReplaceGlyphs( GlyphIndex glyphIndex,
177                                  Length numberOfGlyphsToRemove,
178                                  const GlyphInfo* const glyphs,
179                                  const Length* const numberOfCharacters,
180                                  Length numberOfGlyphsToInsert )
181 {
182 }
183
184 CharacterIndex VisualModel::GetCharacterIndex( GlyphIndex glyphIndex ) const
185 {
186   return mImpl->mGlyphsToCharacters[glyphIndex];
187 }
188
189 Length VisualModel::GetCharactersPerGlyph( GlyphIndex glyphIndex ) const
190 {
191   return mImpl->mCharactersPerGlyph[glyphIndex];
192 }
193
194 GlyphIndex VisualModel::GetGlyphIndex( CharacterIndex characterIndex ) const
195 {
196   return mImpl->mCharactersToGlyph[characterIndex];
197 }
198
199 void VisualModel::GetCharacterToGlyphMap( GlyphIndex* characterToGlyphMap,
200                                           CharacterIndex characterIndex,
201                                           Length numberOfCharacters ) const
202 {
203   const Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
204   memcpy( characterToGlyphMap, modelCharactersToGlyph.Begin() + characterIndex, numberOfCharacters * sizeof( GlyphIndex ) );
205 }
206
207 void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
208                                           GlyphIndex glyphIndex,
209                                           Length numberOfGlyphs ) const
210 {
211   const Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
212   memcpy( glyphToCharacter, modelGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
213 }
214
215 void VisualModel::GetCharactersPerGlyphMap( Length* charactersPerGlyph,
216                                             GlyphIndex glyphIndex,
217                                             Length numberOfGlyphs ) const
218 {
219   const Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
220   memcpy( charactersPerGlyph, modelCharactersPerGlyph.Begin() + glyphIndex, numberOfGlyphs * sizeof( Length ) );
221 }
222
223 void VisualModel::GetGlyphsPerCharacterMap( Length* glyphsPerCharacter,
224                                             CharacterIndex characterIndex,
225                                             Length numberOfCharacters ) const
226 {
227   const Vector<Length>& modelGlyphsPerCharacter = mImpl->mGlyphsPerCharacter;
228   memcpy( glyphsPerCharacter, modelGlyphsPerCharacter.Begin() + characterIndex, numberOfCharacters * sizeof( Length ) );
229 }
230
231 void VisualModel::SetGlyphPositions( const Vector2* glyphPositions,
232                                      Length numberOfGlyphs )
233 {
234   Vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
235   if( 0u == numberOfGlyphs )
236   {
237     modelPositions.Clear();
238   }
239   else
240   {
241     modelPositions.Resize( numberOfGlyphs );
242     memcpy( modelPositions.Begin(), glyphPositions, numberOfGlyphs * sizeof( Vector2 ) );
243   }
244 }
245
246 Length VisualModel::GetNumberOfGlyphPositions() const
247 {
248   return mImpl->mGlyphPositions.Count();
249 }
250
251 void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
252                                      GlyphIndex glyphIndex,
253                                      Length numberOfGlyphs ) const
254 {
255   const Vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
256   memcpy( glyphPositions, modelPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
257 }
258
259 const Vector2& VisualModel::GetGlyphPosition( GlyphIndex glyphIndex ) const
260 {
261   return *( mImpl->mGlyphPositions.Begin() + glyphIndex );
262 }
263
264 void VisualModel::ReplaceGlyphPositions( GlyphIndex glyphIndex,
265                                          Length numberOfGlyphsToRemove,
266                                          const Vector2* const positions,
267                                          Length numberOfGlyphsToInsert )
268 {
269 }
270
271 void VisualModel::SetLines( const LineRun* const lines,
272                             Length numberOfLines )
273 {
274   Vector<LineRun>& modelLines = mImpl->mLines;
275   GetLineCache& lineCache = mImpl->mGetLineCache;
276
277   if( 0u == numberOfLines )
278   {
279     modelLines.Clear();
280   }
281   else
282   {
283     modelLines.Resize( numberOfLines );
284     memcpy( modelLines.Begin(), lines, numberOfLines * sizeof( LineRun ) );
285   }
286
287   // Clear the get line cache.
288   lineCache.glyphIndex = 0u;
289   lineCache.numberOfGlyphs = 0u;
290   lineCache.firstLine = 0u;
291   lineCache.numberOfLines = 0u;
292 }
293
294 Length VisualModel::GetNumberOfLines() const
295 {
296   return mImpl->mLines.Count();
297 }
298
299 void VisualModel::GetLines( LineRun* lines,
300                             LineIndex lineIndex,
301                             Length numberOfLines ) const
302 {
303   const Vector<LineRun>& modelLines = mImpl->mLines;
304   memcpy( lines, modelLines.Begin() + lineIndex, numberOfLines * sizeof( LineRun ) );
305 }
306
307 Length VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
308                                       Length numberOfGlyphs ) const
309 {
310   // If is likely the user query consecutively for the number of lines with the same
311   // glyph index and number of glyphs, use the cache could be considered.
312   GetLineCache& lineCache = mImpl->mGetLineCache;
313
314   // Cache the glyph index and number of glyphs to be used in the GetLinesOfGlyphRange().
315   lineCache.glyphIndex = glyphIndex;
316   lineCache.numberOfGlyphs = numberOfGlyphs;
317
318   // Check first if the query is for the total number of glyphs.
319   const Length totalNumberOfGlyphs = mImpl->mGlyphs.Count();
320
321   if( ( 0u == glyphIndex ) &&
322       ( totalNumberOfGlyphs == numberOfGlyphs ) )
323   {
324     lineCache.firstLine = 0u;
325     lineCache.numberOfLines = mImpl->mLines.Count();
326
327     return lineCache.numberOfLines;
328   }
329
330   // Initialize the number of lines and the first line.
331   lineCache.numberOfLines = 0u;
332   lineCache.firstLine = 0u;
333   bool firstLineFound = false;
334
335   const Vector<LineRun>& modelLines = mImpl->mLines;
336   const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
337
338   // Traverse the lines and count those lines within the range of glyphs.
339   for( Vector<LineRun>::ConstIterator it = modelLines.Begin(),
340          endIt = modelLines.End();
341        it != endIt;
342        ++it )
343   {
344     const LineRun& line = *it;
345
346     if( ( line.glyphIndex + line.numberOfGlyphs > glyphIndex ) &&
347         ( lastGlyphIndex > line.glyphIndex ) )
348     {
349       firstLineFound = true;
350       ++lineCache.numberOfLines;
351     }
352     else if( lastGlyphIndex <= line.glyphIndex )
353     {
354       // nothing else to do.
355       break;
356     }
357
358     if( !firstLineFound )
359     {
360       ++lineCache.firstLine;
361     }
362   }
363
364   return lineCache.numberOfLines;
365 }
366
367 void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
368                                         GlyphIndex glyphIndex,
369                                         Length numberOfGlyphs ) const
370 {
371   const Vector<LineRun>& modelLines = mImpl->mLines;
372   GetLineCache& lineCache = mImpl->mGetLineCache;
373
374   if( ( glyphIndex != lineCache.glyphIndex ) ||
375       ( numberOfGlyphs != lineCache.numberOfGlyphs ) )
376   {
377     GetNumberOfLines( glyphIndex,
378                       numberOfGlyphs );
379   }
380
381   memcpy( lines, modelLines.Begin() + lineCache.firstLine, lineCache.numberOfLines * sizeof( LineRun ) );
382 }
383
384 void VisualModel::ReplaceLines( GlyphIndex glyphIndex,
385                                 Length numberOfGlyphsToRemove,
386                                 const LineRun* const lines,
387                                 Length numberOfGlyphsToInsert )
388 {
389 }
390
391 void VisualModel::SetNaturalSize( const Vector2& size  )
392 {
393   mImpl->mNaturalSize = size;
394 }
395
396 const Vector2& VisualModel::GetNaturalSize() const
397 {
398   return mImpl->mNaturalSize;
399 }
400
401 void VisualModel::SetActualSize( const Vector2& size )
402 {
403   mImpl->mActualSize = size;
404 }
405
406 const Vector2& VisualModel::GetActualSize() const
407 {
408   return mImpl->mActualSize;
409 }
410
411 VisualModel::~VisualModel()
412 {
413   delete mImpl;
414 }
415
416 VisualModel::VisualModel()
417 : mImpl( NULL )
418 {
419   mImpl = new VisualModel::Impl();
420 }
421
422 } // namespace Text
423
424 } // namespace Toolkit
425
426 } // namespace Dali