Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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/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 225 of file SkScan_Path.cpp.

226 { \
227 if (!(cond)) { \
228 SkDEBUGFAILF("assert(%s)", #cond); \
229 return; \
230 } \
231 } while (0)

◆ kEDGE_HEAD_Y

#define kEDGE_HEAD_Y   SK_MinS32

Definition at line 37 of file SkScan_Path.cpp.

◆ kEDGE_TAIL_Y

#define kEDGE_TAIL_Y   SK_MaxS32

Definition at line 38 of file SkScan_Path.cpp.

◆ PREPOST_END

#define PREPOST_END   false

Definition at line 110 of file SkScan_Path.cpp.

◆ PREPOST_START

#define PREPOST_START   true

Definition at line 109 of file SkScan_Path.cpp.

◆ validate_edges_for_y

#define validate_edges_for_y (   edge,
  curr_y 
)

Definition at line 100 of file SkScan_Path.cpp.

◆ validate_sort

#define validate_sort (   edge)

Definition at line 53 of file SkScan_Path.cpp.

Typedef Documentation

◆ PrePostProc

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

Definition at line 108 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 694 of file SkScan_Path.cpp.

695 {
696 SkEdge** start = list;
697
698 if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
699 *list++ = edge;
700 edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
701 }
702 if (edge->setLine(pts[1], pts[2], clipRect, 0)) {
703 *list++ = edge;
704 edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
705 }
706 if (edge->setLine(pts[2], pts[0], clipRect, 0)) {
707 *list++ = edge;
708 }
709 return (int)(list - start);
710}
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 560 of file SkScan_Path.cpp.

560 {
561 // need to limit coordinates such that the width/height of our rect can be represented
562 // in SkFixed (16.16). See skbug.com/7998
563 const int32_t limit = 32767 >> 1;
564
565 SkIRect limitR;
566 limitR.setLTRB(-limit, -limit, limit, limit);
567 if (limitR.contains(orig.getBounds())) {
568 return false;
569 }
570 reduced->op(orig, limitR, SkRegion::kIntersect_Op);
571 return true;
572}
@ 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
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 615 of file SkScan_Path.cpp.

615 {
616 return {
617 round_down_to_int(src.fLeft),
619 round_up_to_int(src.fRight),
620 round_up_to_int(src.fBottom),
621 };
622}
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 56 of file SkScan_Path.cpp.

56 {
57 if (newEdge->fFirstY != curr_y) {
58 return;
59 }
60 SkEdge* prev = newEdge->fPrev;
61 if (prev->fX <= newEdge->fX) {
62 return;
63 }
64 // find first x pos to insert
66 // insert the lot, fixing up the links as we go
67 do {
68 SkEdge* next = newEdge->fNext;
69 do {
70 if (start->fNext == newEdge) {
71 goto nextEdge;
72 }
73 SkEdge* after = start->fNext;
74 if (after->fX >= newEdge->fX) {
75 break;
76 }
77 start = after;
78 } while (true);
79 remove_edge(newEdge);
80 insert_edge_after(newEdge, start);
81nextEdge:
82 start = newEdge;
83 newEdge = next;
84 } while (newEdge->fFirstY == curr_y);
85}
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:33
SkEdge * fPrev
Definition SkEdge.h:34
SkFixed fX
Definition SkEdge.h:36
int32_t fFirstY
Definition SkEdge.h:38

◆ operator<()

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

Definition at line 377 of file SkScan_Path.cpp.

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

◆ PrePostInverseBlitterProc()

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

Definition at line 367 of file SkScan_Path.cpp.

367 {
368 ((InverseBlitter*)blitter)->prepost(y, isStart);
369}
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 590 of file SkScan_Path.cpp.

590 {
591 double xx = x;
593 return sk_double_saturate2int(ceil(xx));
594}
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 601 of file SkScan_Path.cpp.

601 {
602 double xx = x;
604 return sk_double_saturate2int(floor(xx));
605}
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 486 of file SkScan_Path.cpp.

486 {
487 const SkIRect& cr = clip.getBounds();
488 SkIRect tmp;
489
490 tmp.fLeft = cr.fLeft;
491 tmp.fRight = cr.fRight;
492 tmp.fTop = cr.fTop;
493 tmp.fBottom = ir.fTop;
494 if (!tmp.isEmpty()) {
495 blitter->blitRectRegion(tmp, clip);
496 }
497}
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
void blitRectRegion(const SkIRect &rect, const SkRegion &clip)
const SkRect & getBounds() const
Definition SkPath.cpp:420
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 499 of file SkScan_Path.cpp.

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

◆ 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 403 of file SkScan_Path.cpp.

