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