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

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

Issue 1532733002: check bounds of each cubic segment against clip (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years 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
« src/core/SkEdgeClipper.cpp ('K') | « src/core/SkEdgeClipper.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 * 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 300 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 Sk2s C = Sk2s::Load(&coeff[2].fX); 311 Sk2s C = Sk2s::Load(&coeff[2].fX);
312 Sk2s D = Sk2s::Load(&coeff[3].fX); 312 Sk2s D = Sk2s::Load(&coeff[3].fX);
313 for (int i = 1; i < lines; ++i) { 313 for (int i = 1; i < lines; ++i) {
314 t = t + dt; 314 t = t + dt;
315 (((A * t + B) * t + C) * t + D).store(&tmp[i].fX); 315 (((A * t + B) * t + C) * t + D).store(&tmp[i].fX);
316 } 316 }
317 tmp[lines] = pts[3]; 317 tmp[lines] = pts[3];
318 lineproc(tmp, lines + 1, clip, blitter); 318 lineproc(tmp, lines + 1, clip, blitter);
319 } 319 }
320 320
321 static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, 321 static SkRect compute_nocheck_cubic_bounds(const SkPoint pts[4]) {
322 SkASSERT(SkScalarsAreFinite(&pts[0].fX, 8));
323
324 Sk2s min = Sk2s::Load(&pts[0].fX);
mtklein 2015/12/17 14:58:15 This might be slightly faster to do as a tree of m
325 Sk2s max = min;
326 for (int i = 1; i < 4; ++i) {
327 Sk2s pair = Sk2s::Load(&pts[i].fX);
328 min = Sk2s::Min(min, pair);
329 max = Sk2s::Max(max, pair);
330 }
331 return { min.kth<0>(), min.kth<1>(), max.kth<0>(), max.kth<1>() };
mtklein 2015/12/17 14:58:15 We might want to double check this is the same as
332 }
333
334 static bool is_inverted(const SkRect& r) {
335 return r.fLeft > r.fRight || r.fTop > r.fBottom;
336 }
337
338 // Can't call SkRect::intersects, since it cares about empty, and we don't (sinc e we tracking
339 // something to be stroked, so empty can still draw something (e.g. horizontal l ine)
340 static bool geometric_overlap(const SkRect& a, const SkRect& b) {
341 SkASSERT(!is_inverted(a) && !is_inverted(b));
342 return a.fLeft < b.fRight && b.fLeft < a.fRight &&
343 a.fTop < b.fBottom && b.fTop < a.fBottom;
344 }
345
346 // Can't call SkRect::contains, since it cares about empty, and we don't (since we tracking
347 // something to be stroked, so empty can still draw something (e.g. horizontal l ine)
348 static bool geometric_contains(const SkRect& outer, const SkRect& inner) {
349 SkASSERT(!is_inverted(outer) && !is_inverted(inner));
350 return inner.fRight <= outer.fRight && inner.fLeft >= outer.fLeft &&
351 inner.fBottom <= outer.fBottom && inner.fTop >= outer.fTop;
352 }
353
354 //#define SK_SHOW_HAIRCLIP_STATS
355 #ifdef SK_SHOW_HAIRCLIP_STATS
356 static int gKillClip, gRejectClip, gClipCount;
357 #endif
358
359 static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, const S kRect* insetClip, const SkRect* outsetClip,
322 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro c) { 360 SkBlitter* blitter, int level, SkScan::HairRgnProc linepro c) {
361 if (insetClip) {
362 SkASSERT(outsetClip);
363 #ifdef SK_SHOW_HAIRCLIP_STATS
364 gClipCount += 1;
365 #endif
366 SkRect bounds = compute_nocheck_cubic_bounds(pts);
367 if (!geometric_overlap(*outsetClip, bounds)) {
368 #ifdef SK_SHOW_HAIRCLIP_STATS
369 gRejectClip += 1;
370 #endif
371 return;
372 } else if (geometric_contains(*insetClip, bounds)) {
373 clip = nullptr;
374 #ifdef SK_SHOW_HAIRCLIP_STATS
375 gKillClip += 1;
376 #endif
377 }
378 #ifdef SK_SHOW_HAIRCLIP_STATS
379 if (0 == gClipCount % 256)
380 SkDebugf("kill %g reject %g total %d\n", 1.0*gKillClip / gClipCount, 1.0*gRejectClip/gClipCount, gClipCount);
381 #endif
382 }
383
323 if (quick_cubic_niceness_check(pts)) { 384 if (quick_cubic_niceness_check(pts)) {
324 hair_cubic(pts, clip, blitter, lineproc); 385 hair_cubic(pts, clip, blitter, lineproc);
325 } else { 386 } else {
326 SkPoint tmp[13]; 387 SkPoint tmp[13];
327 SkScalar tValues[3]; 388 SkScalar tValues[3];
328 389
329 int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues); 390 int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues);
330 for (int i = 0; i < count; i++) { 391 for (int i = 0; i < count; i++) {
331 hair_cubic(&tmp[i * 3], clip, blitter, lineproc); 392 hair_cubic(&tmp[i * 3], clip, blitter, lineproc);
332 } 393 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 454
394 template <SkPaint::Cap capStyle> 455 template <SkPaint::Cap capStyle>
395 void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter , 456 void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter ,
396 SkScan::HairRgnProc lineproc) { 457 SkScan::HairRgnProc lineproc) {
397 if (path.isEmpty()) { 458 if (path.isEmpty()) {
398 return; 459 return;
399 } 460 }
400 461
401 SkAAClipBlitterWrapper wrap; 462 SkAAClipBlitterWrapper wrap;
402 const SkRegion* clip = nullptr; 463 const SkRegion* clip = nullptr;
464 SkRect insetStorage, outsetStorage;
465 const SkRect* insetClip = nullptr;
466 const SkRect* outsetClip = nullptr;
403 467
404 { 468 {
405 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1); 469 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1);
406 470
407 if (rclip.quickReject(ibounds)) { 471 if (rclip.quickReject(ibounds)) {
408 return; 472 return;
409 } 473 }
410 if (!rclip.quickContains(ibounds)) { 474 if (!rclip.quickContains(ibounds)) {
411 if (rclip.isBW()) { 475 if (rclip.isBW()) {
412 clip = &rclip.bwRgn(); 476 clip = &rclip.bwRgn();
413 } else { 477 } else {
414 wrap.init(rclip, blitter); 478 wrap.init(rclip, blitter);
415 blitter = wrap.getBlitter(); 479 blitter = wrap.getBlitter();
416 clip = &wrap.getRgn(); 480 clip = &wrap.getRgn();
417 } 481 }
482
483 /*
484 * We now cache two scalar rects, to use for culling per-segment (e .g. cubic).
485 * Since we're hairlining, the "bounds" of the control points isn't necessairly the
486 * limit of where a segment can draw (it might draw up to 1 pixel b eyond in aa-hairs).
487 *
488 * Compute the pt-bounds per segment is easy, so we do that, and th en inversely adjust
489 * the culling bounds so we can just do a straight compare per segm ent.
490 *
491 * insetClip is use for quick-accept (i.e. the segment is not clipp ed), so we inset
492 * it from the clip-bounds (since segment bounds can be off by 1).
493 *
494 * outsetClip is used for quick-reject (i.e. the segment is entirel y outside), so we
495 * outset it from the clip-bounds.
496 */
497 insetStorage.set(clip->getBounds());
498 outsetStorage = insetStorage.makeOutset(1, 1);
499 insetStorage.inset(1, 1);
500 if (is_inverted(insetStorage)) {
501 /*
502 * our bounds checks assume the rects are never inverted. If in setting has
503 * created that, we assume that the area is too small to safely perform a
504 * quick-accept, so we just mark the rect as empty (so the quic k-accept check
505 * will always fail.
506 */
507 insetStorage.setEmpty(); // just so we don't pass an inverted rect
508 }
509 insetClip = &insetStorage;
510 outsetClip = &outsetStorage;
418 } 511 }
419 } 512 }
420 513
421 SkPath::RawIter iter(path); 514 SkPath::RawIter iter(path);
422 SkPoint pts[4], firstPt, lastPt; 515 SkPoint pts[4], firstPt, lastPt;
423 SkPath::Verb verb, prevVerb; 516 SkPath::Verb verb, prevVerb;
424 SkAutoConicToQuads converter; 517 SkAutoConicToQuads converter;
425 518
426 if (SkPaint::kButt_Cap != capStyle) { 519 if (SkPaint::kButt_Cap != capStyle) {
427 prevVerb = SkPath::kDone_Verb; 520 prevVerb = SkPath::kDone_Verb;
(...skipping 30 matching lines...) Expand all
458 hairquad(quadPts, clip, blitter, level, lineproc); 551 hairquad(quadPts, clip, blitter, level, lineproc);
459 quadPts += 2; 552 quadPts += 2;
460 } 553 }
461 lastPt = pts[2]; 554 lastPt = pts[2];
462 break; 555 break;
463 } 556 }
464 case SkPath::kCubic_Verb: { 557 case SkPath::kCubic_Verb: {
465 if (SkPaint::kButt_Cap != capStyle) { 558 if (SkPaint::kButt_Cap != capStyle) {
466 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 4); 559 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 4);
467 } 560 }
468 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc) ; 561 haircubic(pts, clip, insetClip, outsetClip, blitter, kMaxCubicSu bdivideLevel, lineproc);
469 lastPt = pts[3]; 562 lastPt = pts[3];
470 } break; 563 } break;
471 case SkPath::kClose_Verb: 564 case SkPath::kClose_Verb:
472 pts[0] = lastPt; 565 pts[0] = lastPt;
473 pts[1] = firstPt; 566 pts[1] = firstPt;
474 if (SkPaint::kButt_Cap != capStyle && prevVerb == SkPath::kMove_ Verb) { 567 if (SkPaint::kButt_Cap != capStyle && prevVerb == SkPath::kMove_ Verb) {
475 // cap moveTo/close to match svg expectations for degenerate segments 568 // cap moveTo/close to match svg expectations for degenerate segments
476 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 2); 569 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 2);
477 } 570 }
478 lineproc(pts, 2, clip, blitter); 571 lineproc(pts, 2, clip, blitter);
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 673
581 SkAAClipBlitterWrapper wrap; 674 SkAAClipBlitterWrapper wrap;
582 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { 675 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) {
583 wrap.init(clip, blitter); 676 wrap.init(clip, blitter);
584 blitter = wrap.getBlitter(); 677 blitter = wrap.getBlitter();
585 clipRgn = &wrap.getRgn(); 678 clipRgn = &wrap.getRgn();
586 } 679 }
587 AntiHairLineRgn(pts, count, clipRgn, blitter); 680 AntiHairLineRgn(pts, count, clipRgn, blitter);
588 } 681 }
589 } 682 }
OLDNEW
« src/core/SkEdgeClipper.cpp ('K') | « src/core/SkEdgeClipper.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698