1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2006 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/SkMacros.h" 11cb93a386Sopenharmony_ci#include "include/private/SkSafe32.h" 12cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 13cb93a386Sopenharmony_ci#include "src/core/SkBlitter.h" 14cb93a386Sopenharmony_ci#include "src/core/SkEdge.h" 15cb93a386Sopenharmony_ci#include "src/core/SkEdgeBuilder.h" 16cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 17cb93a386Sopenharmony_ci#include "src/core/SkQuadClipper.h" 18cb93a386Sopenharmony_ci#include "src/core/SkRasterClip.h" 19cb93a386Sopenharmony_ci#include "src/core/SkRectPriv.h" 20cb93a386Sopenharmony_ci#include "src/core/SkScanPriv.h" 21cb93a386Sopenharmony_ci#include "src/core/SkTSort.h" 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci#include <utility> 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci#define kEDGE_HEAD_Y SK_MinS32 26cb93a386Sopenharmony_ci#define kEDGE_TAIL_Y SK_MaxS32 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci#ifdef SK_DEBUG 29cb93a386Sopenharmony_ci static void validate_sort(const SkEdge* edge) { 30cb93a386Sopenharmony_ci int y = kEDGE_HEAD_Y; 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci while (edge->fFirstY != SK_MaxS32) { 33cb93a386Sopenharmony_ci edge->validate(); 34cb93a386Sopenharmony_ci SkASSERT(y <= edge->fFirstY); 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci y = edge->fFirstY; 37cb93a386Sopenharmony_ci edge = edge->fNext; 38cb93a386Sopenharmony_ci } 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci#else 41cb93a386Sopenharmony_ci #define validate_sort(edge) 42cb93a386Sopenharmony_ci#endif 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_cistatic void insert_new_edges(SkEdge* newEdge, int curr_y) { 45cb93a386Sopenharmony_ci if (newEdge->fFirstY != curr_y) { 46cb93a386Sopenharmony_ci return; 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci SkEdge* prev = newEdge->fPrev; 49cb93a386Sopenharmony_ci if (prev->fX <= newEdge->fX) { 50cb93a386Sopenharmony_ci return; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci // find first x pos to insert 53cb93a386Sopenharmony_ci SkEdge* start = backward_insert_start(prev, newEdge->fX); 54cb93a386Sopenharmony_ci // insert the lot, fixing up the links as we go 55cb93a386Sopenharmony_ci do { 56cb93a386Sopenharmony_ci SkEdge* next = newEdge->fNext; 57cb93a386Sopenharmony_ci do { 58cb93a386Sopenharmony_ci if (start->fNext == newEdge) { 59cb93a386Sopenharmony_ci goto nextEdge; 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci SkEdge* after = start->fNext; 62cb93a386Sopenharmony_ci if (after->fX >= newEdge->fX) { 63cb93a386Sopenharmony_ci break; 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci start = after; 66cb93a386Sopenharmony_ci } while (true); 67cb93a386Sopenharmony_ci remove_edge(newEdge); 68cb93a386Sopenharmony_ci insert_edge_after(newEdge, start); 69cb93a386Sopenharmony_cinextEdge: 70cb93a386Sopenharmony_ci start = newEdge; 71cb93a386Sopenharmony_ci newEdge = next; 72cb93a386Sopenharmony_ci } while (newEdge->fFirstY == curr_y); 73cb93a386Sopenharmony_ci} 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci#ifdef SK_DEBUG 76cb93a386Sopenharmony_cistatic void validate_edges_for_y(const SkEdge* edge, int curr_y) { 77cb93a386Sopenharmony_ci while (edge->fFirstY <= curr_y) { 78cb93a386Sopenharmony_ci SkASSERT(edge->fPrev && edge->fNext); 79cb93a386Sopenharmony_ci SkASSERT(edge->fPrev->fNext == edge); 80cb93a386Sopenharmony_ci SkASSERT(edge->fNext->fPrev == edge); 81cb93a386Sopenharmony_ci SkASSERT(edge->fFirstY <= edge->fLastY); 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci SkASSERT(edge->fPrev->fX <= edge->fX); 84cb93a386Sopenharmony_ci edge = edge->fNext; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci} 87cb93a386Sopenharmony_ci#else 88cb93a386Sopenharmony_ci #define validate_edges_for_y(edge, curr_y) 89cb93a386Sopenharmony_ci#endif 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci#if defined _WIN32 // disable warning : local variable used without having been initialized 92cb93a386Sopenharmony_ci#pragma warning ( push ) 93cb93a386Sopenharmony_ci#pragma warning ( disable : 4701 ) 94cb93a386Sopenharmony_ci#endif 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_citypedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline); 97cb93a386Sopenharmony_ci#define PREPOST_START true 98cb93a386Sopenharmony_ci#define PREPOST_END false 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_cistatic void walk_edges(SkEdge* prevHead, SkPathFillType fillType, 101cb93a386Sopenharmony_ci SkBlitter* blitter, int start_y, int stop_y, 102cb93a386Sopenharmony_ci PrePostProc proc, int rightClip) { 103cb93a386Sopenharmony_ci validate_sort(prevHead->fNext); 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci int curr_y = start_y; 106cb93a386Sopenharmony_ci int windingMask = SkPathFillType_IsEvenOdd(fillType) ? 1 : -1; 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci for (;;) { 109cb93a386Sopenharmony_ci int w = 0; 110cb93a386Sopenharmony_ci int left SK_INIT_TO_AVOID_WARNING; 111cb93a386Sopenharmony_ci SkEdge* currE = prevHead->fNext; 112cb93a386Sopenharmony_ci SkFixed prevX = prevHead->fX; 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci validate_edges_for_y(currE, curr_y); 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci if (proc) { 117cb93a386Sopenharmony_ci proc(blitter, curr_y, PREPOST_START); // pre-proc 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci while (currE->fFirstY <= curr_y) { 121cb93a386Sopenharmony_ci SkASSERT(currE->fLastY >= curr_y); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci int x = SkFixedRoundToInt(currE->fX); 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci if ((w & windingMask) == 0) { // we're starting interval 126cb93a386Sopenharmony_ci left = x; 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci w += currE->fWinding; 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci if ((w & windingMask) == 0) { // we finished an interval 132cb93a386Sopenharmony_ci int width = x - left; 133cb93a386Sopenharmony_ci SkASSERT(width >= 0); 134cb93a386Sopenharmony_ci if (width > 0) { 135cb93a386Sopenharmony_ci blitter->blitH(left, curr_y, width); 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci SkEdge* next = currE->fNext; 140cb93a386Sopenharmony_ci SkFixed newX; 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci if (currE->fLastY == curr_y) { // are we done with this edge? 143cb93a386Sopenharmony_ci if (currE->fCurveCount > 0) { 144cb93a386Sopenharmony_ci if (((SkQuadraticEdge*)currE)->updateQuadratic()) { 145cb93a386Sopenharmony_ci newX = currE->fX; 146cb93a386Sopenharmony_ci goto NEXT_X; 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci } else if (currE->fCurveCount < 0) { 149cb93a386Sopenharmony_ci if (((SkCubicEdge*)currE)->updateCubic()) { 150cb93a386Sopenharmony_ci SkASSERT(currE->fFirstY == curr_y + 1); 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci newX = currE->fX; 153cb93a386Sopenharmony_ci goto NEXT_X; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci remove_edge(currE); 157cb93a386Sopenharmony_ci } else { 158cb93a386Sopenharmony_ci SkASSERT(currE->fLastY > curr_y); 159cb93a386Sopenharmony_ci newX = currE->fX + currE->fDX; 160cb93a386Sopenharmony_ci currE->fX = newX; 161cb93a386Sopenharmony_ci NEXT_X: 162cb93a386Sopenharmony_ci if (newX < prevX) { // ripple currE backwards until it is x-sorted 163cb93a386Sopenharmony_ci backward_insert_edge_based_on_x(currE); 164cb93a386Sopenharmony_ci } else { 165cb93a386Sopenharmony_ci prevX = newX; 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci currE = next; 169cb93a386Sopenharmony_ci SkASSERT(currE); 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci if ((w & windingMask) != 0) { // was our right-edge culled away? 173cb93a386Sopenharmony_ci int width = rightClip - left; 174cb93a386Sopenharmony_ci if (width > 0) { 175cb93a386Sopenharmony_ci blitter->blitH(left, curr_y, width); 176cb93a386Sopenharmony_ci } 177cb93a386Sopenharmony_ci } 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci if (proc) { 180cb93a386Sopenharmony_ci proc(blitter, curr_y, PREPOST_END); // post-proc 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci curr_y += 1; 184cb93a386Sopenharmony_ci if (curr_y >= stop_y) { 185cb93a386Sopenharmony_ci break; 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci // now currE points to the first edge with a Yint larger than curr_y 188cb93a386Sopenharmony_ci insert_new_edges(currE, curr_y); 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci} 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci// return true if we're NOT done with this edge 193cb93a386Sopenharmony_cistatic bool update_edge(SkEdge* edge, int last_y) { 194cb93a386Sopenharmony_ci SkASSERT(edge->fLastY >= last_y); 195cb93a386Sopenharmony_ci if (last_y == edge->fLastY) { 196cb93a386Sopenharmony_ci if (edge->fCurveCount < 0) { 197cb93a386Sopenharmony_ci if (((SkCubicEdge*)edge)->updateCubic()) { 198cb93a386Sopenharmony_ci SkASSERT(edge->fFirstY == last_y + 1); 199cb93a386Sopenharmony_ci return true; 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci } else if (edge->fCurveCount > 0) { 202cb93a386Sopenharmony_ci if (((SkQuadraticEdge*)edge)->updateQuadratic()) { 203cb93a386Sopenharmony_ci SkASSERT(edge->fFirstY == last_y + 1); 204cb93a386Sopenharmony_ci return true; 205cb93a386Sopenharmony_ci } 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci return false; 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci return true; 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci// Unexpected conditions for which we need to return 213cb93a386Sopenharmony_ci#define ASSERT_RETURN(cond) \ 214cb93a386Sopenharmony_ci do { \ 215cb93a386Sopenharmony_ci if (!(cond)) { \ 216cb93a386Sopenharmony_ci SkDEBUGFAILF("assert(%s)", #cond); \ 217cb93a386Sopenharmony_ci return; \ 218cb93a386Sopenharmony_ci } \ 219cb93a386Sopenharmony_ci } while (0) 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci// Needs Y to only change once (looser than convex in X) 222cb93a386Sopenharmony_cistatic void walk_simple_edges(SkEdge* prevHead, SkBlitter* blitter, int start_y, int stop_y) { 223cb93a386Sopenharmony_ci validate_sort(prevHead->fNext); 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci SkEdge* leftE = prevHead->fNext; 226cb93a386Sopenharmony_ci SkEdge* riteE = leftE->fNext; 227cb93a386Sopenharmony_ci SkEdge* currE = riteE->fNext; 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci // our edge choppers for curves can result in the initial edges 230cb93a386Sopenharmony_ci // not lining up, so we take the max. 231cb93a386Sopenharmony_ci int local_top = std::max(leftE->fFirstY, riteE->fFirstY); 232cb93a386Sopenharmony_ci ASSERT_RETURN(local_top >= start_y); 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci while (local_top < stop_y) { 235cb93a386Sopenharmony_ci SkASSERT(leftE->fFirstY <= stop_y); 236cb93a386Sopenharmony_ci SkASSERT(riteE->fFirstY <= stop_y); 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci int local_bot = std::min(leftE->fLastY, riteE->fLastY); 239cb93a386Sopenharmony_ci local_bot = std::min(local_bot, stop_y - 1); 240cb93a386Sopenharmony_ci ASSERT_RETURN(local_top <= local_bot); 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_ci SkFixed left = leftE->fX; 243cb93a386Sopenharmony_ci SkFixed dLeft = leftE->fDX; 244cb93a386Sopenharmony_ci SkFixed rite = riteE->fX; 245cb93a386Sopenharmony_ci SkFixed dRite = riteE->fDX; 246cb93a386Sopenharmony_ci int count = local_bot - local_top; 247cb93a386Sopenharmony_ci ASSERT_RETURN(count >= 0); 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci if (0 == (dLeft | dRite)) { 250cb93a386Sopenharmony_ci int L = SkFixedRoundToInt(left); 251cb93a386Sopenharmony_ci int R = SkFixedRoundToInt(rite); 252cb93a386Sopenharmony_ci if (L > R) { 253cb93a386Sopenharmony_ci std::swap(L, R); 254cb93a386Sopenharmony_ci } 255cb93a386Sopenharmony_ci if (L < R) { 256cb93a386Sopenharmony_ci count += 1; 257cb93a386Sopenharmony_ci blitter->blitRect(L, local_top, R - L, count); 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci local_top = local_bot + 1; 260cb93a386Sopenharmony_ci } else { 261cb93a386Sopenharmony_ci do { 262cb93a386Sopenharmony_ci int L = SkFixedRoundToInt(left); 263cb93a386Sopenharmony_ci int R = SkFixedRoundToInt(rite); 264cb93a386Sopenharmony_ci if (L > R) { 265cb93a386Sopenharmony_ci std::swap(L, R); 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci if (L < R) { 268cb93a386Sopenharmony_ci blitter->blitH(L, local_top, R - L); 269cb93a386Sopenharmony_ci } 270cb93a386Sopenharmony_ci // Either/both of these might overflow, since we perform this step even if 271cb93a386Sopenharmony_ci // (later) we determine that we are done with the edge, and so the computed 272cb93a386Sopenharmony_ci // left or rite edge will not be used (see update_edge). Use this helper to 273cb93a386Sopenharmony_ci // silence UBSAN when we perform the add. 274cb93a386Sopenharmony_ci left = Sk32_can_overflow_add(left, dLeft); 275cb93a386Sopenharmony_ci rite = Sk32_can_overflow_add(rite, dRite); 276cb93a386Sopenharmony_ci local_top += 1; 277cb93a386Sopenharmony_ci } while (--count >= 0); 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci leftE->fX = left; 281cb93a386Sopenharmony_ci riteE->fX = rite; 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci if (!update_edge(leftE, local_bot)) { 284cb93a386Sopenharmony_ci if (currE->fFirstY >= stop_y) { 285cb93a386Sopenharmony_ci return; // we're done 286cb93a386Sopenharmony_ci } 287cb93a386Sopenharmony_ci leftE = currE; 288cb93a386Sopenharmony_ci currE = currE->fNext; 289cb93a386Sopenharmony_ci ASSERT_RETURN(leftE->fFirstY == local_top); 290cb93a386Sopenharmony_ci } 291cb93a386Sopenharmony_ci if (!update_edge(riteE, local_bot)) { 292cb93a386Sopenharmony_ci if (currE->fFirstY >= stop_y) { 293cb93a386Sopenharmony_ci return; // we're done 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci riteE = currE; 296cb93a386Sopenharmony_ci currE = currE->fNext; 297cb93a386Sopenharmony_ci ASSERT_RETURN(riteE->fFirstY == local_top); 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci } 300cb93a386Sopenharmony_ci} 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 303cb93a386Sopenharmony_ci 304cb93a386Sopenharmony_ci// this overrides blitH, and will call its proxy blitter with the inverse 305cb93a386Sopenharmony_ci// of the spans it is given (clipped to the left/right of the cliprect) 306cb93a386Sopenharmony_ci// 307cb93a386Sopenharmony_ci// used to implement inverse filltypes on paths 308cb93a386Sopenharmony_ci// 309cb93a386Sopenharmony_ciclass InverseBlitter : public SkBlitter { 310cb93a386Sopenharmony_cipublic: 311cb93a386Sopenharmony_ci void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) { 312cb93a386Sopenharmony_ci fBlitter = blitter; 313cb93a386Sopenharmony_ci fFirstX = clip.fLeft << shift; 314cb93a386Sopenharmony_ci fLastX = clip.fRight << shift; 315cb93a386Sopenharmony_ci } 316cb93a386Sopenharmony_ci void prepost(int y, bool isStart) { 317cb93a386Sopenharmony_ci if (isStart) { 318cb93a386Sopenharmony_ci fPrevX = fFirstX; 319cb93a386Sopenharmony_ci } else { 320cb93a386Sopenharmony_ci int invWidth = fLastX - fPrevX; 321cb93a386Sopenharmony_ci if (invWidth > 0) { 322cb93a386Sopenharmony_ci fBlitter->blitH(fPrevX, y, invWidth); 323cb93a386Sopenharmony_ci } 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci // overrides 328cb93a386Sopenharmony_ci void blitH(int x, int y, int width) override { 329cb93a386Sopenharmony_ci int invWidth = x - fPrevX; 330cb93a386Sopenharmony_ci if (invWidth > 0) { 331cb93a386Sopenharmony_ci fBlitter->blitH(fPrevX, y, invWidth); 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci fPrevX = x + width; 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci // we do not expect to get called with these entrypoints 337cb93a386Sopenharmony_ci void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) override { 338cb93a386Sopenharmony_ci SkDEBUGFAIL("blitAntiH unexpected"); 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci void blitV(int x, int y, int height, SkAlpha alpha) override { 341cb93a386Sopenharmony_ci SkDEBUGFAIL("blitV unexpected"); 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci void blitRect(int x, int y, int width, int height) override { 344cb93a386Sopenharmony_ci SkDEBUGFAIL("blitRect unexpected"); 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci void blitMask(const SkMask&, const SkIRect& clip) override { 347cb93a386Sopenharmony_ci SkDEBUGFAIL("blitMask unexpected"); 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci const SkPixmap* justAnOpaqueColor(uint32_t* value) override { 350cb93a386Sopenharmony_ci SkDEBUGFAIL("justAnOpaqueColor unexpected"); 351cb93a386Sopenharmony_ci return nullptr; 352cb93a386Sopenharmony_ci } 353cb93a386Sopenharmony_ci 354cb93a386Sopenharmony_ciprivate: 355cb93a386Sopenharmony_ci SkBlitter* fBlitter; 356cb93a386Sopenharmony_ci int fFirstX, fLastX, fPrevX; 357cb93a386Sopenharmony_ci}; 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_cistatic void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) { 360cb93a386Sopenharmony_ci ((InverseBlitter*)blitter)->prepost(y, isStart); 361cb93a386Sopenharmony_ci} 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ci#if defined _WIN32 366cb93a386Sopenharmony_ci#pragma warning ( pop ) 367cb93a386Sopenharmony_ci#endif 368cb93a386Sopenharmony_ci 369cb93a386Sopenharmony_cistatic bool operator<(const SkEdge& a, const SkEdge& b) { 370cb93a386Sopenharmony_ci int valuea = a.fFirstY; 371cb93a386Sopenharmony_ci int valueb = b.fFirstY; 372cb93a386Sopenharmony_ci 373cb93a386Sopenharmony_ci if (valuea == valueb) { 374cb93a386Sopenharmony_ci valuea = a.fX; 375cb93a386Sopenharmony_ci valueb = b.fX; 376cb93a386Sopenharmony_ci } 377cb93a386Sopenharmony_ci 378cb93a386Sopenharmony_ci return valuea < valueb; 379cb93a386Sopenharmony_ci} 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_cistatic SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) { 382cb93a386Sopenharmony_ci SkTQSort(list, list + count); 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_ci // now make the edges linked in sorted order 385cb93a386Sopenharmony_ci for (int i = 1; i < count; i++) { 386cb93a386Sopenharmony_ci list[i - 1]->fNext = list[i]; 387cb93a386Sopenharmony_ci list[i]->fPrev = list[i - 1]; 388cb93a386Sopenharmony_ci } 389cb93a386Sopenharmony_ci 390cb93a386Sopenharmony_ci *last = list[count - 1]; 391cb93a386Sopenharmony_ci return list[0]; 392cb93a386Sopenharmony_ci} 393cb93a386Sopenharmony_ci 394cb93a386Sopenharmony_ci// clipRect has not been shifted up 395cb93a386Sopenharmony_civoid sk_fill_path(const SkPath& path, const SkIRect& clipRect, SkBlitter* blitter, 396cb93a386Sopenharmony_ci int start_y, int stop_y, int shiftEdgesUp, bool pathContainedInClip) { 397cb93a386Sopenharmony_ci SkASSERT(blitter); 398cb93a386Sopenharmony_ci 399cb93a386Sopenharmony_ci SkIRect shiftedClip = clipRect; 400cb93a386Sopenharmony_ci shiftedClip.fLeft = SkLeftShift(shiftedClip.fLeft, shiftEdgesUp); 401cb93a386Sopenharmony_ci shiftedClip.fRight = SkLeftShift(shiftedClip.fRight, shiftEdgesUp); 402cb93a386Sopenharmony_ci shiftedClip.fTop = SkLeftShift(shiftedClip.fTop, shiftEdgesUp); 403cb93a386Sopenharmony_ci shiftedClip.fBottom = SkLeftShift(shiftedClip.fBottom, shiftEdgesUp); 404cb93a386Sopenharmony_ci 405cb93a386Sopenharmony_ci SkBasicEdgeBuilder builder(shiftEdgesUp); 406cb93a386Sopenharmony_ci int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &shiftedClip); 407cb93a386Sopenharmony_ci SkEdge** list = builder.edgeList(); 408cb93a386Sopenharmony_ci 409cb93a386Sopenharmony_ci if (0 == count) { 410cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 411cb93a386Sopenharmony_ci /* 412cb93a386Sopenharmony_ci * Since we are in inverse-fill, our caller has already drawn above 413cb93a386Sopenharmony_ci * our top (start_y) and will draw below our bottom (stop_y). Thus 414cb93a386Sopenharmony_ci * we need to restrict our drawing to the intersection of the clip 415cb93a386Sopenharmony_ci * and those two limits. 416cb93a386Sopenharmony_ci */ 417cb93a386Sopenharmony_ci SkIRect rect = clipRect; 418cb93a386Sopenharmony_ci if (rect.fTop < start_y) { 419cb93a386Sopenharmony_ci rect.fTop = start_y; 420cb93a386Sopenharmony_ci } 421cb93a386Sopenharmony_ci if (rect.fBottom > stop_y) { 422cb93a386Sopenharmony_ci rect.fBottom = stop_y; 423cb93a386Sopenharmony_ci } 424cb93a386Sopenharmony_ci if (!rect.isEmpty()) { 425cb93a386Sopenharmony_ci blitter->blitRect(rect.fLeft << shiftEdgesUp, 426cb93a386Sopenharmony_ci rect.fTop << shiftEdgesUp, 427cb93a386Sopenharmony_ci rect.width() << shiftEdgesUp, 428cb93a386Sopenharmony_ci rect.height() << shiftEdgesUp); 429cb93a386Sopenharmony_ci } 430cb93a386Sopenharmony_ci } 431cb93a386Sopenharmony_ci return; 432cb93a386Sopenharmony_ci } 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci SkEdge headEdge, tailEdge, *last; 435cb93a386Sopenharmony_ci // this returns the first and last edge after they're sorted into a dlink list 436cb93a386Sopenharmony_ci SkEdge* edge = sort_edges(list, count, &last); 437cb93a386Sopenharmony_ci 438cb93a386Sopenharmony_ci headEdge.fPrev = nullptr; 439cb93a386Sopenharmony_ci headEdge.fNext = edge; 440cb93a386Sopenharmony_ci headEdge.fFirstY = kEDGE_HEAD_Y; 441cb93a386Sopenharmony_ci headEdge.fX = SK_MinS32; 442cb93a386Sopenharmony_ci edge->fPrev = &headEdge; 443cb93a386Sopenharmony_ci 444cb93a386Sopenharmony_ci tailEdge.fPrev = last; 445cb93a386Sopenharmony_ci tailEdge.fNext = nullptr; 446cb93a386Sopenharmony_ci tailEdge.fFirstY = kEDGE_TAIL_Y; 447cb93a386Sopenharmony_ci last->fNext = &tailEdge; 448cb93a386Sopenharmony_ci 449cb93a386Sopenharmony_ci // now edge is the head of the sorted linklist 450cb93a386Sopenharmony_ci 451cb93a386Sopenharmony_ci start_y = SkLeftShift(start_y, shiftEdgesUp); 452cb93a386Sopenharmony_ci stop_y = SkLeftShift(stop_y, shiftEdgesUp); 453cb93a386Sopenharmony_ci if (!pathContainedInClip && start_y < shiftedClip.fTop) { 454cb93a386Sopenharmony_ci start_y = shiftedClip.fTop; 455cb93a386Sopenharmony_ci } 456cb93a386Sopenharmony_ci if (!pathContainedInClip && stop_y > shiftedClip.fBottom) { 457cb93a386Sopenharmony_ci stop_y = shiftedClip.fBottom; 458cb93a386Sopenharmony_ci } 459cb93a386Sopenharmony_ci 460cb93a386Sopenharmony_ci InverseBlitter ib; 461cb93a386Sopenharmony_ci PrePostProc proc = nullptr; 462cb93a386Sopenharmony_ci 463cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 464cb93a386Sopenharmony_ci ib.setBlitter(blitter, clipRect, shiftEdgesUp); 465cb93a386Sopenharmony_ci blitter = &ib; 466cb93a386Sopenharmony_ci proc = PrePostInverseBlitterProc; 467cb93a386Sopenharmony_ci } 468cb93a386Sopenharmony_ci 469cb93a386Sopenharmony_ci // count >= 2 is required as the convex walker does not handle missing right edges 470cb93a386Sopenharmony_ci if (path.isConvex() && (nullptr == proc) && count >= 2) { 471cb93a386Sopenharmony_ci walk_simple_edges(&headEdge, blitter, start_y, stop_y); 472cb93a386Sopenharmony_ci } else { 473cb93a386Sopenharmony_ci walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, 474cb93a386Sopenharmony_ci shiftedClip.right()); 475cb93a386Sopenharmony_ci } 476cb93a386Sopenharmony_ci} 477cb93a386Sopenharmony_ci 478cb93a386Sopenharmony_civoid sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { 479cb93a386Sopenharmony_ci const SkIRect& cr = clip.getBounds(); 480cb93a386Sopenharmony_ci SkIRect tmp; 481cb93a386Sopenharmony_ci 482cb93a386Sopenharmony_ci tmp.fLeft = cr.fLeft; 483cb93a386Sopenharmony_ci tmp.fRight = cr.fRight; 484cb93a386Sopenharmony_ci tmp.fTop = cr.fTop; 485cb93a386Sopenharmony_ci tmp.fBottom = ir.fTop; 486cb93a386Sopenharmony_ci if (!tmp.isEmpty()) { 487cb93a386Sopenharmony_ci blitter->blitRectRegion(tmp, clip); 488cb93a386Sopenharmony_ci } 489cb93a386Sopenharmony_ci} 490cb93a386Sopenharmony_ci 491cb93a386Sopenharmony_civoid sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { 492cb93a386Sopenharmony_ci const SkIRect& cr = clip.getBounds(); 493cb93a386Sopenharmony_ci SkIRect tmp; 494cb93a386Sopenharmony_ci 495cb93a386Sopenharmony_ci tmp.fLeft = cr.fLeft; 496cb93a386Sopenharmony_ci tmp.fRight = cr.fRight; 497cb93a386Sopenharmony_ci tmp.fTop = ir.fBottom; 498cb93a386Sopenharmony_ci tmp.fBottom = cr.fBottom; 499cb93a386Sopenharmony_ci if (!tmp.isEmpty()) { 500cb93a386Sopenharmony_ci blitter->blitRectRegion(tmp, clip); 501cb93a386Sopenharmony_ci } 502cb93a386Sopenharmony_ci} 503cb93a386Sopenharmony_ci 504cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci/** 507cb93a386Sopenharmony_ci * If the caller is drawing an inverse-fill path, then it pass true for 508cb93a386Sopenharmony_ci * skipRejectTest, so we don't abort drawing just because the src bounds (ir) 509cb93a386Sopenharmony_ci * is outside of the clip. 510cb93a386Sopenharmony_ci */ 511cb93a386Sopenharmony_ciSkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, 512cb93a386Sopenharmony_ci const SkIRect& ir, bool skipRejectTest, bool irPreClipped) { 513cb93a386Sopenharmony_ci fBlitter = nullptr; // null means blit nothing 514cb93a386Sopenharmony_ci fClipRect = nullptr; 515cb93a386Sopenharmony_ci 516cb93a386Sopenharmony_ci if (clip) { 517cb93a386Sopenharmony_ci fClipRect = &clip->getBounds(); 518cb93a386Sopenharmony_ci if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out 519cb93a386Sopenharmony_ci return; 520cb93a386Sopenharmony_ci } 521cb93a386Sopenharmony_ci 522cb93a386Sopenharmony_ci if (clip->isRect()) { 523cb93a386Sopenharmony_ci if (!irPreClipped && fClipRect->contains(ir)) { 524cb93a386Sopenharmony_ci#ifdef SK_DEBUG 525cb93a386Sopenharmony_ci fRectClipCheckBlitter.init(blitter, *fClipRect); 526cb93a386Sopenharmony_ci blitter = &fRectClipCheckBlitter; 527cb93a386Sopenharmony_ci#endif 528cb93a386Sopenharmony_ci fClipRect = nullptr; 529cb93a386Sopenharmony_ci } else { 530cb93a386Sopenharmony_ci // only need a wrapper blitter if we're horizontally clipped 531cb93a386Sopenharmony_ci if (irPreClipped || 532cb93a386Sopenharmony_ci fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) { 533cb93a386Sopenharmony_ci fRectBlitter.init(blitter, *fClipRect); 534cb93a386Sopenharmony_ci blitter = &fRectBlitter; 535cb93a386Sopenharmony_ci } else { 536cb93a386Sopenharmony_ci#ifdef SK_DEBUG 537cb93a386Sopenharmony_ci fRectClipCheckBlitter.init(blitter, *fClipRect); 538cb93a386Sopenharmony_ci blitter = &fRectClipCheckBlitter; 539cb93a386Sopenharmony_ci#endif 540cb93a386Sopenharmony_ci } 541cb93a386Sopenharmony_ci } 542cb93a386Sopenharmony_ci } else { 543cb93a386Sopenharmony_ci fRgnBlitter.init(blitter, clip); 544cb93a386Sopenharmony_ci blitter = &fRgnBlitter; 545cb93a386Sopenharmony_ci } 546cb93a386Sopenharmony_ci } 547cb93a386Sopenharmony_ci fBlitter = blitter; 548cb93a386Sopenharmony_ci} 549cb93a386Sopenharmony_ci 550cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 551cb93a386Sopenharmony_ci 552cb93a386Sopenharmony_cistatic bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) { 553cb93a386Sopenharmony_ci // need to limit coordinates such that the width/height of our rect can be represented 554cb93a386Sopenharmony_ci // in SkFixed (16.16). See skbug.com/7998 555cb93a386Sopenharmony_ci const int32_t limit = 32767 >> 1; 556cb93a386Sopenharmony_ci 557cb93a386Sopenharmony_ci SkIRect limitR; 558cb93a386Sopenharmony_ci limitR.setLTRB(-limit, -limit, limit, limit); 559cb93a386Sopenharmony_ci if (limitR.contains(orig.getBounds())) { 560cb93a386Sopenharmony_ci return false; 561cb93a386Sopenharmony_ci } 562cb93a386Sopenharmony_ci reduced->op(orig, limitR, SkRegion::kIntersect_Op); 563cb93a386Sopenharmony_ci return true; 564cb93a386Sopenharmony_ci} 565cb93a386Sopenharmony_ci 566cb93a386Sopenharmony_ci// Bias used for conservative rounding of float rects to int rects, to nudge the irects a little 567cb93a386Sopenharmony_ci// larger, so we don't "think" a path's bounds are inside a clip, when (due to numeric drift in 568cb93a386Sopenharmony_ci// the scan-converter) we might walk beyond the predicted limits. 569cb93a386Sopenharmony_ci// 570cb93a386Sopenharmony_ci// This value has been determined trial and error: pick the smallest value (after the 0.5) that 571cb93a386Sopenharmony_ci// fixes any problematic cases (e.g. crbug.com/844457) 572cb93a386Sopenharmony_ci// NOTE: cubics appear to be the main reason for needing this slop. If we could (perhaps) have a 573cb93a386Sopenharmony_ci// more accurate walker for cubics, we may be able to reduce this fudge factor. 574cb93a386Sopenharmony_cistatic const double kConservativeRoundBias = 0.5 + 1.5 / SK_FDot6One; 575cb93a386Sopenharmony_ci 576cb93a386Sopenharmony_ci/** 577cb93a386Sopenharmony_ci * Round the value down. This is used to round the top and left of a rectangle, 578cb93a386Sopenharmony_ci * and corresponds to the way the scan converter treats the top and left edges. 579cb93a386Sopenharmony_ci * It has a slight bias to make the "rounded" int smaller than a normal round, to create a more 580cb93a386Sopenharmony_ci * conservative int-bounds (larger) from a float rect. 581cb93a386Sopenharmony_ci */ 582cb93a386Sopenharmony_cistatic inline int round_down_to_int(SkScalar x) { 583cb93a386Sopenharmony_ci double xx = x; 584cb93a386Sopenharmony_ci xx -= kConservativeRoundBias; 585cb93a386Sopenharmony_ci return sk_double_saturate2int(ceil(xx)); 586cb93a386Sopenharmony_ci} 587cb93a386Sopenharmony_ci 588cb93a386Sopenharmony_ci/** 589cb93a386Sopenharmony_ci * Round the value up. This is used to round the right and bottom of a rectangle. 590cb93a386Sopenharmony_ci * It has a slight bias to make the "rounded" int smaller than a normal round, to create a more 591cb93a386Sopenharmony_ci * conservative int-bounds (larger) from a float rect. 592cb93a386Sopenharmony_ci */ 593cb93a386Sopenharmony_cistatic inline int round_up_to_int(SkScalar x) { 594cb93a386Sopenharmony_ci double xx = x; 595cb93a386Sopenharmony_ci xx += kConservativeRoundBias; 596cb93a386Sopenharmony_ci return sk_double_saturate2int(floor(xx)); 597cb93a386Sopenharmony_ci} 598cb93a386Sopenharmony_ci 599cb93a386Sopenharmony_ci/* 600cb93a386Sopenharmony_ci * Conservative rounding function, which effectively nudges the int-rect to be slightly larger 601cb93a386Sopenharmony_ci * than SkRect::round() might have produced. This is a safety-net for the scan-converter, which 602cb93a386Sopenharmony_ci * inspects the returned int-rect, and may disable clipping (for speed) if it thinks all of the 603cb93a386Sopenharmony_ci * edges will fit inside the clip's bounds. The scan-converter introduces slight numeric errors 604cb93a386Sopenharmony_ci * due to accumulated += of the slope, so this function is used to return a conservatively large 605cb93a386Sopenharmony_ci * int-bounds, and thus we will only disable clipping if we're sure the edges will stay in-bounds. 606cb93a386Sopenharmony_ci */ 607cb93a386Sopenharmony_cistatic SkIRect conservative_round_to_int(const SkRect& src) { 608cb93a386Sopenharmony_ci return { 609cb93a386Sopenharmony_ci round_down_to_int(src.fLeft), 610cb93a386Sopenharmony_ci round_down_to_int(src.fTop), 611cb93a386Sopenharmony_ci round_up_to_int(src.fRight), 612cb93a386Sopenharmony_ci round_up_to_int(src.fBottom), 613cb93a386Sopenharmony_ci }; 614cb93a386Sopenharmony_ci} 615cb93a386Sopenharmony_ci 616cb93a386Sopenharmony_civoid SkScan::FillPath(const SkPath& path, const SkRegion& origClip, 617cb93a386Sopenharmony_ci SkBlitter* blitter) { 618cb93a386Sopenharmony_ci if (origClip.isEmpty()) { 619cb93a386Sopenharmony_ci return; 620cb93a386Sopenharmony_ci } 621cb93a386Sopenharmony_ci 622cb93a386Sopenharmony_ci // Our edges are fixed-point, and don't like the bounds of the clip to 623cb93a386Sopenharmony_ci // exceed that. Here we trim the clip just so we don't overflow later on 624cb93a386Sopenharmony_ci const SkRegion* clipPtr = &origClip; 625cb93a386Sopenharmony_ci SkRegion finiteClip; 626cb93a386Sopenharmony_ci if (clip_to_limit(origClip, &finiteClip)) { 627cb93a386Sopenharmony_ci if (finiteClip.isEmpty()) { 628cb93a386Sopenharmony_ci return; 629cb93a386Sopenharmony_ci } 630cb93a386Sopenharmony_ci clipPtr = &finiteClip; 631cb93a386Sopenharmony_ci } 632cb93a386Sopenharmony_ci // don't reference "origClip" any more, just use clipPtr 633cb93a386Sopenharmony_ci 634cb93a386Sopenharmony_ci 635cb93a386Sopenharmony_ci SkRect bounds = path.getBounds(); 636cb93a386Sopenharmony_ci bool irPreClipped = false; 637cb93a386Sopenharmony_ci if (!SkRectPriv::MakeLargeS32().contains(bounds)) { 638cb93a386Sopenharmony_ci if (!bounds.intersect(SkRectPriv::MakeLargeS32())) { 639cb93a386Sopenharmony_ci bounds.setEmpty(); 640cb93a386Sopenharmony_ci } 641cb93a386Sopenharmony_ci irPreClipped = true; 642cb93a386Sopenharmony_ci } 643cb93a386Sopenharmony_ci 644cb93a386Sopenharmony_ci SkIRect ir = conservative_round_to_int(bounds); 645cb93a386Sopenharmony_ci if (ir.isEmpty()) { 646cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 647cb93a386Sopenharmony_ci blitter->blitRegion(*clipPtr); 648cb93a386Sopenharmony_ci } 649cb93a386Sopenharmony_ci return; 650cb93a386Sopenharmony_ci } 651cb93a386Sopenharmony_ci 652cb93a386Sopenharmony_ci SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType(), irPreClipped); 653cb93a386Sopenharmony_ci 654cb93a386Sopenharmony_ci blitter = clipper.getBlitter(); 655cb93a386Sopenharmony_ci if (blitter) { 656cb93a386Sopenharmony_ci // we have to keep our calls to blitter in sorted order, so we 657cb93a386Sopenharmony_ci // must blit the above section first, then the middle, then the bottom. 658cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 659cb93a386Sopenharmony_ci sk_blit_above(blitter, ir, *clipPtr); 660cb93a386Sopenharmony_ci } 661cb93a386Sopenharmony_ci SkASSERT(clipper.getClipRect() == nullptr || 662cb93a386Sopenharmony_ci *clipper.getClipRect() == clipPtr->getBounds()); 663cb93a386Sopenharmony_ci sk_fill_path(path, clipPtr->getBounds(), blitter, ir.fTop, ir.fBottom, 664cb93a386Sopenharmony_ci 0, clipper.getClipRect() == nullptr); 665cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 666cb93a386Sopenharmony_ci sk_blit_below(blitter, ir, *clipPtr); 667cb93a386Sopenharmony_ci } 668cb93a386Sopenharmony_ci } else { 669cb93a386Sopenharmony_ci // what does it mean to not have a blitter if path.isInverseFillType??? 670cb93a386Sopenharmony_ci } 671cb93a386Sopenharmony_ci} 672cb93a386Sopenharmony_ci 673cb93a386Sopenharmony_civoid SkScan::FillPath(const SkPath& path, const SkIRect& ir, 674cb93a386Sopenharmony_ci SkBlitter* blitter) { 675cb93a386Sopenharmony_ci SkRegion rgn(ir); 676cb93a386Sopenharmony_ci FillPath(path, rgn, blitter); 677cb93a386Sopenharmony_ci} 678cb93a386Sopenharmony_ci 679cb93a386Sopenharmony_cibool SkScan::DowngradeClipAA(const SkIRect& bounds) { 680cb93a386Sopenharmony_ci SkRegion out; // ignored 681cb93a386Sopenharmony_ci return clip_to_limit(SkRegion(bounds), &out); 682cb93a386Sopenharmony_ci} 683cb93a386Sopenharmony_ci 684cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 685cb93a386Sopenharmony_ci 686cb93a386Sopenharmony_cistatic int build_tri_edges(SkEdge edge[], const SkPoint pts[], 687cb93a386Sopenharmony_ci const SkIRect* clipRect, SkEdge* list[]) { 688cb93a386Sopenharmony_ci SkEdge** start = list; 689cb93a386Sopenharmony_ci 690cb93a386Sopenharmony_ci if (edge->setLine(pts[0], pts[1], clipRect, 0)) { 691cb93a386Sopenharmony_ci *list++ = edge; 692cb93a386Sopenharmony_ci edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); 693cb93a386Sopenharmony_ci } 694cb93a386Sopenharmony_ci if (edge->setLine(pts[1], pts[2], clipRect, 0)) { 695cb93a386Sopenharmony_ci *list++ = edge; 696cb93a386Sopenharmony_ci edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); 697cb93a386Sopenharmony_ci } 698cb93a386Sopenharmony_ci if (edge->setLine(pts[2], pts[0], clipRect, 0)) { 699cb93a386Sopenharmony_ci *list++ = edge; 700cb93a386Sopenharmony_ci } 701cb93a386Sopenharmony_ci return (int)(list - start); 702cb93a386Sopenharmony_ci} 703cb93a386Sopenharmony_ci 704cb93a386Sopenharmony_ci 705cb93a386Sopenharmony_cistatic void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect, 706cb93a386Sopenharmony_ci SkBlitter* blitter, const SkIRect& ir) { 707cb93a386Sopenharmony_ci SkASSERT(pts && blitter); 708cb93a386Sopenharmony_ci 709cb93a386Sopenharmony_ci SkEdge edgeStorage[3]; 710cb93a386Sopenharmony_ci SkEdge* list[3]; 711cb93a386Sopenharmony_ci 712cb93a386Sopenharmony_ci int count = build_tri_edges(edgeStorage, pts, clipRect, list); 713cb93a386Sopenharmony_ci if (count < 2) { 714cb93a386Sopenharmony_ci return; 715cb93a386Sopenharmony_ci } 716cb93a386Sopenharmony_ci 717cb93a386Sopenharmony_ci SkEdge headEdge, tailEdge, *last; 718cb93a386Sopenharmony_ci 719cb93a386Sopenharmony_ci // this returns the first and last edge after they're sorted into a dlink list 720cb93a386Sopenharmony_ci SkEdge* edge = sort_edges(list, count, &last); 721cb93a386Sopenharmony_ci 722cb93a386Sopenharmony_ci headEdge.fPrev = nullptr; 723cb93a386Sopenharmony_ci headEdge.fNext = edge; 724cb93a386Sopenharmony_ci headEdge.fFirstY = kEDGE_HEAD_Y; 725cb93a386Sopenharmony_ci headEdge.fX = SK_MinS32; 726cb93a386Sopenharmony_ci edge->fPrev = &headEdge; 727cb93a386Sopenharmony_ci 728cb93a386Sopenharmony_ci tailEdge.fPrev = last; 729cb93a386Sopenharmony_ci tailEdge.fNext = nullptr; 730cb93a386Sopenharmony_ci tailEdge.fFirstY = kEDGE_TAIL_Y; 731cb93a386Sopenharmony_ci last->fNext = &tailEdge; 732cb93a386Sopenharmony_ci 733cb93a386Sopenharmony_ci // now edge is the head of the sorted linklist 734cb93a386Sopenharmony_ci int stop_y = ir.fBottom; 735cb93a386Sopenharmony_ci if (clipRect && stop_y > clipRect->fBottom) { 736cb93a386Sopenharmony_ci stop_y = clipRect->fBottom; 737cb93a386Sopenharmony_ci } 738cb93a386Sopenharmony_ci int start_y = ir.fTop; 739cb93a386Sopenharmony_ci if (clipRect && start_y < clipRect->fTop) { 740cb93a386Sopenharmony_ci start_y = clipRect->fTop; 741cb93a386Sopenharmony_ci } 742cb93a386Sopenharmony_ci walk_simple_edges(&headEdge, blitter, start_y, stop_y); 743cb93a386Sopenharmony_ci} 744cb93a386Sopenharmony_ci 745cb93a386Sopenharmony_civoid SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip, 746cb93a386Sopenharmony_ci SkBlitter* blitter) { 747cb93a386Sopenharmony_ci if (clip.isEmpty()) { 748cb93a386Sopenharmony_ci return; 749cb93a386Sopenharmony_ci } 750cb93a386Sopenharmony_ci 751cb93a386Sopenharmony_ci SkRect r; 752cb93a386Sopenharmony_ci r.setBounds(pts, 3); 753cb93a386Sopenharmony_ci // If r is too large (larger than can easily fit in SkFixed) then we need perform geometric 754cb93a386Sopenharmony_ci // clipping. This is a bit of work, so we just call the general FillPath() to handle it. 755cb93a386Sopenharmony_ci // Use FixedMax/2 as the limit so we can subtract two edges and still store that in Fixed. 756cb93a386Sopenharmony_ci const SkScalar limit = SK_MaxS16 >> 1; 757cb93a386Sopenharmony_ci if (!SkRect::MakeLTRB(-limit, -limit, limit, limit).contains(r)) { 758cb93a386Sopenharmony_ci SkPath path; 759cb93a386Sopenharmony_ci path.addPoly(pts, 3, false); 760cb93a386Sopenharmony_ci FillPath(path, clip, blitter); 761cb93a386Sopenharmony_ci return; 762cb93a386Sopenharmony_ci } 763cb93a386Sopenharmony_ci 764cb93a386Sopenharmony_ci SkIRect ir = conservative_round_to_int(r); 765cb93a386Sopenharmony_ci if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) { 766cb93a386Sopenharmony_ci return; 767cb93a386Sopenharmony_ci } 768cb93a386Sopenharmony_ci 769cb93a386Sopenharmony_ci SkAAClipBlitterWrapper wrap; 770cb93a386Sopenharmony_ci const SkRegion* clipRgn; 771cb93a386Sopenharmony_ci if (clip.isBW()) { 772cb93a386Sopenharmony_ci clipRgn = &clip.bwRgn(); 773cb93a386Sopenharmony_ci } else { 774cb93a386Sopenharmony_ci wrap.init(clip, blitter); 775cb93a386Sopenharmony_ci clipRgn = &wrap.getRgn(); 776cb93a386Sopenharmony_ci blitter = wrap.getBlitter(); 777cb93a386Sopenharmony_ci } 778cb93a386Sopenharmony_ci 779cb93a386Sopenharmony_ci SkScanClipper clipper(blitter, clipRgn, ir); 780cb93a386Sopenharmony_ci blitter = clipper.getBlitter(); 781cb93a386Sopenharmony_ci if (blitter) { 782cb93a386Sopenharmony_ci sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); 783cb93a386Sopenharmony_ci } 784cb93a386Sopenharmony_ci} 785