Merge "Support to reset the image in ImageView" into 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 first in the cached line.
268
269   const LineRun& lineRun = *( mLines.Begin() + mCachedLineIndex );
270
271   if( ( lineRun.characterRun.characterIndex <= characterIndex ) &&
272       ( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters ) )
273   {
274     return mCachedLineIndex;
275   }
276
277   // 2) Is not in the cached line. Check in the other lines.
278
279   LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
280
281   for( Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
282          endIt = mLines.End();
283        it != endIt;
284        ++it, ++index )
285   {
286     const LineRun& lineRun = *it;
287
288     if( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters )
289     {
290       mCachedLineIndex = index;
291       break;
292     }
293   }
294
295   return index;
296 }
297
298 void VisualModel::GetUnderlineRuns( GlyphRun* underlineRuns,
299                                     UnderlineRunIndex index,
300                                     Length numberOfRuns ) const
301 {
302   memcpy( underlineRuns,
303           mUnderlineRuns.Begin() + index,
304           numberOfRuns * sizeof( GlyphRun ) );
305 }
306
307 void VisualModel::SetNaturalSize( const Vector2& size  )
308 {
309   mNaturalSize = size;
310 }
311
312 const Vector2& VisualModel::GetNaturalSize() const
313 {
314   return mNaturalSize;
315 }
316
317 void VisualModel::SetLayoutSize( const Vector2& size )
318 {
319   mLayoutSize = size;
320 }
321
322 const Vector2& VisualModel::GetLayoutSize() const
323 {
324   return mLayoutSize;
325 }
326
327 void VisualModel::SetTextColor( const Vector4& textColor )
328 {
329   mTextColor = textColor;
330
331   if ( !mUnderlineColorSet )
332   {
333     mUnderlineColor = textColor;
334   }
335 }
336
337 void VisualModel::SetShadowOffset( const Vector2& shadowOffset )
338 {
339   mShadowOffset = shadowOffset;
340 }
341
342 void VisualModel::SetShadowColor( const Vector4& shadowColor )
343 {
344   mShadowColor = shadowColor;
345 }
346
347 void VisualModel::SetShadowBlurRadius( const float& shadowBlurRadius )
348 {
349   mShadowBlurRadius = shadowBlurRadius;
350 }
351
352 void VisualModel::SetUnderlineColor( const Vector4& color )
353 {
354   mUnderlineColor = color;
355   mUnderlineColorSet = true;
356 }
357
358 void VisualModel::SetOutlineColor( const Vector4& color )
359 {
360   mOutlineColor = color;
361 }
362
363 void VisualModel::SetUnderlineEnabled( bool enabled )
364 {
365   mUnderlineEnabled = enabled;
366 }
367
368 void VisualModel::SetUnderlineHeight( float height )
369 {
370   mUnderlineHeight = height;
371 }
372
373 void VisualModel::SetOutlineWidth( float width )
374 {
375   mOutlineWidth = width;
376 }
377
378 const Vector4& VisualModel::GetTextColor() const
379 {
380   return mTextColor;
381 }
382
383 const Vector2& VisualModel::GetShadowOffset() const
384 {
385   return mShadowOffset;
386 }
387
388 const Vector4& VisualModel::GetShadowColor() const
389 {
390   return mShadowColor;
391 }
392
393 const float& VisualModel::GetShadowBlurRadius() const
394 {
395   return mShadowBlurRadius;
396 }
397
398 const Vector4& VisualModel::GetUnderlineColor() const
399 {
400   return mUnderlineColor;
401 }
402
403 const Vector4& VisualModel::GetOutlineColor() const
404 {
405   return mOutlineColor;
406 }
407
408 bool VisualModel::IsUnderlineEnabled() const
409 {
410   return mUnderlineEnabled;
411 }
412
413 float VisualModel::GetUnderlineHeight() const
414 {
415   return mUnderlineHeight;
416 }
417
418 float VisualModel::GetOutlineWidth() const
419 {
420   return mOutlineWidth;
421 }
422
423 Length VisualModel::GetNumberOfUnderlineRuns() const
424 {
425   return mUnderlineRuns.Count();
426 }
427
428 void VisualModel::ClearCaches()
429 {
430   mCachedLineIndex = 0u;
431 }
432
433 VisualModel::~VisualModel()
434 {
435 }
436
437 VisualModel::VisualModel()
438 : mGlyphs(),
439   mGlyphsToCharacters(),
440   mCharactersToGlyph(),
441   mCharactersPerGlyph(),
442   mGlyphsPerCharacter(),
443   mGlyphPositions(),
444   mLines(),
445   mTextColor( Color::BLACK ),
446   mShadowColor( Color::BLACK ),
447   mUnderlineColor( Color::BLACK ),
448   mOutlineColor( Color::WHITE ),
449   mControlSize(),
450   mShadowOffset(),
451   mUnderlineHeight( 0.0f ),
452   mOutlineWidth( 0.0f ),
453   mShadowBlurRadius( 0.0f ),
454   mNaturalSize(),
455   mLayoutSize(),
456   mCachedLineIndex( 0u ),
457   mUnderlineEnabled( false ),
458   mUnderlineColorSet( false )
459 {
460 }
461
462 } // namespace Text
463
464 } // namespace Toolkit
465
466 } // namespace Dali