blob: 1e8613b5bcd86c5a74c3d7614f337a0db9bafe68 [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.orgc2f78242014-02-19 15:18:05 +000013#include "GrTBackendEffectFactory.h"
14
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000015#include "SkRRect.h"
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +000016
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +000017// The effects defined here only handle rrect radii >= kRadiusMin.
18static const SkScalar kRadiusMin = SK_ScalarHalf;
19
20//////////////////////////////////////////////////////////////////////////////
21
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000022class GLCircularRRectEffect;
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000023
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000024class CircularRRectEffect : public GrEffect {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000025public:
skia.committer@gmail.comf1f66c02014-03-05 03:02:06 +000026
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000027 enum CornerFlags {
28 kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner),
29 kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner),
30 kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
31 kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner),
32
33 kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag,
34 kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag,
35 kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag,
36 kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
37
38 kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag |
39 kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
40
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +000041 kNone_CornerFlags = 0
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000042 };
43
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000044 // The flags are used to indicate which corners are circluar (unflagged corners are assumed to
45 // be square).
46 static GrEffectRef* Create(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000047
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000048 virtual ~CircularRRectEffect() {};
49 static const char* Name() { return "CircularRRect"; }
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000050
51 const SkRRect& getRRect() const { return fRRect; }
52
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000053 uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; }
skia.committer@gmail.com06acb582014-03-06 03:02:32 +000054
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000055 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000056
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000057 typedef GLCircularRRectEffect GLEffect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000058
59 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
60
61 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
62
63private:
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000064 CircularRRectEffect(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000065
66 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
67
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000068 SkRRect fRRect;
69 GrEffectEdgeType fEdgeType;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000070 uint32_t fCircularCornerFlags;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000071
72 GR_DECLARE_EFFECT_TEST;
73
74 typedef GrEffect INHERITED;
75};
76
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000077GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000078 uint32_t circularCornerFlags,
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000079 const SkRRect& rrect) {
commit-bot@chromium.orge5a041c2014-03-07 19:43:43 +000080 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000081 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000082 (edgeType, circularCornerFlags, rrect))));
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000083}
84
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000085void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000086 *validFlags = 0;
87}
88
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000089const GrBackendEffectFactory& CircularRRectEffect::getFactory() const {
90 return GrTBackendEffectFactory<CircularRRectEffect>::getInstance();
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000091}
92
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000093CircularRRectEffect::CircularRRectEffect(GrEffectEdgeType edgeType, uint32_t circularCornerFlags,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000094 const SkRRect& rrect)
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000095 : fRRect(rrect)
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000096 , fEdgeType(edgeType)
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000097 , fCircularCornerFlags(circularCornerFlags) {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000098 this->setWillReadFragmentPosition();
99}
100
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000101bool CircularRRectEffect::onIsEqual(const GrEffect& other) const {
102 const CircularRRectEffect& crre = CastEffect<CircularRRectEffect>(other);
103 // The corner flags are derived from fRRect, so no need to check them.
104 return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000105}
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000106
107//////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000108
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000109GR_DEFINE_EFFECT_TEST(CircularRRectEffect);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000110
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000111GrEffectRef* CircularRRectEffect::TestCreate(SkRandom* random,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000112 GrContext*,
113 const GrDrawTargetCaps& caps,
114 GrTexture*[]) {
115 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
116 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
117 SkScalar r = random->nextRangeF(kRadiusMin, 9.f);
118 SkRRect rrect;
119 rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000120 GrEffectRef* effect;
121 do {
122 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
123 effect = GrRRectEffect::Create(et, rrect);
124 } while (NULL == effect);
125 return effect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000126}
127
128//////////////////////////////////////////////////////////////////////////////
129
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000130class GLCircularRRectEffect : public GrGLEffect {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000131public:
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000132 GLCircularRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000133
134 virtual void emitCode(GrGLShaderBuilder* builder,
135 const GrDrawEffect& drawEffect,
136 EffectKey key,
137 const char* outputColor,
138 const char* inputColor,
139 const TransformedCoordsArray&,
140 const TextureSamplerArray&) SK_OVERRIDE;
141
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000142 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000143
144 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
145
146private:
147 GrGLUniformManager::UniformHandle fInnerRectUniform;
148 GrGLUniformManager::UniformHandle fRadiusPlusHalfUniform;
149 SkRRect fPrevRRect;
150 typedef GrGLEffect INHERITED;
151};
152
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000153GLCircularRRectEffect::GLCircularRRectEffect(const GrBackendEffectFactory& factory,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000154 const GrDrawEffect& drawEffect)
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000155 : INHERITED (factory) {
156 fPrevRRect.setEmpty();
157}
158
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000159void GLCircularRRectEffect::emitCode(GrGLShaderBuilder* builder,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000160 const GrDrawEffect& drawEffect,
161 EffectKey key,
162 const char* outputColor,
163 const char* inputColor,
164 const TransformedCoordsArray&,
165 const TextureSamplerArray& samplers) {
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000166 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000167 const char *rectName;
168 const char *radiusPlusHalfName;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000169 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
170 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
171 // only rectangular corners, that side's value corresponds to the rect edge's value outset by
172 // half a pixel.
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000173 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
174 kVec4f_GrSLType,
175 "innerRect",
176 &rectName);
177 fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
178 kFloat_GrSLType,
179 "radiusPlusHalf",
180 &radiusPlusHalfName);
181 const char* fragmentPos = builder->fragmentPosition();
182 // At each quarter-circle corner we compute a vector that is the offset of the fragment position
183 // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
184 // to that corner. This means that points near the interior near the rrect top edge will have
185 // a vector that points straight up for both the TL left and TR corners. Computing an
186 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
187 // fragments near the other three edges will get the correct AA. Fragments in the interior of
188 // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
189 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
190 // The code below is a simplified version of the above that performs maxs on the vector
191 // components before computing distances and alpha values so that only one distance computation
192 // need be computed to determine the min alpha.
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000193 //
194 // For the cases where one half of the rrect is rectangular we drop one of the x or y
195 // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
196 // alphas together.
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000197 switch (crre.getCircularCornerFlags()) {
198 case CircularRRectEffect::kAll_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000199 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
200 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
201 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
202 builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
203 radiusPlusHalfName);
204 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000205 case CircularRRectEffect::kTopLeft_CornerFlag:
206 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
207 rectName, fragmentPos);
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000208 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
209 rectName, fragmentPos);
210 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
211 rectName, fragmentPos);
212 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
213 radiusPlusHalfName);
214 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000215 case CircularRRectEffect::kTopRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000216 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
217 fragmentPos, rectName, rectName, fragmentPos);
218 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
219 fragmentPos, rectName);
220 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
221 rectName, fragmentPos);
222 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
223 radiusPlusHalfName);
224 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000225 case CircularRRectEffect::kBottomRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000226 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
227 fragmentPos, rectName);
228 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
229 fragmentPos, rectName);
230 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
231 fragmentPos, rectName);
232 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
233 radiusPlusHalfName);
234 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000235 case CircularRRectEffect::kBottomLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000236 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
237 rectName, fragmentPos, fragmentPos, rectName);
238 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
239 rectName, fragmentPos);
240 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
241 fragmentPos, rectName);
242 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
243 radiusPlusHalfName);
244 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000245 case CircularRRectEffect::kLeft_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000246 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
247 builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
248 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
249 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
250 rectName, fragmentPos);
251 builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
252 radiusPlusHalfName);
253 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000254 case CircularRRectEffect::kTop_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000255 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
256 builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
257 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
258 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
259 rectName, fragmentPos);
260 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
261 radiusPlusHalfName);
262 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000263 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000264 builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
265 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
266 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
267 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
268 fragmentPos, rectName);
269 builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
270 radiusPlusHalfName);
271 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000272 case CircularRRectEffect::kBottom_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000273 builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
274 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
275 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
276 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
277 fragmentPos, rectName);
278 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
279 radiusPlusHalfName);
280 break;
281 }
skia.committer@gmail.com06acb582014-03-06 03:02:32 +0000282
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000283 if (kInverseFillAA_GrEffectEdgeType == crre.getEdgeType()) {
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000284 builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
285 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000286
287 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
288 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
289}
290
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000291GrGLEffect::EffectKey GLCircularRRectEffect::GenKey(const GrDrawEffect& drawEffect,
292 const GrGLCaps&) {
293 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000294 GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000295 return (crre.getCircularCornerFlags() << 3) | crre.getEdgeType();
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000296}
297
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000298void GLCircularRRectEffect::setData(const GrGLUniformManager& uman,
299 const GrDrawEffect& drawEffect) {
300 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
301 const SkRRect& rrect = crre.getRRect();
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000302 if (rrect != fPrevRRect) {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000303 SkRect rect = rrect.getBounds();
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000304 SkScalar radius = 0;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000305 switch (crre.getCircularCornerFlags()) {
306 case CircularRRectEffect::kAll_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000307 SkASSERT(rrect.isSimpleCircular());
308 radius = rrect.getSimpleRadii().fX;
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000309 SkASSERT(radius >= kRadiusMin);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000310 rect.inset(radius, radius);
311 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000312 case CircularRRectEffect::kTopLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000313 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
314 rect.fLeft += radius;
315 rect.fTop += radius;
316 rect.fRight += 0.5f;
317 rect.fBottom += 0.5f;
318 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000319 case CircularRRectEffect::kTopRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000320 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000321 rect.fLeft -= 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000322 rect.fTop += radius;
323 rect.fRight -= radius;
324 rect.fBottom += 0.5f;
325 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000326 case CircularRRectEffect::kBottomRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000327 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000328 rect.fLeft -= 0.5f;
329 rect.fTop -= 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000330 rect.fRight -= radius;
331 rect.fBottom -= radius;
332 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000333 case CircularRRectEffect::kBottomLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000334 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
335 rect.fLeft += radius;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000336 rect.fTop -= 0.5f;
337 rect.fRight += 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000338 rect.fBottom -= radius;
339 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000340 case CircularRRectEffect::kLeft_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000341 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
342 rect.fLeft += radius;
343 rect.fTop += radius;
344 rect.fRight += 0.5f;
345 rect.fBottom -= radius;
346 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000347 case CircularRRectEffect::kTop_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000348 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
349 rect.fLeft += radius;
350 rect.fTop += radius;
351 rect.fRight -= radius;
352 rect.fBottom += 0.5f;
353 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000354 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000355 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
356 rect.fLeft -= 0.5f;
357 rect.fTop += radius;
358 rect.fRight -= radius;
359 rect.fBottom -= radius;
360 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000361 case CircularRRectEffect::kBottom_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000362 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
363 rect.fLeft += radius;
364 rect.fTop -= 0.5f;
365 rect.fRight -= radius;
366 rect.fBottom -= radius;
367 break;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000368 default:
369 GrCrash("Should have been one of the above cases.");
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000370 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000371 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
372 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
373 fPrevRRect = rrect;
374 }
375}
376
377//////////////////////////////////////////////////////////////////////////////
378
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000379class GLEllipticalRRectEffect;
380
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000381class EllipticalRRectEffect : public GrEffect {
382public:
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000383 static GrEffectRef* Create(GrEffectEdgeType, const SkRRect&);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000384
385 virtual ~EllipticalRRectEffect() {};
386 static const char* Name() { return "EllipticalRRect"; }
387
388 const SkRRect& getRRect() const { return fRRect; }
389
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000390
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000391 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
392
393 typedef GLEllipticalRRectEffect GLEffect;
394
395 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
396
397 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
398
399private:
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000400 EllipticalRRectEffect(GrEffectEdgeType, const SkRRect&);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000401
402 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
403
404 SkRRect fRRect;
405 GrEffectEdgeType fEdgeType;
406
407 GR_DECLARE_EFFECT_TEST;
408
409 typedef GrEffect INHERITED;
410};
411
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000412GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000413 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType);
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000414 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrect))));
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000415}
416
417void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
418 *validFlags = 0;
419}
420
421const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const {
422 return GrTBackendEffectFactory<EllipticalRRectEffect>::getInstance();
423}
424
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000425EllipticalRRectEffect::EllipticalRRectEffect(GrEffectEdgeType edgeType, const SkRRect& rrect)
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000426 : fRRect(rrect)
427 , fEdgeType(edgeType){
428 this->setWillReadFragmentPosition();
429}
430
431bool EllipticalRRectEffect::onIsEqual(const GrEffect& other) const {
432 const EllipticalRRectEffect& erre = CastEffect<EllipticalRRectEffect>(other);
433 return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
434}
435
436//////////////////////////////////////////////////////////////////////////////
437
438GR_DEFINE_EFFECT_TEST(EllipticalRRectEffect);
439
440GrEffectRef* EllipticalRRectEffect::TestCreate(SkRandom* random,
441 GrContext*,
442 const GrDrawTargetCaps& caps,
443 GrTexture*[]) {
444 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
445 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000446 SkVector r[4];
447 r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
448 // ensure at least one corner really is elliptical
449 do {
450 r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
451 } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
452
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000453 SkRRect rrect;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000454 if (random->nextBool()) {
455 // half the time create a four-radii rrect.
456 r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
457 r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
458
459 r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
460 r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
461
462 r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
463 r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
464
465 rrect.setRectRadii(SkRect::MakeWH(w, h), r);
466 } else {
467 rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
468 r[SkRRect::kUpperLeft_Corner].fY);
469 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000470 GrEffectRef* effect;
471 do {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000472 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
473 effect = GrRRectEffect::Create(et, rrect);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000474 } while (NULL == effect);
475 return effect;
476}
477
478//////////////////////////////////////////////////////////////////////////////
479
480class GLEllipticalRRectEffect : public GrGLEffect {
481public:
482 GLEllipticalRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
483
484 virtual void emitCode(GrGLShaderBuilder* builder,
485 const GrDrawEffect& drawEffect,
486 EffectKey key,
487 const char* outputColor,
488 const char* inputColor,
489 const TransformedCoordsArray&,
490 const TextureSamplerArray&) SK_OVERRIDE;
491
492 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
493
494 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
495
496private:
497 GrGLUniformManager::UniformHandle fInnerRectUniform;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000498 GrGLUniformManager::UniformHandle fInvRadiiSqdUniform;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000499 SkRRect fPrevRRect;
500 typedef GrGLEffect INHERITED;
501};
502
503GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendEffectFactory& factory,
504 const GrDrawEffect& drawEffect)
505 : INHERITED (factory) {
506 fPrevRRect.setEmpty();
507}
508
509void GLEllipticalRRectEffect::emitCode(GrGLShaderBuilder* builder,
510 const GrDrawEffect& drawEffect,
511 EffectKey key,
512 const char* outputColor,
513 const char* inputColor,
514 const TransformedCoordsArray&,
515 const TextureSamplerArray& samplers) {
516 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
517 const char *rectName;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000518 // The inner rect is the rrect bounds inset by the x/y radii
519 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
520 kVec4f_GrSLType,
521 "innerRect",
522 &rectName);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000523 const char* fragmentPos = builder->fragmentPosition();
524 // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
525 // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
526 // to that corner. This means that points near the interior near the rrect top edge will have
527 // a vector that points straight up for both the TL left and TR corners. Computing an
528 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
529 // fragments near the other three edges will get the correct AA. Fragments in the interior of
530 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
531 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
532 // The code below is a simplified version of the above that performs maxs on the vector
533 // components before computing distances and alpha values so that only one distance computation
534 // need be computed to determine the min alpha.
535 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
536 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000537 switch (erre.getRRect().getType()) {
538 case SkRRect::kSimple_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000539 const char *invRadiiXYSqdName;
540 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
541 kVec2f_GrSLType,
542 "invRadiiXY",
543 &invRadiiXYSqdName);
544 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
545 // Z is the x/y offsets divided by squared radii.
546 builder->fsCodeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
547 break;
548 }
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000549 case SkRRect::kNinePatch_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000550 const char *invRadiiLTRBSqdName;
551 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
552 kVec4f_GrSLType,
553 "invRadiiLTRB",
554 &invRadiiLTRBSqdName);
555 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
556 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
557 // corner where both the x and y offsets are positive, hence the maxes. (The inverse
558 // squared radii will always be positive.)
559 builder->fsCodeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
560 invRadiiLTRBSqdName, invRadiiLTRBSqdName);
561 break;
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000562 }
563 default:
564 GrCrash("RRect should always be simple or nine-patch.");
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000565 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000566 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
567 builder->fsCodeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
568 // grad_dot is the squared length of the gradient of the implicit.
569 builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
570 builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
571 builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
572
573 if (kFillAA_GrEffectEdgeType == erre.getEdgeType()) {
574 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
575 } else {
576 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
577 }
578
579 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
580 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
581}
582
583GrGLEffect::EffectKey GLEllipticalRRectEffect::GenKey(const GrDrawEffect& drawEffect,
584 const GrGLCaps&) {
585 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000586 GR_STATIC_ASSERT(kLast_GrEffectEdgeType < (1 << 3));
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000587 return erre.getRRect().getType() | erre.getEdgeType() << 3;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000588}
589
590void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman,
591 const GrDrawEffect& drawEffect) {
592 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
593 const SkRRect& rrect = erre.getRRect();
594 if (rrect != fPrevRRect) {
595 SkRect rect = rrect.getBounds();
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000596 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000597 SkASSERT(r0.fX >= kRadiusMin);
598 SkASSERT(r0.fY >= kRadiusMin);
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000599 switch (erre.getRRect().getType()) {
600 case SkRRect::kSimple_Type:
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000601 rect.inset(r0.fX, r0.fY);
602 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
603 1.f / (r0.fY * r0.fY));
604 break;
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000605 case SkRRect::kNinePatch_Type: {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000606 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000607 SkASSERT(r1.fX >= kRadiusMin);
608 SkASSERT(r1.fY >= kRadiusMin);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000609 rect.fLeft += r0.fX;
610 rect.fTop += r0.fY;
611 rect.fRight -= r1.fX;
612 rect.fBottom -= r1.fY;
613 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
614 1.f / (r0.fY * r0.fY),
615 1.f / (r1.fX * r1.fX),
616 1.f / (r1.fY * r1.fY));
617 break;
618 }
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000619 default:
620 GrCrash("RRect should always be simple or nine-patch.");
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000621 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000622 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000623 fPrevRRect = rrect;
624 }
625}
626
627//////////////////////////////////////////////////////////////////////////////
628
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000629GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
commit-bot@chromium.orge5a041c2014-03-07 19:43:43 +0000630 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000631 return NULL;
632 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000633
634 if (rrect.isRect()) {
635 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
636 }
637
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000638 if (rrect.isSimple()) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000639 if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) {
640 // In this case the corners are extremely close to rectangular and we collapse the
641 // clip to a rectangular clip.
642 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
643 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000644 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000645 return CircularRRectEffect::Create(edgeType, CircularRRectEffect::kAll_CornerFlags,
646 rrect);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000647 } else {
commit-bot@chromium.org9615d5f2014-03-20 21:39:03 +0000648 return EllipticalRRectEffect::Create(edgeType, rrect);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000649 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000650 }
651
652 if (rrect.isComplex() || rrect.isNinePatch()) {
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000653 // Check for the "tab" cases - two adjacent circular corners and two square corners.
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000654 SkScalar circularRadius = 0;
655 uint32_t cornerFlags = 0;
656
657 SkVector radii[4];
658 bool squashedRadii = false;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000659 for (int c = 0; c < 4; ++c) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000660 radii[c] = rrect.radii((SkRRect::Corner)c);
661 SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY));
662 if (0 == radii[c].fX) {
663 // The corner is square, so no need to squash or flag as circular.
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000664 continue;
665 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000666 if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) {
667 radii[c].set(0, 0);
668 squashedRadii = true;
669 continue;
670 }
671 if (radii[c].fX != radii[c].fY) {
bsalomon@google.com44a435b2014-03-13 19:20:32 +0000672 cornerFlags = ~0U;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000673 break;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000674 }
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000675 if (!cornerFlags) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000676 circularRadius = radii[c].fX;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000677 cornerFlags = 1 << c;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000678 } else {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000679 if (radii[c].fX != circularRadius) {
bsalomon@google.com44a435b2014-03-13 19:20:32 +0000680 cornerFlags = ~0U;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000681 break;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000682 }
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000683 cornerFlags |= 1 << c;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000684 }
685 }
686
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000687 switch (cornerFlags) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000688 case CircularRRectEffect::kAll_CornerFlags:
689 // This rrect should have been caught in the simple case above. Though, it would
690 // be correctly handled in the fallthrough code.
691 SkASSERT(false);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000692 case CircularRRectEffect::kTopLeft_CornerFlag:
693 case CircularRRectEffect::kTopRight_CornerFlag:
694 case CircularRRectEffect::kBottomRight_CornerFlag:
695 case CircularRRectEffect::kBottomLeft_CornerFlag:
696 case CircularRRectEffect::kLeft_CornerFlags:
697 case CircularRRectEffect::kTop_CornerFlags:
698 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000699 case CircularRRectEffect::kBottom_CornerFlags: {
700 SkTCopyOnFirstWrite<SkRRect> rr(rrect);
701 if (squashedRadii) {
702 rr.writable()->setRectRadii(rrect.getBounds(), radii);
703 }
704 return CircularRRectEffect::Create(edgeType, cornerFlags, *rr);
705 }
706 case CircularRRectEffect::kNone_CornerFlags:
707 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
708 default: {
709 if (squashedRadii) {
710 // If we got here then we squashed some but not all the radii to zero. (If all
711 // had been squashed cornerFlags would be 0.) The elliptical effect doesn't
712 // support some rounded and some square corners.
713 return NULL;
714 }
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000715 if (rrect.isNinePatch()) {
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000716 return EllipticalRRectEffect::Create(edgeType, rrect);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000717 }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000718 return NULL;
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000719 }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000720 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000721 }
commit-bot@chromium.org2a8be902014-03-24 19:24:59 +0000722
723 return NULL;
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000724}