404 {
405 SkASSERT(blitter);
406
407 SkIRect shiftedClip = clipRect;
408 shiftedClip.fLeft = SkLeftShift(shiftedClip.fLeft, shiftEdgesUp);
409 shiftedClip.fRight = SkLeftShift(shiftedClip.fRight, shiftEdgesUp);
410 shiftedClip.fTop = SkLeftShift(shiftedClip.fTop, shiftEdgesUp);
411 shiftedClip.fBottom = SkLeftShift(shiftedClip.fBottom, shiftEdgesUp);
412
413 SkBasicEdgeBuilder builder(shiftEdgesUp);
414 int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &shiftedClip);
415 SkEdge** list = builder.edgeList();
416
417 if (0 == count) {
418 if (path.isInverseFillType()) {
419 /*
420 * Since we are in inverse-fill, our caller has already drawn above
421 * our top (start_y) and will draw below our bottom (stop_y). Thus
422 * we need to restrict our drawing to the intersection of the clip
423 * and those two limits.
424 */
426 if (rect.fTop < start_y) {
427 rect.fTop = start_y;
428 }
429 if (rect.fBottom > stop_y) {
430 rect.fBottom = stop_y;
431 }
432 if (!rect.isEmpty()) {
433 blitter->blitRect(rect.fLeft << shiftEdgesUp,
434 rect.fTop << shiftEdgesUp,
435 rect.width() << shiftEdgesUp,
436 rect.height() << shiftEdgesUp);
437 }
438 }
439 return;
440 }
441
442 SkEdge headEdge, tailEdge, *last;
443 // this returns the first and last edge after they're sorted into a dlink list
444 SkEdge* edge = sort_edges(list, count, &last);
445
446 headEdge.fPrev = nullptr;
447 headEdge.fNext = edge;
448 headEdge.fFirstY = kEDGE_HEAD_Y;
449 headEdge.fX = SK_MinS32;
450 edge->fPrev = &headEdge;
451
452 tailEdge.fPrev = last;
453 tailEdge.fNext = nullptr;
454 tailEdge.fFirstY = kEDGE_TAIL_Y;
455 last->fNext = &tailEdge;
456
457 // now edge is the head of the sorted linklist
458
459 start_y = SkLeftShift(start_y, shiftEdgesUp);
460 stop_y = SkLeftShift(stop_y, shiftEdgesUp);
461 if (!pathContainedInClip && start_y < shiftedClip.fTop) {
462 start_y = shiftedClip.fTop;
463 }
464 if (!pathContainedInClip && stop_y > shiftedClip.fBottom) {
465 stop_y = shiftedClip.fBottom;
466 }
467
469 PrePostProc proc = nullptr;
470
471 if (path.isInverseFillType()) {
472 ib.setBlitter(blitter, clipRect, shiftEdgesUp);
473 blitter = &ib;
475 }
476
477 // count >= 2 is required as the convex walker does not handle missing right edges
478 if (path.isConvex() && (nullptr == proc) && count >= 2) {
479 walk_simple_edges(&headEdge, blitter, start_y, stop_y);
480 } else {
481 walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc,
482 shiftedClip.right());
483 }
484}
int count
#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
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
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.
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
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
constexpr int32_t right() const
Definition SkRect.h:127

◆ sk_fill_triangle()

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

Definition at line 713 of file SkScan_Path.cpp.

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

389 {
390 SkTQSort(list, list + count);
391
392 // now make the edges linked in sorted order
393 for (int i = 1; i < count; i++) {
394 list[i - 1]->fNext = list[i];
395 list[i]->fPrev = list[i - 1];
396 }
397
398 *last = list[count - 1];
399 return list[0];
400}
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 205 of file SkScan_Path.cpp.

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

◆ 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 112 of file SkScan_Path.cpp.

114 {
115 validate_sort(prevHead->fNext);
116
117 int curr_y = start_y;
118 int windingMask = SkPathFillType_IsEvenOdd(fillType) ? 1 : -1;
119
120 for (;;) {
121 int w = 0;
123 SkEdge* currE = prevHead->fNext;
124 SkFixed prevX = prevHead->fX;
125
126 validate_edges_for_y(currE, curr_y);
127
128 if (proc) {
129 proc(blitter, curr_y, PREPOST_START); // pre-proc
130 }
131
132 while (currE->fFirstY <= curr_y) {
133 SkASSERT(currE->fLastY >= curr_y);
134
135 int x = SkFixedRoundToInt(currE->fX);
136
137 if ((w & windingMask) == 0) { // we're starting interval
138 left = x;
139 }
140
141 w += currE->fWinding;
142
143 if ((w & windingMask) == 0) { // we finished an interval
144 int width = x - left;
145 SkASSERT(width >= 0);
146 if (width > 0) {
147 blitter->blitH(left, curr_y, width);
148 }
149 }
150
151 SkEdge* next = currE->fNext;
152 SkFixed newX;
153
154 if (currE->fLastY == curr_y) { // are we done with this edge?
155 if (currE->fCurveCount > 0) {
156 if (((SkQuadraticEdge*)currE)->updateQuadratic()) {
157 newX = currE->fX;
158 goto NEXT_X;
159 }
160 } else if (currE->fCurveCount < 0) {
161 if (((SkCubicEdge*)currE)->updateCubic()) {
162 SkASSERT(currE->fFirstY == curr_y + 1);
163
164 newX = currE->fX;
165 goto NEXT_X;
166 }
167 }
168 remove_edge(currE);
169 } else {
170 SkASSERT(currE->fLastY > curr_y);
171 newX = currE->fX + currE->fDX;
172 currE->fX = newX;
173 NEXT_X:
174 if (newX < prevX) { // ripple currE backwards until it is x-sorted
176 } else {
177 prevX = newX;
178 }
179 }
180 currE = next;
181 SkASSERT(currE);
182 }
183
184 if ((w & windingMask) != 0) { // was our right-edge culled away?
185 int width = rightClip - left;
186 if (width > 0) {
187 blitter->blitH(left, curr_y, width);
188 }
189 }
190
191 if (proc) {
192 proc(blitter, curr_y, PREPOST_END); // post-proc
193 }
194
195 curr_y += 1;
196 if (curr_y >= stop_y) {
197 break;
198 }
199 // now currE points to the first edge with a Yint larger than curr_y
200 insert_new_edges(currE, curr_y);
201 }
202}
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)
#define PREPOST_START
#define validate_sort(edge)
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:44
SkFixed fDX
Definition SkEdge.h:37

◆ walk_simple_edges()

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

Definition at line 234 of file SkScan_Path.cpp.

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

Variable Documentation

◆ kConservativeRoundBias

const double kConservativeRoundBias = 0.5 + 1.5 / SK_FDot6One
static

Definition at line 582 of file SkScan_Path.cpp.