Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Functions
SkDashPath.cpp File Reference
#include "src/utils/SkDashPathPriv.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathEffect.h"
#include "include/core/SkPathMeasure.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkStrokeRec.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkAlign.h"
#include "include/private/base/SkFloatingPoint.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkPathEnums.h"
#include "src/core/SkPathPriv.h"
#include "src/core/SkPointPriv.h"
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <iterator>

Go to the source code of this file.

Classes

class  SpecialLineRec
 

Functions

static int is_even (int x)
 
static SkScalar find_first_interval (const SkScalar intervals[], SkScalar phase, int32_t *index, int count)
 
static void outset_for_stroke (SkRect *rect, const SkStrokeRec &rec)
 
static void adjust_zero_length_line (SkPoint pts[2])
 
static bool clip_line (SkPoint pts[2], const SkRect &bounds, SkScalar intervalLength, SkScalar priorPhase)
 
static bool cull_path (const SkPath &srcPath, const SkStrokeRec &rec, const SkRect *cullRect, SkScalar intervalLength, SkPath *dstPath)
 

Function Documentation

◆ adjust_zero_length_line()

static void adjust_zero_length_line ( SkPoint  pts[2])
static

Definition at line 109 of file SkDashPath.cpp.

109 {
110 SkASSERT(pts[0] == pts[1]);
111 pts[1].fX += std::max(1.001f, pts[1].fX) * SK_ScalarNearlyZero;
112}
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SK_ScalarNearlyZero
Definition SkScalar.h:99
float fX
x-axis value

◆ clip_line()

static bool clip_line ( SkPoint  pts[2],
const SkRect bounds,
SkScalar  intervalLength,
SkScalar  priorPhase 
)
static

Definition at line 114 of file SkDashPath.cpp.

115 {
116 SkVector dxy = pts[1] - pts[0];
117
118 // only horizontal or vertical lines
119 if (dxy.fX && dxy.fY) {
120 return false;
121 }
122 int xyOffset = SkToBool(dxy.fY); // 0 to adjust horizontal, 1 to adjust vertical
123
124 SkScalar minXY = (&pts[0].fX)[xyOffset];
125 SkScalar maxXY = (&pts[1].fX)[xyOffset];
126 bool swapped = maxXY < minXY;
127 if (swapped) {
128 using std::swap;
129 swap(minXY, maxXY);
130 }
131
132 SkASSERT(minXY <= maxXY);
133 SkScalar leftTop = (&bounds.fLeft)[xyOffset];
134 SkScalar rightBottom = (&bounds.fRight)[xyOffset];
135 if (maxXY < leftTop || minXY > rightBottom) {
136 return false;
137 }
138
139 // Now we actually perform the chop, removing the excess to the left/top and
140 // right/bottom of the bounds (keeping our new line "in phase" with the dash,
141 // hence the (mod intervalLength).
142
143 if (minXY < leftTop) {
144 minXY = leftTop - SkScalarMod(leftTop - minXY, intervalLength);
145 if (!swapped) {
146 minXY -= priorPhase; // for rectangles, adjust by prior phase
147 }
148 }
149 if (maxXY > rightBottom) {
150 maxXY = rightBottom + SkScalarMod(maxXY - rightBottom, intervalLength);
151 if (swapped) {
152 maxXY += priorPhase; // for rectangles, adjust by prior phase
153 }
154 }
155
156 SkASSERT(maxXY >= minXY);
157 if (swapped) {
158 using std::swap;
159 swap(minXY, maxXY);
160 }
161 (&pts[0].fX)[xyOffset] = minXY;
162 (&pts[1].fX)[xyOffset] = maxXY;
163
164 if (minXY == maxXY) {
166 }
167 return true;
168}
static void adjust_zero_length_line(SkPoint pts[2])
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition SkRefCnt.h:341
#define SkScalarMod(x, y)
Definition SkScalar.h:41
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
float SkScalar
Definition extension.cpp:12
Optional< SkRect > bounds
Definition SkRecords.h:189
float fY
y-axis value

◆ cull_path()

static bool cull_path ( const SkPath srcPath,
const SkStrokeRec rec,
const SkRect cullRect,
SkScalar  intervalLength,
SkPath dstPath 
)
static

Definition at line 173 of file SkDashPath.cpp.

