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