blob: d39ab0d4b0e540f46f12d2646988d95f86290dca [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).
bsalomon83d081a2014-07-08 09:56:10 -070047 static GrEffect* 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
bsalomon83d081a2014-07-08 09:56:10 -070078GrEffect* CircularRRectEffect::Create(GrEffectEdgeType edgeType,
79 uint32_t circularCornerFlags,
80 const SkRRect& rrect) {
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +000081 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
82 return NULL;
83 }
bsalomon55fad7a2014-07-08 07:34:20 -070084 return SkNEW_ARGS(CircularRRectEffect, (edgeType, circularCornerFlags, rrect));
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000085}
86
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000087void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000088 *validFlags = 0;
89}
90
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000091const GrBackendEffectFactory& CircularRRectEffect::getFactory() const {
92 return GrTBackendEffectFactory<CircularRRectEffect>::getInstance();
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000093}
94
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000095CircularRRectEffect::CircularRRectEffect(GrEffectEdgeType edgeType, uint32_t circularCornerFlags,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000096 const SkRRect& rrect)
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000097 : fRRect(rrect)
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000098 , fEdgeType(edgeType)
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000099 , fCircularCornerFlags(circularCornerFlags) {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000100 this->setWillReadFragmentPosition();
101}
102
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000103bool CircularRRectEffect::onIsEqual(const GrEffect& other) const {
104 const CircularRRectEffect& crre = CastEffect<CircularRRectEffect>(other);
105 // The corner flags are derived from fRRect, so no need to check them.
106 return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000107}
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000108
109//////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000110
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000111GR_DEFINE_EFFECT_TEST(CircularRRectEffect);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000112
bsalomon83d081a2014-07-08 09:56:10 -0700113GrEffect* CircularRRectEffect::TestCreate(SkRandom* random,
114 GrContext*,
115 const GrDrawTargetCaps& caps,
116 GrTexture*[]) {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000117 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
118 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
119 SkScalar r = random->nextRangeF(kRadiusMin, 9.f);
120 SkRRect rrect;
121 rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
bsalomon83d081a2014-07-08 09:56:10 -0700122 GrEffect* effect;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000123 do {
124 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
125 effect = GrRRectEffect::Create(et, rrect);
126 } while (NULL == effect);
127 return effect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000128}
129
130//////////////////////////////////////////////////////////////////////////////
131
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000132class GLCircularRRectEffect : public GrGLEffect {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000133public:
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000134 GLCircularRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000135
136 virtual void emitCode(GrGLShaderBuilder* builder,
137 const GrDrawEffect& drawEffect,
138 EffectKey key,
139 const char* outputColor,
140 const char* inputColor,
141 const TransformedCoordsArray&,
142 const TextureSamplerArray&) SK_OVERRIDE;
143
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000144 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000145
146 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
147
148private:
149 GrGLUniformManager::UniformHandle fInnerRectUniform;
150 GrGLUniformManager::UniformHandle fRadiusPlusHalfUniform;
151 SkRRect fPrevRRect;
152 typedef GrGLEffect INHERITED;
153};
154
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000155GLCircularRRectEffect::GLCircularRRectEffect(const GrBackendEffectFactory& factory,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000156 const GrDrawEffect& drawEffect)
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000157 : INHERITED (factory) {
158 fPrevRRect.setEmpty();
159}
160
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000161void GLCircularRRectEffect::emitCode(GrGLShaderBuilder* builder,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000162 const GrDrawEffect& drawEffect,
163 EffectKey key,
164 const char* outputColor,
165 const char* inputColor,
166 const TransformedCoordsArray&,
167 const TextureSamplerArray& samplers) {
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000168 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000169 const char *rectName;
170 const char *radiusPlusHalfName;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000171 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
172 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
173 // only rectangular corners, that side's value corresponds to the rect edge's value outset by
174 // half a pixel.
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000175 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
176 kVec4f_GrSLType,
177 "innerRect",
178 &rectName);
179 fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
180 kFloat_GrSLType,
181 "radiusPlusHalf",
182 &radiusPlusHalfName);
183 const char* fragmentPos = builder->fragmentPosition();
184 // At each quarter-circle corner we compute a vector that is the offset of the fragment position
185 // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
186 // to that corner. This means that points near the interior near the rrect top edge will have
187 // a vector that points straight up for both the TL left and TR corners. Computing an
188 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
189 // fragments near the other three edges will get the correct AA. Fragments in the interior of
190 // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
191 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
192 // The code below is a simplified version of the above that performs maxs on the vector
193 // components before computing distances and alpha values so that only one distance computation
194 // need be computed to determine the min alpha.
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000195 //
196 // For the cases where one half of the rrect is rectangular we drop one of the x or y
197 // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
198 // alphas together.
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000199 switch (crre.getCircularCornerFlags()) {
200 case CircularRRectEffect::kAll_CornerFlags:
bsalomon22900002014-06-24 11:16:52 -0700201 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
202 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000203 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
204 builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
205 radiusPlusHalfName);
206 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000207 case CircularRRectEffect::kTopLeft_CornerFlag:
208 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
209 rectName, fragmentPos);
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000210 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
211 rectName, fragmentPos);
212 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
213 rectName, fragmentPos);
214 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
215 radiusPlusHalfName);
216 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000217 case CircularRRectEffect::kTopRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000218 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
219 fragmentPos, rectName, rectName, fragmentPos);
220 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
221 fragmentPos, rectName);
222 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
223 rectName, fragmentPos);
224 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
225 radiusPlusHalfName);
226 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000227 case CircularRRectEffect::kBottomRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000228 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
229 fragmentPos, rectName);
230 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
231 fragmentPos, rectName);
232 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
233 fragmentPos, rectName);
234 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
235 radiusPlusHalfName);
236 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000237 case CircularRRectEffect::kBottomLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000238 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
239 rectName, fragmentPos, fragmentPos, rectName);
240 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
241 rectName, fragmentPos);
242 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
243 fragmentPos, rectName);
244 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
245 radiusPlusHalfName);
246 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000247 case CircularRRectEffect::kLeft_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000248 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
249 builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
250 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
251 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
252 rectName, fragmentPos);
253 builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
254 radiusPlusHalfName);
255 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000256 case CircularRRectEffect::kTop_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000257 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
258 builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
259 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
260 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
261 rectName, fragmentPos);
262 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
263 radiusPlusHalfName);
264 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000265 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000266 builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
267 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
268 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
269 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
270 fragmentPos, rectName);
271 builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
272 radiusPlusHalfName);
273 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000274 case CircularRRectEffect::kBottom_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000275 builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
276 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
277 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
278 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
279 fragmentPos, rectName);
280 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
281 radiusPlusHalfName);
282 break;
283 }
skia.committer@gmail.com06acb582014-03-06 03:02:32 +0000284
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000285 if (kInverseFillAA_GrEffectEdgeType == crre.getEdgeType()) {
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000286 builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
287 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000288
289 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
290 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
291}
292
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000293GrGLEffect::EffectKey GLCircularRRectEffect::GenKey(const GrDrawEffect& drawEffect,
294 const GrGLCaps&) {
295 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000296 GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000297 return (crre.getCircularCornerFlags() << 3) | crre.getEdgeType();
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000298}
299
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000300void GLCircularRRectEffect::setData(const GrGLUniformManager& uman,
301 const GrDrawEffect& drawEffect) {
302 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
303 const SkRRect& rrect = crre.getRRect();
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000304 if (rrect != fPrevRRect) {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000305 SkRect rect = rrect.getBounds();
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000306 SkScalar radius = 0;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000307 switch (crre.getCircularCornerFlags()) {
308 case CircularRRectEffect::kAll_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000309 SkASSERT(rrect.isSimpleCircular());
310 radius = rrect.getSimpleRadii().fX;
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000311 SkASSERT(radius >= kRadiusMin);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000312 rect.inset(radius, radius);
313 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000314 case CircularRRectEffect::kTopLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000315 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
316 rect.fLeft += radius;
317 rect.fTop += radius;
318 rect.fRight += 0.5f;
319 rect.fBottom += 0.5f;
320 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000321 case CircularRRectEffect::kTopRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000322 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000323 rect.fLeft -= 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000324 rect.fTop += radius;
325 rect.fRight -= radius;
326 rect.fBottom += 0.5f;
327 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000328 case CircularRRectEffect::kBottomRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000329 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000330 rect.fLeft -= 0.5f;
331 rect.fTop -= 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000332 rect.fRight -= radius;
333 rect.fBottom -= radius;
334 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000335 case CircularRRectEffect::kBottomLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000336 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
337 rect.fLeft += radius;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000338 rect.fTop -= 0.5f;
339 rect.fRight += 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000340 rect.fBottom -= radius;
341 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000342 case CircularRRectEffect::kLeft_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000343 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
344 rect.fLeft += radius;
345 rect.fTop += radius;
346 rect.fRight += 0.5f;
347 rect.fBottom -= radius;
348 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000349 case CircularRRectEffect::kTop_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000350 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
351 rect.fLeft += radius;
352 rect.fTop += radius;
353 rect.fRight -= radius;
354 rect.fBottom += 0.5f;
355 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000356 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000357 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
358 rect.fLeft -= 0.5f;
359 rect.fTop += radius;
360 rect.fRight -= radius;
361 rect.fBottom -= radius;
362 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000363 case CircularRRectEffect::kBottom_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000364 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
365 rect.fLeft += radius;
366 rect.fTop -= 0.5f;
367 rect.fRight -= radius;
368 rect.fBottom -= radius;
369 break;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000370 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000371 SkFAIL("Should have been one of the above cases.");
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000372 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000373 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
374 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
375 fPrevRRect = rrect;
376 }
377}
378
379//////////////////////////////////////////////////////////////////////////////
380
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000381class GLEllipticalRRectEffect;
382
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000383class EllipticalRRectEffect : public GrEffect {
384public:
bsalomon83d081a2014-07-08 09:56:10 -0700385 static GrEffect* Create(GrEffectEdgeType, const SkRRect&);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000386
387 virtual ~EllipticalRRectEffect() {};
388 static const char* Name() { return "EllipticalRRect"; }
389
390 const SkRRect& getRRect() const { return fRRect; }
391
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000392
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000393 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
394
395 typedef GLEllipticalRRectEffect GLEffect;
396
397 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
398
399 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
400
401private:
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000402 EllipticalRRectEffect(GrEffectEdgeType, const SkRRect&);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000403
404 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
405
406 SkRRect fRRect;
407 GrEffectEdgeType fEdgeType;
408
409 GR_DECLARE_EFFECT_TEST;
410
411 typedef GrEffect INHERITED;
412};
413
bsalomon83d081a2014-07-08 09:56:10 -0700414GrEffect* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +0000415 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
416 return NULL;
417 }
bsalomon55fad7a2014-07-08 07:34:20 -0700418 return SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrect));
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000419}
420
421void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
422 *validFlags = 0;
423}
424
425const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const {
426 return GrTBackendEffectFactory<EllipticalRRectEffect>::getInstance();
427}
428
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000429EllipticalRRectEffect::EllipticalRRectEffect(GrEffectEdgeType edgeType, const SkRRect& rrect)
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000430 : fRRect(rrect)
431 , fEdgeType(edgeType){
432 this->setWillReadFragmentPosition();
433}
434
435bool EllipticalRRectEffect::onIsEqual(const GrEffect& other) const {
436 const EllipticalRRectEffect& erre = CastEffect<EllipticalRRectEffect>(other);
437 return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
438}
439
440//////////////////////////////////////////////////////////////////////////////
441
442GR_DEFINE_EFFECT_TEST(EllipticalRRectEffect);
443
bsalomon83d081a2014-07-08 09:56:10 -0700444GrEffect* EllipticalRRectEffect::TestCreate(SkRandom* random,
445 GrContext*,
446 const GrDrawTargetCaps& caps,
447 GrTexture*[]) {
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000448 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
449 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000450 SkVector r[4];
451 r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
452 // ensure at least one corner really is elliptical
453 do {
454 r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
455 } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
456
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000457 SkRRect rrect;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000458 if (random->nextBool()) {
459 // half the time create a four-radii rrect.
460 r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
461 r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
462
463 r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
464 r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
465
466 r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
467 r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
468
469 rrect.setRectRadii(SkRect::MakeWH(w, h), r);
470 } else {
471 rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
472 r[SkRRect::kUpperLeft_Corner].fY);
473 }
bsalomon83d081a2014-07-08 09:56:10 -0700474 GrEffect* effect;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000475 do {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000476 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
477 effect = GrRRectEffect::Create(et, rrect);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000478 } while (NULL == effect);
479 return effect;
480}
481
482//////////////////////////////////////////////////////////////////////////////
483
484class GLEllipticalRRectEffect : public GrGLEffect {
485public:
486 GLEllipticalRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
487
488 virtual void emitCode(GrGLShaderBuilder* builder,
489 const GrDrawEffect& drawEffect,
490 EffectKey key,
491 const char* outputColor,
492 const char* inputColor,
493 const TransformedCoordsArray&,
494 const TextureSamplerArray&) SK_OVERRIDE;
495
496 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
497
498 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
499
500private:
501 GrGLUniformManager::UniformHandle fInnerRectUniform;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000502 GrGLUniformManager::UniformHandle fInvRadiiSqdUniform;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000503 SkRRect fPrevRRect;
504 typedef GrGLEffect INHERITED;
505};
506
507GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendEffectFactory& factory,
508 const GrDrawEffect& drawEffect)
509 : INHERITED (factory) {
510 fPrevRRect.setEmpty();
511}
512
513void GLEllipticalRRectEffect::emitCode(GrGLShaderBuilder* builder,
514 const GrDrawEffect& drawEffect,
515 EffectKey key,
516 const char* outputColor,
517 const char* inputColor,
518 const TransformedCoordsArray&,
519 const TextureSamplerArray& samplers) {
520 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
521 const char *rectName;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000522 // The inner rect is the rrect bounds inset by the x/y radii
523 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
524 kVec4f_GrSLType,
525 "innerRect",
526 &rectName);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000527 const char* fragmentPos = builder->fragmentPosition();
528 // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
529 // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
530 // to that corner. This means that points near the interior near the rrect top edge will have
531 // a vector that points straight up for both the TL left and TR corners. Computing an
532 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
533 // fragments near the other three edges will get the correct AA. Fragments in the interior of
534 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
535 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
536 // The code below is a simplified version of the above that performs maxs on the vector
537 // components before computing distances and alpha values so that only one distance computation
538 // need be computed to determine the min alpha.
bsalomon22900002014-06-24 11:16:52 -0700539 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
540 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000541 switch (erre.getRRect().getType()) {
542 case SkRRect::kSimple_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000543 const char *invRadiiXYSqdName;
544 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
545 kVec2f_GrSLType,
546 "invRadiiXY",
547 &invRadiiXYSqdName);
548 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
549 // Z is the x/y offsets divided by squared radii.
550 builder->fsCodeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
551 break;
552 }
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000553 case SkRRect::kNinePatch_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000554 const char *invRadiiLTRBSqdName;
555 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
556 kVec4f_GrSLType,
557 "invRadiiLTRB",
558 &invRadiiLTRBSqdName);
559 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
560 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
561 // corner where both the x and y offsets are positive, hence the maxes. (The inverse
562 // squared radii will always be positive.)
563 builder->fsCodeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
564 invRadiiLTRBSqdName, invRadiiLTRBSqdName);
565 break;
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000566 }
567 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000568 SkFAIL("RRect should always be simple or nine-patch.");
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000569 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000570 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
571 builder->fsCodeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
572 // grad_dot is the squared length of the gradient of the implicit.
573 builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
commit-bot@chromium.org1b035d82014-04-09 17:11:09 +0000574 // avoid calling inversesqrt on zero.
575 builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000576 builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
577
578 if (kFillAA_GrEffectEdgeType == erre.getEdgeType()) {
579 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
580 } else {
581 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
582 }
583
584 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
585 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
586}
587
588GrGLEffect::EffectKey GLEllipticalRRectEffect::GenKey(const GrDrawEffect& drawEffect,
589 const GrGLCaps&) {
590 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000591 GR_STATIC_ASSERT(kLast_GrEffectEdgeType < (1 << 3));
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000592 return erre.getRRect().getType() | erre.getEdgeType() << 3;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000593}
594
595void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman,
596 const GrDrawEffect& drawEffect) {
597 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
598 const SkRRect& rrect = erre.getRRect();
599 if (rrect != fPrevRRect) {
600 SkRect rect = rrect.getBounds();
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000601 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000602 SkASSERT(r0.fX >= kRadiusMin);
603 SkASSERT(r0.fY >= kRadiusMin);
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000604 switch (erre.getRRect().getType()) {
605 case SkRRect::kSimple_Type:
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000606 rect.inset(r0.fX, r0.fY);
607 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
608 1.f / (r0.fY * r0.fY));
609 break;
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000610 case SkRRect::kNinePatch_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000611 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000612 SkASSERT(r1.fX >= kRadiusMin);
613 SkASSERT(r1.fY >= kRadiusMin);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000614 rect.fLeft += r0.fX;
615 rect.fTop += r0.fY;
616 rect.fRight -= r1.fX;
617 rect.fBottom -= r1.fY;
618 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
619 1.f / (r0.fY * r0.fY),
620 1.f / (r1.fX * r1.fX),
621 1.f / (r1.fY * r1.fY));
622 break;
623 }
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000624 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000625 SkFAIL("RRect should always be simple or nine-patch.");
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000626 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000627 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000628 fPrevRRect = rrect;
629 }
630}
631
632//////////////////////////////////////////////////////////////////////////////
633
bsalomon83d081a2014-07-08 09:56:10 -0700634GrEffect* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000635 if (rrect.isRect()) {
636 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
637 }
638
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +0000639 if (rrect.isOval()) {
640 return GrOvalEffect::Create(edgeType, rrect.getBounds());
641 }
642
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000643 if (rrect.isSimple()) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000644 if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) {
645 // In this case the corners are extremely close to rectangular and we collapse the
646 // clip to a rectangular clip.
647 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
648 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000649 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
skia.committer@gmail.com6e4eb212014-03-25 03:02:32 +0000650 return CircularRRectEffect::Create(edgeType, CircularRRectEffect::kAll_CornerFlags,
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000651 rrect);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000652 } else {
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000653 return EllipticalRRectEffect::Create(edgeType, rrect);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000654 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000655 }
656
657 if (rrect.isComplex() || rrect.isNinePatch()) {
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000658 // Check for the "tab" cases - two adjacent circular corners and two square corners.
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000659 SkScalar circularRadius = 0;
660 uint32_t cornerFlags = 0;
661
662 SkVector radii[4];
663 bool squashedRadii = false;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000664 for (int c = 0; c < 4; ++c) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000665 radii[c] = rrect.radii((SkRRect::Corner)c);
666 SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY));
667 if (0 == radii[c].fX) {
668 // The corner is square, so no need to squash or flag as circular.
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000669 continue;
670 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000671 if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) {
672 radii[c].set(0, 0);
673 squashedRadii = true;
674 continue;
675 }
676 if (radii[c].fX != radii[c].fY) {
bsalomon@google.com44a435b2014-03-13 19:20:32 +0000677 cornerFlags = ~0U;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000678 break;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000679 }
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000680 if (!cornerFlags) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000681 circularRadius = radii[c].fX;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000682 cornerFlags = 1 << c;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000683 } else {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000684 if (radii[c].fX != circularRadius) {
bsalomon@google.com44a435b2014-03-13 19:20:32 +0000685 cornerFlags = ~0U;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000686 break;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000687 }
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000688 cornerFlags |= 1 << c;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000689 }
690 }
691
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000692 switch (cornerFlags) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000693 case CircularRRectEffect::kAll_CornerFlags:
694 // This rrect should have been caught in the simple case above. Though, it would
695 // be correctly handled in the fallthrough code.
696 SkASSERT(false);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000697 case CircularRRectEffect::kTopLeft_CornerFlag:
698 case CircularRRectEffect::kTopRight_CornerFlag:
699 case CircularRRectEffect::kBottomRight_CornerFlag:
700 case CircularRRectEffect::kBottomLeft_CornerFlag:
701 case CircularRRectEffect::kLeft_CornerFlags:
702 case CircularRRectEffect::kTop_CornerFlags:
703 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000704 case CircularRRectEffect::kBottom_CornerFlags: {
705 SkTCopyOnFirstWrite<SkRRect> rr(rrect);
706 if (squashedRadii) {
707 rr.writable()->setRectRadii(rrect.getBounds(), radii);
708 }
709 return CircularRRectEffect::Create(edgeType, cornerFlags, *rr);
710 }
711 case CircularRRectEffect::kNone_CornerFlags:
712 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
713 default: {
714 if (squashedRadii) {
715 // If we got here then we squashed some but not all the radii to zero. (If all
716 // had been squashed cornerFlags would be 0.) The elliptical effect doesn't
717 // support some rounded and some square corners.
718 return NULL;
719 }
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000720 if (rrect.isNinePatch()) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000721 return EllipticalRRectEffect::Create(edgeType, rrect);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000722 }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000723 return NULL;
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000724 }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000725 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000726 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000727
728 return NULL;
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000729}