Merge "Move TextSelectionPopup from public to devel" into tizen
[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 void VisualModel::SetUnderlineHeight( float height )
445 {
446   mUnderlineHeight = height;
447 }
448
449 const Vector4& VisualModel::GetTextColor() const
450 {
451   return mTextColor;
452 }
453
454 const Vector2& VisualModel::GetShadowOffset() const
455 {
456   return mShadowOffset;
457 }
458
459 const Vector4& VisualModel::GetShadowColor() const
460 {
461   return mShadowColor;
462 }
463
464 const Vector4& VisualModel::GetUnderlineColor() const
465 {
466   return mUnderlineColor;
467 }
468
469 bool VisualModel::IsUnderlineEnabled() const
470 {
471   return mUnderlineEnabled;
472 }
473
474 float VisualModel::GetUnderlineHeight() const
475 {
476   return mUnderlineHeight;
477 }
478
479 void VisualModel::ClearCaches()
480 {
481   mCachedLineIndex = 0u;
482 }
483
484 VisualModel::~VisualModel()
485 {
486 }
487
488 VisualModel::VisualModel()
489 : mGlyphs(),
490   mGlyphsToCharacters(),
491   mCharactersToGlyph(),
492   mCharactersPerGlyph(),
493   mGlyphsPerCharacter(),
494   mGlyphPositions(),
495   mLines(),
496   mTextColor( Color::BLACK ),
497   mShadowColor( Color::BLACK ),
498   mUnderlineColor( Color::BLACK ),
499   mShadowOffset( Vector2::ZERO ),
500   mUnderlineHeight( 0.0f ),
501   mNaturalSize(),
502   mActualSize(),
503   mCachedLineIndex( 0u ),
504   mUnderlineEnabled( false ),
505   mUnderlineColorSet( false )
506 {
507 }
508
509 } // namespace Text
510
511 } // namespace Toolkit
512
513 } // namespace Dali