Flutter Engine
The Flutter Engine
Classes | Macros | Typedefs | Functions | Variables
SkScan_Path.cpp File Reference
#include "include/core/SkColor.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkRect.h"
#include "include/core/SkRegion.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkFixed.h"
#include "include/private/base/SkFloatingPoint.h"
#include "include/private/base/SkMacros.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkPoint_impl.h"
#include "include/private/base/SkSafe32.h"
#include "src/base/SkTSort.h"
#include "src/core/SkBlitter.h"
#include "src/core/SkEdge.h"
#include "src/core/SkEdgeBuilder.h"
#include "src/core/SkFDot6.h"
#include "src/core/SkRasterClip.h"
#include "src/core/SkRectPriv.h"
#include "src/core/SkScan.h"
#include "src/core/SkScanPriv.h"
#include <algorithm>
#include <cmath>
#include <cstdint>

Go to the source code of this file.

Classes

class  InverseBlitter
 

Macros

#define kEDGE_HEAD_Y   SK_MinS32
 
#define kEDGE_TAIL_Y   SK_MaxS32
 
#define validate_sort(edge)
 
#define validate_edges_for_y(edge, curr_y)
 
#define PREPOST_START   true
 
#define PREPOST_END   false
 
#define ASSERT_RETURN(cond)
 

Typedefs

typedef void(* PrePostProc) (SkBlitter *blitter, int y, bool isStartOfScanline)
 

Functions

static void insert_new_edges (SkEdge *newEdge, int curr_y)
 
static void walk_edges (SkEdge *prevHead, SkPathFillType fillType, SkBlitter *blitter, int start_y, int stop_y, PrePostProc proc, int rightClip)
 
static bool update_edge (SkEdge *edge, int last_y)
 
static void walk_simple_edges (SkEdge *prevHead, SkBlitter *blitter, int start_y, int stop_y)
 
static void PrePostInverseBlitterProc (SkBlitter *blitter, int y, bool isStart)
 
static bool operator< (const SkEdge &a, const SkEdge &b)
 
static SkEdgesort_edges (SkEdge *list[], int count, SkEdge **last)
 
void sk_fill_path (const SkPath &path, const SkIRect &clipRect, SkBlitter *blitter, int start_y, int stop_y, int shiftEdgesUp, bool pathContainedInClip)
 
void sk_blit_above (SkBlitter *blitter, const SkIRect &ir, const SkRegion &clip)
 
void sk_blit_below (SkBlitter *blitter, const SkIRect &ir, const SkRegion &clip)
 
static bool clip_to_limit (const SkRegion &orig, SkRegion *reduced)
 
static int round_down_to_int (SkScalar x)
 
static int round_up_to_int (SkScalar x)
 
static SkIRect conservative_round_to_int (const SkRect &src)
 
static int build_tri_edges (SkEdge edge[], const SkPoint pts[], const SkIRect *clipRect, SkEdge *list[])
 
static void sk_fill_triangle (const SkPoint pts[], const SkIRect *clipRect, SkBlitter *blitter, const SkIRect &ir)
 

Variables

static const double kConservativeRoundBias = 0.5 + 1.5 / SK_FDot6One
 

Macro Definition Documentation

◆ ASSERT_RETURN

#define ASSERT_RETURN (   cond)
Value:
do { \
if (!(cond)) { \
SkDEBUGFAILF("assert(%s)", #cond); \
return; \
} \
} while (0)

Definition at line 226 of file SkScan_Path.cpp.

◆ kEDGE_HEAD_Y

#define kEDGE_HEAD_Y   SK_MinS32

Definition at line 38 of file SkScan_Path.cpp.

◆ kEDGE_TAIL_Y

#define kEDGE_TAIL_Y   SK_MaxS32

Definition at line 39 of file SkScan_Path.cpp.

◆ PREPOST_END

#define PREPOST_END   false

Definition at line 111 of file SkScan_Path.cpp.

◆ PREPOST_START

#define PREPOST_START   true

Definition at line 110 of file SkScan_Path.cpp.

◆ validate_edges_for_y

#define validate_edges_for_y (   edge,
  curr_y 
)

