1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License.
5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at
6a3e0fd82Sopenharmony_ci *
7a3e0fd82Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8a3e0fd82Sopenharmony_ci *
9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and
13a3e0fd82Sopenharmony_ci * limitations under the License.
14a3e0fd82Sopenharmony_ci */
15a3e0fd82Sopenharmony_ci
16a3e0fd82Sopenharmony_ci#include "draw/draw_label.h"
17a3e0fd82Sopenharmony_ci#include "common/typed_text.h"
18a3e0fd82Sopenharmony_ci#include "draw/draw_utils.h"
19a3e0fd82Sopenharmony_ci#include "engines/gfx/gfx_engine_manager.h"
20a3e0fd82Sopenharmony_ci#include "font/ui_font.h"
21a3e0fd82Sopenharmony_ci#include "font/ui_font_header.h"
22a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_log.h"
23a3e0fd82Sopenharmony_ci
24a3e0fd82Sopenharmony_cinamespace OHOS {
25a3e0fd82Sopenharmony_ciuint16_t DrawLabel::DrawTextOneLine(BufferInfo& gfxDstBuffer, const LabelLineInfo& labelLine, uint16_t& letterIndex)
26a3e0fd82Sopenharmony_ci{
27a3e0fd82Sopenharmony_ci    if (labelLine.text == nullptr) {
28a3e0fd82Sopenharmony_ci        return 0;
29a3e0fd82Sopenharmony_ci    }
30a3e0fd82Sopenharmony_ci    UIFont* fontEngine = UIFont::GetInstance();
31a3e0fd82Sopenharmony_ci    if (labelLine.direct == TEXT_DIRECT_RTL) {
32a3e0fd82Sopenharmony_ci        labelLine.pos.x -= labelLine.offset.x;
33a3e0fd82Sopenharmony_ci    } else {
34a3e0fd82Sopenharmony_ci        labelLine.pos.x += labelLine.offset.x;
35a3e0fd82Sopenharmony_ci    }
36a3e0fd82Sopenharmony_ci
37a3e0fd82Sopenharmony_ci    uint32_t i = 0;
38a3e0fd82Sopenharmony_ci    uint16_t retOffsetY = 0; // ret value elipse offsetY
39a3e0fd82Sopenharmony_ci    uint16_t offsetPosY = 0;
40a3e0fd82Sopenharmony_ci    uint8_t maxLetterSize = GetLineMaxLetterSize(labelLine.text, labelLine.lineLength, labelLine.fontId,
41a3e0fd82Sopenharmony_ci                                                 labelLine.fontSize, letterIndex, labelLine.spannableString);
42a3e0fd82Sopenharmony_ci    GlyphNode glyphNode;
43a3e0fd82Sopenharmony_ci    while (i < labelLine.lineLength) {
44a3e0fd82Sopenharmony_ci        uint32_t letter = TypedText::GetUTF8Next(labelLine.text, i, i);
45a3e0fd82Sopenharmony_ci        uint16_t fontId = labelLine.fontId;
46a3e0fd82Sopenharmony_ci        uint8_t fontSize = labelLine.fontSize;
47a3e0fd82Sopenharmony_ci#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
48a3e0fd82Sopenharmony_ci        TextStyle textStyle = TEXT_STYLE_NORMAL;
49a3e0fd82Sopenharmony_ci        if (labelLine.textStyles) {
50a3e0fd82Sopenharmony_ci            textStyle = labelLine.textStyles[letterIndex];
51a3e0fd82Sopenharmony_ci        }
52a3e0fd82Sopenharmony_ci#endif
53a3e0fd82Sopenharmony_ci        bool haveLineBackgroundColor = false;
54a3e0fd82Sopenharmony_ci        ColorType lineBackgroundColor;
55a3e0fd82Sopenharmony_ci        bool havebackgroundColor = false;
56a3e0fd82Sopenharmony_ci        ColorType backgroundColor;
57a3e0fd82Sopenharmony_ci        ColorType foregroundColor = labelLine.style.textColor_;
58a3e0fd82Sopenharmony_ci
59a3e0fd82Sopenharmony_ci        if (labelLine.spannableString != nullptr && labelLine.spannableString->GetSpannable(letterIndex)) {
60a3e0fd82Sopenharmony_ci            labelLine.spannableString->GetFontId(letterIndex, fontId);
61a3e0fd82Sopenharmony_ci            labelLine.spannableString->GetFontSize(letterIndex, fontSize);
62a3e0fd82Sopenharmony_ci            havebackgroundColor = labelLine.spannableString->GetBackgroundColor(letterIndex, backgroundColor);
63a3e0fd82Sopenharmony_ci            labelLine.spannableString->GetForegroundColor(letterIndex, foregroundColor);
64a3e0fd82Sopenharmony_ci#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
65a3e0fd82Sopenharmony_ci            labelLine.spannableString->GetTextStyle(letterIndex, textStyle);
66a3e0fd82Sopenharmony_ci#endif
67a3e0fd82Sopenharmony_ci            haveLineBackgroundColor =
68a3e0fd82Sopenharmony_ci                labelLine.spannableString->GetLineBackgroundColor(letterIndex, lineBackgroundColor);
69a3e0fd82Sopenharmony_ci        }
70a3e0fd82Sopenharmony_ci        LabelLetterInfo letterInfo{labelLine.pos,
71a3e0fd82Sopenharmony_ci                                   labelLine.mask,
72a3e0fd82Sopenharmony_ci                                   foregroundColor,
73a3e0fd82Sopenharmony_ci                                   labelLine.opaScale,
74a3e0fd82Sopenharmony_ci                                   0,
75a3e0fd82Sopenharmony_ci                                   0,
76a3e0fd82Sopenharmony_ci                                   letter,
77a3e0fd82Sopenharmony_ci                                   labelLine.direct,
78a3e0fd82Sopenharmony_ci                                   fontId,
79a3e0fd82Sopenharmony_ci                                   0,
80a3e0fd82Sopenharmony_ci                                   fontSize,
81a3e0fd82Sopenharmony_ci#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
82a3e0fd82Sopenharmony_ci                                   textStyle,
83a3e0fd82Sopenharmony_ci#endif
84a3e0fd82Sopenharmony_ci                                   labelLine.baseLine,
85a3e0fd82Sopenharmony_ci                                   labelLine.style.letterSpace_,
86a3e0fd82Sopenharmony_ci                                   labelLine.style.lineSpace_,
87a3e0fd82Sopenharmony_ci                                   havebackgroundColor,
88a3e0fd82Sopenharmony_ci                                   backgroundColor,
89a3e0fd82Sopenharmony_ci                                   haveLineBackgroundColor,
90a3e0fd82Sopenharmony_ci                                   lineBackgroundColor
91a3e0fd82Sopenharmony_ci                                   };
92a3e0fd82Sopenharmony_ci#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
93a3e0fd82Sopenharmony_ci        glyphNode.textStyle = letterInfo.textStyle;
94a3e0fd82Sopenharmony_ci#endif
95a3e0fd82Sopenharmony_ci        glyphNode.advance = 0;
96a3e0fd82Sopenharmony_ci        uint8_t* fontMap = fontEngine->GetBitmap(letterInfo.letter, glyphNode, letterInfo.fontId, letterInfo.fontSize,
97a3e0fd82Sopenharmony_ci                                                 letterInfo.shapingId);
98a3e0fd82Sopenharmony_ci        if (fontMap != nullptr) {
99a3e0fd82Sopenharmony_ci            uint8_t weight = fontEngine->GetFontWeight(glyphNode.fontId);
100a3e0fd82Sopenharmony_ci            // 16: rgb565->16 rgba8888->32 font with rgba
101a3e0fd82Sopenharmony_ci            if (weight >= 16) {
102a3e0fd82Sopenharmony_ci                DrawUtils::GetInstance()->DrawColorLetter(gfxDstBuffer, letterInfo, fontMap,
103a3e0fd82Sopenharmony_ci                                                          glyphNode, labelLine.lineHeight);
104a3e0fd82Sopenharmony_ci            } else {
105a3e0fd82Sopenharmony_ci                letterInfo.offsetY = labelLine.ellipsisOssetY == 0 ? offsetPosY : labelLine.ellipsisOssetY;
106a3e0fd82Sopenharmony_ci                retOffsetY = offsetPosY;
107a3e0fd82Sopenharmony_ci                DrawUtils::GetInstance()->DrawNormalLetter(gfxDstBuffer, letterInfo, fontMap, glyphNode, maxLetterSize);
108a3e0fd82Sopenharmony_ci            }
109a3e0fd82Sopenharmony_ci        }
110a3e0fd82Sopenharmony_ci        if (labelLine.direct == TEXT_DIRECT_RTL) {
111a3e0fd82Sopenharmony_ci            labelLine.pos.x -= (glyphNode.advance + labelLine.style.letterSpace_);
112a3e0fd82Sopenharmony_ci        } else {
113a3e0fd82Sopenharmony_ci            labelLine.pos.x += (glyphNode.advance + labelLine.style.letterSpace_);
114a3e0fd82Sopenharmony_ci        }
115a3e0fd82Sopenharmony_ci        letterIndex++;
116a3e0fd82Sopenharmony_ci    }
117a3e0fd82Sopenharmony_ci    return retOffsetY;
118a3e0fd82Sopenharmony_ci}
119a3e0fd82Sopenharmony_ci
120a3e0fd82Sopenharmony_ciuint8_t DrawLabel::GetLineMaxLetterSize(const char* text, uint16_t lineLength, uint16_t fontId, uint8_t fontSize,
121a3e0fd82Sopenharmony_ci                                        uint16_t letterIndex, SpannableString* spannableString)
122a3e0fd82Sopenharmony_ci{
123a3e0fd82Sopenharmony_ci    if (spannableString == nullptr) {
124a3e0fd82Sopenharmony_ci        return fontSize;
125a3e0fd82Sopenharmony_ci    }
126a3e0fd82Sopenharmony_ci    uint32_t i = 0;
127a3e0fd82Sopenharmony_ci    uint8_t maxLetterSize = fontSize;
128a3e0fd82Sopenharmony_ci    while (i < lineLength) {
129a3e0fd82Sopenharmony_ci        uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
130a3e0fd82Sopenharmony_ci        if (TypedText::IsColourWord(unicode, fontId, fontSize)) {
131a3e0fd82Sopenharmony_ci            letterIndex++;
132a3e0fd82Sopenharmony_ci            continue;
133a3e0fd82Sopenharmony_ci        }
134a3e0fd82Sopenharmony_ci        if (spannableString != nullptr && spannableString->GetSpannable(letterIndex)) {
135a3e0fd82Sopenharmony_ci            uint8_t tempSize = fontSize;
136a3e0fd82Sopenharmony_ci            spannableString->GetFontSize(letterIndex, tempSize);
137a3e0fd82Sopenharmony_ci            if (tempSize > maxLetterSize) {
138a3e0fd82Sopenharmony_ci                maxLetterSize = tempSize;
139a3e0fd82Sopenharmony_ci            }
140a3e0fd82Sopenharmony_ci        }
141a3e0fd82Sopenharmony_ci        letterIndex++;
142a3e0fd82Sopenharmony_ci    }
143a3e0fd82Sopenharmony_ci    return maxLetterSize;
144a3e0fd82Sopenharmony_ci}
145a3e0fd82Sopenharmony_ci
146a3e0fd82Sopenharmony_civoid DrawLabel::DrawArcText(BufferInfo& gfxDstBuffer,
147a3e0fd82Sopenharmony_ci                            const Rect& mask,
148a3e0fd82Sopenharmony_ci                            const char* text,
149a3e0fd82Sopenharmony_ci                            const Point& arcCenter,
150a3e0fd82Sopenharmony_ci                            uint16_t fontId,
151a3e0fd82Sopenharmony_ci                            uint8_t fontSize,
152a3e0fd82Sopenharmony_ci                            const ArcTextInfo arcTextInfo,
153a3e0fd82Sopenharmony_ci                            const float changeAngle,
154a3e0fd82Sopenharmony_ci                            TextOrientation orientation,
155a3e0fd82Sopenharmony_ci                            const Style& style,
156a3e0fd82Sopenharmony_ci                            OpacityType opaScale,
157a3e0fd82Sopenharmony_ci                            bool compatibilityMode)
158a3e0fd82Sopenharmony_ci{
159a3e0fd82Sopenharmony_ci    if ((text == nullptr) || (arcTextInfo.lineStart == arcTextInfo.lineEnd) || (arcTextInfo.radius == 0)) {
160a3e0fd82Sopenharmony_ci        GRAPHIC_LOGE("DrawLabel::DrawArcText invalid parameter\n");
161a3e0fd82Sopenharmony_ci        return;
162a3e0fd82Sopenharmony_ci    }
163a3e0fd82Sopenharmony_ci    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.textOpa_);
164a3e0fd82Sopenharmony_ci    if (opa == OPA_TRANSPARENT) {
165a3e0fd82Sopenharmony_ci        return;
166a3e0fd82Sopenharmony_ci    }
167a3e0fd82Sopenharmony_ci    uint16_t letterWidth;
168a3e0fd82Sopenharmony_ci    UIFont* fontEngine = UIFont::GetInstance();
169a3e0fd82Sopenharmony_ci
170a3e0fd82Sopenharmony_ci    uint16_t letterHeight = fontEngine->GetHeight(fontId, fontSize);
171a3e0fd82Sopenharmony_ci    uint32_t i = arcTextInfo.lineStart;
172a3e0fd82Sopenharmony_ci    bool orientationFlag = (orientation == TextOrientation::INSIDE);
173a3e0fd82Sopenharmony_ci    bool directFlag = (arcTextInfo.direct == TEXT_DIRECT_LTR);
174a3e0fd82Sopenharmony_ci    bool xorFlag = !directFlag;
175a3e0fd82Sopenharmony_ci    if (compatibilityMode) {
176a3e0fd82Sopenharmony_ci        xorFlag = !((orientationFlag && directFlag) || (!orientationFlag && !directFlag));
177a3e0fd82Sopenharmony_ci    }
178a3e0fd82Sopenharmony_ci    float angle = directFlag ? (arcTextInfo.startAngle + changeAngle) : (arcTextInfo.startAngle - changeAngle);
179a3e0fd82Sopenharmony_ci
180a3e0fd82Sopenharmony_ci    float posX;
181a3e0fd82Sopenharmony_ci    float posY;
182a3e0fd82Sopenharmony_ci    float rotateAngle;
183a3e0fd82Sopenharmony_ci    while (i < arcTextInfo.lineEnd) {
184a3e0fd82Sopenharmony_ci        uint32_t tmp = i;
185a3e0fd82Sopenharmony_ci        uint32_t letter = TypedText::GetUTF8Next(text, tmp, i);
186a3e0fd82Sopenharmony_ci        if (letter == 0) {
187a3e0fd82Sopenharmony_ci            continue;
188a3e0fd82Sopenharmony_ci        }
189a3e0fd82Sopenharmony_ci        if ((letter == '\r') || (letter == '\n')) {
190a3e0fd82Sopenharmony_ci            break;
191a3e0fd82Sopenharmony_ci        }
192a3e0fd82Sopenharmony_ci        letterWidth = fontEngine->GetWidth(letter, fontId, fontSize, 0);
193a3e0fd82Sopenharmony_ci        if (!DrawLabel::CalculateAngle(letterWidth, letterHeight, style.letterSpace_,
194a3e0fd82Sopenharmony_ci                                       arcTextInfo, xorFlag, tmp, orientation,
195a3e0fd82Sopenharmony_ci                                       posX, posY, rotateAngle, angle,
196a3e0fd82Sopenharmony_ci                                       arcCenter, compatibilityMode)) {
197a3e0fd82Sopenharmony_ci            continue;
198a3e0fd82Sopenharmony_ci        }
199a3e0fd82Sopenharmony_ci
200a3e0fd82Sopenharmony_ci        ArcLetterInfo letterInfo;
201a3e0fd82Sopenharmony_ci        letterInfo.InitData(fontId, fontSize, letter, { MATH_ROUND(posX), MATH_ROUND(posY) },
202a3e0fd82Sopenharmony_ci            static_cast<int16_t>(rotateAngle), style.textColor_, opaScale, arcTextInfo.startAngle,
203a3e0fd82Sopenharmony_ci            arcTextInfo.endAngle, angle, arcTextInfo.radius, compatibilityMode,
204a3e0fd82Sopenharmony_ci            directFlag, orientationFlag, arcTextInfo.hasAnimator);
205a3e0fd82Sopenharmony_ci
206a3e0fd82Sopenharmony_ci        DrawLetterWithRotate(gfxDstBuffer, mask, letterInfo, posX, posY);
207a3e0fd82Sopenharmony_ci    }
208a3e0fd82Sopenharmony_ci}
209a3e0fd82Sopenharmony_ci
210a3e0fd82Sopenharmony_cibool DrawLabel::CalculateAngle(uint16_t letterWidth,
211a3e0fd82Sopenharmony_ci                               uint16_t letterHeight,
212a3e0fd82Sopenharmony_ci                               int16_t letterSpace,
213a3e0fd82Sopenharmony_ci                               const ArcTextInfo arcTextInfo,
214a3e0fd82Sopenharmony_ci                               bool xorFlag,
215a3e0fd82Sopenharmony_ci                               uint32_t index,
216a3e0fd82Sopenharmony_ci                               TextOrientation orientation,
217a3e0fd82Sopenharmony_ci                               float& posX,
218a3e0fd82Sopenharmony_ci                               float& posY,
219a3e0fd82Sopenharmony_ci                               float& rotateAngle,
220a3e0fd82Sopenharmony_ci                               float& angle,
221a3e0fd82Sopenharmony_ci                               const Point& arcCenter,
222a3e0fd82Sopenharmony_ci                               bool compatibilityMode)
223a3e0fd82Sopenharmony_ci{
224a3e0fd82Sopenharmony_ci    const int DIVIDER_BY_TWO = 2;
225a3e0fd82Sopenharmony_ci    if (compatibilityMode) {
226a3e0fd82Sopenharmony_ci        if ((index == arcTextInfo.lineStart) && xorFlag) {
227a3e0fd82Sopenharmony_ci            angle += TypedText::GetAngleForArcLen(static_cast<float>(letterWidth), letterHeight, arcTextInfo.radius,
228a3e0fd82Sopenharmony_ci                                                  arcTextInfo.direct, orientation);
229a3e0fd82Sopenharmony_ci        }
230a3e0fd82Sopenharmony_ci        uint16_t arcLen = letterWidth + letterSpace;
231a3e0fd82Sopenharmony_ci        if (arcLen == 0) {
232a3e0fd82Sopenharmony_ci            return false;
233a3e0fd82Sopenharmony_ci        }
234a3e0fd82Sopenharmony_ci        float incrementAngle = TypedText::GetAngleForArcLen(static_cast<float>(arcLen), letterHeight,
235a3e0fd82Sopenharmony_ci                                                            arcTextInfo.radius, arcTextInfo.direct, orientation);
236a3e0fd82Sopenharmony_ci
237a3e0fd82Sopenharmony_ci        rotateAngle = (orientation == TextOrientation::INSIDE) ? angle : (angle - SEMICIRCLE_IN_DEGREE);
238a3e0fd82Sopenharmony_ci
239a3e0fd82Sopenharmony_ci        // 2: half
240a3e0fd82Sopenharmony_ci        float fineTuningAngle = incrementAngle * (static_cast<float>(letterWidth) / (DIVIDER_BY_TWO * arcLen));
241a3e0fd82Sopenharmony_ci        rotateAngle += (xorFlag ? -fineTuningAngle : fineTuningAngle);
242a3e0fd82Sopenharmony_ci        TypedText::GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY);
243a3e0fd82Sopenharmony_ci        angle += incrementAngle;
244a3e0fd82Sopenharmony_ci    } else {
245a3e0fd82Sopenharmony_ci        float incrementAngle = TypedText::GetAngleForArcLen(letterWidth, letterSpace, arcTextInfo.radius);
246a3e0fd82Sopenharmony_ci        if (incrementAngle >= -EPSINON && incrementAngle <= EPSINON) {
247a3e0fd82Sopenharmony_ci            return false;
248a3e0fd82Sopenharmony_ci        }
249a3e0fd82Sopenharmony_ci
250a3e0fd82Sopenharmony_ci        float fineTuningAngle = incrementAngle / DIVIDER_BY_TWO;
251a3e0fd82Sopenharmony_ci        rotateAngle = xorFlag ? (angle - SEMICIRCLE_IN_DEGREE - fineTuningAngle) : (angle + fineTuningAngle);
252a3e0fd82Sopenharmony_ci        TypedText::GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY);
253a3e0fd82Sopenharmony_ci        angle = xorFlag ? (angle - incrementAngle) : (angle + incrementAngle);
254a3e0fd82Sopenharmony_ci    }
255a3e0fd82Sopenharmony_ci
256a3e0fd82Sopenharmony_ci    return true;
257a3e0fd82Sopenharmony_ci}
258a3e0fd82Sopenharmony_ci
259a3e0fd82Sopenharmony_civoid DrawLabel::DrawLetterWithRotate(BufferInfo& gfxDstBuffer,
260a3e0fd82Sopenharmony_ci                                     const Rect& mask,
261a3e0fd82Sopenharmony_ci                                     const ArcLetterInfo& letterInfo,
262a3e0fd82Sopenharmony_ci                                     float posX,
263a3e0fd82Sopenharmony_ci                                     float posY)
264a3e0fd82Sopenharmony_ci{
265a3e0fd82Sopenharmony_ci    UIFont* fontEngine = UIFont::GetInstance();
266a3e0fd82Sopenharmony_ci    FontHeader head;
267a3e0fd82Sopenharmony_ci    GlyphNode node;
268a3e0fd82Sopenharmony_ci#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
269a3e0fd82Sopenharmony_ci    node.textStyle = TEXT_STYLE_NORMAL;
270a3e0fd82Sopenharmony_ci#endif
271a3e0fd82Sopenharmony_ci    if (fontEngine->GetFontHeader(head, letterInfo.fontId, letterInfo.fontSize) != 0) {
272a3e0fd82Sopenharmony_ci        return;
273a3e0fd82Sopenharmony_ci    }
274a3e0fd82Sopenharmony_ci
275a3e0fd82Sopenharmony_ci    const uint8_t* fontMap = fontEngine->GetBitmap(letterInfo.letter, node,
276a3e0fd82Sopenharmony_ci        letterInfo.fontId, letterInfo.fontSize, 0);
277a3e0fd82Sopenharmony_ci    if (fontMap == nullptr) {
278a3e0fd82Sopenharmony_ci        return;
279a3e0fd82Sopenharmony_ci    }
280a3e0fd82Sopenharmony_ci    uint8_t fontWeight = fontEngine->GetFontWeight(letterInfo.fontId);
281a3e0fd82Sopenharmony_ci    ColorMode colorMode = fontEngine->GetColorType(letterInfo.fontId);
282a3e0fd82Sopenharmony_ci
283a3e0fd82Sopenharmony_ci    int16_t offset = letterInfo.compatibilityMode ? head.ascender : 0;
284a3e0fd82Sopenharmony_ci    Rect rectLetter;
285a3e0fd82Sopenharmony_ci    rectLetter.Resize(node.cols, node.rows);
286a3e0fd82Sopenharmony_ci    TransformMap transMap(rectLetter);
287a3e0fd82Sopenharmony_ci    // Avoiding errors caused by rounding calculations
288a3e0fd82Sopenharmony_ci    transMap.Translate(Vector2<float>(posX + node.left, posY + offset - node.top));
289a3e0fd82Sopenharmony_ci    transMap.Rotate(letterInfo.rotateAngle, Vector2<float>(posX, posY));
290a3e0fd82Sopenharmony_ci
291a3e0fd82Sopenharmony_ci    TransformDataInfo letterTranDataInfo = {ImageHeader{colorMode, 0, 0, 0, node.cols, node.rows}, fontMap, fontWeight,
292a3e0fd82Sopenharmony_ci                                            BlurLevel::LEVEL0, TransformAlgorithm::BILINEAR};
293a3e0fd82Sopenharmony_ci
294a3e0fd82Sopenharmony_ci    uint8_t* buffer = nullptr;
295a3e0fd82Sopenharmony_ci    if (letterInfo.hasAnimator) {
296a3e0fd82Sopenharmony_ci        bool inRange = DrawLabel::CalculatedTransformDataInfo(&buffer, letterTranDataInfo, letterInfo);
297a3e0fd82Sopenharmony_ci        if (inRange == false) {
298a3e0fd82Sopenharmony_ci            if (buffer != nullptr) {
299a3e0fd82Sopenharmony_ci                UIFree(buffer);
300a3e0fd82Sopenharmony_ci                buffer = nullptr;
301a3e0fd82Sopenharmony_ci            }
302a3e0fd82Sopenharmony_ci            return;
303a3e0fd82Sopenharmony_ci        }
304a3e0fd82Sopenharmony_ci    }
305a3e0fd82Sopenharmony_ci
306a3e0fd82Sopenharmony_ci    BaseGfxEngine::GetInstance()->DrawTransform(gfxDstBuffer, mask, Point { 0, 0 }, letterInfo.color,
307a3e0fd82Sopenharmony_ci        letterInfo.opaScale, transMap, letterTranDataInfo);
308a3e0fd82Sopenharmony_ci    if (buffer != nullptr) {
309a3e0fd82Sopenharmony_ci        UIFree(buffer);
310a3e0fd82Sopenharmony_ci        buffer = nullptr;
311a3e0fd82Sopenharmony_ci    }
312a3e0fd82Sopenharmony_ci}
313a3e0fd82Sopenharmony_ci
314a3e0fd82Sopenharmony_cibool DrawLabel::CalculatedClipAngle(const ArcLetterInfo& letterInfo, float& angle)
315a3e0fd82Sopenharmony_ci{
316a3e0fd82Sopenharmony_ci    if (letterInfo.directFlag) {
317a3e0fd82Sopenharmony_ci        if ((letterInfo.compatibilityMode && letterInfo.orientationFlag) || !letterInfo.compatibilityMode) {
318a3e0fd82Sopenharmony_ci            if (letterInfo.currentAngle > letterInfo.endAngle) {
319a3e0fd82Sopenharmony_ci                angle = letterInfo.currentAngle - letterInfo.endAngle;
320a3e0fd82Sopenharmony_ci            } else if (letterInfo.currentAngle > letterInfo.startAngle) {
321a3e0fd82Sopenharmony_ci                angle = letterInfo.currentAngle - letterInfo.startAngle;
322a3e0fd82Sopenharmony_ci            } else {
323a3e0fd82Sopenharmony_ci                return false;
324a3e0fd82Sopenharmony_ci            }
325a3e0fd82Sopenharmony_ci        } else {
326a3e0fd82Sopenharmony_ci            if (letterInfo.currentAngle > letterInfo.endAngle) {
327a3e0fd82Sopenharmony_ci                angle = letterInfo.currentAngle - letterInfo.endAngle;
328a3e0fd82Sopenharmony_ci            } else if (letterInfo.currentAngle > letterInfo.startAngle) {
329a3e0fd82Sopenharmony_ci                angle = letterInfo.currentAngle - letterInfo.startAngle;
330a3e0fd82Sopenharmony_ci            } else {
331a3e0fd82Sopenharmony_ci                return false;
332a3e0fd82Sopenharmony_ci            }
333a3e0fd82Sopenharmony_ci        }
334a3e0fd82Sopenharmony_ci    } else {
335a3e0fd82Sopenharmony_ci        if (letterInfo.compatibilityMode && letterInfo.orientationFlag) {
336a3e0fd82Sopenharmony_ci            if (letterInfo.currentAngle < letterInfo.endAngle) {
337a3e0fd82Sopenharmony_ci                angle = letterInfo.endAngle - letterInfo.currentAngle;
338a3e0fd82Sopenharmony_ci            } else if (letterInfo.currentAngle < letterInfo.startAngle) {
339a3e0fd82Sopenharmony_ci                angle = letterInfo.startAngle - letterInfo.currentAngle;
340a3e0fd82Sopenharmony_ci            } else {
341a3e0fd82Sopenharmony_ci                return false;
342a3e0fd82Sopenharmony_ci            }
343a3e0fd82Sopenharmony_ci        } else if ((letterInfo.compatibilityMode && !letterInfo.orientationFlag) || !letterInfo.compatibilityMode) {
344a3e0fd82Sopenharmony_ci            if (letterInfo.currentAngle < letterInfo.endAngle) {
345a3e0fd82Sopenharmony_ci                angle = letterInfo.endAngle - letterInfo.currentAngle;
346a3e0fd82Sopenharmony_ci            } else if (letterInfo.currentAngle < letterInfo.startAngle) {
347a3e0fd82Sopenharmony_ci                angle = letterInfo.startAngle - letterInfo.currentAngle;
348a3e0fd82Sopenharmony_ci            } else {
349a3e0fd82Sopenharmony_ci                return false;
350a3e0fd82Sopenharmony_ci            }
351a3e0fd82Sopenharmony_ci        }
352a3e0fd82Sopenharmony_ci    }
353a3e0fd82Sopenharmony_ci
354a3e0fd82Sopenharmony_ci    return true;
355a3e0fd82Sopenharmony_ci}
356a3e0fd82Sopenharmony_ci
357a3e0fd82Sopenharmony_civoid DrawLabel::OnCalculatedClockwise(const ArcLetterInfo& letterInfo, const uint16_t sizePerPx,
358a3e0fd82Sopenharmony_ci                                      const uint16_t cols, const int16_t offsetX, uint16_t& begin,
359a3e0fd82Sopenharmony_ci                                      uint16_t& copyCols, TextInRange& range)
360a3e0fd82Sopenharmony_ci{
361a3e0fd82Sopenharmony_ci    if (!letterInfo.directFlag) {
362a3e0fd82Sopenharmony_ci        return;
363a3e0fd82Sopenharmony_ci    }
364a3e0fd82Sopenharmony_ci    if ((letterInfo.compatibilityMode && letterInfo.orientationFlag) || !letterInfo.compatibilityMode) {
365a3e0fd82Sopenharmony_ci        if (letterInfo.currentAngle > letterInfo.endAngle) {
366a3e0fd82Sopenharmony_ci            if (offsetX >= cols) {
367a3e0fd82Sopenharmony_ci                range = TextInRange::OUT_RANGE;
368a3e0fd82Sopenharmony_ci            }
369a3e0fd82Sopenharmony_ci            copyCols = cols - offsetX;
370a3e0fd82Sopenharmony_ci        } else if (letterInfo.currentAngle > letterInfo.startAngle) {
371a3e0fd82Sopenharmony_ci            if (offsetX >= cols) {
372a3e0fd82Sopenharmony_ci                range = TextInRange::IN_RANGE;
373a3e0fd82Sopenharmony_ci            }
374a3e0fd82Sopenharmony_ci            copyCols = offsetX;
375a3e0fd82Sopenharmony_ci            begin = (cols - offsetX) * sizePerPx;
376a3e0fd82Sopenharmony_ci        }
377a3e0fd82Sopenharmony_ci    } else {
378a3e0fd82Sopenharmony_ci        if (letterInfo.currentAngle > letterInfo.endAngle) {
379a3e0fd82Sopenharmony_ci            if (offsetX >= cols) {
380a3e0fd82Sopenharmony_ci                range = TextInRange::OUT_RANGE;
381a3e0fd82Sopenharmony_ci            }
382a3e0fd82Sopenharmony_ci            copyCols = cols - offsetX;
383a3e0fd82Sopenharmony_ci            begin = offsetX * sizePerPx;
384a3e0fd82Sopenharmony_ci        } else if (letterInfo.currentAngle > letterInfo.startAngle) {
385a3e0fd82Sopenharmony_ci            if (offsetX >= cols) {
386a3e0fd82Sopenharmony_ci                range = TextInRange::IN_RANGE;
387a3e0fd82Sopenharmony_ci            }
388a3e0fd82Sopenharmony_ci            copyCols = offsetX;
389a3e0fd82Sopenharmony_ci        }
390a3e0fd82Sopenharmony_ci    }
391a3e0fd82Sopenharmony_ci}
392a3e0fd82Sopenharmony_ci
393a3e0fd82Sopenharmony_civoid DrawLabel::OnCalculatedAnticlockwise(const ArcLetterInfo& letterInfo, const uint16_t sizePerPx,
394a3e0fd82Sopenharmony_ci                                          const uint16_t cols, const int16_t offsetX, uint16_t& begin,
395a3e0fd82Sopenharmony_ci                                          uint16_t& copyCols, TextInRange& range)
396a3e0fd82Sopenharmony_ci{
397a3e0fd82Sopenharmony_ci    if (letterInfo.directFlag) {
398a3e0fd82Sopenharmony_ci        return;
399a3e0fd82Sopenharmony_ci    }
400a3e0fd82Sopenharmony_ci    if (letterInfo.compatibilityMode && letterInfo.orientationFlag) {
401a3e0fd82Sopenharmony_ci        if (letterInfo.currentAngle < letterInfo.endAngle) {
402a3e0fd82Sopenharmony_ci            if (offsetX >= cols) {
403a3e0fd82Sopenharmony_ci                range = TextInRange::OUT_RANGE;
404a3e0fd82Sopenharmony_ci            }
405a3e0fd82Sopenharmony_ci            copyCols = cols - offsetX;
406a3e0fd82Sopenharmony_ci            begin = offsetX * sizePerPx;
407a3e0fd82Sopenharmony_ci        } else if (letterInfo.currentAngle < letterInfo.startAngle) {
408a3e0fd82Sopenharmony_ci            if (offsetX >= cols) {
409a3e0fd82Sopenharmony_ci                range = TextInRange::IN_RANGE;
410a3e0fd82Sopenharmony_ci            }
411a3e0fd82Sopenharmony_ci            copyCols = offsetX;
412a3e0fd82Sopenharmony_ci        }
413a3e0fd82Sopenharmony_ci    } else if ((letterInfo.compatibilityMode && !letterInfo.orientationFlag) || !letterInfo.compatibilityMode) {
414a3e0fd82Sopenharmony_ci        if (letterInfo.currentAngle < letterInfo.endAngle) {
415a3e0fd82Sopenharmony_ci            if (offsetX >= cols) {
416a3e0fd82Sopenharmony_ci                range = TextInRange::OUT_RANGE;
417a3e0fd82Sopenharmony_ci            }
418a3e0fd82Sopenharmony_ci            copyCols = cols - offsetX;
419a3e0fd82Sopenharmony_ci        } else if (letterInfo.currentAngle < letterInfo.startAngle) {
420a3e0fd82Sopenharmony_ci            if (offsetX >= cols) {
421a3e0fd82Sopenharmony_ci                range = TextInRange::IN_RANGE;
422a3e0fd82Sopenharmony_ci            }
423a3e0fd82Sopenharmony_ci            copyCols = offsetX;
424a3e0fd82Sopenharmony_ci            begin = (cols - offsetX) * sizePerPx;
425a3e0fd82Sopenharmony_ci        }
426a3e0fd82Sopenharmony_ci    }
427a3e0fd82Sopenharmony_ci}
428a3e0fd82Sopenharmony_ci
429a3e0fd82Sopenharmony_civoid DrawLabel::CalculatedBeginAndCopySize(const ArcLetterInfo& letterInfo, const uint16_t sizePerPx,
430a3e0fd82Sopenharmony_ci                                           const uint16_t cols, const int16_t offsetX, uint16_t& begin,
431a3e0fd82Sopenharmony_ci                                           uint16_t& copyCols, TextInRange& range)
432a3e0fd82Sopenharmony_ci{
433a3e0fd82Sopenharmony_ci    if (letterInfo.directFlag) {
434a3e0fd82Sopenharmony_ci        OnCalculatedClockwise(letterInfo, sizePerPx, cols, offsetX, begin, copyCols, range);
435a3e0fd82Sopenharmony_ci    } else {
436a3e0fd82Sopenharmony_ci        OnCalculatedAnticlockwise(letterInfo, sizePerPx, cols, offsetX, begin, copyCols, range);
437a3e0fd82Sopenharmony_ci    }
438a3e0fd82Sopenharmony_ci}
439a3e0fd82Sopenharmony_ci
440a3e0fd82Sopenharmony_cibool DrawLabel::CalculatedTransformDataInfo(uint8_t** buffer, TransformDataInfo& letterTranDataInfo,
441a3e0fd82Sopenharmony_ci    const ArcLetterInfo& letterInfo)
442a3e0fd82Sopenharmony_ci{
443a3e0fd82Sopenharmony_ci    float angle = 0.0f;
444a3e0fd82Sopenharmony_ci    if (DrawLabel::CalculatedClipAngle(letterInfo, angle) == false) {
445a3e0fd82Sopenharmony_ci        return false;
446a3e0fd82Sopenharmony_ci    }
447a3e0fd82Sopenharmony_ci    if (angle >= -EPSINON && angle <= EPSINON) {
448a3e0fd82Sopenharmony_ci        return true;
449a3e0fd82Sopenharmony_ci    }
450a3e0fd82Sopenharmony_ci
451a3e0fd82Sopenharmony_ci    int16_t offsetX = static_cast<uint16_t>(angle * letterInfo.radius * UI_PI / SEMICIRCLE_IN_DEGREE);
452a3e0fd82Sopenharmony_ci    uint16_t copyCols = 0;
453a3e0fd82Sopenharmony_ci    uint16_t begin = 0;
454a3e0fd82Sopenharmony_ci    uint16_t sizePerPx = letterTranDataInfo.pxSize / 8; // 8 bit
455a3e0fd82Sopenharmony_ci    TextInRange range = TextInRange::NEED_CLIP;
456a3e0fd82Sopenharmony_ci    uint16_t cols = letterTranDataInfo.header.width;
457a3e0fd82Sopenharmony_ci    uint16_t rows = letterTranDataInfo.header.height;
458a3e0fd82Sopenharmony_ci    DrawLabel::CalculatedBeginAndCopySize(letterInfo, sizePerPx, cols, offsetX, begin, copyCols, range);
459a3e0fd82Sopenharmony_ci    if (range == TextInRange::IN_RANGE) {
460a3e0fd82Sopenharmony_ci        return true;
461a3e0fd82Sopenharmony_ci    } else if (range == TextInRange::OUT_RANGE) {
462a3e0fd82Sopenharmony_ci        return false;
463a3e0fd82Sopenharmony_ci    }
464a3e0fd82Sopenharmony_ci
465a3e0fd82Sopenharmony_ci    const uint8_t* fontMap = letterTranDataInfo.data;
466a3e0fd82Sopenharmony_ci
467a3e0fd82Sopenharmony_ci    uint32_t size = cols * rows * sizePerPx;
468a3e0fd82Sopenharmony_ci    *buffer = static_cast<uint8_t*>(UIMalloc(size));
469a3e0fd82Sopenharmony_ci    if (*buffer == nullptr) {
470a3e0fd82Sopenharmony_ci        return false;
471a3e0fd82Sopenharmony_ci    }
472a3e0fd82Sopenharmony_ci
473a3e0fd82Sopenharmony_ci    if (memset_s(*buffer, size, 0, size) != EOK) {
474a3e0fd82Sopenharmony_ci        UIFree(*buffer);
475a3e0fd82Sopenharmony_ci        return false;
476a3e0fd82Sopenharmony_ci    }
477a3e0fd82Sopenharmony_ci
478a3e0fd82Sopenharmony_ci    for (uint16_t i = 0; i < rows; i++) {
479a3e0fd82Sopenharmony_ci        uint16_t beginSize = i * cols * sizePerPx + begin;
480a3e0fd82Sopenharmony_ci        uint16_t copySize = copyCols * sizePerPx;
481a3e0fd82Sopenharmony_ci        if (memcpy_s(*buffer + beginSize, copySize, fontMap + beginSize, copySize) != EOK) {
482a3e0fd82Sopenharmony_ci            UIFree(*buffer);
483a3e0fd82Sopenharmony_ci            return false;
484a3e0fd82Sopenharmony_ci        }
485a3e0fd82Sopenharmony_ci    }
486a3e0fd82Sopenharmony_ci    letterTranDataInfo.data = *buffer;
487a3e0fd82Sopenharmony_ci    return true;
488a3e0fd82Sopenharmony_ci}
489a3e0fd82Sopenharmony_ci
490a3e0fd82Sopenharmony_civoid DrawLabel::GetLineBackgroundColor(uint16_t letterIndex, List<LineBackgroundColor>* linebackgroundColor,
491a3e0fd82Sopenharmony_ci                                       bool& havelinebackground, ColorType& linebgColor)
492a3e0fd82Sopenharmony_ci{
493a3e0fd82Sopenharmony_ci    if (linebackgroundColor->Size() > 0) {
494a3e0fd82Sopenharmony_ci        ListNode<LineBackgroundColor>* lbColor = linebackgroundColor->Begin();
495a3e0fd82Sopenharmony_ci        for (; lbColor != linebackgroundColor->End(); lbColor = lbColor->next_) {
496a3e0fd82Sopenharmony_ci            uint32_t start = lbColor->data_.start;
497a3e0fd82Sopenharmony_ci            uint32_t end = lbColor->data_.end;
498a3e0fd82Sopenharmony_ci            if (letterIndex >= start && letterIndex <= end) {
499a3e0fd82Sopenharmony_ci                havelinebackground = true;
500a3e0fd82Sopenharmony_ci                linebgColor = lbColor->data_.linebackgroundColor ;
501a3e0fd82Sopenharmony_ci            }
502a3e0fd82Sopenharmony_ci        }
503a3e0fd82Sopenharmony_ci    }
504a3e0fd82Sopenharmony_ci};
505a3e0fd82Sopenharmony_ci
506a3e0fd82Sopenharmony_civoid DrawLabel::GetBackgroundColor(uint16_t letterIndex, List<BackgroundColor>* backgroundColor,
507a3e0fd82Sopenharmony_ci                                   bool& havebackground, ColorType& bgColor)
508a3e0fd82Sopenharmony_ci{
509a3e0fd82Sopenharmony_ci    if (backgroundColor->Size() > 0) {
510a3e0fd82Sopenharmony_ci        ListNode<BackgroundColor>* bColor = backgroundColor->Begin();
511a3e0fd82Sopenharmony_ci        for (; bColor != backgroundColor->End(); bColor = bColor->next_) {
512a3e0fd82Sopenharmony_ci            uint16_t start = bColor->data_.start;
513a3e0fd82Sopenharmony_ci            uint16_t end = bColor->data_.end;
514a3e0fd82Sopenharmony_ci            if (letterIndex >= start && letterIndex <= end) {
515a3e0fd82Sopenharmony_ci                havebackground = true;
516a3e0fd82Sopenharmony_ci                bgColor = bColor->data_.backgroundColor ;
517a3e0fd82Sopenharmony_ci            }
518a3e0fd82Sopenharmony_ci        }
519a3e0fd82Sopenharmony_ci    }
520a3e0fd82Sopenharmony_ci};
521a3e0fd82Sopenharmony_ci
522a3e0fd82Sopenharmony_civoid DrawLabel::GetForegroundColor(uint16_t letterIndex, List<ForegroundColor>* foregroundColor, ColorType& fgColor)
523a3e0fd82Sopenharmony_ci{
524a3e0fd82Sopenharmony_ci    if (foregroundColor->Size() > 0) {
525a3e0fd82Sopenharmony_ci        ListNode<ForegroundColor>* fColor = foregroundColor->Begin();
526a3e0fd82Sopenharmony_ci        for (; fColor != foregroundColor->End(); fColor = fColor->next_) {
527a3e0fd82Sopenharmony_ci            uint32_t start = fColor->data_.start;
528a3e0fd82Sopenharmony_ci            uint32_t end = fColor->data_.end;
529a3e0fd82Sopenharmony_ci            if (letterIndex >= start && letterIndex <= end) {
530a3e0fd82Sopenharmony_ci                fgColor = fColor->data_.fontColor;
531a3e0fd82Sopenharmony_ci            }
532a3e0fd82Sopenharmony_ci        }
533a3e0fd82Sopenharmony_ci    }
534a3e0fd82Sopenharmony_ci};
535a3e0fd82Sopenharmony_ci
536a3e0fd82Sopenharmony_civoid DrawLabel::DrawLineBackgroundColor(BufferInfo& gfxDstBuffer, uint16_t letterIndex, const LabelLineInfo& labelLine)
537a3e0fd82Sopenharmony_ci{
538a3e0fd82Sopenharmony_ci    uint32_t i = 0;
539a3e0fd82Sopenharmony_ci    while (i < labelLine.lineLength) {
540a3e0fd82Sopenharmony_ci        TypedText::GetUTF8Next(labelLine.text, i, i);
541a3e0fd82Sopenharmony_ci        bool havelinebackground = false;
542a3e0fd82Sopenharmony_ci        ColorType linebackgroundColor;
543a3e0fd82Sopenharmony_ci        if (labelLine.spannableString != nullptr &&
544a3e0fd82Sopenharmony_ci            labelLine.spannableString->GetSpannable(letterIndex)) {
545a3e0fd82Sopenharmony_ci            havelinebackground =
546a3e0fd82Sopenharmony_ci                labelLine.spannableString->GetLineBackgroundColor(
547a3e0fd82Sopenharmony_ci                    letterIndex, linebackgroundColor);
548a3e0fd82Sopenharmony_ci        }
549a3e0fd82Sopenharmony_ci        if (havelinebackground) {
550a3e0fd82Sopenharmony_ci            Style style;
551a3e0fd82Sopenharmony_ci            style.bgColor_ = linebackgroundColor;
552a3e0fd82Sopenharmony_ci            Rect linebackground(labelLine.mask.GetLeft(), labelLine.pos.y,
553a3e0fd82Sopenharmony_ci                                labelLine.mask.GetRight(),
554a3e0fd82Sopenharmony_ci                                labelLine.pos.y + labelLine.lineHeight);
555a3e0fd82Sopenharmony_ci            BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, labelLine.mask,
556a3e0fd82Sopenharmony_ci                                                   linebackground, style,
557a3e0fd82Sopenharmony_ci                                                   linebackgroundColor.alpha);
558a3e0fd82Sopenharmony_ci        }
559a3e0fd82Sopenharmony_ci        letterIndex++;
560a3e0fd82Sopenharmony_ci    }
561a3e0fd82Sopenharmony_ci};
562a3e0fd82Sopenharmony_ci} // namespace OHOS
563