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

Side by Side Diff: src/core/SkScan_Hairline.cpp

Issue 1085883002: change hairline procs to take array of points (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 8 months 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/SkScan_Antihair.cpp ('k') | no next file » | 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 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkScan.h" 10 #include "SkScan.h"
(...skipping 22 matching lines...) Expand all
33 } while (++y < stopy); 33 } while (++y < stopy);
34 } 34 }
35 35
36 #ifdef SK_DEBUG 36 #ifdef SK_DEBUG
37 static bool canConvertFDot6ToFixed(SkFDot6 x) { 37 static bool canConvertFDot6ToFixed(SkFDot6 x) {
38 const int maxDot6 = SK_MaxS32 >> (16 - 6); 38 const int maxDot6 = SK_MaxS32 >> (16 - 6);
39 return SkAbs32(x) <= maxDot6; 39 return SkAbs32(x) <= maxDot6;
40 } 40 }
41 #endif 41 #endif
42 42
43 void SkScan::HairLineRgn(SkPoint pt0, SkPoint pt1, const SkRegion* clip, SkBlitt er* blitter) { 43 void SkScan::HairLineRgn(const SkPoint array[], int arrayCount, const SkRegion* clip,
44 SkBlitter* origBlitter) {
44 SkBlitterClipper clipper; 45 SkBlitterClipper clipper;
45 SkRect r;
46 SkIRect clipR, ptsR; 46 SkIRect clipR, ptsR;
47 SkPoint pts[2] = { pt0, pt1 };
48 47
49 // We have to pre-clip the line to fit in a SkFixed, so we just chop 48 const SkScalar max = SkIntToScalar(32767);
50 // the line. TODO find a way to actually draw beyond that range. 49 const SkRect fixedBounds = SkRect::MakeLTRB(-max, -max, max, max);
51 { 50
52 SkRect fixedBounds; 51 SkRect clipBounds;
53 const SkScalar max = SkIntToScalar(32767); 52 if (clip) {
54 fixedBounds.set(-max, -max, max, max); 53 clipBounds.set(clip->getBounds());
55 if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) {
56 return;
57 }
58 } 54 }
59 55
60 if (clip) { 56 for (int i = 0; i < arrayCount - 1; ++i) {
57 SkBlitter* blitter = origBlitter;
58
59 SkPoint pts[2];
60
61 // We have to pre-clip the line to fit in a SkFixed, so we just chop
62 // the line. TODO find a way to actually draw beyond that range.
63 if (!SkLineClipper::IntersectLine(&array[i], fixedBounds, pts)) {
64 continue;
65 }
66
61 // Perform a clip in scalar space, so we catch huge values which might 67 // Perform a clip in scalar space, so we catch huge values which might
62 // be missed after we convert to SkFDot6 (overflow) 68 // be missed after we convert to SkFDot6 (overflow)
63 r.set(clip->getBounds()); 69 if (clip && !SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
64 if (!SkLineClipper::IntersectLine(pts, r, pts)) { 70 continue;
65 return;
66 }
67 }
68
69 SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
70 SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
71 SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
72 SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
73
74 SkASSERT(canConvertFDot6ToFixed(x0));
75 SkASSERT(canConvertFDot6ToFixed(y0));
76 SkASSERT(canConvertFDot6ToFixed(x1));
77 SkASSERT(canConvertFDot6ToFixed(y1));
78
79 if (clip) {
80 // now perform clipping again, as the rounding to dot6 can wiggle us
81 // our rects are really dot6 rects, but since we've already used
82 // lineclipper, we know they will fit in 32bits (26.6)
83 const SkIRect& bounds = clip->getBounds();
84
85 clipR.set(SkIntToFDot6(bounds.fLeft), SkIntToFDot6(bounds.fTop),
86 SkIntToFDot6(bounds.fRight), SkIntToFDot6(bounds.fBottom));
87 ptsR.set(x0, y0, x1, y1);
88 ptsR.sort();
89
90 // outset the right and bottom, to account for how hairlines are
91 // actually drawn, which may hit the pixel to the right or below of
92 // the coordinate
93 ptsR.fRight += SK_FDot6One;
94 ptsR.fBottom += SK_FDot6One;
95
96 if (!SkIRect::Intersects(ptsR, clipR)) {
97 return;
98 }
99 if (clip->isRect() && clipR.contains(ptsR)) {
100 clip = NULL;
101 } else {
102 blitter = clipper.apply(blitter, clip);
103 }
104 }
105
106 SkFDot6 dx = x1 - x0;
107 SkFDot6 dy = y1 - y0;
108
109 if (SkAbs32(dx) > SkAbs32(dy)) { // mostly horizontal
110 if (x0 > x1) { // we want to go left-to-right
111 SkTSwap<SkFDot6>(x0, x1);
112 SkTSwap<SkFDot6>(y0, y1);
113 }
114 int ix0 = SkFDot6Round(x0);
115 int ix1 = SkFDot6Round(x1);
116 if (ix0 == ix1) {// too short to draw
117 return;
118 } 71 }
119 72
120 SkFixed slope = SkFixedDiv(dy, dx); 73 SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
121 SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6); 74 SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
75 SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
76 SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
122 77
123 horiline(ix0, ix1, startY, slope, blitter); 78 SkASSERT(canConvertFDot6ToFixed(x0));
124 } else { // mostly vertical 79 SkASSERT(canConvertFDot6ToFixed(y0));
125 if (y0 > y1) { // we want to go top-to-bottom 80 SkASSERT(canConvertFDot6ToFixed(x1));
126 SkTSwap<SkFDot6>(x0, x1); 81 SkASSERT(canConvertFDot6ToFixed(y1));
127 SkTSwap<SkFDot6>(y0, y1); 82
128 } 83 if (clip) {
129 int iy0 = SkFDot6Round(y0); 84 // now perform clipping again, as the rounding to dot6 can wiggle us
130 int iy1 = SkFDot6Round(y1); 85 // our rects are really dot6 rects, but since we've already used
131 if (iy0 == iy1) { // too short to draw 86 // lineclipper, we know they will fit in 32bits (26.6)
132 return; 87 const SkIRect& bounds = clip->getBounds();
88
89 clipR.set(SkIntToFDot6(bounds.fLeft), SkIntToFDot6(bounds.fTop),
90 SkIntToFDot6(bounds.fRight), SkIntToFDot6(bounds.fBottom)) ;
91 ptsR.set(x0, y0, x1, y1);
92 ptsR.sort();
93
94 // outset the right and bottom, to account for how hairlines are
95 // actually drawn, which may hit the pixel to the right or below of
96 // the coordinate
97 ptsR.fRight += SK_FDot6One;
98 ptsR.fBottom += SK_FDot6One;
99
100 if (!SkIRect::Intersects(ptsR, clipR)) {
101 continue;
102 }
103 if (!clip->isRect() || !clipR.contains(ptsR)) {
104 blitter = clipper.apply(origBlitter, clip);
105 }
133 } 106 }
134 107
135 SkFixed slope = SkFixedDiv(dx, dy); 108 SkFDot6 dx = x1 - x0;
136 SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6); 109 SkFDot6 dy = y1 - y0;
137 110
138 vertline(iy0, iy1, startX, slope, blitter); 111 if (SkAbs32(dx) > SkAbs32(dy)) { // mostly horizontal
112 if (x0 > x1) { // we want to go left-to-right
113 SkTSwap<SkFDot6>(x0, x1);
114 SkTSwap<SkFDot6>(y0, y1);
115 }
116 int ix0 = SkFDot6Round(x0);
117 int ix1 = SkFDot6Round(x1);
118 if (ix0 == ix1) {// too short to draw
119 continue;
120 }
121
122 SkFixed slope = SkFixedDiv(dy, dx);
123 SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6 );
124
125 horiline(ix0, ix1, startY, slope, blitter);
126 } else { // mostly vertical
127 if (y0 > y1) { // we want to go top-to-bottom
128 SkTSwap<SkFDot6>(x0, x1);
129 SkTSwap<SkFDot6>(y0, y1);
130 }
131 int iy0 = SkFDot6Round(y0);
132 int iy1 = SkFDot6Round(y1);
133 if (iy0 == iy1) { // too short to draw
134 continue;
135 }
136
137 SkFixed slope = SkFixedDiv(dx, dy);
138 SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6 );
139
140 vertline(iy0, iy1, startX, slope, blitter);
141 }
139 } 142 }
140 } 143 }
141 144
142 // we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right 145 // we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
143 // and double-hit the top-left. 146 // and double-hit the top-left.
144 // TODO: handle huge coordinates on rect (before calling SkScalarToFixed) 147 // TODO: handle huge coordinates on rect (before calling SkScalarToFixed)
145 void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip, 148 void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip,
146 SkBlitter* blitter) { 149 SkBlitter* blitter) {
147 SkAAClipBlitterWrapper wrapper; 150 SkAAClipBlitterWrapper wrapper;
148 SkBlitterClipper clipper; 151 SkBlitterClipper clipper;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 int idx = SkScalarCeilToInt(dx); 205 int idx = SkScalarCeilToInt(dx);
203 int idy = SkScalarCeilToInt(dy); 206 int idy = SkScalarCeilToInt(dy);
204 // use the cheap approx for distance 207 // use the cheap approx for distance
205 if (idx > idy) { 208 if (idx > idy) {
206 return idx + (idy >> 1); 209 return idx + (idy >> 1);
207 } else { 210 } else {
208 return idy + (idx >> 1); 211 return idy + (idx >> 1);
209 } 212 }
210 } 213 }
211 214
212 typedef void (*LineProc)(SkPoint, SkPoint, const SkRegion*, SkBlitter*);
213
214 static void hairquad(const SkPoint pts[3], const SkRegion* clip, 215 static void hairquad(const SkPoint pts[3], const SkRegion* clip,
215 SkBlitter* blitter, int level, LineProc lineproc) { 216 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc ) {
216 if (level > 0) { 217 if (level > 0) {
217 SkPoint tmp[5]; 218 SkPoint tmp[5];
218 219
219 SkChopQuadAtHalf(pts, tmp); 220 SkChopQuadAtHalf(pts, tmp);
220 hairquad(tmp, clip, blitter, level - 1, lineproc); 221 hairquad(tmp, clip, blitter, level - 1, lineproc);
221 hairquad(&tmp[2], clip, blitter, level - 1, lineproc); 222 hairquad(&tmp[2], clip, blitter, level - 1, lineproc);
222 } else { 223 } else {
223 lineproc(pts[0], pts[2], clip, blitter); 224 SkPoint tmp[] = { pts[0], pts[2] };
225 lineproc(tmp, 2, clip, blitter);
224 } 226 }
225 } 227 }
226 228
227 static void haircubic(const SkPoint pts[4], const SkRegion* clip, 229 static void haircubic(const SkPoint pts[4], const SkRegion* clip,
228 SkBlitter* blitter, int level, LineProc lineproc) { 230 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro c) {
229 if (level > 0) { 231 if (level > 0) {
230 SkPoint tmp[7]; 232 SkPoint tmp[7];
231 233
232 SkChopCubicAt(pts, tmp, SK_Scalar1/2); 234 SkChopCubicAt(pts, tmp, SK_Scalar1/2);
233 haircubic(tmp, clip, blitter, level - 1, lineproc); 235 haircubic(tmp, clip, blitter, level - 1, lineproc);
234 haircubic(&tmp[3], clip, blitter, level - 1, lineproc); 236 haircubic(&tmp[3], clip, blitter, level - 1, lineproc);
235 } else { 237 } else {
236 lineproc(pts[0], pts[3], clip, blitter); 238 SkPoint tmp[] = { pts[0], pts[3] };
239 lineproc(tmp, 2, clip, blitter);
237 } 240 }
238 } 241 }
239 242
240 #define kMaxCubicSubdivideLevel 6 243 #define kMaxCubicSubdivideLevel 6
241 #define kMaxQuadSubdivideLevel 5 244 #define kMaxQuadSubdivideLevel 5
242 245
243 static int compute_quad_level(const SkPoint pts[3]) { 246 static int compute_quad_level(const SkPoint pts[3]) {
244 int d = compute_int_quad_dist(pts); 247 int d = compute_int_quad_dist(pts);
245 /* quadratics approach the line connecting their start and end points 248 /* quadratics approach the line connecting their start and end points
246 4x closer with each subdivision, so we compute the number of 249 4x closer with each subdivision, so we compute the number of
247 subdivisions to be the minimum need to get that distance to be less 250 subdivisions to be the minimum need to get that distance to be less
248 than a pixel. 251 than a pixel.
249 */ 252 */
250 int level = (33 - SkCLZ(d)) >> 1; 253 int level = (33 - SkCLZ(d)) >> 1;
251 // sanity check on level (from the previous version) 254 // sanity check on level (from the previous version)
252 if (level > kMaxQuadSubdivideLevel) { 255 if (level > kMaxQuadSubdivideLevel) {
253 level = kMaxQuadSubdivideLevel; 256 level = kMaxQuadSubdivideLevel;
254 } 257 }
255 return level; 258 return level;
256 } 259 }
257 260
258 static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter, 261 static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter,
259 LineProc lineproc) { 262 SkScan::HairRgnProc lineproc) {
260 if (path.isEmpty()) { 263 if (path.isEmpty()) {
261 return; 264 return;
262 } 265 }
263 266
264 SkAAClipBlitterWrapper wrap; 267 SkAAClipBlitterWrapper wrap;
265 const SkRegion* clip = NULL; 268 const SkRegion* clip = NULL;
266 269
267 { 270 {
268 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1); 271 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1);
269 272
(...skipping 14 matching lines...) Expand all
284 SkPath::Iter iter(path, false); 287 SkPath::Iter iter(path, false);
285 SkPoint pts[4]; 288 SkPoint pts[4];
286 SkPath::Verb verb; 289 SkPath::Verb verb;
287 SkAutoConicToQuads converter; 290 SkAutoConicToQuads converter;
288 291
289 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) { 292 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
290 switch (verb) { 293 switch (verb) {
291 case SkPath::kMove_Verb: 294 case SkPath::kMove_Verb:
292 break; 295 break;
293 case SkPath::kLine_Verb: 296 case SkPath::kLine_Verb:
294 lineproc(pts[0], pts[1], clip, blitter); 297 lineproc(pts, 2, clip, blitter);
295 break; 298 break;
296 case SkPath::kQuad_Verb: 299 case SkPath::kQuad_Verb:
297 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc); 300 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc);
298 break; 301 break;
299 case SkPath::kConic_Verb: { 302 case SkPath::kConic_Verb: {
300 // how close should the quads be to the original conic? 303 // how close should the quads be to the original conic?
301 const SkScalar tol = SK_Scalar1 / 4; 304 const SkScalar tol = SK_Scalar1 / 4;
302 const SkPoint* quadPts = converter.computeQuads(pts, 305 const SkPoint* quadPts = converter.computeQuads(pts,
303 iter.conicWeight(), tol); 306 iter.conicWeight(), tol);
304 for (int i = 0; i < converter.countQuads(); ++i) { 307 for (int i = 0; i < converter.countQuads(); ++i) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 tmp.fBottom = outer.fBottom; 360 tmp.fBottom = outer.fBottom;
358 SkScan::FillRect(tmp, clip, blitter); 361 SkScan::FillRect(tmp, clip, blitter);
359 362
360 tmp.set(outer.fLeft, outer.fTop + dy, outer.fLeft + dx, outer.fBottom - dy); 363 tmp.set(outer.fLeft, outer.fTop + dy, outer.fLeft + dx, outer.fBottom - dy);
361 SkScan::FillRect(tmp, clip, blitter); 364 SkScan::FillRect(tmp, clip, blitter);
362 tmp.fLeft = outer.fRight - dx; 365 tmp.fLeft = outer.fRight - dx;
363 tmp.fRight = outer.fRight; 366 tmp.fRight = outer.fRight;
364 SkScan::FillRect(tmp, clip, blitter); 367 SkScan::FillRect(tmp, clip, blitter);
365 } 368 }
366 369
367 void SkScan::HairLine(SkPoint p0, SkPoint p1, const SkRasterClip& clip, SkBlitte r* blitter) { 370 void SkScan::HairLine(const SkPoint pts[], int count, const SkRasterClip& clip,
371 SkBlitter* blitter) {
368 if (clip.isBW()) { 372 if (clip.isBW()) {
369 HairLineRgn(p0, p1, &clip.bwRgn(), blitter); 373 HairLineRgn(pts, count, &clip.bwRgn(), blitter);
370 } else { 374 } else {
371 const SkRegion* clipRgn = NULL; 375 const SkRegion* clipRgn = NULL;
376
372 SkRect r; 377 SkRect r;
373 r.set(p0.fX, p0.fY, p1.fX, p1.fY); 378 r.set(pts, count);
374 r.sort();
375 r.outset(SK_ScalarHalf, SK_ScalarHalf); 379 r.outset(SK_ScalarHalf, SK_ScalarHalf);
376 380
377 SkAAClipBlitterWrapper wrap; 381 SkAAClipBlitterWrapper wrap;
378 if (!clip.quickContains(r.roundOut())) { 382 if (!clip.quickContains(r.roundOut())) {
379 wrap.init(clip, blitter); 383 wrap.init(clip, blitter);
380 blitter = wrap.getBlitter(); 384 blitter = wrap.getBlitter();
381 clipRgn = &wrap.getRgn(); 385 clipRgn = &wrap.getRgn();
382 } 386 }
383 HairLineRgn(p0, p1, clipRgn, blitter); 387 HairLineRgn(pts, count, clipRgn, blitter);
384 } 388 }
385 } 389 }
386 390
387 void SkScan::AntiHairLine(SkPoint p0, SkPoint p1, const SkRasterClip& clip, SkBl itter* blitter) { 391 void SkScan::AntiHairLine(const SkPoint pts[], int count, const SkRasterClip& cl ip,
392 SkBlitter* blitter) {
388 if (clip.isBW()) { 393 if (clip.isBW()) {
389 AntiHairLineRgn(p0, p1, &clip.bwRgn(), blitter); 394 AntiHairLineRgn(pts, count, &clip.bwRgn(), blitter);
390 } else { 395 } else {
391 const SkRegion* clipRgn = NULL; 396 const SkRegion* clipRgn = NULL;
397
392 SkRect r; 398 SkRect r;
393 r.set(p0.fX, p0.fY, p1.fX, p1.fY); 399 r.set(pts, count);
394 r.sort();
395 400
396 SkAAClipBlitterWrapper wrap; 401 SkAAClipBlitterWrapper wrap;
397 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { 402 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) {
398 wrap.init(clip, blitter); 403 wrap.init(clip, blitter);
399 blitter = wrap.getBlitter(); 404 blitter = wrap.getBlitter();
400 clipRgn = &wrap.getRgn(); 405 clipRgn = &wrap.getRgn();
401 } 406 }
402 AntiHairLineRgn(p0, p1, clipRgn, blitter); 407 AntiHairLineRgn(pts, count, clipRgn, blitter);
403 } 408 }
404 } 409 }
OLDNEW
« no previous file with comments | « src/core/SkScan_Antihair.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698