diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-24 19:24:59 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-24 19:24:59 +0000 |
commit | 2a8be900db664bb26dca1adcb3a524a1bb1f45e6 (patch) | |
tree | 3f660fe022223f798d6a7f2e0d222983f44d8164 /src/gpu | |
parent | 1ba62629f4d8300eb5ff82a83807119032eb0c02 (diff) |
When clipping treat rrect corners where either the x or y radius is < 0.5 as square.
BUG=skia:2181
R=robertphillips@google.com, jvanverth@google.com
Author: bsalomon@google.com
Review URL: https://codereview.chromium.org/200723011
git-svn-id: http://skia.googlecode.com/svn/trunk@13918 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/effects/GrRRectEffect.cpp | 119 |
1 files changed, 68 insertions, 51 deletions
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp index e4120c956a..1e8613b5bc 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; } |