Fix SkRRect::ConservativeIntersect when inputs share corner

Encountered while debugging new GrClipStack.

Basically, with the old checks, if aCorner == bCorner but A was a rect,
we'd end up rejecting it as not a viable intersection (failing the
testCorner == aCorner checks), but wouldn't fall through to the
testCorner == bCorner checks.

Instead of splitting the if-elseif-else into separate ifs, I chose to
add an additional if case that lets the ellipse containment check match
a few more cases when we know the two ellipses share an anchor point.

Change-Id: I6c8bc9a30d19a56f25da7d9be7832ff72dde1765
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/315636
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
Michael Ludwig 2020-09-08 11:14:09 -04:00 committed by Skia Commit-Bot
parent 9bfe92a39d
commit 04b9443274
2 changed files with 32 additions and 1 deletions

View File

@ -790,7 +790,22 @@ SkRRect SkRRectPriv::ConservativeIntersect(const SkRRect& a, const SkRRect& b) {
SkPoint aCorner = getCorner(a.rect(), corner); SkPoint aCorner = getCorner(a.rect(), corner);
SkPoint bCorner = getCorner(b.rect(), corner); SkPoint bCorner = getCorner(b.rect(), corner);
if (test == aCorner) { if (test == aCorner && test == bCorner) {
// The round rects share a corner anchor, so pick A or B such that its X and Y radii
// are both larger than the other rrect's, or return false if neither A or B has the max
// corner radii (this is more permissive than the single corner tests below).
SkVector aRadii = a.radii(corner);
SkVector bRadii = b.radii(corner);
if (aRadii.fX >= bRadii.fX && aRadii.fY >= bRadii.fY) {
*radii = aRadii;
return true;
} else if (bRadii.fX >= aRadii.fX && bRadii.fY >= aRadii.fY) {
*radii = bRadii;
return true;
} else {
return false;
}
} else if (test == aCorner) {
// Test that A's ellipse is contained by B. This is a non-trivial function to evaluate // Test that A's ellipse is contained by B. This is a non-trivial function to evaluate
// so we resrict it to when the corners have the same radii. If not, we use the more // so we resrict it to when the corners have the same radii. If not, we use the more
// conservative test that the extreme point of A's bounding box is contained in B. // conservative test that the extreme point of A's bounding box is contained in B.

View File

@ -1207,6 +1207,22 @@ static void test_conservative_intersection(skiatest::Reporter* reporter) {
verify_success(reporter, a, make_inset(a, 1.f, 1.f), kB, kB, kB, kB); verify_success(reporter, a, make_inset(a, 1.f, 1.f), kB, kB, kB, kB);
verify_success(reporter, make_inset(b, 2.f, 2.f), b, kA, kA, kA, kA); verify_success(reporter, make_inset(b, 2.f, 2.f), b, kA, kA, kA, kA);
// A rectangle exactly matching the corners of the rrect bounds keeps the rrect radii,
// regardless of whether or not it's the 1st or 2nd arg to ConservativeIntersect.
SkRRect c = SkRRect::MakeRectXY({0.f, 0.f, 10.f, 10.f}, 2.f, 2.f);
SkRRect cT = SkRRect::MakeRect({0.f, 0.f, 10.f, 5.f});
verify_success(reporter, c, cT, kA, kA, kRect, kRect);
verify_success(reporter, cT, c, kB, kB, kRect, kRect);
SkRRect cB = SkRRect::MakeRect({0.f, 5.f, 10.f, 10.});
verify_success(reporter, c, cB, kRect, kRect, kA, kA);
verify_success(reporter, cB, c, kRect, kRect, kB, kB);
SkRRect cL = SkRRect::MakeRect({0.f, 0.f, 5.f, 10.f});
verify_success(reporter, c, cL, kA, kRect, kRect, kA);
verify_success(reporter, cL, c, kB, kRect, kRect, kB);
SkRRect cR = SkRRect::MakeRect({5.f, 0.f, 10.f, 10.f});
verify_success(reporter, c, cR, kRect, kA, kA, kRect);
verify_success(reporter, cR, c, kRect, kB, kB, kRect);
// Failed intersection operations: // Failed intersection operations:
// A and B's bounds do not intersect // A and B's bounds do not intersect