Definition at line 101 of file SkScan_Path.cpp.

◆ validate_sort

#define validate_sort (   edge)

Definition at line 54 of file SkScan_Path.cpp.

Typedef Documentation

◆ PrePostProc

typedef void(* PrePostProc) (SkBlitter *blitter, int y, bool isStartOfScanline)

Definition at line 109 of file SkScan_Path.cpp.

Function Documentation

◆ build_tri_edges()

static int build_tri_edges ( SkEdge  edge[],
const SkPoint  pts[],
const SkIRect clipRect,
SkEdge list[] 
)
static

Definition at line 695 of file SkScan_Path.cpp.

696 {
697 SkEdge** start = list;
698
699 if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
700 *list++ = edge;
701 edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
702 }
703 if (edge->setLine(pts[1], pts[2], clipRect, 0)) {
704 *list++ = edge;
705 edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
706 }
707 if (edge->setLine(pts[2], pts[0], clipRect, 0)) {
708 *list++ = edge;
709 }
710 return (int)(list - start);
711}
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
Definition: SkEdge.h:27
int setLine(const SkPoint &p0, const SkPoint &p1, const SkIRect *clip, int shiftUp)
Definition: SkEdge.cpp:57

◆ clip_to_limit()

static bool clip_to_limit ( const SkRegion orig,
SkRegion reduced 
)
static

Definition at line 561 of file SkScan_Path.cpp.

561 {
562 // need to limit coordinates such that the width/height of our rect can be represented
563 // in SkFixed (16.16). See skbug.com/7998
564 const int32_t limit = 32767 >> 1;
565
566 SkIRect limitR;
567 limitR.setLTRB(-limit, -limit, limit, limit);
568 if (limitR.contains(orig.getBounds())) {
569 return false;
570 }
571 reduced->op(orig, limitR, SkRegion::kIntersect_Op);
572 return true;
573}
@ kIntersect_Op
target intersected with operand
Definition: SkRegion.h:368
const SkIRect & getBounds() const
Definition: SkRegion.h:165
bool op(const SkIRect &rect, Op op)
Definition: SkRegion.h:384
Definition: SkRect.h:32
void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom)
Definition: SkRect.h:253
bool contains(int32_t x, int32_t y) const
Definition: SkRect.h:463

◆ conservative_round_to_int()

static SkIRect conservative_round_to_int ( const SkRect src)
static

Definition at line 616 of file SkScan_Path.cpp.

616 {
617 return {
618 round_down_to_int(src.fLeft),
620 round_up_to_int(src.fRight),
621 round_up_to_int(src.fBottom),
622 };
623}
static int round_down_to_int(SkScalar x)
static int round_up_to_int(SkScalar x)

◆ insert_new_edges()

static void insert_new_edges ( SkEdge newEdge,
int  curr_y 
)
static

Definition at line 57 of file SkScan_Path.cpp.

57 {
58 if (newEdge->fFirstY != curr_y) {
59 return;
60 }
61 SkEdge* prev = newEdge->fPrev;
62 if (prev->fX <= newEdge->fX) {
63 return;
64 }
65 // find first x pos to insert
67 // insert the lot, fixing up the links as we go
68 do {
69 SkEdge* next = newEdge->fNext;
70 do {
71 if (start->fNext == newEdge) {
72 goto nextEdge;
73 }
74 SkEdge* after = start->fNext;
75 if (after->fX >= newEdge->fX) {
76 break;
77 }
78 start = after;
79 } while (true);
80 remove_edge(newEdge);
81 insert_edge_after(newEdge, start);
82nextEdge:
83 start = newEdge;
84 newEdge = next;
85 } while (newEdge->fFirstY == curr_y);
86}
static float next(float f)
static float prev(float f)
static void remove_edge(EdgeType *edge)
Definition: SkScanPriv.h:45
static void insert_edge_after(EdgeType *edge, EdgeType *afterMe)
Definition: SkScanPriv.h:51
EdgeType * backward_insert_start(EdgeType *prev, SkFixed x)
Definition: SkScanPriv.h:76
SkEdge * fNext
Definition: SkEdge.h:34
SkEdge * fPrev
Definition: SkEdge.h:35
SkFixed fX
Definition: SkEdge.h:37
int32_t fFirstY
Definition: SkEdge.h:39

