Index: src/gpu/effects/GrRRectEffect.cpp |
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp |
index e4120c956ae5156a8680a4e3f621cc36ec6b6031..1e8613b5bcd86c5a74c3d7614f337a0db9bafe68 100644 |
--- a/src/gpu/effects/GrRRectEffect.cpp |
+++ b/src/gpu/effects/GrRRectEffect.cpp |
@@ -9,16 +9,20 @@ |
#include "gl/GrGLEffect.h" |
#include "gl/GrGLSL.h" |
+#include "GrConvexPolyEffect.h" |
#include "GrTBackendEffectFactory.h" |
#include "SkRRect.h" |
+// The effects defined here only handle rrect radii >= kRadiusMin. |
+static const SkScalar kRadiusMin = SK_ScalarHalf; |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
class GLCircularRRectEffect; |
class CircularRRectEffect : public GrEffect { |
public: |
- // This effect only supports circular corner rrects where the radius is >= kRadiusMin. |
- static const SkScalar kRadiusMin; |
enum CornerFlags { |
kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner), |
@@ -34,6 +38,7 @@ public: |
kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag | |
kBottomLeft_CornerFlag | kBottomRight_CornerFlag, |
+ kNone_CornerFlags = 0 |
}; |
// The flags are used to indicate which corners are circluar (unflagged corners are assumed to |
@@ -69,8 +74,6 @@ private: |
typedef GrEffect INHERITED; |
}; |
-const SkScalar CircularRRectEffect::kRadiusMin = 0.5f; |
- |
GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType, |
uint32_t circularCornerFlags, |
const SkRRect& rrect) { |
@@ -303,7 +306,7 @@ void GLCircularRRectEffect::setData(const GrGLUniformManager& uman, |
case CircularRRectEffect::kAll_CornerFlags: |
SkASSERT(rrect.isSimpleCircular()); |
radius = rrect.getSimpleRadii().fX; |
- SkASSERT(radius >= CircularRRectEffect::kRadiusMin); |
+ SkASSERT(radius >= kRadiusMin); |
rect.inset(radius, radius); |
break; |
case CircularRRectEffect::kTopLeft_CornerFlag: |
@@ -377,9 +380,6 @@ class GLEllipticalRRectEffect; |
class EllipticalRRectEffect : public GrEffect { |
public: |
- // This effect only supports rrects where the radii are >= kRadiusMin. |
- static const SkScalar kRadiusMin; |
- |
static GrEffectRef* Create(GrEffectEdgeType, const SkRRect&); |
virtual ~EllipticalRRectEffect() {}; |
@@ -409,8 +409,6 @@ private: |
typedef GrEffect INHERITED; |
}; |
-const SkScalar EllipticalRRectEffect::kRadiusMin = 0.5f; |
- |
GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) { |
SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType); |
return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrect)))); |
@@ -596,8 +594,8 @@ void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman, |
if (rrect != fPrevRRect) { |
SkRect rect = rrect.getBounds(); |
const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); |
- SkASSERT(r0.fX >= EllipticalRRectEffect::kRadiusMin); |
- SkASSERT(r0.fY >= EllipticalRRectEffect::kRadiusMin); |
+ SkASSERT(r0.fX >= kRadiusMin); |
+ SkASSERT(r0.fY >= kRadiusMin); |
switch (erre.getRRect().getType()) { |
case SkRRect::kSimple_Type: |
rect.inset(r0.fX, r0.fY); |
@@ -606,8 +604,8 @@ void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman, |
break; |
case SkRRect::kNinePatch_Type: { |
const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); |
- SkASSERT(r1.fX >= EllipticalRRectEffect::kRadiusMin); |
- SkASSERT(r1.fY >= EllipticalRRectEffect::kRadiusMin); |
+ SkASSERT(r1.fX >= kRadiusMin); |
+ SkASSERT(r1.fY >= kRadiusMin); |
rect.fLeft += r0.fX; |
rect.fTop += r0.fY; |
rect.fRight -= r1.fX; |
@@ -632,43 +630,53 @@ GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rre |
if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) { |
return NULL; |
} |
- uint32_t cornerFlags; |
+ |
+ if (rrect.isRect()) { |
+ return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); |
+ } |
+ |
if (rrect.isSimple()) { |
+ if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) { |
+ // In this case the corners are extremely close to rectangular and we collapse the |
+ // clip to a rectangular clip. |
+ return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); |
+ } |
if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) { |
- if (rrect.getSimpleRadii().fX < CircularRRectEffect::kRadiusMin) { |
- return NULL; |
- } |
- cornerFlags = CircularRRectEffect::kAll_CornerFlags; |
+ return CircularRRectEffect::Create(edgeType, CircularRRectEffect::kAll_CornerFlags, |
+ rrect); |
} else { |
- if (rrect.getSimpleRadii().fX < EllipticalRRectEffect::kRadiusMin || |
- rrect.getSimpleRadii().fY < EllipticalRRectEffect::kRadiusMin) { |
- return NULL; |
- } |
return EllipticalRRectEffect::Create(edgeType, rrect); |
} |
- } else if (rrect.isComplex() || rrect.isNinePatch()) { |
+ } |
+ |
+ if (rrect.isComplex() || rrect.isNinePatch()) { |
// Check for the "tab" cases - two adjacent circular corners and two square corners. |
- SkScalar radius = 0; |
- cornerFlags = 0; |
+ SkScalar circularRadius = 0; |
+ uint32_t cornerFlags = 0; |
+ |
+ SkVector radii[4]; |
+ bool squashedRadii = false; |
for (int c = 0; c < 4; ++c) { |
- const SkVector& r = rrect.radii((SkRRect::Corner)c); |
- SkASSERT((0 == r.fX) == (0 == r.fY)); |
- if (0 == r.fX) { |
+ 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 (r.fX != r.fY) { |
+ if (radii[c].fX != radii[c].fY) { |
cornerFlags = ~0U; |
break; |
} |
if (!cornerFlags) { |
- radius = r.fX; |
- if (radius < CircularRRectEffect::kRadiusMin) { |
- cornerFlags = ~0U; |
- break; |
- } |
+ circularRadius = radii[c].fX; |
cornerFlags = 1 << c; |
} else { |
- if (r.fX != radius) { |
+ if (radii[c].fX != circularRadius) { |
cornerFlags = ~0U; |
break; |
} |
@@ -677,6 +685,10 @@ GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rre |
} |
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: |
@@ -684,24 +696,29 @@ GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rre |
case CircularRRectEffect::kLeft_CornerFlags: |
case CircularRRectEffect::kTop_CornerFlags: |
case CircularRRectEffect::kRight_CornerFlags: |
- case CircularRRectEffect::kBottom_CornerFlags: |
- case CircularRRectEffect::kAll_CornerFlags: |
- break; |
- default: |
+ case CircularRRectEffect::kBottom_CornerFlags: { |
+ SkTCopyOnFirstWrite<SkRRect> rr(rrect); |
+ if (squashedRadii) { |
+ rr.writable()->setRectRadii(rrect.getBounds(), radii); |
+ } |
+ return CircularRRectEffect::Create(edgeType, cornerFlags, *rr); |
+ } |
+ case CircularRRectEffect::kNone_CornerFlags: |
+ return GrConvexPolyEffect::Create(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 NULL; |
+ } |
if (rrect.isNinePatch()) { |
- const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); |
- const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); |
- if (r0.fX >= EllipticalRRectEffect::kRadiusMin && |
- r0.fY >= EllipticalRRectEffect::kRadiusMin && |
- r1.fX >= EllipticalRRectEffect::kRadiusMin && |
- r1.fY >= EllipticalRRectEffect::kRadiusMin) { |
- return EllipticalRRectEffect::Create(edgeType, rrect); |
- } |
+ return EllipticalRRectEffect::Create(edgeType, rrect); |
} |
return NULL; |
+ } |
} |
- } else { |
- return NULL; |
} |
- return CircularRRectEffect::Create(edgeType, cornerFlags, rrect); |
+ |
+ return NULL; |
} |