Merge "Fixed patch-coverage generation" 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::SetUnderlineColor( const Vector4& color )
348 {
349   mUnderlineColor = color;
350   mUnderlineColorSet = true;
351 }
352
353 void VisualModel::SetUnderlineEnabled( bool enabled )
354 {
355   mUnderlineEnabled = enabled;
356 }
357
358 void VisualModel::SetUnderlineHeight( float height )
359 {
360   mUnderlineHeight = height;
361 }
362
363 const Vector4& VisualModel::GetTextColor() const
364 {
365   return mTextColor;
366 }
367
368 const Vector2& VisualModel::GetShadowOffset() const
369 {
370   return mShadowOffset;
371 }
372
373 const Vector4& VisualModel::GetShadowColor() const
374 {
375   return mShadowColor;
376 }
377
378 const Vector4& VisualModel::GetUnderlineColor() const
379 {
380   return mUnderlineColor;
381 }
382
383 bool VisualModel::IsUnderlineEnabled() const
384 {
385   return mUnderlineEnabled;
386 }
387
388 float VisualModel::GetUnderlineHeight() const
389 {
390   return mUnderlineHeight;
391 }
392
393 void VisualModel::ClearCaches()
394 {
395   mCachedLineIndex = 0u;
396 }
397
398 VisualModel::~VisualModel()
399 {
400 }
401
402 VisualModel::VisualModel()
403 : mGlyphs(),
404   mGlyphsToCharacters(),
405   mCharactersToGlyph(),
406   mCharactersPerGlyph(),
407   mGlyphsPerCharacter(),
408   mGlyphPositions(),
409   mLines(),
410   mTextColor( Color::BLACK ),
411   mShadowColor( Color::BLACK ),
412   mUnderlineColor( Color::BLACK ),
413   mControlSize(),
414   mShadowOffset(),
415   mUnderlineHeight( 0.0f ),
416   mNaturalSize(),
417   mLayoutSize(),
418   mCachedLineIndex( 0u ),
419   mUnderlineEnabled( false ),
420   mUnderlineColorSet( false )
421 {
422 }
423
424 } // namespace Text
425
426 } // namespace Toolkit
427
428 } // namespace Dali