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