Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(660)

Side by Side Diff: src/effects/SkDashPathEffect.cpp

Issue 699623003: Crop the fast path dashed lines to the cull rect (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address coordinate xform issue Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkDraw.cpp ('k') | src/utils/SkDashPath.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2006 The Android Open Source Project 2 * Copyright 2006 The Android Open Source Project
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkDashPathEffect.h" 8 #include "SkDashPathEffect.h"
9 9
10 #include "SkDashPathPriv.h" 10 #include "SkDashPathPriv.h"
(...skipping 23 matching lines...) Expand all
34 SkDashPathEffect::~SkDashPathEffect() { 34 SkDashPathEffect::~SkDashPathEffect() {
35 sk_free(fIntervals); 35 sk_free(fIntervals);
36 } 36 }
37 37
38 bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, 38 bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src,
39 SkStrokeRec* rec, const SkRect* cullRect) const { 39 SkStrokeRec* rec, const SkRect* cullRect) const {
40 return SkDashPath::FilterDashPath(dst, src, rec, cullRect, fIntervals, fCoun t, 40 return SkDashPath::FilterDashPath(dst, src, rec, cullRect, fIntervals, fCoun t,
41 fInitialDashLength, fInitialDashIndex, fIn tervalLength); 41 fInitialDashLength, fInitialDashIndex, fIn tervalLength);
42 } 42 }
43 43
44 static void outset_for_stroke(SkRect* rect, const SkStrokeRec& rec) {
45 SkScalar radius = SkScalarHalf(rec.getWidth());
46 if (0 == radius) {
47 radius = SK_Scalar1; // hairlines
48 }
49 if (SkPaint::kMiter_Join == rec.getJoin()) {
50 radius = SkScalarMul(radius, rec.getMiter());
51 }
52 rect->outset(radius, radius);
53 }
54
55 // Attempt to trim the line to minimally cover the cull rect (currently
56 // only works for horizontal and vertical lines).
57 // Return true if processing should continue; false otherwise.
58 static bool cull_line(SkPoint* pts, const SkStrokeRec& rec,
59 const SkMatrix& ctm, const SkRect* cullRect,
60 const SkScalar intervalLength) {
61 if (NULL == cullRect) {
62 SkASSERT(false); // Shouldn't ever occur in practice
63 return false;
64 }
65
66 SkScalar dx = pts[1].x() - pts[0].x();
67 SkScalar dy = pts[1].y() - pts[0].y();
68
69 if (dx && dy) {
70 return false;
71 }
72
73 SkRect bounds = *cullRect;
74 outset_for_stroke(&bounds, rec);
75
76 // cullRect is in device space while pts are in the local coordinate system
77 // defined by the ctm. We want our answer in the local coordinate system.
78
79 SkASSERT(ctm.rectStaysRect());
80 SkMatrix inv;
81 if (!ctm.invert(&inv)) {
82 return false;
83 }
84
85 inv.mapRect(&bounds);
86
87 if (dx) {
88 SkASSERT(dx && !dy);
89 SkScalar minX = pts[0].fX;
90 SkScalar maxX = pts[1].fX;
91
92 if (dx < 0) {
93 SkTSwap(minX, maxX);
94 }
95
96 SkASSERT(minX < maxX);
97 if (maxX < bounds.fLeft || minX > bounds.fRight) {
98 return false;
99 }
100
101 // Now we actually perform the chop, removing the excess to the left and
102 // right of the bounds (keeping our new line "in phase" with the dash,
103 // hence the (mod intervalLength).
104
105 if (minX < bounds.fLeft) {
106 minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX, intervalLengt h);
107 }
108 if (maxX > bounds.fRight) {
109 maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight, intervalLen gth);
110 }
111
112 SkASSERT(maxX > minX);
113 if (dx < 0) {
114 SkTSwap(minX, maxX);
115 }
116 pts[0].fX = minX;
117 pts[1].fX = maxX;
118 } else {
119 SkASSERT(dy && !dx);
120 SkScalar minY = pts[0].fY;
121 SkScalar maxY = pts[1].fY;
122
123 if (dy < 0) {
124 SkTSwap(minY, maxY);
125 }
126
127 SkASSERT(minY < maxY);
128 if (maxY < bounds.fTop || minY > bounds.fBottom) {
129 return false;
130 }
131
132 // Now we actually perform the chop, removing the excess to the top and
133 // bottom of the bounds (keeping our new line "in phase" with the dash,
134 // hence the (mod intervalLength).
135
136 if (minY < bounds.fTop) {
137 minY = bounds.fTop - SkScalarMod(bounds.fTop - minY, intervalLength) ;
138 }
139 if (maxY > bounds.fBottom) {
140 maxY = bounds.fBottom + SkScalarMod(maxY - bounds.fBottom, intervalL ength);
141 }
142
143 SkASSERT(maxY > minY);
144 if (dy < 0) {
145 SkTSwap(minY, maxY);
146 }
147 pts[0].fY = minY;
148 pts[1].fY = maxY;
149 }
150
151 return true;
152 }
153
44 // Currently asPoints is more restrictive then it needs to be. In the future 154 // Currently asPoints is more restrictive then it needs to be. In the future
45 // we need to: 155 // we need to:
46 // allow kRound_Cap capping (could allow rotations in the matrix with this) 156 // allow kRound_Cap capping (could allow rotations in the matrix with this)
47 // allow paths to be returned 157 // allow paths to be returned
48 bool SkDashPathEffect::asPoints(PointData* results, 158 bool SkDashPathEffect::asPoints(PointData* results,
49 const SkPath& src, 159 const SkPath& src,
50 const SkStrokeRec& rec, 160 const SkStrokeRec& rec,
51 const SkMatrix& matrix, 161 const SkMatrix& matrix,
52 const SkRect* cullRect) const { 162 const SkRect* cullRect) const {
53 // width < 0 -> fill && width == 0 -> hairline so requiring width > 0 rules both out 163 // width < 0 -> fill && width == 0 -> hairline so requiring width > 0 rules both out
(...skipping 22 matching lines...) Expand all
76 // TODO: this test could be eased up to allow circles 186 // TODO: this test could be eased up to allow circles
77 if (SkPaint::kButt_Cap != rec.getCap()) { 187 if (SkPaint::kButt_Cap != rec.getCap()) {
78 return false; 188 return false;
79 } 189 }
80 190
81 // TODO: this test could be eased up for circles. Rotations could be allowed . 191 // TODO: this test could be eased up for circles. Rotations could be allowed .
82 if (!matrix.rectStaysRect()) { 192 if (!matrix.rectStaysRect()) {
83 return false; 193 return false;
84 } 194 }
85 195
86 SkScalar length = SkPoint::Distance(pts[1], pts[0]); 196 // See if the line can be limited to something plausible.
197 if (!cull_line(pts, rec, matrix, cullRect, fIntervalLength)) {
198 return false;
199 }
200
201 SkScalar length = SkPoint::Distance(pts[1], pts[0]);
87 202
88 SkVector tangent = pts[1] - pts[0]; 203 SkVector tangent = pts[1] - pts[0];
89 if (tangent.isZero()) { 204 if (tangent.isZero()) {
90 return false; 205 return false;
91 } 206 }
92 207
93 tangent.scale(SkScalarInvert(length)); 208 tangent.scale(SkScalarInvert(length));
94 209
95 // TODO: make this test for horizontal & vertical lines more robust 210 // TODO: make this test for horizontal & vertical lines more robust
96 bool isXAxis = true; 211 bool isXAxis = true;
97 if (SK_Scalar1 == tangent.fX || -SK_Scalar1 == tangent.fX) { 212 if (SkScalarNearlyEqual(SK_Scalar1, tangent.fX) ||
213 SkScalarNearlyEqual(-SK_Scalar1, tangent.fX)) {
98 results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidt h())); 214 results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidt h()));
99 } else if (SK_Scalar1 == tangent.fY || -SK_Scalar1 == tangent.fY) { 215 } else if (SkScalarNearlyEqual(SK_Scalar1, tangent.fY) ||
216 SkScalarNearlyEqual(-SK_Scalar1, tangent.fY)) {
100 results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals [0])); 217 results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals [0]));
101 isXAxis = false; 218 isXAxis = false;
102 } else if (SkPaint::kRound_Cap != rec.getCap()) { 219 } else if (SkPaint::kRound_Cap != rec.getCap()) {
103 // Angled lines don't have axis-aligned boxes. 220 // Angled lines don't have axis-aligned boxes.
104 return false; 221 return false;
105 } 222 }
106 223
107 if (results) { 224 if (results) {
108 results->fFlags = 0; 225 results->fFlags = 0;
109 SkScalar clampedInitialDashLength = SkMinScalar(length, fInitialDashLeng th); 226 SkScalar clampedInitialDashLength = SkMinScalar(length, fInitialDashLeng th);
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 } 406 }
290 } else { 407 } else {
291 // set the internal data members, fPhase should have been between 0 and intervalLength 408 // set the internal data members, fPhase should have been between 0 and intervalLength
292 // when written to buffer so no need to adjust it 409 // when written to buffer so no need to adjust it
293 SkDashPath::CalcDashParameters(fPhase, fIntervals, fCount, 410 SkDashPath::CalcDashParameters(fPhase, fIntervals, fCount,
294 &fInitialDashLength, &fInitialDashIndex, &fIntervalLength); 411 &fInitialDashLength, &fInitialDashIndex, &fIntervalLength);
295 } 412 }
296 } 413 }
297 #endif 414 #endif
298 415
OLDNEW
« no previous file with comments | « src/core/SkDraw.cpp ('k') | src/utils/SkDashPath.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698