c0701796da42a80fef22fd0a4f8ca3be8c76da29
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / visual-model-impl.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-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <memory.h>
23 #include <dali/public-api/math/vector2.h>
24
25 namespace Dali
26 {
27
28 namespace Toolkit
29 {
30
31 namespace Text
32 {
33
34 VisualModelPtr VisualModel::New()
35 {
36   return VisualModelPtr( new VisualModel() );
37 }
38
39 void VisualModel::SetGlyphs( const GlyphInfo* glyphs,
40                              const CharacterIndex* characterIndices,
41                              const Length* charactersPerGlyph,
42                              Length numberOfGlyphs )
43 {
44   if( 0u == numberOfGlyphs )
45   {
46     mGlyphs.Clear();
47     mGlyphsToCharacters.Clear();
48     mCharactersToGlyph.Clear();
49     mCharactersPerGlyph.Clear();
50     mGlyphsPerCharacter.Clear();
51   }
52   else
53   {
54     if( NULL != glyphs )
55     {
56       mGlyphs.Resize( numberOfGlyphs );
57       memcpy( mGlyphs.Begin(), glyphs, numberOfGlyphs * sizeof( GlyphInfo ) );
58     }
59
60     if( NULL != characterIndices )
61     {
62       mGlyphsToCharacters.Resize( numberOfGlyphs );
63       memcpy( mGlyphsToCharacters.Begin(), characterIndices, numberOfGlyphs * sizeof( CharacterIndex ) );
64     }
65
66     if( NULL != charactersPerGlyph )
67     {
68       mCharactersPerGlyph.Resize( numberOfGlyphs );
69       memcpy( mCharactersPerGlyph.Begin(), charactersPerGlyph, numberOfGlyphs * sizeof( Length ) );
70
71       // Build the glyphs per character table.
72       CreateGlyphsPerCharacterTable();
73
74       // Build the characters to glyph conversion table.
75       CreateCharacterToGlyphTable();
76     }
77   }
78 }
79
80 void VisualModel::CreateCharacterToGlyphTable( Length numberOfCharacters )
81 {
82   // 1) Reserve some space for the characters to avoid reallocations.
83   if( 0u == numberOfCharacters )
84   {
85     // If no number of characters is given, just set something sensible to avoid reallocations.
86     numberOfCharacters = static_cast<Length> ( static_cast<float>( mGlyphs.Count() ) * 1.3f );
87   }
88   mCharactersToGlyph.Reserve( numberOfCharacters );
89
90   DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u ||
91                      ( 0u == numberOfCharacters ) );
92
93   const Length* const glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin();
94
95   // 2) Traverse the glyphs and set the glyph indices per character.
96
97   // Index to the glyph.
98   GlyphIndex glyphIndex = 0u;
99   CharacterIndex characterIndex = 0u;
100   for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin(),
101          endIt = mCharactersPerGlyph.End();
102        it != endIt;
103        ++it )
104   {
105     const Length numberOfCharactersPerGlyph = *it;
106
107     Length numberOfGlyphs = 0u;
108     // Set the glyph indices.
109     for( Length index = 0u; index < numberOfCharactersPerGlyph; ++index, ++characterIndex )
110     {
111       mCharactersToGlyph.PushBack( glyphIndex );
112       numberOfGlyphs += *( glyphsPerCharacterBuffer + characterIndex );
113     }
114     glyphIndex += numberOfGlyphs;
115   }
116 }
117
118 void VisualModel::CreateGlyphsPerCharacterTable( Length numberOfCharacters )
119 {
120   // 1) Reserve some space for the characters to avoid reallocations.
121   if( 0u == numberOfCharacters )
122   {
123     // If no number of characters is given, just set something sensible to avoid reallocations.
124     numberOfCharacters = static_cast<Length> ( static_cast<float>( mGlyphs.Count() ) * 1.3f );
125   }
126   mGlyphsPerCharacter.Reserve( numberOfCharacters );
127
128   // 2) Traverse the glyphs and set the number of glyphs per character.
129
130   // The number of 'characters per glyph' equal to zero.
131   Length zeroCharactersPerGlyph = 0u;
132
133   for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin(),
134          endIt = mCharactersPerGlyph.End();
135        it != endIt;
136        ++it )
137   {
138     const Length numberOfCharactersPerGlyph = *it;
139
140     // Set the glyphs per character.
141     if( 0u == numberOfCharactersPerGlyph )
142     {
143       ++zeroCharactersPerGlyph;
144     }
145     else
146     {
147       const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharactersPerGlyph - 1u );
148       for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter ; ++zeroIndex )
149       {
150         mGlyphsPerCharacter.PushBack( 0u );
151       }
152
153       mGlyphsPerCharacter.PushBack( 1u + zeroCharactersPerGlyph );
154
155       zeroCharactersPerGlyph = 0u;
156     }
157   }
158 }
159
160 Length VisualModel::GetNumberOfGlyphs() const
161 {
162   return mGlyphs.Count();
163 }
164
165 void VisualModel::GetGlyphs( GlyphInfo* glyphs,
166                              GlyphIndex glyphIndex,
167                              Length numberOfGlyphs ) const
168 {
169   memcpy( glyphs, mGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
170 }
171
172 const GlyphInfo& VisualModel::GetGlyphInfo( GlyphIndex glyphIndex ) const
173 {
174   return mGlyphs[glyphIndex];
175 }
176
177 void VisualModel::ReplaceGlyphs( GlyphIndex glyphIndex,
178                                  Length numberOfGlyphsToRemove,
179                                  const GlyphInfo* const glyphs,
180                                  const Length* const numberOfCharacters,
181                                  Length numberOfGlyphsToInsert )
182 {
183 }
184
185 CharacterIndex VisualModel::GetCharacterIndex( GlyphIndex glyphIndex ) const
186 {
187   return mGlyphsToCharacters[glyphIndex];
188 }
189
190 Length VisualModel::GetCharactersPerGlyph( GlyphIndex glyphIndex ) const
191 {
192   return mCharactersPerGlyph[glyphIndex];
193 }
194
195 GlyphIndex VisualModel::GetGlyphIndex( CharacterIndex characterIndex ) const
196 {
197   return mCharactersToGlyph[characterIndex];
198 }
199
200 void VisualModel::GetCharacterToGlyphMap( GlyphIndex* characterToGlyphMap,
201                                           CharacterIndex characterIndex,
202                                           Length numberOfCharacters ) const
203 {
204   memcpy( characterToGlyphMap, mCharactersToGlyph.Begin() + characterIndex, numberOfCharacters * sizeof( GlyphIndex ) );
205 }
206
207 void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
208                                           GlyphIndex glyphIndex,
209                                           Length numberOfGlyphs ) const
210 {
211   memcpy( glyphToCharacter, mGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
212 }
213
214 void VisualModel::GetCharactersPerGlyphMap( Length* charactersPerGlyph,
215                                             GlyphIndex glyphIndex,
216                                             Length numberOfGlyphs ) const
217 {
218   memcpy( charactersPerGlyph, mCharactersPerGlyph.Begin() + glyphIndex, numberOfGlyphs * sizeof( Length ) );
219 }
220
221 void VisualModel::GetGlyphsPerCharacterMap( Length* glyphsPerCharacter,
222                                             CharacterIndex characterIndex,
223                                             Length numberOfCharacters ) const
224 {
225   memcpy( glyphsPerCharacter, mGlyphsPerCharacter.Begin() + characterIndex, numberOfCharacters * sizeof( Length ) );
226 }
227
228 void VisualModel::SetGlyphPositions( const Vector2* glyphPositions,
229                                      Length numberOfGlyphs )
230 {
231   if( 0u == numberOfGlyphs )
232   {
233     mGlyphPositions.Clear();
234   }
235   else
236   {
237     mGlyphPositions.Resize( numberOfGlyphs );
238     memcpy( mGlyphPositions.Begin(), glyphPositions, numberOfGlyphs * sizeof( Vector2 ) );
239   }
240 }
241
242 Length VisualModel::GetNumberOfGlyphPositions() const
243 {
244   return mGlyphPositions.Count();
245 }
246
247 void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
248                                      GlyphIndex glyphIndex,
249                                      Length numberOfGlyphs ) const
250 {
251   memcpy( glyphPositions, mGlyphPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
252 }
253
254 const Vector2& VisualModel::GetGlyphPosition( GlyphIndex glyphIndex ) const
255 {
256   return *( mGlyphPositions.Begin() + glyphIndex );
257 }
258
259 void VisualModel::ReplaceGlyphPositions( GlyphIndex glyphIndex,
260                                          Length numberOfGlyphsToRemove,
261                                          const Vector2* const positions,
262                                          Length numberOfGlyphsToInsert )
263 {
264 }
265
266 void VisualModel::SetLines( const LineRun* const lines,
267                             Length numberOfLines )
268 {
269   if( 0u == numberOfLines )
270   {
271     mLines.Clear();
272   }
273   else
274   {
275     mLines.Resize( numberOfLines );
276     memcpy( mLines.Begin(), lines, numberOfLines * sizeof( LineRun ) );
277   }
278 }
279
280 Length VisualModel::GetNumberOfLines() const
281 {
282   return mLines.Count();
283 }
284
285 void VisualModel::GetLines( LineRun* lines,
286                             LineIndex lineIndex,
287                             Length numberOfLines ) const
288 {
289   memcpy( lines, mLines.Begin() + lineIndex, numberOfLines * sizeof( LineRun ) );
290 }
291
292 void VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
293                                     Length numberOfGlyphs,
294                                     LineIndex& firstLine,
295                                     Length& numberOfLines ) const
296 {
297   // Initialize the number of lines and the first line.
298   firstLine = 0u;
299   numberOfLines = 0u;
300   bool firstLineFound = false;
301
302   const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
303
304   // Traverse the lines and count those lines within the range of glyphs.
305   for( Vector<LineRun>::ConstIterator it = mLines.Begin(),
306          endIt = mLines.End();
307        it != endIt;
308        ++it )
309   {
310     const LineRun& line = *it;
311
312     if( ( line.glyphIndex + line.numberOfGlyphs > glyphIndex ) &&
313         ( lastGlyphIndex > line.glyphIndex ) )
314     {
315       firstLineFound = true;
316       ++numberOfLines;
317     }
318     else if( lastGlyphIndex <= line.glyphIndex )
319     {
320       // nothing else to do.
321       break;
322     }
323
324     if( !firstLineFound )
325     {
326       ++firstLine;
327     }
328   }
329 }
330
331 void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
332                                         GlyphIndex glyphIndex,
333                                         Length numberOfGlyphs ) const
334 {
335   LineIndex firstLine = 0u;
336   Length numberOfLines = 0u;
337
338   GetNumberOfLines( glyphIndex,
339                     numberOfGlyphs,
340                     firstLine,
341                     numberOfLines );
342
343   memcpy( lines, mLines.Begin() + firstLine, numberOfLines * sizeof( LineRun ) );
344 }
345
346 LineIndex VisualModel::GetLineOfGlyph( GlyphIndex glyphIndex )
347 {
348   const CharacterIndex characterIndex = *( mGlyphsToCharacters.Begin() + glyphIndex );
349
350   return GetLineOfCharacter( characterIndex );
351 }
352
353 LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
354 {
355   // 1) Check first in the cached line.
356
357   const LineRun& lineRun = *( mLines.Begin() + mCachedLineIndex );
358
359   if( ( lineRun.characterRun.characterIndex <= characterIndex ) &&
360       ( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters ) )
361   {
362     return mCachedLineIndex;
363   }
364
365   // 2) Is not in the cached line. Check in the other lines.
366
367   LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
368
369   for( Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
370          endIt = mLines.End();
371        it != endIt;
372        ++it, ++index )
373   {
374     const LineRun& lineRun = *it;
375
376     if( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters )
377     {
378       mCachedLineIndex = index;
379       break;
380     }
381   }
382
383   return index;
384 }
385
386 void VisualModel::ReplaceLines( GlyphIndex glyphIndex,
387                                 Length numberOfGlyphsToRemove,
388                                 const LineRun* const lines,
389                                 Length numberOfGlyphsToInsert )
390 {
391 }
392
393 void VisualModel::SetNaturalSize( const Vector2& size  )
394 {
395   mNaturalSize = size;
396 }
397
398 const Vector2& VisualModel::GetNaturalSize() const
399 {
400   return mNaturalSize;
401 }
402
403 void VisualModel::SetActualSize( const Vector2& size )
404 {
405   mActualSize = size;
406 }
407
408 const Vector2& VisualModel::GetActualSize() const
409 {
410   return mActualSize;
411 }
412
413 void VisualModel::SetTextColor( const Vector4& textColor )
414 {
415   mTextColor = textColor;
416
417   if ( !mUnderlineColorSet )
418   {
419     mUnderlineColor = textColor;
420   }
421 }
422
423 void VisualModel::SetShadowOffset( const Vector2& shadowOffset )
424 {
425   mShadowOffset = shadowOffset;
426 }
427
428 void VisualModel::SetShadowColor( const Vector4& shadowColor )
429 {
430   mShadowColor = shadowColor;
431 }
432
433 void VisualModel::SetUnderlineColor( const Vector4& color )
434 {
435   mUnderlineColor = color;
436   mUnderlineColorSet = true;
437 }
438
439 void VisualModel::SetUnderlineEnabled( bool enabled )
440 {
441   mUnderlineEnabled = enabled;
442 }
443
444 const Vector4& VisualModel::GetTextColor() const
445 {
446   return mTextColor;
447 }
448
449 const Vector2& VisualModel::GetShadowOffset() const
450 {
451   return mShadowOffset;
452 }
453
454 const Vector4& VisualModel::GetShadowColor() const
455 {
456   return mShadowColor;
457 }
458
459 const Vector4& VisualModel::GetUnderlineColor() const
460 {
461   return mUnderlineColor;
462 }
463
464 bool VisualModel::IsUnderlineEnabled() const
465 {
466   return mUnderlineEnabled;
467 }
468
469 void VisualModel::ClearCaches()
470 {
471   mCachedLineIndex = 0u;
472 }
473
474 VisualModel::~VisualModel()
475 {
476 }
477
478 VisualModel::VisualModel()
479 : mGlyphs(),
480   mGlyphsToCharacters(),
481   mCharactersToGlyph(),
482   mCharactersPerGlyph(),
483   mGlyphsPerCharacter(),
484   mGlyphPositions(),
485   mLines(),
486   mTextColor(),
487   mShadowColor(),
488   mUnderlineColor(),
489   mShadowOffset(),
490   mNaturalSize(),
491   mActualSize(),
492   mCachedLineIndex( 0u ),
493   mUnderlineEnabled( false ),
494   mUnderlineColorSet( false )
495 {
496 }
497
498 } // namespace Text
499
500 } // namespace Toolkit
501
502 } // namespace Dali