std::unique_ptr<GrFragmentProcessor> GrRRectEffect::Make(GrClipEdgeType edgeType, const SkRRect& rrect, const GrShaderCaps& caps) { if (rrect.isRect()) { return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); } if (rrect.isOval()) { return GrOvalEffect::Make(edgeType, rrect.getBounds(), caps); } if (rrect.isSimple()) { if (SkRRectPriv::GetSimpleRadii(rrect).fX < kRadiusMin || SkRRectPriv::GetSimpleRadii(rrect).fY < kRadiusMin) { // In this case the corners are extremely close to rectangular and we collapse the // clip to a rectangular clip. return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); } if (SkRRectPriv::GetSimpleRadii(rrect).fX == SkRRectPriv::GetSimpleRadii(rrect).fY) { return CircularRRectEffect::Make(edgeType, CircularRRectEffect::kAll_CornerFlags, rrect); } else { return EllipticalRRectEffect::Make(edgeType, rrect); } } if (rrect.isComplex() || rrect.isNinePatch()) { // Check for the "tab" cases - two adjacent circular corners and two square corners. SkScalar circularRadius = 0; uint32_t cornerFlags = 0; SkVector radii[4]; bool squashedRadii = false; for (int c = 0; c < 4; ++c) { radii[c] = rrect.radii((SkRRect::Corner)c); SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY)); if (0 == radii[c].fX) { // The corner is square, so no need to squash or flag as circular. continue; } if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) { radii[c].set(0, 0); squashedRadii = true; continue; } if (radii[c].fX != radii[c].fY) { cornerFlags = ~0U; break; } if (!cornerFlags) { circularRadius = radii[c].fX; cornerFlags = 1 << c; } else { if (radii[c].fX != circularRadius) { cornerFlags = ~0U; break; } cornerFlags |= 1 << c; } } switch (cornerFlags) { case CircularRRectEffect::kAll_CornerFlags: // This rrect should have been caught in the simple case above. Though, it would // be correctly handled in the fallthrough code. SkASSERT(false); case CircularRRectEffect::kTopLeft_CornerFlag: case CircularRRectEffect::kTopRight_CornerFlag: case CircularRRectEffect::kBottomRight_CornerFlag: case CircularRRectEffect::kBottomLeft_CornerFlag: case CircularRRectEffect::kLeft_CornerFlags: case CircularRRectEffect::kTop_CornerFlags: case CircularRRectEffect::kRight_CornerFlags: case CircularRRectEffect::kBottom_CornerFlags: { SkTCopyOnFirstWrite<SkRRect> rr(rrect); if (squashedRadii) { rr.writable()->setRectRadii(rrect.getBounds(), radii); } return CircularRRectEffect::Make(edgeType, cornerFlags, *rr); } case CircularRRectEffect::kNone_CornerFlags: return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); default: { if (squashedRadii) { // If we got here then we squashed some but not all the radii to zero. (If all // had been squashed cornerFlags would be 0.) The elliptical effect doesn't // support some rounded and some square corners. return nullptr; } if (rrect.isNinePatch()) { return EllipticalRRectEffect::Make(edgeType, rrect); } return nullptr; } } } return nullptr; }