◆ operator<()

static bool operator< ( const SkEdge a,
const SkEdge b 
)
static

Definition at line 378 of file SkScan_Path.cpp.

378 {
379 int valuea = a.fFirstY;
380 int valueb = b.fFirstY;
381
382 if (valuea == valueb) {
383 valuea = a.fX;
384 valueb = b.fX;
385 }
386
387 return valuea < valueb;
388}
static bool b
struct MyStruct a[10]

◆ PrePostInverseBlitterProc()

static void PrePostInverseBlitterProc ( SkBlitter blitter,
int  y,
bool  isStart 
)
static

Definition at line 368 of file SkScan_Path.cpp.

368 {
369 ((InverseBlitter*)blitter)->prepost(y, isStart);
370}
double y

◆ round_down_to_int()

static int round_down_to_int ( SkScalar  x)
inlinestatic

Round the value down. This is used to round the top and left of a rectangle, and corresponds to the way the scan converter treats the top and left edges. It has a slight bias to make the "rounded" int smaller than a normal round, to create a more conservative int-bounds (larger) from a float rect.

Definition at line 591 of file SkScan_Path.cpp.

591 {
592 double xx = x;
594 return sk_double_saturate2int(ceil(xx));
595}
static constexpr int sk_double_saturate2int(double x)
static const double kConservativeRoundBias
double x
SIN Vec< N, float > ceil(const Vec< N, float > &x)
Definition: SkVx.h:702

◆ round_up_to_int()

static int round_up_to_int ( SkScalar  x)
inlinestatic

Round the value up. This is used to round the right and bottom of a rectangle. It has a slight bias to make the "rounded" int smaller than a normal round, to create a more conservative int-bounds (larger) from a float rect.

Definition at line 602 of file SkScan_Path.cpp.

602 {
603 double xx = x;
605 return sk_double_saturate2int(floor(xx));
606}
SIN Vec< N, float > floor(const Vec< N, float > &x)
Definition: SkVx.h:703

◆ sk_blit_above()

void sk_blit_above ( SkBlitter blitter,
const SkIRect ir,
const SkRegion clip 
)

Definition at line 487 of file SkScan_Path.cpp.

487 {
488 const SkIRect& cr = clip.getBounds();
489 SkIRect tmp;
490
491 tmp.fLeft = cr.fLeft;
492 tmp.fRight = cr.fRight;
493 tmp.fTop = cr.fTop;
494 tmp.fBottom = ir.fTop;
495 if (!tmp.isEmpty()) {
496 blitter->blitRectRegion(tmp, clip);
497 }
498}
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
void blitRectRegion(const SkIRect &rect, const SkRegion &clip)
Definition: SkBlitter.cpp:300
const SkRect & getBounds() const
Definition: SkPath.cpp:430
int32_t fBottom
larger y-axis bounds
Definition: SkRect.h:36
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
bool isEmpty() const
Definition: SkRect.h:202
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33
int32_t fRight
larger x-axis bounds
Definition: SkRect.h:35

◆ sk_blit_below()

void sk_blit_below ( SkBlitter blitter,
const SkIRect ir,
const SkRegion clip 
)

Definition at line 500 of file SkScan_Path.cpp.

