OLD | NEW |
---|---|
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 "SkScan.h" | 8 #include "SkScan.h" |
9 #include "SkBlitter.h" | 9 #include "SkBlitter.h" |
10 #include "SkRasterClip.h" | 10 #include "SkRasterClip.h" |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
207 int idx = SkScalarCeilToInt(dx); | 207 int idx = SkScalarCeilToInt(dx); |
208 int idy = SkScalarCeilToInt(dy); | 208 int idy = SkScalarCeilToInt(dy); |
209 // use the cheap approx for distance | 209 // use the cheap approx for distance |
210 if (idx > idy) { | 210 if (idx > idy) { |
211 return idx + (idy >> 1); | 211 return idx + (idy >> 1); |
212 } else { | 212 } else { |
213 return idy + (idx >> 1); | 213 return idy + (idx >> 1); |
214 } | 214 } |
215 } | 215 } |
216 | 216 |
217 static void hairquad(const SkPoint pts[3], const SkRegion* clip, | 217 static void hair_quad(const SkPoint pts[3], const SkRegion* clip, |
218 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc ) { | 218 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc ) { |
219 SkASSERT(level <= kMaxQuadSubdivideLevel); | 219 SkASSERT(level <= kMaxQuadSubdivideLevel); |
220 | 220 |
221 SkQuadCoeff coeff(pts); | 221 SkQuadCoeff coeff(pts); |
222 | 222 |
223 const int lines = 1 << level; | 223 const int lines = 1 << level; |
224 Sk2s t(0); | 224 Sk2s t(0); |
225 Sk2s dt(SK_Scalar1 / lines); | 225 Sk2s dt(SK_Scalar1 / lines); |
226 | 226 |
227 SkPoint tmp[(1 << kMaxQuadSubdivideLevel) + 1]; | 227 SkPoint tmp[(1 << kMaxQuadSubdivideLevel) + 1]; |
228 SkASSERT((unsigned)lines < SK_ARRAY_COUNT(tmp)); | 228 SkASSERT((unsigned)lines < SK_ARRAY_COUNT(tmp)); |
229 | 229 |
230 tmp[0] = pts[0]; | 230 tmp[0] = pts[0]; |
231 Sk2s A = coeff.fA; | 231 Sk2s A = coeff.fA; |
232 Sk2s B = coeff.fB; | 232 Sk2s B = coeff.fB; |
233 Sk2s C = coeff.fC; | 233 Sk2s C = coeff.fC; |
234 for (int i = 1; i < lines; ++i) { | 234 for (int i = 1; i < lines; ++i) { |
235 t = t + dt; | 235 t = t + dt; |
236 ((A * t + B) * t + C).store(&tmp[i]); | 236 ((A * t + B) * t + C).store(&tmp[i]); |
237 } | 237 } |
238 tmp[lines] = pts[2]; | 238 tmp[lines] = pts[2]; |
239 lineproc(tmp, lines + 1, clip, blitter); | 239 lineproc(tmp, lines + 1, clip, blitter); |
240 } | 240 } |
241 | 241 |
242 static SkRect compute_nocheck_quad_bounds(const SkPoint pts[3]) { | |
243 SkASSERT(SkScalarsAreFinite(&pts[0].fX, 8)); | |
244 | |
245 Sk2s min = Sk2s::Load(pts); | |
246 Sk2s max = min; | |
247 for (int i = 1; i < 3; ++i) { | |
248 Sk2s pair = Sk2s::Load(pts+i); | |
249 min = Sk2s::Min(min, pair); | |
250 max = Sk2s::Max(max, pair); | |
251 } | |
252 return { min[0], min[1], max[0], max[1] }; | |
253 } | |
254 | |
255 static bool is_inverted(const SkRect& r) { | |
256 return r.fLeft > r.fRight || r.fTop > r.fBottom; | |
257 } | |
258 | |
259 // Can't call SkRect::intersects, since it cares about empty, and we don't (sinc e we tracking | |
260 // something to be stroked, so empty can still draw something (e.g. horizontal l ine) | |
261 static bool geometric_overlap(const SkRect& a, const SkRect& b) { | |
262 SkASSERT(!is_inverted(a) && !is_inverted(b)); | |
263 return a.fLeft < b.fRight && b.fLeft < a.fRight && | |
264 a.fTop < b.fBottom && b.fTop < a.fBottom; | |
265 } | |
266 | |
267 // Can't call SkRect::contains, since it cares about empty, and we don't (since we tracking | |
268 // something to be stroked, so empty can still draw something (e.g. horizontal l ine) | |
269 static bool geometric_contains(const SkRect& outer, const SkRect& inner) { | |
270 SkASSERT(!is_inverted(outer) && !is_inverted(inner)); | |
271 return inner.fRight <= outer.fRight && inner.fLeft >= outer.fLeft && | |
272 inner.fBottom <= outer.fBottom && inner.fTop >= outer.fTop; | |
273 } | |
274 | |
275 //#define SK_SHOW_HAIRCLIP_STATS | |
276 #ifdef SK_SHOW_HAIRCLIP_STATS | |
277 static int gKillClip, gRejectClip, gClipCount; | |
278 #endif | |
279 | |
280 static inline void hairquad(const SkPoint pts[3], const SkRegion* clip, const Sk Rect* insetClip, const SkRect* outsetClip, | |
281 SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc) { | |
282 if (insetClip) { | |
283 SkASSERT(outsetClip); | |
284 #ifdef SK_SHOW_HAIRCLIP_STATS | |
reed1
2016/05/11 19:47:50
I'm fine with these, or fine if we remove all this
| |
285 gClipCount += 1; | |
286 #endif | |
287 SkRect bounds = compute_nocheck_quad_bounds(pts); | |
288 if (!geometric_overlap(*outsetClip, bounds)) { | |
289 #ifdef SK_SHOW_HAIRCLIP_STATS | |
290 gRejectClip += 1; | |
291 #endif | |
292 return; | |
293 } else if (geometric_contains(*insetClip, bounds)) { | |
294 clip = nullptr; | |
295 #ifdef SK_SHOW_HAIRCLIP_STATS | |
296 gKillClip += 1; | |
297 #endif | |
298 } | |
299 #ifdef SK_SHOW_HAIRCLIP_STATS | |
300 if (0 == gClipCount % 256) | |
301 SkDebugf("kill %g reject %g total %d\n", 1.0*gKillClip / gClipCount, 1.0*gRejectClip/gClipCount, gClipCount); | |
302 #endif | |
303 } | |
304 | |
305 hair_quad(pts, clip, blitter, level, lineproc); | |
306 } | |
307 | |
242 static inline Sk2s abs(const Sk2s& value) { | 308 static inline Sk2s abs(const Sk2s& value) { |
243 return Sk2s::Max(value, Sk2s(0)-value); | 309 return Sk2s::Max(value, Sk2s(0)-value); |
244 } | 310 } |
245 | 311 |
246 static inline SkScalar max_component(const Sk2s& value) { | 312 static inline SkScalar max_component(const Sk2s& value) { |
247 SkScalar components[2]; | 313 SkScalar components[2]; |
248 value.store(components); | 314 value.store(components); |
249 return SkTMax(components[0], components[1]); | 315 return SkTMax(components[0], components[1]); |
250 } | 316 } |
251 | 317 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
322 Sk2s min = Sk2s::Load(pts); | 388 Sk2s min = Sk2s::Load(pts); |
323 Sk2s max = min; | 389 Sk2s max = min; |
324 for (int i = 1; i < 4; ++i) { | 390 for (int i = 1; i < 4; ++i) { |
325 Sk2s pair = Sk2s::Load(pts+i); | 391 Sk2s pair = Sk2s::Load(pts+i); |
326 min = Sk2s::Min(min, pair); | 392 min = Sk2s::Min(min, pair); |
327 max = Sk2s::Max(max, pair); | 393 max = Sk2s::Max(max, pair); |
328 } | 394 } |
329 return { min[0], min[1], max[0], max[1] }; | 395 return { min[0], min[1], max[0], max[1] }; |
330 } | 396 } |
331 | 397 |
332 static bool is_inverted(const SkRect& r) { | |
333 return r.fLeft > r.fRight || r.fTop > r.fBottom; | |
334 } | |
335 | |
336 // Can't call SkRect::intersects, since it cares about empty, and we don't (sinc e we tracking | |
337 // something to be stroked, so empty can still draw something (e.g. horizontal l ine) | |
338 static bool geometric_overlap(const SkRect& a, const SkRect& b) { | |
339 SkASSERT(!is_inverted(a) && !is_inverted(b)); | |
340 return a.fLeft < b.fRight && b.fLeft < a.fRight && | |
341 a.fTop < b.fBottom && b.fTop < a.fBottom; | |
342 } | |
343 | |
344 // Can't call SkRect::contains, since it cares about empty, and we don't (since we tracking | |
345 // something to be stroked, so empty can still draw something (e.g. horizontal l ine) | |
346 static bool geometric_contains(const SkRect& outer, const SkRect& inner) { | |
347 SkASSERT(!is_inverted(outer) && !is_inverted(inner)); | |
348 return inner.fRight <= outer.fRight && inner.fLeft >= outer.fLeft && | |
349 inner.fBottom <= outer.fBottom && inner.fTop >= outer.fTop; | |
350 } | |
351 | |
352 //#define SK_SHOW_HAIRCLIP_STATS | |
353 #ifdef SK_SHOW_HAIRCLIP_STATS | |
354 static int gKillClip, gRejectClip, gClipCount; | |
355 #endif | |
356 | |
357 static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, const S kRect* insetClip, const SkRect* outsetClip, | 398 static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, const S kRect* insetClip, const SkRect* outsetClip, |
358 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro c) { | 399 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro c) { |
359 if (insetClip) { | 400 if (insetClip) { |
360 SkASSERT(outsetClip); | 401 SkASSERT(outsetClip); |
361 #ifdef SK_SHOW_HAIRCLIP_STATS | 402 #ifdef SK_SHOW_HAIRCLIP_STATS |
362 gClipCount += 1; | 403 gClipCount += 1; |
363 #endif | 404 #endif |
364 SkRect bounds = compute_nocheck_cubic_bounds(pts); | 405 SkRect bounds = compute_nocheck_cubic_bounds(pts); |
365 if (!geometric_overlap(*outsetClip, bounds)) { | 406 if (!geometric_overlap(*outsetClip, bounds)) { |
366 #ifdef SK_SHOW_HAIRCLIP_STATS | 407 #ifdef SK_SHOW_HAIRCLIP_STATS |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
505 insetStorage.inset(1, 1); | 546 insetStorage.inset(1, 1); |
506 if (is_inverted(insetStorage)) { | 547 if (is_inverted(insetStorage)) { |
507 /* | 548 /* |
508 * our bounds checks assume the rects are never inverted. If in setting has | 549 * our bounds checks assume the rects are never inverted. If in setting has |
509 * created that, we assume that the area is too small to safely perform a | 550 * created that, we assume that the area is too small to safely perform a |
510 * quick-accept, so we just mark the rect as empty (so the quic k-accept check | 551 * quick-accept, so we just mark the rect as empty (so the quic k-accept check |
511 * will always fail. | 552 * will always fail. |
512 */ | 553 */ |
513 insetStorage.setEmpty(); // just so we don't pass an inverted rect | 554 insetStorage.setEmpty(); // just so we don't pass an inverted rect |
514 } | 555 } |
515 insetClip = &insetStorage; | 556 » » » if (rclip.isRect()) { |
reed1
2016/05/11 19:47:50
funny indenting (tabs?)
| |
557 » » » » insetClip = &insetStorage; | |
558 » » » } | |
516 outsetClip = &outsetStorage; | 559 outsetClip = &outsetStorage; |
517 } | 560 } |
518 } | 561 } |
519 | 562 |
520 SkPath::RawIter iter(path); | 563 SkPath::RawIter iter(path); |
521 SkPoint pts[4], firstPt, lastPt; | 564 SkPoint pts[4], firstPt, lastPt; |
522 SkPath::Verb verb, prevVerb; | 565 SkPath::Verb verb, prevVerb; |
523 SkAutoConicToQuads converter; | 566 SkAutoConicToQuads converter; |
524 | 567 |
525 if (SkPaint::kButt_Cap != capStyle) { | 568 if (SkPaint::kButt_Cap != capStyle) { |
526 prevVerb = SkPath::kDone_Verb; | 569 prevVerb = SkPath::kDone_Verb; |
527 } | 570 } |
528 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 571 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
529 switch (verb) { | 572 switch (verb) { |
530 case SkPath::kMove_Verb: | 573 case SkPath::kMove_Verb: |
531 firstPt = lastPt = pts[0]; | 574 firstPt = lastPt = pts[0]; |
532 break; | 575 break; |
533 case SkPath::kLine_Verb: | 576 case SkPath::kLine_Verb: |
534 if (SkPaint::kButt_Cap != capStyle) { | 577 if (SkPaint::kButt_Cap != capStyle) { |
535 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 2); | 578 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 2); |
536 } | 579 } |
537 lineproc(pts, 2, clip, blitter); | 580 lineproc(pts, 2, clip, blitter); |
538 lastPt = pts[1]; | 581 lastPt = pts[1]; |
539 break; | 582 break; |
540 case SkPath::kQuad_Verb: | 583 case SkPath::kQuad_Verb: |
541 if (SkPaint::kButt_Cap != capStyle) { | 584 if (SkPaint::kButt_Cap != capStyle) { |
542 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3); | 585 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3); |
543 } | 586 } |
544 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc); | 587 hairquad(pts, clip, insetClip, outsetClip, blitter, compute_quad _level(pts), lineproc); |
545 lastPt = pts[2]; | 588 lastPt = pts[2]; |
546 break; | 589 break; |
547 case SkPath::kConic_Verb: { | 590 case SkPath::kConic_Verb: { |
548 if (SkPaint::kButt_Cap != capStyle) { | 591 if (SkPaint::kButt_Cap != capStyle) { |
549 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3); | 592 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3); |
550 } | 593 } |
551 // how close should the quads be to the original conic? | 594 // how close should the quads be to the original conic? |
552 const SkScalar tol = SK_Scalar1 / 4; | 595 const SkScalar tol = SK_Scalar1 / 4; |
553 const SkPoint* quadPts = converter.computeQuads(pts, | 596 const SkPoint* quadPts = converter.computeQuads(pts, |
554 iter.conicWeight(), tol); | 597 iter.conicWeight(), tol); |
555 for (int i = 0; i < converter.countQuads(); ++i) { | 598 for (int i = 0; i < converter.countQuads(); ++i) { |
556 int level = compute_quad_level(quadPts); | 599 int level = compute_quad_level(quadPts); |
557 hairquad(quadPts, clip, blitter, level, lineproc); | 600 hairquad(quadPts, clip, insetClip, outsetClip, blitter, leve l, lineproc); |
558 quadPts += 2; | 601 quadPts += 2; |
559 } | 602 } |
560 lastPt = pts[2]; | 603 lastPt = pts[2]; |
561 break; | 604 break; |
562 } | 605 } |
563 case SkPath::kCubic_Verb: { | 606 case SkPath::kCubic_Verb: { |
564 if (SkPaint::kButt_Cap != capStyle) { | 607 if (SkPaint::kButt_Cap != capStyle) { |
565 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 4); | 608 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 4); |
566 } | 609 } |
567 haircubic(pts, clip, insetClip, outsetClip, blitter, kMaxCubicSu bdivideLevel, lineproc); | 610 haircubic(pts, clip, insetClip, outsetClip, blitter, kMaxCubicSu bdivideLevel, lineproc); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
679 | 722 |
680 SkAAClipBlitterWrapper wrap; | 723 SkAAClipBlitterWrapper wrap; |
681 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { | 724 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { |
682 wrap.init(clip, blitter); | 725 wrap.init(clip, blitter); |
683 blitter = wrap.getBlitter(); | 726 blitter = wrap.getBlitter(); |
684 clipRgn = &wrap.getRgn(); | 727 clipRgn = &wrap.getRgn(); |
685 } | 728 } |
686 AntiHairLineRgn(pts, count, clipRgn, blitter); | 729 AntiHairLineRgn(pts, count, clipRgn, blitter); |
687 } | 730 } |
688 } | 731 } |
OLD | NEW |