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 = UIFont::GetInstance()->GetFontWeight(glyphNode.fontId);
93 // 16: rgb565->16 rgba8888->32 font with rgba
94 if (weight >= 16) {
95 DrawUtils::GetInstance()->DrawColorLetter(gfxDstBuffer, letterInfo, fontMap, glyphNode, maxLetterSize);
96 } else {
97 letterInfo.offsetY = labelLine.ellipsisOssetY == 0 ? offsetPosY : labelLine.ellipsisOssetY;
98 retOffsetY = offsetPosY;
99 DrawUtils::GetInstance()->DrawNormalLetter(gfxDstBuffer, letterInfo, fontMap, glyphNode, maxLetterSize);
100 }
101 }
102 if (labelLine.direct == TEXT_DIRECT_RTL) {
103 labelLine.pos.x -= (glyphNode.advance + labelLine.style.letterSpace_);
104 } else {
105 labelLine.pos.x += (glyphNode.advance + labelLine.style.letterSpace_);
106 }
107
108 letterIndex++;
109 }
110 return retOffsetY;
111 }
112
GetLineMaxLetterSize(const char * text,uint16_t lineLength,uint16_t fontId,uint8_t fontSize,uint16_t letterIndex,SizeSpan * sizeSpans)113 uint8_t DrawLabel::GetLineMaxLetterSize(const char* text, uint16_t lineLength, uint16_t fontId, uint8_t fontSize,
114 uint16_t letterIndex, SizeSpan* sizeSpans)
115 {
116 if (sizeSpans == nullptr) {
117 return fontSize;
118 }
119 uint32_t i = 0;
120 uint8_t maxLetterSize = fontSize;
121 while (i < lineLength) {
122 uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
123 if (TypedText::IsColourWord(unicode, fontId, fontSize)) {
124 letterIndex++;
125 continue;
126 }
127 if (sizeSpans != nullptr && sizeSpans[letterIndex].isSizeSpan) {
128 uint8_t tempSize = sizeSpans[letterIndex].size;
129 if (tempSize > maxLetterSize) {
130 maxLetterSize = tempSize;
131 }
132 }
133 letterIndex++;
134 }
135 return maxLetterSize;
136 }
137
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)138 void DrawLabel::DrawArcText(BufferInfo& gfxDstBuffer,
139 const Rect& mask,
140 const char* text,
141 const Point& arcCenter,
142 uint16_t fontId,
143 uint8_t fontSize,
144 const ArcTextInfo arcTextInfo,
145 TextOrientation orientation,
146 const Style& style,
147 OpacityType opaScale)
148 {
149 if ((text == nullptr) || (arcTextInfo.lineStart == arcTextInfo.lineEnd) || (arcTextInfo.radius == 0)) {
150 GRAPHIC_LOGE("DrawLabel::DrawArcText invalid parameter\n");
151 return;
152 }
153 OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.textOpa_);
154 if (opa == OPA_TRANSPARENT) {
155 return;
156 }
157 uint16_t letterWidth;
158 uint16_t letterHeight = UIFont::GetInstance()->GetHeight(fontId, fontSize);
159 uint32_t i = arcTextInfo.lineStart;
160 float angle = arcTextInfo.startAngle;
161 float posX;
162 float posY;
163 float rotateAngle;
164
165 bool orientationFlag = (orientation == TextOrientation::INSIDE);
166 bool directFlag = (arcTextInfo.direct == TEXT_DIRECT_LTR);
167 bool xorFlag = !((orientationFlag && directFlag) || (!orientationFlag && !directFlag));
168
169 while (i < arcTextInfo.lineEnd) {
170 uint32_t tmp = i;
171 uint32_t letter = TypedText::GetUTF8Next(text, tmp, i);
172 if (letter == 0) {
173 continue;
174 }
175 if ((letter == '\r') || (letter == '\n')) {
176 break;
177 }
178 letterWidth = UIFont::GetInstance()->GetWidth(letter, fontId, fontSize, 0);
179 if ((tmp == arcTextInfo.lineStart) && xorFlag) {
180 angle += TypedText::GetAngleForArcLen(static_cast<float>(letterWidth), letterHeight, arcTextInfo.radius,
181 arcTextInfo.direct, orientation);
182 }
183 uint16_t arcLen = letterWidth + style.letterSpace_;
184 if (arcLen == 0) {
185 continue;
186 }
187 float incrementAngle = TypedText::GetAngleForArcLen(static_cast<float>(arcLen), letterHeight,
188 arcTextInfo.radius, arcTextInfo.direct, orientation);
189
190 rotateAngle = (orientation == TextOrientation::INSIDE) ? angle : (angle - SEMICIRCLE_IN_DEGREE);
191
192 // 2: half
193 float fineTuningAngle = incrementAngle * (static_cast<float>(letterWidth) / (2 * arcLen));
194 rotateAngle += (xorFlag ? -fineTuningAngle : fineTuningAngle);
195 TypedText::GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY);
196 angle += incrementAngle;
197
198 DrawLetterWithRotate(gfxDstBuffer, mask, fontId, fontSize, letter, Point { MATH_ROUND(posX), MATH_ROUND(posY) },
199 static_cast<int16_t>(rotateAngle), style.textColor_, opaScale);
200 }
201 }
202
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)203 void DrawLabel::DrawLetterWithRotate(BufferInfo& gfxDstBuffer,
204 const Rect& mask,
205 uint16_t fontId,
206 uint8_t fontSize,
207 uint32_t letter,
208 const Point& pos,
209 int16_t rotateAngle,
210 const ColorType& color,
211 OpacityType opaScale)
212 {
213 UIFont* fontEngine = UIFont::GetInstance();
214 FontHeader head;
215 GlyphNode node;
216 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
217 node.textStyle = TEXT_STYLE_NORMAL;
218 #endif
219 if (fontEngine->GetFontHeader(head, fontId, fontSize) != 0) {
220 return;
221 }
222
223 const uint8_t* fontMap = fontEngine->GetBitmap(letter, node, fontId, fontSize, 0);
224 if (fontMap == nullptr) {
225 return;
226 }
227 uint8_t fontWeight = fontEngine->GetFontWeight(fontId);
228 ColorMode colorMode = fontEngine->GetColorType(fontId);
229 Rect rectLetter;
230 rectLetter.SetPosition(pos.x + node.left, pos.y + head.ascender - node.top);
231 rectLetter.Resize(node.cols, node.rows);
232 TransformMap transMap(rectLetter);
233 transMap.Rotate(rotateAngle, Vector2<float>(-node.left, node.top - head.ascender));
234 TransformDataInfo letterTranDataInfo = {ImageHeader{colorMode, 0, 0, 0, node.cols, node.rows}, fontMap, fontWeight,
235 BlurLevel::LEVEL0, TransformAlgorithm::BILINEAR};
236 BaseGfxEngine::GetInstance()->DrawTransform(gfxDstBuffer, mask, Point { 0, 0 }, color, opaScale, transMap,
237 letterTranDataInfo);
238 }
239
GetLineBackgroundColor(uint16_t letterIndex,List<LineBackgroundColor> * linebackgroundColor,bool & havelinebackground,ColorType & linebgColor)240 void DrawLabel::GetLineBackgroundColor(uint16_t letterIndex, List<LineBackgroundColor>* linebackgroundColor,
241 bool& havelinebackground, ColorType& linebgColor)
242 {
243 if (linebackgroundColor->Size() > 0) {
244 ListNode<LineBackgroundColor>* lbColor = linebackgroundColor->Begin();
245 for (; lbColor != linebackgroundColor->End(); lbColor = lbColor->next_) {
246 uint32_t start = lbColor->data_.start;
247 uint32_t end = lbColor->data_.end;
248 if (letterIndex >= start && letterIndex <= end) {
249 havelinebackground = true;
250 linebgColor = lbColor->data_.linebackgroundColor ;
251 }
252 }
253 }
254 };
255
GetBackgroundColor(uint16_t letterIndex,List<BackgroundColor> * backgroundColor,bool & havebackground,ColorType & bgColor)256 void DrawLabel::GetBackgroundColor(uint16_t letterIndex, List<BackgroundColor>* backgroundColor,
257 bool& havebackground, ColorType& bgColor)
258 {
259 if (backgroundColor->Size() > 0) {
260 ListNode<BackgroundColor>* bColor = backgroundColor->Begin();
261 for (; bColor != backgroundColor->End(); bColor = bColor->next_) {
262 uint16_t start = bColor->data_.start;
263 uint16_t end = bColor->data_.end;
264 if (letterIndex >= start && letterIndex <= end) {
265 havebackground = true;
266 bgColor = bColor->data_.backgroundColor ;
267 }
268 }
269 }
270 };
271
GetForegroundColor(uint16_t letterIndex,List<ForegroundColor> * foregroundColor,ColorType & fgColor)272 void DrawLabel::GetForegroundColor(uint16_t letterIndex, List<ForegroundColor>* foregroundColor, ColorType& fgColor)
273 {
274 if (foregroundColor->Size() > 0) {
275 ListNode<ForegroundColor>* fColor = foregroundColor->Begin();
276 for (; fColor != foregroundColor->End(); fColor = fColor->next_) {
277 uint32_t start = fColor->data_.start;
278 uint32_t end = fColor->data_.end;
279 if (letterIndex >= start && letterIndex <= end) {
280 fgColor = fColor->data_.fontColor;
281 }
282 }
283 }
284 };
285
DrawLineBackgroundColor(BufferInfo & gfxDstBuffer,uint16_t letterIndex,const LabelLineInfo & labelLine)286 void DrawLabel::DrawLineBackgroundColor(BufferInfo& gfxDstBuffer, uint16_t letterIndex, const LabelLineInfo& labelLine)
287 {
288 uint32_t i = 0;
289 while (i < labelLine.lineLength) {
290 TypedText::GetUTF8Next(labelLine.text, i, i);
291 bool havelinebackground = false;
292 ColorType linebackgroundColor;
293 GetLineBackgroundColor(letterIndex, labelLine.linebackgroundColor, havelinebackground, linebackgroundColor);
294 if (havelinebackground) {
295 Style style;
296 style.bgColor_ = linebackgroundColor;
297 Rect linebackground(labelLine.mask.GetLeft(), labelLine.pos.y,
298 labelLine.mask.GetRight(), labelLine.pos.y + labelLine.lineHeight);
299 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, labelLine.mask,
300 linebackground, style, linebackgroundColor.alpha);
301 }
302 letterIndex++;
303 }
304 };
305 } // namespace OHOS
306