500 {
501 const SkIRect& cr = clip.getBounds();
502 SkIRect tmp;
503
504 tmp.fLeft = cr.fLeft;
505 tmp.fRight = cr.fRight;
506 tmp.fTop = ir.fBottom;
507 tmp.fBottom = cr.fBottom;
508 if (!tmp.isEmpty()) {
509 blitter->blitRectRegion(tmp, clip);
510 }
511}

◆ sk_fill_path()

void sk_fill_path ( const SkPath path,
const SkIRect clipRect,
SkBlitter blitter,
int  start_y,
int  stop_y,
int  shiftEdgesUp,
bool  pathContainedInClip 
)

Definition at line 404 of file SkScan_Path.cpp.

405 {
406 SkASSERT(blitter);
407
408 SkIRect shiftedClip = clipRect;
409 shiftedClip.fLeft = SkLeftShift(shiftedClip.fLeft, shiftEdgesUp);
410 shiftedClip.fRight = SkLeftShift(shiftedClip.fRight, shiftEdgesUp);
411 shiftedClip.fTop = SkLeftShift(shiftedClip.fTop, shiftEdgesUp);
412 shiftedClip.fBottom = SkLeftShift(shiftedClip.fBottom, shiftEdgesUp);
413
414 SkBasicEdgeBuilder builder(shiftEdgesUp);
415 int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &shiftedClip);
416 SkEdge** list = builder.edgeList();
417
418 if (0 == count) {
419 if (path.isInverseFillType()) {
420 /*
421 * Since we are in inverse-fill, our caller has already drawn above
422 * our top (start_y) and will draw below our bottom (stop_y). Thus
423 * we need to restrict our drawing to the intersection of the clip
424 * and those two limits.
425 */
427 if (rect.fTop < start_y) {
428 rect.fTop = start_y;
429 }
430 if (rect.fBottom > stop_y) {
431 rect.fBottom = stop_y;
432 }
433 if (!rect.isEmpty()) {
434 blitter->blitRect(rect.fLeft << shiftEdgesUp,
435 rect.fTop << shiftEdgesUp,
436 rect.width() << shiftEdgesUp,
437 rect.height() << shiftEdgesUp);
438 }
439 }
440 return;
441 }
442
443 SkEdge headEdge, tailEdge, *last;
444 // this returns the first and last edge after they're sorted into a dlink list
445 SkEdge* edge = sort_edges(list, count, &last);
446
447 headEdge.fPrev = nullptr;
448 headEdge.fNext = edge;
449 headEdge.fFirstY = kEDGE_HEAD_Y;
450 headEdge.fX = SK_MinS32;
451 edge->fPrev = &headEdge;
452
453 tailEdge.fPrev = last;
454 tailEdge.fNext = nullptr;
455 tailEdge.fFirstY = kEDGE_TAIL_Y;
456 last->fNext = &tailEdge;
457
458 // now edge is the head of the sorted linklist
459
460 start_y = SkLeftShift(start_y, shiftEdgesUp);
461 stop_y = SkLeftShift(stop_y, shiftEdgesUp);
462 if (!pathContainedInClip && start_y < shiftedClip.fTop) {
463 start_y = shiftedClip.fTop;
464 }
465 if (!pathContainedInClip && stop_y > shiftedClip.fBottom) {
466 stop_y = shiftedClip.fBottom;
467 }
468
470 PrePostProc proc = nullptr;
471
472 if (path.isInverseFillType()) {
473 ib.setBlitter(blitter, clipRect, shiftEdgesUp);
474 blitter = &ib;
476 }
477
478 // count >= 2 is required as the convex walker does not handle missing right edges
479 if (path.isConvex() && (nullptr == proc) && count >= 2) {
480 walk_simple_edges(&headEdge, blitter, start_y, stop_y);
481 } else {
482 walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc,
483 shiftedClip.right());
484 }
485}
int count
Definition: FontMgrTest.cpp:50
#define SkASSERT(cond)
Definition: SkAssert.h:116
static constexpr int32_t SkLeftShift(int32_t value, int32_t shift)
Definition: SkMath.h:37
static constexpr int32_t SK_MinS32
Definition: SkMath.h:22
static SkEdge * sort_edges(SkEdge *list[], int count, SkEdge **last)
#define kEDGE_HEAD_Y
Definition: SkScan_Path.cpp:38
static void walk_simple_edges(SkEdge *prevHead, SkBlitter *blitter, int start_y, int stop_y)
static void walk_edges(SkEdge *prevHead, SkPathFillType fillType, SkBlitter *blitter, int start_y, int stop_y, PrePostProc proc, int rightClip)
void(* PrePostProc)(SkBlitter *blitter, int y, bool isStartOfScanline)
#define kEDGE_TAIL_Y
Definition: SkScan_Path.cpp:39
static void PrePostInverseBlitterProc(SkBlitter *blitter, int y, bool isStart)
void setBlitter(SkBlitter *blitter, const SkIRect &clip, int shift)
virtual void blitRect(int x, int y, int width, int height)
Blit a solid rectangle one or more pixels wide.
Definition: SkBlitter.cpp:133
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57

