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