blob: ead4ea16a37aac51d45ca9e729dca52335f56774 [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
8#include "GrAARectRenderer.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +00009#include "GrGpu.h"
joshualitt47bb3822014-10-07 16:43:25 -070010#include "gl/builders/GrGLProgramBuilder.h"
joshualittb0a8a372014-09-23 09:50:21 -070011#include "gl/GrGLProcessor.h"
joshualitt249af152014-09-15 11:41:13 -070012#include "gl/GrGLGeometryProcessor.h"
joshualittb0a8a372014-09-23 09:50:21 -070013#include "GrTBackendProcessorFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000014#include "SkColorPriv.h"
joshualittb0a8a372014-09-23 09:50:21 -070015#include "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:
joshualittb0a8a372014-09-23 09:50:21 -070023 static GrGeometryProcessor* Create() {
bsalomon98b33eb2014-10-15 11:05:26 -070024 GR_CREATE_STATIC_PROCESSOR(gAlignedRectEffect, GrAlignedRectEffect, ());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000025 gAlignedRectEffect->ref();
26 return gAlignedRectEffect;
27 }
28
29 virtual ~GrAlignedRectEffect() {}
30
31 static const char* Name() { return "AlignedRectEdge"; }
32
joshualitt249af152014-09-15 11:41:13 -070033 const GrShaderVar& inRect() const { return fInRect; }
34
joshualittb0a8a372014-09-23 09:50:21 -070035 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
36 return GrTBackendGeometryProcessorFactory<GrAlignedRectEffect>::getInstance();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000037 }
38
joshualittb0a8a372014-09-23 09:50:21 -070039 class GLProcessor : public GrGLGeometryProcessor {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000040 public:
joshualittb0a8a372014-09-23 09:50:21 -070041 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000042 : INHERITED (factory) {}
43
joshualittc369e7c2014-10-22 10:56:26 -070044 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000045 // setup the varying for the Axis aligned rect effect
46 // xy -> interpolated offset
47 // zw -> w/2+0.5, h/2+0.5
joshualitt74077b92014-10-24 11:26:03 -070048 GrGLVertToFrag v(kVec4f_GrSLType);
49 args.fPB->addVarying("Rect", &v);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000050
joshualittc369e7c2014-10-22 10:56:26 -070051 const GrShaderVar& inRect = args.fGP.cast<GrAlignedRectEffect>().inRect();
52 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualitt74077b92014-10-24 11:26:03 -070053 vsBuilder->codeAppendf("\t%s = %s;\n", v.fsIn(), inRect.c_str());
joshualitt30ba4362014-08-21 20:18:45 -070054
joshualittc369e7c2014-10-22 10:56:26 -070055 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000056 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt74077b92014-10-24 11:26:03 -070057 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", v.fsIn());
58 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", v.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -070059 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000060 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
61 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -070062 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
63 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000064 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
65 // value of coverage that is used. In other words it is the coverage that is
66 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -070067 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
68 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000069
70 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -070071 fsBuilder->codeAppendf(
joshualitt74077b92014-10-24 11:26:03 -070072 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", v.fsIn(),
73 v.fsIn());
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000074 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -070075 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000076 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
joshualitt74077b92014-10-24 11:26:03 -070077 v.fsIn(), v.fsIn());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000078
commit-bot@chromium.org824c3462013-10-10 06:30:18 +000079
joshualittc369e7c2014-10-22 10:56:26 -070080 fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
81 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000082 }
83
joshualittb0a8a372014-09-23 09:50:21 -070084 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000085
joshualittb0a8a372014-09-23 09:50:21 -070086 virtual void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) SK_OVERRIDE {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000087
88 private:
joshualitt249af152014-09-15 11:41:13 -070089 typedef GrGLGeometryProcessor INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000090 };
91
92
93private:
joshualitt249af152014-09-15 11:41:13 -070094 GrAlignedRectEffect()
95 : fInRect(this->addVertexAttrib(GrShaderVar("inRect",
96 kVec4f_GrSLType,
97 GrShaderVar::kAttribute_TypeModifier))) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000098 }
99
joshualitt249af152014-09-15 11:41:13 -0700100 const GrShaderVar& fInRect;
101
bsalomon0e08fc12014-10-15 08:19:04 -0700102 virtual bool onIsEqual(const GrGeometryProcessor&) const SK_OVERRIDE { return true; }
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000103
egdaniel1a8ecdf2014-10-03 06:24:12 -0700104 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
egdanielccb2e382014-10-13 12:53:46 -0700105 inout->mulByUnknownAlpha();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700106 }
107
joshualittb0a8a372014-09-23 09:50:21 -0700108 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000109
joshualitt249af152014-09-15 11:41:13 -0700110 typedef GrGeometryProcessor INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000111};
112
113
joshualittb0a8a372014-09-23 09:50:21 -0700114GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrAlignedRectEffect);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000115
joshualittb0a8a372014-09-23 09:50:21 -0700116GrGeometryProcessor* GrAlignedRectEffect::TestCreate(SkRandom* random,
117 GrContext* context,
118 const GrDrawTargetCaps&,
119 GrTexture* textures[]) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000120 return GrAlignedRectEffect::Create();
121}
122
123///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000124class GrGLRectEffect;
125
126/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000127 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000128 * for an arbitrarily oriented rect. The rect is specified as:
129 * Center of the rect
130 * Unit vector point down the height of the rect
131 * Half width + 0.5
132 * Half height + 0.5
133 * The center and vector are stored in a vec4 varying ("RectEdge") with the
134 * center in the xy components and the vector in the zw components.
135 * The munged width and height are stored in a vec2 varying ("WidthHeight")
136 * with the width in x and the height in y.
137 */
joshualitt249af152014-09-15 11:41:13 -0700138
139class GrRectEffect : public GrGeometryProcessor {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000140public:
joshualittb0a8a372014-09-23 09:50:21 -0700141 static GrGeometryProcessor* Create() {
bsalomon98b33eb2014-10-15 11:05:26 -0700142 GR_CREATE_STATIC_PROCESSOR(gRectEffect, GrRectEffect, ());
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000143 gRectEffect->ref();
144 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000145 }
146
147 virtual ~GrRectEffect() {}
148
149 static const char* Name() { return "RectEdge"; }
150
joshualitt249af152014-09-15 11:41:13 -0700151 const GrShaderVar& inRectEdge() const { return fInRectEdge; }
152 const GrShaderVar& inWidthHeight() const { return fInWidthHeight; }
153
joshualittb0a8a372014-09-23 09:50:21 -0700154 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
155 return GrTBackendGeometryProcessorFactory<GrRectEffect>::getInstance();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000156 }
157
joshualittb0a8a372014-09-23 09:50:21 -0700158 class GLProcessor : public GrGLGeometryProcessor {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000159 public:
joshualittb0a8a372014-09-23 09:50:21 -0700160 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000161 : INHERITED (factory) {}
162
joshualittc369e7c2014-10-22 10:56:26 -0700163 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000164 // setup the varying for the center point and the unit vector
165 // that points down the height of the rect
joshualitt74077b92014-10-24 11:26:03 -0700166 GrGLVertToFrag rectEdge(kVec4f_GrSLType);
167 args.fPB->addVarying("RectEdge", &rectEdge);
joshualitt30ba4362014-08-21 20:18:45 -0700168
joshualittc369e7c2014-10-22 10:56:26 -0700169 const GrRectEffect& rectEffect = args.fGP.cast<GrRectEffect>();
170 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualitt74077b92014-10-24 11:26:03 -0700171 vsBuilder->codeAppendf("%s = %s;", rectEdge.vsOut(), rectEffect.inRectEdge().c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000172
173 // setup the varying for width/2+.5 and height/2+.5
joshualitt74077b92014-10-24 11:26:03 -0700174 GrGLVertToFrag widthHeight(kVec2f_GrSLType);
175 args.fPB->addVarying("WidthHeight", &widthHeight);
joshualitt249af152014-09-15 11:41:13 -0700176 vsBuilder->codeAppendf("%s = %s;",
joshualitt74077b92014-10-24 11:26:03 -0700177 widthHeight.vsOut(),
joshualitt249af152014-09-15 11:41:13 -0700178 rectEffect.inWidthHeight().c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000179
joshualittc369e7c2014-10-22 10:56:26 -0700180 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000181 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt74077b92014-10-24 11:26:03 -0700182 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", widthHeight.fsIn());
183 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", widthHeight.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700184 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000185 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
186 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -0700187 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
188 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000189 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
190 // value of coverage that is used. In other words it is the coverage that is
191 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -0700192 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
193 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000194
195 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -0700196 fsBuilder->codeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
joshualitt74077b92014-10-24 11:26:03 -0700197 fsBuilder->fragmentPosition(), rectEdge.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700198 fsBuilder->codeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
joshualitt74077b92014-10-24 11:26:03 -0700199 rectEdge.fsIn(), rectEdge.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700200 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000201 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
joshualitt74077b92014-10-24 11:26:03 -0700202 widthHeight.fsIn());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000203
204 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -0700205 fsBuilder->codeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
joshualitt74077b92014-10-24 11:26:03 -0700206 rectEdge.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700207 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000208 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
joshualitt74077b92014-10-24 11:26:03 -0700209 widthHeight.fsIn());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000210
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000211
joshualittc369e7c2014-10-22 10:56:26 -0700212 fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
213 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000214 }
215
joshualittb0a8a372014-09-23 09:50:21 -0700216 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000217
joshualittb0a8a372014-09-23 09:50:21 -0700218 virtual void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) SK_OVERRIDE {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000219
220 private:
joshualitt249af152014-09-15 11:41:13 -0700221 typedef GrGLGeometryProcessor INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000222 };
223
224
joshualitt249af152014-09-15 11:41:13 -0700225
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000226private:
joshualitt249af152014-09-15 11:41:13 -0700227 GrRectEffect()
228 : fInRectEdge(this->addVertexAttrib(GrShaderVar("inRectEdge",
229 kVec4f_GrSLType,
230 GrShaderVar::kAttribute_TypeModifier)))
231 , fInWidthHeight(this->addVertexAttrib(
232 GrShaderVar("inWidthHeight",
233 kVec2f_GrSLType,
234 GrShaderVar::kAttribute_TypeModifier))) {
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000235 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000236 }
237
bsalomon0e08fc12014-10-15 08:19:04 -0700238 virtual bool onIsEqual(const GrGeometryProcessor&) const SK_OVERRIDE { return true; }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000239
egdaniel1a8ecdf2014-10-03 06:24:12 -0700240 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
egdanielccb2e382014-10-13 12:53:46 -0700241 inout->mulByUnknownAlpha();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700242 }
243
joshualitt249af152014-09-15 11:41:13 -0700244 const GrShaderVar& fInRectEdge;
245 const GrShaderVar& fInWidthHeight;
246
joshualittb0a8a372014-09-23 09:50:21 -0700247 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000248
joshualitt249af152014-09-15 11:41:13 -0700249 typedef GrGeometryProcessor INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000250};
251
252
joshualittb0a8a372014-09-23 09:50:21 -0700253GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrRectEffect);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000254
joshualittb0a8a372014-09-23 09:50:21 -0700255GrGeometryProcessor* GrRectEffect::TestCreate(SkRandom* random,
256 GrContext* context,
257 const GrDrawTargetCaps&,
258 GrTexture* textures[]) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000259 return GrRectEffect::Create();
260}
261
262///////////////////////////////////////////////////////////////////////////////
263
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000264namespace {
bsalomon9c0822a2014-08-11 11:07:48 -0700265extern const GrVertexAttrib gAARectAttribs[] = {
266 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
267 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
egdaniele27065a2014-11-06 08:00:48 -0800268 {kFloat_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000269};
270
bsalomonc30aaa02014-08-13 07:15:29 -0700271// Should the coverage be multiplied into the color attrib or use a separate attrib.
272enum CoverageAttribType {
273 kUseColor_CoverageAttribType,
274 kUseCoverage_CoverageAttribType,
275};
276}
277
278static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
279 if (drawState->canTweakAlphaForCoverage()) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700280 drawState->setVertexAttribs<gAARectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700281 return kUseColor_CoverageAttribType;
282 } else {
egdaniele27065a2014-11-06 08:00:48 -0800283 drawState->setVertexAttribs<gAARectAttribs>(3, sizeof(SkPoint) + sizeof(SkColor) +
284 sizeof(float));
bsalomonc30aaa02014-08-13 07:15:29 -0700285 return kUseCoverage_CoverageAttribType;
286 }
287}
288
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000289static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000290 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000291 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
292 r.fRight - dx, r.fBottom - dy, stride);
293}
294
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000295void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000296 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000297 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
298 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000299}
300
robertphillips@google.com6d067302012-12-18 21:47:47 +0000301static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000302 0, 1, 5, 5, 4, 0,
303 1, 2, 6, 6, 5, 1,
304 2, 3, 7, 7, 6, 2,
305 3, 0, 4, 4, 7, 3,
306 4, 5, 6, 6, 7, 4,
307};
308
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000309static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000310static const int kVertsPerAAFillRect = 8;
311static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000312
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000313static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000314 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
315 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
316 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
317 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
318
319 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
320 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
321 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
322 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
323
324 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
325 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
326 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
327 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
328};
329
joshualitt5ead6da2014-10-22 16:00:29 -0700330static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
331static const int kVertsPerMiterStrokeRect = 16;
332static const int kNumMiterStrokeRectsInIndexBuffer = 256;
333
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000334/**
335 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
336 * from the first index. The index layout:
337 * outer AA line: 0~3, 4~7
338 * outer edge: 8~11, 12~15
339 * inner edge: 16~19
340 * inner AA line: 20~23
341 * Following comes a bevel-stroke rect and its indices:
342 *
343 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000344 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000345 * * ______________________________ *
346 * * / 12 15 \ *
347 * * / \ *
348 * 0 * |8 16_____________________19 11 | * 3
349 * * | | | | *
350 * * | | **************** | | *
351 * * | | * 20 23 * | | *
352 * * | | * * | | *
353 * * | | * 21 22 * | | *
354 * * | | **************** | | *
355 * * | |____________________| | *
356 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000357 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000358 * * \13 __________________________14/ *
359 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000360 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000361 * 5 6
362 */
363static const uint16_t gBevelStrokeAARectIdx[] = {
364 // Draw outer AA, from outer AA line to outer edge, shift is 0.
365 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
366 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
367 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
368 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
369 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
370 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
371 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
372 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
373
374 // Draw the stroke, from outer edge to inner edge, shift is 8.
375 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
376 1 + 8, 5 + 8, 9 + 8,
377 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
378 6 + 8, 2 + 8, 10 + 8,
379 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
380 3 + 8, 7 + 8, 11 + 8,
381 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
382 4 + 8, 0 + 8, 8 + 8,
383
384 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
385 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
386 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
387 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
388 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
389};
390
joshualitt5ead6da2014-10-22 16:00:29 -0700391static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
392static const int kVertsPerBevelStrokeRect = 24;
393static const int kNumBevelStrokeRectsInIndexBuffer = 256;
394
joshualittb44293e2014-10-28 08:12:18 -0700395static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000396 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
397 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000398}
399
joshualittb44293e2014-10-28 08:12:18 -0700400GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000401 if (miterStroke) {
402 if (NULL == fAAMiterStrokeRectIndexBuffer) {
403 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700404 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
405 kIndicesPerMiterStrokeRect,
406 kNumMiterStrokeRectsInIndexBuffer,
407 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000408 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000409 return fAAMiterStrokeRectIndexBuffer;
410 } else {
411 if (NULL == fAABevelStrokeRectIndexBuffer) {
412 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700413 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
414 kIndicesPerBevelStrokeRect,
415 kNumBevelStrokeRectsInIndexBuffer,
416 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000417 }
418 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000419 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000420}
421
joshualittb44293e2014-10-28 08:12:18 -0700422void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000423 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000424 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700425 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000426 GrDrawState* drawState = target->drawState();
427
bsalomon9c0822a2014-08-11 11:07:48 -0700428 GrColor color = drawState->getColor();
429
bsalomonc30aaa02014-08-13 07:15:29 -0700430 CoverageAttribType covAttribType = set_rect_attribs(drawState);
431 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700432 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
433 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000434
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000435 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000436 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700437 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000438 return;
439 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000440
joshualitt5ead6da2014-10-22 16:00:29 -0700441 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700442 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
443 kIndicesPerAAFillRect,
444 kNumAAFillRectsInIndexBuffer,
445 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700446 }
447 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000448 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700449 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000450 return;
451 }
452
453 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700454 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000455
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000456 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700457 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000458
robertphillips@google.com908aed82013-05-28 13:16:20 +0000459 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
460 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
461
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000462 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000463 // Temporarily #if'ed out. We don't want to pass in the devRect but
464 // right now it is computed in GrContext::apply_aa_to_rect and we don't
465 // want to throw away the work
466#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000467 SkRect devRect;
468 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000469#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000470
egdaniel7b3d5ee2014-08-28 05:41:14 -0700471 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
472 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000473 } else {
474 // compute transformed (1, 0) and (0, 1) vectors
475 SkVector vec[2] = {
476 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
477 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
478 };
479
480 vec[0].normalize();
481 vec[0].scale(SK_ScalarHalf);
482 vec[1].normalize();
483 vec[1].scale(SK_ScalarHalf);
484
robertphillips@google.com91b71162013-05-10 14:09:54 +0000485 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000486 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700487 rect.fRight, rect.fBottom, vstride);
488 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000489
robertphillips@google.com91b71162013-05-10 14:09:54 +0000490 // Now create the inset points and then outset the original
491 // rotated points
492
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000493 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700494 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
495 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
496 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000497 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700498 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
499 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
500 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000501 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700502 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
503 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
504 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000505 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700506 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
507 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
508 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000509 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000510
bsalomon9c0822a2014-08-11 11:07:48 -0700511 // 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 +0000512 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000513 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700514 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700515 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800516 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700517 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700518 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700519 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000520 }
521
robertphillips@google.com908aed82013-05-28 13:16:20 +0000522 int scale;
523 if (inset < SK_ScalarHalf) {
524 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
525 SkASSERT(scale >= 0 && scale <= 255);
526 } else {
527 scale = 0xff;
528 }
529
egdaniel7b3d5ee2014-08-28 05:41:14 -0700530 verts += 4 * vstride;
egdaniele27065a2014-11-06 08:00:48 -0800531
532 float innerCoverage = GrNormalizeByteToFloat(scale);
533 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
534
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000535 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700536 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700537 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800538 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700539 } else {
egdaniele27065a2014-11-06 08:00:48 -0800540 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700541 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000542 }
543
544 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000545 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
546 kVertsPerAAFillRect,
547 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000548 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000549}
550
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000551namespace {
552
553// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000554struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000555 SkPoint fPos;
556 SkPoint fCenter;
557 SkPoint fDir;
558 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000559};
560
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000561// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000562extern const GrVertexAttrib gAARectVertexAttribs[] = {
563 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
joshualittb0a8a372014-09-23 09:50:21 -0700564 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
565 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000566};
567
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000568// Axis Aligned
569struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000570 SkPoint fPos;
571 SkPoint fOffset;
572 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000573};
574
575// Axis Aligned
576extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
577 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
joshualittb0a8a372014-09-23 09:50:21 -0700578 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000579};
580
robertphillips@google.com42903302013-04-20 12:26:07 +0000581};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000582
joshualittb44293e2014-10-28 08:12:18 -0700583void GrAARectRenderer::shaderFillAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000584 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000585 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000586 GrDrawState* drawState = target->drawState();
587
588 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
589 combinedMatrix.mapPoints(&center, 1);
590
591 // compute transformed (0, 1) vector
592 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
593 dir.normalize();
594
595 // compute transformed (width, 0) and (0, height) vectors
596 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000597 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
598 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000599 };
600
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000601 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
602 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700603 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs),
604 sizeof(RectVertex));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000605
606 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
607 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700608 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000609 return;
610 }
611
612 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
613
joshualittb0a8a372014-09-23 09:50:21 -0700614 GrGeometryProcessor* gp = GrRectEffect::Create();
615 drawState->setGeometryProcessor(gp)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000616
617 for (int i = 0; i < 4; ++i) {
618 verts[i].fCenter = center;
619 verts[i].fDir = dir;
620 verts[i].fWidthHeight.fX = newWidth;
621 verts[i].fWidthHeight.fY = newHeight;
622 }
623
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000624 SkRect devRect;
625 combinedMatrix.mapRect(&devRect, rect);
626
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000627 SkRect devBounds = {
628 devRect.fLeft - SK_ScalarHalf,
629 devRect.fTop - SK_ScalarHalf,
630 devRect.fRight + SK_ScalarHalf,
631 devRect.fBottom + SK_ScalarHalf
632 };
633
634 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
635 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
636 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
637 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
638
joshualittb44293e2014-10-28 08:12:18 -0700639 target->setIndexSourceToBuffer(fGpu->getContext()->getQuadIndexBuffer());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000640 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
641 target->resetIndexSource();
642}
643
joshualittb44293e2014-10-28 08:12:18 -0700644void GrAARectRenderer::shaderFillAlignedAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000645 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000646 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000647 GrDrawState* drawState = target->drawState();
648 SkASSERT(combinedMatrix.rectStaysRect());
649
egdaniel7b3d5ee2014-08-28 05:41:14 -0700650 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs),
651 sizeof(AARectVertex));
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000652
653 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
654 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700655 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000656 return;
657 }
658
659 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
660
joshualittb0a8a372014-09-23 09:50:21 -0700661 GrGeometryProcessor* gp = GrAlignedRectEffect::Create();
662 drawState->setGeometryProcessor(gp)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000663
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000664 SkRect devRect;
665 combinedMatrix.mapRect(&devRect, rect);
666
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000667 SkRect devBounds = {
668 devRect.fLeft - SK_ScalarHalf,
669 devRect.fTop - SK_ScalarHalf,
670 devRect.fRight + SK_ScalarHalf,
671 devRect.fBottom + SK_ScalarHalf
672 };
673
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000674 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000675 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
676 SkScalarHalf(devRect.height()) + SK_ScalarHalf
677 };
678
679 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
680 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
681 verts[0].fWidthHeight = widthHeight;
682
683 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
684 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
685 verts[1].fWidthHeight = widthHeight;
686
687 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
688 verts[2].fOffset = widthHeight;
689 verts[2].fWidthHeight = widthHeight;
690
691 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
692 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
693 verts[3].fWidthHeight = widthHeight;
694
joshualittb44293e2014-10-28 08:12:18 -0700695 target->setIndexSourceToBuffer(fGpu->getContext()->getQuadIndexBuffer());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000696 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
697 target->resetIndexSource();
698}
699
joshualittb44293e2014-10-28 08:12:18 -0700700void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000701 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000702 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000703 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700704 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000705 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700706 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000707 if (width > 0) {
708 devStrokeSize.set(width, width);
709 combinedMatrix.mapVectors(&devStrokeSize, 1);
710 devStrokeSize.setAbs(devStrokeSize);
711 } else {
712 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
713 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000714
robertphillips@google.com18136d12013-05-10 11:05:58 +0000715 const SkScalar dx = devStrokeSize.fX;
716 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000717 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
718 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000719
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000720 // Temporarily #if'ed out. We don't want to pass in the devRect but
721 // right now it is computed in GrContext::apply_aa_to_rect and we don't
722 // want to throw away the work
723#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000724 SkRect devRect;
725 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000726#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000727
bsalomon@google.com81712882012-11-01 17:12:34 +0000728 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000729 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000730 SkScalar w = devRect.width() - dx;
731 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000732 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000733 }
734
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000735 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000736 devOutside.outset(rx, ry);
737
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000738 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700739 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000740 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700741 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
742 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000743 miterStroke = false;
744 }
745
746 if (spare <= 0 && miterStroke) {
joshualittb44293e2014-10-28 08:12:18 -0700747 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000748 return;
749 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000750
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000751 SkRect devInside(devRect);
752 devInside.inset(rx, ry);
753
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000754 SkRect devOutsideAssist(devRect);
755
756 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
757 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000758 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000759 if (!miterStroke) {
760 devOutside.inset(0, ry);
761 devOutsideAssist.outset(0, ry);
762 }
763
joshualittb44293e2014-10-28 08:12:18 -0700764 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000765}
766
joshualittb44293e2014-10-28 08:12:18 -0700767void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000768 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000769 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000770 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000771 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000772 GrDrawState* drawState = target->drawState();
773
bsalomonc30aaa02014-08-13 07:15:29 -0700774 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700775
776 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700777 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700778 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
779 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000780
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000781 int innerVertexNum = 4;
782 int outerVertexNum = miterStroke ? 4 : 8;
783 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
784
785 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000786 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700787 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000788 return;
789 }
joshualittb44293e2014-10-28 08:12:18 -0700790 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000791 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700792 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000793 return;
794 }
795
796 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700797 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000798
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000799 // We create vertices for four nested rectangles. There are two ramps from 0 to full
800 // coverage, one on the exterior of the stroke and the other on the interior.
801 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000802 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700803 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
804 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
805 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000806
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000807#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000808 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700809 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000810 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
811 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
812 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000813 if (miterStroke) {
814 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
815 } else {
816 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
817 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000818 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000819#else
820 SkScalar inset = SK_ScalarHalf;
821#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000822
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000823 if (miterStroke) {
824 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700825 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000826 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700827 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
828 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000829 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700830 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000831 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700832 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
833 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000834 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700835 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
836 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000837 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700838 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
839 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000840 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700841 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000842 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700843 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000844 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000845
bsalomon9c0822a2014-08-11 11:07:48 -0700846 // 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 +0000847 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000848 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000849 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700850 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700851 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800852 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700853 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700854 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700855 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000856 }
857
bsalomon9c0822a2014-08-11 11:07:48 -0700858 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000859 int scale;
860 if (inset < SK_ScalarHalf) {
861 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
862 SkASSERT(scale >= 0 && scale <= 255);
863 } else {
864 scale = 0xff;
865 }
866
egdaniele27065a2014-11-06 08:00:48 -0800867 float innerCoverage = GrNormalizeByteToFloat(scale);
868 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700869
egdaniele27065a2014-11-06 08:00:48 -0800870 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000871 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700872 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700873 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800874 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700875 } else {
egdaniele27065a2014-11-06 08:00:48 -0800876 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700877 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000878 }
879
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000880 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700881 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000882 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700883 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700884 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
885 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700886 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700887 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700888 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000889 }
890
891 target->setIndexSourceToBuffer(indexBuffer);
joshualitt5ead6da2014-10-22 16:00:29 -0700892 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
joshualittb44293e2014-10-28 08:12:18 -0700893 totalVertexNum, aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700894 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000895}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000896
joshualittb44293e2014-10-28 08:12:18 -0700897void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000898 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700899 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000900 SkASSERT(combinedMatrix.rectStaysRect());
901 SkASSERT(!rects[1].isEmpty());
902
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000903 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000904 combinedMatrix.mapRect(&devOutside, rects[0]);
905 // can't call mapRect for devInside since it calls sort
906 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
907
908 if (devInside.isEmpty()) {
joshualittb44293e2014-10-28 08:12:18 -0700909 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000910 return;
911 }
912
joshualittb44293e2014-10-28 08:12:18 -0700913 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000914}