◆ sk_fill_triangle()

static void sk_fill_triangle ( const SkPoint  pts[],
const SkIRect clipRect,
SkBlitter blitter,
const SkIRect ir 
)
static

Definition at line 714 of file SkScan_Path.cpp.

715 {
716 SkASSERT(pts && blitter);
717
718 SkEdge edgeStorage[3];
719 SkEdge* list[3];
720
721 int count = build_tri_edges(edgeStorage, pts, clipRect, list);
722 if (count < 2) {
723 return;
724 }
725
726 SkEdge headEdge, tailEdge, *last;
727
728 // this returns the first and last edge after they're sorted into a dlink list
729 SkEdge* edge = sort_edges(list, count, &last);
730
731 headEdge.fPrev = nullptr;
732 headEdge.fNext = edge;
733 headEdge.fFirstY = kEDGE_HEAD_Y;
734 headEdge.fX = SK_MinS32;
735 edge->fPrev = &headEdge;
736
737 tailEdge.fPrev = last;
738 tailEdge.fNext = nullptr;
739 tailEdge.fFirstY = kEDGE_TAIL_Y;
740 last->fNext = &tailEdge;
741
742 // now edge is the head of the sorted linklist
743 int stop_y = ir.fBottom;
744 if (clipRect && stop_y > clipRect->fBottom) {
745 stop_y = clipRect->fBottom;
746 }
747 int start_y = ir.fTop;
748 if (clipRect && start_y < clipRect->fTop) {
749 start_y = clipRect->fTop;
750 }
751 walk_simple_edges(&headEdge, blitter, start_y, stop_y);
752}
static int build_tri_edges(SkEdge edge[], const SkPoint pts[], const SkIRect *clipRect, SkEdge *list[])

◆ sort_edges()

static SkEdge * sort_edges ( SkEdge list[],
int  count,
SkEdge **  last 
)
static

Definition at line 390 of file SkScan_Path.cpp.

390 {
391 SkTQSort(list, list + count);
392
393 // now make the edges linked in sorted order
394 for (int i = 1; i < count; i++) {
395 list[i - 1]->fNext = list[i];
396 list[i]->fPrev = list[i - 1];
397 }
398
399 *last = list[count - 1];
400 return list[0];
401}
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition: SkTSort.h:194

◆ update_edge()

static bool update_edge ( SkEdge edge,
int  last_y 
)
static

Definition at line 206 of file SkScan_Path.cpp.

206 {
207 SkASSERT(edge->fLastY >= last_y);
208 if (last_y == edge->fLastY) {
209 if (edge->fCurveCount < 0) {
210 if (((SkCubicEdge*)edge)->updateCubic()) {
211 SkASSERT(edge->fFirstY == last_y + 1);
212 return true;
213 }
214 } else if (edge->fCurveCount > 0) {
215 if (((SkQuadraticEdge*)edge)->updateQuadratic()) {
216 SkASSERT(edge->fFirstY == last_y + 1);
217 return true;
218 }
219 }
220 return false;
221 }
222 return true;
223}
int32_t fLastY
Definition: SkEdge.h:40
int8_t fCurveCount
Definition: SkEdge.h:42

