1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2016 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 9cb93a386Sopenharmony_ci#include "include/core/SkRegion.h" 10cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 11cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 12cb93a386Sopenharmony_ci#include "src/core/SkAnalyticEdge.h" 13cb93a386Sopenharmony_ci#include "src/core/SkAntiRun.h" 14cb93a386Sopenharmony_ci#include "src/core/SkAutoMalloc.h" 15cb93a386Sopenharmony_ci#include "src/core/SkBlitter.h" 16cb93a386Sopenharmony_ci#include "src/core/SkEdge.h" 17cb93a386Sopenharmony_ci#include "src/core/SkEdgeBuilder.h" 18cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 19cb93a386Sopenharmony_ci#include "src/core/SkQuadClipper.h" 20cb93a386Sopenharmony_ci#include "src/core/SkRasterClip.h" 21cb93a386Sopenharmony_ci#include "src/core/SkScan.h" 22cb93a386Sopenharmony_ci#include "src/core/SkScanPriv.h" 23cb93a386Sopenharmony_ci#include "src/core/SkTSort.h" 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci#include <utility> 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci#if defined(SK_DISABLE_AAA) 28cb93a386Sopenharmony_civoid SkScan::AAAFillPath(const SkPath&, SkBlitter*, const SkIRect&, const SkIRect&, bool) { 29cb93a386Sopenharmony_ci SkDEBUGFAIL("AAA Disabled"); 30cb93a386Sopenharmony_ci return; 31cb93a386Sopenharmony_ci} 32cb93a386Sopenharmony_ci#else 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci/* 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ciThe following is a high-level overview of our analytic anti-aliasing 37cb93a386Sopenharmony_cialgorithm. We consider a path as a collection of line segments, as 38cb93a386Sopenharmony_ciquadratic/cubic curves are converted to small line segments. Without loss of 39cb93a386Sopenharmony_cigenerality, let's assume that the draw region is [0, W] x [0, H]. 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ciOur algorithm is based on horizontal scan lines (y = c_i) as the previous 42cb93a386Sopenharmony_cisampling-based algorithm did. However, our algorithm uses non-equal-spaced 43cb93a386Sopenharmony_ciscan lines, while the previous method always uses equal-spaced scan lines, 44cb93a386Sopenharmony_cisuch as (y = 1/2 + 0, 1/2 + 1, 1/2 + 2, ...) in the previous non-AA algorithm, 45cb93a386Sopenharmony_ciand (y = 1/8 + 1/4, 1/8 + 2/4, 1/8 + 3/4, ...) in the previous 46cb93a386Sopenharmony_ci16-supersampling AA algorithm. 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ciOur algorithm contains scan lines y = c_i for c_i that is either: 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci1. an integer between [0, H] 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci2. the y value of a line segment endpoint 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci3. the y value of an intersection of two line segments 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ciFor two consecutive scan lines y = c_i, y = c_{i+1}, we analytically computes 57cb93a386Sopenharmony_cithe coverage of this horizontal strip of our path on each pixel. This can be 58cb93a386Sopenharmony_cidone very efficiently because the strip of our path now only consists of 59cb93a386Sopenharmony_citrapezoids whose top and bottom edges are y = c_i, y = c_{i+1} (this includes 60cb93a386Sopenharmony_cirectangles and triangles as special cases). 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ciWe now describe how the coverage of single pixel is computed against such a 63cb93a386Sopenharmony_citrapezoid. That coverage is essentially the intersection area of a rectangle 64cb93a386Sopenharmony_ci(e.g., [0, 1] x [c_i, c_{i+1}]) and our trapezoid. However, that intersection 65cb93a386Sopenharmony_cicould be complicated, as shown in the example region A below: 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci+-----------\----+ 68cb93a386Sopenharmony_ci| \ C| 69cb93a386Sopenharmony_ci| \ | 70cb93a386Sopenharmony_ci\ \ | 71cb93a386Sopenharmony_ci|\ A \| 72cb93a386Sopenharmony_ci| \ \ 73cb93a386Sopenharmony_ci| \ | 74cb93a386Sopenharmony_ci| B \ | 75cb93a386Sopenharmony_ci+----\-----------+ 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ciHowever, we don't have to compute the area of A directly. Instead, we can 78cb93a386Sopenharmony_cicompute the excluded area, which are B and C, quite easily, because they're 79cb93a386Sopenharmony_cijust triangles. In fact, we can prove that an excluded region (take B as an 80cb93a386Sopenharmony_ciexample) is either itself a simple trapezoid (including rectangles, triangles, 81cb93a386Sopenharmony_ciand empty regions), or its opposite (the opposite of B is A + C) is a simple 82cb93a386Sopenharmony_citrapezoid. In any case, we can compute its area efficiently. 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ciIn summary, our algorithm has a higher quality because it generates ground- 85cb93a386Sopenharmony_citruth coverages analytically. It is also faster because it has much fewer 86cb93a386Sopenharmony_ciunnessasary horizontal scan lines. For example, given a triangle path, the 87cb93a386Sopenharmony_cinumber of scan lines in our algorithm is only about 3 + H while the 88cb93a386Sopenharmony_ci16-supersampling algorithm has about 4H scan lines. 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci*/ 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_cistatic void add_alpha(SkAlpha* alpha, SkAlpha delta) { 93cb93a386Sopenharmony_ci SkASSERT(*alpha + delta <= 256); 94cb93a386Sopenharmony_ci *alpha = SkAlphaRuns::CatchOverflow(*alpha + delta); 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_cistatic void safely_add_alpha(SkAlpha* alpha, SkAlpha delta) { 98cb93a386Sopenharmony_ci *alpha = std::min(0xFF, *alpha + delta); 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ciclass AdditiveBlitter : public SkBlitter { 102cb93a386Sopenharmony_cipublic: 103cb93a386Sopenharmony_ci ~AdditiveBlitter() override {} 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci virtual SkBlitter* getRealBlitter(bool forceRealBlitter = false) = 0; 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci virtual void blitAntiH(int x, int y, const SkAlpha antialias[], int len) = 0; 108cb93a386Sopenharmony_ci virtual void blitAntiH(int x, int y, const SkAlpha alpha) = 0; 109cb93a386Sopenharmony_ci virtual void blitAntiH(int x, int y, int width, const SkAlpha alpha) = 0; 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ci void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override { 112cb93a386Sopenharmony_ci SkDEBUGFAIL("Please call real blitter's blitAntiH instead."); 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci void blitV(int x, int y, int height, SkAlpha alpha) override { 116cb93a386Sopenharmony_ci SkDEBUGFAIL("Please call real blitter's blitV instead."); 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci void blitH(int x, int y, int width) override { 120cb93a386Sopenharmony_ci SkDEBUGFAIL("Please call real blitter's blitH instead."); 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci void blitRect(int x, int y, int width, int height) override { 124cb93a386Sopenharmony_ci SkDEBUGFAIL("Please call real blitter's blitRect instead."); 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) 128cb93a386Sopenharmony_ci override { 129cb93a386Sopenharmony_ci SkDEBUGFAIL("Please call real blitter's blitAntiRect instead."); 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci virtual int getWidth() = 0; 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci // Flush the additive alpha cache if floor(y) and floor(nextY) is different 135cb93a386Sopenharmony_ci // (i.e., we'll start working on a new pixel row). 136cb93a386Sopenharmony_ci virtual void flush_if_y_changed(SkFixed y, SkFixed nextY) = 0; 137cb93a386Sopenharmony_ci}; 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci// We need this mask blitter because it significantly accelerates small path filling. 140cb93a386Sopenharmony_ciclass MaskAdditiveBlitter : public AdditiveBlitter { 141cb93a386Sopenharmony_cipublic: 142cb93a386Sopenharmony_ci MaskAdditiveBlitter(SkBlitter* realBlitter, 143cb93a386Sopenharmony_ci const SkIRect& ir, 144cb93a386Sopenharmony_ci const SkIRect& clipBounds, 145cb93a386Sopenharmony_ci bool isInverse); 146cb93a386Sopenharmony_ci ~MaskAdditiveBlitter() override { fRealBlitter->blitMask(fMask, fClipRect); } 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_ci // Most of the time, we still consider this mask blitter as the real blitter 149cb93a386Sopenharmony_ci // so we can accelerate blitRect and others. But sometimes we want to return 150cb93a386Sopenharmony_ci // the absolute real blitter (e.g., when we fall back to the old code path). 151cb93a386Sopenharmony_ci SkBlitter* getRealBlitter(bool forceRealBlitter) override { 152cb93a386Sopenharmony_ci return forceRealBlitter ? fRealBlitter : this; 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci // Virtual function is slow. So don't use this. Directly add alpha to the mask instead. 156cb93a386Sopenharmony_ci void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci // Allowing following methods are used to blit rectangles during aaa_walk_convex_edges 159cb93a386Sopenharmony_ci // Since there aren't many rectangles, we can still bear the slow speed of virtual functions. 160cb93a386Sopenharmony_ci void blitAntiH(int x, int y, const SkAlpha alpha) override; 161cb93a386Sopenharmony_ci void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; 162cb93a386Sopenharmony_ci void blitV(int x, int y, int height, SkAlpha alpha) override; 163cb93a386Sopenharmony_ci void blitRect(int x, int y, int width, int height) override; 164cb93a386Sopenharmony_ci void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) 165cb93a386Sopenharmony_ci override; 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci // The flush is only needed for RLE (RunBasedAdditiveBlitter) 168cb93a386Sopenharmony_ci void flush_if_y_changed(SkFixed y, SkFixed nextY) override {} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci int getWidth() override { return fClipRect.width(); } 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci static bool CanHandleRect(const SkIRect& bounds) { 173cb93a386Sopenharmony_ci int width = bounds.width(); 174cb93a386Sopenharmony_ci if (width > MaskAdditiveBlitter::kMAX_WIDTH) { 175cb93a386Sopenharmony_ci return false; 176cb93a386Sopenharmony_ci } 177cb93a386Sopenharmony_ci int64_t rb = SkAlign4(width); 178cb93a386Sopenharmony_ci // use 64bits to detect overflow 179cb93a386Sopenharmony_ci int64_t storage = rb * bounds.height(); 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci return (width <= MaskAdditiveBlitter::kMAX_WIDTH) && 182cb93a386Sopenharmony_ci (storage <= MaskAdditiveBlitter::kMAX_STORAGE); 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci // Return a pointer where pointer[x] corresonds to the alpha of (x, y) 186cb93a386Sopenharmony_ci uint8_t* getRow(int y) { 187cb93a386Sopenharmony_ci if (y != fY) { 188cb93a386Sopenharmony_ci fY = y; 189cb93a386Sopenharmony_ci fRow = fMask.fImage + (y - fMask.fBounds.fTop) * fMask.fRowBytes - fMask.fBounds.fLeft; 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci return fRow; 192cb93a386Sopenharmony_ci } 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ciprivate: 195cb93a386Sopenharmony_ci // so we don't try to do very wide things, where the RLE blitter would be faster 196cb93a386Sopenharmony_ci static const int kMAX_WIDTH = 32; 197cb93a386Sopenharmony_ci static const int kMAX_STORAGE = 1024; 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci SkBlitter* fRealBlitter; 200cb93a386Sopenharmony_ci SkMask fMask; 201cb93a386Sopenharmony_ci SkIRect fClipRect; 202cb93a386Sopenharmony_ci // we add 2 because we can write 1 extra byte at either end due to precision error 203cb93a386Sopenharmony_ci uint32_t fStorage[(kMAX_STORAGE >> 2) + 2]; 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci uint8_t* fRow; 206cb93a386Sopenharmony_ci int fY; 207cb93a386Sopenharmony_ci}; 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ciMaskAdditiveBlitter::MaskAdditiveBlitter(SkBlitter* realBlitter, 210cb93a386Sopenharmony_ci const SkIRect& ir, 211cb93a386Sopenharmony_ci const SkIRect& clipBounds, 212cb93a386Sopenharmony_ci bool isInverse) { 213cb93a386Sopenharmony_ci SkASSERT(CanHandleRect(ir)); 214cb93a386Sopenharmony_ci SkASSERT(!isInverse); 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci fRealBlitter = realBlitter; 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci fMask.fImage = (uint8_t*)fStorage + 1; // There's 1 extra byte at either end of fStorage 219cb93a386Sopenharmony_ci fMask.fBounds = ir; 220cb93a386Sopenharmony_ci fMask.fRowBytes = ir.width(); 221cb93a386Sopenharmony_ci fMask.fFormat = SkMask::kA8_Format; 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci fY = ir.fTop - 1; 224cb93a386Sopenharmony_ci fRow = nullptr; 225cb93a386Sopenharmony_ci 226cb93a386Sopenharmony_ci fClipRect = ir; 227cb93a386Sopenharmony_ci if (!fClipRect.intersect(clipBounds)) { 228cb93a386Sopenharmony_ci SkASSERT(0); 229cb93a386Sopenharmony_ci fClipRect.setEmpty(); 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 2); 233cb93a386Sopenharmony_ci} 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_civoid MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { 236cb93a386Sopenharmony_ci SK_ABORT("Don't use this; directly add alphas to the mask."); 237cb93a386Sopenharmony_ci} 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_civoid MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { 240cb93a386Sopenharmony_ci SkASSERT(x >= fMask.fBounds.fLeft - 1); 241cb93a386Sopenharmony_ci add_alpha(&this->getRow(y)[x], alpha); 242cb93a386Sopenharmony_ci} 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_civoid MaskAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { 245cb93a386Sopenharmony_ci SkASSERT(x >= fMask.fBounds.fLeft - 1); 246cb93a386Sopenharmony_ci uint8_t* row = this->getRow(y); 247cb93a386Sopenharmony_ci for (int i = 0; i < width; ++i) { 248cb93a386Sopenharmony_ci add_alpha(&row[x + i], alpha); 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci} 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_civoid MaskAdditiveBlitter::blitV(int x, int y, int height, SkAlpha alpha) { 253cb93a386Sopenharmony_ci if (alpha == 0) { 254cb93a386Sopenharmony_ci return; 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci SkASSERT(x >= fMask.fBounds.fLeft - 1); 257cb93a386Sopenharmony_ci // This must be called as if this is a real blitter. 258cb93a386Sopenharmony_ci // So we directly set alpha rather than adding it. 259cb93a386Sopenharmony_ci uint8_t* row = this->getRow(y); 260cb93a386Sopenharmony_ci for (int i = 0; i < height; ++i) { 261cb93a386Sopenharmony_ci row[x] = alpha; 262cb93a386Sopenharmony_ci row += fMask.fRowBytes; 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci} 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_civoid MaskAdditiveBlitter::blitRect(int x, int y, int width, int height) { 267cb93a386Sopenharmony_ci SkASSERT(x >= fMask.fBounds.fLeft - 1); 268cb93a386Sopenharmony_ci // This must be called as if this is a real blitter. 269cb93a386Sopenharmony_ci // So we directly set alpha rather than adding it. 270cb93a386Sopenharmony_ci uint8_t* row = this->getRow(y); 271cb93a386Sopenharmony_ci for (int i = 0; i < height; ++i) { 272cb93a386Sopenharmony_ci memset(row + x, 0xFF, width); 273cb93a386Sopenharmony_ci row += fMask.fRowBytes; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci} 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_civoid MaskAdditiveBlitter::blitAntiRect(int x, 278cb93a386Sopenharmony_ci int y, 279cb93a386Sopenharmony_ci int width, 280cb93a386Sopenharmony_ci int height, 281cb93a386Sopenharmony_ci SkAlpha leftAlpha, 282cb93a386Sopenharmony_ci SkAlpha rightAlpha) { 283cb93a386Sopenharmony_ci blitV(x, y, height, leftAlpha); 284cb93a386Sopenharmony_ci blitV(x + 1 + width, y, height, rightAlpha); 285cb93a386Sopenharmony_ci blitRect(x + 1, y, width, height); 286cb93a386Sopenharmony_ci} 287cb93a386Sopenharmony_ci 288cb93a386Sopenharmony_ciclass RunBasedAdditiveBlitter : public AdditiveBlitter { 289cb93a386Sopenharmony_cipublic: 290cb93a386Sopenharmony_ci RunBasedAdditiveBlitter(SkBlitter* realBlitter, 291cb93a386Sopenharmony_ci const SkIRect& ir, 292cb93a386Sopenharmony_ci const SkIRect& clipBounds, 293cb93a386Sopenharmony_ci bool isInverse); 294cb93a386Sopenharmony_ci 295cb93a386Sopenharmony_ci ~RunBasedAdditiveBlitter() override { this->flush(); } 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci SkBlitter* getRealBlitter(bool forceRealBlitter) override { return fRealBlitter; } 298cb93a386Sopenharmony_ci 299cb93a386Sopenharmony_ci void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; 300cb93a386Sopenharmony_ci void blitAntiH(int x, int y, const SkAlpha alpha) override; 301cb93a386Sopenharmony_ci void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci int getWidth() override { return fWidth; } 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci void flush_if_y_changed(SkFixed y, SkFixed nextY) override { 306cb93a386Sopenharmony_ci if (SkFixedFloorToInt(y) != SkFixedFloorToInt(nextY)) { 307cb93a386Sopenharmony_ci this->flush(); 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ciprotected: 312cb93a386Sopenharmony_ci SkBlitter* fRealBlitter; 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_ci int fCurrY; // Current y coordinate. 315cb93a386Sopenharmony_ci int fWidth; // Widest row of region to be blitted 316cb93a386Sopenharmony_ci int fLeft; // Leftmost x coordinate in any row 317cb93a386Sopenharmony_ci int fTop; // Initial y coordinate (top of bounds) 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci // The next three variables are used to track a circular buffer that 320cb93a386Sopenharmony_ci // contains the values used in SkAlphaRuns. These variables should only 321cb93a386Sopenharmony_ci // ever be updated in advanceRuns(), and fRuns should always point to 322cb93a386Sopenharmony_ci // a valid SkAlphaRuns... 323cb93a386Sopenharmony_ci int fRunsToBuffer; 324cb93a386Sopenharmony_ci void* fRunsBuffer; 325cb93a386Sopenharmony_ci int fCurrentRun; 326cb93a386Sopenharmony_ci SkAlphaRuns fRuns; 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci int fOffsetX; 329cb93a386Sopenharmony_ci 330cb93a386Sopenharmony_ci bool check(int x, int width) const { return x >= 0 && x + width <= fWidth; } 331cb93a386Sopenharmony_ci 332cb93a386Sopenharmony_ci // extra one to store the zero at the end 333cb93a386Sopenharmony_ci int getRunsSz() const { return (fWidth + 1 + (fWidth + 2) / 2) * sizeof(int16_t); } 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci // This function updates the fRuns variable to point to the next buffer space 336cb93a386Sopenharmony_ci // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun 337cb93a386Sopenharmony_ci // and resets fRuns to point to an empty scanline. 338cb93a386Sopenharmony_ci void advanceRuns() { 339cb93a386Sopenharmony_ci const size_t kRunsSz = this->getRunsSz(); 340cb93a386Sopenharmony_ci fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer; 341cb93a386Sopenharmony_ci fRuns.fRuns = reinterpret_cast<int16_t*>(reinterpret_cast<uint8_t*>(fRunsBuffer) + 342cb93a386Sopenharmony_ci fCurrentRun * kRunsSz); 343cb93a386Sopenharmony_ci fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1); 344cb93a386Sopenharmony_ci fRuns.reset(fWidth); 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci 347cb93a386Sopenharmony_ci // Blitting 0xFF and 0 is much faster so we snap alphas close to them 348cb93a386Sopenharmony_ci SkAlpha snapAlpha(SkAlpha alpha) { return alpha > 247 ? 0xFF : alpha < 8 ? 0x00 : alpha; } 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci void flush() { 351cb93a386Sopenharmony_ci if (fCurrY >= fTop) { 352cb93a386Sopenharmony_ci SkASSERT(fCurrentRun < fRunsToBuffer); 353cb93a386Sopenharmony_ci for (int x = 0; fRuns.fRuns[x]; x += fRuns.fRuns[x]) { 354cb93a386Sopenharmony_ci // It seems that blitting 255 or 0 is much faster than blitting 254 or 1 355cb93a386Sopenharmony_ci fRuns.fAlpha[x] = snapAlpha(fRuns.fAlpha[x]); 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci if (!fRuns.empty()) { 358cb93a386Sopenharmony_ci // SkDEBUGCODE(fRuns.dump();) 359cb93a386Sopenharmony_ci fRealBlitter->blitAntiH(fLeft, fCurrY, fRuns.fAlpha, fRuns.fRuns); 360cb93a386Sopenharmony_ci this->advanceRuns(); 361cb93a386Sopenharmony_ci fOffsetX = 0; 362cb93a386Sopenharmony_ci } 363cb93a386Sopenharmony_ci fCurrY = fTop - 1; 364cb93a386Sopenharmony_ci } 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci void checkY(int y) { 368cb93a386Sopenharmony_ci if (y != fCurrY) { 369cb93a386Sopenharmony_ci this->flush(); 370cb93a386Sopenharmony_ci fCurrY = y; 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci}; 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ciRunBasedAdditiveBlitter::RunBasedAdditiveBlitter(SkBlitter* realBlitter, 376cb93a386Sopenharmony_ci const SkIRect& ir, 377cb93a386Sopenharmony_ci const SkIRect& clipBounds, 378cb93a386Sopenharmony_ci bool isInverse) { 379cb93a386Sopenharmony_ci fRealBlitter = realBlitter; 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_ci SkIRect sectBounds; 382cb93a386Sopenharmony_ci if (isInverse) { 383cb93a386Sopenharmony_ci // We use the clip bounds instead of the ir, since we may be asked to 384cb93a386Sopenharmony_ci // draw outside of the rect when we're a inverse filltype 385cb93a386Sopenharmony_ci sectBounds = clipBounds; 386cb93a386Sopenharmony_ci } else { 387cb93a386Sopenharmony_ci if (!sectBounds.intersect(ir, clipBounds)) { 388cb93a386Sopenharmony_ci sectBounds.setEmpty(); 389cb93a386Sopenharmony_ci } 390cb93a386Sopenharmony_ci } 391cb93a386Sopenharmony_ci 392cb93a386Sopenharmony_ci const int left = sectBounds.left(); 393cb93a386Sopenharmony_ci const int right = sectBounds.right(); 394cb93a386Sopenharmony_ci 395cb93a386Sopenharmony_ci fLeft = left; 396cb93a386Sopenharmony_ci fWidth = right - left; 397cb93a386Sopenharmony_ci fTop = sectBounds.top(); 398cb93a386Sopenharmony_ci fCurrY = fTop - 1; 399cb93a386Sopenharmony_ci 400cb93a386Sopenharmony_ci fRunsToBuffer = realBlitter->requestRowsPreserved(); 401cb93a386Sopenharmony_ci fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz()); 402cb93a386Sopenharmony_ci fCurrentRun = -1; 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci this->advanceRuns(); 405cb93a386Sopenharmony_ci 406cb93a386Sopenharmony_ci fOffsetX = 0; 407cb93a386Sopenharmony_ci} 408cb93a386Sopenharmony_ci 409cb93a386Sopenharmony_civoid RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { 410cb93a386Sopenharmony_ci checkY(y); 411cb93a386Sopenharmony_ci x -= fLeft; 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci if (x < 0) { 414cb93a386Sopenharmony_ci len += x; 415cb93a386Sopenharmony_ci antialias -= x; 416cb93a386Sopenharmony_ci x = 0; 417cb93a386Sopenharmony_ci } 418cb93a386Sopenharmony_ci len = std::min(len, fWidth - x); 419cb93a386Sopenharmony_ci SkASSERT(check(x, len)); 420cb93a386Sopenharmony_ci 421cb93a386Sopenharmony_ci if (x < fOffsetX) { 422cb93a386Sopenharmony_ci fOffsetX = 0; 423cb93a386Sopenharmony_ci } 424cb93a386Sopenharmony_ci 425cb93a386Sopenharmony_ci fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run 426cb93a386Sopenharmony_ci for (int i = 0; i < len; i += fRuns.fRuns[x + i]) { 427cb93a386Sopenharmony_ci for (int j = 1; j < fRuns.fRuns[x + i]; j++) { 428cb93a386Sopenharmony_ci fRuns.fRuns[x + i + j] = 1; 429cb93a386Sopenharmony_ci fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i]; 430cb93a386Sopenharmony_ci } 431cb93a386Sopenharmony_ci fRuns.fRuns[x + i] = 1; 432cb93a386Sopenharmony_ci } 433cb93a386Sopenharmony_ci for (int i = 0; i < len; ++i) { 434cb93a386Sopenharmony_ci add_alpha(&fRuns.fAlpha[x + i], antialias[i]); 435cb93a386Sopenharmony_ci } 436cb93a386Sopenharmony_ci} 437cb93a386Sopenharmony_ci 438cb93a386Sopenharmony_civoid RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { 439cb93a386Sopenharmony_ci checkY(y); 440cb93a386Sopenharmony_ci x -= fLeft; 441cb93a386Sopenharmony_ci 442cb93a386Sopenharmony_ci if (x < fOffsetX) { 443cb93a386Sopenharmony_ci fOffsetX = 0; 444cb93a386Sopenharmony_ci } 445cb93a386Sopenharmony_ci 446cb93a386Sopenharmony_ci if (this->check(x, 1)) { 447cb93a386Sopenharmony_ci fOffsetX = fRuns.add(x, 0, 1, 0, alpha, fOffsetX); 448cb93a386Sopenharmony_ci } 449cb93a386Sopenharmony_ci} 450cb93a386Sopenharmony_ci 451cb93a386Sopenharmony_civoid RunBasedAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { 452cb93a386Sopenharmony_ci checkY(y); 453cb93a386Sopenharmony_ci x -= fLeft; 454cb93a386Sopenharmony_ci 455cb93a386Sopenharmony_ci if (x < fOffsetX) { 456cb93a386Sopenharmony_ci fOffsetX = 0; 457cb93a386Sopenharmony_ci } 458cb93a386Sopenharmony_ci 459cb93a386Sopenharmony_ci if (this->check(x, width)) { 460cb93a386Sopenharmony_ci fOffsetX = fRuns.add(x, 0, width, 0, alpha, fOffsetX); 461cb93a386Sopenharmony_ci } 462cb93a386Sopenharmony_ci} 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_ci// This exists specifically for concave path filling. 465cb93a386Sopenharmony_ci// In those cases, we can easily accumulate alpha greater than 0xFF. 466cb93a386Sopenharmony_ciclass SafeRLEAdditiveBlitter : public RunBasedAdditiveBlitter { 467cb93a386Sopenharmony_cipublic: 468cb93a386Sopenharmony_ci SafeRLEAdditiveBlitter(SkBlitter* realBlitter, 469cb93a386Sopenharmony_ci const SkIRect& ir, 470cb93a386Sopenharmony_ci const SkIRect& clipBounds, 471cb93a386Sopenharmony_ci bool isInverse) 472cb93a386Sopenharmony_ci : RunBasedAdditiveBlitter(realBlitter, ir, clipBounds, isInverse) {} 473cb93a386Sopenharmony_ci 474cb93a386Sopenharmony_ci void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; 475cb93a386Sopenharmony_ci void blitAntiH(int x, int y, const SkAlpha alpha) override; 476cb93a386Sopenharmony_ci void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; 477cb93a386Sopenharmony_ci}; 478cb93a386Sopenharmony_ci 479cb93a386Sopenharmony_civoid SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { 480cb93a386Sopenharmony_ci checkY(y); 481cb93a386Sopenharmony_ci x -= fLeft; 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci if (x < 0) { 484cb93a386Sopenharmony_ci len += x; 485cb93a386Sopenharmony_ci antialias -= x; 486cb93a386Sopenharmony_ci x = 0; 487cb93a386Sopenharmony_ci } 488cb93a386Sopenharmony_ci len = std::min(len, fWidth - x); 489cb93a386Sopenharmony_ci SkASSERT(check(x, len)); 490cb93a386Sopenharmony_ci 491cb93a386Sopenharmony_ci if (x < fOffsetX) { 492cb93a386Sopenharmony_ci fOffsetX = 0; 493cb93a386Sopenharmony_ci } 494cb93a386Sopenharmony_ci 495cb93a386Sopenharmony_ci fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run 496cb93a386Sopenharmony_ci for (int i = 0; i < len; i += fRuns.fRuns[x + i]) { 497cb93a386Sopenharmony_ci for (int j = 1; j < fRuns.fRuns[x + i]; j++) { 498cb93a386Sopenharmony_ci fRuns.fRuns[x + i + j] = 1; 499cb93a386Sopenharmony_ci fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i]; 500cb93a386Sopenharmony_ci } 501cb93a386Sopenharmony_ci fRuns.fRuns[x + i] = 1; 502cb93a386Sopenharmony_ci } 503cb93a386Sopenharmony_ci for (int i = 0; i < len; ++i) { 504cb93a386Sopenharmony_ci safely_add_alpha(&fRuns.fAlpha[x + i], antialias[i]); 505cb93a386Sopenharmony_ci } 506cb93a386Sopenharmony_ci} 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_civoid SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { 509cb93a386Sopenharmony_ci checkY(y); 510cb93a386Sopenharmony_ci x -= fLeft; 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_ci if (x < fOffsetX) { 513cb93a386Sopenharmony_ci fOffsetX = 0; 514cb93a386Sopenharmony_ci } 515cb93a386Sopenharmony_ci 516cb93a386Sopenharmony_ci if (check(x, 1)) { 517cb93a386Sopenharmony_ci // Break the run 518cb93a386Sopenharmony_ci fOffsetX = fRuns.add(x, 0, 1, 0, 0, fOffsetX); 519cb93a386Sopenharmony_ci safely_add_alpha(&fRuns.fAlpha[x], alpha); 520cb93a386Sopenharmony_ci } 521cb93a386Sopenharmony_ci} 522cb93a386Sopenharmony_ci 523cb93a386Sopenharmony_civoid SafeRLEAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { 524cb93a386Sopenharmony_ci checkY(y); 525cb93a386Sopenharmony_ci x -= fLeft; 526cb93a386Sopenharmony_ci 527cb93a386Sopenharmony_ci if (x < fOffsetX) { 528cb93a386Sopenharmony_ci fOffsetX = 0; 529cb93a386Sopenharmony_ci } 530cb93a386Sopenharmony_ci 531cb93a386Sopenharmony_ci if (check(x, width)) { 532cb93a386Sopenharmony_ci // Break the run 533cb93a386Sopenharmony_ci fOffsetX = fRuns.add(x, 0, width, 0, 0, fOffsetX); 534cb93a386Sopenharmony_ci for (int i = x; i < x + width; i += fRuns.fRuns[i]) { 535cb93a386Sopenharmony_ci safely_add_alpha(&fRuns.fAlpha[i], alpha); 536cb93a386Sopenharmony_ci } 537cb93a386Sopenharmony_ci } 538cb93a386Sopenharmony_ci} 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ci// Return the alpha of a trapezoid whose height is 1 541cb93a386Sopenharmony_cistatic SkAlpha trapezoid_to_alpha(SkFixed l1, SkFixed l2) { 542cb93a386Sopenharmony_ci SkASSERT(l1 >= 0 && l2 >= 0); 543cb93a386Sopenharmony_ci SkFixed area = (l1 + l2) / 2; 544cb93a386Sopenharmony_ci return SkTo<SkAlpha>(area >> 8); 545cb93a386Sopenharmony_ci} 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci// The alpha of right-triangle (a, a*b) 548cb93a386Sopenharmony_cistatic SkAlpha partial_triangle_to_alpha(SkFixed a, SkFixed b) { 549cb93a386Sopenharmony_ci SkASSERT(a <= SK_Fixed1); 550cb93a386Sopenharmony_ci#if 0 551cb93a386Sopenharmony_ci // TODO(mtklein): skia:8877 552cb93a386Sopenharmony_ci SkASSERT(b <= SK_Fixed1); 553cb93a386Sopenharmony_ci#endif 554cb93a386Sopenharmony_ci 555cb93a386Sopenharmony_ci // Approximating... 556cb93a386Sopenharmony_ci // SkFixed area = SkFixedMul(a, SkFixedMul(a,b)) / 2; 557cb93a386Sopenharmony_ci SkFixed area = (a >> 11) * (a >> 11) * (b >> 11); 558cb93a386Sopenharmony_ci 559cb93a386Sopenharmony_ci#if 0 560cb93a386Sopenharmony_ci // TODO(mtklein): skia:8877 561cb93a386Sopenharmony_ci return SkTo<SkAlpha>(area >> 8); 562cb93a386Sopenharmony_ci#else 563cb93a386Sopenharmony_ci return SkTo<SkAlpha>((area >> 8) & 0xFF); 564cb93a386Sopenharmony_ci#endif 565cb93a386Sopenharmony_ci} 566cb93a386Sopenharmony_ci 567cb93a386Sopenharmony_cistatic SkAlpha get_partial_alpha(SkAlpha alpha, SkFixed partialHeight) { 568cb93a386Sopenharmony_ci return SkToU8(SkFixedRoundToInt(alpha * partialHeight)); 569cb93a386Sopenharmony_ci} 570cb93a386Sopenharmony_ci 571cb93a386Sopenharmony_cistatic SkAlpha get_partial_alpha(SkAlpha alpha, SkAlpha fullAlpha) { 572cb93a386Sopenharmony_ci return (alpha * fullAlpha) >> 8; 573cb93a386Sopenharmony_ci} 574cb93a386Sopenharmony_ci 575cb93a386Sopenharmony_ci// For SkFixed that's close to SK_Fixed1, we can't convert it to alpha by just shifting right. 576cb93a386Sopenharmony_ci// For example, when f = SK_Fixed1, right shifting 8 will get 256, but we need 255. 577cb93a386Sopenharmony_ci// This is rarely the problem so we'll only use this for blitting rectangles. 578cb93a386Sopenharmony_cistatic SkAlpha fixed_to_alpha(SkFixed f) { 579cb93a386Sopenharmony_ci SkASSERT(f <= SK_Fixed1); 580cb93a386Sopenharmony_ci return get_partial_alpha(0xFF, f); 581cb93a386Sopenharmony_ci} 582cb93a386Sopenharmony_ci 583cb93a386Sopenharmony_ci// Suppose that line (l1, y)-(r1, y+1) intersects with (l2, y)-(r2, y+1), 584cb93a386Sopenharmony_ci// approximate (very coarsely) the x coordinate of the intersection. 585cb93a386Sopenharmony_cistatic SkFixed approximate_intersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFixed r2) { 586cb93a386Sopenharmony_ci if (l1 > r1) { 587cb93a386Sopenharmony_ci std::swap(l1, r1); 588cb93a386Sopenharmony_ci } 589cb93a386Sopenharmony_ci if (l2 > r2) { 590cb93a386Sopenharmony_ci std::swap(l2, r2); 591cb93a386Sopenharmony_ci } 592cb93a386Sopenharmony_ci return (std::max(l1, l2) + std::min(r1, r2)) / 2; 593cb93a386Sopenharmony_ci} 594cb93a386Sopenharmony_ci 595cb93a386Sopenharmony_ci// Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0] 596cb93a386Sopenharmony_cistatic void compute_alpha_above_line(SkAlpha* alphas, 597cb93a386Sopenharmony_ci SkFixed l, 598cb93a386Sopenharmony_ci SkFixed r, 599cb93a386Sopenharmony_ci SkFixed dY, 600cb93a386Sopenharmony_ci SkAlpha fullAlpha) { 601cb93a386Sopenharmony_ci SkASSERT(l <= r); 602cb93a386Sopenharmony_ci SkASSERT(l >> 16 == 0); 603cb93a386Sopenharmony_ci int R = SkFixedCeilToInt(r); 604cb93a386Sopenharmony_ci if (R == 0) { 605cb93a386Sopenharmony_ci return; 606cb93a386Sopenharmony_ci } else if (R == 1) { 607cb93a386Sopenharmony_ci alphas[0] = get_partial_alpha(((R << 17) - l - r) >> 9, fullAlpha); 608cb93a386Sopenharmony_ci } else { 609cb93a386Sopenharmony_ci SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle 610cb93a386Sopenharmony_ci SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle 611cb93a386Sopenharmony_ci SkFixed firstH = SkFixedMul(first, dY); // vertical edge of the left-most triangle 612cb93a386Sopenharmony_ci alphas[0] = SkFixedMul(first, firstH) >> 9; // triangle alpha 613cb93a386Sopenharmony_ci SkFixed alpha16 = firstH + (dY >> 1); // rectangle plus triangle 614cb93a386Sopenharmony_ci for (int i = 1; i < R - 1; ++i) { 615cb93a386Sopenharmony_ci alphas[i] = alpha16 >> 8; 616cb93a386Sopenharmony_ci alpha16 += dY; 617cb93a386Sopenharmony_ci } 618cb93a386Sopenharmony_ci alphas[R - 1] = fullAlpha - partial_triangle_to_alpha(last, dY); 619cb93a386Sopenharmony_ci } 620cb93a386Sopenharmony_ci} 621cb93a386Sopenharmony_ci 622cb93a386Sopenharmony_ci// Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0] 623cb93a386Sopenharmony_cistatic void compute_alpha_below_line(SkAlpha* alphas, 624cb93a386Sopenharmony_ci SkFixed l, 625cb93a386Sopenharmony_ci SkFixed r, 626cb93a386Sopenharmony_ci SkFixed dY, 627cb93a386Sopenharmony_ci SkAlpha fullAlpha) { 628cb93a386Sopenharmony_ci SkASSERT(l <= r); 629cb93a386Sopenharmony_ci SkASSERT(l >> 16 == 0); 630cb93a386Sopenharmony_ci int R = SkFixedCeilToInt(r); 631cb93a386Sopenharmony_ci if (R == 0) { 632cb93a386Sopenharmony_ci return; 633cb93a386Sopenharmony_ci } else if (R == 1) { 634cb93a386Sopenharmony_ci alphas[0] = get_partial_alpha(trapezoid_to_alpha(l, r), fullAlpha); 635cb93a386Sopenharmony_ci } else { 636cb93a386Sopenharmony_ci SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle 637cb93a386Sopenharmony_ci SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle 638cb93a386Sopenharmony_ci SkFixed lastH = SkFixedMul(last, dY); // vertical edge of the right-most triangle 639cb93a386Sopenharmony_ci alphas[R - 1] = SkFixedMul(last, lastH) >> 9; // triangle alpha 640cb93a386Sopenharmony_ci SkFixed alpha16 = lastH + (dY >> 1); // rectangle plus triangle 641cb93a386Sopenharmony_ci for (int i = R - 2; i > 0; i--) { 642cb93a386Sopenharmony_ci alphas[i] = (alpha16 >> 8) & 0xFF; 643cb93a386Sopenharmony_ci alpha16 += dY; 644cb93a386Sopenharmony_ci } 645cb93a386Sopenharmony_ci alphas[0] = fullAlpha - partial_triangle_to_alpha(first, dY); 646cb93a386Sopenharmony_ci } 647cb93a386Sopenharmony_ci} 648cb93a386Sopenharmony_ci 649cb93a386Sopenharmony_ci// Note that if fullAlpha != 0xFF, we'll multiply alpha by fullAlpha 650cb93a386Sopenharmony_cistatic SK_ALWAYS_INLINE void blit_single_alpha(AdditiveBlitter* blitter, 651cb93a386Sopenharmony_ci int y, 652cb93a386Sopenharmony_ci int x, 653cb93a386Sopenharmony_ci SkAlpha alpha, 654cb93a386Sopenharmony_ci SkAlpha fullAlpha, 655cb93a386Sopenharmony_ci SkAlpha* maskRow, 656cb93a386Sopenharmony_ci bool isUsingMask, 657cb93a386Sopenharmony_ci bool noRealBlitter, 658cb93a386Sopenharmony_ci bool needSafeCheck) { 659cb93a386Sopenharmony_ci if (isUsingMask) { 660cb93a386Sopenharmony_ci if (fullAlpha == 0xFF && !noRealBlitter) { // noRealBlitter is needed for concave paths 661cb93a386Sopenharmony_ci maskRow[x] = alpha; 662cb93a386Sopenharmony_ci } else if (needSafeCheck) { 663cb93a386Sopenharmony_ci safely_add_alpha(&maskRow[x], get_partial_alpha(alpha, fullAlpha)); 664cb93a386Sopenharmony_ci } else { 665cb93a386Sopenharmony_ci add_alpha(&maskRow[x], get_partial_alpha(alpha, fullAlpha)); 666cb93a386Sopenharmony_ci } 667cb93a386Sopenharmony_ci } else { 668cb93a386Sopenharmony_ci if (fullAlpha == 0xFF && !noRealBlitter) { 669cb93a386Sopenharmony_ci blitter->getRealBlitter()->blitV(x, y, 1, alpha); 670cb93a386Sopenharmony_ci } else { 671cb93a386Sopenharmony_ci blitter->blitAntiH(x, y, get_partial_alpha(alpha, fullAlpha)); 672cb93a386Sopenharmony_ci } 673cb93a386Sopenharmony_ci } 674cb93a386Sopenharmony_ci} 675cb93a386Sopenharmony_ci 676cb93a386Sopenharmony_cistatic SK_ALWAYS_INLINE void blit_two_alphas(AdditiveBlitter* blitter, 677cb93a386Sopenharmony_ci int y, 678cb93a386Sopenharmony_ci int x, 679cb93a386Sopenharmony_ci SkAlpha a1, 680cb93a386Sopenharmony_ci SkAlpha a2, 681cb93a386Sopenharmony_ci SkAlpha fullAlpha, 682cb93a386Sopenharmony_ci SkAlpha* maskRow, 683cb93a386Sopenharmony_ci bool isUsingMask, 684cb93a386Sopenharmony_ci bool noRealBlitter, 685cb93a386Sopenharmony_ci bool needSafeCheck) { 686cb93a386Sopenharmony_ci if (isUsingMask) { 687cb93a386Sopenharmony_ci if (needSafeCheck) { 688cb93a386Sopenharmony_ci safely_add_alpha(&maskRow[x], a1); 689cb93a386Sopenharmony_ci safely_add_alpha(&maskRow[x + 1], a2); 690cb93a386Sopenharmony_ci } else { 691cb93a386Sopenharmony_ci add_alpha(&maskRow[x], a1); 692cb93a386Sopenharmony_ci add_alpha(&maskRow[x + 1], a2); 693cb93a386Sopenharmony_ci } 694cb93a386Sopenharmony_ci } else { 695cb93a386Sopenharmony_ci if (fullAlpha == 0xFF && !noRealBlitter) { 696cb93a386Sopenharmony_ci blitter->getRealBlitter()->blitAntiH2(x, y, a1, a2); 697cb93a386Sopenharmony_ci } else { 698cb93a386Sopenharmony_ci blitter->blitAntiH(x, y, a1); 699cb93a386Sopenharmony_ci blitter->blitAntiH(x + 1, y, a2); 700cb93a386Sopenharmony_ci } 701cb93a386Sopenharmony_ci } 702cb93a386Sopenharmony_ci} 703cb93a386Sopenharmony_ci 704cb93a386Sopenharmony_cistatic SK_ALWAYS_INLINE void blit_full_alpha(AdditiveBlitter* blitter, 705cb93a386Sopenharmony_ci int y, 706cb93a386Sopenharmony_ci int x, 707cb93a386Sopenharmony_ci int len, 708cb93a386Sopenharmony_ci SkAlpha fullAlpha, 709cb93a386Sopenharmony_ci SkAlpha* maskRow, 710cb93a386Sopenharmony_ci bool isUsingMask, 711cb93a386Sopenharmony_ci bool noRealBlitter, 712cb93a386Sopenharmony_ci bool needSafeCheck) { 713cb93a386Sopenharmony_ci if (isUsingMask) { 714cb93a386Sopenharmony_ci for (int i = 0; i < len; ++i) { 715cb93a386Sopenharmony_ci if (needSafeCheck) { 716cb93a386Sopenharmony_ci safely_add_alpha(&maskRow[x + i], fullAlpha); 717cb93a386Sopenharmony_ci } else { 718cb93a386Sopenharmony_ci add_alpha(&maskRow[x + i], fullAlpha); 719cb93a386Sopenharmony_ci } 720cb93a386Sopenharmony_ci } 721cb93a386Sopenharmony_ci } else { 722cb93a386Sopenharmony_ci if (fullAlpha == 0xFF && !noRealBlitter) { 723cb93a386Sopenharmony_ci blitter->getRealBlitter()->blitH(x, y, len); 724cb93a386Sopenharmony_ci } else { 725cb93a386Sopenharmony_ci blitter->blitAntiH(x, y, len, fullAlpha); 726cb93a386Sopenharmony_ci } 727cb93a386Sopenharmony_ci } 728cb93a386Sopenharmony_ci} 729cb93a386Sopenharmony_ci 730cb93a386Sopenharmony_cistatic void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, 731cb93a386Sopenharmony_ci int y, 732cb93a386Sopenharmony_ci SkFixed ul, 733cb93a386Sopenharmony_ci SkFixed ur, 734cb93a386Sopenharmony_ci SkFixed ll, 735cb93a386Sopenharmony_ci SkFixed lr, 736cb93a386Sopenharmony_ci SkFixed lDY, 737cb93a386Sopenharmony_ci SkFixed rDY, 738cb93a386Sopenharmony_ci SkAlpha fullAlpha, 739cb93a386Sopenharmony_ci SkAlpha* maskRow, 740cb93a386Sopenharmony_ci bool isUsingMask, 741cb93a386Sopenharmony_ci bool noRealBlitter, 742cb93a386Sopenharmony_ci bool needSafeCheck) { 743cb93a386Sopenharmony_ci int L = SkFixedFloorToInt(ul), R = SkFixedCeilToInt(lr); 744cb93a386Sopenharmony_ci int len = R - L; 745cb93a386Sopenharmony_ci 746cb93a386Sopenharmony_ci if (len == 1) { 747cb93a386Sopenharmony_ci SkAlpha alpha = trapezoid_to_alpha(ur - ul, lr - ll); 748cb93a386Sopenharmony_ci blit_single_alpha(blitter, 749cb93a386Sopenharmony_ci y, 750cb93a386Sopenharmony_ci L, 751cb93a386Sopenharmony_ci alpha, 752cb93a386Sopenharmony_ci fullAlpha, 753cb93a386Sopenharmony_ci maskRow, 754cb93a386Sopenharmony_ci isUsingMask, 755cb93a386Sopenharmony_ci noRealBlitter, 756cb93a386Sopenharmony_ci needSafeCheck); 757cb93a386Sopenharmony_ci return; 758cb93a386Sopenharmony_ci } 759cb93a386Sopenharmony_ci 760cb93a386Sopenharmony_ci const int kQuickLen = 31; 761cb93a386Sopenharmony_ci char quickMemory[(sizeof(SkAlpha) * 2 + sizeof(int16_t)) * (kQuickLen + 1)]; 762cb93a386Sopenharmony_ci SkAlpha* alphas; 763cb93a386Sopenharmony_ci 764cb93a386Sopenharmony_ci if (len <= kQuickLen) { 765cb93a386Sopenharmony_ci alphas = (SkAlpha*)quickMemory; 766cb93a386Sopenharmony_ci } else { 767cb93a386Sopenharmony_ci alphas = new SkAlpha[(len + 1) * (sizeof(SkAlpha) * 2 + sizeof(int16_t))]; 768cb93a386Sopenharmony_ci } 769cb93a386Sopenharmony_ci 770cb93a386Sopenharmony_ci SkAlpha* tempAlphas = alphas + len + 1; 771cb93a386Sopenharmony_ci int16_t* runs = (int16_t*)(alphas + (len + 1) * 2); 772cb93a386Sopenharmony_ci 773cb93a386Sopenharmony_ci for (int i = 0; i < len; ++i) { 774cb93a386Sopenharmony_ci runs[i] = 1; 775cb93a386Sopenharmony_ci alphas[i] = fullAlpha; 776cb93a386Sopenharmony_ci } 777cb93a386Sopenharmony_ci runs[len] = 0; 778cb93a386Sopenharmony_ci 779cb93a386Sopenharmony_ci int uL = SkFixedFloorToInt(ul); 780cb93a386Sopenharmony_ci int lL = SkFixedCeilToInt(ll); 781cb93a386Sopenharmony_ci if (uL + 2 == lL) { // We only need to compute two triangles, accelerate this special case 782cb93a386Sopenharmony_ci SkFixed first = SkIntToFixed(uL) + SK_Fixed1 - ul; 783cb93a386Sopenharmony_ci SkFixed second = ll - ul - first; 784cb93a386Sopenharmony_ci SkAlpha a1 = fullAlpha - partial_triangle_to_alpha(first, lDY); 785cb93a386Sopenharmony_ci SkAlpha a2 = partial_triangle_to_alpha(second, lDY); 786cb93a386Sopenharmony_ci alphas[0] = alphas[0] > a1 ? alphas[0] - a1 : 0; 787cb93a386Sopenharmony_ci alphas[1] = alphas[1] > a2 ? alphas[1] - a2 : 0; 788cb93a386Sopenharmony_ci } else { 789cb93a386Sopenharmony_ci compute_alpha_below_line( 790cb93a386Sopenharmony_ci tempAlphas + uL - L, ul - SkIntToFixed(uL), ll - SkIntToFixed(uL), lDY, fullAlpha); 791cb93a386Sopenharmony_ci for (int i = uL; i < lL; ++i) { 792cb93a386Sopenharmony_ci if (alphas[i - L] > tempAlphas[i - L]) { 793cb93a386Sopenharmony_ci alphas[i - L] -= tempAlphas[i - L]; 794cb93a386Sopenharmony_ci } else { 795cb93a386Sopenharmony_ci alphas[i - L] = 0; 796cb93a386Sopenharmony_ci } 797cb93a386Sopenharmony_ci } 798cb93a386Sopenharmony_ci } 799cb93a386Sopenharmony_ci 800cb93a386Sopenharmony_ci int uR = SkFixedFloorToInt(ur); 801cb93a386Sopenharmony_ci int lR = SkFixedCeilToInt(lr); 802cb93a386Sopenharmony_ci if (uR + 2 == lR) { // We only need to compute two triangles, accelerate this special case 803cb93a386Sopenharmony_ci SkFixed first = SkIntToFixed(uR) + SK_Fixed1 - ur; 804cb93a386Sopenharmony_ci SkFixed second = lr - ur - first; 805cb93a386Sopenharmony_ci SkAlpha a1 = partial_triangle_to_alpha(first, rDY); 806cb93a386Sopenharmony_ci SkAlpha a2 = fullAlpha - partial_triangle_to_alpha(second, rDY); 807cb93a386Sopenharmony_ci alphas[len - 2] = alphas[len - 2] > a1 ? alphas[len - 2] - a1 : 0; 808cb93a386Sopenharmony_ci alphas[len - 1] = alphas[len - 1] > a2 ? alphas[len - 1] - a2 : 0; 809cb93a386Sopenharmony_ci } else { 810cb93a386Sopenharmony_ci compute_alpha_above_line( 811cb93a386Sopenharmony_ci tempAlphas + uR - L, ur - SkIntToFixed(uR), lr - SkIntToFixed(uR), rDY, fullAlpha); 812cb93a386Sopenharmony_ci for (int i = uR; i < lR; ++i) { 813cb93a386Sopenharmony_ci if (alphas[i - L] > tempAlphas[i - L]) { 814cb93a386Sopenharmony_ci alphas[i - L] -= tempAlphas[i - L]; 815cb93a386Sopenharmony_ci } else { 816cb93a386Sopenharmony_ci alphas[i - L] = 0; 817cb93a386Sopenharmony_ci } 818cb93a386Sopenharmony_ci } 819cb93a386Sopenharmony_ci } 820cb93a386Sopenharmony_ci 821cb93a386Sopenharmony_ci if (isUsingMask) { 822cb93a386Sopenharmony_ci for (int i = 0; i < len; ++i) { 823cb93a386Sopenharmony_ci if (needSafeCheck) { 824cb93a386Sopenharmony_ci safely_add_alpha(&maskRow[L + i], alphas[i]); 825cb93a386Sopenharmony_ci } else { 826cb93a386Sopenharmony_ci add_alpha(&maskRow[L + i], alphas[i]); 827cb93a386Sopenharmony_ci } 828cb93a386Sopenharmony_ci } 829cb93a386Sopenharmony_ci } else { 830cb93a386Sopenharmony_ci if (fullAlpha == 0xFF && !noRealBlitter) { 831cb93a386Sopenharmony_ci // Real blitter is faster than RunBasedAdditiveBlitter 832cb93a386Sopenharmony_ci blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs); 833cb93a386Sopenharmony_ci } else { 834cb93a386Sopenharmony_ci blitter->blitAntiH(L, y, alphas, len); 835cb93a386Sopenharmony_ci } 836cb93a386Sopenharmony_ci } 837cb93a386Sopenharmony_ci 838cb93a386Sopenharmony_ci if (len > kQuickLen) { 839cb93a386Sopenharmony_ci delete[] alphas; 840cb93a386Sopenharmony_ci } 841cb93a386Sopenharmony_ci} 842cb93a386Sopenharmony_ci 843cb93a386Sopenharmony_cistatic SK_ALWAYS_INLINE void blit_trapezoid_row(AdditiveBlitter* blitter, 844cb93a386Sopenharmony_ci int y, 845cb93a386Sopenharmony_ci SkFixed ul, 846cb93a386Sopenharmony_ci SkFixed ur, 847cb93a386Sopenharmony_ci SkFixed ll, 848cb93a386Sopenharmony_ci SkFixed lr, 849cb93a386Sopenharmony_ci SkFixed lDY, 850cb93a386Sopenharmony_ci SkFixed rDY, 851cb93a386Sopenharmony_ci SkAlpha fullAlpha, 852cb93a386Sopenharmony_ci SkAlpha* maskRow, 853cb93a386Sopenharmony_ci bool isUsingMask, 854cb93a386Sopenharmony_ci bool noRealBlitter = false, 855cb93a386Sopenharmony_ci bool needSafeCheck = false) { 856cb93a386Sopenharmony_ci SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value 857cb93a386Sopenharmony_ci 858cb93a386Sopenharmony_ci if (ul > ur) { 859cb93a386Sopenharmony_ci return; 860cb93a386Sopenharmony_ci } 861cb93a386Sopenharmony_ci 862cb93a386Sopenharmony_ci // Edge crosses. Approximate it. This should only happend due to precision limit, 863cb93a386Sopenharmony_ci // so the approximation could be very coarse. 864cb93a386Sopenharmony_ci if (ll > lr) { 865cb93a386Sopenharmony_ci ll = lr = approximate_intersection(ul, ll, ur, lr); 866cb93a386Sopenharmony_ci } 867cb93a386Sopenharmony_ci 868cb93a386Sopenharmony_ci if (ul == ur && ll == lr) { 869cb93a386Sopenharmony_ci return; // empty trapzoid 870cb93a386Sopenharmony_ci } 871cb93a386Sopenharmony_ci 872cb93a386Sopenharmony_ci // We're going to use the left line ul-ll and the rite line ur-lr 873cb93a386Sopenharmony_ci // to exclude the area that's not covered by the path. 874cb93a386Sopenharmony_ci // Swapping (ul, ll) or (ur, lr) won't affect that exclusion 875cb93a386Sopenharmony_ci // so we'll do that for simplicity. 876cb93a386Sopenharmony_ci if (ul > ll) { 877cb93a386Sopenharmony_ci std::swap(ul, ll); 878cb93a386Sopenharmony_ci } 879cb93a386Sopenharmony_ci if (ur > lr) { 880cb93a386Sopenharmony_ci std::swap(ur, lr); 881cb93a386Sopenharmony_ci } 882cb93a386Sopenharmony_ci 883cb93a386Sopenharmony_ci SkFixed joinLeft = SkFixedCeilToFixed(ll); 884cb93a386Sopenharmony_ci SkFixed joinRite = SkFixedFloorToFixed(ur); 885cb93a386Sopenharmony_ci if (joinLeft <= joinRite) { // There's a rect from joinLeft to joinRite that we can blit 886cb93a386Sopenharmony_ci if (ul < joinLeft) { 887cb93a386Sopenharmony_ci int len = SkFixedCeilToInt(joinLeft - ul); 888cb93a386Sopenharmony_ci if (len == 1) { 889cb93a386Sopenharmony_ci SkAlpha alpha = trapezoid_to_alpha(joinLeft - ul, joinLeft - ll); 890cb93a386Sopenharmony_ci blit_single_alpha(blitter, 891cb93a386Sopenharmony_ci y, 892cb93a386Sopenharmony_ci ul >> 16, 893cb93a386Sopenharmony_ci alpha, 894cb93a386Sopenharmony_ci fullAlpha, 895cb93a386Sopenharmony_ci maskRow, 896cb93a386Sopenharmony_ci isUsingMask, 897cb93a386Sopenharmony_ci noRealBlitter, 898cb93a386Sopenharmony_ci needSafeCheck); 899cb93a386Sopenharmony_ci } else if (len == 2) { 900cb93a386Sopenharmony_ci SkFixed first = joinLeft - SK_Fixed1 - ul; 901cb93a386Sopenharmony_ci SkFixed second = ll - ul - first; 902cb93a386Sopenharmony_ci SkAlpha a1 = partial_triangle_to_alpha(first, lDY); 903cb93a386Sopenharmony_ci SkAlpha a2 = fullAlpha - partial_triangle_to_alpha(second, lDY); 904cb93a386Sopenharmony_ci blit_two_alphas(blitter, 905cb93a386Sopenharmony_ci y, 906cb93a386Sopenharmony_ci ul >> 16, 907cb93a386Sopenharmony_ci a1, 908cb93a386Sopenharmony_ci a2, 909cb93a386Sopenharmony_ci fullAlpha, 910cb93a386Sopenharmony_ci maskRow, 911cb93a386Sopenharmony_ci isUsingMask, 912cb93a386Sopenharmony_ci noRealBlitter, 913cb93a386Sopenharmony_ci needSafeCheck); 914cb93a386Sopenharmony_ci } else { 915cb93a386Sopenharmony_ci blit_aaa_trapezoid_row(blitter, 916cb93a386Sopenharmony_ci y, 917cb93a386Sopenharmony_ci ul, 918cb93a386Sopenharmony_ci joinLeft, 919cb93a386Sopenharmony_ci ll, 920cb93a386Sopenharmony_ci joinLeft, 921cb93a386Sopenharmony_ci lDY, 922cb93a386Sopenharmony_ci SK_MaxS32, 923cb93a386Sopenharmony_ci fullAlpha, 924cb93a386Sopenharmony_ci maskRow, 925cb93a386Sopenharmony_ci isUsingMask, 926cb93a386Sopenharmony_ci noRealBlitter, 927cb93a386Sopenharmony_ci needSafeCheck); 928cb93a386Sopenharmony_ci } 929cb93a386Sopenharmony_ci } 930cb93a386Sopenharmony_ci // SkAAClip requires that we blit from left to right. 931cb93a386Sopenharmony_ci // Hence we must blit [ul, joinLeft] before blitting [joinLeft, joinRite] 932cb93a386Sopenharmony_ci if (joinLeft < joinRite) { 933cb93a386Sopenharmony_ci blit_full_alpha(blitter, 934cb93a386Sopenharmony_ci y, 935cb93a386Sopenharmony_ci SkFixedFloorToInt(joinLeft), 936cb93a386Sopenharmony_ci SkFixedFloorToInt(joinRite - joinLeft), 937cb93a386Sopenharmony_ci fullAlpha, 938cb93a386Sopenharmony_ci maskRow, 939cb93a386Sopenharmony_ci isUsingMask, 940cb93a386Sopenharmony_ci noRealBlitter, 941cb93a386Sopenharmony_ci needSafeCheck); 942cb93a386Sopenharmony_ci } 943cb93a386Sopenharmony_ci if (lr > joinRite) { 944cb93a386Sopenharmony_ci int len = SkFixedCeilToInt(lr - joinRite); 945cb93a386Sopenharmony_ci if (len == 1) { 946cb93a386Sopenharmony_ci SkAlpha alpha = trapezoid_to_alpha(ur - joinRite, lr - joinRite); 947cb93a386Sopenharmony_ci blit_single_alpha(blitter, 948cb93a386Sopenharmony_ci y, 949cb93a386Sopenharmony_ci joinRite >> 16, 950cb93a386Sopenharmony_ci alpha, 951cb93a386Sopenharmony_ci fullAlpha, 952cb93a386Sopenharmony_ci maskRow, 953cb93a386Sopenharmony_ci isUsingMask, 954cb93a386Sopenharmony_ci noRealBlitter, 955cb93a386Sopenharmony_ci needSafeCheck); 956cb93a386Sopenharmony_ci } else if (len == 2) { 957cb93a386Sopenharmony_ci SkFixed first = joinRite + SK_Fixed1 - ur; 958cb93a386Sopenharmony_ci SkFixed second = lr - ur - first; 959cb93a386Sopenharmony_ci SkAlpha a1 = fullAlpha - partial_triangle_to_alpha(first, rDY); 960cb93a386Sopenharmony_ci SkAlpha a2 = partial_triangle_to_alpha(second, rDY); 961cb93a386Sopenharmony_ci blit_two_alphas(blitter, 962cb93a386Sopenharmony_ci y, 963cb93a386Sopenharmony_ci joinRite >> 16, 964cb93a386Sopenharmony_ci a1, 965cb93a386Sopenharmony_ci a2, 966cb93a386Sopenharmony_ci fullAlpha, 967cb93a386Sopenharmony_ci maskRow, 968cb93a386Sopenharmony_ci isUsingMask, 969cb93a386Sopenharmony_ci noRealBlitter, 970cb93a386Sopenharmony_ci needSafeCheck); 971cb93a386Sopenharmony_ci } else { 972cb93a386Sopenharmony_ci blit_aaa_trapezoid_row(blitter, 973cb93a386Sopenharmony_ci y, 974cb93a386Sopenharmony_ci joinRite, 975cb93a386Sopenharmony_ci ur, 976cb93a386Sopenharmony_ci joinRite, 977cb93a386Sopenharmony_ci lr, 978cb93a386Sopenharmony_ci SK_MaxS32, 979cb93a386Sopenharmony_ci rDY, 980cb93a386Sopenharmony_ci fullAlpha, 981cb93a386Sopenharmony_ci maskRow, 982cb93a386Sopenharmony_ci isUsingMask, 983cb93a386Sopenharmony_ci noRealBlitter, 984cb93a386Sopenharmony_ci needSafeCheck); 985cb93a386Sopenharmony_ci } 986cb93a386Sopenharmony_ci } 987cb93a386Sopenharmony_ci } else { 988cb93a386Sopenharmony_ci blit_aaa_trapezoid_row(blitter, 989cb93a386Sopenharmony_ci y, 990cb93a386Sopenharmony_ci ul, 991cb93a386Sopenharmony_ci ur, 992cb93a386Sopenharmony_ci ll, 993cb93a386Sopenharmony_ci lr, 994cb93a386Sopenharmony_ci lDY, 995cb93a386Sopenharmony_ci rDY, 996cb93a386Sopenharmony_ci fullAlpha, 997cb93a386Sopenharmony_ci maskRow, 998cb93a386Sopenharmony_ci isUsingMask, 999cb93a386Sopenharmony_ci noRealBlitter, 1000cb93a386Sopenharmony_ci needSafeCheck); 1001cb93a386Sopenharmony_ci } 1002cb93a386Sopenharmony_ci} 1003cb93a386Sopenharmony_ci 1004cb93a386Sopenharmony_cistatic bool operator<(const SkAnalyticEdge& a, const SkAnalyticEdge& b) { 1005cb93a386Sopenharmony_ci int valuea = a.fUpperY; 1006cb93a386Sopenharmony_ci int valueb = b.fUpperY; 1007cb93a386Sopenharmony_ci 1008cb93a386Sopenharmony_ci if (valuea == valueb) { 1009cb93a386Sopenharmony_ci valuea = a.fX; 1010cb93a386Sopenharmony_ci valueb = b.fX; 1011cb93a386Sopenharmony_ci } 1012cb93a386Sopenharmony_ci 1013cb93a386Sopenharmony_ci if (valuea == valueb) { 1014cb93a386Sopenharmony_ci valuea = a.fDX; 1015cb93a386Sopenharmony_ci valueb = b.fDX; 1016cb93a386Sopenharmony_ci } 1017cb93a386Sopenharmony_ci 1018cb93a386Sopenharmony_ci return valuea < valueb; 1019cb93a386Sopenharmony_ci} 1020cb93a386Sopenharmony_ci 1021cb93a386Sopenharmony_cistatic SkAnalyticEdge* sort_edges(SkAnalyticEdge* list[], int count, SkAnalyticEdge** last) { 1022cb93a386Sopenharmony_ci SkTQSort(list, list + count); 1023cb93a386Sopenharmony_ci 1024cb93a386Sopenharmony_ci // now make the edges linked in sorted order 1025cb93a386Sopenharmony_ci for (int i = 1; i < count; ++i) { 1026cb93a386Sopenharmony_ci list[i - 1]->fNext = list[i]; 1027cb93a386Sopenharmony_ci list[i]->fPrev = list[i - 1]; 1028cb93a386Sopenharmony_ci } 1029cb93a386Sopenharmony_ci 1030cb93a386Sopenharmony_ci *last = list[count - 1]; 1031cb93a386Sopenharmony_ci return list[0]; 1032cb93a386Sopenharmony_ci} 1033cb93a386Sopenharmony_ci 1034cb93a386Sopenharmony_cistatic void validate_sort(const SkAnalyticEdge* edge) { 1035cb93a386Sopenharmony_ci#ifdef SK_DEBUG 1036cb93a386Sopenharmony_ci SkFixed y = SkIntToFixed(-32768); 1037cb93a386Sopenharmony_ci 1038cb93a386Sopenharmony_ci while (edge->fUpperY != SK_MaxS32) { 1039cb93a386Sopenharmony_ci edge->validate(); 1040cb93a386Sopenharmony_ci SkASSERT(y <= edge->fUpperY); 1041cb93a386Sopenharmony_ci 1042cb93a386Sopenharmony_ci y = edge->fUpperY; 1043cb93a386Sopenharmony_ci edge = (SkAnalyticEdge*)edge->fNext; 1044cb93a386Sopenharmony_ci } 1045cb93a386Sopenharmony_ci#endif 1046cb93a386Sopenharmony_ci} 1047cb93a386Sopenharmony_ci 1048cb93a386Sopenharmony_ci// For an edge, we consider it smooth if the Dx doesn't change much, and Dy is large enough 1049cb93a386Sopenharmony_ci// For curves that are updating, the Dx is not changing much if fQDx/fCDx and fQDy/fCDy are 1050cb93a386Sopenharmony_ci// relatively large compared to fQDDx/QCDDx and fQDDy/fCDDy 1051cb93a386Sopenharmony_cistatic bool is_smooth_enough(SkAnalyticEdge* thisEdge, SkAnalyticEdge* nextEdge, int stop_y) { 1052cb93a386Sopenharmony_ci if (thisEdge->fCurveCount < 0) { 1053cb93a386Sopenharmony_ci const SkCubicEdge& cEdge = static_cast<SkAnalyticCubicEdge*>(thisEdge)->fCEdge; 1054cb93a386Sopenharmony_ci int ddshift = cEdge.fCurveShift; 1055cb93a386Sopenharmony_ci return SkAbs32(cEdge.fCDx) >> 1 >= SkAbs32(cEdge.fCDDx) >> ddshift && 1056cb93a386Sopenharmony_ci SkAbs32(cEdge.fCDy) >> 1 >= SkAbs32(cEdge.fCDDy) >> ddshift && 1057cb93a386Sopenharmony_ci // current Dy is (fCDy - (fCDDy >> ddshift)) >> dshift 1058cb93a386Sopenharmony_ci (cEdge.fCDy - (cEdge.fCDDy >> ddshift)) >> cEdge.fCubicDShift >= SK_Fixed1; 1059cb93a386Sopenharmony_ci } else if (thisEdge->fCurveCount > 0) { 1060cb93a386Sopenharmony_ci const SkQuadraticEdge& qEdge = static_cast<SkAnalyticQuadraticEdge*>(thisEdge)->fQEdge; 1061cb93a386Sopenharmony_ci return SkAbs32(qEdge.fQDx) >> 1 >= SkAbs32(qEdge.fQDDx) && 1062cb93a386Sopenharmony_ci SkAbs32(qEdge.fQDy) >> 1 >= SkAbs32(qEdge.fQDDy) && 1063cb93a386Sopenharmony_ci // current Dy is (fQDy - fQDDy) >> shift 1064cb93a386Sopenharmony_ci (qEdge.fQDy - qEdge.fQDDy) >> qEdge.fCurveShift >= SK_Fixed1; 1065cb93a386Sopenharmony_ci } 1066cb93a386Sopenharmony_ci return SkAbs32(nextEdge->fDX - thisEdge->fDX) <= SK_Fixed1 && // DDx should be small 1067cb93a386Sopenharmony_ci nextEdge->fLowerY - nextEdge->fUpperY >= SK_Fixed1; // Dy should be large 1068cb93a386Sopenharmony_ci} 1069cb93a386Sopenharmony_ci 1070cb93a386Sopenharmony_ci// Check if the leftE and riteE are changing smoothly in terms of fDX. 1071cb93a386Sopenharmony_ci// If yes, we can later skip the fractional y and directly jump to integer y. 1072cb93a386Sopenharmony_cistatic bool is_smooth_enough(SkAnalyticEdge* leftE, 1073cb93a386Sopenharmony_ci SkAnalyticEdge* riteE, 1074cb93a386Sopenharmony_ci SkAnalyticEdge* currE, 1075cb93a386Sopenharmony_ci int stop_y) { 1076cb93a386Sopenharmony_ci if (currE->fUpperY >= SkLeftShift(stop_y, 16)) { 1077cb93a386Sopenharmony_ci return false; // We're at the end so we won't skip anything 1078cb93a386Sopenharmony_ci } 1079cb93a386Sopenharmony_ci if (leftE->fLowerY + SK_Fixed1 < riteE->fLowerY) { 1080cb93a386Sopenharmony_ci return is_smooth_enough(leftE, currE, stop_y); // Only leftE is changing 1081cb93a386Sopenharmony_ci } else if (leftE->fLowerY > riteE->fLowerY + SK_Fixed1) { 1082cb93a386Sopenharmony_ci return is_smooth_enough(riteE, currE, stop_y); // Only riteE is changing 1083cb93a386Sopenharmony_ci } 1084cb93a386Sopenharmony_ci 1085cb93a386Sopenharmony_ci // Now both edges are changing, find the second next edge 1086cb93a386Sopenharmony_ci SkAnalyticEdge* nextCurrE = currE->fNext; 1087cb93a386Sopenharmony_ci if (nextCurrE->fUpperY >= stop_y << 16) { // Check if we're at the end 1088cb93a386Sopenharmony_ci return false; 1089cb93a386Sopenharmony_ci } 1090cb93a386Sopenharmony_ci // Ensure that currE is the next left edge and nextCurrE is the next right edge. Swap if not. 1091cb93a386Sopenharmony_ci if (nextCurrE->fUpperX < currE->fUpperX) { 1092cb93a386Sopenharmony_ci std::swap(currE, nextCurrE); 1093cb93a386Sopenharmony_ci } 1094cb93a386Sopenharmony_ci return is_smooth_enough(leftE, currE, stop_y) && is_smooth_enough(riteE, nextCurrE, stop_y); 1095cb93a386Sopenharmony_ci} 1096cb93a386Sopenharmony_ci 1097cb93a386Sopenharmony_cistatic void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, 1098cb93a386Sopenharmony_ci AdditiveBlitter* blitter, 1099cb93a386Sopenharmony_ci int start_y, 1100cb93a386Sopenharmony_ci int stop_y, 1101cb93a386Sopenharmony_ci SkFixed leftBound, 1102cb93a386Sopenharmony_ci SkFixed riteBound, 1103cb93a386Sopenharmony_ci bool isUsingMask) { 1104cb93a386Sopenharmony_ci validate_sort((SkAnalyticEdge*)prevHead->fNext); 1105cb93a386Sopenharmony_ci 1106cb93a386Sopenharmony_ci SkAnalyticEdge* leftE = (SkAnalyticEdge*)prevHead->fNext; 1107cb93a386Sopenharmony_ci SkAnalyticEdge* riteE = (SkAnalyticEdge*)leftE->fNext; 1108cb93a386Sopenharmony_ci SkAnalyticEdge* currE = (SkAnalyticEdge*)riteE->fNext; 1109cb93a386Sopenharmony_ci 1110cb93a386Sopenharmony_ci SkFixed y = std::max(leftE->fUpperY, riteE->fUpperY); 1111cb93a386Sopenharmony_ci 1112cb93a386Sopenharmony_ci for (;;) { 1113cb93a386Sopenharmony_ci // We have to check fLowerY first because some edges might be alone (e.g., there's only 1114cb93a386Sopenharmony_ci // a left edge but no right edge in a given y scan line) due to precision limit. 1115cb93a386Sopenharmony_ci while (leftE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges 1116cb93a386Sopenharmony_ci if (!leftE->update(y)) { 1117cb93a386Sopenharmony_ci if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) { 1118cb93a386Sopenharmony_ci goto END_WALK; 1119cb93a386Sopenharmony_ci } 1120cb93a386Sopenharmony_ci leftE = currE; 1121cb93a386Sopenharmony_ci currE = (SkAnalyticEdge*)currE->fNext; 1122cb93a386Sopenharmony_ci } 1123cb93a386Sopenharmony_ci } 1124cb93a386Sopenharmony_ci while (riteE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges 1125cb93a386Sopenharmony_ci if (!riteE->update(y)) { 1126cb93a386Sopenharmony_ci if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) { 1127cb93a386Sopenharmony_ci goto END_WALK; 1128cb93a386Sopenharmony_ci } 1129cb93a386Sopenharmony_ci riteE = currE; 1130cb93a386Sopenharmony_ci currE = (SkAnalyticEdge*)currE->fNext; 1131cb93a386Sopenharmony_ci } 1132cb93a386Sopenharmony_ci } 1133cb93a386Sopenharmony_ci 1134cb93a386Sopenharmony_ci SkASSERT(leftE); 1135cb93a386Sopenharmony_ci SkASSERT(riteE); 1136cb93a386Sopenharmony_ci 1137cb93a386Sopenharmony_ci // check our bottom clip 1138cb93a386Sopenharmony_ci if (SkFixedFloorToInt(y) >= stop_y) { 1139cb93a386Sopenharmony_ci break; 1140cb93a386Sopenharmony_ci } 1141cb93a386Sopenharmony_ci 1142cb93a386Sopenharmony_ci SkASSERT(SkFixedFloorToInt(leftE->fUpperY) <= stop_y); 1143cb93a386Sopenharmony_ci SkASSERT(SkFixedFloorToInt(riteE->fUpperY) <= stop_y); 1144cb93a386Sopenharmony_ci 1145cb93a386Sopenharmony_ci leftE->goY(y); 1146cb93a386Sopenharmony_ci riteE->goY(y); 1147cb93a386Sopenharmony_ci 1148cb93a386Sopenharmony_ci if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && leftE->fDX > riteE->fDX)) { 1149cb93a386Sopenharmony_ci std::swap(leftE, riteE); 1150cb93a386Sopenharmony_ci } 1151cb93a386Sopenharmony_ci 1152cb93a386Sopenharmony_ci SkFixed local_bot_fixed = std::min(leftE->fLowerY, riteE->fLowerY); 1153cb93a386Sopenharmony_ci if (is_smooth_enough(leftE, riteE, currE, stop_y)) { 1154cb93a386Sopenharmony_ci local_bot_fixed = SkFixedCeilToFixed(local_bot_fixed); 1155cb93a386Sopenharmony_ci } 1156cb93a386Sopenharmony_ci local_bot_fixed = std::min(local_bot_fixed, SkIntToFixed(stop_y)); 1157cb93a386Sopenharmony_ci 1158cb93a386Sopenharmony_ci SkFixed left = std::max(leftBound, leftE->fX); 1159cb93a386Sopenharmony_ci SkFixed dLeft = leftE->fDX; 1160cb93a386Sopenharmony_ci SkFixed rite = std::min(riteBound, riteE->fX); 1161cb93a386Sopenharmony_ci SkFixed dRite = riteE->fDX; 1162cb93a386Sopenharmony_ci if (0 == (dLeft | dRite)) { 1163cb93a386Sopenharmony_ci int fullLeft = SkFixedCeilToInt(left); 1164cb93a386Sopenharmony_ci int fullRite = SkFixedFloorToInt(rite); 1165cb93a386Sopenharmony_ci SkFixed partialLeft = SkIntToFixed(fullLeft) - left; 1166cb93a386Sopenharmony_ci SkFixed partialRite = rite - SkIntToFixed(fullRite); 1167cb93a386Sopenharmony_ci int fullTop = SkFixedCeilToInt(y); 1168cb93a386Sopenharmony_ci int fullBot = SkFixedFloorToInt(local_bot_fixed); 1169cb93a386Sopenharmony_ci SkFixed partialTop = SkIntToFixed(fullTop) - y; 1170cb93a386Sopenharmony_ci SkFixed partialBot = local_bot_fixed - SkIntToFixed(fullBot); 1171cb93a386Sopenharmony_ci if (fullTop > fullBot) { // The rectangle is within one pixel height... 1172cb93a386Sopenharmony_ci partialTop -= (SK_Fixed1 - partialBot); 1173cb93a386Sopenharmony_ci partialBot = 0; 1174cb93a386Sopenharmony_ci } 1175cb93a386Sopenharmony_ci 1176cb93a386Sopenharmony_ci if (fullRite >= fullLeft) { 1177cb93a386Sopenharmony_ci if (partialTop > 0) { // blit first partial row 1178cb93a386Sopenharmony_ci if (partialLeft > 0) { 1179cb93a386Sopenharmony_ci blitter->blitAntiH(fullLeft - 1, 1180cb93a386Sopenharmony_ci fullTop - 1, 1181cb93a386Sopenharmony_ci fixed_to_alpha(SkFixedMul(partialTop, partialLeft))); 1182cb93a386Sopenharmony_ci } 1183cb93a386Sopenharmony_ci blitter->blitAntiH( 1184cb93a386Sopenharmony_ci fullLeft, fullTop - 1, fullRite - fullLeft, fixed_to_alpha(partialTop)); 1185cb93a386Sopenharmony_ci if (partialRite > 0) { 1186cb93a386Sopenharmony_ci blitter->blitAntiH(fullRite, 1187cb93a386Sopenharmony_ci fullTop - 1, 1188cb93a386Sopenharmony_ci fixed_to_alpha(SkFixedMul(partialTop, partialRite))); 1189cb93a386Sopenharmony_ci } 1190cb93a386Sopenharmony_ci blitter->flush_if_y_changed(y, y + partialTop); 1191cb93a386Sopenharmony_ci } 1192cb93a386Sopenharmony_ci 1193cb93a386Sopenharmony_ci // Blit all full-height rows from fullTop to fullBot 1194cb93a386Sopenharmony_ci if (fullBot > fullTop && 1195cb93a386Sopenharmony_ci // SkAAClip cannot handle the empty rect so check the non-emptiness here 1196cb93a386Sopenharmony_ci // (bug chromium:662800) 1197cb93a386Sopenharmony_ci (fullRite > fullLeft || fixed_to_alpha(partialLeft) > 0 || 1198cb93a386Sopenharmony_ci fixed_to_alpha(partialRite) > 0)) { 1199cb93a386Sopenharmony_ci blitter->getRealBlitter()->blitAntiRect(fullLeft - 1, 1200cb93a386Sopenharmony_ci fullTop, 1201cb93a386Sopenharmony_ci fullRite - fullLeft, 1202cb93a386Sopenharmony_ci fullBot - fullTop, 1203cb93a386Sopenharmony_ci fixed_to_alpha(partialLeft), 1204cb93a386Sopenharmony_ci fixed_to_alpha(partialRite)); 1205cb93a386Sopenharmony_ci } 1206cb93a386Sopenharmony_ci 1207cb93a386Sopenharmony_ci if (partialBot > 0) { // blit last partial row 1208cb93a386Sopenharmony_ci if (partialLeft > 0) { 1209cb93a386Sopenharmony_ci blitter->blitAntiH(fullLeft - 1, 1210cb93a386Sopenharmony_ci fullBot, 1211cb93a386Sopenharmony_ci fixed_to_alpha(SkFixedMul(partialBot, partialLeft))); 1212cb93a386Sopenharmony_ci } 1213cb93a386Sopenharmony_ci blitter->blitAntiH( 1214cb93a386Sopenharmony_ci fullLeft, fullBot, fullRite - fullLeft, fixed_to_alpha(partialBot)); 1215cb93a386Sopenharmony_ci if (partialRite > 0) { 1216cb93a386Sopenharmony_ci blitter->blitAntiH(fullRite, 1217cb93a386Sopenharmony_ci fullBot, 1218cb93a386Sopenharmony_ci fixed_to_alpha(SkFixedMul(partialBot, partialRite))); 1219cb93a386Sopenharmony_ci } 1220cb93a386Sopenharmony_ci } 1221cb93a386Sopenharmony_ci } else { 1222cb93a386Sopenharmony_ci // Normal conditions, this means left and rite are within the same pixel, but if 1223cb93a386Sopenharmony_ci // both left and rite were < leftBounds or > rightBounds, both edges are clipped and 1224cb93a386Sopenharmony_ci // we should not do any blitting (particularly since the negative width saturates to 1225cb93a386Sopenharmony_ci // full alpha). 1226cb93a386Sopenharmony_ci SkFixed width = rite - left; 1227cb93a386Sopenharmony_ci if (width > 0) { 1228cb93a386Sopenharmony_ci if (partialTop > 0) { 1229cb93a386Sopenharmony_ci blitter->blitAntiH(fullLeft - 1, 1230cb93a386Sopenharmony_ci fullTop - 1, 1231cb93a386Sopenharmony_ci 1, 1232cb93a386Sopenharmony_ci fixed_to_alpha(SkFixedMul(partialTop, width))); 1233cb93a386Sopenharmony_ci blitter->flush_if_y_changed(y, y + partialTop); 1234cb93a386Sopenharmony_ci } 1235cb93a386Sopenharmony_ci if (fullBot > fullTop) { 1236cb93a386Sopenharmony_ci blitter->getRealBlitter()->blitV( 1237cb93a386Sopenharmony_ci fullLeft - 1, fullTop, fullBot - fullTop, fixed_to_alpha(width)); 1238cb93a386Sopenharmony_ci } 1239cb93a386Sopenharmony_ci if (partialBot > 0) { 1240cb93a386Sopenharmony_ci blitter->blitAntiH(fullLeft - 1, 1241cb93a386Sopenharmony_ci fullBot, 1242cb93a386Sopenharmony_ci 1, 1243cb93a386Sopenharmony_ci fixed_to_alpha(SkFixedMul(partialBot, width))); 1244cb93a386Sopenharmony_ci } 1245cb93a386Sopenharmony_ci } 1246cb93a386Sopenharmony_ci } 1247cb93a386Sopenharmony_ci 1248cb93a386Sopenharmony_ci y = local_bot_fixed; 1249cb93a386Sopenharmony_ci } else { 1250cb93a386Sopenharmony_ci // The following constant are used to snap X 1251cb93a386Sopenharmony_ci // We snap X mainly for speedup (no tiny triangle) and 1252cb93a386Sopenharmony_ci // avoiding edge cases caused by precision errors 1253cb93a386Sopenharmony_ci const SkFixed kSnapDigit = SK_Fixed1 >> 4; 1254cb93a386Sopenharmony_ci const SkFixed kSnapHalf = kSnapDigit >> 1; 1255cb93a386Sopenharmony_ci const SkFixed kSnapMask = (-1 ^ (kSnapDigit - 1)); 1256cb93a386Sopenharmony_ci left += kSnapHalf; 1257cb93a386Sopenharmony_ci rite += kSnapHalf; // For fast rounding 1258cb93a386Sopenharmony_ci 1259cb93a386Sopenharmony_ci // Number of blit_trapezoid_row calls we'll have 1260cb93a386Sopenharmony_ci int count = SkFixedCeilToInt(local_bot_fixed) - SkFixedFloorToInt(y); 1261cb93a386Sopenharmony_ci 1262cb93a386Sopenharmony_ci // If we're using mask blitter, we advance the mask row in this function 1263cb93a386Sopenharmony_ci // to save some "if" condition checks. 1264cb93a386Sopenharmony_ci SkAlpha* maskRow = nullptr; 1265cb93a386Sopenharmony_ci if (isUsingMask) { 1266cb93a386Sopenharmony_ci maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16); 1267cb93a386Sopenharmony_ci } 1268cb93a386Sopenharmony_ci 1269cb93a386Sopenharmony_ci // Instead of writing one loop that handles both partial-row blit_trapezoid_row 1270cb93a386Sopenharmony_ci // and full-row trapezoid_row together, we use the following 3-stage flow to 1271cb93a386Sopenharmony_ci // handle partial-row blit and full-row blit separately. It will save us much time 1272cb93a386Sopenharmony_ci // on changing y, left, and rite. 1273cb93a386Sopenharmony_ci if (count > 1) { 1274cb93a386Sopenharmony_ci if ((int)(y & 0xFFFF0000) != y) { // There's a partial-row on the top 1275cb93a386Sopenharmony_ci count--; 1276cb93a386Sopenharmony_ci SkFixed nextY = SkFixedCeilToFixed(y + 1); 1277cb93a386Sopenharmony_ci SkFixed dY = nextY - y; 1278cb93a386Sopenharmony_ci SkFixed nextLeft = left + SkFixedMul(dLeft, dY); 1279cb93a386Sopenharmony_ci SkFixed nextRite = rite + SkFixedMul(dRite, dY); 1280cb93a386Sopenharmony_ci SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound && 1281cb93a386Sopenharmony_ci (nextLeft & kSnapMask) >= leftBound && 1282cb93a386Sopenharmony_ci (nextRite & kSnapMask) <= riteBound); 1283cb93a386Sopenharmony_ci blit_trapezoid_row(blitter, 1284cb93a386Sopenharmony_ci y >> 16, 1285cb93a386Sopenharmony_ci left & kSnapMask, 1286cb93a386Sopenharmony_ci rite & kSnapMask, 1287cb93a386Sopenharmony_ci nextLeft & kSnapMask, 1288cb93a386Sopenharmony_ci nextRite & kSnapMask, 1289cb93a386Sopenharmony_ci leftE->fDY, 1290cb93a386Sopenharmony_ci riteE->fDY, 1291cb93a386Sopenharmony_ci get_partial_alpha(0xFF, dY), 1292cb93a386Sopenharmony_ci maskRow, 1293cb93a386Sopenharmony_ci isUsingMask); 1294cb93a386Sopenharmony_ci blitter->flush_if_y_changed(y, nextY); 1295cb93a386Sopenharmony_ci left = nextLeft; 1296cb93a386Sopenharmony_ci rite = nextRite; 1297cb93a386Sopenharmony_ci y = nextY; 1298cb93a386Sopenharmony_ci } 1299cb93a386Sopenharmony_ci 1300cb93a386Sopenharmony_ci while (count > 1) { // Full rows in the middle 1301cb93a386Sopenharmony_ci count--; 1302cb93a386Sopenharmony_ci if (isUsingMask) { 1303cb93a386Sopenharmony_ci maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16); 1304cb93a386Sopenharmony_ci } 1305cb93a386Sopenharmony_ci SkFixed nextY = y + SK_Fixed1, nextLeft = left + dLeft, nextRite = rite + dRite; 1306cb93a386Sopenharmony_ci SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound && 1307cb93a386Sopenharmony_ci (nextLeft & kSnapMask) >= leftBound && 1308cb93a386Sopenharmony_ci (nextRite & kSnapMask) <= riteBound); 1309cb93a386Sopenharmony_ci blit_trapezoid_row(blitter, 1310cb93a386Sopenharmony_ci y >> 16, 1311cb93a386Sopenharmony_ci left & kSnapMask, 1312cb93a386Sopenharmony_ci rite & kSnapMask, 1313cb93a386Sopenharmony_ci nextLeft & kSnapMask, 1314cb93a386Sopenharmony_ci nextRite & kSnapMask, 1315cb93a386Sopenharmony_ci leftE->fDY, 1316cb93a386Sopenharmony_ci riteE->fDY, 1317cb93a386Sopenharmony_ci 0xFF, 1318cb93a386Sopenharmony_ci maskRow, 1319cb93a386Sopenharmony_ci isUsingMask); 1320cb93a386Sopenharmony_ci blitter->flush_if_y_changed(y, nextY); 1321cb93a386Sopenharmony_ci left = nextLeft; 1322cb93a386Sopenharmony_ci rite = nextRite; 1323cb93a386Sopenharmony_ci y = nextY; 1324cb93a386Sopenharmony_ci } 1325cb93a386Sopenharmony_ci } 1326cb93a386Sopenharmony_ci 1327cb93a386Sopenharmony_ci if (isUsingMask) { 1328cb93a386Sopenharmony_ci maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16); 1329cb93a386Sopenharmony_ci } 1330cb93a386Sopenharmony_ci 1331cb93a386Sopenharmony_ci SkFixed dY = local_bot_fixed - y; // partial-row on the bottom 1332cb93a386Sopenharmony_ci SkASSERT(dY <= SK_Fixed1); 1333cb93a386Sopenharmony_ci // Smooth jumping to integer y may make the last nextLeft/nextRite out of bound. 1334cb93a386Sopenharmony_ci // Take them back into the bound here. 1335cb93a386Sopenharmony_ci // Note that we substract kSnapHalf later so we have to add them to leftBound/riteBound 1336cb93a386Sopenharmony_ci SkFixed nextLeft = std::max(left + SkFixedMul(dLeft, dY), leftBound + kSnapHalf); 1337cb93a386Sopenharmony_ci SkFixed nextRite = std::min(rite + SkFixedMul(dRite, dY), riteBound + kSnapHalf); 1338cb93a386Sopenharmony_ci SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound && 1339cb93a386Sopenharmony_ci (nextLeft & kSnapMask) >= leftBound && (nextRite & kSnapMask) <= riteBound); 1340cb93a386Sopenharmony_ci blit_trapezoid_row(blitter, 1341cb93a386Sopenharmony_ci y >> 16, 1342cb93a386Sopenharmony_ci left & kSnapMask, 1343cb93a386Sopenharmony_ci rite & kSnapMask, 1344cb93a386Sopenharmony_ci nextLeft & kSnapMask, 1345cb93a386Sopenharmony_ci nextRite & kSnapMask, 1346cb93a386Sopenharmony_ci leftE->fDY, 1347cb93a386Sopenharmony_ci riteE->fDY, 1348cb93a386Sopenharmony_ci get_partial_alpha(0xFF, dY), 1349cb93a386Sopenharmony_ci maskRow, 1350cb93a386Sopenharmony_ci isUsingMask); 1351cb93a386Sopenharmony_ci blitter->flush_if_y_changed(y, local_bot_fixed); 1352cb93a386Sopenharmony_ci left = nextLeft; 1353cb93a386Sopenharmony_ci rite = nextRite; 1354cb93a386Sopenharmony_ci y = local_bot_fixed; 1355cb93a386Sopenharmony_ci left -= kSnapHalf; 1356cb93a386Sopenharmony_ci rite -= kSnapHalf; 1357cb93a386Sopenharmony_ci } 1358cb93a386Sopenharmony_ci 1359cb93a386Sopenharmony_ci leftE->fX = left; 1360cb93a386Sopenharmony_ci riteE->fX = rite; 1361cb93a386Sopenharmony_ci leftE->fY = riteE->fY = y; 1362cb93a386Sopenharmony_ci } 1363cb93a386Sopenharmony_ci 1364cb93a386Sopenharmony_ciEND_WALK:; 1365cb93a386Sopenharmony_ci} 1366cb93a386Sopenharmony_ci 1367cb93a386Sopenharmony_cistatic void update_next_next_y(SkFixed y, SkFixed nextY, SkFixed* nextNextY) { 1368cb93a386Sopenharmony_ci *nextNextY = y > nextY && y < *nextNextY ? y : *nextNextY; 1369cb93a386Sopenharmony_ci} 1370cb93a386Sopenharmony_ci 1371cb93a386Sopenharmony_cistatic void check_intersection(const SkAnalyticEdge* edge, SkFixed nextY, SkFixed* nextNextY) { 1372cb93a386Sopenharmony_ci if (edge->fPrev->fPrev && edge->fPrev->fX + edge->fPrev->fDX > edge->fX + edge->fDX) { 1373cb93a386Sopenharmony_ci *nextNextY = nextY + (SK_Fixed1 >> SkAnalyticEdge::kDefaultAccuracy); 1374cb93a386Sopenharmony_ci } 1375cb93a386Sopenharmony_ci} 1376cb93a386Sopenharmony_ci 1377cb93a386Sopenharmony_cistatic void insert_new_edges(SkAnalyticEdge* newEdge, SkFixed y, SkFixed* nextNextY) { 1378cb93a386Sopenharmony_ci if (newEdge->fUpperY > y) { 1379cb93a386Sopenharmony_ci update_next_next_y(newEdge->fUpperY, y, nextNextY); 1380cb93a386Sopenharmony_ci return; 1381cb93a386Sopenharmony_ci } 1382cb93a386Sopenharmony_ci SkAnalyticEdge* prev = newEdge->fPrev; 1383cb93a386Sopenharmony_ci if (prev->fX <= newEdge->fX) { 1384cb93a386Sopenharmony_ci while (newEdge->fUpperY <= y) { 1385cb93a386Sopenharmony_ci check_intersection(newEdge, y, nextNextY); 1386cb93a386Sopenharmony_ci update_next_next_y(newEdge->fLowerY, y, nextNextY); 1387cb93a386Sopenharmony_ci newEdge = newEdge->fNext; 1388cb93a386Sopenharmony_ci } 1389cb93a386Sopenharmony_ci update_next_next_y(newEdge->fUpperY, y, nextNextY); 1390cb93a386Sopenharmony_ci return; 1391cb93a386Sopenharmony_ci } 1392cb93a386Sopenharmony_ci // find first x pos to insert 1393cb93a386Sopenharmony_ci SkAnalyticEdge* start = backward_insert_start(prev, newEdge->fX); 1394cb93a386Sopenharmony_ci // insert the lot, fixing up the links as we go 1395cb93a386Sopenharmony_ci do { 1396cb93a386Sopenharmony_ci SkAnalyticEdge* next = newEdge->fNext; 1397cb93a386Sopenharmony_ci do { 1398cb93a386Sopenharmony_ci if (start->fNext == newEdge) { 1399cb93a386Sopenharmony_ci goto nextEdge; 1400cb93a386Sopenharmony_ci } 1401cb93a386Sopenharmony_ci SkAnalyticEdge* after = start->fNext; 1402cb93a386Sopenharmony_ci if (after->fX >= newEdge->fX) { 1403cb93a386Sopenharmony_ci break; 1404cb93a386Sopenharmony_ci } 1405cb93a386Sopenharmony_ci SkASSERT(start != after); 1406cb93a386Sopenharmony_ci start = after; 1407cb93a386Sopenharmony_ci } while (true); 1408cb93a386Sopenharmony_ci remove_edge(newEdge); 1409cb93a386Sopenharmony_ci insert_edge_after(newEdge, start); 1410cb93a386Sopenharmony_ci nextEdge: 1411cb93a386Sopenharmony_ci check_intersection(newEdge, y, nextNextY); 1412cb93a386Sopenharmony_ci update_next_next_y(newEdge->fLowerY, y, nextNextY); 1413cb93a386Sopenharmony_ci start = newEdge; 1414cb93a386Sopenharmony_ci newEdge = next; 1415cb93a386Sopenharmony_ci } while (newEdge->fUpperY <= y); 1416cb93a386Sopenharmony_ci update_next_next_y(newEdge->fUpperY, y, nextNextY); 1417cb93a386Sopenharmony_ci} 1418cb93a386Sopenharmony_ci 1419cb93a386Sopenharmony_cistatic void validate_edges_for_y(const SkAnalyticEdge* edge, SkFixed y) { 1420cb93a386Sopenharmony_ci#ifdef SK_DEBUG 1421cb93a386Sopenharmony_ci while (edge->fUpperY <= y) { 1422cb93a386Sopenharmony_ci SkASSERT(edge->fPrev && edge->fNext); 1423cb93a386Sopenharmony_ci SkASSERT(edge->fPrev->fNext == edge); 1424cb93a386Sopenharmony_ci SkASSERT(edge->fNext->fPrev == edge); 1425cb93a386Sopenharmony_ci SkASSERT(edge->fUpperY <= edge->fLowerY); 1426cb93a386Sopenharmony_ci SkASSERT(edge->fPrev->fPrev == nullptr || edge->fPrev->fX <= edge->fX); 1427cb93a386Sopenharmony_ci edge = edge->fNext; 1428cb93a386Sopenharmony_ci } 1429cb93a386Sopenharmony_ci#endif 1430cb93a386Sopenharmony_ci} 1431cb93a386Sopenharmony_ci 1432cb93a386Sopenharmony_ci// Return true if prev->fX, next->fX are too close in the current pixel row. 1433cb93a386Sopenharmony_cistatic bool edges_too_close(SkAnalyticEdge* prev, SkAnalyticEdge* next, SkFixed lowerY) { 1434cb93a386Sopenharmony_ci // When next->fDX == 0, prev->fX >= next->fX - SkAbs32(next->fDX) would be false 1435cb93a386Sopenharmony_ci // even if prev->fX and next->fX are close and within one pixel (e.g., prev->fX == 0.1, 1436cb93a386Sopenharmony_ci // next->fX == 0.9). Adding SLACK = 1 to the formula would guarantee it to be true if two 1437cb93a386Sopenharmony_ci // edges prev and next are within one pixel. 1438cb93a386Sopenharmony_ci constexpr SkFixed SLACK = SK_Fixed1; 1439cb93a386Sopenharmony_ci 1440cb93a386Sopenharmony_ci // Note that even if the following test failed, the edges might still be very close to each 1441cb93a386Sopenharmony_ci // other at some point within the current pixel row because of prev->fDX and next->fDX. 1442cb93a386Sopenharmony_ci // However, to handle that case, we have to sacrafice more performance. 1443cb93a386Sopenharmony_ci // I think the current quality is good enough (mainly by looking at Nebraska-StateSeal.svg) 1444cb93a386Sopenharmony_ci // so I'll ignore fDX for performance tradeoff. 1445cb93a386Sopenharmony_ci return next && prev && next->fUpperY < lowerY && 1446cb93a386Sopenharmony_ci prev->fX + SLACK >= next->fX - SkAbs32(next->fDX); 1447cb93a386Sopenharmony_ci // The following is more accurate but also slower. 1448cb93a386Sopenharmony_ci // return (prev && prev->fPrev && next && next->fNext != nullptr && next->fUpperY < lowerY && 1449cb93a386Sopenharmony_ci // prev->fX + SkAbs32(prev->fDX) + SLACK >= next->fX - SkAbs32(next->fDX)); 1450cb93a386Sopenharmony_ci} 1451cb93a386Sopenharmony_ci 1452cb93a386Sopenharmony_ci// This function exists for the case where the previous rite edge is removed because 1453cb93a386Sopenharmony_ci// its fLowerY <= nextY 1454cb93a386Sopenharmony_cistatic bool edges_too_close(int prevRite, SkFixed ul, SkFixed ll) { 1455cb93a386Sopenharmony_ci return prevRite > SkFixedFloorToInt(ul) || prevRite > SkFixedFloorToInt(ll); 1456cb93a386Sopenharmony_ci} 1457cb93a386Sopenharmony_ci 1458cb93a386Sopenharmony_cistatic void blit_saved_trapezoid(SkAnalyticEdge* leftE, 1459cb93a386Sopenharmony_ci SkFixed lowerY, 1460cb93a386Sopenharmony_ci SkFixed lowerLeft, 1461cb93a386Sopenharmony_ci SkFixed lowerRite, 1462cb93a386Sopenharmony_ci AdditiveBlitter* blitter, 1463cb93a386Sopenharmony_ci SkAlpha* maskRow, 1464cb93a386Sopenharmony_ci bool isUsingMask, 1465cb93a386Sopenharmony_ci bool noRealBlitter, 1466cb93a386Sopenharmony_ci SkFixed leftClip, 1467cb93a386Sopenharmony_ci SkFixed rightClip) { 1468cb93a386Sopenharmony_ci SkAnalyticEdge* riteE = leftE->fRiteE; 1469cb93a386Sopenharmony_ci SkASSERT(riteE); 1470cb93a386Sopenharmony_ci SkASSERT(riteE->fNext == nullptr || leftE->fSavedY == riteE->fSavedY); 1471cb93a386Sopenharmony_ci SkASSERT(SkFixedFloorToInt(lowerY - 1) == SkFixedFloorToInt(leftE->fSavedY)); 1472cb93a386Sopenharmony_ci int y = SkFixedFloorToInt(leftE->fSavedY); 1473cb93a386Sopenharmony_ci // Instead of using fixed_to_alpha(lowerY - leftE->fSavedY), we use the following fullAlpha 1474cb93a386Sopenharmony_ci // to elimiate cumulative error: if there are many fractional y scan lines within the 1475cb93a386Sopenharmony_ci // same row, the former may accumulate the rounding error while the later won't. 1476cb93a386Sopenharmony_ci SkAlpha fullAlpha = fixed_to_alpha(lowerY - SkIntToFixed(y)) - 1477cb93a386Sopenharmony_ci fixed_to_alpha(leftE->fSavedY - SkIntToFixed(y)); 1478cb93a386Sopenharmony_ci // We need fSavedDY because the (quad or cubic) edge might be updated 1479cb93a386Sopenharmony_ci blit_trapezoid_row( 1480cb93a386Sopenharmony_ci blitter, 1481cb93a386Sopenharmony_ci y, 1482cb93a386Sopenharmony_ci std::max(leftE->fSavedX, leftClip), 1483cb93a386Sopenharmony_ci std::min(riteE->fSavedX, rightClip), 1484cb93a386Sopenharmony_ci std::max(lowerLeft, leftClip), 1485cb93a386Sopenharmony_ci std::min(lowerRite, rightClip), 1486cb93a386Sopenharmony_ci leftE->fSavedDY, 1487cb93a386Sopenharmony_ci riteE->fSavedDY, 1488cb93a386Sopenharmony_ci fullAlpha, 1489cb93a386Sopenharmony_ci maskRow, 1490cb93a386Sopenharmony_ci isUsingMask, 1491cb93a386Sopenharmony_ci noRealBlitter || (fullAlpha == 0xFF && (edges_too_close(leftE->fPrev, leftE, lowerY) || 1492cb93a386Sopenharmony_ci edges_too_close(riteE, riteE->fNext, lowerY))), 1493cb93a386Sopenharmony_ci true); 1494cb93a386Sopenharmony_ci leftE->fRiteE = nullptr; 1495cb93a386Sopenharmony_ci} 1496cb93a386Sopenharmony_ci 1497cb93a386Sopenharmony_cistatic void deferred_blit(SkAnalyticEdge* leftE, 1498cb93a386Sopenharmony_ci SkAnalyticEdge* riteE, 1499cb93a386Sopenharmony_ci SkFixed left, 1500cb93a386Sopenharmony_ci SkFixed leftDY, // don't save leftE->fX/fDY as they may have been updated 1501cb93a386Sopenharmony_ci SkFixed y, 1502cb93a386Sopenharmony_ci SkFixed nextY, 1503cb93a386Sopenharmony_ci bool isIntegralNextY, 1504cb93a386Sopenharmony_ci bool leftEnds, 1505cb93a386Sopenharmony_ci bool riteEnds, 1506cb93a386Sopenharmony_ci AdditiveBlitter* blitter, 1507cb93a386Sopenharmony_ci SkAlpha* maskRow, 1508cb93a386Sopenharmony_ci bool isUsingMask, 1509cb93a386Sopenharmony_ci bool noRealBlitter, 1510cb93a386Sopenharmony_ci SkFixed leftClip, 1511cb93a386Sopenharmony_ci SkFixed rightClip, 1512cb93a386Sopenharmony_ci int yShift) { 1513cb93a386Sopenharmony_ci if (leftE->fRiteE && leftE->fRiteE != riteE) { 1514cb93a386Sopenharmony_ci // leftE's right edge changed. Blit the saved trapezoid. 1515cb93a386Sopenharmony_ci SkASSERT(leftE->fRiteE->fNext == nullptr || leftE->fRiteE->fY == y); 1516cb93a386Sopenharmony_ci blit_saved_trapezoid(leftE, 1517cb93a386Sopenharmony_ci y, 1518cb93a386Sopenharmony_ci left, 1519cb93a386Sopenharmony_ci leftE->fRiteE->fX, 1520cb93a386Sopenharmony_ci blitter, 1521cb93a386Sopenharmony_ci maskRow, 1522cb93a386Sopenharmony_ci isUsingMask, 1523cb93a386Sopenharmony_ci noRealBlitter, 1524cb93a386Sopenharmony_ci leftClip, 1525cb93a386Sopenharmony_ci rightClip); 1526cb93a386Sopenharmony_ci } 1527cb93a386Sopenharmony_ci if (!leftE->fRiteE) { 1528cb93a386Sopenharmony_ci // Save and defer blitting the trapezoid 1529cb93a386Sopenharmony_ci SkASSERT(riteE->fRiteE == nullptr); 1530cb93a386Sopenharmony_ci SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY); 1531cb93a386Sopenharmony_ci SkASSERT(riteE->fNext == nullptr || riteE->fY == y); 1532cb93a386Sopenharmony_ci leftE->saveXY(left, y, leftDY); 1533cb93a386Sopenharmony_ci riteE->saveXY(riteE->fX, y, riteE->fDY); 1534cb93a386Sopenharmony_ci leftE->fRiteE = riteE; 1535cb93a386Sopenharmony_ci } 1536cb93a386Sopenharmony_ci SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY); 1537cb93a386Sopenharmony_ci riteE->goY(nextY, yShift); 1538cb93a386Sopenharmony_ci // Always blit when edges end or nextY is integral 1539cb93a386Sopenharmony_ci if (isIntegralNextY || leftEnds || riteEnds) { 1540cb93a386Sopenharmony_ci blit_saved_trapezoid(leftE, 1541cb93a386Sopenharmony_ci nextY, 1542cb93a386Sopenharmony_ci leftE->fX, 1543cb93a386Sopenharmony_ci riteE->fX, 1544cb93a386Sopenharmony_ci blitter, 1545cb93a386Sopenharmony_ci maskRow, 1546cb93a386Sopenharmony_ci isUsingMask, 1547cb93a386Sopenharmony_ci noRealBlitter, 1548cb93a386Sopenharmony_ci leftClip, 1549cb93a386Sopenharmony_ci rightClip); 1550cb93a386Sopenharmony_ci } 1551cb93a386Sopenharmony_ci} 1552cb93a386Sopenharmony_ci 1553cb93a386Sopenharmony_cistatic void aaa_walk_edges(SkAnalyticEdge* prevHead, 1554cb93a386Sopenharmony_ci SkAnalyticEdge* nextTail, 1555cb93a386Sopenharmony_ci SkPathFillType fillType, 1556cb93a386Sopenharmony_ci AdditiveBlitter* blitter, 1557cb93a386Sopenharmony_ci int start_y, 1558cb93a386Sopenharmony_ci int stop_y, 1559cb93a386Sopenharmony_ci SkFixed leftClip, 1560cb93a386Sopenharmony_ci SkFixed rightClip, 1561cb93a386Sopenharmony_ci bool isUsingMask, 1562cb93a386Sopenharmony_ci bool forceRLE, 1563cb93a386Sopenharmony_ci bool useDeferred, 1564cb93a386Sopenharmony_ci bool skipIntersect) { 1565cb93a386Sopenharmony_ci prevHead->fX = prevHead->fUpperX = leftClip; 1566cb93a386Sopenharmony_ci nextTail->fX = nextTail->fUpperX = rightClip; 1567cb93a386Sopenharmony_ci SkFixed y = std::max(prevHead->fNext->fUpperY, SkIntToFixed(start_y)); 1568cb93a386Sopenharmony_ci SkFixed nextNextY = SK_MaxS32; 1569cb93a386Sopenharmony_ci 1570cb93a386Sopenharmony_ci { 1571cb93a386Sopenharmony_ci SkAnalyticEdge* edge; 1572cb93a386Sopenharmony_ci for (edge = prevHead->fNext; edge->fUpperY <= y; edge = edge->fNext) { 1573cb93a386Sopenharmony_ci edge->goY(y); 1574cb93a386Sopenharmony_ci update_next_next_y(edge->fLowerY, y, &nextNextY); 1575cb93a386Sopenharmony_ci } 1576cb93a386Sopenharmony_ci update_next_next_y(edge->fUpperY, y, &nextNextY); 1577cb93a386Sopenharmony_ci } 1578cb93a386Sopenharmony_ci 1579cb93a386Sopenharmony_ci int windingMask = SkPathFillType_IsEvenOdd(fillType) ? 1 : -1; 1580cb93a386Sopenharmony_ci bool isInverse = SkPathFillType_IsInverse(fillType); 1581cb93a386Sopenharmony_ci 1582cb93a386Sopenharmony_ci if (isInverse && SkIntToFixed(start_y) != y) { 1583cb93a386Sopenharmony_ci int width = SkFixedFloorToInt(rightClip - leftClip); 1584cb93a386Sopenharmony_ci if (SkFixedFloorToInt(y) != start_y) { 1585cb93a386Sopenharmony_ci blitter->getRealBlitter()->blitRect( 1586cb93a386Sopenharmony_ci SkFixedFloorToInt(leftClip), start_y, width, SkFixedFloorToInt(y) - start_y); 1587cb93a386Sopenharmony_ci start_y = SkFixedFloorToInt(y); 1588cb93a386Sopenharmony_ci } 1589cb93a386Sopenharmony_ci SkAlpha* maskRow = 1590cb93a386Sopenharmony_ci isUsingMask ? static_cast<MaskAdditiveBlitter*>(blitter)->getRow(start_y) : nullptr; 1591cb93a386Sopenharmony_ci blit_full_alpha(blitter, 1592cb93a386Sopenharmony_ci start_y, 1593cb93a386Sopenharmony_ci SkFixedFloorToInt(leftClip), 1594cb93a386Sopenharmony_ci width, 1595cb93a386Sopenharmony_ci fixed_to_alpha(y - SkIntToFixed(start_y)), 1596cb93a386Sopenharmony_ci maskRow, 1597cb93a386Sopenharmony_ci isUsingMask, 1598cb93a386Sopenharmony_ci false, 1599cb93a386Sopenharmony_ci false); 1600cb93a386Sopenharmony_ci } 1601cb93a386Sopenharmony_ci 1602cb93a386Sopenharmony_ci while (true) { 1603cb93a386Sopenharmony_ci int w = 0; 1604cb93a386Sopenharmony_ci bool in_interval = isInverse; 1605cb93a386Sopenharmony_ci SkFixed prevX = prevHead->fX; 1606cb93a386Sopenharmony_ci SkFixed nextY = std::min(nextNextY, SkFixedCeilToFixed(y + 1)); 1607cb93a386Sopenharmony_ci bool isIntegralNextY = (nextY & (SK_Fixed1 - 1)) == 0; 1608cb93a386Sopenharmony_ci SkAnalyticEdge* currE = prevHead->fNext; 1609cb93a386Sopenharmony_ci SkAnalyticEdge* leftE = prevHead; 1610cb93a386Sopenharmony_ci SkFixed left = leftClip; 1611cb93a386Sopenharmony_ci SkFixed leftDY = 0; 1612cb93a386Sopenharmony_ci bool leftEnds = false; 1613cb93a386Sopenharmony_ci int prevRite = SkFixedFloorToInt(leftClip); 1614cb93a386Sopenharmony_ci 1615cb93a386Sopenharmony_ci nextNextY = SK_MaxS32; 1616cb93a386Sopenharmony_ci 1617cb93a386Sopenharmony_ci SkASSERT((nextY & ((SK_Fixed1 >> 2) - 1)) == 0); 1618cb93a386Sopenharmony_ci int yShift = 0; 1619cb93a386Sopenharmony_ci if ((nextY - y) & (SK_Fixed1 >> 2)) { 1620cb93a386Sopenharmony_ci yShift = 2; 1621cb93a386Sopenharmony_ci nextY = y + (SK_Fixed1 >> 2); 1622cb93a386Sopenharmony_ci } else if ((nextY - y) & (SK_Fixed1 >> 1)) { 1623cb93a386Sopenharmony_ci yShift = 1; 1624cb93a386Sopenharmony_ci SkASSERT(nextY == y + (SK_Fixed1 >> 1)); 1625cb93a386Sopenharmony_ci } 1626cb93a386Sopenharmony_ci 1627cb93a386Sopenharmony_ci SkAlpha fullAlpha = fixed_to_alpha(nextY - y); 1628cb93a386Sopenharmony_ci 1629cb93a386Sopenharmony_ci // If we're using mask blitter, we advance the mask row in this function 1630cb93a386Sopenharmony_ci // to save some "if" condition checks. 1631cb93a386Sopenharmony_ci SkAlpha* maskRow = nullptr; 1632cb93a386Sopenharmony_ci if (isUsingMask) { 1633cb93a386Sopenharmony_ci maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(SkFixedFloorToInt(y)); 1634cb93a386Sopenharmony_ci } 1635cb93a386Sopenharmony_ci 1636cb93a386Sopenharmony_ci SkASSERT(currE->fPrev == prevHead); 1637cb93a386Sopenharmony_ci validate_edges_for_y(currE, y); 1638cb93a386Sopenharmony_ci 1639cb93a386Sopenharmony_ci // Even if next - y == SK_Fixed1, we can still break the left-to-right order requirement 1640cb93a386Sopenharmony_ci // of the SKAAClip: |\| (two trapezoids with overlapping middle wedges) 1641cb93a386Sopenharmony_ci bool noRealBlitter = forceRLE; // forceRLE && (nextY - y != SK_Fixed1); 1642cb93a386Sopenharmony_ci 1643cb93a386Sopenharmony_ci while (currE->fUpperY <= y) { 1644cb93a386Sopenharmony_ci SkASSERT(currE->fLowerY >= nextY); 1645cb93a386Sopenharmony_ci SkASSERT(currE->fY == y); 1646cb93a386Sopenharmony_ci 1647cb93a386Sopenharmony_ci w += currE->fWinding; 1648cb93a386Sopenharmony_ci bool prev_in_interval = in_interval; 1649cb93a386Sopenharmony_ci in_interval = !(w & windingMask) == isInverse; 1650cb93a386Sopenharmony_ci 1651cb93a386Sopenharmony_ci bool isLeft = in_interval && !prev_in_interval; 1652cb93a386Sopenharmony_ci bool isRite = !in_interval && prev_in_interval; 1653cb93a386Sopenharmony_ci bool currEnds = currE->fLowerY == nextY; 1654cb93a386Sopenharmony_ci 1655cb93a386Sopenharmony_ci if (useDeferred) { 1656cb93a386Sopenharmony_ci if (currE->fRiteE && !isLeft) { 1657cb93a386Sopenharmony_ci // currE is a left edge previously, but now it's not. 1658cb93a386Sopenharmony_ci // Blit the trapezoid between fSavedY and y. 1659cb93a386Sopenharmony_ci SkASSERT(currE->fRiteE->fY == y); 1660cb93a386Sopenharmony_ci blit_saved_trapezoid(currE, 1661cb93a386Sopenharmony_ci y, 1662cb93a386Sopenharmony_ci currE->fX, 1663cb93a386Sopenharmony_ci currE->fRiteE->fX, 1664cb93a386Sopenharmony_ci blitter, 1665cb93a386Sopenharmony_ci maskRow, 1666cb93a386Sopenharmony_ci isUsingMask, 1667cb93a386Sopenharmony_ci noRealBlitter, 1668cb93a386Sopenharmony_ci leftClip, 1669cb93a386Sopenharmony_ci rightClip); 1670cb93a386Sopenharmony_ci } 1671cb93a386Sopenharmony_ci if (leftE->fRiteE == currE && !isRite) { 1672cb93a386Sopenharmony_ci // currE is a right edge previously, but now it's not. 1673cb93a386Sopenharmony_ci // Moreover, its corresponding leftE doesn't change (otherwise we'll handle it 1674cb93a386Sopenharmony_ci // in the previous if clause). Hence we blit the trapezoid. 1675cb93a386Sopenharmony_ci blit_saved_trapezoid(leftE, 1676cb93a386Sopenharmony_ci y, 1677cb93a386Sopenharmony_ci left, 1678cb93a386Sopenharmony_ci currE->fX, 1679cb93a386Sopenharmony_ci blitter, 1680cb93a386Sopenharmony_ci maskRow, 1681cb93a386Sopenharmony_ci isUsingMask, 1682cb93a386Sopenharmony_ci noRealBlitter, 1683cb93a386Sopenharmony_ci leftClip, 1684cb93a386Sopenharmony_ci rightClip); 1685cb93a386Sopenharmony_ci } 1686cb93a386Sopenharmony_ci } 1687cb93a386Sopenharmony_ci 1688cb93a386Sopenharmony_ci if (isRite) { 1689cb93a386Sopenharmony_ci if (useDeferred) { 1690cb93a386Sopenharmony_ci deferred_blit(leftE, 1691cb93a386Sopenharmony_ci currE, 1692cb93a386Sopenharmony_ci left, 1693cb93a386Sopenharmony_ci leftDY, 1694cb93a386Sopenharmony_ci y, 1695cb93a386Sopenharmony_ci nextY, 1696cb93a386Sopenharmony_ci isIntegralNextY, 1697cb93a386Sopenharmony_ci leftEnds, 1698cb93a386Sopenharmony_ci currEnds, 1699cb93a386Sopenharmony_ci blitter, 1700cb93a386Sopenharmony_ci maskRow, 1701cb93a386Sopenharmony_ci isUsingMask, 1702cb93a386Sopenharmony_ci noRealBlitter, 1703cb93a386Sopenharmony_ci leftClip, 1704cb93a386Sopenharmony_ci rightClip, 1705cb93a386Sopenharmony_ci yShift); 1706cb93a386Sopenharmony_ci } else { 1707cb93a386Sopenharmony_ci SkFixed rite = currE->fX; 1708cb93a386Sopenharmony_ci currE->goY(nextY, yShift); 1709cb93a386Sopenharmony_ci SkFixed nextLeft = std::max(leftClip, leftE->fX); 1710cb93a386Sopenharmony_ci rite = std::min(rightClip, rite); 1711cb93a386Sopenharmony_ci SkFixed nextRite = std::min(rightClip, currE->fX); 1712cb93a386Sopenharmony_ci blit_trapezoid_row( 1713cb93a386Sopenharmony_ci blitter, 1714cb93a386Sopenharmony_ci y >> 16, 1715cb93a386Sopenharmony_ci left, 1716cb93a386Sopenharmony_ci rite, 1717cb93a386Sopenharmony_ci nextLeft, 1718cb93a386Sopenharmony_ci nextRite, 1719cb93a386Sopenharmony_ci leftDY, 1720cb93a386Sopenharmony_ci currE->fDY, 1721cb93a386Sopenharmony_ci fullAlpha, 1722cb93a386Sopenharmony_ci maskRow, 1723cb93a386Sopenharmony_ci isUsingMask, 1724cb93a386Sopenharmony_ci noRealBlitter || (fullAlpha == 0xFF && 1725cb93a386Sopenharmony_ci (edges_too_close(prevRite, left, leftE->fX) || 1726cb93a386Sopenharmony_ci edges_too_close(currE, currE->fNext, nextY))), 1727cb93a386Sopenharmony_ci true); 1728cb93a386Sopenharmony_ci prevRite = SkFixedCeilToInt(std::max(rite, currE->fX)); 1729cb93a386Sopenharmony_ci } 1730cb93a386Sopenharmony_ci } else { 1731cb93a386Sopenharmony_ci if (isLeft) { 1732cb93a386Sopenharmony_ci left = std::max(currE->fX, leftClip); 1733cb93a386Sopenharmony_ci leftDY = currE->fDY; 1734cb93a386Sopenharmony_ci leftE = currE; 1735cb93a386Sopenharmony_ci leftEnds = leftE->fLowerY == nextY; 1736cb93a386Sopenharmony_ci } 1737cb93a386Sopenharmony_ci currE->goY(nextY, yShift); 1738cb93a386Sopenharmony_ci } 1739cb93a386Sopenharmony_ci 1740cb93a386Sopenharmony_ci SkAnalyticEdge* next = currE->fNext; 1741cb93a386Sopenharmony_ci SkFixed newX; 1742cb93a386Sopenharmony_ci 1743cb93a386Sopenharmony_ci while (currE->fLowerY <= nextY) { 1744cb93a386Sopenharmony_ci if (currE->fCurveCount < 0) { 1745cb93a386Sopenharmony_ci SkAnalyticCubicEdge* cubicEdge = (SkAnalyticCubicEdge*)currE; 1746cb93a386Sopenharmony_ci cubicEdge->keepContinuous(); 1747cb93a386Sopenharmony_ci if (!cubicEdge->updateCubic()) { 1748cb93a386Sopenharmony_ci break; 1749cb93a386Sopenharmony_ci } 1750cb93a386Sopenharmony_ci } else if (currE->fCurveCount > 0) { 1751cb93a386Sopenharmony_ci SkAnalyticQuadraticEdge* quadEdge = (SkAnalyticQuadraticEdge*)currE; 1752cb93a386Sopenharmony_ci quadEdge->keepContinuous(); 1753cb93a386Sopenharmony_ci if (!quadEdge->updateQuadratic()) { 1754cb93a386Sopenharmony_ci break; 1755cb93a386Sopenharmony_ci } 1756cb93a386Sopenharmony_ci } else { 1757cb93a386Sopenharmony_ci break; 1758cb93a386Sopenharmony_ci } 1759cb93a386Sopenharmony_ci } 1760cb93a386Sopenharmony_ci SkASSERT(currE->fY == nextY); 1761cb93a386Sopenharmony_ci 1762cb93a386Sopenharmony_ci if (currE->fLowerY <= nextY) { 1763cb93a386Sopenharmony_ci remove_edge(currE); 1764cb93a386Sopenharmony_ci } else { 1765cb93a386Sopenharmony_ci update_next_next_y(currE->fLowerY, nextY, &nextNextY); 1766cb93a386Sopenharmony_ci newX = currE->fX; 1767cb93a386Sopenharmony_ci SkASSERT(currE->fLowerY > nextY); 1768cb93a386Sopenharmony_ci if (newX < prevX) { // ripple currE backwards until it is x-sorted 1769cb93a386Sopenharmony_ci // If the crossing edge is a right edge, blit the saved trapezoid. 1770cb93a386Sopenharmony_ci if (leftE->fRiteE == currE && useDeferred) { 1771cb93a386Sopenharmony_ci SkASSERT(leftE->fY == nextY && currE->fY == nextY); 1772cb93a386Sopenharmony_ci blit_saved_trapezoid(leftE, 1773cb93a386Sopenharmony_ci nextY, 1774cb93a386Sopenharmony_ci leftE->fX, 1775cb93a386Sopenharmony_ci currE->fX, 1776cb93a386Sopenharmony_ci blitter, 1777cb93a386Sopenharmony_ci maskRow, 1778cb93a386Sopenharmony_ci isUsingMask, 1779cb93a386Sopenharmony_ci noRealBlitter, 1780cb93a386Sopenharmony_ci leftClip, 1781cb93a386Sopenharmony_ci rightClip); 1782cb93a386Sopenharmony_ci } 1783cb93a386Sopenharmony_ci backward_insert_edge_based_on_x(currE); 1784cb93a386Sopenharmony_ci } else { 1785cb93a386Sopenharmony_ci prevX = newX; 1786cb93a386Sopenharmony_ci } 1787cb93a386Sopenharmony_ci if (!skipIntersect) { 1788cb93a386Sopenharmony_ci check_intersection(currE, nextY, &nextNextY); 1789cb93a386Sopenharmony_ci } 1790cb93a386Sopenharmony_ci } 1791cb93a386Sopenharmony_ci 1792cb93a386Sopenharmony_ci currE = next; 1793cb93a386Sopenharmony_ci SkASSERT(currE); 1794cb93a386Sopenharmony_ci } 1795cb93a386Sopenharmony_ci 1796cb93a386Sopenharmony_ci // was our right-edge culled away? 1797cb93a386Sopenharmony_ci if (in_interval) { 1798cb93a386Sopenharmony_ci if (useDeferred) { 1799cb93a386Sopenharmony_ci deferred_blit(leftE, 1800cb93a386Sopenharmony_ci nextTail, 1801cb93a386Sopenharmony_ci left, 1802cb93a386Sopenharmony_ci leftDY, 1803cb93a386Sopenharmony_ci y, 1804cb93a386Sopenharmony_ci nextY, 1805cb93a386Sopenharmony_ci isIntegralNextY, 1806cb93a386Sopenharmony_ci leftEnds, 1807cb93a386Sopenharmony_ci false, 1808cb93a386Sopenharmony_ci blitter, 1809cb93a386Sopenharmony_ci maskRow, 1810cb93a386Sopenharmony_ci isUsingMask, 1811cb93a386Sopenharmony_ci noRealBlitter, 1812cb93a386Sopenharmony_ci leftClip, 1813cb93a386Sopenharmony_ci rightClip, 1814cb93a386Sopenharmony_ci yShift); 1815cb93a386Sopenharmony_ci } else { 1816cb93a386Sopenharmony_ci blit_trapezoid_row(blitter, 1817cb93a386Sopenharmony_ci y >> 16, 1818cb93a386Sopenharmony_ci left, 1819cb93a386Sopenharmony_ci rightClip, 1820cb93a386Sopenharmony_ci std::max(leftClip, leftE->fX), 1821cb93a386Sopenharmony_ci rightClip, 1822cb93a386Sopenharmony_ci leftDY, 1823cb93a386Sopenharmony_ci 0, 1824cb93a386Sopenharmony_ci fullAlpha, 1825cb93a386Sopenharmony_ci maskRow, 1826cb93a386Sopenharmony_ci isUsingMask, 1827cb93a386Sopenharmony_ci noRealBlitter || (fullAlpha == 0xFF && 1828cb93a386Sopenharmony_ci edges_too_close(leftE->fPrev, leftE, nextY)), 1829cb93a386Sopenharmony_ci true); 1830cb93a386Sopenharmony_ci } 1831cb93a386Sopenharmony_ci } 1832cb93a386Sopenharmony_ci 1833cb93a386Sopenharmony_ci if (forceRLE) { 1834cb93a386Sopenharmony_ci ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, nextY); 1835cb93a386Sopenharmony_ci } 1836cb93a386Sopenharmony_ci 1837cb93a386Sopenharmony_ci y = nextY; 1838cb93a386Sopenharmony_ci if (y >= SkIntToFixed(stop_y)) { 1839cb93a386Sopenharmony_ci break; 1840cb93a386Sopenharmony_ci } 1841cb93a386Sopenharmony_ci 1842cb93a386Sopenharmony_ci // now currE points to the first edge with a fUpperY larger than the previous y 1843cb93a386Sopenharmony_ci insert_new_edges(currE, y, &nextNextY); 1844cb93a386Sopenharmony_ci } 1845cb93a386Sopenharmony_ci} 1846cb93a386Sopenharmony_ci 1847cb93a386Sopenharmony_cistatic SK_ALWAYS_INLINE void aaa_fill_path( 1848cb93a386Sopenharmony_ci const SkPath& path, 1849cb93a386Sopenharmony_ci const SkIRect& clipRect, 1850cb93a386Sopenharmony_ci AdditiveBlitter* blitter, 1851cb93a386Sopenharmony_ci int start_y, 1852cb93a386Sopenharmony_ci int stop_y, 1853cb93a386Sopenharmony_ci bool pathContainedInClip, 1854cb93a386Sopenharmony_ci bool isUsingMask, 1855cb93a386Sopenharmony_ci bool forceRLE) { // forceRLE implies that SkAAClip is calling us 1856cb93a386Sopenharmony_ci SkASSERT(blitter); 1857cb93a386Sopenharmony_ci 1858cb93a386Sopenharmony_ci SkAnalyticEdgeBuilder builder; 1859cb93a386Sopenharmony_ci int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &clipRect); 1860cb93a386Sopenharmony_ci SkAnalyticEdge** list = builder.analyticEdgeList(); 1861cb93a386Sopenharmony_ci 1862cb93a386Sopenharmony_ci SkIRect rect = clipRect; 1863cb93a386Sopenharmony_ci if (0 == count) { 1864cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 1865cb93a386Sopenharmony_ci /* 1866cb93a386Sopenharmony_ci * Since we are in inverse-fill, our caller has already drawn above 1867cb93a386Sopenharmony_ci * our top (start_y) and will draw below our bottom (stop_y). Thus 1868cb93a386Sopenharmony_ci * we need to restrict our drawing to the intersection of the clip 1869cb93a386Sopenharmony_ci * and those two limits. 1870cb93a386Sopenharmony_ci */ 1871cb93a386Sopenharmony_ci if (rect.fTop < start_y) { 1872cb93a386Sopenharmony_ci rect.fTop = start_y; 1873cb93a386Sopenharmony_ci } 1874cb93a386Sopenharmony_ci if (rect.fBottom > stop_y) { 1875cb93a386Sopenharmony_ci rect.fBottom = stop_y; 1876cb93a386Sopenharmony_ci } 1877cb93a386Sopenharmony_ci if (!rect.isEmpty()) { 1878cb93a386Sopenharmony_ci blitter->getRealBlitter()->blitRect( 1879cb93a386Sopenharmony_ci rect.fLeft, rect.fTop, rect.width(), rect.height()); 1880cb93a386Sopenharmony_ci } 1881cb93a386Sopenharmony_ci } 1882cb93a386Sopenharmony_ci return; 1883cb93a386Sopenharmony_ci } 1884cb93a386Sopenharmony_ci 1885cb93a386Sopenharmony_ci SkAnalyticEdge headEdge, tailEdge, *last; 1886cb93a386Sopenharmony_ci // this returns the first and last edge after they're sorted into a dlink list 1887cb93a386Sopenharmony_ci SkAnalyticEdge* edge = sort_edges(list, count, &last); 1888cb93a386Sopenharmony_ci 1889cb93a386Sopenharmony_ci headEdge.fRiteE = nullptr; 1890cb93a386Sopenharmony_ci headEdge.fPrev = nullptr; 1891cb93a386Sopenharmony_ci headEdge.fNext = edge; 1892cb93a386Sopenharmony_ci headEdge.fUpperY = headEdge.fLowerY = SK_MinS32; 1893cb93a386Sopenharmony_ci headEdge.fX = SK_MinS32; 1894cb93a386Sopenharmony_ci headEdge.fDX = 0; 1895cb93a386Sopenharmony_ci headEdge.fDY = SK_MaxS32; 1896cb93a386Sopenharmony_ci headEdge.fUpperX = SK_MinS32; 1897cb93a386Sopenharmony_ci edge->fPrev = &headEdge; 1898cb93a386Sopenharmony_ci 1899cb93a386Sopenharmony_ci tailEdge.fRiteE = nullptr; 1900cb93a386Sopenharmony_ci tailEdge.fPrev = last; 1901cb93a386Sopenharmony_ci tailEdge.fNext = nullptr; 1902cb93a386Sopenharmony_ci tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32; 1903cb93a386Sopenharmony_ci tailEdge.fX = SK_MaxS32; 1904cb93a386Sopenharmony_ci tailEdge.fDX = 0; 1905cb93a386Sopenharmony_ci tailEdge.fDY = SK_MaxS32; 1906cb93a386Sopenharmony_ci tailEdge.fUpperX = SK_MaxS32; 1907cb93a386Sopenharmony_ci last->fNext = &tailEdge; 1908cb93a386Sopenharmony_ci 1909cb93a386Sopenharmony_ci // now edge is the head of the sorted linklist 1910cb93a386Sopenharmony_ci 1911cb93a386Sopenharmony_ci if (!pathContainedInClip && start_y < clipRect.fTop) { 1912cb93a386Sopenharmony_ci start_y = clipRect.fTop; 1913cb93a386Sopenharmony_ci } 1914cb93a386Sopenharmony_ci if (!pathContainedInClip && stop_y > clipRect.fBottom) { 1915cb93a386Sopenharmony_ci stop_y = clipRect.fBottom; 1916cb93a386Sopenharmony_ci } 1917cb93a386Sopenharmony_ci 1918cb93a386Sopenharmony_ci SkFixed leftBound = SkIntToFixed(rect.fLeft); 1919cb93a386Sopenharmony_ci SkFixed rightBound = SkIntToFixed(rect.fRight); 1920cb93a386Sopenharmony_ci if (isUsingMask) { 1921cb93a386Sopenharmony_ci // If we're using mask, then we have to limit the bound within the path bounds. 1922cb93a386Sopenharmony_ci // Otherwise, the edge drift may access an invalid address inside the mask. 1923cb93a386Sopenharmony_ci SkIRect ir; 1924cb93a386Sopenharmony_ci path.getBounds().roundOut(&ir); 1925cb93a386Sopenharmony_ci leftBound = std::max(leftBound, SkIntToFixed(ir.fLeft)); 1926cb93a386Sopenharmony_ci rightBound = std::min(rightBound, SkIntToFixed(ir.fRight)); 1927cb93a386Sopenharmony_ci } 1928cb93a386Sopenharmony_ci 1929cb93a386Sopenharmony_ci if (!path.isInverseFillType() && path.isConvex() && count >= 2) { 1930cb93a386Sopenharmony_ci aaa_walk_convex_edges( 1931cb93a386Sopenharmony_ci &headEdge, blitter, start_y, stop_y, leftBound, rightBound, isUsingMask); 1932cb93a386Sopenharmony_ci } else { 1933cb93a386Sopenharmony_ci // Only use deferred blitting if there are many edges. 1934cb93a386Sopenharmony_ci bool useDeferred = 1935cb93a386Sopenharmony_ci count > 1936cb93a386Sopenharmony_ci (SkFixedFloorToInt(tailEdge.fPrev->fLowerY - headEdge.fNext->fUpperY) + 1) * 4; 1937cb93a386Sopenharmony_ci 1938cb93a386Sopenharmony_ci // We skip intersection computation if there are many points which probably already 1939cb93a386Sopenharmony_ci // give us enough fractional scan lines. 1940cb93a386Sopenharmony_ci bool skipIntersect = path.countPoints() > (stop_y - start_y) * 2; 1941cb93a386Sopenharmony_ci 1942cb93a386Sopenharmony_ci aaa_walk_edges(&headEdge, 1943cb93a386Sopenharmony_ci &tailEdge, 1944cb93a386Sopenharmony_ci path.getFillType(), 1945cb93a386Sopenharmony_ci blitter, 1946cb93a386Sopenharmony_ci start_y, 1947cb93a386Sopenharmony_ci stop_y, 1948cb93a386Sopenharmony_ci leftBound, 1949cb93a386Sopenharmony_ci rightBound, 1950cb93a386Sopenharmony_ci isUsingMask, 1951cb93a386Sopenharmony_ci forceRLE, 1952cb93a386Sopenharmony_ci useDeferred, 1953cb93a386Sopenharmony_ci skipIntersect); 1954cb93a386Sopenharmony_ci } 1955cb93a386Sopenharmony_ci} 1956cb93a386Sopenharmony_ci 1957cb93a386Sopenharmony_civoid SkScan::AAAFillPath(const SkPath& path, 1958cb93a386Sopenharmony_ci SkBlitter* blitter, 1959cb93a386Sopenharmony_ci const SkIRect& ir, 1960cb93a386Sopenharmony_ci const SkIRect& clipBounds, 1961cb93a386Sopenharmony_ci bool forceRLE) { 1962cb93a386Sopenharmony_ci bool containedInClip = clipBounds.contains(ir); 1963cb93a386Sopenharmony_ci bool isInverse = path.isInverseFillType(); 1964cb93a386Sopenharmony_ci 1965cb93a386Sopenharmony_ci // The mask blitter (where we store intermediate alpha values directly in a mask, and then call 1966cb93a386Sopenharmony_ci // the real blitter once in the end to blit the whole mask) is faster than the RLE blitter when 1967cb93a386Sopenharmony_ci // the blit region is small enough (i.e., CanHandleRect(ir)). When isInverse is true, the blit 1968cb93a386Sopenharmony_ci // region is no longer the rectangle ir so we won't use the mask blitter. The caller may also 1969cb93a386Sopenharmony_ci // use the forceRLE flag to force not using the mask blitter. Also, when the path is a simple 1970cb93a386Sopenharmony_ci // rect, preparing a mask and blitting it might have too much overhead. Hence we'll use 1971cb93a386Sopenharmony_ci // blitFatAntiRect to avoid the mask and its overhead. 1972cb93a386Sopenharmony_ci if (MaskAdditiveBlitter::CanHandleRect(ir) && !isInverse && !forceRLE) { 1973cb93a386Sopenharmony_ci // blitFatAntiRect is slower than the normal AAA flow without MaskAdditiveBlitter. 1974cb93a386Sopenharmony_ci // Hence only tryBlitFatAntiRect when MaskAdditiveBlitter would have been used. 1975cb93a386Sopenharmony_ci if (!TryBlitFatAntiRect(blitter, path, clipBounds)) { 1976cb93a386Sopenharmony_ci MaskAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse); 1977cb93a386Sopenharmony_ci aaa_fill_path(path, 1978cb93a386Sopenharmony_ci clipBounds, 1979cb93a386Sopenharmony_ci &additiveBlitter, 1980cb93a386Sopenharmony_ci ir.fTop, 1981cb93a386Sopenharmony_ci ir.fBottom, 1982cb93a386Sopenharmony_ci containedInClip, 1983cb93a386Sopenharmony_ci true, 1984cb93a386Sopenharmony_ci forceRLE); 1985cb93a386Sopenharmony_ci } 1986cb93a386Sopenharmony_ci } else if (!isInverse && path.isConvex()) { 1987cb93a386Sopenharmony_ci // If the filling area is convex (i.e., path.isConvex && !isInverse), our simpler 1988cb93a386Sopenharmony_ci // aaa_walk_convex_edges won't generate alphas above 255. Hence we don't need 1989cb93a386Sopenharmony_ci // SafeRLEAdditiveBlitter (which is slow due to clamping). The basic RLE blitter 1990cb93a386Sopenharmony_ci // RunBasedAdditiveBlitter would suffice. 1991cb93a386Sopenharmony_ci RunBasedAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse); 1992cb93a386Sopenharmony_ci aaa_fill_path(path, 1993cb93a386Sopenharmony_ci clipBounds, 1994cb93a386Sopenharmony_ci &additiveBlitter, 1995cb93a386Sopenharmony_ci ir.fTop, 1996cb93a386Sopenharmony_ci ir.fBottom, 1997cb93a386Sopenharmony_ci containedInClip, 1998cb93a386Sopenharmony_ci false, 1999cb93a386Sopenharmony_ci forceRLE); 2000cb93a386Sopenharmony_ci } else { 2001cb93a386Sopenharmony_ci // If the filling area might not be convex, the more involved aaa_walk_edges would 2002cb93a386Sopenharmony_ci // be called and we have to clamp the alpha downto 255. The SafeRLEAdditiveBlitter 2003cb93a386Sopenharmony_ci // does that at a cost of performance. 2004cb93a386Sopenharmony_ci SafeRLEAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse); 2005cb93a386Sopenharmony_ci aaa_fill_path(path, 2006cb93a386Sopenharmony_ci clipBounds, 2007cb93a386Sopenharmony_ci &additiveBlitter, 2008cb93a386Sopenharmony_ci ir.fTop, 2009cb93a386Sopenharmony_ci ir.fBottom, 2010cb93a386Sopenharmony_ci containedInClip, 2011cb93a386Sopenharmony_ci false, 2012cb93a386Sopenharmony_ci forceRLE); 2013cb93a386Sopenharmony_ci } 2014cb93a386Sopenharmony_ci} 2015cb93a386Sopenharmony_ci#endif // defined(SK_DISABLE_AAA) 2016