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
This commit is contained in:
commit-bot@chromium.org 2014-03-24 19:24:59 +00:00
parent 1ba62629f4
commit 2a8be900db

View File

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