TextDecorator. Do not destroy the highlight geometry every OnRelayout.
[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::CreateCharacterToGlyphTable( Length numberOfCharacters )
40 {
41   // 1) Reserve some space for the characters to avoid reallocations.
42   if( 0u == numberOfCharacters )
43   {
44     // If no number of characters is given, just set something sensible to avoid reallocations.
45     numberOfCharacters = static_cast<Length> ( static_cast<float>( mGlyphs.Count() ) * 1.3f );
46   }
47   mCharactersToGlyph.Reserve( numberOfCharacters );
48
49   DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u ||
50                      ( 0u == numberOfCharacters ) );
51
52   const Length* const glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin();
53
54   // 2) Traverse the glyphs and set the glyph indices per character.
55
56   // Index to the glyph.
57   GlyphIndex glyphIndex = 0u;
58   CharacterIndex characterIndex = 0u;
59   for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin(),
60          endIt = mCharactersPerGlyph.End();
61        it != endIt;
62        ++it )
63   {
64     const Length numberOfCharactersPerGlyph = *it;
65
66     Length numberOfGlyphs = 0u;
67     // Set the glyph indices.
68     for( Length index = 0u; index < numberOfCharactersPerGlyph; ++index, ++characterIndex )
69     {
70       mCharactersToGlyph.PushBack( glyphIndex );
71       numberOfGlyphs += *( glyphsPerCharacterBuffer + characterIndex );
72     }
73     glyphIndex += numberOfGlyphs;
74   }
75 }
76
77 void VisualModel::CreateGlyphsPerCharacterTable( Length numberOfCharacters )
78 {
79   // 1) Reserve some space for the characters to avoid reallocations.
80   if( 0u == numberOfCharacters )
81   {
82     // If no number of characters is given, just set something sensible to avoid reallocations.
83     numberOfCharacters = static_cast<Length> ( static_cast<float>( mGlyphs.Count() ) * 1.3f );
84   }
85   mGlyphsPerCharacter.Reserve( numberOfCharacters );
86
87   // 2) Traverse the glyphs and set the number of glyphs per character.
88
89   // The number of 'characters per glyph' equal to zero.
90   Length zeroCharactersPerGlyph = 0u;
91
92   for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin(),
93          endIt = mCharactersPerGlyph.End();
94        it != endIt;
95        ++it )
96   {
97     const Length numberOfCharactersPerGlyph = *it;
98
99     // Set the glyphs per character.
100     if( 0u == numberOfCharactersPerGlyph )
101     {
102       ++zeroCharactersPerGlyph;
103     }
104     else
105     {
106       const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharactersPerGlyph - 1u );
107       for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter ; ++zeroIndex )
108       {
109         mGlyphsPerCharacter.PushBack( 0u );
110       }
111
112       mGlyphsPerCharacter.PushBack( 1u + zeroCharactersPerGlyph );
113
114       zeroCharactersPerGlyph = 0u;
115     }
116   }
117 }
118
119 void VisualModel::GetGlyphs( GlyphInfo* glyphs,
120                              GlyphIndex glyphIndex,
121                              Length numberOfGlyphs ) const
122 {
123   memcpy( glyphs, mGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
124 }
125
126 void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
127                                      GlyphIndex glyphIndex,
128                                      Length numberOfGlyphs ) const
129 {
130   memcpy( glyphPositions, mGlyphPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
131 }
132
133 void VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
134                                     Length numberOfGlyphs,
135                                     LineIndex& firstLine,
136                                     Length& numberOfLines ) const
137 {
138   // Initialize the number of lines and the first line.
139   firstLine = 0u;
140   numberOfLines = 0u;
141   bool firstLineFound = false;
142
143   const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
144
145   // Traverse the lines and count those lines within the range of glyphs.
146   for( Vector<LineRun>::ConstIterator it = mLines.Begin(),
147          endIt = mLines.End();
148        it != endIt;
149        ++it )
150   {
151     const LineRun& line = *it;
152
153     if( ( line.glyphIndex + line.numberOfGlyphs > glyphIndex ) &&
154         ( lastGlyphIndex > line.glyphIndex ) )
155     {
156       firstLineFound = true;
157       ++numberOfLines;
158     }
159     else if( lastGlyphIndex <= line.glyphIndex )
160     {
161       // nothing else to do.
162       break;
163     }
164
165     if( !firstLineFound )
166     {
167       ++firstLine;
168     }
169   }
170 }
171
172 void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
173                                         GlyphIndex glyphIndex,
174                                         Length numberOfGlyphs ) const
175 {
176   LineIndex firstLine = 0u;
177   Length numberOfLines = 0u;
178
179   GetNumberOfLines( glyphIndex,
180                     numberOfGlyphs,
181                     firstLine,
182                     numberOfLines );
183
184   memcpy( lines, mLines.Begin() + firstLine, numberOfLines * sizeof( LineRun ) );
185 }
186
187 LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
188 {
189   // 1) Check first in the cached line.
190
191   const LineRun& lineRun = *( mLines.Begin() + mCachedLineIndex );
192
193   if( ( lineRun.characterRun.characterIndex <= characterIndex ) &&
194       ( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters ) )
195   {
196     return mCachedLineIndex;
197   }
198
199   // 2) Is not in the cached line. Check in the other lines.
200
201   LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
202
203   for( Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
204          endIt = mLines.End();
205        it != endIt;
206        ++it, ++index )
207   {
208     const LineRun& lineRun = *it;
209
210     if( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters )
211     {
212       mCachedLineIndex = index;
213       break;
214     }
215   }
216
217   return index;
218 }
219
220 void VisualModel::SetNaturalSize( const Vector2& size  )
221 {
222   mNaturalSize = size;
223 }
224
225 const Vector2& VisualModel::GetNaturalSize() const
226 {
227   return mNaturalSize;
228 }
229
230 void VisualModel::SetActualSize( const Vector2& size )
231 {
232   mActualSize = size;
233 }
234
235 const Vector2& VisualModel::GetActualSize() const
236 {
237   return mActualSize;
238 }
239
240 void VisualModel::SetTextColor( const Vector4& textColor )
241 {
242   mTextColor = textColor;
243
244   if ( !mUnderlineColorSet )
245   {
246     mUnderlineColor = textColor;
247   }
248 }
249
250 void VisualModel::SetShadowOffset( const Vector2& shadowOffset )
251 {
252   mShadowOffset = shadowOffset;
253 }
254
255 void VisualModel::SetShadowColor( const Vector4& shadowColor )
256 {
257   mShadowColor = shadowColor;
258 }
259
260 void VisualModel::SetUnderlineColor( const Vector4& color )
261 {
262   mUnderlineColor = color;
263   mUnderlineColorSet = true;
264 }
265
266 void VisualModel::SetUnderlineEnabled( bool enabled )
267 {
268   mUnderlineEnabled = enabled;
269 }
270
271 void VisualModel::SetUnderlineHeight( float height )
272 {
273   mUnderlineHeight = height;
274 }
275
276 const Vector4& VisualModel::GetTextColor() const
277 {
278   return mTextColor;
279 }
280
281 const Vector2& VisualModel::GetShadowOffset() const
282 {
283   return mShadowOffset;
284 }
285
286 const Vector4& VisualModel::GetShadowColor() const
287 {
288   return mShadowColor;
289 }
290
291 const Vector4& VisualModel::GetUnderlineColor() const
292 {
293   return mUnderlineColor;
294 }
295
296 bool VisualModel::IsUnderlineEnabled() const
297 {
298   return mUnderlineEnabled;
299 }
300
301 float VisualModel::GetUnderlineHeight() const
302 {
303   return mUnderlineHeight;
304 }
305
306 void VisualModel::ClearCaches()
307 {
308   mCachedLineIndex = 0u;
309 }
310
311 VisualModel::~VisualModel()
312 {
313 }
314
315 VisualModel::VisualModel()
316 : mGlyphs(),
317   mGlyphsToCharacters(),
318   mCharactersToGlyph(),
319   mCharactersPerGlyph(),
320   mGlyphsPerCharacter(),
321   mGlyphPositions(),
322   mLines(),
323   mTextColor( Color::BLACK ),
324   mShadowColor( Color::BLACK ),
325   mUnderlineColor( Color::BLACK ),
326   mShadowOffset( Vector2::ZERO ),
327   mUnderlineHeight( 0.0f ),
328   mNaturalSize(),
329   mActualSize(),
330   mCachedLineIndex( 0u ),
331   mUnderlineEnabled( false ),
332   mUnderlineColorSet( false )
333 {
334 }
335
336 } // namespace Text
337
338 } // namespace Toolkit
339
340 } // namespace Dali