◆ walk_edges()

static void walk_edges ( SkEdge prevHead,
SkPathFillType  fillType,
SkBlitter blitter,
int  start_y,
int  stop_y,
PrePostProc  proc,
int  rightClip 
)
static

Definition at line 113 of file SkScan_Path.cpp.

115 {
116 validate_sort(prevHead->fNext);
117
118 int curr_y = start_y;
119 int windingMask = SkPathFillType_IsEvenOdd(fillType) ? 1 : -1;
120
121 for (;;) {
122 int w = 0;
124 SkEdge* currE = prevHead->fNext;
125 SkFixed prevX = prevHead->fX;
126
127 validate_edges_for_y(currE, curr_y);
128
129 if (proc) {
130 proc(blitter, curr_y, PREPOST_START); // pre-proc
131 }
132
133 while (currE->fFirstY <= curr_y) {
134 SkASSERT(currE->fLastY >= curr_y);
135
136 int x = SkFixedRoundToInt(currE->fX);
137
138 if ((w & windingMask) == 0) { // we're starting interval
139 left = x;
140 }
141
142 w += currE->fWinding;
143
144 if ((w & windingMask) == 0) { // we finished an interval
145 int width = x - left;
146 SkASSERT(width >= 0);
147 if (width > 0) {
148 blitter->blitH(left, curr_y, width);
149 }
150 }
151
152 SkEdge* next = currE->fNext;
153 SkFixed newX;
154
155 if (currE->fLastY == curr_y) { // are we done with this edge?
156 if (currE->fCurveCount > 0) {
157 if (((SkQuadraticEdge*)currE)->updateQuadratic()) {
158 newX = currE->fX;
159 goto NEXT_X;
160 }
161 } else if (currE->fCurveCount < 0) {
162 if (((SkCubicEdge*)currE)->updateCubic()) {
163 SkASSERT(currE->fFirstY == curr_y + 1);
164
165 newX = currE->fX;
166 goto NEXT_X;
167 }
168 }
169 remove_edge(currE);
170 } else {
171 SkASSERT(currE->fLastY > curr_y);
172 newX = currE->fX + currE->fDX;
173 currE->fX = newX;
174 NEXT_X:
175 if (newX < prevX) { // ripple currE backwards until it is x-sorted
177 } else {
178 prevX = newX;
179 }
180 }
181 currE = next;
182 SkASSERT(currE);
183 }
184
185 if ((w & windingMask) != 0) { // was our right-edge culled away?
186 int width = rightClip - left;
187 if (width > 0) {
188 blitter->blitH(left, curr_y, width);
189 }
190 }
191
192 if (proc) {
193 proc(blitter, curr_y, PREPOST_END); // post-proc
194 }
195
196 curr_y += 1;
197 if (curr_y >= stop_y) {
198 break;
199 }
200 // now currE points to the first edge with a Yint larger than curr_y
201 insert_new_edges(currE, curr_y);
202 }
203}
int32_t SkFixed
Definition: SkFixed.h:25
#define SkFixedRoundToInt(x)
Definition: SkFixed.h:76
#define SK_INIT_TO_AVOID_WARNING
Definition: SkMacros.h:58
static bool SkPathFillType_IsEvenOdd(SkPathFillType ft)
Definition: SkPathTypes.h:22
static bool left(const SkPoint &p0, const SkPoint &p1)
void backward_insert_edge_based_on_x(EdgeType *edge)
Definition: SkScanPriv.h:59
#define validate_edges_for_y(edge, curr_y)
#define PREPOST_END
static void insert_new_edges(SkEdge *newEdge, int curr_y)
Definition: SkScan_Path.cpp:57
#define PREPOST_START
#define validate_sort(edge)
Definition: SkScan_Path.cpp:54
virtual void blitH(int x, int y, int width)=0
Blit a horizontal run of one or more pixels.
SkScalar w
int32_t width
int8_t fWinding
Definition: SkEdge.h:45
SkFixed fDX
Definition: SkEdge.h:38

