[dali_1.3.6] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / visual-model-impl.cpp
1 /*
2  * Copyright (c) 2017 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
24 namespace Dali
25 {
26
27 namespace Toolkit
28 {
29
30 namespace Text
31 {
32
33 VisualModelPtr VisualModel::New()
34 {
35   return VisualModelPtr( new VisualModel() );
36 }
37
38 void VisualModel::CreateCharacterToGlyphTable( CharacterIndex startIndex,
39                                                GlyphIndex startGlyphIndex,
40                                                Length numberOfCharacters )
41 {
42   if( 0u == numberOfCharacters )
43   {
44     // Nothing to do.
45     return;
46   }
47
48   DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u );
49
50   // Get the total number of characters.
51   const Length totalNumberOfCharacters = ( 0u == mGlyphsToCharacters.Count() ) ? 0u : *( mGlyphsToCharacters.End() - 1u ) + *( mCharactersPerGlyph.End() - 1u ); // Index to the first character + the number of characters that form the last glyph.
52
53   // Whether the current buffer is being updated or is set from scratch.
54   const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
55
56   Vector<GlyphIndex> newCharactersToGlyph;
57   GlyphIndex* charactersToGlyphBuffer = NULL;
58
59   // 1) Reserve some space for the glyph indices to avoid reallocations.
60   if( updateCurrentBuffer )
61   {
62     newCharactersToGlyph.Resize( numberOfCharacters );
63     charactersToGlyphBuffer = newCharactersToGlyph.Begin();
64   }
65   else
66   {
67     mCharactersToGlyph.Resize( numberOfCharacters );
68     charactersToGlyphBuffer = mCharactersToGlyph.Begin() + startIndex;
69   }
70
71   const Length* const glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin();
72
73   // 2) Traverse the glyphs and set the glyph indices per character.
74
75   // Index to the glyph.
76   GlyphIndex glyphIndex = startGlyphIndex;
77   CharacterIndex characterIndex = startIndex;
78   const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters;
79   for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin() + glyphIndex,
80          endIt = mCharactersPerGlyph.End();
81        ( it != endIt ) && ( characterIndex < lastCharacterIndexPlusOne );
82        ++it )
83   {
84     const Length numberOfCharactersPerGlyph = *it;
85
86     Length numberOfGlyphs = 0u;
87     // Set the glyph indices.
88     for( Length index = 0u; index < numberOfCharactersPerGlyph; ++index, ++characterIndex )
89     {
90       *charactersToGlyphBuffer = glyphIndex;
91       numberOfGlyphs += *( glyphsPerCharacterBuffer + characterIndex );
92       ++charactersToGlyphBuffer;
93     }
94     glyphIndex += numberOfGlyphs;
95   }
96
97   // If the character to glyph buffer is updated, it needs to be inserted in the model.
98   if( updateCurrentBuffer )
99   {
100     // Update the indices.
101     const Length numberOfGlyphs = glyphIndex - startGlyphIndex;
102     for( Vector<Length>::Iterator it = mCharactersToGlyph.Begin() + startIndex,
103            endIt = mCharactersToGlyph.End();
104          it != endIt;
105          ++it )
106     {
107       *it += numberOfGlyphs;
108     }
109
110     mCharactersToGlyph.Insert( mCharactersToGlyph.Begin() + startIndex,
111                                newCharactersToGlyph.Begin(),
112                                newCharactersToGlyph.End() );
113
114   }
115 }
116
117 void VisualModel::CreateGlyphsPerCharacterTable( CharacterIndex startIndex,
118                                                  GlyphIndex startGlyphIndex,
119                                                  Length numberOfCharacters )
120 {
121   if( 0u == numberOfCharacters )
122   {
123     // Nothing to do.
124     return;
125   }
126
127   // Get the total number of characters.
128   const Length totalNumberOfCharacters = ( 0u == mGlyphsToCharacters.Count() ) ? 0u : *( mGlyphsToCharacters.End() - 1u ) + *( mCharactersPerGlyph.End() - 1u ); // Index to the first character + the number of characters that form the last glyph.
129
130   // Whether the current buffer is being updated or is set from scratch.
131   const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
132
133   Vector<Length> newGlyphsPerCharacter;
134   Length* glyphsPerCharacterBuffer = NULL;
135
136   // 1) Reserve some space for the glyphs per character to avoid reallocations.
137   if( updateCurrentBuffer )
138   {
139     newGlyphsPerCharacter.Resize( numberOfCharacters );
140     glyphsPerCharacterBuffer = newGlyphsPerCharacter.Begin();
141   }
142   else
143   {
144     mGlyphsPerCharacter.Resize( numberOfCharacters );
145     glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin() + startIndex;
146   }
147
148   // 2) Traverse the glyphs and set the number of glyphs per character.
149
150   Length traversedCharacters = 0;
151
152   // The number of 'characters per glyph' equal to zero.
153   Length zeroCharactersPerGlyph = 0u;
154
155   for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin() + startGlyphIndex,
156          endIt = mCharactersPerGlyph.End();
157        ( it != endIt ) && ( traversedCharacters < numberOfCharacters );
158        ++it )
159   {
160     const Length numberOfCharactersPerGlyph = *it;
161     traversedCharacters += numberOfCharactersPerGlyph;
162
163     // Set the glyphs per character.
164     if( 0u == numberOfCharactersPerGlyph )
165     {
166       ++zeroCharactersPerGlyph;
167     }
168     else
169     {
170       const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharactersPerGlyph - 1u );
171       for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter; ++zeroIndex )
172       {
173         *glyphsPerCharacterBuffer = 0u;
174
175         // Point to the next position in the buffer.
176         ++glyphsPerCharacterBuffer;
177       }
178
179       *glyphsPerCharacterBuffer = zeroCharactersPerGlyph + 1u;
180
181       zeroCharactersPerGlyph = 0u;
182
183       // Point to the next position in the buffer.
184       ++glyphsPerCharacterBuffer;
185     }
186   }
187
188   // If the glyphs per character buffer is updated, it needs to be inserted in the model.
189   if( updateCurrentBuffer )
190   {
191     mGlyphsPerCharacter.Insert( mGlyphsPerCharacter.Begin() + startIndex,
192                                 newGlyphsPerCharacter.Begin(),
193                                 newGlyphsPerCharacter.End() );
194   }
195 }
196
197 void VisualModel::GetGlyphs( GlyphInfo* glyphs,
198                              GlyphIndex glyphIndex,
199                              Length numberOfGlyphs ) const
200 {
201   memcpy( glyphs, mGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
202 }
203
204 void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
205                                      GlyphIndex glyphIndex,
206                                      Length numberOfGlyphs ) const
207 {
208   memcpy( glyphPositions, mGlyphPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
209 }
210
211 void VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
212                                     Length numberOfGlyphs,
213                                     LineIndex& firstLine,
214                                     Length& numberOfLines ) const
215 {
216   // Initialize the number of lines and the first line.
217   firstLine = 0u;
218   numberOfLines = 0u;
219   bool firstLineFound = false;
220
221   const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
222
223   // Traverse the lines and count those lines within the range of glyphs.
224   for( Vector<LineRun>::ConstIterator it = mLines.Begin(),
225          endIt = mLines.End();
226        it != endIt;
227        ++it )
228   {
229     const LineRun& line = *it;
230
231     if( ( line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs > glyphIndex ) &&
232         ( lastGlyphIndex > line.glyphRun.glyphIndex ) )
233     {
234       firstLineFound = true;
235       ++numberOfLines;
236     }
237     else if( lastGlyphIndex <= line.glyphRun.glyphIndex )
238     {
239       // nothing else to do.
240       break;
241     }
242
243     if( !firstLineFound )
244     {
245       ++firstLine;
246     }
247   }
248 }
249
250 void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
251                                         GlyphIndex glyphIndex,
252                                         Length numberOfGlyphs ) const
253 {
254   LineIndex firstLine = 0u;
255   Length numberOfLines = 0u;
256
257   GetNumberOfLines( glyphIndex,
258                     numberOfGlyphs,
259                     firstLine,
260                     numberOfLines );
261
262   memcpy( lines, mLines.Begin() + firstLine, numberOfLines * sizeof( LineRun ) );
263 }
264
265 LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
266 {
267   // 1) Check line is empty or not.
268   if( mLines.Empty() )
269   {
270     return 0u;
271   }
272
273   // 2) Check in the cached line.
274   const LineRun& lineRun = *( mLines.Begin() + mCachedLineIndex );
275   if( ( lineRun.characterRun.characterIndex <= characterIndex ) &&
276       ( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters ) )
277   {
278     return mCachedLineIndex;
279   }
280
281   // 3) Is not in the cached line. Check in the other lines.
282   LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
283
284   for( Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
285          endIt = mLines.End();
286        it != endIt;
287        ++it, ++index )
288   {
289     const LineRun& lineRun = *it;
290
291     if( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters )
292     {
293       mCachedLineIndex = index;
294       break;
295     }
296   }
297
298   return index;
299 }
300
301 void VisualModel::GetUnderlineRuns( GlyphRun* underlineRuns,
302                                     UnderlineRunIndex index,
303                                     Length numberOfRuns ) const
304 {
305   memcpy( underlineRuns,
306           mUnderlineRuns.Begin() + index,
307           numberOfRuns * sizeof( GlyphRun ) );
308 }
309
310 void VisualModel::SetNaturalSize( const Vector2& size  )
311 {
312   mNaturalSize = size;
313 }
314
315 const Vector2& VisualModel::GetNaturalSize() const
316 {
317   return mNaturalSize;
318 }
319
320 void VisualModel::SetLayoutSize( const Vector2& size )
321 {
322   mLayoutSize = size;
323 }
324
325 const Vector2& VisualModel::GetLayoutSize() const
326 {
327   return mLayoutSize;
328 }
329
330 void VisualModel::SetTextColor( const Vector4& textColor )
331 {
332   mTextColor = textColor;
333
334   if ( !mUnderlineColorSet )
335   {
336     mUnderlineColor = textColor;
337   }
338 }
339
340 void VisualModel::SetShadowOffset( const Vector2& shadowOffset )
341 {
342   mShadowOffset = shadowOffset;
343 }
344
345 void VisualModel::SetShadowColor( const Vector4& shadowColor )
346 {
347   mShadowColor = shadowColor;
348 }
349
350 void VisualModel::SetShadowBlurRadius( const float& shadowBlurRadius )
351 {
352   mShadowBlurRadius = shadowBlurRadius;
353 }
354
355 void VisualModel::SetUnderlineColor( const Vector4& color )
356 {
357   mUnderlineColor = color;
358   mUnderlineColorSet = true;
359 }
360
361 void VisualModel::SetOutlineColor( const Vector4& color )
362 {
363   mOutlineColor = color;
364 }
365
366 void VisualModel::SetUnderlineEnabled( bool enabled )
367 {
368   mUnderlineEnabled = enabled;
369 }
370
371 void VisualModel::SetUnderlineHeight( float height )
372 {
373   mUnderlineHeight = height;
374 }
375
376 void VisualModel::SetOutlineWidth( unsigned int width )
377 {
378   mOutlineWidth = width;
379 }
380
381 const Vector4& VisualModel::GetTextColor() const
382 {
383   return mTextColor;
384 }
385
386 const Vector2& VisualModel::GetShadowOffset() const
387 {
388   return mShadowOffset;
389 }
390
391 const Vector4& VisualModel::GetShadowColor() const
392 {
393   return mShadowColor;
394 }
395
396 const float& VisualModel::GetShadowBlurRadius() const
397 {
398   return mShadowBlurRadius;
399 }
400
401 const Vector4& VisualModel::GetUnderlineColor() const
402 {
403   return mUnderlineColor;
404 }
405
406 const Vector4& VisualModel::GetOutlineColor() const
407 {
408   return mOutlineColor;
409 }
410
411 bool VisualModel::IsUnderlineEnabled() const
412 {
413   return mUnderlineEnabled;
414 }
415
416 float VisualModel::GetUnderlineHeight() const
417 {
418   return mUnderlineHeight;
419 }
420
421 unsigned int VisualModel::GetOutlineWidth() const
422 {
423   return mOutlineWidth;
424 }
425
426 Length VisualModel::GetNumberOfUnderlineRuns() const
427 {
428   return mUnderlineRuns.Count();
429 }
430
431 void VisualModel::ClearCaches()
432 {
433   mCachedLineIndex = 0u;
434 }
435
436 VisualModel::~VisualModel()
437 {
438 }
439
440 VisualModel::VisualModel()
441 : mGlyphs(),
442   mGlyphsToCharacters(),
443   mCharactersToGlyph(),
444   mCharactersPerGlyph(),
445   mGlyphsPerCharacter(),
446   mGlyphPositions(),
447   mLines(),
448   mTextColor( Color::BLACK ),
449   mShadowColor( Color::BLACK ),
450   mUnderlineColor( Color::BLACK ),
451   mOutlineColor( Color::WHITE ),
452   mControlSize(),
453   mShadowOffset(),
454   mUnderlineHeight( 0.0f ),
455   mOutlineWidth( 0u ),
456   mShadowBlurRadius( 0.0f ),
457   mNaturalSize(),
458   mLayoutSize(),
459   mCachedLineIndex( 0u ),
460   mUnderlineEnabled( false ),
461   mUnderlineColorSet( false )
462 {
463 }
464
465 } // namespace Text
466
467 } // namespace Toolkit
468
469 } // namespace Dali