• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "draw/draw_label.h"
17 #include <cstdio>
18 #include "common/typed_text.h"
19 #include "draw/draw_utils.h"
20 #include "engines/gfx/gfx_engine_manager.h"
21 #include "font/ui_font.h"
22 #include "font/ui_font_header.h"
23 #include "gfx_utils/graphic_log.h"
24 
25 namespace OHOS {
DrawTextOneLine(BufferInfo & gfxDstBuffer,const LabelLineInfo & labelLine,uint16_t & letterIndex)26 uint16_t DrawLabel::DrawTextOneLine(BufferInfo& gfxDstBuffer, const LabelLineInfo& labelLine,
27                                     uint16_t& letterIndex)
28 {
29     if (labelLine.text == nullptr) {
30         return 0;
31     }
32     UIFont* fontEngine = UIFont::GetInstance();
33     if (labelLine.direct == TEXT_DIRECT_RTL) {
34         labelLine.pos.x -= labelLine.offset.x;
35     } else {
36         labelLine.pos.x += labelLine.offset.x;
37     }
38 
39     uint32_t i = 0;
40     uint16_t retOffsetY = 0; // ret value elipse offsetY
41     uint16_t offsetPosY = 0;
42     uint8_t maxLetterSize = GetLineMaxLetterSize(labelLine.text, labelLine.lineLength, labelLine.fontId,
43                                                  labelLine.fontSize, letterIndex, labelLine.sizeSpans);
44     DrawLineBackgroundColor(gfxDstBuffer, letterIndex, labelLine);
45     GlyphNode glyphNode;
46     while (i < labelLine.lineLength) {
47         uint32_t letter = TypedText::GetUTF8Next(labelLine.text, i, i);
48         uint16_t fontId = labelLine.fontId;
49         uint8_t fontSize = labelLine.fontSize;
50         if (labelLine.sizeSpans != nullptr && labelLine.sizeSpans[letterIndex].isSizeSpan) {
51             fontId = labelLine.sizeSpans[letterIndex].fontId;
52             fontSize = labelLine.sizeSpans[letterIndex].size;
53         }
54         bool havebackgroundColor = false;
55         ColorType backgroundColor;
56         GetBackgroundColor(letterIndex, labelLine.backgroundColor, havebackgroundColor, backgroundColor);
57 
58         ColorType foregroundColor = labelLine.style.textColor_;
59         GetForegroundColor(letterIndex, labelLine.foregroundColor, foregroundColor);
60 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
61         TextStyle textStyle = TEXT_STYLE_NORMAL;
62         if (labelLine.textStyles) {
63             textStyle = labelLine.textStyles[letterIndex];
64         }
65 #endif
66         LabelLetterInfo letterInfo{labelLine.pos,
67                                    labelLine.mask,
68                                    foregroundColor,
69                                    labelLine.opaScale,
70                                    0,
71                                    0,
72                                    letter,
73                                    labelLine.direct,
74                                    fontId,
75                                    0,
76                                    fontSize,
77 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
78                                    textStyle,
79 #endif
80                                    labelLine.baseLine,
81                                    labelLine.style.letterSpace_,
82                                    labelLine.style.lineSpace_,
83                                    havebackgroundColor,
84                                    backgroundColor};
85 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
86         glyphNode.textStyle = letterInfo.textStyle;
87 #endif
88         glyphNode.advance = 0;
89         uint8_t* fontMap = fontEngine->GetBitmap(letterInfo.letter, glyphNode, letterInfo.fontId, letterInfo.fontSize,
90                                                  letterInfo.shapingId);
91         if (fontMap != nullptr) {
92             uint8_t weight = fontEngine->GetFontWeight(glyphNode.fontId);
93             // 16: rgb565->16 rgba8888->32 font with rgba
94             if (weight >= 16) {
95                 DrawUtils::GetInstance()->DrawColorLetter(gfxDstBuffer, letterInfo, fontMap,
96                                                           glyphNode, labelLine.lineHeight);
97             } else {
98                 letterInfo.offsetY = labelLine.ellipsisOssetY == 0 ? offsetPosY : labelLine.ellipsisOssetY;
99                 retOffsetY = offsetPosY;
100                 DrawUtils::GetInstance()->DrawNormalLetter(gfxDstBuffer, letterInfo, fontMap, glyphNode, maxLetterSize);
101             }
102         }
103         if (labelLine.direct == TEXT_DIRECT_RTL) {
104             labelLine.pos.x -= (glyphNode.advance + labelLine.style.letterSpace_);
105         } else {
106             labelLine.pos.x += (glyphNode.advance + labelLine.style.letterSpace_);
107         }
108 
109         letterIndex++;
110     }
111     return retOffsetY;
112 }
113 
GetLineMaxLetterSize(const char * text,uint16_t lineLength,uint16_t fontId,uint8_t fontSize,uint16_t letterIndex,SizeSpan * sizeSpans)114 uint8_t DrawLabel::GetLineMaxLetterSize(const char* text, uint16_t lineLength, uint16_t fontId, uint8_t fontSize,
115                                         uint16_t letterIndex, SizeSpan* sizeSpans)
116 {
117     if (sizeSpans == nullptr) {
118         return fontSize;
119     }
120     uint32_t i = 0;
121     uint8_t maxLetterSize = fontSize;
122     while (i < lineLength) {
123         uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
124         if (TypedText::IsColourWord(unicode, fontId, fontSize)) {
125             letterIndex++;
126             continue;
127         }
128         if (sizeSpans != nullptr && sizeSpans[letterIndex].isSizeSpan) {
129             uint8_t tempSize = sizeSpans[letterIndex].size;
130             if (tempSize > maxLetterSize) {
131                 maxLetterSize = tempSize;
132             }
133         }
134         letterIndex++;
135     }
136     return maxLetterSize;
137 }
138 
DrawArcText(BufferInfo & gfxDstBuffer,const Rect & mask,const char * text,const Point & arcCenter,uint16_t fontId,uint8_t fontSize,const ArcTextInfo arcTextInfo,TextOrientation orientation,const Style & style,OpacityType opaScale,bool compatibilityMode)139 void DrawLabel::DrawArcText(BufferInfo& gfxDstBuffer,
140                             const Rect& mask,
141                             const char* text,
142                             const Point& arcCenter,
143                             uint16_t fontId,
144                             uint8_t fontSize,
145                             const ArcTextInfo arcTextInfo,
146                             TextOrientation orientation,
147                             const Style& style,
148                             OpacityType opaScale,
149                             bool compatibilityMode)
150 {
151     if ((text == nullptr) || (arcTextInfo.lineStart == arcTextInfo.lineEnd) || (arcTextInfo.radius == 0)) {
152         GRAPHIC_LOGE("DrawLabel::DrawArcText invalid parameter\n");
153         return;
154     }
155     OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.textOpa_);
156     if (opa == OPA_TRANSPARENT) {
157         return;
158     }
159     uint16_t letterWidth;
160     UIFont* fontEngine = UIFont::GetInstance();
161 
162     uint16_t letterHeight = fontEngine->GetHeight(fontId, fontSize);
163     uint32_t i = arcTextInfo.lineStart;
164     float angle = arcTextInfo.startAngle;
165     float posX;
166     float posY;
167     float rotateAngle;
168 
169     bool orientationFlag = (orientation == TextOrientation::INSIDE);
170     bool directFlag = (arcTextInfo.direct == TEXT_DIRECT_LTR);
171     bool xorFlag = !((orientationFlag && directFlag) || (!orientationFlag && !directFlag));
172 
173     while (i < arcTextInfo.lineEnd) {
174         uint32_t tmp = i;
175         uint32_t letter = TypedText::GetUTF8Next(text, tmp, i);
176         if (letter == 0) {
177             continue;
178         }
179         if ((letter == '\r') || (letter == '\n')) {
180             break;
181         }
182         letterWidth = fontEngine->GetWidth(letter, fontId, fontSize, 0);
183         if (!DrawLabel::CalculateAngle(letterWidth, letterHeight, style.letterSpace_,
184                                        arcTextInfo, xorFlag, tmp, orientation,
185                                        posX, posY, rotateAngle, angle,
186                                        arcCenter, compatibilityMode)) {
187             continue;
188         }
189 
190         DrawLetterWithRotate(gfxDstBuffer, mask, fontId, fontSize, letter, Point { MATH_ROUND(posX), MATH_ROUND(posY) },
191                              static_cast<int16_t>(rotateAngle), style.textColor_, opaScale, compatibilityMode);
192     }
193 }
194 
CalculateAngle(uint16_t letterWidth,uint16_t letterHeight,int16_t letterSpace,const ArcTextInfo arcTextInfo,bool xorFlag,uint32_t index,TextOrientation orientation,float & posX,float & posY,float & rotateAngle,float & angle,const Point & arcCenter,bool compatibilityMode)195 bool DrawLabel::CalculateAngle(uint16_t letterWidth,
196                                uint16_t letterHeight,
197                                int16_t letterSpace,
198                                const ArcTextInfo arcTextInfo,
199                                bool xorFlag,
200                                uint32_t index,
201                                TextOrientation orientation,
202                                float& posX,
203                                float& posY,
204                                float& rotateAngle,
205                                float& angle,
206                                const Point& arcCenter,
207                                bool compatibilityMode)
208 {
209     const int DIVIDER_BY_TWO = 2;
210     if (compatibilityMode) {
211         if ((index == arcTextInfo.lineStart) && xorFlag) {
212             angle += TypedText::GetAngleForArcLen(static_cast<float>(letterWidth), letterHeight, arcTextInfo.radius,
213                                                   arcTextInfo.direct, orientation);
214         }
215         uint16_t arcLen = letterWidth + letterSpace;
216         if (arcLen == 0) {
217             return false;
218         }
219         float incrementAngle = TypedText::GetAngleForArcLen(static_cast<float>(arcLen), letterHeight,
220                                                             arcTextInfo.radius, arcTextInfo.direct, orientation);
221 
222         rotateAngle = (orientation == TextOrientation::INSIDE) ? angle : (angle - SEMICIRCLE_IN_DEGREE);
223 
224         // 2: half
225         float fineTuningAngle = incrementAngle * (static_cast<float>(letterWidth) / (DIVIDER_BY_TWO * arcLen));
226         rotateAngle += (xorFlag ? -fineTuningAngle : fineTuningAngle);
227         TypedText::GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY);
228         angle += incrementAngle;
229     } else {
230         float incrementAngle = TypedText::GetAngleForArcLen(letterWidth, letterSpace, arcTextInfo.radius);
231         if (incrementAngle >= -EPSINON && incrementAngle <= EPSINON) {
232             return false;
233         }
234 
235         float fineTuningAngle = incrementAngle / DIVIDER_BY_TWO;
236         rotateAngle = xorFlag ?  (angle - SEMICIRCLE_IN_DEGREE - fineTuningAngle) : (angle + fineTuningAngle);
237         TypedText::GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY);
238         angle = xorFlag ? (angle - incrementAngle) : (angle + incrementAngle);
239     }
240 
241     return true;
242 }
243 
DrawLetterWithRotate(BufferInfo & gfxDstBuffer,const Rect & mask,uint16_t fontId,uint8_t fontSize,uint32_t letter,const Point & pos,int16_t rotateAngle,const ColorType & color,OpacityType opaScale,bool compatibilityMode)244 void DrawLabel::DrawLetterWithRotate(BufferInfo& gfxDstBuffer,
245                                      const Rect& mask,
246                                      uint16_t fontId,
247                                      uint8_t fontSize,
248                                      uint32_t letter,
249                                      const Point& pos,
250                                      int16_t rotateAngle,
251                                      const ColorType& color,
252                                      OpacityType opaScale,
253                                      bool compatibilityMode)
254 {
255     UIFont* fontEngine = UIFont::GetInstance();
256     FontHeader head;
257     GlyphNode node;
258 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
259     node.textStyle = TEXT_STYLE_NORMAL;
260 #endif
261     if (fontEngine->GetFontHeader(head, fontId, fontSize) != 0) {
262         return;
263     }
264 
265     const uint8_t* fontMap = fontEngine->GetBitmap(letter, node, fontId, fontSize, 0);
266     if (fontMap == nullptr) {
267         return;
268     }
269     uint8_t fontWeight = fontEngine->GetFontWeight(fontId);
270     ColorMode colorMode = fontEngine->GetColorType(fontId);
271 
272     int16_t offset = compatibilityMode ? head.ascender : 0;
273     Rect rectLetter;
274     rectLetter.SetPosition(pos.x + node.left, pos.y + offset - node.top);
275     rectLetter.Resize(node.cols, node.rows);
276     TransformMap transMap(rectLetter);
277     transMap.Rotate(rotateAngle, Vector2<float>(-node.left, node.top - offset));
278     TransformDataInfo letterTranDataInfo = {ImageHeader{colorMode, 0, 0, 0, node.cols, node.rows}, fontMap, fontWeight,
279                                             BlurLevel::LEVEL0, TransformAlgorithm::BILINEAR};
280     BaseGfxEngine::GetInstance()->DrawTransform(gfxDstBuffer, mask, Point { 0, 0 }, color, opaScale, transMap,
281                                                 letterTranDataInfo);
282 }
283 
GetLineBackgroundColor(uint16_t letterIndex,List<LineBackgroundColor> * linebackgroundColor,bool & havelinebackground,ColorType & linebgColor)284 void DrawLabel::GetLineBackgroundColor(uint16_t letterIndex, List<LineBackgroundColor>* linebackgroundColor,
285                                        bool& havelinebackground, ColorType& linebgColor)
286 {
287     if (linebackgroundColor->Size() > 0) {
288         ListNode<LineBackgroundColor>* lbColor = linebackgroundColor->Begin();
289         for (; lbColor != linebackgroundColor->End(); lbColor = lbColor->next_) {
290             uint32_t start = lbColor->data_.start;
291             uint32_t end = lbColor->data_.end;
292             if (letterIndex >= start && letterIndex <= end) {
293                 havelinebackground = true;
294                 linebgColor = lbColor->data_.linebackgroundColor ;
295             }
296         }
297     }
298 };
299 
GetBackgroundColor(uint16_t letterIndex,List<BackgroundColor> * backgroundColor,bool & havebackground,ColorType & bgColor)300 void DrawLabel::GetBackgroundColor(uint16_t letterIndex, List<BackgroundColor>* backgroundColor,
301                                    bool& havebackground, ColorType& bgColor)
302 {
303     if (backgroundColor->Size() > 0) {
304         ListNode<BackgroundColor>* bColor = backgroundColor->Begin();
305         for (; bColor != backgroundColor->End(); bColor = bColor->next_) {
306             uint16_t start = bColor->data_.start;
307             uint16_t end = bColor->data_.end;
308             if (letterIndex >= start && letterIndex <= end) {
309                 havebackground = true;
310                 bgColor = bColor->data_.backgroundColor ;
311             }
312         }
313     }
314 };
315 
GetForegroundColor(uint16_t letterIndex,List<ForegroundColor> * foregroundColor,ColorType & fgColor)316 void DrawLabel::GetForegroundColor(uint16_t letterIndex, List<ForegroundColor>* foregroundColor, ColorType& fgColor)
317 {
318     if (foregroundColor->Size() > 0) {
319         ListNode<ForegroundColor>* fColor = foregroundColor->Begin();
320         for (; fColor != foregroundColor->End(); fColor = fColor->next_) {
321             uint32_t start = fColor->data_.start;
322             uint32_t end = fColor->data_.end;
323             if (letterIndex >= start && letterIndex <= end) {
324                 fgColor = fColor->data_.fontColor;
325             }
326         }
327     }
328 };
329 
DrawLineBackgroundColor(BufferInfo & gfxDstBuffer,uint16_t letterIndex,const LabelLineInfo & labelLine)330 void DrawLabel::DrawLineBackgroundColor(BufferInfo& gfxDstBuffer, uint16_t letterIndex, const LabelLineInfo& labelLine)
331 {
332     uint32_t i = 0;
333     while (i < labelLine.lineLength) {
334         TypedText::GetUTF8Next(labelLine.text, i, i);
335         bool havelinebackground = false;
336         ColorType linebackgroundColor;
337         GetLineBackgroundColor(letterIndex, labelLine.linebackgroundColor, havelinebackground, linebackgroundColor);
338         if (havelinebackground) {
339                 Style style;
340                 style.bgColor_ = linebackgroundColor;
341                 Rect linebackground(labelLine.mask.GetLeft(), labelLine.pos.y,
342                                     labelLine.mask.GetRight(), labelLine.pos.y + labelLine.lineHeight);
343                 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, labelLine.mask,
344                                                        linebackground, style, linebackgroundColor.alpha);
345         }
346         letterIndex++;
347     }
348 };
349 } // namespace OHOS
350