174 {
175 if (!cullRect) {
176 SkPoint pts[2];
177 if (srcPath.isLine(pts) && pts[0] == pts[1]) {
179 dstPath->moveTo(pts[0]);
180 dstPath->lineTo(pts[1]);
181 return true;
182 }
183 return false;
184 }
185
187 bounds = *cullRect;
188 outset_for_stroke(&bounds, rec);
189
190 {
191 SkPoint pts[2];
192 if (srcPath.isLine(pts)) {
193 if (clip_line(pts, bounds, intervalLength, 0)) {
194 dstPath->moveTo(pts[0]);
195 dstPath->lineTo(pts[1]);
196 return true;
197 }
198 return false;
199 }
200 }
201
202 if (srcPath.isRect(nullptr)) {
203 // We'll break the rect into four lines, culling each separately.
204 SkPath::Iter iter(srcPath, false);
205
206 SkPoint pts[4]; // Rects are all moveTo and lineTo, so we'll only use pts[0] and pts[1].
207 SkAssertResult(SkPath::kMove_Verb == iter.next(pts));
208
209 double accum = 0; // Sum of unculled edge lengths to keep the phase correct.
210 // Intentionally a double to minimize the risk of overflow and drift.
211 while (iter.next(pts) == SkPath::kLine_Verb) {
212 // Notice this vector v and accum work with the original unclipped length.
213 SkVector v = pts[1] - pts[0];
214
215 if (clip_line(pts, bounds, intervalLength, std::fmod(accum, intervalLength))) {
216 // pts[0] may have just been changed by clip_line().
217 // If that's not where we ended the previous lineTo(), we need to moveTo() there.
218 SkPoint last;
219 if (!dstPath->getLastPt(&last) || last != pts[0]) {
220 dstPath->moveTo(pts[0]);
221 }
222 dstPath->lineTo(pts[1]);
223 }
224
225 // We either just traveled v.fX horizontally or v.fY vertically.
226 SkASSERT(v.fX == 0 || v.fY == 0);
227 accum += SkScalarAbs(v.fX + v.fY);
228 }
229 return !dstPath->isEmpty();
230 }
231
232 return false;
233}
#define SkAssertResult(cond)
Definition SkAssert.h:123
static bool clip_line(SkPoint pts[2], const SkRect &bounds, SkScalar intervalLength, SkScalar priorPhase)
static void outset_for_stroke(SkRect *rect, const SkStrokeRec &rec)
#define SkScalarAbs(x)
Definition SkScalar.h:39
bool isEmpty() const
Definition SkPath.cpp:406
SkPath & moveTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:678
bool isLine(SkPoint line[2]) const
Definition SkPath.cpp:388
bool getLastPt(SkPoint *lastPt) const
Definition SkPath.cpp:570
SkPath & lineTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:718
@ kMove_Verb
Definition SkPath.h:1458
@ kLine_Verb
Definition SkPath.h:1459
bool isRect(SkRect *rect, bool *isClosed=nullptr, SkPathDirection *direction=nullptr) const
Definition SkPath.cpp:506

◆ find_first_interval()

static SkScalar find_first_interval ( const SkScalar  intervals[],
SkScalar  phase,
int32_t *  index,
int  count 
)
static

Definition at line 35 of file SkDashPath.cpp.

36 {
37 for (int i = 0; i < count; ++i) {
38 SkScalar gap = intervals[i];
39 if (phase > gap || (phase == gap && gap)) {
40 phase -= gap;
41 } else {
42 *index = i;
43 return gap - phase;
44 }
45 }
46 // If we get here, phase "appears" to be larger than our length. This
47 // shouldn't happen with perfect precision, but we can accumulate errors
48 // during the initial length computation (rounding can make our sum be too
49 // big or too small. In that event, we just have to eat the error here.
50 *index = 0;
51 return intervals[0];
52}
int count

◆ is_even()

static int is_even ( int  x)
inlinestatic

Definition at line 31 of file SkDashPath.cpp.

31 {
32 return !(x & 1);
33}
double x

◆ outset_for_stroke()

static void outset_for_stroke ( SkRect rect,
const SkStrokeRec rec 
)
static

Definition at line 93 of file SkDashPath.cpp.

93 {
94 SkScalar radius = SkScalarHalf(rec.getWidth());
95 if (0 == radius) {
96 radius = SK_Scalar1; // hairlines
97 }
98 if (SkPaint::kMiter_Join == rec.getJoin()) {
99 radius *= rec.getMiter();
100 }
101 rect->outset(radius, radius);
102}
#define SK_Scalar1
Definition SkScalar.h:18
#define SkScalarHalf(a)
Definition SkScalar.h:75
@ kMiter_Join
extends to miter limit
Definition SkPaint.h:359
SkScalar getWidth() const
Definition SkStrokeRec.h:42
SkPaint::Join getJoin() const
Definition SkStrokeRec.h:45
SkScalar getMiter() const
Definition SkStrokeRec.h:43
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350