• 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_utils.h"
17 
18 #include "draw/draw_triangle.h"
19 #include "engines/gfx/gfx_engine_manager.h"
20 #include "font/ui_font.h"
21 #include "gfx_utils/color.h"
22 #include "gfx_utils/graphic_log.h"
23 #include "gfx_utils/graphic_math.h"
24 #include "graphic_performance.h"
25 #include "securec.h"
26 #include "common/typed_text.h"
27 #ifdef ARM_NEON_OPT
28 #include "graphic_neon_pipeline.h"
29 #include "graphic_neon_utils.h"
30 #endif
31 
32 #if ENABLE_ARM_MATH
33 #include "arm_math.h"
34 #endif
35 
36 namespace OHOS {
37 // Preprocess operation for draw
38 #define DRAW_UTILS_PREPROCESS(gfxBufferInfo, opa)                         \
39     if ((opa) == OPA_TRANSPARENT) {                                       \
40         return;                                                           \
41     }                                                                     \
42     uint8_t* screenBuffer = static_cast<uint8_t*>(gfxBufferInfo.virAddr); \
43     if (screenBuffer == nullptr) {                                        \
44         return;                                                           \
45     }                                                                     \
46     ColorMode bufferMode = gfxBufferInfo.mode;                            \
47     uint8_t bufferPxSize = GetByteSizeByColorMode(bufferMode);            \
48     uint16_t screenBufferWidth = gfxBufferInfo.width;
49 
50 /* cover mode, src alpha is 255 */
51 #define COLOR_FILL_COVER(d, dm, r2, g2, b2, sm)               \
52     if ((dm) == ARGB8888 || (dm) == XRGB8888) {               \
53         reinterpret_cast<Color32*>(d)->alpha = OPA_OPAQUE;    \
54         if (sm == RGB565) {                                   \
55             reinterpret_cast<Color32*>(d)->red = (r2) << 3;   \
56             reinterpret_cast<Color32*>(d)->green = (g2) << 2; \
57             reinterpret_cast<Color32*>(d)->blue = (b2) << 3;  \
58         } else {                                              \
59             reinterpret_cast<Color32*>(d)->red = (r2);        \
60             reinterpret_cast<Color32*>(d)->green = (g2);      \
61             reinterpret_cast<Color32*>(d)->blue = (b2);       \
62         }                                                     \
63     } else if ((dm) == RGB888) {                              \
64         if (sm == RGB565) {                                   \
65             reinterpret_cast<Color24*>(d)->red = (r2) << 3;   \
66             reinterpret_cast<Color24*>(d)->green = (g2) << 2; \
67             reinterpret_cast<Color24*>(d)->blue = (b2) << 3;  \
68         } else {                                              \
69             reinterpret_cast<Color24*>(d)->red = (r2);        \
70             reinterpret_cast<Color24*>(d)->green = (g2);      \
71             reinterpret_cast<Color24*>(d)->blue = (b2);       \
72         }                                                     \
73     } else if ((dm) == RGB565) {                              \
74         if ((sm) == ARGB8888 || (sm) == RGB888 || (sm) == XRGB8888) {  \
75             reinterpret_cast<Color16*>(d)->red = (r2) >> 3;   \
76             reinterpret_cast<Color16*>(d)->green = (g2) >> 2; \
77             reinterpret_cast<Color16*>(d)->blue = (b2) >> 3;  \
78         } else {                                              \
79             reinterpret_cast<Color16*>(d)->red = (r2);        \
80             reinterpret_cast<Color16*>(d)->green = (g2);      \
81             reinterpret_cast<Color16*>(d)->blue = (b2);       \
82         }                                                     \
83     } else {                                                  \
84         ASSERT(0);                                            \
85     }
86 
87 #define COLOR_BLEND_RGBA(r1, g1, b1, a1, r2, g2, b2, a2)                                  \
88     const float Alpha1 = static_cast<float>(a1) / OPA_OPAQUE;                             \
89     const float Alpha2 = static_cast<float>(a2) / OPA_OPAQUE;                             \
90     const float Alpha3 = 1 - (1 - Alpha1) * (1 - Alpha2);                                 \
91     (r1) = static_cast<uint8_t>((Alpha2 * (r2) + (1 - Alpha2) * Alpha1 * (r1)) / Alpha3); \
92     (g1) = static_cast<uint8_t>((Alpha2 * (g2) + (1 - Alpha2) * Alpha1 * (g1)) / Alpha3); \
93     (b1) = static_cast<uint8_t>((Alpha2 * (b2) + (1 - Alpha2) * Alpha1 * (b1)) / Alpha3); \
94     (a1) = static_cast<uint8_t>(Alpha3 * OPA_OPAQUE)
95 
96 #define COLOR_BLEND_XRGB(r1, g1, b1, a1, r2, g2, b2, a2)                               \
97     (r1) = (((r2) * (a2)) / OPA_OPAQUE) + (((r1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
98     (g1) = (((g2) * (a2)) / OPA_OPAQUE) + (((g1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
99     (b1) = (((b2) * (a2)) / OPA_OPAQUE) + (((b1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
100     (a1) = static_cast<uint8_t>(OPA_OPAQUE)
101 
102 #define COLOR_BLEND_RGB(r1, g1, b1, r2, g2, b2, a2)                                    \
103     (r1) = (((r2) * (a2)) / OPA_OPAQUE) + (((r1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
104     (g1) = (((g2) * (a2)) / OPA_OPAQUE) + (((g1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
105     (b1) = (((b2) * (a2)) / OPA_OPAQUE) + (((b1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE)
106 
107 // 565
108 #define COLOR_FILL_BLEND(d, dm, s, sm, a)                                                                           \
109     if ((dm) == ARGB8888) {                                                                                         \
110         Color32* p = reinterpret_cast<Color32*>(d);                                                                 \
111         if ((sm) == ARGB8888 || (sm) == XRGB8888) {                                                                 \
112             Color32* sTmp = reinterpret_cast<Color32*>(s);                                                          \
113             uint8_t alpha = (sTmp->alpha * (a)) / OPA_OPAQUE;                                                       \
114             COLOR_BLEND_RGBA(p->red, p->green, p->blue, p->alpha, sTmp->red, sTmp->green, sTmp->blue, alpha);       \
115         } else if ((sm) == RGB888) {                                                                                \
116             Color24* sTmp = reinterpret_cast<Color24*>(s);                                                          \
117             COLOR_BLEND_RGBA(p->red, p->green, p->blue, p->alpha, sTmp->red, sTmp->green, sTmp->blue, a);           \
118         } else if ((sm) == RGB565) {                                                                                \
119             Color16* sTmp = reinterpret_cast<Color16*>(s);                                                          \
120             COLOR_BLEND_RGBA(p->red, p->green, p->blue, p->alpha, (sTmp->red) << 3, (sTmp->green) << 2,             \
121                              (sTmp->blue) << 3, a);                                                                 \
122         }                                                                                                           \
123     } else if ((dm) == XRGB8888) {                                                                                  \
124         Color32* p = reinterpret_cast<Color32*>(d);                                                                 \
125         if ((sm) == ARGB8888 || (sm) == XRGB8888) {                                                                 \
126             Color32* sTmp = reinterpret_cast<Color32*>(s);                                                          \
127             uint8_t alpha = (sTmp->alpha * (a)) / OPA_OPAQUE;                                                       \
128             COLOR_BLEND_XRGB(p->red, p->green, p->blue, p->alpha, sTmp->red, sTmp->green, sTmp->blue, alpha);       \
129         } else if ((sm) == RGB888) {                                                                                \
130             Color24* sTmp = reinterpret_cast<Color24*>(s);                                                          \
131             COLOR_BLEND_XRGB(p->red, p->green, p->blue, p->alpha, sTmp->red, sTmp->green, sTmp->blue, a);           \
132         } else if ((sm) == RGB565) {                                                                                \
133             Color16* sTmp = reinterpret_cast<Color16*>(s);                                                          \
134             COLOR_BLEND_XRGB(p->red, p->green, p->blue, p->alpha, (sTmp->red) << 3, (sTmp->green) << 2,             \
135                              (sTmp->blue) << 3, a);                                                                 \
136         }                                                                                                           \
137     } else if ((dm) == RGB888) {                                                                                    \
138         Color24* p = reinterpret_cast<Color24*>(d);                                                                 \
139         if ((sm) == ARGB8888 || (sm) == XRGB8888) {                                                                 \
140             Color32* sTmp = reinterpret_cast<Color32*>(s);                                                          \
141             uint8_t alpha = (sTmp->alpha * (a)) / OPA_OPAQUE;                                                       \
142             COLOR_BLEND_RGB(p->red, p->green, p->blue, sTmp->red, sTmp->green, sTmp->blue, alpha);                  \
143         } else if ((sm) == RGB888) {                                                                                \
144             Color24* sTmp = reinterpret_cast<Color24*>(s);                                                          \
145             COLOR_BLEND_RGB(p->red, p->green, p->blue, sTmp->red, sTmp->green, sTmp->blue, a);                      \
146         } else if ((sm) == RGB565) {                                                                                \
147             Color16* sTmp = reinterpret_cast<Color16*>(s);                                                          \
148             COLOR_BLEND_RGB(p->red, p->green, p->blue, (sTmp->red) << 3, (sTmp->green) << 2, (sTmp->blue) << 3, a); \
149         }                                                                                                           \
150     } else if ((dm) == RGB565) {                                                                                    \
151         Color16* p = reinterpret_cast<Color16*>(d);                                                                 \
152         if ((sm) == ARGB8888 || (sm) == XRGB8888) {                                                                 \
153             Color32* sTmp = reinterpret_cast<Color32*>(s);                                                          \
154             uint8_t alpha = (sTmp->alpha * (a)) / OPA_OPAQUE;                                                       \
155             COLOR_BLEND_RGB(p->red, p->green, p->blue, (sTmp->red) >> 3, (sTmp->green) >> 2, (sTmp->blue) >> 3,     \
156                             alpha);                                                                                 \
157         } else if ((sm) == RGB888) {                                                                                \
158             Color24* sTmp = reinterpret_cast<Color24*>(s);                                                          \
159             COLOR_BLEND_RGB(p->red, p->green, p->blue, (sTmp->red) >> 3, (sTmp->green) >> 2, (sTmp->blue) >> 3, a); \
160         } else if ((sm) == RGB565) {                                                                                \
161             Color16* sTmp = reinterpret_cast<Color16*>(s);                                                          \
162             COLOR_BLEND_RGB(p->red, p->green, p->blue, sTmp->red, sTmp->green, sTmp->blue, a);                      \
163         }                                                                                                           \
164     } else {                                                                                                        \
165         ASSERT(0);                                                                                                  \
166     }
167 
168 namespace {
169 static constexpr uint8_t OPACITY_STEP_A1 = 255;
170 static constexpr uint8_t OPACITY_STEP_A2 = 85;
171 static constexpr uint8_t OPACITY_STEP_A4 = 17;
172 } // namespace
173 
TriangleEdge(int16_t x1,int16_t y1,int16_t x2,int16_t y2)174 TriangleEdge::TriangleEdge(int16_t x1, int16_t y1, int16_t x2, int16_t y2)
175 {
176 #if ENABLE_FIXED_POINT
177     curX = FO_TRANS_INTEGER_TO_FIXED(x1);
178     curY = FO_TRANS_INTEGER_TO_FIXED(y1);
179     du = FO_TRANS_INTEGER_TO_FIXED(x2 - x1);
180     dv = FO_TRANS_INTEGER_TO_FIXED(y2 - y1);
181 #else
182     curX = static_cast<float>(x1);
183     curY = static_cast<float>(y1);
184     du = static_cast<float>(x2 - x1);
185     dv = static_cast<float>(y2 - y1);
186 #endif
187 }
188 
~TriangleEdge()189 TriangleEdge::~TriangleEdge() {}
190 
GetInstance()191 DrawUtils* DrawUtils::GetInstance()
192 {
193     static DrawUtils instance;
194     return &instance;
195 }
196 
DrawColorAreaBySides(BufferInfo & gfxDstBuffer,const Rect & mask,const ColorType & color,OpacityType opa,const EdgeSides & sides) const197 void DrawUtils::DrawColorAreaBySides(BufferInfo& gfxDstBuffer,
198                                      const Rect& mask,
199                                      const ColorType& color,
200                                      OpacityType opa,
201                                      const EdgeSides& sides) const
202 {
203     Rect area(sides.left, sides.top, sides.right, sides.bottom);
204     DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, area, mask, color, opa);
205 }
206 
DrawColorArea(BufferInfo & gfxDstBuffer,const Rect & area,const Rect & mask,const ColorType & color,OpacityType opa) const207 void DrawUtils::DrawColorArea(BufferInfo& gfxDstBuffer,
208                               const Rect& area,
209                               const Rect& mask,
210                               const ColorType& color,
211                               OpacityType opa) const
212 {
213     if (opa == OPA_TRANSPARENT) {
214         return;
215     }
216 
217     Rect maskedArea;
218     if (!maskedArea.Intersect(area, mask)) {
219         return;
220     }
221 
222     BaseGfxEngine::GetInstance()->Fill(gfxDstBuffer, maskedArea, color, opa);
223 }
224 
GetPxSizeByColorMode(uint8_t colorMode)225 uint8_t DrawUtils::GetPxSizeByColorMode(uint8_t colorMode)
226 {
227     switch (colorMode) {
228         case TSC6:
229         case TSC6A:
230         case ARGB8888:
231         case XRGB8888:
232             return 32; // 32: 32 bit
233         case RGB888:
234             return 24; // 24: 24 bit
235         case RGB565:
236         case ARGB1555:
237         case ARGB4444:
238             return 16; // 16: 16 bit
239         case L1:
240         case A1:
241             return 1; // 1: 1 bit
242         case L2:
243         case A2:
244             return 2; // 2: 2 bit
245         case L4:
246         case A4:
247             return 4; // 4: 4 bit
248         case L8:
249         case A8:
250             return 8; // 8: 8 bit
251         default:
252             return 0;
253     }
254 }
255 
GetByteSizeByColorMode(uint8_t colorMode)256 uint8_t DrawUtils::GetByteSizeByColorMode(uint8_t colorMode)
257 {
258     switch (colorMode) {
259         case ARGB8888:
260         case XRGB8888:
261             return 4; // 4: 4 Byte
262         case RGB888:
263             return 3; // 3: 3 Byte
264         case RGB565:
265         case ARGB1555:
266         case ARGB4444:
267             return 2; // 2: 2 Byte
268         default:
269             return 0;
270     }
271 }
272 
DrawPixel(BufferInfo & gfxDstBuffer,int16_t x,int16_t y,const Rect & mask,const ColorType & color,OpacityType opa) const273 void DrawUtils::DrawPixel(BufferInfo& gfxDstBuffer,
274                           int16_t x,
275                           int16_t y,
276                           const Rect& mask,
277                           const ColorType& color,
278                           OpacityType opa) const
279 {
280     if ((x < mask.GetLeft()) || (x > mask.GetRight()) || (y < mask.GetTop()) || (y > mask.GetBottom())) {
281         return;
282     }
283 
284     DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
285 
286     Color32 fillColor;
287     fillColor.full = Color::ColorTo32(color);
288 
289     screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
290     COLOR_FILL_BLEND(screenBuffer, bufferMode, &fillColor, ARGB8888, opa);
291 }
292 
DrawColorLetter(BufferInfo & gfxDstBuffer,const LabelLetterInfo & letterInfo,uint8_t * fontMap,GlyphNode node,uint8_t maxLetterSize) const293 void DrawUtils::DrawColorLetter(BufferInfo& gfxDstBuffer,
294                                 const LabelLetterInfo& letterInfo,
295                                 uint8_t* fontMap,
296                                 GlyphNode node,
297                                 uint8_t maxLetterSize) const
298 {
299     if (fontMap == nullptr) {
300         return;
301     }
302     UIFont* fontEngine = UIFont::GetInstance();
303     uint16_t letterW = node.cols;
304     uint16_t letterH = node.rows;
305     int16_t posX;
306     int16_t posY;
307     if (letterInfo.baseLine) {
308         posY = letterInfo.pos.y + maxLetterSize - node.top + letterInfo.offsetY;
309     } else {
310         FontHeader head;
311         if (fontEngine->GetFontHeader(head, letterInfo.fontId, letterInfo.fontSize) != 0) {
312             return;
313         }
314         posY = letterInfo.pos.y + head.ascender - letterInfo.offsetY;
315     }
316     if (letterInfo.direct == TEXT_DIRECT_RTL) {
317         /* RTL */
318         posX = letterInfo.pos.x- node.advance + letterInfo.offsetX;
319     } else {
320         /* LTR */
321         posX = letterInfo.pos.x;
322     }
323 
324     uint16_t rowStart = (posY >= letterInfo.mask.GetTop()) ? 0 : (letterInfo.mask.GetTop() - posY);
325     uint16_t rowEnd =
326         (posY + letterH <= letterInfo.mask.GetBottom()) ? letterH : (letterInfo.mask.GetBottom() - posY + 1);
327     uint16_t colStart = (posX >= letterInfo.mask.GetLeft()) ? 0 : (letterInfo.mask.GetLeft() - posX);
328     uint16_t colEnd =
329         (posX + letterW <= letterInfo.mask.GetRight()) ? letterW : (letterInfo.mask.GetRight() - posX + 1);
330 
331     Rect srcRect(posX, posY, posX + letterW - 1, posY + letterH - 1);
332     Rect subRect(posX + colStart, posY + rowStart, colEnd - 1 + posX, rowEnd - 1 + posY);
333 
334     uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(gfxDstBuffer.mode);
335     DrawImage(gfxDstBuffer, srcRect, letterInfo.mask, fontMap, letterInfo.opa, pxSize, ARGB8888);
336 }
337 
DrawNormalLetter(BufferInfo & gfxDstBuffer,const LabelLetterInfo & letterInfo,uint8_t * fontMap,GlyphNode node,uint8_t maxLetterSize) const338 void DrawUtils::DrawNormalLetter(BufferInfo& gfxDstBuffer,
339                                  const LabelLetterInfo& letterInfo,
340                                  uint8_t* fontMap,
341                                  GlyphNode node,
342                                  uint8_t maxLetterSize) const
343 {
344     if (fontMap == nullptr) {
345         return;
346     }
347 
348     UIFont* fontEngine = UIFont::GetInstance();
349     uint16_t letterW = node.cols;
350     uint16_t letterH = node.rows;
351     int16_t posX;
352     int16_t posY;
353 
354     if (letterInfo.baseLine) {
355         posY = letterInfo.pos.y + maxLetterSize - node.top + letterInfo.offsetY;
356     } else {
357         FontHeader head;
358         if (fontEngine->GetFontHeader(head, letterInfo.fontId, letterInfo.fontSize) != 0) {
359             return;
360         }
361         posY = letterInfo.pos.y + head.ascender - node.top - letterInfo.offsetY;
362     }
363     if (letterInfo.direct == TEXT_DIRECT_RTL) {
364         /* RTL */
365         posX = letterInfo.pos.x - node.advance + node.left + letterInfo.offsetX;
366     } else {
367         /* LTR */
368         posX = letterInfo.pos.x + node.left + letterInfo.offsetX;
369     }
370 
371     if (letterInfo.havebackgroundColor) {
372         Rect backgroundRect(posX, letterInfo.mask.GetTop(), posX + letterW + letterInfo.letterSpace_ - 1,
373                             letterInfo.mask.GetBottom() - letterInfo.lineSpace_);
374         Style style;
375         style.bgColor_ = letterInfo.backgroundColor;
376         BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, backgroundRect,
377                                                backgroundRect, style, style.bgColor_.alpha);
378     }
379 
380     if ((posX + letterW < letterInfo.mask.GetLeft()) || (posX > letterInfo.mask.GetRight()) ||
381         (posY + letterH < letterInfo.mask.GetTop()) || (posY > letterInfo.mask.GetBottom())) {
382         return;
383     }
384 
385     uint16_t rowStart = (posY >= letterInfo.mask.GetTop()) ? 0 : (letterInfo.mask.GetTop() - posY);
386     uint16_t rowEnd =
387         (posY + letterH <= letterInfo.mask.GetBottom()) ? letterH : (letterInfo.mask.GetBottom() - posY + 1);
388     uint16_t colStart = (posX >= letterInfo.mask.GetLeft()) ? 0 : (letterInfo.mask.GetLeft() - posX);
389     uint16_t colEnd =
390         (posX + letterW <= letterInfo.mask.GetRight()) ? letterW : (letterInfo.mask.GetRight() - posX + 1);
391 
392     Rect srcRect(posX, posY, posX + letterW - 1, posY + letterH - 1);
393     Rect subRect(posX + colStart, posY + rowStart, colEnd - 1 + posX, rowEnd - 1 + posY);
394 
395     uint8_t fontWeight = fontEngine->GetFontWeight(letterInfo.fontId);
396     BaseGfxEngine::GetInstance()->DrawLetter(gfxDstBuffer, fontMap, srcRect, subRect,
397                                              fontWeight, letterInfo.color, letterInfo.opa);
398 }
399 
DrawLetter(BufferInfo & gfxDstBuffer,const uint8_t * fontMap,const Rect & fontRect,const Rect & subRect,const uint8_t fontWeight,const ColorType & color,const OpacityType opa) const400 void DrawUtils::DrawLetter(BufferInfo& gfxDstBuffer,
401                            const uint8_t* fontMap,
402                            const Rect& fontRect,
403                            const Rect& subRect,
404                            const uint8_t fontWeight,
405                            const ColorType& color,
406                            const OpacityType opa) const
407 {
408     Color32 fillColor;
409     fillColor.full = Color::ColorTo32(color);
410     uint8_t opacityMask;
411     uint8_t opacityStep = 1;
412     switch (fontWeight) {
413         case FONT_WEIGHT_1:
414             opacityStep = OPACITY_STEP_A1;
415             opacityMask = 0x01;
416             break;
417         case FONT_WEIGHT_2:
418             opacityStep = OPACITY_STEP_A2;
419             opacityMask = 0x03;
420             break;
421         case FONT_WEIGHT_4:
422             opacityStep = OPACITY_STEP_A4;
423             opacityMask = 0x0F;
424             break;
425         case FONT_WEIGHT_8:
426             opacityMask = 0xFF;
427             break;
428         case FONT_WEIGHT_32:
429             opacityMask = 0xFF;
430             break;
431         default:
432             return;
433     }
434 
435     uint8_t letterWidthInByte = (fontRect.GetWidth() * fontWeight) >> SHIFT_3;
436     if ((fontRect.GetWidth() * fontWeight) & 0x7) { // 0x7 : less than 1 byte is counted as 1 byte
437         letterWidthInByte++;
438     }
439     int16_t rowStart = subRect.GetY() - fontRect.GetY();
440     int16_t rowEnd = rowStart + subRect.GetHeight();
441     int16_t colStart = subRect.GetX() - fontRect.GetX();
442     int16_t colEnd = colStart + subRect.GetWidth();
443 
444     DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
445     screenBuffer += ((subRect.GetY() * screenBufferWidth) + subRect.GetX()) * bufferPxSize;
446     fontMap += (rowStart * letterWidthInByte) + ((colStart * fontWeight) >> SHIFT_3);
447 
448     uint8_t offsetInFont = (colStart * fontWeight) % FONT_WEIGHT_8;
449     int16_t temp = subRect.GetWidth() * fontWeight - FONT_WEIGHT_8 + offsetInFont;
450     if (temp < 0) {
451         temp = 0;
452     }
453     int16_t validWidthInByte = temp / FONT_WEIGHT_8 + 1;
454     if (temp % FONT_WEIGHT_8 != 0) {
455         validWidthInByte++;
456     }
457     for (int16_t i = rowStart; i < rowEnd; i++) {
458         int16_t col = colStart;
459         uint8_t tempOffset = offsetInFont;
460         uint8_t tempFontByte = (*fontMap++) >> offsetInFont;
461         while (col < colEnd) {
462             while ((tempOffset < FONT_WEIGHT_8) && (col < colEnd)) {
463                 uint8_t validOpacity = tempFontByte & opacityMask;
464                 if (validOpacity != 0) {
465                     validOpacity *= opacityStep;
466                     if (opa != OPA_OPAQUE) {
467                         validOpacity =
468                             static_cast<OpacityType>((static_cast<uint16_t>(validOpacity) * opa) >> FONT_WEIGHT_8);
469                     }
470                     COLOR_FILL_BLEND(screenBuffer, bufferMode, &fillColor, ARGB8888, validOpacity);
471                 }
472                 screenBuffer += bufferPxSize;
473                 tempFontByte = tempFontByte >> fontWeight;
474                 tempOffset += fontWeight;
475                 col++;
476             }
477             tempOffset = 0;
478             tempFontByte = *(fontMap++);
479         }
480         fontMap += letterWidthInByte - validWidthInByte - 1;
481         screenBuffer += (screenBufferWidth - (colEnd - colStart)) * bufferPxSize;
482     }
483 }
484 
DrawImage(BufferInfo & gfxDstBuffer,const Rect & area,const Rect & mask,const uint8_t * image,OpacityType opa,uint8_t pxBitSize,ColorMode colorMode) const485 void DrawUtils::DrawImage(BufferInfo& gfxDstBuffer,
486                           const Rect& area,
487                           const Rect& mask,
488                           const uint8_t* image,
489                           OpacityType opa,
490                           uint8_t pxBitSize,
491                           ColorMode colorMode) const
492 {
493     if (image == nullptr) {
494         return;
495     }
496     Rect maskedArea;
497     if (!maskedArea.Intersect(area, mask)) {
498         return;
499     }
500     int16_t mapWidth = area.GetWidth();
501     int16_t imageX = maskedArea.GetLeft() - area.GetLeft();
502     int16_t imageY = maskedArea.GetTop() - area.GetTop();
503     uint32_t imageWidthInByte = (static_cast<uint32_t>(mapWidth) * pxBitSize) >> SHIFT_3;
504     if ((mapWidth * pxBitSize) & 0x7) { // 0x7 : less than 1 byte is counted as 1 byte
505         imageWidthInByte++;
506     }
507 
508     BufferInfo src;
509     src.rect = {imageX, imageY, static_cast<int16_t>(imageX + maskedArea.GetWidth() - 1),
510                 static_cast<int16_t>(imageY + maskedArea.GetHeight() - 1)};
511 
512     src.virAddr = static_cast<void*>(const_cast<uint8_t*>(image));
513     src.stride = imageWidthInByte;
514     src.mode = colorMode;
515     src.color = 0;
516 
517     Point dstPos = {maskedArea.GetLeft(), maskedArea.GetTop()};
518     BlendOption blendOption;
519     blendOption.opacity = opa;
520     blendOption.mode = BLEND_SRC_OVER;
521     BaseGfxEngine::GetInstance()->Blit(gfxDstBuffer, dstPos, src, maskedArea, blendOption);
522 }
523 
FillAreaWithSoftWare(BufferInfo & gfxDstBuffer,const Rect & fillArea,const ColorType & color,const OpacityType & opa) const524 void DrawUtils::FillAreaWithSoftWare(BufferInfo& gfxDstBuffer,
525                                      const Rect& fillArea,
526                                      const ColorType& color,
527                                      const OpacityType& opa) const
528 {
529     if (gfxDstBuffer.virAddr == nullptr) {
530         return;
531     }
532     ColorMode mode = gfxDstBuffer.mode;
533     uint8_t destByteSize = GetByteSizeByColorMode(mode);
534     int16_t destWidth = gfxDstBuffer.width;
535     int32_t halBufferDeltaByteLen = static_cast<int32_t>(destWidth) * destByteSize;
536     int16_t width = fillArea.GetWidth();
537     int16_t height = fillArea.GetHeight();
538     uint8_t* dest = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
539     int32_t offset = static_cast<int32_t>(fillArea.GetTop()) * destWidth + fillArea.GetLeft();
540     dest += offset * destByteSize;
541 
542     int32_t dstMaxSize = (gfxDstBuffer.width * gfxDstBuffer.height - offset) * destByteSize;
543     Color32 fillColor;
544     fillColor.full = Color::ColorTo32(color);
545     uint8_t* dstTmp = nullptr;
546 
547     if ((fillColor.alpha == OPA_TRANSPARENT) || (opa == OPA_TRANSPARENT)) {
548         return;
549     }
550     /* cover mode */
551     if ((opa == OPA_OPAQUE) && (fillColor.alpha == OPA_OPAQUE)) {
552         for (int16_t col = 0; col < width; ++col) {
553             dstTmp = dest + (col * destByteSize);
554             COLOR_FILL_COVER(dstTmp, mode, fillColor.red, fillColor.green, fillColor.blue, ARGB8888);
555         }
556         uint8_t* memStart = dest;
557         int32_t memSize = static_cast<int32_t>(width) * destByteSize;
558         dest += halBufferDeltaByteLen;
559         dstMaxSize -= halBufferDeltaByteLen;
560         for (int16_t row = 1; row < height; ++row) {
561 #ifdef ARM_NEON_OPT
562             {
563                 DEBUG_PERFORMANCE_TRACE("memcpy_neon");
564                 NeonMemcpy(dest, dstMaxSize, memStart, memSize);
565             }
566 #else
567             {
568                 DEBUG_PERFORMANCE_TRACE("memcpy");
569                 if (memcpy_s(dest, dstMaxSize, memStart, memSize) != EOK) {
570                     GRAPHIC_LOGE("DrawUtils::FillAreaWithSoftWare memcpy failed!\n");
571                     return;
572                 }
573             }
574 #endif
575             dest += halBufferDeltaByteLen;
576             dstMaxSize -= halBufferDeltaByteLen;
577         }
578     } else {
579 #ifdef ARM_NEON_OPT
580         {
581             DEBUG_PERFORMANCE_TRACE("FillAreaWithSoftWare_neon");
582             NeonBlendPipeLine pipeLine;
583             pipeLine.Construct(mode, ARGB8888, &fillColor, opa);
584             int16_t step = NEON_STEP_8 * GetByteSizeByColorMode(mode);
585             for (int16_t row = 0; row < height; ++row) {
586                 uint8_t* buf = dest;
587                 int16_t tmpWidth = width;
588                 while (tmpWidth >= NEON_STEP_8) {
589                     pipeLine.Invoke(buf);
590                     buf += step;
591                     tmpWidth -= NEON_STEP_8;
592                 }
593                 for (int16_t i = 0; i < tmpWidth; ++i) {
594                     COLOR_FILL_BLEND(buf, mode, &fillColor, ARGB8888, opa);
595                     buf += destByteSize;
596                 }
597                 dest += halBufferDeltaByteLen;
598             }
599         }
600 #else
601         {
602             DEBUG_PERFORMANCE_TRACE("FillAreaWithSoftWare");
603             for (int16_t row = 0; row < height; row++) {
604                 for (int16_t col = 0; col < width; col++) {
605                     dstTmp = dest + (col * destByteSize);
606                     COLOR_FILL_BLEND(dstTmp, mode, &fillColor, ARGB8888, opa);
607                 }
608                 dest += destWidth * destByteSize;
609             }
610         }
611 #endif
612     }
613 }
614 
615 #ifdef ARM_NEON_OPT
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t cover)616 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
617                              uint8_t alpha, uint8_t cover)
618 {
619     NeonBlendPipeLine mNeonBlendPipeLine;
620     mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha, cover);
621 }
622 
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha)623 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
624 {
625     NeonBlendPipeLine mNeonBlendPipeLine;
626     mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha);
627 }
628 
BlendLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t srcCover)629 void DrawUtils::BlendLerpPix(uint8_t* dstColors, uint8_t* srcColors, uint8_t srcCover)
630 {
631     NeonBlendPipeLine mNeonBlendPipeLine;
632     mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCover);
633 }
634 
BlendLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t * srcCovers)635 void DrawUtils::BlendLerpPix(uint8_t* dstColors, uint8_t* srcColors, uint8_t* srcCovers)
636 {
637     NeonBlendPipeLine mNeonBlendPipeLine;
638     mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCovers);
639 }
640 
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t * covers)641 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
642                              uint8_t alpha, uint8_t* covers)
643 {
644     NeonBlendPipeLine mNeonBlendPipeLine;
645     mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha, covers);
646 }
647 
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t cover)648 void DrawUtils::BlendPreLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
649                                 uint8_t alpha, uint8_t cover)
650 {
651     NeonBlendPipeLine mNeonBlendPipeLine;
652     mNeonBlendPipeLine.NeonPrelerpARGB8888(color, red, green, blue, alpha, cover);
653 }
654 
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha)655 void DrawUtils::BlendPreLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
656 {
657     NeonBlendPipeLine mNeonBlendPipeLine;
658     mNeonBlendPipeLine.NeonPrelerpARGB8888(color, red, green, blue, alpha);
659 }
BlendPreLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t srcCover)660 void DrawUtils::BlendPreLerpPix(uint8_t *dstColors, uint8_t *srcColors, uint8_t srcCover)
661 {
662     NeonBlendPipeLine mNeonBlendPipeLine;
663     mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCover);
664 }
665 
BlendPreLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t * srcCovers)666 void DrawUtils::BlendPreLerpPix(uint8_t *dstColors, uint8_t *srcColors, uint8_t *srcCovers)
667 {
668     NeonBlendPipeLine mNeonBlendPipeLine;
669     mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCovers);
670 }
671 
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t * covers)672 void DrawUtils::BlendPreLerpPix(uint8_t *color, uint8_t red, uint8_t green, uint8_t blue,
673                                 uint8_t alpha, uint8_t *covers)
674 {
675     NeonBlendPipeLine mNeonBlendPipeLine;
676     mNeonBlendPipeLine.NeonPreLerpARGB8888(color, red, green, blue, alpha, covers);
677 }
678 #endif
679 
BlendWithSoftWare(const uint8_t * src1,const Rect & srcRect,uint32_t srcStride,uint32_t srcLineNumber,ColorMode srcMode,uint32_t color,OpacityType opa,uint8_t * dst,uint32_t destStride,ColorMode destMode,uint32_t x,uint32_t y) const680 void DrawUtils::BlendWithSoftWare(const uint8_t* src1,
681                                   const Rect& srcRect,
682                                   uint32_t srcStride,
683                                   uint32_t srcLineNumber,
684                                   ColorMode srcMode,
685                                   uint32_t color,
686                                   OpacityType opa,
687                                   uint8_t* dst,
688                                   uint32_t destStride,
689                                   ColorMode destMode,
690                                   uint32_t x,
691                                   uint32_t y) const
692 {
693     if ((dst == nullptr) || (src1 == nullptr)) {
694         return;
695     }
696     uint8_t destByteSize = GetByteSizeByColorMode(destMode);
697     uint8_t srcByteSize = GetByteSizeByColorMode(srcMode);
698 
699     uint8_t* dest = dst + destStride * y;
700     dest += destByteSize * x;
701 
702     uint8_t pxByteSize = GetPxSizeByColorMode(srcMode) >> 3; // 3 : right shift 3 bits
703     uint8_t* src = const_cast<uint8_t*>(src1) + srcStride * srcRect.GetY() + pxByteSize * srcRect.GetX();
704     uint32_t width = srcRect.GetWidth();
705     uint32_t height = srcRect.GetHeight();
706 #ifdef ARM_NEON_OPT
707     {
708         DEBUG_PERFORMANCE_TRACE("BlendWithSoftWare_neon");
709         NeonBlendPipeLine pipeLine;
710         pipeLine.Construct(destMode, srcMode);
711         int16_t dstStep = NEON_STEP_8 * GetByteSizeByColorMode(destMode);
712         int16_t srcStep = NEON_STEP_8 * GetByteSizeByColorMode(srcMode);
713         for (uint32_t row = 0; row < height; ++row) {
714             uint8_t* dstBuf = dest;
715             uint8_t* srcBuf = const_cast<uint8_t*>(src);
716             int16_t tmpWidth = width;
717             while (tmpWidth >= NEON_STEP_8) {
718                 pipeLine.Invoke(dstBuf, srcBuf, opa);
719                 dstBuf += dstStep;
720                 srcBuf += srcStep;
721                 tmpWidth -= NEON_STEP_8;
722             }
723             for (int16_t i = 0; i < tmpWidth; ++i) {
724                 COLOR_FILL_BLEND(dstBuf, destMode, srcBuf, srcMode, opa);
725                 dstBuf += destByteSize;
726                 srcBuf += srcByteSize;
727             }
728             dest += destStride;
729             src += srcStride;
730         }
731     }
732 #else
733     {
734         DEBUG_PERFORMANCE_TRACE("BlendWithSoftWare");
735         for (uint32_t row = 0; row < height; ++row) {
736             uint8_t* destTmp = dest;
737             uint8_t* srcTmp = const_cast<uint8_t*>(src);
738             for (uint32_t col = 0; col < width; ++col) {
739                 COLOR_FILL_BLEND(destTmp, destMode, srcTmp, srcMode, opa);
740                 destTmp += destByteSize;
741                 srcTmp += srcByteSize;
742             }
743             dest += destStride;
744             src += srcStride;
745         }
746     }
747 #endif
748 }
749 
GetXAxisErrForJunctionLine(bool ignoreJunctionPoint,bool isRightPart,int16_t & xMinErr,int16_t & xMaxErr)750 void DrawUtils::GetXAxisErrForJunctionLine(bool ignoreJunctionPoint,
751                                            bool isRightPart,
752                                            int16_t& xMinErr,
753                                            int16_t& xMaxErr)
754 {
755     xMinErr = 0;
756     xMaxErr = 0;
757     if (ignoreJunctionPoint) {
758         if (isRightPart) {
759             xMinErr = 1;
760         } else {
761             xMaxErr = -1;
762         }
763     }
764 }
765 
GetTransformInitState(const TransformMap & transMap,const Point & position,const Rect & trans,TransformInitState & init)766 void DrawUtils::GetTransformInitState(const TransformMap& transMap,
767                                       const Point& position,
768                                       const Rect& trans,
769                                       TransformInitState& init)
770 {
771     int16_t x = trans.GetLeft();
772     int16_t y = trans.GetTop();
773 #if ENABLE_FIXED_POINT
774     init.duHorizon = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[0]);
775     init.dvHorizon = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[1]);
776     init.duVertical = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[3]); // 3:RSxy
777     init.dvVertical = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[4]); // 4:RSyy
778     init.verticalU = (x - position.x) * init.duHorizon + (y - position.y) * init.duVertical +
779                      FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[6]); // 6:TRSx
780     init.verticalV = (x - position.x) * init.dvHorizon + (y - position.y) * init.dvVertical +
781                      FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[7]); // 7:TRSy
782 #else
783     init.duHorizon = transMap.invMatrix_.GetData()[0];
784     init.dvHorizon = transMap.invMatrix_.GetData()[1];
785     init.duVertical = transMap.invMatrix_.GetData()[3]; // 3:RSxy
786     init.dvVertical = transMap.invMatrix_.GetData()[4]; // 4:RSyy
787     init.verticalU = (x - position.x) * init.duHorizon + (y - position.y) * init.duVertical +
788                      transMap.invMatrix_.GetData()[6]; // 6:TRSx
789     init.verticalV = (x - position.x) * init.dvHorizon + (y - position.y) * init.dvVertical +
790                      transMap.invMatrix_.GetData()[7]; // 7:TRSy
791 #endif
792 }
793 
StepToNextLine(TriangleEdge & edge1,TriangleEdge & edge2)794 inline void DrawUtils::StepToNextLine(TriangleEdge& edge1, TriangleEdge& edge2)
795 {
796 #if ENABLE_FIXED_POINT
797     edge1.curY += FIXED_NUM_1;
798     edge2.curY += FIXED_NUM_1;
799     edge1.curX += FO_DIV(edge1.du, edge1.dv);
800     edge2.curX += FO_DIV(edge2.du, edge2.dv);
801 #else
802     edge1.curY++;
803     edge2.curY++;
804     edge1.curX += edge1.du / edge1.dv;
805     edge2.curX += edge2.du / edge2.dv;
806 #endif
807 }
808 
DrawTriangleAlphaBilinear(const TriangleScanInfo & in,const ColorMode bufferMode)809 void DrawUtils::DrawTriangleAlphaBilinear(const TriangleScanInfo& in, const ColorMode bufferMode)
810 {
811     int16_t maskLeft = in.mask.GetLeft();
812     int16_t maskRight = in.mask.GetRight();
813     for (int16_t y = in.yMin; y <= in.yMax; y++) {
814 #if ENABLE_FIXED_POINT
815         int16_t tempV = FO_TO_INTEGER(in.edge1.curX);
816         int16_t xMin = MATH_MAX(tempV, maskLeft);
817         tempV = FO_TO_INTEGER(in.edge2.curX);
818         int16_t xMax = MATH_MIN(tempV, maskRight);
819         int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
820 #else
821         int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX), maskLeft);
822         int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX), maskRight);
823         int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
824 #endif
825         in.init.verticalU += in.init.duHorizon * diffX;
826         in.init.verticalV += in.init.dvHorizon * diffX;
827         uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
828 
829 #if ENABLE_FIXED_POINT
830         // parameters below are Q15 fixed-point number
831         int64_t u = in.init.verticalU;
832         int64_t v = in.init.verticalV;
833         // parameters above are Q15 fixed-point number
834 #else
835         float u = in.init.verticalU;
836         float v = in.init.verticalV;
837 #endif
838         for (int16_t x = xMin; x <= xMax; x++) {
839 #if ENABLE_FIXED_POINT
840             int16_t intU = FO_TO_INTEGER(u);
841             int16_t intV = FO_TO_INTEGER(v);
842             if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
843                 int16_t intUPlus1 = intU + 1;
844                 int16_t intVPlus1 = intV + 1;
845 #else
846             const int16_t intU = static_cast<int16_t>(u);
847             const int16_t intV = static_cast<int16_t>(v);
848             if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
849                 const int16_t intUPlus1 = intU + 1;
850                 const int16_t intVPlus1 = intV + 1;
851 #endif
852                 OpacityType p1 = GetPxAlphaForAlphaImg(in.info, {intU, intV});
853                 OpacityType p2 = GetPxAlphaForAlphaImg(in.info, {intUPlus1, intV});
854                 OpacityType p3 = GetPxAlphaForAlphaImg(in.info, {intU, intVPlus1});
855                 OpacityType p4 = GetPxAlphaForAlphaImg(in.info, {intUPlus1, intVPlus1});
856 #if ENABLE_FIXED_POINT
857                 // parameters below are Q15 fixed-point number
858                 int64_t decU = FO_DECIMAL(u);
859                 int64_t decV = FO_DECIMAL(v);
860                 int64_t decUMinus1 = FIXED_NUM_1 - decU;
861                 int64_t decVMinus1 = FIXED_NUM_1 - decV;
862                 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
863                 int64_t w2 = FO_MUL(decU, decVMinus1);
864                 int64_t w3 = FO_MUL(decUMinus1, decV);
865                 int64_t w4 = FO_MUL(decU, decV);
866                 // parameters above are Q15 fixed-point number
867 #else
868                 const float decU = u - intU;
869                 const float decV = v - intV;
870                 const float decUMinus1 = 1.0f - decU;
871                 const float decVMinus1 = 1.0f - decV;
872 
873                 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
874                 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f);       // 256:shift 8 bit left
875                 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f);       // 256:shift 8 bit left
876                 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f);             // 256:shift 8 bit left
877 #endif
878 #if ENABLE_ARM_MATH
879                 const int64_t outA = __SMUAD(p1, w1) + __SMUAD(p2, w2) + __SMUAD(p3, w3) + __SMUAD(p4, w4);
880 #else
881                 const int64_t outA = p1 * w1 + p2 * w2 + p3 * w3 + p4 * w4;
882 #endif
883                 Color32 result;
884                 result.full = Color::ColorTo32(in.color);
885 #if ENABLE_FIXED_POINT
886                 result.alpha = FO_TO_INTEGER(outA);
887 #else
888                 result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
889 #endif
890                 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
891             }
892             u += in.init.duHorizon;
893             v += in.init.dvHorizon;
894             screenBuffer += in.bufferPxSize;
895         }
896         StepToNextLine(in.edge1, in.edge2);
897         in.init.verticalU += in.init.duVertical;
898         in.init.verticalV += in.init.dvVertical;
899 #if ENABLE_FIXED_POINT
900         int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
901 #else
902         int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
903 #endif
904         in.init.verticalU += in.init.duHorizon * deltaX;
905         in.init.verticalV += in.init.dvHorizon * deltaX;
906     }
907 }
908 
909 void DrawUtils::DrawTriangleTrueColorBilinear565(const TriangleScanInfo& in, const ColorMode bufferMode)
910 {
911     int16_t maskLeft = in.mask.GetLeft();
912     int16_t maskRight = in.mask.GetRight();
913     int16_t xMinErr = 0;
914     int16_t xMaxErr = 0;
915     GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
916     for (int16_t y = in.yMin; y <= in.yMax; y++) {
917 #if ENABLE_FIXED_POINT
918         int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
919         int16_t xMin = MATH_MAX(tempV, maskLeft);
920         tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
921         int16_t xMax = MATH_MIN(tempV, maskRight);
922         int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
923 #else
924         int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
925         int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
926         int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
927 #endif
928         in.init.verticalU += in.init.duHorizon * diffX;
929         in.init.verticalV += in.init.dvHorizon * diffX;
930         uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
931 #if ENABLE_FIXED_POINT
932         // parameters below are Q15 fixed-point number
933         int64_t u = in.init.verticalU;
934         int64_t v = in.init.verticalV;
935         // parameters above are Q15 fixed-point number
936 #else
937         float u = in.init.verticalU;
938         float v = in.init.verticalV;
939 #endif
940         for (int16_t x = xMin; x <= xMax; x++) {
941 #if ENABLE_FIXED_POINT
942             int16_t intU = FO_TO_INTEGER(u);
943             int16_t intV = FO_TO_INTEGER(v);
944             if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
945 #else
946             const int16_t intU = static_cast<int16_t>(u);
947             const int16_t intV = static_cast<int16_t>(v);
948             if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
949 #endif
950 #if ENABLE_ARM_MATH
951                 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
952                 uint32_t val2 = __SMUAD(intU, in.pixelSize);
953                 uint32_t px1 = val1 + val2;
954 #else
955                 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
956 #endif
957                 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
958                 const Color16 p1 = *(reinterpret_cast<Color16*>(&imgHead[px1]));
959                 const Color16 p2 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.pixelSize]));
960                 const Color16 p3 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.srcLineWidth]));
961                 const Color16 p4 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
962 #if ENABLE_FIXED_POINT
963                 // parameters below are Q15 fixed-point number
964                 int64_t decU = FO_DECIMAL(u);
965                 int64_t decV = FO_DECIMAL(v);
966                 int64_t decUMinus1 = FIXED_NUM_1 - decU;
967                 int64_t decVMinus1 = FIXED_NUM_1 - decV;
968                 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
969                 int64_t w2 = FO_MUL(decU, decVMinus1);
970                 int64_t w3 = FO_MUL(decUMinus1, decV);
971                 int64_t w4 = FO_MUL(decU, decV);
972                 // parameters above are Q15 fixed-point number
973 #else
974                 const float decU = u - intU;
975                 const float decV = v - intV;
976                 const float decUMinus1 = 1 - decU;
977                 const float decVMinus1 = 1 - decV;
978                 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
979                 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f);       // 256:shift 8 bit left
980                 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f);       // 256:shift 8 bit left
981                 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f);             // 256:shift 8 bit left
982 #endif
983 #if ENABLE_ARM_MATH
984                 const int64_t outR =
985                     __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
986                 const int64_t outG =
987                     __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
988                 const int64_t outB =
989                     __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
990 #else
991                 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
992                 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
993                 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
994 #endif
995 
996                 Color16 result;
997 #if ENABLE_FIXED_POINT
998                 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
999                 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1000                 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1001 #else
1002                 result.red = static_cast<uint8_t>(outR >> 5);   // 5:shift 5 bit right
1003                 result.green = static_cast<uint8_t>(outG >> 6); // 6:shift 6 bit right
1004                 result.blue = static_cast<uint8_t>(outB >> 5);  // 5:shift 5 bit right
1005 #endif
1006                 if (in.opaScale == OPA_OPAQUE) {
1007                     COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, RGB565);
1008                 } else {
1009                     COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, RGB565, in.opaScale);
1010                 }
1011             }
1012             u += in.init.duHorizon;
1013             v += in.init.dvHorizon;
1014             screenBuffer += in.bufferPxSize;
1015         }
1016         StepToNextLine(in.edge1, in.edge2);
1017         in.init.verticalU += in.init.duVertical;
1018         in.init.verticalV += in.init.dvVertical;
1019 #if ENABLE_FIXED_POINT
1020         int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1021 #else
1022         int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1023 #endif
1024         in.init.verticalU += in.init.duHorizon * deltaX;
1025         in.init.verticalV += in.init.dvHorizon * deltaX;
1026     }
1027 }
1028 
1029 void DrawUtils::DrawTriangleTrueColorBilinear888(const TriangleScanInfo& in, const ColorMode bufferMode)
1030 {
1031     int16_t maskLeft = in.mask.GetLeft();
1032     int16_t maskRight = in.mask.GetRight();
1033     int16_t xMinErr = 0;
1034     int16_t xMaxErr = 0;
1035     GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1036     for (int16_t y = in.yMin; y <= in.yMax; y++) {
1037 #if ENABLE_FIXED_POINT
1038         int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1039         int16_t xMin = MATH_MAX(tempV, maskLeft);
1040         tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1041         int16_t xMax = MATH_MIN(tempV, maskRight);
1042         int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
1043 #else
1044         int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1045         int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1046         int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
1047 #endif
1048         in.init.verticalU += in.init.duHorizon * diffX;
1049         in.init.verticalV += in.init.dvHorizon * diffX;
1050         uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1051 #if ENABLE_FIXED_POINT
1052         // parameters below are Q15 fixed-point number
1053         int64_t u = in.init.verticalU;
1054         int64_t v = in.init.verticalV;
1055         // parameters above are Q15 fixed-point number
1056 #else
1057         float u = in.init.verticalU;
1058         float v = in.init.verticalV;
1059 #endif
1060         for (int16_t x = xMin; x <= xMax; x++) {
1061 #if ENABLE_FIXED_POINT
1062             int16_t intU = FO_TO_INTEGER(u);
1063             int16_t intV = FO_TO_INTEGER(v);
1064 #else
1065             const int16_t intU = static_cast<int16_t>(u);
1066             const int16_t intV = static_cast<int16_t>(v);
1067 #endif
1068             if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1069 #if ENABLE_ARM_MATH
1070                 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1071                 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1072                 uint32_t px1 = val1 + val2;
1073 #else
1074                 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1075 #endif
1076                 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1077                 const Color24 p1 = *(reinterpret_cast<Color24*>(&imgHead[px1]));
1078                 const Color24 p2 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.pixelSize]));
1079                 const Color24 p3 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.srcLineWidth]));
1080                 const Color24 p4 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1081 #if ENABLE_FIXED_POINT
1082                 // parameters below are Q15 fixed-point number
1083                 int64_t decU = FO_DECIMAL(u);
1084                 int64_t decV = FO_DECIMAL(v);
1085                 int64_t decUMinus1 = FIXED_NUM_1 - decU;
1086                 int64_t decVMinus1 = FIXED_NUM_1 - decV;
1087                 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
1088                 int64_t w2 = FO_MUL(decU, decVMinus1);
1089                 int64_t w3 = FO_MUL(decUMinus1, decV);
1090                 int64_t w4 = FO_MUL(decU, decV);
1091                 // parameters above are Q15 fixed-point number
1092 #else
1093                 const float decU = u - intU;
1094                 const float decV = v - intV;
1095                 const float decUMinus1 = 1 - decU;
1096                 const float decVMinus1 = 1 - decV;
1097                 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
1098                 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f);       // 256:shift 8 bit left
1099                 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f);       // 256:shift 8 bit left
1100                 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f);             // 256:shift 8 bit left
1101 #endif
1102 
1103 #if ENABLE_ARM_MATH
1104                 const int64_t outR =
1105                     __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1106                 const int64_t outG =
1107                     __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1108                 const int64_t outB =
1109                     __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1110 #else
1111                 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1112                 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1113                 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1114 #endif
1115 
1116                 Color24 result;
1117 #if ENABLE_FIXED_POINT
1118                 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1119                 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1120                 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1121 #else
1122                 result.red = static_cast<uint8_t>(outR >> 8);   // 8:shift 8 bit right
1123                 result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1124                 result.blue = static_cast<uint8_t>(outB >> 8);  // 8:shift 8 bit right
1125 #endif
1126                 if (in.opaScale == OPA_OPAQUE) {
1127                     COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, RGB888);
1128                 } else {
1129                     COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, RGB888, in.opaScale);
1130                 }
1131             }
1132             u += in.init.duHorizon;
1133             v += in.init.dvHorizon;
1134             screenBuffer += in.bufferPxSize;
1135         }
1136         StepToNextLine(in.edge1, in.edge2);
1137         in.init.verticalU += in.init.duVertical;
1138         in.init.verticalV += in.init.dvVertical;
1139 #if ENABLE_FIXED_POINT
1140         int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1141 #else
1142         int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1143 #endif
1144         in.init.verticalU += in.init.duHorizon * deltaX;
1145         in.init.verticalV += in.init.dvHorizon * deltaX;
1146     }
1147 }
1148 
1149 #if !ENABLE_FIXED_POINT
1150 static void DrawTriangleTrueColorBilinear8888Inner(const TriangleScanInfo& in,
1151                                                    uint8_t* screenBuffer,
1152                                                    int16_t len,
1153                                                    const ColorMode bufferMode,
1154                                                    float u,
1155                                                    float v)
1156 {
1157     for (int16_t x = 0; x < len; ++x) {
1158         const int16_t intU = static_cast<int16_t>(u);
1159         const int16_t intV = static_cast<int16_t>(v);
1160         if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1161 #if ENABLE_ARM_MATH
1162             uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1163             uint32_t val2 = __SMUAD(intU, in.pixelSize);
1164             uint32_t px1 = val1 + val2;
1165 #else
1166             uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1167 #endif
1168             uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1169             const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1170             const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1171             const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1172             const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1173 
1174             const float decU = u - intU;
1175             const float decV = v - intV;
1176             const float decUMinus1 = 1 - decU;
1177             const float decVMinus1 = 1 - decV;
1178 
1179             const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
1180             const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f);       // 256:shift 8 bit left
1181             const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f);       // 256:shift 8 bit left
1182             const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f);             // 256:shift 8 bit left
1183 
1184 #if ENABLE_ARM_MATH
1185             const int32_t outR = __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1186             const int32_t outG =
1187                 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1188             const int32_t outB =
1189                 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1190             const int32_t outA =
1191                 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1192 #else
1193             const int32_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1194             const int32_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1195             const int32_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1196             const int32_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1197 #endif
1198 
1199             Color32 result;
1200             result.red = static_cast<uint8_t>(outR >> 8);   // 8:shift 8 bit right
1201             result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1202             result.blue = static_cast<uint8_t>(outB >> 8);  // 8:shift 8 bit right
1203             result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
1204             if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1205                 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1206             } else {
1207                 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1208             }
1209         }
1210         u += in.init.duHorizon;
1211         v += in.init.dvHorizon;
1212         screenBuffer += in.bufferPxSize;
1213     }
1214 }
1215 #endif
1216 
1217 #if defined(ENABLE_FIXED_POINT) && ENABLE_FIXED_POINT
1218 static void DrawFixedTriangleTrueColorBilinear8888Inner(const TriangleScanInfo& in,
1219                                                         uint8_t* screenBuffer,
1220                                                         int16_t len,
1221                                                         const ColorMode bufferMode,
1222                                                         int64_t u,
1223                                                         int64_t v)
1224 {
1225     for (int16_t x = 0; x < len; ++x) {
1226         int16_t intU = FO_TO_INTEGER(u);
1227         int16_t intV = FO_TO_INTEGER(v);
1228         if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1229 #if ENABLE_ARM_MATH
1230             uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1231             uint32_t val2 = __SMUAD(intU, in.pixelSize);
1232             uint32_t px1 = val1 + val2;
1233 #else
1234             uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1235 #endif
1236             uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1237             const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1238             const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1239             const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1240             const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1241 
1242             // parameters below are Q15 fixed-point number
1243             int64_t decU = FO_DECIMAL(u);
1244             int64_t decV = FO_DECIMAL(v);
1245             int64_t decUMinus1 = FIXED_NUM_1 - decU;
1246             int64_t decVMinus1 = FIXED_NUM_1 - decV;
1247             int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
1248             int64_t w2 = FO_MUL(decU, decVMinus1);
1249             int64_t w3 = FO_MUL(decUMinus1, decV);
1250             int64_t w4 = FO_MUL(decU, decV);
1251             // parameters above are Q15 fixed-point number
1252 
1253 #if ENABLE_ARM_MATH
1254             const int64_t outR = __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1255             const int64_t outG =
1256                 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1257             const int64_t outB =
1258                 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1259             const int64_t outA =
1260                 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1261 #else
1262             const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1263             const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1264             const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1265             const int64_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1266 #endif
1267 
1268             Color32 result;
1269             result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1270             result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1271             result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1272             result.alpha = static_cast<uint8_t>(outA >> FIXED_Q_NUM);
1273             if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1274                 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1275             } else {
1276                 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1277             }
1278         }
1279         u += in.init.duHorizon;
1280         v += in.init.dvHorizon;
1281         screenBuffer += in.bufferPxSize;
1282     }
1283 }
1284 #endif
1285 
1286 #ifdef ARM_NEON_OPT
1287 static void DrawTriangleTrueColorBilinear8888InnerNeon(const TriangleScanInfo& in,
1288                                                        uint8_t* screenBuffer,
1289                                                        int16_t len,
1290                                                        float u,
1291                                                        float v,
1292                                                        NeonBlendPipeLine& pipeLine,
1293                                                        const ColorMode bufferMode)
1294 {
1295     ColorType arrayp1[NEON_STEP_8] = {};
1296     ColorType arrayp2[NEON_STEP_8] = {};
1297     ColorType arrayp3[NEON_STEP_8] = {};
1298     ColorType arrayp4[NEON_STEP_8] = {};
1299     float arrayU[NEON_STEP_8] = {0};
1300     float arrayV[NEON_STEP_8] = {0};
1301     int32_t arrayPx1[NEON_STEP_8] = {0};
1302     int16_t step = in.bufferPxSize * NEON_STEP_8;
1303 #if ENABLE_FIXED_POINT
1304     float duHorizon = static_cast<float>(in.init.duHorizon) / FIXED_NUM_1;
1305     float dvHorizon = static_cast<float>(in.init.dvHorizon) / FIXED_NUM_1;
1306 #endif
1307     while (len >= NEON_STEP_8) {
1308         for (uint32_t i = 0; i < NEON_STEP_8; ++i) {
1309             arrayU[i] = u;
1310             arrayV[i] = v;
1311 #if ENABLE_FIXED_POINT
1312             u += duHorizon;
1313             v += dvHorizon;
1314 #else
1315             u += in.init.duHorizon;
1316             v += in.init.dvHorizon;
1317 #endif
1318         }
1319         // Monotonically increasing or decreasing, so only judge the beginning and end.
1320         if ((arrayU[0] >= 0) && (arrayU[0] < in.info.header.width - 1) && (arrayV[0] >= 0) &&
1321             (arrayV[0] < in.info.header.height - 1) && (arrayU[NEON_STEP_8 - 1] >= 0) &&
1322             (arrayU[NEON_STEP_8 - 1] < in.info.header.width - 1) && (arrayV[NEON_STEP_8 - 1] >= 0) &&
1323             (arrayV[NEON_STEP_8 - 1] < in.info.header.height - 1)) {
1324             // Process the lower half of arrayU and arrayV
1325             float32x4_t vU = vld1q_f32(arrayU);
1326             float32x4_t vV = vld1q_f32(arrayV);
1327             int32x4_t vIntU = vcvtq_s32_f32(vU);
1328             int32x4_t vIntV = vcvtq_s32_f32(vV);
1329             int32x4_t vPx1 =
1330                 vaddq_s32(vmulq_s32(vIntV, vdupq_n_s32(in.srcLineWidth)), vmulq_s32(vIntU, vdupq_n_s32(in.pixelSize)));
1331             vst1q_s32(arrayPx1, vPx1);
1332             float32x4_t vDecU = vsubq_f32(vU, vcvtq_f32_s32(vIntU));
1333             float32x4_t vDecV = vsubq_f32(vV, vcvtq_f32_s32(vIntV));
1334             float32x4_t vDecUMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecU);
1335             float32x4_t vDecVMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecV);
1336             // 256:shift 8 bit left
1337             uint32x4_t vLowW1 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecVMinus1), vdupq_n_f32(256.0)));
1338             uint32x4_t vLowW2 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecVMinus1), vdupq_n_f32(256.0)));
1339             uint32x4_t vLowW3 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecV), vdupq_n_f32(256.0)));
1340             uint32x4_t vLowW4 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecV), vdupq_n_f32(256.0)));
1341             // Process the higher half of arrayU and arrayV
1342             vU = vld1q_f32(arrayU + NEON_STEP_4);
1343             vV = vld1q_f32(arrayV + NEON_STEP_4);
1344             vIntU = vcvtq_s32_f32(vU);
1345             vIntV = vcvtq_s32_f32(vV);
1346             vPx1 =
1347                 vaddq_s32(vmulq_s32(vIntV, vdupq_n_s32(in.srcLineWidth)), vmulq_s32(vIntU, vdupq_n_s32(in.pixelSize)));
1348             vst1q_s32(arrayPx1 + NEON_STEP_4, vPx1);
1349             vDecU = vsubq_f32(vU, vcvtq_f32_s32(vIntU));
1350             vDecV = vsubq_f32(vV, vcvtq_f32_s32(vIntV));
1351             vDecUMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecU);
1352             vDecVMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecV);
1353             // 256:shift 8 bit left
1354             uint32x4_t vHighW1 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecVMinus1), vdupq_n_f32(256.0)));
1355             uint32x4_t vHighW2 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecVMinus1), vdupq_n_f32(256.0)));
1356             uint32x4_t vHighW3 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecV), vdupq_n_f32(256.0)));
1357             uint32x4_t vHighW4 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecV), vdupq_n_f32(256.0)));
1358 
1359             // joins two uint32x4_t vectors into a uint16x8_t vector
1360             uint16x8_t vW1 = vcombine_u16(vmovn_u32(vLowW1), vmovn_u32(vHighW1));
1361             uint16x8_t vW2 = vcombine_u16(vmovn_u32(vLowW2), vmovn_u32(vHighW2));
1362             uint16x8_t vW3 = vcombine_u16(vmovn_u32(vLowW3), vmovn_u32(vHighW3));
1363             uint16x8_t vW4 = vcombine_u16(vmovn_u32(vLowW4), vmovn_u32(vHighW4));
1364 
1365             uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1366             for (uint32_t i = 0; i < NEON_STEP_8; ++i) {
1367                 int32_t px1 = arrayPx1[i];
1368                 arrayp1[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1369                 arrayp2[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1370                 arrayp3[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1371                 arrayp4[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1372             }
1373 
1374             uint8x8x4_t v4p1 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp1));
1375             uint8x8x4_t v4p2 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp2));
1376             uint8x8x4_t v4p3 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp3));
1377             uint8x8x4_t v4p4 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp4));
1378             uint8x8_t vOutB =
1379                 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_B]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_B]), vW2) +
1380                                 vmulq_u16(vmovl_u8(v4p3.val[NEON_B]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_B]), vW4),
1381                             8); // 8:shift 8 bit right
1382             uint8x8_t vOutG =
1383                 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_G]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_G]), vW2) +
1384                                 vmulq_u16(vmovl_u8(v4p3.val[NEON_G]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_G]), vW4),
1385                             8); // 8:shift 8 bit right
1386             uint8x8_t vOutR =
1387                 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_R]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_R]), vW2) +
1388                                 vmulq_u16(vmovl_u8(v4p3.val[NEON_R]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_R]), vW4),
1389                             8); // 8:shift 8 bit right
1390             uint8x8_t vOutA =
1391                 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_A]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_A]), vW2) +
1392                                 vmulq_u16(vmovl_u8(v4p3.val[NEON_A]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_A]), vW4),
1393                             8); // 8:shift 8 bit right
1394             vOutA = NeonMulDiv255(vdup_n_u8(in.opaScale), vOutA);
1395             pipeLine.Invoke(screenBuffer, vOutR, vOutG, vOutB, vOutA);
1396         } else {
1397 #if ENABLE_FIXED_POINT
1398             int64_t fixedU = FO_TRANS_FLOAT_TO_FIXED(arrayU[0]);
1399             int64_t fixedV = FO_TRANS_FLOAT_TO_FIXED(arrayV[0]);
1400             DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, NEON_STEP_8, bufferMode, fixedU, fixedV);
1401 #else
1402             DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, NEON_STEP_8, bufferMode, arrayU[0], arrayV[0]);
1403 #endif
1404         }
1405         screenBuffer += step;
1406         len -= NEON_STEP_8;
1407     }
1408     if (len > 0) {
1409 #if ENABLE_FIXED_POINT
1410         int64_t fixedU = FO_TRANS_FLOAT_TO_FIXED(u);
1411         int64_t fixedV = FO_TRANS_FLOAT_TO_FIXED(v);
1412         DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, len, bufferMode, fixedU, fixedV);
1413 #else
1414         DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, len, bufferMode, u, v);
1415 #endif
1416     }
1417 }
1418 #endif
1419 
1420 void DrawUtils::Draw3DTriangleTrueColorBilinear8888(const TriangleScanInfo& in, const ColorMode bufferMode)
1421 {
1422     int16_t maskLeft = in.mask.GetLeft();
1423     int16_t maskRight = in.mask.GetRight();
1424     int16_t xMinErr = 0;
1425     int16_t xMaxErr = 0;
1426     GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1427 #if ENABLE_FIXED_POINT
1428     int64_t invMatrix00 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[0]);
1429     int64_t invMatrix01 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[1]);
1430     int64_t invMatrix02 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[2]);
1431     int64_t invMatrix20 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[3]);
1432     int64_t invMatrix21 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[4]);
1433     int64_t invMatrix22 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[5]);
1434     int64_t invMatrix30 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[6]);
1435     int64_t invMatrix31 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[7]);
1436     int64_t invMatrix32 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[8]);
1437 #else  // ENABLE_FIXED_POINT
1438     float invMatrix00 = in.matrix.GetData()[0];
1439     float invMatrix01 = in.matrix.GetData()[1];
1440     float invMatrix02 = in.matrix.GetData()[2];
1441     float invMatrix20 = in.matrix.GetData()[3];
1442     float invMatrix21 = in.matrix.GetData()[4];
1443     float invMatrix22 = in.matrix.GetData()[5];
1444     float invMatrix30 = in.matrix.GetData()[6];
1445     float invMatrix31 = in.matrix.GetData()[7];
1446     float invMatrix32 = in.matrix.GetData()[8];
1447 #endif // ENABLE_FIXED_POINT
1448     for (int16_t y = in.yMin; y <= in.yMax; ++y) {
1449 #if ENABLE_FIXED_POINT
1450         int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1451         int16_t xMin = MATH_MAX(tempV, maskLeft);
1452         tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1453         int16_t xMax = MATH_MIN(tempV, maskRight);
1454 #else  // ENABLE_FIXED_POINT
1455         int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1456         int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1457 #endif // ENABLE_FIXED_POINT
1458         uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1459         // move to current position
1460         for (int16_t x = xMin; x <= xMax; x++) {
1461 #if ENABLE_FIXED_POINT
1462             int64_t w = invMatrix02 * x + invMatrix22 * y + invMatrix32;
1463             int64_t u = FO_DIV((invMatrix00 * x + invMatrix20 * y + invMatrix30), w);
1464             int64_t v = FO_DIV((invMatrix01 * x + invMatrix21 * y + invMatrix31), w);
1465             int16_t intU = FO_TO_INTEGER(u);
1466             int16_t intV = FO_TO_INTEGER(v);
1467 #else  // ENABLE_FIXED_POINT
1468             float w = invMatrix02 * x + invMatrix22 * y + invMatrix32;
1469             float u = (invMatrix00 * x + invMatrix20 * y + invMatrix30) / w;
1470             float v = (invMatrix01 * x + invMatrix21 * y + invMatrix31) / w;
1471             int16_t intU = static_cast<int16_t>(u);
1472             int16_t intV = static_cast<int16_t>(v);
1473 #endif // ENABLE_FIXED_POINT
1474             if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1475 #if ENABLE_ARM_MATH
1476                 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1477                 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1478                 uint32_t px1 = val1 + val2;
1479 #else  // ENABLE_ARM_MATH
1480                 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1481 #endif // ENABLE_ARM_MATH
1482                 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1483                 const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1484                 const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1485                 const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1486                 const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1487 #if ENABLE_FIXED_POINT
1488                 int64_t decU = FO_DECIMAL(u);
1489                 int64_t decV = FO_DECIMAL(v);
1490                 int64_t decUMinus1 = FIXED_NUM_1 - decU;
1491                 int64_t decVMinus1 = FIXED_NUM_1 - decV;
1492                 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
1493                 int64_t w2 = FO_MUL(decU, decVMinus1);
1494                 int64_t w3 = FO_MUL(decUMinus1, decV);
1495                 int64_t w4 = FO_MUL(decU, decV);
1496 #if ENABLE_ARM_MATH
1497                 const int64_t outR =
1498                     __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1499                 const int64_t outG =
1500                     __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1501                 const int64_t outB =
1502                     __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1503                 const int64_t outA =
1504                     __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1505 #else
1506                 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1507                 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1508                 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1509                 const int64_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1510 #endif
1511                 Color32 result;
1512                 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1513                 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1514                 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1515                 result.alpha = static_cast<uint8_t>(outA >> FIXED_Q_NUM);
1516 #else // ENABLE_FIXED_POINT
1517                 const float decU = u - intU;
1518                 const float decV = v - intV;
1519                 const float decUMinus1 = 1 - decU;
1520                 const float decVMinus1 = 1 - decV;
1521                 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
1522                 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f);       // 256:shift 8 bit left
1523                 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f);       // 256:shift 8 bit left
1524                 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f);
1525 #if ENABLE_ARM_MATH
1526                 const int32_t outR =
1527                     __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1528                 const int32_t outG =
1529                     __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1530                 const int32_t outB =
1531                     __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1532                 const int32_t outA =
1533                     __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1534 #else  // ENABLE_ARM_MATH
1535                 const int32_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1536                 const int32_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1537                 const int32_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1538                 const int32_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1539 #endif // ENABLE_ARM_MATH
1540                 Color32 result;
1541                 result.red = static_cast<uint8_t>(outR >> 8);   // 8:shift 8 bit right
1542                 result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1543                 result.blue = static_cast<uint8_t>(outB >> 8);  // 8:shift 8 bit right
1544                 result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
1545 #endif // ENABLE_FIXED_POINT
1546                 if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1547                     COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1548                 } else {
1549                     COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1550                 }
1551             }
1552             screenBuffer += in.bufferPxSize;
1553         }
1554         StepToNextLine(in.edge1, in.edge2);
1555     }
1556 }
1557 
1558 void DrawUtils::DrawTriangleTrueColorBilinear8888(const TriangleScanInfo& in, const ColorMode bufferMode)
1559 {
1560     int16_t maskLeft = in.mask.GetLeft();
1561     int16_t maskRight = in.mask.GetRight();
1562     int16_t xMinErr = 0;
1563     int16_t xMaxErr = 0;
1564     GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1565 #ifdef ARM_NEON_OPT
1566     NeonBlendPipeLine pipeLine;
1567     pipeLine.Construct(bufferMode, ARGB8888);
1568 #endif
1569     for (int16_t y = in.yMin; y <= in.yMax; ++y) {
1570 #if ENABLE_FIXED_POINT
1571         int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1572         int16_t xMin = MATH_MAX(tempV, maskLeft);
1573         tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1574         int16_t xMax = MATH_MIN(tempV, maskRight);
1575         int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
1576 #else
1577         int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1578         int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1579         int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
1580 #endif
1581         in.init.verticalU += in.init.duHorizon * diffX;
1582         in.init.verticalV += in.init.dvHorizon * diffX;
1583         uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1584 #ifdef ARM_NEON_OPT
1585         {
1586 #if ENABLE_FIXED_POINT
1587             float u = static_cast<float>(in.init.verticalU) / FIXED_NUM_1;
1588             float v = static_cast<float>(in.init.verticalV) / FIXED_NUM_1;
1589 #else
1590             float u = in.init.verticalU;
1591             float v = in.init.verticalV;
1592 #endif
1593             DEBUG_PERFORMANCE_TRACE("DrawTriangleTrueColorBilinear8888_neon");
1594             DrawTriangleTrueColorBilinear8888InnerNeon(in, screenBuffer, xMax - xMin + 1, u, v, pipeLine, bufferMode);
1595         }
1596 #else
1597         {
1598             DEBUG_PERFORMANCE_TRACE("DrawTriangleTrueColorBilinear8888");
1599 #if ENABLE_FIXED_POINT
1600             DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, xMax - xMin + 1, bufferMode,
1601                                                         in.init.verticalU, in.init.verticalV);
1602 #else
1603             DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, xMax - xMin + 1, bufferMode, in.init.verticalU,
1604                                                    in.init.verticalV);
1605 #endif
1606         }
1607 #endif
1608         StepToNextLine(in.edge1, in.edge2);
1609         in.init.verticalU += in.init.duVertical;
1610         in.init.verticalV += in.init.dvVertical;
1611 #if ENABLE_FIXED_POINT
1612         int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1613 #else
1614         int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1615 #endif
1616         in.init.verticalU += in.init.duHorizon * deltaX;
1617         in.init.verticalV += in.init.dvHorizon * deltaX;
1618     }
1619 }
1620 
1621 void DrawUtils::DrawTriangleTrueColorNearest(const TriangleScanInfo& in, const ColorMode bufferMode)
1622 {
1623     int16_t maskLeft = in.mask.GetLeft();
1624     int16_t maskRight = in.mask.GetRight();
1625     int16_t xMinErr = 0;
1626     int16_t xMaxErr = 0;
1627     GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1628     for (int16_t y = in.yMin; y <= in.yMax; y++) {
1629 #if ENABLE_FIXED_POINT
1630         int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1631         int16_t xMin = MATH_MAX(tempV, maskLeft);
1632         tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1633         int16_t xMax = MATH_MIN(tempV, maskRight);
1634         int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
1635 #else
1636         int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1637         int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1638         int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
1639 #endif
1640         in.init.verticalU += in.init.duHorizon * diffX;
1641         in.init.verticalV += in.init.dvHorizon * diffX;
1642         uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1643 #if ENABLE_FIXED_POINT
1644         // parameters below are Q15 fixed-point number
1645         int64_t u = in.init.verticalU;
1646         int64_t v = in.init.verticalV;
1647         // parameters above are Q15 fixed-point number
1648 #else
1649         float u = in.init.verticalU;
1650         float v = in.init.verticalV;
1651 #endif
1652         for (int16_t x = xMin; x <= xMax; x++) {
1653 #if ENABLE_FIXED_POINT
1654             int16_t intU = FO_TO_INTEGER(u);
1655             int16_t intV = FO_TO_INTEGER(v);
1656             if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
1657 #else
1658             const int16_t intU = static_cast<int16_t>(u);
1659             const int16_t intV = static_cast<int16_t>(v);
1660             if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1661 #endif
1662 #if ENABLE_ARM_MATH
1663                 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1664                 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1665                 uint32_t px1 = val1 + val2;
1666 #else
1667                 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1668 #endif
1669                 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1670                 OpacityType opa = in.opaScale;
1671 
1672                 switch (in.info.header.colorMode) {
1673                     case RGB888: {
1674                         Color24 p24 = *(reinterpret_cast<Color24*>(&imgHead[px1]));
1675                         if (opa == OPA_OPAQUE) {
1676                             COLOR_FILL_COVER(screenBuffer, bufferMode, p24.red, p24.green, p24.blue, RGB888);
1677                         } else {
1678                             COLOR_FILL_BLEND(screenBuffer, bufferMode, &p24, RGB888, opa);
1679                         }
1680                         break;
1681                     }
1682                     case RGB565: {
1683                         Color16 p16 = *(reinterpret_cast<Color16*>(&imgHead[px1]));
1684                         if (opa == OPA_OPAQUE) {
1685                             COLOR_FILL_COVER(screenBuffer, bufferMode, p16.red, p16.green, p16.blue, RGB565);
1686                         } else {
1687                             COLOR_FILL_BLEND(screenBuffer, bufferMode, &p16, RGB565, opa);
1688                         }
1689                         break;
1690                     }
1691                     case ARGB8888: {
1692                         Color32 p32 = *(reinterpret_cast<Color32*>(&imgHead[px1]));
1693                         if ((in.opaScale == OPA_OPAQUE) && (p32.alpha == OPA_OPAQUE)) {
1694                             COLOR_FILL_COVER(screenBuffer, bufferMode, p32.red, p32.green, p32.blue, ARGB8888);
1695                         } else {
1696                             COLOR_FILL_BLEND(screenBuffer, bufferMode, &p32, ARGB8888, in.opaScale);
1697                         }
1698                         break;
1699                     }
1700                     case XRGB8888: {
1701                         Color32 p32 = *(reinterpret_cast<Color32*>(&imgHead[px1]));
1702                         if ((in.opaScale == OPA_OPAQUE) && (p32.alpha == OPA_OPAQUE)) {
1703                             COLOR_FILL_COVER(screenBuffer, bufferMode, p32.red, p32.green, p32.blue, XRGB8888);
1704                         } else {
1705                             COLOR_FILL_BLEND(screenBuffer, bufferMode, &p32, XRGB8888, in.opaScale);
1706                         }
1707                         break;
1708                     }
1709                     default:
1710                         return;
1711                 }
1712             }
1713             u += in.init.duHorizon;
1714             v += in.init.dvHorizon;
1715             screenBuffer += in.bufferPxSize;
1716         }
1717         StepToNextLine(in.edge1, in.edge2);
1718         in.init.verticalU += in.init.duVertical;
1719         in.init.verticalV += in.init.dvVertical;
1720 #if ENABLE_FIXED_POINT
1721         int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1722 #else
1723         int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1724 #endif
1725         in.init.verticalU += in.init.duHorizon * deltaX;
1726         in.init.verticalV += in.init.dvHorizon * deltaX;
1727     }
1728 }
1729 
1730 void DrawUtils::DrawTriangleTransformPart(BufferInfo& gfxDstBuffer, const TrianglePartInfo& part)
1731 {
1732 #if ENABLE_FIXED_POINT
1733     // parameters below are Q15 fixed-point number
1734     int64_t yMin = FO_TRANS_INTEGER_TO_FIXED(part.yMin);
1735     part.edge1.curX += (static_cast<int64_t>(part.edge1.du) * (yMin - part.edge1.curY) / part.edge1.dv);
1736     part.edge1.curY = yMin;
1737     part.edge2.curX += (static_cast<int64_t>(part.edge2.du) * (yMin - part.edge2.curY) / part.edge2.dv);
1738     part.edge2.curY = yMin;
1739     Rect line;
1740     line.SetLeft(FO_TO_INTEGER(part.edge1.curX));
1741     line.SetRight(FO_TO_INTEGER(part.edge1.curX));
1742     line.SetTop(FO_TO_INTEGER(part.edge1.curY));
1743     line.SetBottom(FO_TO_INTEGER(part.edge1.curY));
1744     // parameters above are Q15 fixed-point number
1745 #else
1746     part.edge1.curX += part.edge1.du * (part.yMin - part.edge1.curY) / part.edge1.dv;
1747     part.edge1.curY = part.yMin;
1748     part.edge2.curX += part.edge2.du * (part.yMin - part.edge2.curY) / part.edge2.dv;
1749     part.edge2.curY = part.yMin;
1750     Rect line;
1751     line.SetLeft(static_cast<int16_t>(part.edge1.curX));
1752     line.SetRight(static_cast<int16_t>(part.edge1.curX));
1753     line.SetTop(static_cast<int16_t>(part.edge1.curY));
1754     line.SetBottom(static_cast<int16_t>(part.edge1.curY));
1755 #endif
1756     TransformInitState init;
1757     GetTransformInitState(part.transMap, part.position, line, init);
1758 
1759     uint8_t* screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
1760     if (screenBuffer == nullptr) {
1761         return;
1762     }
1763     ColorMode bufferMode = gfxDstBuffer.mode;
1764     uint8_t bufferPxSize = GetByteSizeByColorMode(bufferMode);
1765 
1766     uint8_t pixelSize;
1767     DrawTriangleTransformFuc fuc;
1768     bool isTrueColor = (part.info.header.colorMode == ARGB8888) || (part.info.header.colorMode == RGB888) ||
1769                        (part.info.header.colorMode == RGB565) || (part.info.header.colorMode == XRGB8888);
1770     if (isTrueColor) {
1771         pixelSize = part.info.pxSize >> SHIFT_3;
1772         if (part.info.algorithm == TransformAlgorithm::NEAREST_NEIGHBOR) {
1773             fuc = DrawTriangleTrueColorNearest;
1774         } else if (part.info.header.colorMode == ARGB8888 || part.info.header.colorMode == XRGB8888) {
1775             if (part.transMap.Is3DTransform()) {
1776                 fuc = Draw3DTriangleTrueColorBilinear8888;
1777             } else {
1778                 fuc = DrawTriangleTrueColorBilinear8888;
1779             }
1780         } else if (part.info.header.colorMode == RGB888) {
1781             fuc = DrawTriangleTrueColorBilinear888;
1782         } else {
1783             fuc = DrawTriangleTrueColorBilinear565;
1784         }
1785     } else {
1786         pixelSize = part.info.pxSize;
1787         fuc = DrawTriangleAlphaBilinear;
1788     }
1789     const int32_t srcLineWidth = part.info.header.width * pixelSize;
1790     TriangleScanInfo input{part.yMin,
1791                            part.yMax,
1792                            part.edge1,
1793                            part.edge2,
1794                            screenBuffer,
1795                            bufferPxSize,
1796                            part.color,
1797                            part.opaScale,
1798                            init,
1799                            gfxDstBuffer.width,
1800                            pixelSize,
1801                            srcLineWidth,
1802                            part.info,
1803                            part.mask,
1804                            part.isRightPart,
1805                            part.ignoreJunctionPoint,
1806                            part.transMap.invMatrix_};
1807     fuc(input, gfxDstBuffer.mode);
1808 }
1809 
1810 void DrawUtils::DrawTriangleTransform(BufferInfo& gfxDstBuffer,
1811                                       const Rect& mask,
1812                                       const Point& position,
1813                                       const ColorType& color,
1814                                       OpacityType opaScale,
1815                                       const TransformMap& transMap,
1816                                       const TriangleTransformDataInfo& triangleInfo)
1817 {
1818     bool p3IsInRight = ((triangleInfo.p1.y - triangleInfo.p2.y) * triangleInfo.p3.x +
1819                         (triangleInfo.p2.x - triangleInfo.p1.x) * triangleInfo.p3.y +
1820                         triangleInfo.p1.x * triangleInfo.p2.y - triangleInfo.p2.x * triangleInfo.p1.y) < 0;
1821     TriangleEdge edge1;
1822     TriangleEdge edge2;
1823     TrianglePartInfo part{
1824         mask,
1825         transMap,
1826         position,
1827         edge1,
1828         edge2,
1829         0,
1830         0,
1831         triangleInfo.info,
1832         color,
1833         opaScale,
1834         triangleInfo.isRightPart,
1835         triangleInfo.ignoreJunctionPoint,
1836     };
1837 
1838     uint8_t yErr = 1;
1839     if (triangleInfo.p2.y == triangleInfo.p1.y) {
1840         yErr = 0;
1841         goto BottomHalf;
1842     }
1843     if (p3IsInRight) {
1844         edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p2.x, triangleInfo.p2.y);
1845         edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1846     } else {
1847         edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p2.x, triangleInfo.p2.y);
1848         edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1849     }
1850 
1851     part.yMin = MATH_MAX(mask.GetTop(), triangleInfo.p1.y);
1852     part.yMax = MATH_MIN(mask.GetBottom(), triangleInfo.p2.y);
1853     part.edge1 = edge1;
1854     part.edge2 = edge2;
1855     DrawTriangleTransformPart(gfxDstBuffer, part);
1856 BottomHalf:
1857     if (triangleInfo.p2.y == triangleInfo.p3.y) {
1858         return;
1859     }
1860 
1861     if (triangleInfo.p2.y == triangleInfo.p1.y) {
1862         if (triangleInfo.p1.x < triangleInfo.p2.x) {
1863             edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1864             edge2 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1865         } else {
1866             edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1867             edge1 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1868         }
1869     } else {
1870         if (p3IsInRight) {
1871             edge1 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1872         } else {
1873             edge2 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1874         }
1875     }
1876 
1877     part.yMin = MATH_MAX(mask.GetTop(), triangleInfo.p2.y + yErr);
1878     part.yMax = MATH_MIN(mask.GetBottom(), triangleInfo.p3.y);
1879     part.edge1 = edge1;
1880     part.edge2 = edge2;
1881     DrawTriangleTransformPart(gfxDstBuffer, part);
1882 }
1883 
1884 void DrawUtils::AddBorderToImageData(TransformDataInfo& newDataInfo, ImageInfo& imageinfo)
1885 {
1886     int16_t border = 1;          // 1 : border width
1887     int16_t offset = border * 2; // 2 : offset
1888     uint16_t width = newDataInfo.header.width;
1889     uint16_t height = newDataInfo.header.height;
1890     int16_t diff = 0;
1891     if (newDataInfo.pxSize > FONT_WEIGHT_8) {
1892         width += offset;
1893         height += offset;
1894         diff = border * newDataInfo.pxSize / FONT_WEIGHT_8;
1895     } else {
1896         width += offset * FONT_WEIGHT_8 / newDataInfo.pxSize;
1897         height += offset;
1898         diff = border;
1899     }
1900     uint16_t widthInByte = width * newDataInfo.pxSize / FONT_WEIGHT_8;
1901     if ((width * newDataInfo.pxSize) % FONT_WEIGHT_8 != 0) {
1902         widthInByte++;
1903     }
1904     imageinfo.header.width = newDataInfo.header.width;
1905     imageinfo.header.height = newDataInfo.header.height;
1906     imageinfo.dataSize = widthInByte * height;
1907     uint8_t* newData = static_cast<uint8_t*>(ImageCacheMalloc(imageinfo));
1908     if (newData == nullptr) {
1909         return;
1910     }
1911     imageinfo.data = newData;
1912     if (memset_s(newData, widthInByte * height, 0, widthInByte * height) != EOK) {
1913         ImageCacheFree(imageinfo);
1914         newData = nullptr;
1915         return;
1916     }
1917     uint8_t* tmp = newData;
1918     uint8_t* data = const_cast<uint8_t*>(newDataInfo.data);
1919     tmp += widthInByte * border + diff;
1920     for (int i = 0; i < newDataInfo.header.height; ++i) {
1921         // 2 : double
1922         if (memcpy_s(tmp, widthInByte - diff * 2, data, widthInByte - diff * 2) != EOK) {
1923         ImageCacheFree(imageinfo);
1924             newData = nullptr;
1925             return;
1926         }
1927         tmp += widthInByte;
1928         data += widthInByte - diff * 2; // 2 : double
1929     }
1930     newDataInfo.header.width = width;
1931     newDataInfo.header.height = height;
1932     newDataInfo.data = newData;
1933 }
1934 
1935 void DrawUtils::UpdateTransMap(int16_t width, int16_t height, TransformMap& transMap)
1936 {
1937     Rect rect = transMap.GetTransMapRect();
1938     Matrix4<float> matrix = transMap.GetTransformMatrix();
1939     matrix = matrix * (Matrix4<float>::Translate(Vector3<float>(-rect.GetX(), -rect.GetY(), 0)));
1940     int16_t offsetX = (width - rect.GetWidth()) / 2;   //  2 : half;
1941     int16_t offsetY = (height - rect.GetHeight()) / 2; //  2 : half;
1942     rect.SetPosition(rect.GetX() - offsetX, rect.GetY() - offsetY);
1943     rect.Resize(width, height);
1944     Polygon polygon = Polygon(rect);
1945     uint8_t vertexNum = transMap.GetPolygon().GetVertexNum();
1946     Vector4<float> imgPoint4;
1947     for (uint8_t i = 0; i < vertexNum; i++) {
1948         Vector4<float> point(polygon[i].x_, polygon[i].y_, 0, 1);
1949         imgPoint4 = matrix * point;
1950         if (imgPoint4.x_ < COORD_MIN) {
1951             polygon[i].x_ = COORD_MIN;
1952         } else if (imgPoint4.x_ > COORD_MAX) {
1953             polygon[i].x_ = COORD_MAX;
1954         } else {
1955             polygon[i].x_ = MATH_ROUND(imgPoint4.x_);
1956         }
1957 
1958         if (imgPoint4.y_ < COORD_MIN) {
1959             polygon[i].y_ = COORD_MIN;
1960         } else if (imgPoint4.y_ > COORD_MAX) {
1961             polygon[i].y_ = COORD_MAX;
1962         } else {
1963             polygon[i].y_ = MATH_ROUND(imgPoint4.y_);
1964         }
1965     }
1966     transMap.SetPolygon(polygon);
1967     Matrix3<float> matrix3(matrix[0][0], matrix[0][1], matrix[0][3], matrix[1][0], matrix[1][1], matrix[1][3],
1968                            matrix[3][0], matrix[3][1], matrix[3][3]);
1969     transMap.invMatrix_ = (matrix3 * (Matrix3<float>::Translate(Vector2<float>(rect.GetX(), rect.GetY())))).Inverse();
1970 }
1971 
1972 void DrawUtils::DrawTransform(BufferInfo& gfxDstBuffer,
1973                               const Rect& mask,
1974                               const Point& position,
1975                               const ColorType& color,
1976                               OpacityType opaScale,
1977                               const TransformMap& transMap,
1978                               const TransformDataInfo& dataInfo) const
1979 {
1980     if (opaScale == OPA_TRANSPARENT) {
1981         return;
1982     }
1983     if ((gfxDstBuffer.virAddr == nullptr) || (dataInfo.data == nullptr)) {
1984         return;
1985     }
1986     ImageInfo imageinfo;
1987     TransformDataInfo newDataInfo = dataInfo;
1988     TransformMap newTransMap = transMap;
1989     // If the width and height of the rectangle of transMap are not equal to the width and height of the ImageHeader,
1990     // a border of transparency values to the data cannot be added.
1991     if ((transMap.GetTransMapRect().GetWidth() == dataInfo.header.width) &&
1992         (transMap.GetTransMapRect().GetHeight() == dataInfo.header.height)) {
1993         // Add a border of transparency values to the data
1994         AddBorderToImageData(newDataInfo, imageinfo);
1995         // Update the transMap according to new rect width and height
1996         UpdateTransMap(newDataInfo.header.width, newDataInfo.header.height, newTransMap);
1997     }
1998 
1999     Rect trans = newTransMap.GetBoxRect();
2000     trans.SetX(trans.GetX() + position.x);
2001     trans.SetY(trans.GetY() + position.y);
2002     imageinfo.data = newDataInfo.data;
2003     if (!trans.Intersect(trans, mask)) {
2004         if (newDataInfo.data != dataInfo.data) {
2005             ImageCacheFree(imageinfo);
2006         }
2007         return;
2008     }
2009 
2010     TriangleTransformDataInfo triangleInfo{
2011         newDataInfo,
2012     };
2013     Polygon polygon = newTransMap.GetPolygon();
2014     Point p1;
2015     p1.x = polygon[0].x_ + position.x; // 0:first point
2016     p1.y = polygon[0].y_ + position.y; // 0:first point
2017     Point p2;
2018     p2.x = polygon[1].x_ + position.x; // 1:second point
2019     p2.y = polygon[1].y_ + position.y; // 1:second point
2020     Point p3;
2021     p3.x = polygon[2].x_ + position.x; // 2:third point
2022     p3.y = polygon[2].y_ + position.y; // 2:third point
2023     triangleInfo.isRightPart = ((p1.y - p3.y) * p2.x + (p3.x - p1.x) * p2.y + p1.x * p3.y - p3.x * p1.y) < 0;
2024     triangleInfo.isRightPart = (p1.y < p3.y) ? triangleInfo.isRightPart : !triangleInfo.isRightPart;
2025     DrawTriangle::SortVertexs(p1, p2, p3);
2026     triangleInfo.ignoreJunctionPoint = false;
2027     triangleInfo.p1 = p1;
2028     triangleInfo.p2 = p2;
2029     triangleInfo.p3 = p3;
2030     if ((triangleInfo.p1.y <= mask.GetBottom()) && (triangleInfo.p3.y >= mask.GetTop())) {
2031         DrawTriangleTransform(gfxDstBuffer, mask, position, color, opaScale, newTransMap, triangleInfo);
2032     }
2033 
2034     triangleInfo.ignoreJunctionPoint = true;
2035     triangleInfo.isRightPart = !triangleInfo.isRightPart;
2036     p1.x = polygon[0].x_ + position.x; // 0:first point
2037     p1.y = polygon[0].y_ + position.y; // 0:first point
2038     p3.x = polygon[2].x_ + position.x; // 2:third point
2039     p3.y = polygon[2].y_ + position.y; // 2:third point
2040     Point p4;
2041     p4.x = polygon[3].x_ + position.x; // 3:fourth point
2042     p4.y = polygon[3].y_ + position.y; // 3:fourth point
2043     DrawTriangle::SortVertexs(p1, p3, p4);
2044     triangleInfo.p1 = p1;
2045     triangleInfo.p2 = p3;
2046     triangleInfo.p3 = p4;
2047     if ((triangleInfo.p1.y <= mask.GetBottom()) && (triangleInfo.p3.y >= mask.GetTop())) {
2048         DrawTriangleTransform(gfxDstBuffer, mask, position, color, opaScale, newTransMap, triangleInfo);
2049     }
2050     if (newDataInfo.data != dataInfo.data) {
2051         ImageCacheFree(imageinfo);
2052     }
2053 }
2054 
2055 OpacityType DrawUtils::GetPxAlphaForAlphaImg(const TransformDataInfo& dataInfo, const Point& point)
2056 {
2057     Point tmpPoint = point;
2058     const uint8_t* bufU8 = const_cast<uint8_t*>(dataInfo.data);
2059 #if ENABLE_SPEC_FONT
2060     if (dataInfo.header.colorMode == A1) {
2061         uint8_t bit = tmpPoint.x & 0x7; // 0x7: 1 byte is 8 bit,
2062         tmpPoint.x = tmpPoint.x >> SHIFT_3;
2063 
2064         uint32_t px = (dataInfo.header.width >> SHIFT_3) * tmpPoint.y + tmpPoint.x;
2065         // 1: A1 means 1 bit, 7: maximum offset in bytes
2066         uint8_t pxOpa = (bufU8[px] & (1 << (7 - bit))) >> (7 - bit);
2067         return pxOpa ? OPA_TRANSPARENT : OPA_OPAQUE;
2068     } else if (dataInfo.header.colorMode == A2) {
2069         uint8_t bit = (tmpPoint.x & 0x3) * 2; // 0x3: 0b0011, 2: A2 color mode
2070         tmpPoint.x = tmpPoint.x >> SHIFT_2;
2071 
2072         uint32_t px = (dataInfo.header.width >> SHIFT_2) * tmpPoint.y + tmpPoint.x;
2073         // 3: the value of 0b0011
2074         uint8_t pxOpa = (bufU8[px] & (3 << (SHIFT_6 - bit))) >> (SHIFT_6 - bit);
2075         return pxOpa * OPACITY_STEP_A2;
2076     } else if (dataInfo.header.colorMode == A8) {
2077         uint32_t px = dataInfo.header.width * tmpPoint.y + tmpPoint.x;
2078         return bufU8[px];
2079     }
2080 #else
2081     uint8_t letterWidthInByte = (dataInfo.header.width * dataInfo.pxSize) >> SHIFT_3;
2082     // 0x7: for rounding
2083     if ((dataInfo.header.width * dataInfo.pxSize) & 0x7) {
2084         letterWidthInByte++;
2085     }
2086     uint8_t bit = (tmpPoint.x & 0x1) << SHIFT_2;
2087     bufU8 += (tmpPoint.y * letterWidthInByte) + ((tmpPoint.x * dataInfo.pxSize) >> SHIFT_3);
2088     // 0xF: 0b1111, get the data of the A4 color mode
2089     uint8_t pxOpa = (*bufU8 & (0xF << bit)) >> (bit);
2090     return pxOpa * OPACITY_STEP_A4;
2091 #endif // ENABLE_SPEC_FONT
2092 }
2093 
2094 void DrawUtils::DrawTranspantArea(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& mask)
2095 {
2096     FillArea(gfxDstBuffer, rect, mask, true, nullptr);
2097 }
2098 
2099 void DrawUtils::DrawWithBuffer(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& mask, const ColorType* colorBuf)
2100 {
2101     FillArea(gfxDstBuffer, rect, mask, false, colorBuf);
2102 }
2103 
2104 void DrawUtils::FillArea(BufferInfo& gfxDstBuffer,
2105                          const Rect& rect,
2106                          const Rect& mask,
2107                          bool isTransparent,
2108                          const ColorType* colorBuf)
2109 {
2110     Rect maskedArea;
2111     if (!maskedArea.Intersect(rect, mask)) {
2112         return;
2113     }
2114 
2115     int16_t left = maskedArea.GetLeft();
2116     int16_t right = maskedArea.GetRight();
2117     int16_t top = maskedArea.GetTop();
2118     int16_t bottom = maskedArea.GetBottom();
2119 
2120     DRAW_UTILS_PREPROCESS(gfxDstBuffer, OPA_OPAQUE);
2121     uint8_t* mem = screenBuffer;
2122     mem += top * screenBufferWidth * bufferPxSize;
2123     if (isTransparent) {
2124         uint16_t sz = (right - left + 1) * bufferPxSize;
2125         for (int16_t row = top; row <= bottom; row++) {
2126             if (memset_s(mem + (left * bufferPxSize), sz, 0, sz) != EOK) {
2127                 return;
2128             }
2129             mem += screenBufferWidth * bufferPxSize;
2130         }
2131     } else {
2132         if (colorBuf == nullptr) {
2133             return;
2134         }
2135         for (int16_t row = top; row <= bottom; row++) {
2136             for (int16_t col = left; col <= right; col++) {
2137 #if COLOR_DEPTH == 32
2138                 COLOR_FILL_COVER(mem[col * bufferPxSize], bufferMode, colorBuf[row * screenBufferWidth + col].red,
2139                                  colorBuf[row * screenBufferWidth + col].green,
2140                                  colorBuf[row * screenBufferWidth + col].blue, ARGB8888);
2141 #else
2142                 COLOR_FILL_COVER(mem[col * bufferPxSize], bufferMode, colorBuf[row * screenBufferWidth + col].red,
2143                                  colorBuf[row * screenBufferWidth + col].green,
2144                                  colorBuf[row * screenBufferWidth + col].blue, RGB565);
2145 #endif
2146             }
2147             mem += screenBufferWidth * bufferPxSize;
2148         }
2149     }
2150 }
2151 
2152 void DrawUtils::DrawAdjPixelInLine(BufferInfo& gfxDstBuffer,
2153                                    int16_t x1,
2154                                    int16_t y1,
2155                                    int16_t x2,
2156                                    int16_t y2,
2157                                    const Rect& mask,
2158                                    const ColorType& color,
2159                                    OpacityType opa,
2160                                    uint16_t weight) const
2161 {
2162     DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2163     Color32 result;
2164     result.full = Color::ColorTo32(color);
2165     if ((x1 >= mask.GetLeft()) && (x1 <= mask.GetRight()) && (y1 >= mask.GetTop()) && (y1 <= mask.GetBottom())) {
2166         screenBuffer += (y1 * screenBufferWidth + x1) * bufferPxSize;
2167         OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2168         COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2169     }
2170     if ((x2 >= mask.GetLeft()) && (x2 <= mask.GetRight()) && (y2 >= mask.GetTop()) && (y2 <= mask.GetBottom())) {
2171         screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2172         screenBuffer += (y2 * screenBufferWidth + x2) * bufferPxSize;
2173         OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2174         COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2175     }
2176 }
2177 
2178 void DrawUtils::DrawPixelInLine(BufferInfo& gfxDstBuffer,
2179                                 int16_t x,
2180                                 int16_t y,
2181                                 const Rect& mask,
2182                                 const ColorType& color,
2183                                 OpacityType opa,
2184                                 uint16_t weight) const
2185 {
2186     DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2187     Color32 result;
2188     result.full = Color::ColorTo32(color);
2189     if ((x >= mask.GetLeft()) && (x <= mask.GetRight()) && (y >= mask.GetTop()) && (y <= mask.GetBottom())) {
2190         screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2191         OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2192         COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2193     }
2194 }
2195 
2196 void DrawUtils::DrawVerPixelInLine(BufferInfo& gfxDstBuffer,
2197                                    int16_t x,
2198                                    int16_t y,
2199                                    int8_t dir,
2200                                    const Rect& mask,
2201                                    const ColorType& color,
2202                                    OpacityType opa,
2203                                    uint16_t weight) const
2204 {
2205     DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2206     if ((y < mask.GetTop()) || (y > mask.GetBottom())) {
2207         return;
2208     }
2209     Color32 result;
2210     result.full = Color::ColorTo32(color);
2211     int16_t x0 = x + dir;
2212     int16_t x1 = x - dir;
2213     if ((x0 >= mask.GetLeft()) && (x0 <= mask.GetRight())) {
2214         screenBuffer += (y * screenBufferWidth + x0) * bufferPxSize;
2215         OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2216         COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2217     }
2218     if ((x >= mask.GetLeft()) && (x <= mask.GetRight())) {
2219         screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2220         screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2221         if (opa == OPA_OPAQUE) {
2222             COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
2223         } else {
2224             COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, opa);
2225         }
2226     }
2227     if ((x1 >= mask.GetLeft()) && (x1 <= mask.GetRight())) {
2228         screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2229         screenBuffer += (y * screenBufferWidth + x1) * bufferPxSize;
2230         OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2231         COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2232     }
2233 }
2234 
2235 void DrawUtils::DrawHorPixelInLine(BufferInfo& gfxDstBuffer,
2236                                    int16_t x,
2237                                    int16_t y,
2238                                    int8_t dir,
2239                                    const Rect& mask,
2240                                    const ColorType& color,
2241                                    OpacityType opa,
2242                                    uint16_t weight) const
2243 {
2244     DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2245     if ((x < mask.GetLeft()) || (x > mask.GetRight())) {
2246         return;
2247     }
2248     Color32 result;
2249     result.full = Color::ColorTo32(color);
2250     int16_t y0 = y + dir;
2251     int16_t y1 = y - dir;
2252     if ((y0 >= mask.GetTop()) && (y0 <= mask.GetBottom())) {
2253         screenBuffer += (y0 * screenBufferWidth + x) * bufferPxSize;
2254         OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2255         COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2256     }
2257     if ((y >= mask.GetTop()) && (y <= mask.GetBottom())) {
2258         screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2259         screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2260         if (opa == OPA_OPAQUE) {
2261             COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
2262         } else {
2263             COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, opa);
2264         }
2265     }
2266     if ((y1 >= mask.GetTop()) && (y1 <= mask.GetBottom())) {
2267         screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2268         screenBuffer += (y1 * screenBufferWidth + x) * bufferPxSize;
2269         OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2270         COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2271     }
2272 }
2273 } // namespace OHOS
2274