blob: 954a6f2d5d3d61e082c5001fc714a0f716f259eb [file] [log] [blame]
robertphillips@google.comf6747b02012-06-12 00:32:28 +00001/*
2 * Copyright 2012 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
joshualitt30ba4362014-08-21 20:18:45 -07008#include "gl/builders/GrGLProgramBuilder.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +00009#include "GrAARectRenderer.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000010#include "GrGpu.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000011#include "gl/GrGLEffect.h"
joshualitt249af152014-09-15 11:41:13 -070012#include "gl/GrGLGeometryProcessor.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000013#include "GrTBackendEffectFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000014#include "SkColorPriv.h"
joshualitt249af152014-09-15 11:41:13 -070015#include "effects/GrGeometryProcessor.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000016
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000017///////////////////////////////////////////////////////////////////////////////
18class GrGLAlignedRectEffect;
19
20// Axis Aligned special case
joshualitt249af152014-09-15 11:41:13 -070021class GrAlignedRectEffect : public GrGeometryProcessor {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000022public:
bsalomon83d081a2014-07-08 09:56:10 -070023 static GrEffect* Create() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000024 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
25 gAlignedRectEffect->ref();
26 return gAlignedRectEffect;
27 }
28
29 virtual ~GrAlignedRectEffect() {}
30
31 static const char* Name() { return "AlignedRectEdge"; }
32
33 virtual void getConstantColorComponents(GrColor* color,
34 uint32_t* validFlags) const SK_OVERRIDE {
35 *validFlags = 0;
36 }
37
joshualitt249af152014-09-15 11:41:13 -070038 const GrShaderVar& inRect() const { return fInRect; }
39
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000040 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
41 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
42 }
43
joshualitt249af152014-09-15 11:41:13 -070044 class GLEffect : public GrGLGeometryProcessor {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000045 public:
46 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
47 : INHERITED (factory) {}
48
joshualitt30ba4362014-08-21 20:18:45 -070049 virtual void emitCode(GrGLFullProgramBuilder* builder,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000050 const GrDrawEffect& drawEffect,
bsalomon63e99f72014-07-21 08:03:14 -070051 const GrEffectKey& key,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000052 const char* outputColor,
53 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +000054 const TransformedCoordsArray&,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000055 const TextureSamplerArray& samplers) SK_OVERRIDE {
56 // setup the varying for the Axis aligned rect effect
57 // xy -> interpolated offset
58 // zw -> w/2+0.5, h/2+0.5
59 const char *vsRectName, *fsRectName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000060 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000061
joshualitt249af152014-09-15 11:41:13 -070062 const GrShaderVar& inRect = drawEffect.castEffect<GrAlignedRectEffect>().inRect();
joshualitt30ba4362014-08-21 20:18:45 -070063 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
joshualitt249af152014-09-15 11:41:13 -070064 vsBuilder->codeAppendf("\t%s = %s;\n", vsRectName, inRect.c_str());
joshualitt30ba4362014-08-21 20:18:45 -070065
66 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000067 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt30ba4362014-08-21 20:18:45 -070068 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
69 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
70 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000071 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
72 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -070073 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
74 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000075 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
76 // value of coverage that is used. In other words it is the coverage that is
77 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -070078 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
79 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000080
81 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -070082 fsBuilder->codeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000083 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
84 fsRectName);
85 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -070086 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000087 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
88 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000089
commit-bot@chromium.org824c3462013-10-10 06:30:18 +000090
joshualitt30ba4362014-08-21 20:18:45 -070091 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000092 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000093 }
94
bsalomon63e99f72014-07-21 08:03:14 -070095 static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000096
kkinnunen7510b222014-07-30 00:04:16 -070097 virtual void setData(const GrGLProgramDataManager& pdman, const GrDrawEffect&) SK_OVERRIDE {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000098
99 private:
joshualitt249af152014-09-15 11:41:13 -0700100 typedef GrGLGeometryProcessor INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000101 };
102
103
104private:
joshualitt249af152014-09-15 11:41:13 -0700105 GrAlignedRectEffect()
106 : fInRect(this->addVertexAttrib(GrShaderVar("inRect",
107 kVec4f_GrSLType,
108 GrShaderVar::kAttribute_TypeModifier))) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000109 }
110
joshualitt249af152014-09-15 11:41:13 -0700111 const GrShaderVar& fInRect;
112
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000113 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
114
115 GR_DECLARE_EFFECT_TEST;
116
joshualitt249af152014-09-15 11:41:13 -0700117 typedef GrGeometryProcessor INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000118};
119
120
121GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
122
bsalomon83d081a2014-07-08 09:56:10 -0700123GrEffect* GrAlignedRectEffect::TestCreate(SkRandom* random,
124 GrContext* context,
125 const GrDrawTargetCaps&,
126 GrTexture* textures[]) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000127 return GrAlignedRectEffect::Create();
128}
129
130///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000131class GrGLRectEffect;
132
133/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000134 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000135 * for an arbitrarily oriented rect. The rect is specified as:
136 * Center of the rect
137 * Unit vector point down the height of the rect
138 * Half width + 0.5
139 * Half height + 0.5
140 * The center and vector are stored in a vec4 varying ("RectEdge") with the
141 * center in the xy components and the vector in the zw components.
142 * The munged width and height are stored in a vec2 varying ("WidthHeight")
143 * with the width in x and the height in y.
144 */
joshualitt249af152014-09-15 11:41:13 -0700145
146class GrRectEffect : public GrGeometryProcessor {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000147public:
bsalomon83d081a2014-07-08 09:56:10 -0700148 static GrEffect* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000149 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
150 gRectEffect->ref();
151 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000152 }
153
154 virtual ~GrRectEffect() {}
155
156 static const char* Name() { return "RectEdge"; }
157
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000158 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000159 uint32_t* validFlags) const SK_OVERRIDE {
160 *validFlags = 0;
161 }
162
joshualitt249af152014-09-15 11:41:13 -0700163 const GrShaderVar& inRectEdge() const { return fInRectEdge; }
164 const GrShaderVar& inWidthHeight() const { return fInWidthHeight; }
165
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000166 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
167 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
168 }
169
joshualitt249af152014-09-15 11:41:13 -0700170 class GLEffect : public GrGLGeometryProcessor {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000171 public:
172 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
173 : INHERITED (factory) {}
174
joshualitt30ba4362014-08-21 20:18:45 -0700175 virtual void emitCode(GrGLFullProgramBuilder* builder,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000176 const GrDrawEffect& drawEffect,
bsalomon63e99f72014-07-21 08:03:14 -0700177 const GrEffectKey& key,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000178 const char* outputColor,
179 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000180 const TransformedCoordsArray&,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000181 const TextureSamplerArray& samplers) SK_OVERRIDE {
182 // setup the varying for the center point and the unit vector
183 // that points down the height of the rect
184 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000185 builder->addVarying(kVec4f_GrSLType, "RectEdge",
186 &vsRectEdgeName, &fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700187
joshualitt249af152014-09-15 11:41:13 -0700188 const GrRectEffect& rectEffect = drawEffect.castEffect<GrRectEffect>();
joshualitt30ba4362014-08-21 20:18:45 -0700189 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
joshualitt249af152014-09-15 11:41:13 -0700190 vsBuilder->codeAppendf("%s = %s;", vsRectEdgeName, rectEffect.inRectEdge().c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000191
192 // setup the varying for width/2+.5 and height/2+.5
193 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000194 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
195 &vsWidthHeightName, &fsWidthHeightName);
joshualitt249af152014-09-15 11:41:13 -0700196 vsBuilder->codeAppendf("%s = %s;",
197 vsWidthHeightName,
198 rectEffect.inWidthHeight().c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000199
joshualitt30ba4362014-08-21 20:18:45 -0700200 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000201 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt30ba4362014-08-21 20:18:45 -0700202 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
203 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
204 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000205 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
206 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -0700207 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
208 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000209 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
210 // value of coverage that is used. In other words it is the coverage that is
211 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -0700212 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
213 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000214
215 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -0700216 fsBuilder->codeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
217 fsBuilder->fragmentPosition(), fsRectEdgeName);
218 fsBuilder->codeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000219 fsRectEdgeName, fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700220 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000221 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
222 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000223
224 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -0700225 fsBuilder->codeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000226 fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700227 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000228 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000229 fsWidthHeightName);
230
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000231
joshualitt30ba4362014-08-21 20:18:45 -0700232 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000233 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000234 }
235
bsalomon63e99f72014-07-21 08:03:14 -0700236 static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000237
kkinnunen7510b222014-07-30 00:04:16 -0700238 virtual void setData(const GrGLProgramDataManager& pdman, const GrDrawEffect&) SK_OVERRIDE {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000239
240 private:
joshualitt249af152014-09-15 11:41:13 -0700241 typedef GrGLGeometryProcessor INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000242 };
243
244
joshualitt249af152014-09-15 11:41:13 -0700245
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000246private:
joshualitt249af152014-09-15 11:41:13 -0700247 GrRectEffect()
248 : fInRectEdge(this->addVertexAttrib(GrShaderVar("inRectEdge",
249 kVec4f_GrSLType,
250 GrShaderVar::kAttribute_TypeModifier)))
251 , fInWidthHeight(this->addVertexAttrib(
252 GrShaderVar("inWidthHeight",
253 kVec2f_GrSLType,
254 GrShaderVar::kAttribute_TypeModifier))) {
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000255 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000256 }
257
258 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
259
joshualitt249af152014-09-15 11:41:13 -0700260 const GrShaderVar& fInRectEdge;
261 const GrShaderVar& fInWidthHeight;
262
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000263 GR_DECLARE_EFFECT_TEST;
264
joshualitt249af152014-09-15 11:41:13 -0700265 typedef GrGeometryProcessor INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000266};
267
268
269GR_DEFINE_EFFECT_TEST(GrRectEffect);
270
bsalomon83d081a2014-07-08 09:56:10 -0700271GrEffect* GrRectEffect::TestCreate(SkRandom* random,
272 GrContext* context,
273 const GrDrawTargetCaps&,
274 GrTexture* textures[]) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000275 return GrRectEffect::Create();
276}
277
278///////////////////////////////////////////////////////////////////////////////
279
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000280namespace {
bsalomon9c0822a2014-08-11 11:07:48 -0700281extern const GrVertexAttrib gAARectAttribs[] = {
282 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
283 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
284 {kVec4ub_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000285};
286
bsalomonc30aaa02014-08-13 07:15:29 -0700287// Should the coverage be multiplied into the color attrib or use a separate attrib.
288enum CoverageAttribType {
289 kUseColor_CoverageAttribType,
290 kUseCoverage_CoverageAttribType,
291};
292}
293
294static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
295 if (drawState->canTweakAlphaForCoverage()) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700296 drawState->setVertexAttribs<gAARectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700297 return kUseColor_CoverageAttribType;
298 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700299 drawState->setVertexAttribs<gAARectAttribs>(3, sizeof(SkPoint) + 2 * sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700300 return kUseCoverage_CoverageAttribType;
301 }
302}
303
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000304static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000305 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000306 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
307 r.fRight - dx, r.fBottom - dy, stride);
308}
309
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000310void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000311 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000312 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
313 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000314}
315
robertphillips@google.com6d067302012-12-18 21:47:47 +0000316static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000317 0, 1, 5, 5, 4, 0,
318 1, 2, 6, 6, 5, 1,
319 2, 3, 7, 7, 6, 2,
320 3, 0, 4, 4, 7, 3,
321 4, 5, 6, 6, 7, 4,
322};
323
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000324static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000325static const int kVertsPerAAFillRect = 8;
326static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000327
328GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000329 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
330 sizeof(uint16_t) *
331 kNumAAFillRectsInIndexBuffer;
332
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000333 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000334 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
bsalomon49f085d2014-09-05 13:34:00 -0700335 if (fAAFillRectIndexBuffer) {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000336 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000337 bool useTempData = (NULL == data);
338 if (useTempData) {
339 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
340 }
341 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
342 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
343 // the inner rect (for AA) and 2 for the inner rect.
344 int baseIdx = i * kIndicesPerAAFillRect;
345 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
346 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
347 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
348 }
349 }
350 if (useTempData) {
351 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000352 SkFAIL("Can't get AA Fill Rect indices into buffer!");
robertphillips@google.com6d067302012-12-18 21:47:47 +0000353 }
354 SkDELETE_ARRAY(data);
355 } else {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000356 fAAFillRectIndexBuffer->unmap();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000357 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000358 }
359 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000360
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000361 return fAAFillRectIndexBuffer;
362}
363
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000364static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000365 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
366 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
367 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
368 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
369
370 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
371 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
372 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
373 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
374
375 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
376 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
377 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
378 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
379};
380
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000381/**
382 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
383 * from the first index. The index layout:
384 * outer AA line: 0~3, 4~7
385 * outer edge: 8~11, 12~15
386 * inner edge: 16~19
387 * inner AA line: 20~23
388 * Following comes a bevel-stroke rect and its indices:
389 *
390 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000391 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000392 * * ______________________________ *
393 * * / 12 15 \ *
394 * * / \ *
395 * 0 * |8 16_____________________19 11 | * 3
396 * * | | | | *
397 * * | | **************** | | *
398 * * | | * 20 23 * | | *
399 * * | | * * | | *
400 * * | | * 21 22 * | | *
401 * * | | **************** | | *
402 * * | |____________________| | *
403 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000404 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000405 * * \13 __________________________14/ *
406 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000407 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000408 * 5 6
409 */
410static const uint16_t gBevelStrokeAARectIdx[] = {
411 // Draw outer AA, from outer AA line to outer edge, shift is 0.
412 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
413 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
414 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
415 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
416 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
417 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
418 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
419 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
420
421 // Draw the stroke, from outer edge to inner edge, shift is 8.
422 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
423 1 + 8, 5 + 8, 9 + 8,
424 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
425 6 + 8, 2 + 8, 10 + 8,
426 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
427 3 + 8, 7 + 8, 11 + 8,
428 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
429 4 + 8, 0 + 8, 8 + 8,
430
431 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
432 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
433 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
434 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
435 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
436};
437
438int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000439 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
440 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000441}
442
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000443GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
444 if (miterStroke) {
445 if (NULL == fAAMiterStrokeRectIndexBuffer) {
446 fAAMiterStrokeRectIndexBuffer =
447 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
bsalomon49f085d2014-09-05 13:34:00 -0700448 if (fAAMiterStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000449#ifdef SK_DEBUG
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000450 bool updated =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000451#endif
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000452 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
453 sizeof(gMiterStrokeAARectIdx));
454 GR_DEBUGASSERT(updated);
455 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000456 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000457 return fAAMiterStrokeRectIndexBuffer;
458 } else {
459 if (NULL == fAABevelStrokeRectIndexBuffer) {
460 fAABevelStrokeRectIndexBuffer =
461 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
bsalomon49f085d2014-09-05 13:34:00 -0700462 if (fAABevelStrokeRectIndexBuffer) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000463#ifdef SK_DEBUG
464 bool updated =
465#endif
466 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
467 sizeof(gBevelStrokeAARectIdx));
468 GR_DEBUGASSERT(updated);
469 }
470 }
471 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000472 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000473}
474
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000475void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
476 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000477 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000478 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700479 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000480 GrDrawState* drawState = target->drawState();
481
bsalomon9c0822a2014-08-11 11:07:48 -0700482 GrColor color = drawState->getColor();
483
bsalomonc30aaa02014-08-13 07:15:29 -0700484 CoverageAttribType covAttribType = set_rect_attribs(drawState);
485 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700486 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
487 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000488
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000489 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000490 if (!geo.succeeded()) {
491 GrPrintf("Failed to get space for vertices!\n");
492 return;
493 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000494
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000495 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
496 if (NULL == indexBuffer) {
497 GrPrintf("Failed to create index buffer!\n");
498 return;
499 }
500
501 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700502 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000503
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000504 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700505 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000506
robertphillips@google.com908aed82013-05-28 13:16:20 +0000507 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
508 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
509
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000510 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000511 // Temporarily #if'ed out. We don't want to pass in the devRect but
512 // right now it is computed in GrContext::apply_aa_to_rect and we don't
513 // want to throw away the work
514#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000515 SkRect devRect;
516 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000517#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000518
egdaniel7b3d5ee2014-08-28 05:41:14 -0700519 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
520 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000521 } else {
522 // compute transformed (1, 0) and (0, 1) vectors
523 SkVector vec[2] = {
524 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
525 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
526 };
527
528 vec[0].normalize();
529 vec[0].scale(SK_ScalarHalf);
530 vec[1].normalize();
531 vec[1].scale(SK_ScalarHalf);
532
robertphillips@google.com91b71162013-05-10 14:09:54 +0000533 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000534 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700535 rect.fRight, rect.fBottom, vstride);
536 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000537
robertphillips@google.com91b71162013-05-10 14:09:54 +0000538 // Now create the inset points and then outset the original
539 // rotated points
540
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000541 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700542 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
543 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
544 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000545 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700546 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
547 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
548 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000549 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700550 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
551 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
552 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000553 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700554 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
555 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
556 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000557 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000558
bsalomon9c0822a2014-08-11 11:07:48 -0700559 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000560 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000561 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700562 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700563 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
564 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700565 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700566 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700567 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000568 }
569
robertphillips@google.com908aed82013-05-28 13:16:20 +0000570 int scale;
571 if (inset < SK_ScalarHalf) {
572 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
573 SkASSERT(scale >= 0 && scale <= 255);
574 } else {
575 scale = 0xff;
576 }
577
bsalomon9c0822a2014-08-11 11:07:48 -0700578 GrColor innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700579 if (kUseCoverage_CoverageAttribType == covAttribType) {
580 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
581 } else {
582 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
583 }
egdaniel7b3d5ee2014-08-28 05:41:14 -0700584 verts += 4 * vstride;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000585 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700586 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700587 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
588 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700589 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700590 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700591 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000592 }
593
594 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000595 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
596 kVertsPerAAFillRect,
597 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000598 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000599}
600
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000601namespace {
602
603// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000604struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000605 SkPoint fPos;
606 SkPoint fCenter;
607 SkPoint fDir;
608 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000609};
610
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000611// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000612extern const GrVertexAttrib gAARectVertexAttribs[] = {
613 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000614 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
615 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000616};
617
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000618// Axis Aligned
619struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000620 SkPoint fPos;
621 SkPoint fOffset;
622 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000623};
624
625// Axis Aligned
626extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
627 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000628 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000629};
630
robertphillips@google.com42903302013-04-20 12:26:07 +0000631};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000632
633void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
634 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000635 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000636 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000637 GrDrawState* drawState = target->drawState();
638
639 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
640 combinedMatrix.mapPoints(&center, 1);
641
642 // compute transformed (0, 1) vector
643 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
644 dir.normalize();
645
646 // compute transformed (width, 0) and (0, height) vectors
647 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000648 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
649 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000650 };
651
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000652 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
653 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700654 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs),
655 sizeof(RectVertex));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000656
657 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
658 if (!geo.succeeded()) {
659 GrPrintf("Failed to get space for vertices!\n");
660 return;
661 }
662
663 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
664
bsalomon83d081a2014-07-08 09:56:10 -0700665 GrEffect* effect = GrRectEffect::Create();
joshualitt249af152014-09-15 11:41:13 -0700666 drawState->setGeometryProcessor(effect)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000667
668 for (int i = 0; i < 4; ++i) {
669 verts[i].fCenter = center;
670 verts[i].fDir = dir;
671 verts[i].fWidthHeight.fX = newWidth;
672 verts[i].fWidthHeight.fY = newHeight;
673 }
674
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000675 SkRect devRect;
676 combinedMatrix.mapRect(&devRect, rect);
677
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000678 SkRect devBounds = {
679 devRect.fLeft - SK_ScalarHalf,
680 devRect.fTop - SK_ScalarHalf,
681 devRect.fRight + SK_ScalarHalf,
682 devRect.fBottom + SK_ScalarHalf
683 };
684
685 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
686 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
687 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
688 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
689
690 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
691 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
692 target->resetIndexSource();
693}
694
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000695void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
696 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000697 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000698 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000699 GrDrawState* drawState = target->drawState();
700 SkASSERT(combinedMatrix.rectStaysRect());
701
egdaniel7b3d5ee2014-08-28 05:41:14 -0700702 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs),
703 sizeof(AARectVertex));
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000704
705 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
706 if (!geo.succeeded()) {
707 GrPrintf("Failed to get space for vertices!\n");
708 return;
709 }
710
711 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
712
bsalomon83d081a2014-07-08 09:56:10 -0700713 GrEffect* effect = GrAlignedRectEffect::Create();
joshualitt249af152014-09-15 11:41:13 -0700714 drawState->setGeometryProcessor(effect)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000715
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000716 SkRect devRect;
717 combinedMatrix.mapRect(&devRect, rect);
718
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000719 SkRect devBounds = {
720 devRect.fLeft - SK_ScalarHalf,
721 devRect.fTop - SK_ScalarHalf,
722 devRect.fRight + SK_ScalarHalf,
723 devRect.fBottom + SK_ScalarHalf
724 };
725
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000726 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000727 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
728 SkScalarHalf(devRect.height()) + SK_ScalarHalf
729 };
730
731 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
732 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
733 verts[0].fWidthHeight = widthHeight;
734
735 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
736 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
737 verts[1].fWidthHeight = widthHeight;
738
739 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
740 verts[2].fOffset = widthHeight;
741 verts[2].fWidthHeight = widthHeight;
742
743 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
744 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
745 verts[3].fWidthHeight = widthHeight;
746
747 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
748 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
749 target->resetIndexSource();
750}
751
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000752void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000753 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000754 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000755 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000756 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700757 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000758 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700759 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000760 if (width > 0) {
761 devStrokeSize.set(width, width);
762 combinedMatrix.mapVectors(&devStrokeSize, 1);
763 devStrokeSize.setAbs(devStrokeSize);
764 } else {
765 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
766 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000767
robertphillips@google.com18136d12013-05-10 11:05:58 +0000768 const SkScalar dx = devStrokeSize.fX;
769 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000770 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
771 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000772
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000773 // Temporarily #if'ed out. We don't want to pass in the devRect but
774 // right now it is computed in GrContext::apply_aa_to_rect and we don't
775 // want to throw away the work
776#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000777 SkRect devRect;
778 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000779#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000780
bsalomon@google.com81712882012-11-01 17:12:34 +0000781 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000782 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000783 SkScalar w = devRect.width() - dx;
784 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000785 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000786 }
787
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000788 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000789 devOutside.outset(rx, ry);
790
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000791 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700792 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000793 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700794 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
795 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000796 miterStroke = false;
797 }
798
799 if (spare <= 0 && miterStroke) {
bsalomon9c0822a2014-08-11 11:07:48 -0700800 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000801 return;
802 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000803
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000804 SkRect devInside(devRect);
805 devInside.inset(rx, ry);
806
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000807 SkRect devOutsideAssist(devRect);
808
809 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
810 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000811 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000812 if (!miterStroke) {
813 devOutside.inset(0, ry);
814 devOutsideAssist.outset(0, ry);
815 }
816
bsalomon9c0822a2014-08-11 11:07:48 -0700817 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000818}
819
820void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
821 GrDrawTarget* target,
822 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000823 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000824 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000825 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000826 GrDrawState* drawState = target->drawState();
827
bsalomonc30aaa02014-08-13 07:15:29 -0700828 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700829
830 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700831 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700832 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
833 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000834
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000835 int innerVertexNum = 4;
836 int outerVertexNum = miterStroke ? 4 : 8;
837 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
838
839 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000840 if (!geo.succeeded()) {
841 GrPrintf("Failed to get space for vertices!\n");
842 return;
843 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000844 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000845 if (NULL == indexBuffer) {
846 GrPrintf("Failed to create index buffer!\n");
847 return;
848 }
849
850 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700851 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000852
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000853 // We create vertices for four nested rectangles. There are two ramps from 0 to full
854 // coverage, one on the exterior of the stroke and the other on the interior.
855 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000856 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700857 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
858 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
859 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000860
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000861#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000862 // TODO: this only really works if the X & Y margins are the same all around
863 // the rect
864 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
865 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
866 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000867 if (miterStroke) {
868 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
869 } else {
870 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
871 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000872 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000873#else
874 SkScalar inset = SK_ScalarHalf;
875#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000876
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000877 if (miterStroke) {
878 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700879 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000880 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700881 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
882 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000883 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700884 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000885 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700886 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
887 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000888 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700889 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
890 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000891 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700892 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
893 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000894 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700895 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000896 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700897 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000898 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000899
bsalomon9c0822a2014-08-11 11:07:48 -0700900 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000901 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000902 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000903 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700904 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700905 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
906 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700907 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700908 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700909 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000910 }
911
bsalomon9c0822a2014-08-11 11:07:48 -0700912 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000913 int scale;
914 if (inset < SK_ScalarHalf) {
915 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
916 SkASSERT(scale >= 0 && scale <= 255);
917 } else {
918 scale = 0xff;
919 }
920
egdaniel7b3d5ee2014-08-28 05:41:14 -0700921 verts += outerVertexNum * vstride;
bsalomonc30aaa02014-08-13 07:15:29 -0700922 GrColor innerCoverage;
923 if (kUseCoverage_CoverageAttribType == covAttribType) {
924 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
925 } else {
926 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
927 }
928
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000929 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700930 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700931 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
932 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700933 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700934 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700935 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000936 }
937
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000938 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700939 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000940 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700941 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700942 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
943 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700944 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700945 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700946 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000947 }
948
949 target->setIndexSourceToBuffer(indexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000950 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
951 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000952}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000953
954void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
955 GrDrawTarget* target,
956 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700957 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000958 SkASSERT(combinedMatrix.rectStaysRect());
959 SkASSERT(!rects[1].isEmpty());
960
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000961 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000962 combinedMatrix.mapRect(&devOutside, rects[0]);
963 // can't call mapRect for devInside since it calls sort
964 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
965
966 if (devInside.isEmpty()) {
bsalomon9c0822a2014-08-11 11:07:48 -0700967 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000968 return;
969 }
970
bsalomon9c0822a2014-08-11 11:07:48 -0700971 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000972}