Merge "Text improvement 1. Text - Layout text & icons. * Feature added to layout...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / visual-model-impl.cpp
1 /*
2  * Copyright (c) 2019 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( uint16_t width )
377 {
378   mOutlineWidth = width;
379 }
380
381 void VisualModel::SetBackgroundColor( const Vector4& color )
382 {
383   mBackgroundColor = color;
384 }
385
386 void VisualModel::SetBackgroundEnabled( bool enabled )
387 {
388   mBackgroundEnabled = enabled;
389 }
390
391 const Vector4& VisualModel::GetTextColor() const
392 {
393   return mTextColor;
394 }
395
396 const Vector2& VisualModel::GetShadowOffset() const
397 {
398   return mShadowOffset;
399 }
400
401 const Vector4& VisualModel::GetShadowColor() const
402 {
403   return mShadowColor;
404 }
405
406 const float& VisualModel::GetShadowBlurRadius() const
407 {
408   return mShadowBlurRadius;
409 }
410
411 const Vector4& VisualModel::GetUnderlineColor() const
412 {
413   return mUnderlineColor;
414 }
415
416 const Vector4& VisualModel::GetOutlineColor() const
417 {
418   return mOutlineColor;
419 }
420
421 bool VisualModel::IsUnderlineEnabled() const
422 {
423   return mUnderlineEnabled;
424 }
425
426 float VisualModel::GetUnderlineHeight() const
427 {
428   return mUnderlineHeight;
429 }
430
431 uint16_t VisualModel::GetOutlineWidth() const
432 {
433   return mOutlineWidth;
434 }
435
436 const Vector4& VisualModel::GetBackgroundColor() const
437 {
438   return mBackgroundColor;
439 }
440
441 bool VisualModel::IsBackgroundEnabled() const
442 {
443   return mBackgroundEnabled;
444 }
445
446 Length VisualModel::GetNumberOfUnderlineRuns() const
447 {
448   return mUnderlineRuns.Count();
449 }
450
451 void VisualModel::ClearCaches()
452 {
453   mCachedLineIndex = 0u;
454 }
455
456 VisualModel::~VisualModel()
457 {
458 }
459
460 VisualModel::VisualModel()
461 : mGlyphs(),
462   mGlyphsToCharacters(),
463   mCharactersToGlyph(),
464   mCharactersPerGlyph(),
465   mGlyphsPerCharacter(),
466   mGlyphPositions(),
467   mLines(),
468   mTextColor( Color::BLACK ),
469   mShadowColor( Color::BLACK ),
470   mUnderlineColor( Color::BLACK ),
471   mOutlineColor( Color::WHITE ),
472   mBackgroundColor( Color::CYAN ),
473   mControlSize(),
474   mShadowOffset(),
475   mUnderlineHeight( 0.0f ),
476   mShadowBlurRadius( 0.0f ),
477   mOutlineWidth( 0u ),
478   mNaturalSize(),
479   mLayoutSize(),
480   mCachedLineIndex( 0u ),
481   mUnderlineEnabled( false ),
482   mUnderlineColorSet( false ),
483   mBackgroundEnabled( false )
484 {
485 }
486
487 } // namespace Text
488
489 } // namespace Toolkit
490
491 } // namespace Dali