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