1a3e0fd82Sopenharmony_ci/* 2a3e0fd82Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License. 5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at 6a3e0fd82Sopenharmony_ci * 7a3e0fd82Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8a3e0fd82Sopenharmony_ci * 9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and 13a3e0fd82Sopenharmony_ci * limitations under the License. 14a3e0fd82Sopenharmony_ci */ 15a3e0fd82Sopenharmony_ci 16a3e0fd82Sopenharmony_ci#include "clip_utils.h" 17a3e0fd82Sopenharmony_ci#include "draw_utils.h" 18a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/depiction/depict_curve.h" 19a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/rasterizer/rasterizer_scanline_antialias.h" 20a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/scanline/geometry_scanline.h" 21a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/spancolorfill/fill_base.h" 22a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/spancolorfill/fill_pattern_rgba.h" 23a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_log.h" 24a3e0fd82Sopenharmony_ci#include "render/render_base.h" 25a3e0fd82Sopenharmony_ci#include "render/render_pixfmt_rgba_blend.h" 26a3e0fd82Sopenharmony_ci 27a3e0fd82Sopenharmony_cinamespace OHOS { 28a3e0fd82Sopenharmony_ciusing UICanvasPath = DepictCurve; 29a3e0fd82Sopenharmony_ciusing PathTransform = DepictTransform<UICanvasPath>; 30a3e0fd82Sopenharmony_ci 31a3e0fd82Sopenharmony_ciClipPath& ClipPath::MoveTo(const PointF& point) 32a3e0fd82Sopenharmony_ci{ 33a3e0fd82Sopenharmony_ci vertices_->MoveTo(point.x, point.y); 34a3e0fd82Sopenharmony_ci return *this; 35a3e0fd82Sopenharmony_ci} 36a3e0fd82Sopenharmony_ci 37a3e0fd82Sopenharmony_ciClipPath& ClipPath::LineTo(const PointF& point) 38a3e0fd82Sopenharmony_ci{ 39a3e0fd82Sopenharmony_ci if (vertices_->GetTotalVertices() != 0) { 40a3e0fd82Sopenharmony_ci vertices_->LineTo(point.x, point.y); 41a3e0fd82Sopenharmony_ci } else { 42a3e0fd82Sopenharmony_ci vertices_->MoveTo(point.x, point.y); 43a3e0fd82Sopenharmony_ci } 44a3e0fd82Sopenharmony_ci return *this; 45a3e0fd82Sopenharmony_ci} 46a3e0fd82Sopenharmony_ci 47a3e0fd82Sopenharmony_ciClipPath& ClipPath::CurveTo(const PointF& control1, const PointF& control2, const PointF& end) 48a3e0fd82Sopenharmony_ci{ 49a3e0fd82Sopenharmony_ci vertices_->CubicBezierCurve(control1.x, control1.y, control2.x, control2.y, end.x, end.y); 50a3e0fd82Sopenharmony_ci return *this; 51a3e0fd82Sopenharmony_ci} 52a3e0fd82Sopenharmony_ci 53a3e0fd82Sopenharmony_ciClipPath& ClipPath::Arc(const PointF& center, float radius, int16_t startAngle, int16_t endAngle) 54a3e0fd82Sopenharmony_ci{ 55a3e0fd82Sopenharmony_ci if (startAngle == endAngle) { 56a3e0fd82Sopenharmony_ci return *this; 57a3e0fd82Sopenharmony_ci } 58a3e0fd82Sopenharmony_ci float sinma = radius * Sin(startAngle); 59a3e0fd82Sopenharmony_ci float cosma = radius * Sin(QUARTER_IN_DEGREE - startAngle); 60a3e0fd82Sopenharmony_ci if (vertices_->GetTotalVertices() != 0) { 61a3e0fd82Sopenharmony_ci vertices_->LineTo(float(center.x + sinma), float(center.y - cosma)); 62a3e0fd82Sopenharmony_ci } else { 63a3e0fd82Sopenharmony_ci vertices_->MoveTo(float(center.x + sinma), float(center.y - cosma)); 64a3e0fd82Sopenharmony_ci } 65a3e0fd82Sopenharmony_ci if (MATH_ABS(startAngle - endAngle) < CIRCLE_IN_DEGREE) { 66a3e0fd82Sopenharmony_ci sinma = radius * Sin(endAngle); 67a3e0fd82Sopenharmony_ci cosma = radius * Sin(QUARTER_IN_DEGREE - endAngle); 68a3e0fd82Sopenharmony_ci } else { 69a3e0fd82Sopenharmony_ci Circle(center, radius); 70a3e0fd82Sopenharmony_ci return *this; 71a3e0fd82Sopenharmony_ci } 72a3e0fd82Sopenharmony_ci 73a3e0fd82Sopenharmony_ci int16_t angle = endAngle - startAngle; 74a3e0fd82Sopenharmony_ci bool largeArcFlag = false; 75a3e0fd82Sopenharmony_ci if (angle > SEMICIRCLE_IN_DEGREE || angle <= 0) { 76a3e0fd82Sopenharmony_ci largeArcFlag = true; 77a3e0fd82Sopenharmony_ci } 78a3e0fd82Sopenharmony_ci vertices_->ArcTo(radius, radius, angle, largeArcFlag, 1, center.x + sinma, center.y - cosma); 79a3e0fd82Sopenharmony_ci return *this; 80a3e0fd82Sopenharmony_ci} 81a3e0fd82Sopenharmony_ci 82a3e0fd82Sopenharmony_ciClipPath& ClipPath::Circle(const PointF& center, float radius) 83a3e0fd82Sopenharmony_ci{ 84a3e0fd82Sopenharmony_ci if (radius <= 0) { 85a3e0fd82Sopenharmony_ci return *this; 86a3e0fd82Sopenharmony_ci } 87a3e0fd82Sopenharmony_ci vertices_->RemoveAll(); 88a3e0fd82Sopenharmony_ci#if defined(GRAPHIC_ENABLE_BEZIER_ARC_FLAG) && GRAPHIC_ENABLE_BEZIER_ARC_FLAG 89a3e0fd82Sopenharmony_ci BezierArc arc(center.x, center.y, radius, radius, 0, TWO_TIMES * PI); 90a3e0fd82Sopenharmony_ci vertices_->ConcatPath(arc, 0); 91a3e0fd82Sopenharmony_ci#endif 92a3e0fd82Sopenharmony_ci return *this; 93a3e0fd82Sopenharmony_ci} 94a3e0fd82Sopenharmony_ci 95a3e0fd82Sopenharmony_ciUICanvasVertices& ClipUtils::CloseVertices(const ClipPath& path) 96a3e0fd82Sopenharmony_ci{ 97a3e0fd82Sopenharmony_ci UICanvasVertices& vertices = path.GetVertices(); 98a3e0fd82Sopenharmony_ci vertices.ClosePolygon(); 99a3e0fd82Sopenharmony_ci return vertices; 100a3e0fd82Sopenharmony_ci} 101a3e0fd82Sopenharmony_ci 102a3e0fd82Sopenharmony_civoid ClipUtils::PerformScan(const ClipPath& path, const ImageInfo* imageInfo) 103a3e0fd82Sopenharmony_ci{ 104a3e0fd82Sopenharmony_ci RasterizerScanlineAntialias rasterizer; 105a3e0fd82Sopenharmony_ci GeometryScanline scanline; 106a3e0fd82Sopenharmony_ci TransAffine transform; 107a3e0fd82Sopenharmony_ci UICanvasVertices& vertices = CloseVertices(path); 108a3e0fd82Sopenharmony_ci UICanvasPath canvasPath(vertices); 109a3e0fd82Sopenharmony_ci PathTransform pathTransform(canvasPath, transform); 110a3e0fd82Sopenharmony_ci rasterizer.Reset(); 111a3e0fd82Sopenharmony_ci rasterizer.AddPath(pathTransform); 112a3e0fd82Sopenharmony_ci if (!rasterizer.RewindScanlines()) { 113a3e0fd82Sopenharmony_ci for (int32_t i = 0; i < imageInfo->header.height; i++) { 114a3e0fd82Sopenharmony_ci DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo); 115a3e0fd82Sopenharmony_ci } 116a3e0fd82Sopenharmony_ci return; 117a3e0fd82Sopenharmony_ci } 118a3e0fd82Sopenharmony_ci scanline.Reset(rasterizer.GetMinX(), rasterizer.GetMaxX()); 119a3e0fd82Sopenharmony_ci 120a3e0fd82Sopenharmony_ci bool first = true; 121a3e0fd82Sopenharmony_ci int16_t y = 0; 122a3e0fd82Sopenharmony_ci while (rasterizer.SweepScanline(scanline)) { 123a3e0fd82Sopenharmony_ci y = scanline.GetYLevel(); 124a3e0fd82Sopenharmony_ci if (first) { 125a3e0fd82Sopenharmony_ci for (int32_t i = 0; i < y; i++) { 126a3e0fd82Sopenharmony_ci DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo); 127a3e0fd82Sopenharmony_ci } 128a3e0fd82Sopenharmony_ci first = false; 129a3e0fd82Sopenharmony_ci } 130a3e0fd82Sopenharmony_ci uint32_t numSpans = scanline.NumSpans(); 131a3e0fd82Sopenharmony_ci GeometryScanline::ConstIterator span = scanline.Begin(); 132a3e0fd82Sopenharmony_ci int16_t index = 0; 133a3e0fd82Sopenharmony_ci while (true) { 134a3e0fd82Sopenharmony_ci int32_t x = span->x; 135a3e0fd82Sopenharmony_ci int32_t len = span->spanLength; 136a3e0fd82Sopenharmony_ci const uint8_t* covers = span->covers; 137a3e0fd82Sopenharmony_ci 138a3e0fd82Sopenharmony_ci if (len < 0) { 139a3e0fd82Sopenharmony_ci len = -len; 140a3e0fd82Sopenharmony_ci } 141a3e0fd82Sopenharmony_ci DrawHorLine(index, y, x - index - 1, OPA_TRANSPARENT, imageInfo); 142a3e0fd82Sopenharmony_ci for (int16_t i = x; i < x + len; i++, covers++) { 143a3e0fd82Sopenharmony_ci DrawPixel(i, y, *covers, imageInfo); 144a3e0fd82Sopenharmony_ci } 145a3e0fd82Sopenharmony_ci index = x + len; 146a3e0fd82Sopenharmony_ci if (--numSpans == 0) { 147a3e0fd82Sopenharmony_ci break; 148a3e0fd82Sopenharmony_ci } 149a3e0fd82Sopenharmony_ci ++span; 150a3e0fd82Sopenharmony_ci } 151a3e0fd82Sopenharmony_ci DrawHorLine(index, y, imageInfo->header.width - index, OPA_TRANSPARENT, imageInfo); 152a3e0fd82Sopenharmony_ci } 153a3e0fd82Sopenharmony_ci 154a3e0fd82Sopenharmony_ci for (int32_t i = y + 1; i < imageInfo->header.height; i++) { 155a3e0fd82Sopenharmony_ci DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo); 156a3e0fd82Sopenharmony_ci } 157a3e0fd82Sopenharmony_ci} 158a3e0fd82Sopenharmony_ci 159a3e0fd82Sopenharmony_civoid ClipUtils::DrawPixel(int16_t x, int16_t y, uint8_t opa, const ImageInfo* imageInfo) 160a3e0fd82Sopenharmony_ci{ 161a3e0fd82Sopenharmony_ci if (x < 0 || x > imageInfo->header.width - 1 || y < 0 || y > imageInfo->header.height - 1) { 162a3e0fd82Sopenharmony_ci return; 163a3e0fd82Sopenharmony_ci } 164a3e0fd82Sopenharmony_ci 165a3e0fd82Sopenharmony_ci int32_t offset = imageInfo->header.width * y + x; 166a3e0fd82Sopenharmony_ci switch (imageInfo->header.colorMode) { 167a3e0fd82Sopenharmony_ci case ARGB8888: { 168a3e0fd82Sopenharmony_ci Color32* buffer = reinterpret_cast<Color32*>(const_cast<uint8_t*>(imageInfo->data)); 169a3e0fd82Sopenharmony_ci buffer[offset].alpha = buffer[offset].alpha * opa / OPA_OPAQUE; 170a3e0fd82Sopenharmony_ci break; 171a3e0fd82Sopenharmony_ci } 172a3e0fd82Sopenharmony_ci default: { 173a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("Only images in ARGB8888 format are supported!"); 174a3e0fd82Sopenharmony_ci break; 175a3e0fd82Sopenharmony_ci } 176a3e0fd82Sopenharmony_ci } 177a3e0fd82Sopenharmony_ci} 178a3e0fd82Sopenharmony_ci 179a3e0fd82Sopenharmony_civoid ClipUtils::DrawHorLine(int16_t x, int16_t y, int16_t width, uint8_t opa, const ImageInfo* imageInfo) 180a3e0fd82Sopenharmony_ci{ 181a3e0fd82Sopenharmony_ci for (int32_t i = x; i <= x + width; i++) { 182a3e0fd82Sopenharmony_ci DrawPixel(i, y, opa, imageInfo); 183a3e0fd82Sopenharmony_ci } 184a3e0fd82Sopenharmony_ci} 185a3e0fd82Sopenharmony_ci}; 186