1/* 2 * Copyright (c) 2021-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 "clip_utils.h" 17#include "draw_utils.h" 18#include "gfx_utils/diagram/depiction/depict_curve.h" 19#include "gfx_utils/diagram/rasterizer/rasterizer_scanline_antialias.h" 20#include "gfx_utils/diagram/scanline/geometry_scanline.h" 21#include "gfx_utils/diagram/spancolorfill/fill_base.h" 22#include "gfx_utils/diagram/spancolorfill/fill_pattern_rgba.h" 23#include "gfx_utils/graphic_log.h" 24#include "render/render_base.h" 25#include "render/render_pixfmt_rgba_blend.h" 26 27namespace OHOS { 28using UICanvasPath = DepictCurve; 29using PathTransform = DepictTransform<UICanvasPath>; 30 31ClipPath& ClipPath::MoveTo(const PointF& point) 32{ 33 vertices_->MoveTo(point.x, point.y); 34 return *this; 35} 36 37ClipPath& ClipPath::LineTo(const PointF& point) 38{ 39 if (vertices_->GetTotalVertices() != 0) { 40 vertices_->LineTo(point.x, point.y); 41 } else { 42 vertices_->MoveTo(point.x, point.y); 43 } 44 return *this; 45} 46 47ClipPath& ClipPath::CurveTo(const PointF& control1, const PointF& control2, const PointF& end) 48{ 49 vertices_->CubicBezierCurve(control1.x, control1.y, control2.x, control2.y, end.x, end.y); 50 return *this; 51} 52 53ClipPath& ClipPath::Arc(const PointF& center, float radius, int16_t startAngle, int16_t endAngle) 54{ 55 if (startAngle == endAngle) { 56 return *this; 57 } 58 float sinma = radius * Sin(startAngle); 59 float cosma = radius * Sin(QUARTER_IN_DEGREE - startAngle); 60 if (vertices_->GetTotalVertices() != 0) { 61 vertices_->LineTo(float(center.x + sinma), float(center.y - cosma)); 62 } else { 63 vertices_->MoveTo(float(center.x + sinma), float(center.y - cosma)); 64 } 65 if (MATH_ABS(startAngle - endAngle) < CIRCLE_IN_DEGREE) { 66 sinma = radius * Sin(endAngle); 67 cosma = radius * Sin(QUARTER_IN_DEGREE - endAngle); 68 } else { 69 Circle(center, radius); 70 return *this; 71 } 72 73 int16_t angle = endAngle - startAngle; 74 bool largeArcFlag = false; 75 if (angle > SEMICIRCLE_IN_DEGREE || angle <= 0) { 76 largeArcFlag = true; 77 } 78 vertices_->ArcTo(radius, radius, angle, largeArcFlag, 1, center.x + sinma, center.y - cosma); 79 return *this; 80} 81 82ClipPath& ClipPath::Circle(const PointF& center, float radius) 83{ 84 if (radius <= 0) { 85 return *this; 86 } 87 vertices_->RemoveAll(); 88#if defined(GRAPHIC_ENABLE_BEZIER_ARC_FLAG) && GRAPHIC_ENABLE_BEZIER_ARC_FLAG 89 BezierArc arc(center.x, center.y, radius, radius, 0, TWO_TIMES * PI); 90 vertices_->ConcatPath(arc, 0); 91#endif 92 return *this; 93} 94 95UICanvasVertices& ClipUtils::CloseVertices(const ClipPath& path) 96{ 97 UICanvasVertices& vertices = path.GetVertices(); 98 vertices.ClosePolygon(); 99 return vertices; 100} 101 102void ClipUtils::PerformScan(const ClipPath& path, const ImageInfo* imageInfo) 103{ 104 RasterizerScanlineAntialias rasterizer; 105 GeometryScanline scanline; 106 TransAffine transform; 107 UICanvasVertices& vertices = CloseVertices(path); 108 UICanvasPath canvasPath(vertices); 109 PathTransform pathTransform(canvasPath, transform); 110 rasterizer.Reset(); 111 rasterizer.AddPath(pathTransform); 112 if (!rasterizer.RewindScanlines()) { 113 for (int32_t i = 0; i < imageInfo->header.height; i++) { 114 DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo); 115 } 116 return; 117 } 118 scanline.Reset(rasterizer.GetMinX(), rasterizer.GetMaxX()); 119 120 bool first = true; 121 int16_t y = 0; 122 while (rasterizer.SweepScanline(scanline)) { 123 y = scanline.GetYLevel(); 124 if (first) { 125 for (int32_t i = 0; i < y; i++) { 126 DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo); 127 } 128 first = false; 129 } 130 uint32_t numSpans = scanline.NumSpans(); 131 GeometryScanline::ConstIterator span = scanline.Begin(); 132 int16_t index = 0; 133 while (true) { 134 int32_t x = span->x; 135 int32_t len = span->spanLength; 136 const uint8_t* covers = span->covers; 137 138 if (len < 0) { 139 len = -len; 140 } 141 DrawHorLine(index, y, x - index - 1, OPA_TRANSPARENT, imageInfo); 142 for (int16_t i = x; i < x + len; i++, covers++) { 143 DrawPixel(i, y, *covers, imageInfo); 144 } 145 index = x + len; 146 if (--numSpans == 0) { 147 break; 148 } 149 ++span; 150 } 151 DrawHorLine(index, y, imageInfo->header.width - index, OPA_TRANSPARENT, imageInfo); 152 } 153 154 for (int32_t i = y + 1; i < imageInfo->header.height; i++) { 155 DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo); 156 } 157} 158 159void ClipUtils::DrawPixel(int16_t x, int16_t y, uint8_t opa, const ImageInfo* imageInfo) 160{ 161 if (x < 0 || x > imageInfo->header.width - 1 || y < 0 || y > imageInfo->header.height - 1) { 162 return; 163 } 164 165 int32_t offset = imageInfo->header.width * y + x; 166 switch (imageInfo->header.colorMode) { 167 case ARGB8888: { 168 Color32* buffer = reinterpret_cast<Color32*>(const_cast<uint8_t*>(imageInfo->data)); 169 buffer[offset].alpha = buffer[offset].alpha * opa / OPA_OPAQUE; 170 break; 171 } 172 default: { 173 GRAPHIC_LOGE("Only images in ARGB8888 format are supported!"); 174 break; 175 } 176 } 177} 178 179void ClipUtils::DrawHorLine(int16_t x, int16_t y, int16_t width, uint8_t opa, const ImageInfo* imageInfo) 180{ 181 for (int32_t i = x; i <= x + width; i++) { 182 DrawPixel(i, y, opa, imageInfo); 183 } 184} 185}; 186