blob: 0f2178b577eae4e9a8806cf2c19ee109bf0f9ba3 [file] [log] [blame]
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrRRectEffect.h"
9
10#include "gl/GrGLEffect.h"
11#include "gl/GrGLSL.h"
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +000012#include "GrConvexPolyEffect.h"
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +000013#include "GrOvalEffect.h"
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +000014#include "GrTBackendEffectFactory.h"
15
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000016#include "SkRRect.h"
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +000017
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +000018// The effects defined here only handle rrect radii >= kRadiusMin.
19static const SkScalar kRadiusMin = SK_ScalarHalf;
20
21//////////////////////////////////////////////////////////////////////////////
22
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000023class GLCircularRRectEffect;
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000024
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000025class CircularRRectEffect : public GrEffect {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000026public:
skia.committer@gmail.comf1f66c02014-03-05 03:02:06 +000027
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000028 enum CornerFlags {
29 kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner),
30 kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner),
31 kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
32 kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner),
33
34 kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag,
35 kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag,
36 kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag,
37 kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
38
39 kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag |
40 kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
41
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +000042 kNone_CornerFlags = 0
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000043 };
44
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000045 // The flags are used to indicate which corners are circluar (unflagged corners are assumed to
46 // be square).
47 static GrEffectRef* Create(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000048
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000049 virtual ~CircularRRectEffect() {};
50 static const char* Name() { return "CircularRRect"; }
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000051
52 const SkRRect& getRRect() const { return fRRect; }
53
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000054 uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; }
skia.committer@gmail.com06acb582014-03-06 03:02:32 +000055
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000056 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000057
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000058 typedef GLCircularRRectEffect GLEffect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000059
60 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
61
62 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
63
64private:
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000065 CircularRRectEffect(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000066
67 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
68
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000069 SkRRect fRRect;
70 GrEffectEdgeType fEdgeType;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000071 uint32_t fCircularCornerFlags;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000072
73 GR_DECLARE_EFFECT_TEST;
74
75 typedef GrEffect INHERITED;
76};
77
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000078GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000079 uint32_t circularCornerFlags,
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000080 const SkRRect& rrect) {
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +000081 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
82 return NULL;
83 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000084 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000085 (edgeType, circularCornerFlags, rrect))));
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000086}
87
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000088void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000089 *validFlags = 0;
90}
91
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000092const GrBackendEffectFactory& CircularRRectEffect::getFactory() const {
93 return GrTBackendEffectFactory<CircularRRectEffect>::getInstance();
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000094}
95
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000096CircularRRectEffect::CircularRRectEffect(GrEffectEdgeType edgeType, uint32_t circularCornerFlags,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000097 const SkRRect& rrect)
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000098 : fRRect(rrect)
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000099 , fEdgeType(edgeType)
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000100 , fCircularCornerFlags(circularCornerFlags) {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000101 this->setWillReadFragmentPosition();
102}
103
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000104bool CircularRRectEffect::onIsEqual(const GrEffect& other) const {
105 const CircularRRectEffect& crre = CastEffect<CircularRRectEffect>(other);
106 // The corner flags are derived from fRRect, so no need to check them.
107 return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000108}
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000109
110//////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000111
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000112GR_DEFINE_EFFECT_TEST(CircularRRectEffect);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000113
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000114GrEffectRef* CircularRRectEffect::TestCreate(SkRandom* random,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000115 GrContext*,
116 const GrDrawTargetCaps& caps,
117 GrTexture*[]) {
118 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
119 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
120 SkScalar r = random->nextRangeF(kRadiusMin, 9.f);
121 SkRRect rrect;
122 rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000123 GrEffectRef* effect;
124 do {
125 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
126 effect = GrRRectEffect::Create(et, rrect);
127 } while (NULL == effect);
128 return effect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000129}
130
131//////////////////////////////////////////////////////////////////////////////
132
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000133class GLCircularRRectEffect : public GrGLEffect {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000134public:
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000135 GLCircularRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000136
137 virtual void emitCode(GrGLShaderBuilder* builder,
138 const GrDrawEffect& drawEffect,
139 EffectKey key,
140 const char* outputColor,
141 const char* inputColor,
142 const TransformedCoordsArray&,
143 const TextureSamplerArray&) SK_OVERRIDE;
144
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000145 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000146
147 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
148
149private:
150 GrGLUniformManager::UniformHandle fInnerRectUniform;
151 GrGLUniformManager::UniformHandle fRadiusPlusHalfUniform;
152 SkRRect fPrevRRect;
153 typedef GrGLEffect INHERITED;
154};
155
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000156GLCircularRRectEffect::GLCircularRRectEffect(const GrBackendEffectFactory& factory,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000157 const GrDrawEffect& drawEffect)
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000158 : INHERITED (factory) {
159 fPrevRRect.setEmpty();
160}
161
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000162void GLCircularRRectEffect::emitCode(GrGLShaderBuilder* builder,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000163 const GrDrawEffect& drawEffect,
164 EffectKey key,
165 const char* outputColor,
166 const char* inputColor,
167 const TransformedCoordsArray&,
168 const TextureSamplerArray& samplers) {
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000169 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000170 const char *rectName;
171 const char *radiusPlusHalfName;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000172 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
173 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
174 // only rectangular corners, that side's value corresponds to the rect edge's value outset by
175 // half a pixel.
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000176 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
177 kVec4f_GrSLType,
178 "innerRect",
179 &rectName);
180 fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
181 kFloat_GrSLType,
182 "radiusPlusHalf",
183 &radiusPlusHalfName);
184 const char* fragmentPos = builder->fragmentPosition();
185 // At each quarter-circle corner we compute a vector that is the offset of the fragment position
186 // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
187 // to that corner. This means that points near the interior near the rrect top edge will have
188 // a vector that points straight up for both the TL left and TR corners. Computing an
189 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
190 // fragments near the other three edges will get the correct AA. Fragments in the interior of
191 // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
192 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
193 // The code below is a simplified version of the above that performs maxs on the vector
194 // components before computing distances and alpha values so that only one distance computation
195 // need be computed to determine the min alpha.
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000196 //
197 // For the cases where one half of the rrect is rectangular we drop one of the x or y
198 // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
199 // alphas together.
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000200 switch (crre.getCircularCornerFlags()) {
201 case CircularRRectEffect::kAll_CornerFlags:
bsalomon160a52b2014-06-20 07:25:14 -0700202 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s;\n", rectName, fragmentPos);
203 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s - %s.zw;\n", fragmentPos, rectName);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000204 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
205 builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
206 radiusPlusHalfName);
207 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000208 case CircularRRectEffect::kTopLeft_CornerFlag:
209 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
210 rectName, fragmentPos);
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000211 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
212 rectName, fragmentPos);
213 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
214 rectName, fragmentPos);
215 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
216 radiusPlusHalfName);
217 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000218 case CircularRRectEffect::kTopRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000219 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
220 fragmentPos, rectName, rectName, fragmentPos);
221 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
222 fragmentPos, rectName);
223 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
224 rectName, fragmentPos);
225 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
226 radiusPlusHalfName);
227 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000228 case CircularRRectEffect::kBottomRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000229 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
230 fragmentPos, rectName);
231 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
232 fragmentPos, rectName);
233 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
234 fragmentPos, rectName);
235 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
236 radiusPlusHalfName);
237 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000238 case CircularRRectEffect::kBottomLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000239 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
240 rectName, fragmentPos, fragmentPos, rectName);
241 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
242 rectName, fragmentPos);
243 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
244 fragmentPos, rectName);
245 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
246 radiusPlusHalfName);
247 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000248 case CircularRRectEffect::kLeft_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000249 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
250 builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
251 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
252 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
253 rectName, fragmentPos);
254 builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
255 radiusPlusHalfName);
256 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000257 case CircularRRectEffect::kTop_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000258 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
259 builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
260 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
261 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
262 rectName, fragmentPos);
263 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
264 radiusPlusHalfName);
265 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000266 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000267 builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
268 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
269 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
270 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
271 fragmentPos, rectName);
272 builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
273 radiusPlusHalfName);
274 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000275 case CircularRRectEffect::kBottom_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000276 builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
277 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
278 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
279 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
280 fragmentPos, rectName);
281 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
282 radiusPlusHalfName);
283 break;
284 }
skia.committer@gmail.com06acb582014-03-06 03:02:32 +0000285
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000286 if (kInverseFillAA_GrEffectEdgeType == crre.getEdgeType()) {
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000287 builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
288 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000289
290 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
291 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
292}
293
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000294GrGLEffect::EffectKey GLCircularRRectEffect::GenKey(const GrDrawEffect& drawEffect,
295 const GrGLCaps&) {
296 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000297 GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000298 return (crre.getCircularCornerFlags() << 3) | crre.getEdgeType();
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000299}
300
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000301void GLCircularRRectEffect::setData(const GrGLUniformManager& uman,
302 const GrDrawEffect& drawEffect) {
303 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
304 const SkRRect& rrect = crre.getRRect();
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000305 if (rrect != fPrevRRect) {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000306 SkRect rect = rrect.getBounds();
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000307 SkScalar radius = 0;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000308 switch (crre.getCircularCornerFlags()) {
309 case CircularRRectEffect::kAll_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000310 SkASSERT(rrect.isSimpleCircular());
311 radius = rrect.getSimpleRadii().fX;
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000312 SkASSERT(radius >= kRadiusMin);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000313 rect.inset(radius, radius);
314 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000315 case CircularRRectEffect::kTopLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000316 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
317 rect.fLeft += radius;
318 rect.fTop += radius;
319 rect.fRight += 0.5f;
320 rect.fBottom += 0.5f;
321 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000322 case CircularRRectEffect::kTopRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000323 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000324 rect.fLeft -= 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000325 rect.fTop += radius;
326 rect.fRight -= radius;
327 rect.fBottom += 0.5f;
328 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000329 case CircularRRectEffect::kBottomRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000330 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000331 rect.fLeft -= 0.5f;
332 rect.fTop -= 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000333 rect.fRight -= radius;
334 rect.fBottom -= radius;
335 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000336 case CircularRRectEffect::kBottomLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000337 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
338 rect.fLeft += radius;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000339 rect.fTop -= 0.5f;
340 rect.fRight += 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000341 rect.fBottom -= radius;
342 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000343 case CircularRRectEffect::kLeft_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000344 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
345 rect.fLeft += radius;
346 rect.fTop += radius;
347 rect.fRight += 0.5f;
348 rect.fBottom -= radius;
349 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000350 case CircularRRectEffect::kTop_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000351 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
352 rect.fLeft += radius;
353 rect.fTop += radius;
354 rect.fRight -= radius;
355 rect.fBottom += 0.5f;
356 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000357 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000358 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
359 rect.fLeft -= 0.5f;
360 rect.fTop += radius;
361 rect.fRight -= radius;
362 rect.fBottom -= radius;
363 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000364 case CircularRRectEffect::kBottom_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000365 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
366 rect.fLeft += radius;
367 rect.fTop -= 0.5f;
368 rect.fRight -= radius;
369 rect.fBottom -= radius;
370 break;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000371 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000372 SkFAIL("Should have been one of the above cases.");
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000373 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000374 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
375 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
376 fPrevRRect = rrect;
377 }
378}
379
380//////////////////////////////////////////////////////////////////////////////
381
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000382class GLEllipticalRRectEffect;
383
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000384class EllipticalRRectEffect : public GrEffect {
385public:
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000386 static GrEffectRef* Create(GrEffectEdgeType, const SkRRect&);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000387
388 virtual ~EllipticalRRectEffect() {};
389 static const char* Name() { return "EllipticalRRect"; }
390
391 const SkRRect& getRRect() const { return fRRect; }
392
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000393
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000394 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
395
396 typedef GLEllipticalRRectEffect GLEffect;
397
398 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
399
400 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
401
402private:
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000403 EllipticalRRectEffect(GrEffectEdgeType, const SkRRect&);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000404
405 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
406
407 SkRRect fRRect;
408 GrEffectEdgeType fEdgeType;
409
410 GR_DECLARE_EFFECT_TEST;
411
412 typedef GrEffect INHERITED;
413};
414
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000415GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +0000416 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
417 return NULL;
418 }
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000419 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrect))));
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000420}
421
422void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
423 *validFlags = 0;
424}
425
426const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const {
427 return GrTBackendEffectFactory<EllipticalRRectEffect>::getInstance();
428}
429
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000430EllipticalRRectEffect::EllipticalRRectEffect(GrEffectEdgeType edgeType, const SkRRect& rrect)
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000431 : fRRect(rrect)
432 , fEdgeType(edgeType){
433 this->setWillReadFragmentPosition();
434}
435
436bool EllipticalRRectEffect::onIsEqual(const GrEffect& other) const {
437 const EllipticalRRectEffect& erre = CastEffect<EllipticalRRectEffect>(other);
438 return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
439}
440
441//////////////////////////////////////////////////////////////////////////////
442
443GR_DEFINE_EFFECT_TEST(EllipticalRRectEffect);
444
445GrEffectRef* EllipticalRRectEffect::TestCreate(SkRandom* random,
446 GrContext*,
447 const GrDrawTargetCaps& caps,
448 GrTexture*[]) {
449 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
450 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000451 SkVector r[4];
452 r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
453 // ensure at least one corner really is elliptical
454 do {
455 r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
456 } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
457
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000458 SkRRect rrect;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000459 if (random->nextBool()) {
460 // half the time create a four-radii rrect.
461 r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
462 r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
463
464 r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
465 r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
466
467 r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
468 r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
469
470 rrect.setRectRadii(SkRect::MakeWH(w, h), r);
471 } else {
472 rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
473 r[SkRRect::kUpperLeft_Corner].fY);
474 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000475 GrEffectRef* effect;
476 do {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000477 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
478 effect = GrRRectEffect::Create(et, rrect);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000479 } while (NULL == effect);
480 return effect;
481}
482
483//////////////////////////////////////////////////////////////////////////////
484
485class GLEllipticalRRectEffect : public GrGLEffect {
486public:
487 GLEllipticalRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
488
489 virtual void emitCode(GrGLShaderBuilder* builder,
490 const GrDrawEffect& drawEffect,
491 EffectKey key,
492 const char* outputColor,
493 const char* inputColor,
494 const TransformedCoordsArray&,
495 const TextureSamplerArray&) SK_OVERRIDE;
496
497 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
498
499 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
500
501private:
502 GrGLUniformManager::UniformHandle fInnerRectUniform;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000503 GrGLUniformManager::UniformHandle fInvRadiiSqdUniform;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000504 SkRRect fPrevRRect;
505 typedef GrGLEffect INHERITED;
506};
507
508GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendEffectFactory& factory,
509 const GrDrawEffect& drawEffect)
510 : INHERITED (factory) {
511 fPrevRRect.setEmpty();
512}
513
514void GLEllipticalRRectEffect::emitCode(GrGLShaderBuilder* builder,
515 const GrDrawEffect& drawEffect,
516 EffectKey key,
517 const char* outputColor,
518 const char* inputColor,
519 const TransformedCoordsArray&,
520 const TextureSamplerArray& samplers) {
521 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
522 const char *rectName;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000523 // The inner rect is the rrect bounds inset by the x/y radii
524 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
525 kVec4f_GrSLType,
526 "innerRect",
527 &rectName);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000528 const char* fragmentPos = builder->fragmentPosition();
529 // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
530 // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
531 // to that corner. This means that points near the interior near the rrect top edge will have
532 // a vector that points straight up for both the TL left and TR corners. Computing an
533 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
534 // fragments near the other three edges will get the correct AA. Fragments in the interior of
535 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
536 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
537 // The code below is a simplified version of the above that performs maxs on the vector
538 // components before computing distances and alpha values so that only one distance computation
539 // need be computed to determine the min alpha.
bsalomon160a52b2014-06-20 07:25:14 -0700540 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s;\n", rectName, fragmentPos);
541 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s - %s.zw;\n", fragmentPos, rectName);
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000542 switch (erre.getRRect().getType()) {
543 case SkRRect::kSimple_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000544 const char *invRadiiXYSqdName;
545 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
546 kVec2f_GrSLType,
547 "invRadiiXY",
548 &invRadiiXYSqdName);
549 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
550 // Z is the x/y offsets divided by squared radii.
551 builder->fsCodeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
552 break;
553 }
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000554 case SkRRect::kNinePatch_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000555 const char *invRadiiLTRBSqdName;
556 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
557 kVec4f_GrSLType,
558 "invRadiiLTRB",
559 &invRadiiLTRBSqdName);
560 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
561 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
562 // corner where both the x and y offsets are positive, hence the maxes. (The inverse
563 // squared radii will always be positive.)
564 builder->fsCodeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
565 invRadiiLTRBSqdName, invRadiiLTRBSqdName);
566 break;
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000567 }
568 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000569 SkFAIL("RRect should always be simple or nine-patch.");
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000570 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000571 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
572 builder->fsCodeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
573 // grad_dot is the squared length of the gradient of the implicit.
574 builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
commit-bot@chromium.org1b035d82014-04-09 17:11:09 +0000575 // avoid calling inversesqrt on zero.
576 builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000577 builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
578
579 if (kFillAA_GrEffectEdgeType == erre.getEdgeType()) {
580 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
581 } else {
582 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
583 }
584
585 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
586 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
587}
588
589GrGLEffect::EffectKey GLEllipticalRRectEffect::GenKey(const GrDrawEffect& drawEffect,
590 const GrGLCaps&) {
591 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000592 GR_STATIC_ASSERT(kLast_GrEffectEdgeType < (1 << 3));
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000593 return erre.getRRect().getType() | erre.getEdgeType() << 3;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000594}
595
596void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman,
597 const GrDrawEffect& drawEffect) {
598 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
599 const SkRRect& rrect = erre.getRRect();
600 if (rrect != fPrevRRect) {
601 SkRect rect = rrect.getBounds();
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000602 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000603 SkASSERT(r0.fX >= kRadiusMin);
604 SkASSERT(r0.fY >= kRadiusMin);
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000605 switch (erre.getRRect().getType()) {
606 case SkRRect::kSimple_Type:
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000607 rect.inset(r0.fX, r0.fY);
608 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
609 1.f / (r0.fY * r0.fY));
610 break;
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000611 case SkRRect::kNinePatch_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000612 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000613 SkASSERT(r1.fX >= kRadiusMin);
614 SkASSERT(r1.fY >= kRadiusMin);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000615 rect.fLeft += r0.fX;
616 rect.fTop += r0.fY;
617 rect.fRight -= r1.fX;
618 rect.fBottom -= r1.fY;
619 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
620 1.f / (r0.fY * r0.fY),
621 1.f / (r1.fX * r1.fX),
622 1.f / (r1.fY * r1.fY));
623 break;
624 }
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000625 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000626 SkFAIL("RRect should always be simple or nine-patch.");
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000627 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000628 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000629 fPrevRRect = rrect;
630 }
631}
632
633//////////////////////////////////////////////////////////////////////////////
634
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000635GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000636 if (rrect.isRect()) {
637 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
638 }
639
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +0000640 if (rrect.isOval()) {
641 return GrOvalEffect::Create(edgeType, rrect.getBounds());
642 }
643
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000644 if (rrect.isSimple()) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000645 if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) {
646 // In this case the corners are extremely close to rectangular and we collapse the
647 // clip to a rectangular clip.
648 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
649 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000650 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
skia.committer@gmail.com6e4eb212014-03-25 03:02:32 +0000651 return CircularRRectEffect::Create(edgeType, CircularRRectEffect::kAll_CornerFlags,
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000652 rrect);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000653 } else {
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000654 return EllipticalRRectEffect::Create(edgeType, rrect);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000655 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000656 }
657
658 if (rrect.isComplex() || rrect.isNinePatch()) {
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000659 // Check for the "tab" cases - two adjacent circular corners and two square corners.
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000660 SkScalar circularRadius = 0;
661 uint32_t cornerFlags = 0;
662
663 SkVector radii[4];
664 bool squashedRadii = false;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000665 for (int c = 0; c < 4; ++c) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000666 radii[c] = rrect.radii((SkRRect::Corner)c);
667 SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY));
668 if (0 == radii[c].fX) {
669 // The corner is square, so no need to squash or flag as circular.
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000670 continue;
671 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000672 if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) {
673 radii[c].set(0, 0);
674 squashedRadii = true;
675 continue;
676 }
677 if (radii[c].fX != radii[c].fY) {
bsalomon@google.com44a435b2014-03-13 19:20:32 +0000678 cornerFlags = ~0U;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000679 break;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000680 }
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000681 if (!cornerFlags) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000682 circularRadius = radii[c].fX;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000683 cornerFlags = 1 << c;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000684 } else {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000685 if (radii[c].fX != circularRadius) {
bsalomon@google.com44a435b2014-03-13 19:20:32 +0000686 cornerFlags = ~0U;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000687 break;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000688 }
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000689 cornerFlags |= 1 << c;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000690 }
691 }
692
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000693 switch (cornerFlags) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000694 case CircularRRectEffect::kAll_CornerFlags:
695 // This rrect should have been caught in the simple case above. Though, it would
696 // be correctly handled in the fallthrough code.
697 SkASSERT(false);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000698 case CircularRRectEffect::kTopLeft_CornerFlag:
699 case CircularRRectEffect::kTopRight_CornerFlag:
700 case CircularRRectEffect::kBottomRight_CornerFlag:
701 case CircularRRectEffect::kBottomLeft_CornerFlag:
702 case CircularRRectEffect::kLeft_CornerFlags:
703 case CircularRRectEffect::kTop_CornerFlags:
704 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000705 case CircularRRectEffect::kBottom_CornerFlags: {
706 SkTCopyOnFirstWrite<SkRRect> rr(rrect);
707 if (squashedRadii) {
708 rr.writable()->setRectRadii(rrect.getBounds(), radii);
709 }
710 return CircularRRectEffect::Create(edgeType, cornerFlags, *rr);
711 }
712 case CircularRRectEffect::kNone_CornerFlags:
713 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
714 default: {
715 if (squashedRadii) {
716 // If we got here then we squashed some but not all the radii to zero. (If all
717 // had been squashed cornerFlags would be 0.) The elliptical effect doesn't
718 // support some rounded and some square corners.
719 return NULL;
720 }
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000721 if (rrect.isNinePatch()) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000722 return EllipticalRRectEffect::Create(edgeType, rrect);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000723 }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000724 return NULL;
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000725 }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000726 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000727 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000728
729 return NULL;
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000730}