[dali_2.1.30] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / controller / text-controller-background-actor.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 // HEADER
19 #include <dali-toolkit/internal/text/controller/text-controller-background-actor.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/rendering/renderer.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
26 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
27 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
28 #include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
29 #include <dali-toolkit/internal/text/text-view.h>
30
31 namespace Dali::Toolkit::Text
32 {
33 namespace
34 {
35 struct BackgroundVertex
36 {
37   Vector2 mPosition; ///< Vertex posiiton
38   Vector4 mColor;    ///< Vertex color
39 };
40
41 struct BackgroundMesh
42 {
43   Vector<BackgroundVertex> mVertices; ///< container of vertices
44   Vector<unsigned short>   mIndices;  ///< container of indices
45 };
46 } // unnamed namespace
47
48 Length CalculateBackgroundLineHeight(LineRun lineRun)
49 {
50   Length height = lineRun.ascender + -(lineRun.descender);
51
52   if(lineRun.lineSpacing > 0)
53   {
54     height += lineRun.lineSpacing;
55   }
56
57   return height;
58 }
59
60 Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr& textVisualModel, const LogicalModelPtr& textLogicalModel, Shader& textShaderBackground)
61 {
62   // NOTE: Currently we only support background color for left-to-right text.
63
64   Actor actor;
65
66   Length numberOfGlyphs = textView.GetNumberOfGlyphs();
67   if(numberOfGlyphs > 0u)
68   {
69     Vector<GlyphInfo> glyphs;
70     glyphs.Resize(numberOfGlyphs);
71
72     Vector<Vector2> positions;
73     positions.Resize(numberOfGlyphs);
74
75     // Get the line where the glyphs are laid-out.
76     const LineRun* lineRun         = textVisualModel->mLines.Begin();
77     float          alignmentOffset = lineRun->alignmentOffset;
78     numberOfGlyphs                 = textView.GetGlyphs(glyphs.Begin(),
79                                         positions.Begin(),
80                                         alignmentOffset,
81                                         0u,
82                                         numberOfGlyphs);
83
84     glyphs.Resize(numberOfGlyphs);
85     positions.Resize(numberOfGlyphs);
86
87     const GlyphInfo* const glyphsBuffer    = glyphs.Begin();
88     const Vector2* const   positionsBuffer = positions.Begin();
89
90     BackgroundMesh mesh;
91     mesh.mVertices.Reserve(4u * glyphs.Size());
92     mesh.mIndices.Reserve(6u * glyphs.Size());
93
94     const Vector2 textSize = textView.GetLayoutSize();
95
96     const float offsetX = alignmentOffset + textSize.width * 0.5f;
97     const float offsetY = textSize.height * 0.5f;
98
99     const Vector4* const    backgroundColorsBuffer       = textView.GetBackgroundColors();
100     const ColorIndex* const backgroundColorIndicesBuffer = textView.GetBackgroundColorIndices();
101     const Vector4&          defaultBackgroundColor       = textVisualModel->IsBackgroundEnabled() ? textVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
102     const float             modelCharacterSpacing        = textVisualModel->GetCharacterSpacing();
103     Vector<CharacterIndex>& glyphToCharacterMap          = textVisualModel->mGlyphsToCharacters;
104     const CharacterIndex*   glyphToCharacterMapBuffer    = glyphToCharacterMap.Begin();
105     float                   calculatedAdvance            = 0.f;
106
107     // Get the character-spacing runs.
108     const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = textVisualModel->GetCharacterSpacingGlyphRuns();
109
110     Vector4   quad;
111     uint32_t  numberOfQuads = 0u;
112     Length    yLineOffset   = 0;
113     Length    prevLineIndex = 0;
114     LineIndex lineIndex;
115
116     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
117     {
118       const GlyphInfo& glyph = *(glyphsBuffer + i);
119
120       // Get the background color of the character.
121       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
122       const bool       isMarkupBackground       = textView.IsMarkupBackgroundColorSet();
123       const ColorIndex backgroundColorIndex     = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
124       const bool       isDefaultBackgroundColor = (0u == backgroundColorIndex);
125       const Vector4&   backgroundColor          = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
126
127       lineIndex         = textVisualModel->GetLineOfGlyph(i);
128       Length lineHeight = CalculateBackgroundLineHeight(lineRun[lineIndex]);
129
130       if(lineIndex != prevLineIndex)
131       {
132         yLineOffset += CalculateBackgroundLineHeight(lineRun[prevLineIndex]);
133
134         if(lineRun[prevLineIndex].lineSpacing < 0)
135         {
136           yLineOffset += lineRun[prevLineIndex].lineSpacing;
137         }
138       }
139
140       // Only create quads for glyphs with a background color
141       if(backgroundColor != Color::TRANSPARENT)
142       {
143         const float characterSpacing = GetGlyphCharacterSpacing(i, characterSpacingGlyphRuns, modelCharacterSpacing);
144
145         const Vector2 position = *(positionsBuffer + i);
146         calculatedAdvance      = GetCalculatedAdvance(*(textLogicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + i))), characterSpacing, glyph.advance);
147
148         if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
149         {
150           quad.x = position.x;
151           quad.y = yLineOffset;
152           quad.z = quad.x + std::max(calculatedAdvance, glyph.xBearing + glyph.width);
153           quad.w = lineHeight;
154         }
155         else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
156         {
157           quad.x = position.x;
158           quad.y = yLineOffset;
159           quad.z = quad.x - glyph.xBearing + calculatedAdvance;
160           quad.w = quad.y + lineHeight;
161         }
162         else if(i == glyphSize - 1u) // The last glyph in the whole text
163         {
164           quad.x = position.x - glyph.xBearing;
165           quad.y = yLineOffset;
166           quad.z = quad.x + std::max(calculatedAdvance, glyph.xBearing + glyph.width);
167           quad.w = quad.y + lineHeight;
168         }
169         else // The glyph in the middle of the text
170         {
171           quad.x = position.x - glyph.xBearing;
172           quad.y = yLineOffset;
173           quad.z = quad.x + calculatedAdvance;
174           quad.w = quad.y + lineHeight;
175         }
176
177         BackgroundVertex vertex;
178
179         // Top left
180         vertex.mPosition.x = quad.x - offsetX;
181         vertex.mPosition.y = quad.y - offsetY;
182         vertex.mColor      = backgroundColor;
183         mesh.mVertices.PushBack(vertex);
184
185         // Top right
186         vertex.mPosition.x = quad.z - offsetX;
187         vertex.mPosition.y = quad.y - offsetY;
188         vertex.mColor      = backgroundColor;
189         mesh.mVertices.PushBack(vertex);
190
191         // Bottom left
192         vertex.mPosition.x = quad.x - offsetX;
193         vertex.mPosition.y = quad.w - offsetY;
194         vertex.mColor      = backgroundColor;
195         mesh.mVertices.PushBack(vertex);
196
197         // Bottom right
198         vertex.mPosition.x = quad.z - offsetX;
199         vertex.mPosition.y = quad.w - offsetY;
200         vertex.mColor      = backgroundColor;
201         mesh.mVertices.PushBack(vertex);
202
203         // Six indices in counter clockwise winding
204         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
205         mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
206         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
207         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
208         mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
209         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
210
211         numberOfQuads++;
212       }
213
214       if(lineIndex != prevLineIndex)
215       {
216         prevLineIndex = lineIndex;
217       }
218     }
219
220     // Only create the background actor if there are glyphs with background color
221     if(mesh.mVertices.Count() > 0u)
222     {
223       Property::Map quadVertexFormat;
224       quadVertexFormat["aPosition"] = Property::VECTOR2;
225       quadVertexFormat["aColor"]    = Property::VECTOR4;
226
227       VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
228       quadVertices.SetData(&mesh.mVertices[0], mesh.mVertices.Size());
229
230       Geometry quadGeometry = Geometry::New();
231       quadGeometry.AddVertexBuffer(quadVertices);
232       quadGeometry.SetIndexBuffer(&mesh.mIndices[0], mesh.mIndices.Size());
233
234       if(!textShaderBackground)
235       {
236         textShaderBackground = Shader::New(SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG);
237       }
238
239       Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, textShaderBackground);
240       renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
241       renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
242
243       actor = Actor::New();
244       actor.SetProperty(Dali::Actor::Property::NAME, "TextBackgroundColorActor");
245       actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
246       actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
247       actor.SetProperty(Actor::Property::SIZE, textSize);
248       actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
249       actor.AddRenderer(renderer);
250     }
251   }
252
253   return actor;
254 }
255
256 } // namespace Dali::Toolkit::Text