2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/text/visual-model-impl.h>
30 VisualModelPtr VisualModel::New()
32 return VisualModelPtr(new VisualModel());
35 void VisualModel::CreateCharacterToGlyphTable(CharacterIndex startIndex,
36 GlyphIndex startGlyphIndex,
37 Length numberOfCharacters)
39 if(0u == numberOfCharacters)
45 DALI_ASSERT_DEBUG(mGlyphsPerCharacter.Count() != 0u);
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.
50 // Whether the current buffer is being updated or is set from scratch.
51 const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
53 Vector<GlyphIndex> newCharactersToGlyph;
54 GlyphIndex* charactersToGlyphBuffer = NULL;
56 // 1) Reserve some space for the glyph indices to avoid reallocations.
57 if(updateCurrentBuffer)
59 newCharactersToGlyph.Resize(numberOfCharacters);
60 charactersToGlyphBuffer = newCharactersToGlyph.Begin();
64 mCharactersToGlyph.Resize(numberOfCharacters);
65 charactersToGlyphBuffer = mCharactersToGlyph.Begin() + startIndex;
68 const Length* const glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin();
70 // 2) Traverse the glyphs and set the glyph indices per character.
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);
81 const Length numberOfCharactersPerGlyph = *it;
83 Length numberOfGlyphs = 0u;
84 // Set the glyph indices.
85 for(Length index = 0u; index < numberOfCharactersPerGlyph; ++index, ++characterIndex)
87 *charactersToGlyphBuffer = glyphIndex;
88 numberOfGlyphs += *(glyphsPerCharacterBuffer + characterIndex);
89 ++charactersToGlyphBuffer;
91 glyphIndex += numberOfGlyphs;
94 // If the character to glyph buffer is updated, it needs to be inserted in the model.
95 if(updateCurrentBuffer)
97 // Update the indices.
98 const Length numberOfGlyphs = glyphIndex - startGlyphIndex;
99 for(Vector<Length>::Iterator it = mCharactersToGlyph.Begin() + startIndex,
100 endIt = mCharactersToGlyph.End();
104 *it += numberOfGlyphs;
107 mCharactersToGlyph.Insert(mCharactersToGlyph.Begin() + startIndex,
108 newCharactersToGlyph.Begin(),
109 newCharactersToGlyph.End());
113 void VisualModel::CreateGlyphsPerCharacterTable(CharacterIndex startIndex,
114 GlyphIndex startGlyphIndex,
115 Length numberOfCharacters)
117 if(0u == numberOfCharacters)
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.
126 // Whether the current buffer is being updated or is set from scratch.
127 const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
129 Vector<Length> newGlyphsPerCharacter;
130 Length* glyphsPerCharacterBuffer = NULL;
132 // 1) Reserve some space for the glyphs per character to avoid reallocations.
133 if(updateCurrentBuffer)
135 newGlyphsPerCharacter.Resize(numberOfCharacters);
136 glyphsPerCharacterBuffer = newGlyphsPerCharacter.Begin();
140 mGlyphsPerCharacter.Resize(numberOfCharacters);
141 glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin() + startIndex;
144 // 2) Traverse the glyphs and set the number of glyphs per character.
146 Length traversedCharacters = 0;
148 // The number of 'characters per glyph' equal to zero.
149 Length zeroCharactersPerGlyph = 0u;
151 for(Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin() + startGlyphIndex,
152 endIt = mCharactersPerGlyph.End();
153 (it != endIt) && (traversedCharacters < numberOfCharacters);
156 const Length numberOfCharactersPerGlyph = *it;
157 traversedCharacters += numberOfCharactersPerGlyph;
159 // Set the glyphs per character.
160 if(0u == numberOfCharactersPerGlyph)
162 ++zeroCharactersPerGlyph;
166 const Length numberOfZeroGlyphsPerCharacter = (numberOfCharactersPerGlyph - 1u);
167 for(Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter; ++zeroIndex)
169 *glyphsPerCharacterBuffer = 0u;
171 // Point to the next position in the buffer.
172 ++glyphsPerCharacterBuffer;
175 *glyphsPerCharacterBuffer = zeroCharactersPerGlyph + 1u;
177 zeroCharactersPerGlyph = 0u;
179 // Point to the next position in the buffer.
180 ++glyphsPerCharacterBuffer;
184 // If the glyphs per character buffer is updated, it needs to be inserted in the model.
185 if(updateCurrentBuffer)
187 mGlyphsPerCharacter.Insert(mGlyphsPerCharacter.Begin() + startIndex,
188 newGlyphsPerCharacter.Begin(),
189 newGlyphsPerCharacter.End());
193 void VisualModel::GetGlyphs(GlyphInfo* glyphs,
194 GlyphIndex glyphIndex,
195 Length numberOfGlyphs) const
197 memcpy(glyphs, mGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof(GlyphInfo));
200 void VisualModel::GetGlyphPositions(Vector2* glyphPositions,
201 GlyphIndex glyphIndex,
202 Length numberOfGlyphs) const
204 memcpy(glyphPositions, mGlyphPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof(Vector2));
207 Length VisualModel::GetTotalNumberOfLines() const
209 return mLines.Size();
212 void VisualModel::GetNumberOfLines(GlyphIndex glyphIndex,
213 Length numberOfGlyphs,
214 LineIndex& firstLine,
215 Length& numberOfLines) const
217 // Initialize the number of lines and the first line.
220 bool firstLineFound = false;
222 const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
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();
230 const LineRun& line = *it;
232 if((line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs > glyphIndex) &&
233 (lastGlyphIndex > line.glyphRun.glyphIndex))
235 firstLineFound = true;
238 else if((line.glyphRunSecondHalf.glyphIndex + line.glyphRunSecondHalf.numberOfGlyphs > glyphIndex) &&
239 (lastGlyphIndex > line.glyphRunSecondHalf.glyphIndex))
241 firstLineFound = true;
244 else if(lastGlyphIndex <= line.glyphRun.glyphIndex)
246 // nothing else to do.
257 void VisualModel::GetLinesOfGlyphRange(LineRun* lines,
258 GlyphIndex glyphIndex,
259 Length numberOfGlyphs) const
261 LineIndex firstLine = 0u;
262 Length numberOfLines = 0u;
264 GetNumberOfLines(glyphIndex,
269 memcpy(lines, mLines.Begin() + firstLine, numberOfLines * sizeof(LineRun));
272 LineIndex VisualModel::GetLineOfCharacter(CharacterIndex characterIndex)
274 // 1) Check line is empty or not.
280 // 2) Check in the cached line.
281 const LineRun& lineRun = *(mLines.Begin() + mCachedLineIndex);
282 if((lineRun.characterRun.characterIndex <= characterIndex) &&
283 (characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters))
285 return mCachedLineIndex;
288 // 3) Is not in the cached line. Check in the other lines.
289 LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
291 for(Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
292 endIt = mLines.End();
296 const LineRun& lineRun = *it;
298 if(characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters)
300 mCachedLineIndex = index;
308 void VisualModel::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns,
309 UnderlineRunIndex index,
310 Length numberOfRuns) const
312 memcpy(underlineRuns,
313 mUnderlineRuns.Begin() + index,
314 numberOfRuns * sizeof(UnderlinedGlyphRun));
317 void VisualModel::SetNaturalSize(const Vector2& size)
322 const Vector2& VisualModel::GetNaturalSize() const
327 void VisualModel::SetLayoutSize(const Vector2& size)
332 const Vector2& VisualModel::GetLayoutSize() const
337 void VisualModel::SetTextColor(const Vector4& textColor)
339 mTextColor = textColor;
341 if(!mUnderlineColorSet)
343 mUnderlineColor = textColor;
347 void VisualModel::SetShadowOffset(const Vector2& shadowOffset)
349 mShadowOffset = shadowOffset;
352 void VisualModel::SetShadowColor(const Vector4& shadowColor)
354 mShadowColor = shadowColor;
357 void VisualModel::SetShadowBlurRadius(const float& shadowBlurRadius)
359 mShadowBlurRadius = shadowBlurRadius;
362 void VisualModel::SetUnderlineColor(const Vector4& color)
364 mUnderlineColor = color;
365 mUnderlineColorSet = true;
368 void VisualModel::SetOutlineColor(const Vector4& color)
370 mOutlineColor = color;
373 void VisualModel::SetUnderlineEnabled(bool enabled)
375 mUnderlineEnabled = enabled;
378 void VisualModel::SetUnderlineHeight(float height)
380 mUnderlineHeight = height;
383 void VisualModel::SetUnderlineType(Text::Underline::Type type)
385 mUnderlineType = type;
388 void VisualModel::SetDashedUnderlineWidth(float width)
390 mDashedUnderlineWidth = width;
393 void VisualModel::SetDashedUnderlineGap(float gap)
395 mDashedUnderlineGap = gap;
398 void VisualModel::SetOutlineWidth(uint16_t width)
400 mOutlineWidth = width;
403 void VisualModel::SetBackgroundColor(const Vector4& color)
405 mBackgroundColor = color;
408 void VisualModel::SetBackgroundEnabled(bool enabled)
410 mBackgroundEnabled = enabled;
413 void VisualModel::SetMarkupProcessorEnabled(bool enabled)
415 mMarkupProcessorEnabled = enabled;
418 void VisualModel::SetTextElideEnabled(bool enabled)
420 mTextElideEnabled = enabled;
423 void VisualModel::SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition)
425 mEllipsisPosition = ellipsisPosition;
428 void VisualModel::SetStartIndexOfElidedGlyphs(GlyphIndex startIndexOfElidedGlyphs)
430 mStartIndexOfElidedGlyphs = startIndexOfElidedGlyphs;
433 void VisualModel::SetEndIndexOfElidedGlyphs(GlyphIndex endIndexOfElidedGlyphs)
435 mEndIndexOfElidedGlyphs = endIndexOfElidedGlyphs;
438 void VisualModel::SetFirstMiddleIndexOfElidedGlyphs(GlyphIndex firstMiddleIndexOfElidedGlyphs)
440 mFirstMiddleIndexOfElidedGlyphs = firstMiddleIndexOfElidedGlyphs;
443 void VisualModel::SetSecondMiddleIndexOfElidedGlyphs(GlyphIndex secondMiddleIndexOfElidedGlyphs)
445 mSecondMiddleIndexOfElidedGlyphs = secondMiddleIndexOfElidedGlyphs;
448 void VisualModel::SetStrikethroughColor(const Vector4& color)
450 mStrikethroughColor = color;
453 void VisualModel::SetStrikethroughEnabled(bool enabled)
455 mStrikethroughEnabled = enabled;
458 void VisualModel::SetStrikethroughHeight(float height)
460 mStrikethroughHeight = height;
463 void VisualModel::SetCharacterSpacing(float characterSpacing)
465 mCharacterSpacing = characterSpacing;
468 const Vector4& VisualModel::GetTextColor() const
473 const Vector2& VisualModel::GetShadowOffset() const
475 return mShadowOffset;
478 const Vector4& VisualModel::GetShadowColor() const
483 const float& VisualModel::GetShadowBlurRadius() const
485 return mShadowBlurRadius;
488 const Vector4& VisualModel::GetUnderlineColor() const
490 return mUnderlineColor;
493 const Vector4& VisualModel::GetOutlineColor() const
495 return mOutlineColor;
498 bool VisualModel::IsUnderlineEnabled() const
500 return mUnderlineEnabled;
503 float VisualModel::GetUnderlineHeight() const
505 return mUnderlineHeight;
508 Text::Underline::Type VisualModel::GetUnderlineType() const
510 return mUnderlineType;
513 float VisualModel::GetDashedUnderlineWidth() const
515 return mDashedUnderlineWidth;
518 float VisualModel::GetDashedUnderlineGap() const
520 return mDashedUnderlineGap;
523 uint16_t VisualModel::GetOutlineWidth() const
525 return mOutlineWidth;
528 const Vector4& VisualModel::GetBackgroundColor() const
530 return mBackgroundColor;
533 const float VisualModel::GetCharacterSpacing() const
535 return mCharacterSpacing;
538 bool VisualModel::IsBackgroundEnabled() const
540 return mBackgroundEnabled;
543 bool VisualModel::IsMarkupProcessorEnabled() const
545 return mMarkupProcessorEnabled;
548 bool VisualModel::IsTextElideEnabled() const
550 return mTextElideEnabled;
553 Toolkit::DevelText::EllipsisPosition::Type VisualModel::GetEllipsisPosition() const
555 return mEllipsisPosition;
558 GlyphIndex VisualModel::GetStartIndexOfElidedGlyphs() const
560 return mStartIndexOfElidedGlyphs;
563 GlyphIndex VisualModel::GetEndIndexOfElidedGlyphs() const
565 return mEndIndexOfElidedGlyphs;
568 GlyphIndex VisualModel::GetFirstMiddleIndexOfElidedGlyphs() const
570 return mFirstMiddleIndexOfElidedGlyphs;
573 GlyphIndex VisualModel::GetSecondMiddleIndexOfElidedGlyphs() const
575 return mSecondMiddleIndexOfElidedGlyphs;
578 Length VisualModel::GetNumberOfUnderlineRuns() const
580 return mUnderlineRuns.Count();
583 const Vector4& VisualModel::GetStrikethroughColor() const
585 return mStrikethroughColor;
588 bool VisualModel::IsStrikethroughEnabled() const
590 return mStrikethroughEnabled;
593 float VisualModel::GetStrikethroughHeight() const
595 return mStrikethroughHeight;
598 void VisualModel::GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns,
599 StrikethroughRunIndex index,
600 Length numberOfRuns) const
602 memcpy(strikethroughRuns,
603 mStrikethroughRuns.Begin() + index,
604 numberOfRuns * sizeof(StrikethroughGlyphRun));
607 Length VisualModel::GetNumberOfStrikethroughRuns() const
609 return mStrikethroughRuns.Count();
612 void VisualModel::ClearCaches()
614 mCachedLineIndex = 0u;
617 const Vector<CharacterIndex>& VisualModel::GetGlyphsToCharacters() const
619 return mGlyphsToCharacters;
622 VisualModel::~VisualModel()
626 VisualModel::VisualModel()
628 mGlyphsToCharacters(),
629 mCharactersToGlyph(),
630 mCharactersPerGlyph(),
631 mGlyphsPerCharacter(),
634 mTextColor(Color::BLACK),
635 mShadowColor(Color::BLACK),
636 mUnderlineColor(Color::BLACK),
637 mOutlineColor(Color::WHITE),
638 mBackgroundColor(Color::TRANSPARENT),
639 mStrikethroughColor(Color::BLACK),
642 mUnderlineHeight(0.0f),
643 mStrikethroughHeight(0.0f),
644 mUnderlineType(Text::Underline::SOLID),
645 mDashedUnderlineWidth(2.0f),
646 mDashedUnderlineGap(1.0f),
647 mShadowBlurRadius(0.0f),
651 mCachedLineIndex(0u),
652 mEllipsisPosition(DevelText::EllipsisPosition::END),
653 mStartIndexOfElidedGlyphs(0u),
654 mEndIndexOfElidedGlyphs(0u),
655 mFirstMiddleIndexOfElidedGlyphs(0u),
656 mSecondMiddleIndexOfElidedGlyphs(0u),
657 mTextElideEnabled(false),
658 mUnderlineEnabled(false),
659 mUnderlineColorSet(false),
660 mBackgroundEnabled(false),
661 mMarkupProcessorEnabled(false),
662 mStrikethroughEnabled(false),
663 mCharacterSpacing(0.0f)
670 } // namespace Toolkit