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/text-controller-background-actor.h>
22 #include <dali/public-api/rendering/renderer.h>
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>
31 namespace Dali::Toolkit::Text
35 struct BackgroundVertex
37 Vector2 mPosition; ///< Vertex posiiton
38 Vector4 mColor; ///< Vertex color
43 Vector<BackgroundVertex> mVertices; ///< container of vertices
44 Vector<unsigned short> mIndices; ///< container of indices
46 } // unnamed namespace
48 Length CalculateBackgroundLineHeight(LineRun lineRun)
50 Length height = lineRun.ascender + -(lineRun.descender);
52 if(lineRun.lineSpacing > 0)
54 height += lineRun.lineSpacing;
60 Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr& textVisualModel, const LogicalModelPtr& textLogicalModel, Shader& textShaderBackground)
62 // NOTE: Currently we only support background color for left-to-right text.
66 Length numberOfGlyphs = textView.GetNumberOfGlyphs();
67 if(numberOfGlyphs > 0u)
69 Vector<GlyphInfo> glyphs;
70 glyphs.Resize(numberOfGlyphs);
72 Vector<Vector2> positions;
73 positions.Resize(numberOfGlyphs);
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(),
84 glyphs.Resize(numberOfGlyphs);
85 positions.Resize(numberOfGlyphs);
87 const GlyphInfo* const glyphsBuffer = glyphs.Begin();
88 const Vector2* const positionsBuffer = positions.Begin();
91 mesh.mVertices.Reserve(4u * glyphs.Size());
92 mesh.mIndices.Reserve(6u * glyphs.Size());
94 const Vector2 textSize = textView.GetLayoutSize();
96 const float offsetX = alignmentOffset + textSize.width * 0.5f;
97 const float offsetY = textSize.height * 0.5f;
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;
107 // Get the character-spacing runs.
108 const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = textVisualModel->GetCharacterSpacingGlyphRuns();
111 uint32_t numberOfQuads = 0u;
112 Length yLineOffset = 0;
113 Length prevLineIndex = 0;
115 Length numberOfLines;
117 for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
119 const GlyphInfo& glyph = *(glyphsBuffer + i);
121 // Get the background color of the character.
122 // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
123 const bool isMarkupBackground = textView.IsMarkupBackgroundColorSet();
124 const ColorIndex backgroundColorIndex = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
125 const bool isDefaultBackgroundColor = (0u == backgroundColorIndex);
126 const Vector4& backgroundColor = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
128 textVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
129 Length lineHeight = CalculateBackgroundLineHeight(lineRun[lineIndex]);
131 if(lineIndex != prevLineIndex)
133 yLineOffset += CalculateBackgroundLineHeight(lineRun[prevLineIndex]);
135 if(lineRun[prevLineIndex].lineSpacing < 0)
137 yLineOffset += lineRun[prevLineIndex].lineSpacing;
141 // Only create quads for glyphs with a background color
142 if(backgroundColor != Color::TRANSPARENT)
144 const float characterSpacing = GetGlyphCharacterSpacing(i, characterSpacingGlyphRuns, modelCharacterSpacing);
146 const Vector2 position = *(positionsBuffer + i);
147 calculatedAdvance = GetCalculatedAdvance(*(textLogicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + i))), characterSpacing, glyph.advance);
149 if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
152 quad.y = yLineOffset;
153 quad.z = quad.x + std::max(calculatedAdvance, glyph.xBearing + glyph.width);
156 else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
159 quad.y = yLineOffset;
160 quad.z = quad.x - glyph.xBearing + calculatedAdvance;
161 quad.w = quad.y + lineHeight;
163 else if(i == glyphSize - 1u) // The last glyph in the whole text
165 quad.x = position.x - glyph.xBearing;
166 quad.y = yLineOffset;
167 quad.z = quad.x + std::max(calculatedAdvance, glyph.xBearing + glyph.width);
168 quad.w = quad.y + lineHeight;
170 else // The glyph in the middle of the text
172 quad.x = position.x - glyph.xBearing;
173 quad.y = yLineOffset;
174 quad.z = quad.x + calculatedAdvance;
175 quad.w = quad.y + lineHeight;
178 BackgroundVertex vertex;
181 vertex.mPosition.x = quad.x - offsetX;
182 vertex.mPosition.y = quad.y - offsetY;
183 vertex.mColor = backgroundColor;
184 mesh.mVertices.PushBack(vertex);
187 vertex.mPosition.x = quad.z - offsetX;
188 vertex.mPosition.y = quad.y - offsetY;
189 vertex.mColor = backgroundColor;
190 mesh.mVertices.PushBack(vertex);
193 vertex.mPosition.x = quad.x - offsetX;
194 vertex.mPosition.y = quad.w - offsetY;
195 vertex.mColor = backgroundColor;
196 mesh.mVertices.PushBack(vertex);
199 vertex.mPosition.x = quad.z - offsetX;
200 vertex.mPosition.y = quad.w - offsetY;
201 vertex.mColor = backgroundColor;
202 mesh.mVertices.PushBack(vertex);
204 // Six indices in counter clockwise winding
205 mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
206 mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
207 mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
208 mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
209 mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
210 mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
215 if(lineIndex != prevLineIndex)
217 prevLineIndex = lineIndex;
221 // Only create the background actor if there are glyphs with background color
222 if(mesh.mVertices.Count() > 0u)
224 Property::Map quadVertexFormat;
225 quadVertexFormat["aPosition"] = Property::VECTOR2;
226 quadVertexFormat["aColor"] = Property::VECTOR4;
228 VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
229 quadVertices.SetData(&mesh.mVertices[0], mesh.mVertices.Size());
231 Geometry quadGeometry = Geometry::New();
232 quadGeometry.AddVertexBuffer(quadVertices);
233 quadGeometry.SetIndexBuffer(&mesh.mIndices[0], mesh.mIndices.Size());
235 if(!textShaderBackground)
237 textShaderBackground = Shader::New(SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG);
240 Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, textShaderBackground);
241 renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
242 renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
244 actor = Actor::New();
245 actor.SetProperty(Dali::Actor::Property::NAME, "TextBackgroundColorActor");
246 actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
247 actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
248 actor.SetProperty(Actor::Property::SIZE, textSize);
249 actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
250 actor.AddRenderer(renderer);
257 } // namespace Dali::Toolkit::Text