blob: 61652c17452e74033d8ed407e3c2535b77120caf [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"
12#include "GrTBackendEffectFactory.h"
13
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000014#include "SkRRect.h"
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +000015
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000016class GLCircularRRectEffect;
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000017
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000018class CircularRRectEffect : public GrEffect {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000019public:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000020 // This effect only supports circular corner rrects where the radius is >= kRadiusMin.
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000021 static const SkScalar kRadiusMin;
skia.committer@gmail.comf1f66c02014-03-05 03:02:06 +000022
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000023 enum CornerFlags {
24 kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner),
25 kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner),
26 kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
27 kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner),
28
29 kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag,
30 kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag,
31 kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag,
32 kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
33
34 kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag |
35 kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
36
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000037 };
38
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000039 // The flags are used to indicate which corners are circluar (unflagged corners are assumed to
40 // be square).
41 static GrEffectRef* Create(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000042
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000043 virtual ~CircularRRectEffect() {};
44 static const char* Name() { return "CircularRRect"; }
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000045
46 const SkRRect& getRRect() const { return fRRect; }
47
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000048 uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; }
skia.committer@gmail.com06acb582014-03-06 03:02:32 +000049
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000050 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000051
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000052 typedef GLCircularRRectEffect GLEffect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000053
54 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
55
56 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
57
58private:
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000059 CircularRRectEffect(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000060
61 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
62
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000063 SkRRect fRRect;
64 GrEffectEdgeType fEdgeType;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000065 uint32_t fCircularCornerFlags;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000066
67 GR_DECLARE_EFFECT_TEST;
68
69 typedef GrEffect INHERITED;
70};
71
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000072const SkScalar CircularRRectEffect::kRadiusMin = 0.5f;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000073
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000074GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000075 uint32_t circularCornerFlags,
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +000076 const SkRRect& rrect) {
commit-bot@chromium.orge5a041c2014-03-07 19:43:43 +000077 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000078 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000079 (edgeType, circularCornerFlags, rrect))));
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000080}
81
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000082void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000083 *validFlags = 0;
84}
85
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000086const GrBackendEffectFactory& CircularRRectEffect::getFactory() const {
87 return GrTBackendEffectFactory<CircularRRectEffect>::getInstance();
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000088}
89
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000090CircularRRectEffect::CircularRRectEffect(GrEffectEdgeType edgeType, uint32_t circularCornerFlags,
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000091 const SkRRect& rrect)
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +000092 : fRRect(rrect)
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000093 , fEdgeType(edgeType)
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +000094 , fCircularCornerFlags(circularCornerFlags) {
commit-bot@chromium.orge5280892014-02-21 17:52:29 +000095 this->setWillReadFragmentPosition();
96}
97
commit-bot@chromium.org4355f212014-03-12 15:32:50 +000098bool CircularRRectEffect::onIsEqual(const GrEffect& other) const {
99 const CircularRRectEffect& crre = CastEffect<CircularRRectEffect>(other);
100 // The corner flags are derived from fRRect, so no need to check them.
101 return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000102}
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000103
104//////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000105
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000106GR_DEFINE_EFFECT_TEST(CircularRRectEffect);
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000107
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000108GrEffectRef* CircularRRectEffect::TestCreate(SkRandom* random,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000109 GrContext*,
110 const GrDrawTargetCaps& caps,
111 GrTexture*[]) {
112 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
113 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
114 SkScalar r = random->nextRangeF(kRadiusMin, 9.f);
115 SkRRect rrect;
116 rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000117 GrEffectRef* effect;
118 do {
119 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
120 effect = GrRRectEffect::Create(et, rrect);
121 } while (NULL == effect);
122 return effect;
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000123}
124
125//////////////////////////////////////////////////////////////////////////////
126
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000127class GLCircularRRectEffect : public GrGLEffect {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000128public:
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000129 GLCircularRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000130
131 virtual void emitCode(GrGLShaderBuilder* builder,
132 const GrDrawEffect& drawEffect,
133 EffectKey key,
134 const char* outputColor,
135 const char* inputColor,
136 const TransformedCoordsArray&,
137 const TextureSamplerArray&) SK_OVERRIDE;
138
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000139 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000140
141 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
142
143private:
144 GrGLUniformManager::UniformHandle fInnerRectUniform;
145 GrGLUniformManager::UniformHandle fRadiusPlusHalfUniform;
146 SkRRect fPrevRRect;
147 typedef GrGLEffect INHERITED;
148};
149
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000150GLCircularRRectEffect::GLCircularRRectEffect(const GrBackendEffectFactory& factory,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000151 const GrDrawEffect& drawEffect)
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000152 : INHERITED (factory) {
153 fPrevRRect.setEmpty();
154}
155
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000156void GLCircularRRectEffect::emitCode(GrGLShaderBuilder* builder,
commit-bot@chromium.orge5280892014-02-21 17:52:29 +0000157 const GrDrawEffect& drawEffect,
158 EffectKey key,
159 const char* outputColor,
160 const char* inputColor,
161 const TransformedCoordsArray&,
162 const TextureSamplerArray& samplers) {
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000163 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000164 const char *rectName;
165 const char *radiusPlusHalfName;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000166 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
167 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
168 // only rectangular corners, that side's value corresponds to the rect edge's value outset by
169 // half a pixel.
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000170 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
171 kVec4f_GrSLType,
172 "innerRect",
173 &rectName);
174 fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
175 kFloat_GrSLType,
176 "radiusPlusHalf",
177 &radiusPlusHalfName);
178 const char* fragmentPos = builder->fragmentPosition();
179 // At each quarter-circle corner we compute a vector that is the offset of the fragment position
180 // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
181 // to that corner. This means that points near the interior near the rrect top edge will have
182 // a vector that points straight up for both the TL left and TR corners. Computing an
183 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
184 // fragments near the other three edges will get the correct AA. Fragments in the interior of
185 // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
186 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
187 // The code below is a simplified version of the above that performs maxs on the vector
188 // components before computing distances and alpha values so that only one distance computation
189 // need be computed to determine the min alpha.
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000190 //
191 // For the cases where one half of the rrect is rectangular we drop one of the x or y
192 // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
193 // alphas together.
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000194 switch (crre.getCircularCornerFlags()) {
195 case CircularRRectEffect::kAll_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000196 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
197 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
198 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
199 builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
200 radiusPlusHalfName);
201 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000202 case CircularRRectEffect::kTopLeft_CornerFlag:
203 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
204 rectName, fragmentPos);
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000205 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
206 rectName, fragmentPos);
207 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
208 rectName, fragmentPos);
209 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
210 radiusPlusHalfName);
211 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000212 case CircularRRectEffect::kTopRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000213 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
214 fragmentPos, rectName, rectName, fragmentPos);
215 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
216 fragmentPos, rectName);
217 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
218 rectName, fragmentPos);
219 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
220 radiusPlusHalfName);
221 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000222 case CircularRRectEffect::kBottomRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000223 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
224 fragmentPos, rectName);
225 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
226 fragmentPos, rectName);
227 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
228 fragmentPos, rectName);
229 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
230 radiusPlusHalfName);
231 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000232 case CircularRRectEffect::kBottomLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000233 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
234 rectName, fragmentPos, fragmentPos, rectName);
235 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
236 rectName, fragmentPos);
237 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
238 fragmentPos, rectName);
239 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
240 radiusPlusHalfName);
241 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000242 case CircularRRectEffect::kLeft_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000243 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
244 builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
245 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
246 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
247 rectName, fragmentPos);
248 builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
249 radiusPlusHalfName);
250 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000251 case CircularRRectEffect::kTop_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000252 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
253 builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
254 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
255 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
256 rectName, fragmentPos);
257 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
258 radiusPlusHalfName);
259 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000260 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000261 builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
262 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
263 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
264 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
265 fragmentPos, rectName);
266 builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
267 radiusPlusHalfName);
268 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000269 case CircularRRectEffect::kBottom_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000270 builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
271 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
272 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
273 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
274 fragmentPos, rectName);
275 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
276 radiusPlusHalfName);
277 break;
278 }
skia.committer@gmail.com06acb582014-03-06 03:02:32 +0000279
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000280 if (kInverseFillAA_GrEffectEdgeType == crre.getEdgeType()) {
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000281 builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
282 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000283
284 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
285 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
286}
287
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000288GrGLEffect::EffectKey GLCircularRRectEffect::GenKey(const GrDrawEffect& drawEffect,
289 const GrGLCaps&) {
290 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000291 GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000292 return (crre.getCircularCornerFlags() << 3) | crre.getEdgeType();
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000293}
294
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000295void GLCircularRRectEffect::setData(const GrGLUniformManager& uman,
296 const GrDrawEffect& drawEffect) {
297 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
298 const SkRRect& rrect = crre.getRRect();
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000299 if (rrect != fPrevRRect) {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000300 SkRect rect = rrect.getBounds();
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000301 SkScalar radius = 0;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000302 switch (crre.getCircularCornerFlags()) {
303 case CircularRRectEffect::kAll_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000304 SkASSERT(rrect.isSimpleCircular());
305 radius = rrect.getSimpleRadii().fX;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000306 SkASSERT(radius >= CircularRRectEffect::kRadiusMin);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000307 rect.inset(radius, radius);
308 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000309 case CircularRRectEffect::kTopLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000310 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
311 rect.fLeft += radius;
312 rect.fTop += radius;
313 rect.fRight += 0.5f;
314 rect.fBottom += 0.5f;
315 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000316 case CircularRRectEffect::kTopRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000317 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000318 rect.fLeft -= 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000319 rect.fTop += radius;
320 rect.fRight -= radius;
321 rect.fBottom += 0.5f;
322 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000323 case CircularRRectEffect::kBottomRight_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000324 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000325 rect.fLeft -= 0.5f;
326 rect.fTop -= 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000327 rect.fRight -= radius;
328 rect.fBottom -= radius;
329 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000330 case CircularRRectEffect::kBottomLeft_CornerFlag:
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000331 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
332 rect.fLeft += radius;
bsalomon@google.comde9f2512014-03-11 17:09:17 +0000333 rect.fTop -= 0.5f;
334 rect.fRight += 0.5f;
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000335 rect.fBottom -= radius;
336 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000337 case CircularRRectEffect::kLeft_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000338 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
339 rect.fLeft += radius;
340 rect.fTop += radius;
341 rect.fRight += 0.5f;
342 rect.fBottom -= radius;
343 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000344 case CircularRRectEffect::kTop_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000345 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
346 rect.fLeft += radius;
347 rect.fTop += radius;
348 rect.fRight -= radius;
349 rect.fBottom += 0.5f;
350 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000351 case CircularRRectEffect::kRight_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000352 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
353 rect.fLeft -= 0.5f;
354 rect.fTop += radius;
355 rect.fRight -= radius;
356 rect.fBottom -= radius;
357 break;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000358 case CircularRRectEffect::kBottom_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000359 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
360 rect.fLeft += radius;
361 rect.fTop -= 0.5f;
362 rect.fRight -= radius;
363 rect.fBottom -= radius;
364 break;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000365 default:
366 GrCrash("Should have been one of the above cases.");
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000367 }
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000368 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
369 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
370 fPrevRRect = rrect;
371 }
372}
373
374//////////////////////////////////////////////////////////////////////////////
375
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000376class GLEllipticalRRectEffect;
377
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000378class EllipticalRRectEffect : public GrEffect {
379public:
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000380 // This effect currently works for these two classifications of SkRRects
381 enum RRectType {
382 kSimple_RRectType, // SkRRect::kSimple_Type
383 kNinePatch_RRectType, // The two left x radii are the same, the two
384 // top y radii are the same, etc.
385 };
386
387 // This effect only supports rrects where the radii are >= kRadiusMin.
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000388 static const SkScalar kRadiusMin;
389
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000390 static GrEffectRef* Create(GrEffectEdgeType, RRectType, const SkRRect&);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000391
392 virtual ~EllipticalRRectEffect() {};
393 static const char* Name() { return "EllipticalRRect"; }
394
395 const SkRRect& getRRect() const { return fRRect; }
396
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000397 RRectType getRRectType() const { return fRRectType; }
398
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000399 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
400
401 typedef GLEllipticalRRectEffect GLEffect;
402
403 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
404
405 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
406
407private:
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000408 EllipticalRRectEffect(GrEffectEdgeType, RRectType, const SkRRect&);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000409
410 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
411
412 SkRRect fRRect;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000413 RRectType fRRectType;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000414 GrEffectEdgeType fEdgeType;
415
416 GR_DECLARE_EFFECT_TEST;
417
418 typedef GrEffect INHERITED;
419};
420
421const SkScalar EllipticalRRectEffect::kRadiusMin = 0.5f;
422
423GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType,
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000424 RRectType rrType,
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000425 const SkRRect& rrect) {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000426 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType);
427 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrType,
428 rrect))));
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000429}
430
431void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
432 *validFlags = 0;
433}
434
435const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const {
436 return GrTBackendEffectFactory<EllipticalRRectEffect>::getInstance();
437}
438
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000439EllipticalRRectEffect::EllipticalRRectEffect(GrEffectEdgeType edgeType, RRectType rrType,
440 const SkRRect& rrect)
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000441 : fRRect(rrect)
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000442 , fRRectType(rrType)
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000443 , fEdgeType(edgeType){
444 this->setWillReadFragmentPosition();
445}
446
447bool EllipticalRRectEffect::onIsEqual(const GrEffect& other) const {
448 const EllipticalRRectEffect& erre = CastEffect<EllipticalRRectEffect>(other);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000449 // No need to check fRRectType as it is derived from fRRect.
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000450 return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
451}
452
453//////////////////////////////////////////////////////////////////////////////
454
455GR_DEFINE_EFFECT_TEST(EllipticalRRectEffect);
456
457GrEffectRef* EllipticalRRectEffect::TestCreate(SkRandom* random,
458 GrContext*,
459 const GrDrawTargetCaps& caps,
460 GrTexture*[]) {
461 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
462 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000463 SkVector r[4];
464 r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
465 // ensure at least one corner really is elliptical
466 do {
467 r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
468 } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
469
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000470 SkRRect rrect;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000471 if (random->nextBool()) {
472 // half the time create a four-radii rrect.
473 r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
474 r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
475
476 r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
477 r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
478
479 r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
480 r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
481
482 rrect.setRectRadii(SkRect::MakeWH(w, h), r);
483 } else {
484 rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
485 r[SkRRect::kUpperLeft_Corner].fY);
486 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000487 GrEffectRef* effect;
488 do {
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000489 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
490 effect = GrRRectEffect::Create(et, rrect);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000491 } while (NULL == effect);
492 return effect;
493}
494
495//////////////////////////////////////////////////////////////////////////////
496
497class GLEllipticalRRectEffect : public GrGLEffect {
498public:
499 GLEllipticalRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
500
501 virtual void emitCode(GrGLShaderBuilder* builder,
502 const GrDrawEffect& drawEffect,
503 EffectKey key,
504 const char* outputColor,
505 const char* inputColor,
506 const TransformedCoordsArray&,
507 const TextureSamplerArray&) SK_OVERRIDE;
508
509 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
510
511 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
512
513private:
514 GrGLUniformManager::UniformHandle fInnerRectUniform;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000515 GrGLUniformManager::UniformHandle fInvRadiiSqdUniform;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000516 SkRRect fPrevRRect;
517 typedef GrGLEffect INHERITED;
518};
519
520GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendEffectFactory& factory,
521 const GrDrawEffect& drawEffect)
522 : INHERITED (factory) {
523 fPrevRRect.setEmpty();
524}
525
526void GLEllipticalRRectEffect::emitCode(GrGLShaderBuilder* builder,
527 const GrDrawEffect& drawEffect,
528 EffectKey key,
529 const char* outputColor,
530 const char* inputColor,
531 const TransformedCoordsArray&,
532 const TextureSamplerArray& samplers) {
533 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
534 const char *rectName;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000535 // The inner rect is the rrect bounds inset by the x/y radii
536 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
537 kVec4f_GrSLType,
538 "innerRect",
539 &rectName);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000540 const char* fragmentPos = builder->fragmentPosition();
541 // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
542 // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
543 // to that corner. This means that points near the interior near the rrect top edge will have
544 // a vector that points straight up for both the TL left and TR corners. Computing an
545 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
546 // fragments near the other three edges will get the correct AA. Fragments in the interior of
547 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
548 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
549 // The code below is a simplified version of the above that performs maxs on the vector
550 // components before computing distances and alpha values so that only one distance computation
551 // need be computed to determine the min alpha.
552 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
553 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000554 switch (erre.getRRectType()) {
555 case EllipticalRRectEffect::kSimple_RRectType: {
556 const char *invRadiiXYSqdName;
557 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
558 kVec2f_GrSLType,
559 "invRadiiXY",
560 &invRadiiXYSqdName);
561 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
562 // Z is the x/y offsets divided by squared radii.
563 builder->fsCodeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
564 break;
565 }
566 case EllipticalRRectEffect::kNinePatch_RRectType: {
567 const char *invRadiiLTRBSqdName;
568 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
569 kVec4f_GrSLType,
570 "invRadiiLTRB",
571 &invRadiiLTRBSqdName);
572 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
573 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
574 // corner where both the x and y offsets are positive, hence the maxes. (The inverse
575 // squared radii will always be positive.)
576 builder->fsCodeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
577 invRadiiLTRBSqdName, invRadiiLTRBSqdName);
578 break;
579 }
580 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000581 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
582 builder->fsCodeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
583 // grad_dot is the squared length of the gradient of the implicit.
584 builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
585 builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
586 builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
587
588 if (kFillAA_GrEffectEdgeType == erre.getEdgeType()) {
589 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
590 } else {
591 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
592 }
593
594 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
595 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
596}
597
598GrGLEffect::EffectKey GLEllipticalRRectEffect::GenKey(const GrDrawEffect& drawEffect,
599 const GrGLCaps&) {
600 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000601 GR_STATIC_ASSERT(kLast_GrEffectEdgeType < (1 << 3));
602 return erre.getRRectType() | erre.getEdgeType() << 3;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000603}
604
605void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman,
606 const GrDrawEffect& drawEffect) {
607 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
608 const SkRRect& rrect = erre.getRRect();
609 if (rrect != fPrevRRect) {
610 SkRect rect = rrect.getBounds();
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000611 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
612 SkASSERT(r0.fX >= EllipticalRRectEffect::kRadiusMin);
613 SkASSERT(r0.fY >= EllipticalRRectEffect::kRadiusMin);
614 switch (erre.getRRectType()) {
615 case EllipticalRRectEffect::kSimple_RRectType:
616 rect.inset(r0.fX, r0.fY);
617 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
618 1.f / (r0.fY * r0.fY));
619 break;
620 case EllipticalRRectEffect::kNinePatch_RRectType: {
621 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
622 SkASSERT(r1.fX >= EllipticalRRectEffect::kRadiusMin);
623 SkASSERT(r1.fY >= EllipticalRRectEffect::kRadiusMin);
624 rect.fLeft += r0.fX;
625 rect.fTop += r0.fY;
626 rect.fRight -= r1.fX;
627 rect.fBottom -= r1.fY;
628 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
629 1.f / (r0.fY * r0.fY),
630 1.f / (r1.fX * r1.fX),
631 1.f / (r1.fY * r1.fY));
632 break;
633 }
634 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000635 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000636 fPrevRRect = rrect;
637 }
638}
639
640//////////////////////////////////////////////////////////////////////////////
641
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000642GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
commit-bot@chromium.orge5a041c2014-03-07 19:43:43 +0000643 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000644 return NULL;
645 }
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000646 uint32_t cornerFlags;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000647 if (rrect.isSimple()) {
648 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
649 if (rrect.getSimpleRadii().fX < CircularRRectEffect::kRadiusMin) {
650 return NULL;
651 }
652 cornerFlags = CircularRRectEffect::kAll_CornerFlags;
653 } else {
654 if (rrect.getSimpleRadii().fX < EllipticalRRectEffect::kRadiusMin ||
655 rrect.getSimpleRadii().fY < EllipticalRRectEffect::kRadiusMin) {
656 return NULL;
657 }
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000658 return EllipticalRRectEffect::Create(edgeType,
659 EllipticalRRectEffect::kSimple_RRectType, rrect);
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000660 }
commit-bot@chromium.orgf338d7c2014-03-17 21:17:30 +0000661 } else if (rrect.isComplex() || rrect.isNinePatch()) {
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000662 // Check for the "tab" cases - two adjacent circular corners and two square corners.
663 SkScalar radius = 0;
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000664 cornerFlags = 0;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000665 for (int c = 0; c < 4; ++c) {
666 const SkVector& r = rrect.radii((SkRRect::Corner)c);
667 SkASSERT((0 == r.fX) == (0 == r.fY));
668 if (0 == r.fX) {
669 continue;
670 }
671 if (r.fX != r.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.orgcb3672e2014-02-21 22:41:56 +0000676 radius = r.fX;
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000677 if (radius < CircularRRectEffect::kRadiusMin) {
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 cornerFlags = 1 << c;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000682 } else {
683 if (r.fX != radius) {
bsalomon@google.com44a435b2014-03-13 19:20:32 +0000684 cornerFlags = ~0U;
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000685 break;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000686 }
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000687 cornerFlags |= 1 << c;
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000688 }
689 }
690
commit-bot@chromium.orgdd584222014-03-10 16:08:22 +0000691 switch (cornerFlags) {
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:
699 case CircularRRectEffect::kBottom_CornerFlags:
700 case CircularRRectEffect::kAll_CornerFlags:
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000701 break;
702 default:
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000703 if (rrect.isNinePatch()) {
704 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
705 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
706 if (r0.fX >= EllipticalRRectEffect::kRadiusMin &&
707 r0.fY >= EllipticalRRectEffect::kRadiusMin &&
708 r1.fX >= EllipticalRRectEffect::kRadiusMin &&
709 r1.fY >= EllipticalRRectEffect::kRadiusMin) {
710 return EllipticalRRectEffect::Create(edgeType,
711 EllipticalRRectEffect::kNinePatch_RRectType,
712 rrect);
713 }
714 }
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000715 return NULL;
716 }
717 } else {
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000718 return NULL;
719 }
commit-bot@chromium.org4355f212014-03-12 15:32:50 +0000720 return CircularRRectEffect::Create(edgeType, cornerFlags, rrect);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000721}