Support character-spacing tag in markup
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / glyph-metrics-helper.cpp
1
2 /*
3  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 // FILE HEADER
20 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
21
22 // INTERNAL INCLUDES
23 #include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
24
25 namespace Dali
26 {
27 namespace Toolkit
28 {
29 namespace Text
30 {
31 Length GetNumberOfGlyphsOfGroup(GlyphIndex          glyphIndex,
32                                 GlyphIndex          lastGlyphPlusOne,
33                                 const Length* const charactersPerGlyphBuffer)
34 {
35   Length numberOfGLyphsInGroup = 1u;
36
37   for(GlyphIndex index = glyphIndex; index < lastGlyphPlusOne; ++index)
38   {
39     if(0u == *(charactersPerGlyphBuffer + index))
40     {
41       ++numberOfGLyphsInGroup;
42     }
43     else
44     {
45       break;
46     }
47   }
48
49   return numberOfGLyphsInGroup;
50 }
51
52 void GetGlyphsMetrics(GlyphIndex             glyphIndex,
53                       Length                 numberOfGlyphs,
54                       GlyphMetrics&          glyphMetrics,
55                       const GlyphInfo* const glyphsBuffer,
56                       MetricsPtr&            metrics,
57                       float                  calculatedAdvance)
58 {
59   const GlyphInfo& firstGlyph = *(glyphsBuffer + glyphIndex);
60
61   Text::FontMetrics fontMetrics;
62   if(0u != firstGlyph.fontId)
63   {
64     metrics->GetFontMetrics(firstGlyph.fontId, fontMetrics);
65   }
66   else if(0u != firstGlyph.index)
67   {
68     // It may be an embedded image.
69     fontMetrics.ascender  = firstGlyph.height;
70     fontMetrics.descender = 0.f;
71     fontMetrics.height    = fontMetrics.ascender;
72   }
73
74   const bool isItalicFont = metrics->HasItalicStyle(firstGlyph.fontId);
75
76   glyphMetrics.fontId     = firstGlyph.fontId;
77   glyphMetrics.fontHeight = fontMetrics.height;
78   glyphMetrics.width      = firstGlyph.width;
79   glyphMetrics.advance    = calculatedAdvance;
80   glyphMetrics.ascender   = fontMetrics.ascender;
81   glyphMetrics.xBearing   = firstGlyph.xBearing;
82
83   if(1u < numberOfGlyphs)
84   {
85     float maxWidthEdge = firstGlyph.xBearing + firstGlyph.width;
86
87     for(unsigned int i = 1u; i < numberOfGlyphs; ++i)
88     {
89       const GlyphInfo& glyphInfo = *(glyphsBuffer + glyphIndex + i);
90
91       // update the initial xBearing if smaller.
92       glyphMetrics.xBearing = std::min(glyphMetrics.xBearing, glyphMetrics.advance + glyphInfo.xBearing);
93
94       // update the max width edge if bigger.
95       const float currentMaxGlyphWidthEdge = glyphMetrics.advance + glyphInfo.xBearing + glyphInfo.width;
96       maxWidthEdge                         = std::max(maxWidthEdge, currentMaxGlyphWidthEdge);
97
98       glyphMetrics.advance += (glyphInfo.advance);
99     }
100
101     glyphMetrics.width = maxWidthEdge - glyphMetrics.xBearing;
102   }
103
104   glyphMetrics.width += (firstGlyph.isItalicRequired && !isItalicFont) ? TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE * firstGlyph.height : 0.f;
105 }
106
107 void GetGlyphMetricsFromCharacterIndex(CharacterIndex         index,
108                                        const VisualModelPtr&  visualModel,
109                                        const LogicalModelPtr& logicalModel,
110                                        MetricsPtr&            metrics,
111                                        GlyphMetrics&          glyphMetrics,
112                                        GlyphIndex&            glyphIndex,
113                                        Length&                numberOfGlyphs)
114 {
115   const GlyphIndex* const charactersToGlyphBuffer   = visualModel->mCharactersToGlyph.Begin();
116   const Length* const     glyphsPerCharacterBuffer  = visualModel->mGlyphsPerCharacter.Begin();
117   const GlyphInfo* const  glyphInfoBuffer           = visualModel->mGlyphs.Begin();
118   Vector<CharacterIndex>& glyphToCharacterMap       = visualModel->mGlyphsToCharacters;
119   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
120   const float             modelCharacterSpacing     = visualModel->GetCharacterSpacing();
121
122   // Get the character-spacing runs.
123   const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = visualModel->GetCharacterSpacingGlyphRuns();
124
125   //Takes the character index, obtains the glyph index (and the number of Glyphs) from it and finally gets the glyph metrics.
126   glyphIndex     = *(charactersToGlyphBuffer + index);
127   numberOfGlyphs = *(glyphsPerCharacterBuffer + index);
128
129   float calculatedAdvance = 0.f;
130
131   const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
132   calculatedAdvance            = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(visualModel->mGlyphs.Begin() + glyphIndex)).advance);
133
134   // Get the metrics for the group of glyphs.
135   GetGlyphsMetrics(glyphIndex,
136                    numberOfGlyphs,
137                    glyphMetrics,
138                    glyphInfoBuffer,
139                    metrics,
140                    calculatedAdvance);
141 }
142
143 float GetCalculatedAdvance(unsigned int character, float characterSpacing, float advance)
144 {
145   //Gets the final advance value by adding the CharacterSpacing value to it
146   //In some cases the CharacterSpacing should not be added. Ex: when the glyph is a ZWSP (Zero Width Space)
147   return (TextAbstraction::IsZeroWidthNonJoiner(character) || TextAbstraction::IsZeroWidthJoiner(character) ||
148           TextAbstraction::IsZeroWidthSpace(character) || TextAbstraction::IsNewParagraph(character) ||
149           TextAbstraction::IsLeftToRightMark(character) || TextAbstraction::IsRightToLeftMark(character))
150            ? advance
151            : advance + characterSpacing;
152 }
153
154 } // namespace Text
155
156 } // namespace Toolkit
157
158 } // namespace Dali