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