[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / visual-model-impl.cpp
1 /*
2  * Copyright (c) 2022 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 Length VisualModel::GetTotalNumberOfLines() const
208 {
209   return mLines.Size();
210 }
211
212 void VisualModel::GetNumberOfLines(GlyphIndex glyphIndex,
213                                    Length     numberOfGlyphs,
214                                    LineIndex& firstLine,
215                                    Length&    numberOfLines) const
216 {
217   // Initialize the number of lines and the first line.
218   firstLine           = 0u;
219   numberOfLines       = 0u;
220   bool firstLineFound = false;
221
222   const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
223
224   // Traverse the lines and count those lines within the range of glyphs.
225   for(Vector<LineRun>::ConstIterator it    = mLines.Begin(),
226                                      endIt = mLines.End();
227       it != endIt;
228       ++it)
229   {
230     const LineRun& line = *it;
231
232     if((line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs > glyphIndex) &&
233        (lastGlyphIndex > line.glyphRun.glyphIndex))
234     {
235       firstLineFound = true;
236       ++numberOfLines;
237     }
238     else if((line.glyphRunSecondHalf.glyphIndex + line.glyphRunSecondHalf.numberOfGlyphs > glyphIndex) &&
239             (lastGlyphIndex > line.glyphRunSecondHalf.glyphIndex))
240     {
241       firstLineFound = true;
242       ++numberOfLines;
243     }
244     else if(lastGlyphIndex <= line.glyphRun.glyphIndex)
245     {
246       // nothing else to do.
247       break;
248     }
249
250     if(!firstLineFound)
251     {
252       ++firstLine;
253     }
254   }
255 }
256
257 LineIndex VisualModel::GetLineOfGlyph( GlyphIndex glyphIndex )
258 {
259   const CharacterIndex characterIndex = *(mGlyphsToCharacters.Begin() + glyphIndex);
260   return GetLineOfCharacter(characterIndex);
261 }
262
263 void VisualModel::GetLinesOfGlyphRange(LineRun*   lines,
264                                        GlyphIndex glyphIndex,
265                                        Length     numberOfGlyphs) const
266 {
267   LineIndex firstLine     = 0u;
268   Length    numberOfLines = 0u;
269
270   GetNumberOfLines(glyphIndex,
271                    numberOfGlyphs,
272                    firstLine,
273                    numberOfLines);
274
275   memcpy(lines, mLines.Begin() + firstLine, numberOfLines * sizeof(LineRun));
276 }
277
278 LineIndex VisualModel::GetLineOfCharacter(CharacterIndex characterIndex)
279 {
280   // 1) Check line is empty or not.
281   if(mLines.Empty())
282   {
283     return 0u;
284   }
285
286   // 2) Check in the cached line.
287   const LineRun& lineRun = *(mLines.Begin() + mCachedLineIndex);
288   if((lineRun.characterRun.characterIndex <= characterIndex) &&
289      (characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters))
290   {
291     return mCachedLineIndex;
292   }
293
294   // 3) Is not in the cached line. Check in the other lines.
295   LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
296
297   for(Vector<LineRun>::ConstIterator it    = mLines.Begin() + index,
298                                      endIt = mLines.End();
299       it != endIt;
300       ++it, ++index)
301   {
302     const LineRun& lineRun = *it;
303
304     if(characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters)
305     {
306       mCachedLineIndex = index;
307       break;
308     }
309   }
310
311   return index;
312 }
313
314 void VisualModel::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns,
315                                    UnderlineRunIndex   index,
316                                    Length              numberOfRuns) const
317 {
318   memcpy(underlineRuns,
319          mUnderlineRuns.Begin() + index,
320          numberOfRuns * sizeof(UnderlinedGlyphRun));
321 }
322
323 void VisualModel::SetNaturalSize(const Vector2& size)
324 {
325   mNaturalSize = size;
326 }
327
328 const Vector2& VisualModel::GetNaturalSize() const
329 {
330   return mNaturalSize;
331 }
332
333 void VisualModel::SetLayoutSize(const Vector2& size)
334 {
335   mLayoutSize = size;
336 }
337
338 const Vector2& VisualModel::GetLayoutSize() const
339 {
340   return mLayoutSize;
341 }
342
343 void VisualModel::SetHeightForWidth(const Vector2& size)
344 {
345   mHeightForWidth = size;
346 }
347
348 const Vector2& VisualModel::GetHeightForWidth() const
349 {
350   return mHeightForWidth;
351 }
352
353 void VisualModel::SetTextColor(const Vector4& textColor)
354 {
355   mTextColor = textColor;
356
357   if(!mUnderlineColorSet)
358   {
359     mUnderlineColor = textColor;
360   }
361 }
362
363 void VisualModel::SetShadowOffset(const Vector2& shadowOffset)
364 {
365   mShadowOffset = shadowOffset;
366 }
367
368 void VisualModel::SetShadowColor(const Vector4& shadowColor)
369 {
370   mShadowColor = shadowColor;
371 }
372
373 void VisualModel::SetShadowBlurRadius(const float& shadowBlurRadius)
374 {
375   mShadowBlurRadius = shadowBlurRadius;
376 }
377
378 void VisualModel::SetUnderlineColor(const Vector4& color)
379 {
380   mUnderlineColor    = color;
381   mUnderlineColorSet = true;
382 }
383
384 void VisualModel::SetOutlineColor(const Vector4& color)
385 {
386   mOutlineColor = color;
387 }
388
389 void VisualModel::SetUnderlineEnabled(bool enabled)
390 {
391   mUnderlineEnabled = enabled;
392 }
393
394 void VisualModel::SetUnderlineHeight(float height)
395 {
396   mUnderlineHeight = height;
397 }
398
399 void VisualModel::SetUnderlineType(Text::Underline::Type type)
400 {
401   mUnderlineType = type;
402 }
403
404 void VisualModel::SetDashedUnderlineWidth(float width)
405 {
406   mDashedUnderlineWidth = width;
407 }
408
409 void VisualModel::SetDashedUnderlineGap(float gap)
410 {
411   mDashedUnderlineGap = gap;
412 }
413
414 void VisualModel::SetOutlineWidth(uint16_t width)
415 {
416   mOutlineWidth = width;
417 }
418
419 void VisualModel::SetBackgroundColor(const Vector4& color)
420 {
421   mBackgroundColor = color;
422 }
423
424 void VisualModel::SetBackgroundEnabled(bool enabled)
425 {
426   mBackgroundEnabled = enabled;
427 }
428
429 void VisualModel::SetMarkupProcessorEnabled(bool enabled)
430 {
431   mMarkupProcessorEnabled = enabled;
432 }
433
434 void VisualModel::SetTextElideEnabled(bool enabled)
435 {
436   mTextElideEnabled = enabled;
437 }
438
439 void VisualModel::SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition)
440 {
441   mEllipsisPosition = ellipsisPosition;
442 }
443
444 void VisualModel::SetStartIndexOfElidedGlyphs(GlyphIndex startIndexOfElidedGlyphs)
445 {
446   mStartIndexOfElidedGlyphs = startIndexOfElidedGlyphs;
447 }
448
449 void VisualModel::SetEndIndexOfElidedGlyphs(GlyphIndex endIndexOfElidedGlyphs)
450 {
451   mEndIndexOfElidedGlyphs = endIndexOfElidedGlyphs;
452 }
453
454 void VisualModel::SetFirstMiddleIndexOfElidedGlyphs(GlyphIndex firstMiddleIndexOfElidedGlyphs)
455 {
456   mFirstMiddleIndexOfElidedGlyphs = firstMiddleIndexOfElidedGlyphs;
457 }
458
459 void VisualModel::SetSecondMiddleIndexOfElidedGlyphs(GlyphIndex secondMiddleIndexOfElidedGlyphs)
460 {
461   mSecondMiddleIndexOfElidedGlyphs = secondMiddleIndexOfElidedGlyphs;
462 }
463
464 void VisualModel::SetStrikethroughColor(const Vector4& color)
465 {
466   mStrikethroughColor = color;
467 }
468
469 void VisualModel::SetStrikethroughEnabled(bool enabled)
470 {
471   mStrikethroughEnabled = enabled;
472 }
473
474 void VisualModel::SetStrikethroughHeight(float height)
475 {
476   mStrikethroughHeight = height;
477 }
478
479 void VisualModel::SetCharacterSpacing(float characterSpacing)
480 {
481   mCharacterSpacing = characterSpacing;
482 }
483
484 const Vector4& VisualModel::GetTextColor() const
485 {
486   return mTextColor;
487 }
488
489 const Vector2& VisualModel::GetShadowOffset() const
490 {
491   return mShadowOffset;
492 }
493
494 const Vector4& VisualModel::GetShadowColor() const
495 {
496   return mShadowColor;
497 }
498
499 const float& VisualModel::GetShadowBlurRadius() const
500 {
501   return mShadowBlurRadius;
502 }
503
504 const Vector4& VisualModel::GetUnderlineColor() const
505 {
506   return mUnderlineColor;
507 }
508
509 const Vector4& VisualModel::GetOutlineColor() const
510 {
511   return mOutlineColor;
512 }
513
514 bool VisualModel::IsUnderlineEnabled() const
515 {
516   return mUnderlineEnabled;
517 }
518
519 float VisualModel::GetUnderlineHeight() const
520 {
521   return mUnderlineHeight;
522 }
523
524 Text::Underline::Type VisualModel::GetUnderlineType() const
525 {
526   return mUnderlineType;
527 }
528
529 float VisualModel::GetDashedUnderlineWidth() const
530 {
531   return mDashedUnderlineWidth;
532 }
533
534 float VisualModel::GetDashedUnderlineGap() const
535 {
536   return mDashedUnderlineGap;
537 }
538
539 uint16_t VisualModel::GetOutlineWidth() const
540 {
541   return mOutlineWidth;
542 }
543
544 const Vector4& VisualModel::GetBackgroundColor() const
545 {
546   return mBackgroundColor;
547 }
548
549 const float VisualModel::GetCharacterSpacing() const
550 {
551   return mCharacterSpacing;
552 }
553
554 bool VisualModel::IsBackgroundEnabled() const
555 {
556   return mBackgroundEnabled;
557 }
558
559 bool VisualModel::IsMarkupProcessorEnabled() const
560 {
561   return mMarkupProcessorEnabled;
562 }
563
564 bool VisualModel::IsTextElideEnabled() const
565 {
566   return mTextElideEnabled;
567 }
568
569 Toolkit::DevelText::EllipsisPosition::Type VisualModel::GetEllipsisPosition() const
570 {
571   return mEllipsisPosition;
572 }
573
574 GlyphIndex VisualModel::GetStartIndexOfElidedGlyphs() const
575 {
576   return mStartIndexOfElidedGlyphs;
577 }
578
579 GlyphIndex VisualModel::GetEndIndexOfElidedGlyphs() const
580 {
581   return mEndIndexOfElidedGlyphs;
582 }
583
584 GlyphIndex VisualModel::GetFirstMiddleIndexOfElidedGlyphs() const
585 {
586   return mFirstMiddleIndexOfElidedGlyphs;
587 }
588
589 GlyphIndex VisualModel::GetSecondMiddleIndexOfElidedGlyphs() const
590 {
591   return mSecondMiddleIndexOfElidedGlyphs;
592 }
593
594 Length VisualModel::GetNumberOfUnderlineRuns() const
595 {
596   return mUnderlineRuns.Count();
597 }
598
599 const Vector4& VisualModel::GetStrikethroughColor() const
600 {
601   return mStrikethroughColor;
602 }
603
604 bool VisualModel::IsStrikethroughEnabled() const
605 {
606   return mStrikethroughEnabled;
607 }
608
609 float VisualModel::GetStrikethroughHeight() const
610 {
611   return mStrikethroughHeight;
612 }
613
614 void VisualModel::GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns,
615                                        StrikethroughRunIndex  index,
616                                        Length                 numberOfRuns) const
617 {
618   memcpy(strikethroughRuns,
619          mStrikethroughRuns.Begin() + index,
620          numberOfRuns * sizeof(StrikethroughGlyphRun));
621 }
622
623 Length VisualModel::GetNumberOfStrikethroughRuns() const
624 {
625   return mStrikethroughRuns.Count();
626 }
627
628 Length VisualModel::GetNumberOfCharacterSpacingGlyphRuns() const
629 {
630   return mCharacterSpacingRuns.Count();
631 }
632
633 const Vector<CharacterSpacingGlyphRun>& VisualModel::GetCharacterSpacingGlyphRuns() const
634 {
635   return mCharacterSpacingRuns;
636 }
637
638 void VisualModel::ClearCaches()
639 {
640   mCachedLineIndex = 0u;
641 }
642
643 const Vector<CharacterIndex>& VisualModel::GetGlyphsToCharacters() const
644 {
645   return mGlyphsToCharacters;
646 }
647
648 VisualModel::~VisualModel()
649 {
650 }
651
652 VisualModel::VisualModel()
653 : mGlyphs(),
654   mGlyphsToCharacters(),
655   mCharactersToGlyph(),
656   mCharactersPerGlyph(),
657   mGlyphsPerCharacter(),
658   mGlyphPositions(),
659   mLines(),
660   mTextColor(Color::BLACK),
661   mShadowColor(Color::BLACK),
662   mUnderlineColor(Color::BLACK),
663   mOutlineColor(Color::WHITE),
664   mBackgroundColor(Color::TRANSPARENT),
665   mStrikethroughColor(Color::BLACK),
666   mControlSize(),
667   mShadowOffset(),
668   mUnderlineHeight(0.0f),
669   mStrikethroughHeight(0.0f),
670   mUnderlineType(Text::Underline::SOLID),
671   mDashedUnderlineWidth(2.0f),
672   mDashedUnderlineGap(1.0f),
673   mShadowBlurRadius(0.0f),
674   mOutlineWidth(0u),
675   mNaturalSize(),
676   mLayoutSize(),
677   mHeightForWidth(0.0f, 0.0f),
678   mCachedLineIndex(0u),
679   mEllipsisPosition(DevelText::EllipsisPosition::END),
680   mStartIndexOfElidedGlyphs(0u),
681   mEndIndexOfElidedGlyphs(0u),
682   mFirstMiddleIndexOfElidedGlyphs(0u),
683   mSecondMiddleIndexOfElidedGlyphs(0u),
684   mTextElideEnabled(false),
685   mUnderlineEnabled(false),
686   mUnderlineColorSet(false),
687   mBackgroundEnabled(false),
688   mMarkupProcessorEnabled(false),
689   mStrikethroughEnabled(false),
690   mCharacterSpacing(0.0f)
691
692 {
693 }
694
695 } // namespace Text
696
697 } // namespace Toolkit
698
699 } // namespace Dali