◆ walk_simple_edges()

static void walk_simple_edges ( SkEdge prevHead,
SkBlitter blitter,
int  start_y,
int  stop_y 
)
static

Definition at line 235 of file SkScan_Path.cpp.

235 {
236 validate_sort(prevHead->fNext);
237
238 SkEdge* leftE = prevHead->fNext;
239 SkEdge* riteE = leftE->fNext;
240 SkEdge* currE = riteE->fNext;
241
242 // our edge choppers for curves can result in the initial edges
243 // not lining up, so we take the max.
244 int local_top = std::max(leftE->fFirstY, riteE->fFirstY);
245 ASSERT_RETURN(local_top >= start_y);
246
247 while (local_top < stop_y) {
248 SkASSERT(leftE->fFirstY <= stop_y);
249 SkASSERT(riteE->fFirstY <= stop_y);
250
251 int local_bot = std::min(leftE->fLastY, riteE->fLastY);
252 local_bot = std::min(local_bot, stop_y - 1);
253 ASSERT_RETURN(local_top <= local_bot);
254
255 SkFixed left = leftE->fX;
256 SkFixed dLeft = leftE->fDX;
257 SkFixed rite = riteE->fX;
258 SkFixed dRite = riteE->fDX;
259 int count = local_bot - local_top;
260 ASSERT_RETURN(count >= 0);
261
262 if (0 == (dLeft | dRite)) {
263 int L = SkFixedRoundToInt(left);
264 int R = SkFixedRoundToInt(rite);
265 if (L > R) {
266 std::swap(L, R);
267 }
268 if (L < R) {
269 count += 1;
270 blitter->blitRect(L, local_top, R - L, count);
271 }
272 local_top = local_bot + 1;
273 } else {
274 do {
275 int L = SkFixedRoundToInt(left);
276 int R = SkFixedRoundToInt(rite);
277 if (L > R) {
278 std::swap(L, R);
279 }
280 if (L < R) {
281 blitter->blitH(L, local_top, R - L);
282 }
283 // Either/both of these might overflow, since we perform this step even if
284 // (later) we determine that we are done with the edge, and so the computed
285 // left or rite edge will not be used (see update_edge). Use this helper to
286 // silence UBSAN when we perform the add.
288 rite = Sk32_can_overflow_add(rite, dRite);
289 local_top += 1;
290 } while (--count >= 0);
291 }
292
293 leftE->fX = left;
294 riteE->fX = rite;
295
296 if (!update_edge(leftE, local_bot)) {
297 if (currE->fFirstY >= stop_y) {
298 return; // we're done
299 }
300 leftE = currE;
301 currE = currE->fNext;
302 ASSERT_RETURN(leftE->fFirstY == local_top);
303 }
304 if (!update_edge(riteE, local_bot)) {
305 if (currE->fFirstY >= stop_y) {
306 return; // we're done
307 }
308 riteE = currE;
309 currE = currE->fNext;
310 ASSERT_RETURN(riteE->fFirstY == local_top);
311 }
312 }
313}
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
static constexpr int32_t Sk32_can_overflow_add(int32_t a, int32_t b)
Definition: SkSafe32.h:30
#define ASSERT_RETURN(cond)
static bool update_edge(SkEdge *edge, int last_y)
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
#define R(r)

Variable Documentation

◆ kConservativeRoundBias

const double kConservativeRoundBias = 0.5 + 1.5 / SK_FDot6One
static

Definition at line 583 of file SkScan_Path.cpp.