blob: 3f268809b9516cff183ad7049a13bfaa33eb5b0b [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"
9#include "GrRefCnt.h"
10#include "GrGpu.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000011#include "gl/GrGLEffect.h"
12#include "GrTBackendEffectFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000013#include "SkColorPriv.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000014
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000015SK_DEFINE_INST_COUNT(GrAARectRenderer)
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
21class GrAlignedRectEffect : public GrEffect {
22public:
23 static GrEffectRef* Create() {
24 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
38 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
39 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
40 }
41
42 class GLEffect : public GrGLEffect {
43 public:
44 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
45 : INHERITED (factory) {}
46
47 virtual void emitCode(GrGLShaderBuilder* builder,
48 const GrDrawEffect& drawEffect,
49 EffectKey key,
50 const char* outputColor,
51 const char* inputColor,
52 const TextureSamplerArray& samplers) SK_OVERRIDE {
53 // setup the varying for the Axis aligned rect effect
54 // xy -> interpolated offset
55 // zw -> w/2+0.5, h/2+0.5
56 const char *vsRectName, *fsRectName;
57 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
58 const SkString* attr0Name =
59 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
60 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
61
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000062 // TODO: compute all these offsets, spans, and scales in the VS
63 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
64 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
65 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
66 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
67 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
68 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
69 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
70 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
71 // value of coverage that is used. In other words it is the coverage that is
72 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000073 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
74 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000075
76 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000077 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000078 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
79 fsRectName);
80 // Compute the coverage for the rect's height and merge with the width
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000081 builder->fsCodeAppendf(
82 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
83 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000084
85 SkString modulate;
86 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
87 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
88 }
89
90 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
91 return 0;
92 }
93
94 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
95
96 private:
97 typedef GrGLEffect INHERITED;
98 };
99
100
101private:
102 GrAlignedRectEffect() : GrEffect() {
103 this->addVertexAttrib(kVec4f_GrSLType);
104 }
105
106 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
107
108 GR_DECLARE_EFFECT_TEST;
109
110 typedef GrEffect INHERITED;
111};
112
113
114GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
115
116GrEffectRef* GrAlignedRectEffect::TestCreate(SkMWCRandom* random,
117 GrContext* context,
118 const GrDrawTargetCaps&,
119 GrTexture* textures[]) {
120 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 */
138class GrRectEffect : public GrEffect {
139public:
140 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000141 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
142 gRectEffect->ref();
143 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000144 }
145
146 virtual ~GrRectEffect() {}
147
148 static const char* Name() { return "RectEdge"; }
149
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000150 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000151 uint32_t* validFlags) const SK_OVERRIDE {
152 *validFlags = 0;
153 }
154
155 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
156 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
157 }
158
159 class GLEffect : public GrGLEffect {
160 public:
161 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
162 : INHERITED (factory) {}
163
164 virtual void emitCode(GrGLShaderBuilder* builder,
165 const GrDrawEffect& drawEffect,
166 EffectKey key,
167 const char* outputColor,
168 const char* inputColor,
169 const TextureSamplerArray& samplers) SK_OVERRIDE {
170 // setup the varying for the center point and the unit vector
171 // that points down the height of the rect
172 const char *vsRectEdgeName, *fsRectEdgeName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000173 builder->addVarying(kVec4f_GrSLType, "RectEdge",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000174 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000175 const SkString* attr0Name =
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000176 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
177 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
178
179 // setup the varying for width/2+.5 and height/2+.5
180 const char *vsWidthHeightName, *fsWidthHeightName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000181 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000182 &vsWidthHeightName, &fsWidthHeightName);
183 const SkString* attr1Name =
184 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
185 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
186
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000187 // TODO: compute all these offsets, spans, and scales in the VS
188 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
189 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
190 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
191 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
192 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
193 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
194 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
195 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
196 // value of coverage that is used. In other words it is the coverage that is
197 // used in the interior of the rect after the ramp.
198 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
199 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000200
201 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000202 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000203 builder->fragmentPosition(), fsRectEdgeName);
204 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
205 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000206 builder->fsCodeAppendf(
207 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
208 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000209
210 // Compute the coverage for the rect's height and merge with the width
211 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
212 fsRectEdgeName);
213 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000214 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000215 fsWidthHeightName);
216
217 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000218 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000219 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
220 }
221
222 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
223 return 0;
224 }
225
226 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
227
228 private:
229 typedef GrGLEffect INHERITED;
230 };
231
232
233private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000234 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000235 this->addVertexAttrib(kVec4f_GrSLType);
236 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000237 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000238 }
239
240 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
241
242 GR_DECLARE_EFFECT_TEST;
243
244 typedef GrEffect INHERITED;
245};
246
247
248GR_DEFINE_EFFECT_TEST(GrRectEffect);
249
250GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
251 GrContext* context,
252 const GrDrawTargetCaps&,
253 GrTexture* textures[]) {
254 return GrRectEffect::Create();
255}
256
257///////////////////////////////////////////////////////////////////////////////
258
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000259namespace {
260
robertphillips@google.com42903302013-04-20 12:26:07 +0000261extern const GrVertexAttrib gAARectCoverageAttribs[] = {
262 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
263 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
264};
265
266extern const GrVertexAttrib gAARectColorAttribs[] = {
267 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
268 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
269};
270
271static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
272 if (useCoverage) {
273 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
274 } else {
275 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
276 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000277}
278
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000279static void set_inset_fan(GrPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000280 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000281 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
282 r.fRight - dx, r.fBottom - dy, stride);
283}
284
285};
286
287void GrAARectRenderer::reset() {
288 GrSafeSetNull(fAAFillRectIndexBuffer);
289 GrSafeSetNull(fAAStrokeRectIndexBuffer);
290}
291
robertphillips@google.com6d067302012-12-18 21:47:47 +0000292static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000293 0, 1, 5, 5, 4, 0,
294 1, 2, 6, 6, 5, 1,
295 2, 3, 7, 7, 6, 2,
296 3, 0, 4, 4, 7, 3,
297 4, 5, 6, 6, 7, 4,
298};
299
robertphillips@google.com6d067302012-12-18 21:47:47 +0000300static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
301static const int kVertsPerAAFillRect = 8;
302static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000303
304GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000305 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
306 sizeof(uint16_t) *
307 kNumAAFillRectsInIndexBuffer;
308
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000309 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000310 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000311 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000312 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
313 bool useTempData = (NULL == data);
314 if (useTempData) {
315 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
316 }
317 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
318 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
319 // the inner rect (for AA) and 2 for the inner rect.
320 int baseIdx = i * kIndicesPerAAFillRect;
321 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
322 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
323 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
324 }
325 }
326 if (useTempData) {
327 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
328 GrCrash("Can't get AA Fill Rect indices into buffer!");
329 }
330 SkDELETE_ARRAY(data);
331 } else {
332 fAAFillRectIndexBuffer->unlock();
333 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000334 }
335 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000336
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000337 return fAAFillRectIndexBuffer;
338}
339
robertphillips@google.com6d067302012-12-18 21:47:47 +0000340static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000341 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
342 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
343 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
344 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
345
346 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
347 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
348 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
349 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
350
351 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
352 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
353 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
354 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
355};
356
357int GrAARectRenderer::aaStrokeRectIndexCount() {
358 return GR_ARRAY_COUNT(gStrokeAARectIdx);
359}
360
361GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
362 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000363 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000364 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
365 if (NULL != fAAStrokeRectIndexBuffer) {
366#if GR_DEBUG
367 bool updated =
368#endif
369 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
370 sizeof(gStrokeAARectIdx));
371 GR_DEBUGASSERT(updated);
372 }
373 }
374 return fAAStrokeRectIndexBuffer;
375}
376
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000377void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
378 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000379 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000380 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000381 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000382 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000383 GrDrawState* drawState = target->drawState();
384
robertphillips@google.com42903302013-04-20 12:26:07 +0000385 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000386
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000387 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000388 if (!geo.succeeded()) {
389 GrPrintf("Failed to get space for vertices!\n");
390 return;
391 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000392
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000393 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
394 if (NULL == indexBuffer) {
395 GrPrintf("Failed to create index buffer!\n");
396 return;
397 }
398
399 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000400 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000401 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000402
403 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
404 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
405
robertphillips@google.com908aed82013-05-28 13:16:20 +0000406 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
407 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
408
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000409 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000410 // Temporarily #if'ed out. We don't want to pass in the devRect but
411 // right now it is computed in GrContext::apply_aa_to_rect and we don't
412 // want to throw away the work
413#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000414 SkRect devRect;
415 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000416#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000417
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000418 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000419 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000420 } else {
421 // compute transformed (1, 0) and (0, 1) vectors
422 SkVector vec[2] = {
423 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
424 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
425 };
426
427 vec[0].normalize();
428 vec[0].scale(SK_ScalarHalf);
429 vec[1].normalize();
430 vec[1].scale(SK_ScalarHalf);
431
robertphillips@google.com91b71162013-05-10 14:09:54 +0000432 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000433 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
434 rect.fRight, rect.fBottom, vsize);
435 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
436
robertphillips@google.com91b71162013-05-10 14:09:54 +0000437 // Now create the inset points and then outset the original
438 // rotated points
439
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000440 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000441 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000442 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
443 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
444 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000445 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000446 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
447 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
448 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000449 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000450 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
451 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
452 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000453 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000454 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
455 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
456 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000457
458 verts += sizeof(GrPoint);
459 for (int i = 0; i < 4; ++i) {
460 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
461 }
462
robertphillips@google.com908aed82013-05-28 13:16:20 +0000463 int scale;
464 if (inset < SK_ScalarHalf) {
465 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
466 SkASSERT(scale >= 0 && scale <= 255);
467 } else {
468 scale = 0xff;
469 }
470
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000471 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000472 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000473 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000474 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000475 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000476 innerColor = target->getDrawState().getColor();
477 } else {
478 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
479 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000480 }
481
482 verts += 4 * vsize;
483 for (int i = 0; i < 4; ++i) {
484 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
485 }
486
487 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000488 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
489 kVertsPerAAFillRect,
490 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000491 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000492}
493
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000494namespace {
495
496// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000497struct RectVertex {
498 GrPoint fPos;
499 GrPoint fCenter;
500 GrPoint fDir;
501 GrPoint fWidthHeight;
502};
503
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000504// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000505extern const GrVertexAttrib gAARectVertexAttribs[] = {
506 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
507 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
508 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
509};
510
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000511// Axis Aligned
512struct AARectVertex {
513 GrPoint fPos;
514 GrPoint fOffset;
515 GrPoint fWidthHeight;
516};
517
518// Axis Aligned
519extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
520 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
521 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
522};
523
robertphillips@google.com42903302013-04-20 12:26:07 +0000524};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000525
526void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
527 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000528 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000529 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000530 GrDrawState* drawState = target->drawState();
531
532 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
533 combinedMatrix.mapPoints(&center, 1);
534
535 // compute transformed (0, 1) vector
536 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
537 dir.normalize();
538
539 // compute transformed (width, 0) and (0, height) vectors
540 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000541 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
542 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000543 };
544
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000545 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
546 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000547 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000548 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000549
550 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
551 if (!geo.succeeded()) {
552 GrPrintf("Failed to get space for vertices!\n");
553 return;
554 }
555
556 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
557
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000558 GrEffectRef* effect = GrRectEffect::Create();
559 static const int kRectAttrIndex = 1;
560 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000561 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000562
563 for (int i = 0; i < 4; ++i) {
564 verts[i].fCenter = center;
565 verts[i].fDir = dir;
566 verts[i].fWidthHeight.fX = newWidth;
567 verts[i].fWidthHeight.fY = newHeight;
568 }
569
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000570 SkRect devRect;
571 combinedMatrix.mapRect(&devRect, rect);
572
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000573 SkRect devBounds = {
574 devRect.fLeft - SK_ScalarHalf,
575 devRect.fTop - SK_ScalarHalf,
576 devRect.fRight + SK_ScalarHalf,
577 devRect.fBottom + SK_ScalarHalf
578 };
579
580 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
581 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
582 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
583 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
584
585 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
586 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
587 target->resetIndexSource();
588}
589
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000590void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
591 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000592 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000593 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000594 GrDrawState* drawState = target->drawState();
595 SkASSERT(combinedMatrix.rectStaysRect());
596
597 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000598 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000599
600 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
601 if (!geo.succeeded()) {
602 GrPrintf("Failed to get space for vertices!\n");
603 return;
604 }
605
606 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
607
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000608 GrEffectRef* effect = GrAlignedRectEffect::Create();
609 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000610 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000611
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000612 SkRect devRect;
613 combinedMatrix.mapRect(&devRect, rect);
614
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000615 SkRect devBounds = {
616 devRect.fLeft - SK_ScalarHalf,
617 devRect.fTop - SK_ScalarHalf,
618 devRect.fRight + SK_ScalarHalf,
619 devRect.fBottom + SK_ScalarHalf
620 };
621
622 GrPoint widthHeight = {
623 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
624 SkScalarHalf(devRect.height()) + SK_ScalarHalf
625 };
626
627 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
628 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
629 verts[0].fWidthHeight = widthHeight;
630
631 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
632 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
633 verts[1].fWidthHeight = widthHeight;
634
635 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
636 verts[2].fOffset = widthHeight;
637 verts[2].fWidthHeight = widthHeight;
638
639 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
640 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
641 verts[3].fWidthHeight = widthHeight;
642
643 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
644 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
645 target->resetIndexSource();
646}
647
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000648void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000649 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000650 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000651 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000652 const SkRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000653 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000654 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000655 GrVec devStrokeSize;
656 if (width > 0) {
657 devStrokeSize.set(width, width);
658 combinedMatrix.mapVectors(&devStrokeSize, 1);
659 devStrokeSize.setAbs(devStrokeSize);
660 } else {
661 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
662 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000663
robertphillips@google.com18136d12013-05-10 11:05:58 +0000664 const SkScalar dx = devStrokeSize.fX;
665 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000666 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
667 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000668
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000669 // Temporarily #if'ed out. We don't want to pass in the devRect but
670 // right now it is computed in GrContext::apply_aa_to_rect and we don't
671 // want to throw away the work
672#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000673 SkRect devRect;
674 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000675#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000676
bsalomon@google.com81712882012-11-01 17:12:34 +0000677 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000678 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000679 SkScalar w = devRect.width() - dx;
680 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000681 spare = GrMin(w, h);
682 }
683
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000684 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000685 devOutside.outset(rx, ry);
686
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000687 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000688 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000689 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000690 return;
691 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000692
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000693 SkRect devInside(devRect);
694 devInside.inset(rx, ry);
695
696 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
697}
698
699void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
700 GrDrawTarget* target,
701 const SkRect& devOutside,
702 const SkRect& devInside,
703 bool useVertexCoverage) {
704 GrDrawState* drawState = target->drawState();
705
robertphillips@google.com42903302013-04-20 12:26:07 +0000706 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000707
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000708 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000709 if (!geo.succeeded()) {
710 GrPrintf("Failed to get space for vertices!\n");
711 return;
712 }
713 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
714 if (NULL == indexBuffer) {
715 GrPrintf("Failed to create index buffer!\n");
716 return;
717 }
718
719 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000720 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000721 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000722
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000723 // We create vertices for four nested rectangles. There are two ramps from 0 to full
724 // coverage, one on the exterior of the stroke and the other on the interior.
725 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000726 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
727 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
728 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
729 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
730
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000731#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000732 // TODO: this only really works if the X & Y margins are the same all around
733 // the rect
734 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
735 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
736 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
737 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
738 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000739#else
740 SkScalar inset = SK_ScalarHalf;
741#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000742
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000743 // outermost
744 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com353f0972013-06-28 17:57:06 +0000745 // inner two
746 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
747 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000748 // innermost
749 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000750
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000751 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000752 verts += sizeof(GrPoint);
753 for (int i = 0; i < 4; ++i) {
754 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
755 }
756
robertphillips@google.com353f0972013-06-28 17:57:06 +0000757 int scale;
758 if (inset < SK_ScalarHalf) {
759 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
760 SkASSERT(scale >= 0 && scale <= 255);
761 } else {
762 scale = 0xff;
763 }
764
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000765 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000766 GrColor innerColor;
767 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000768 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000769 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000770 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000771 innerColor = target->getDrawState().getColor();
772 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000773 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
774 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000775 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000776
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000777 verts += 4 * vsize;
778 for (int i = 0; i < 8; ++i) {
779 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
780 }
781
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000782 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000783 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000784 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000785 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
786 }
787
788 target->setIndexSourceToBuffer(indexBuffer);
789 target->drawIndexed(kTriangles_GrPrimitiveType,
790 0, 0, 16, aaStrokeRectIndexCount());
791}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000792
793void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
794 GrDrawTarget* target,
795 const SkRect rects[2],
796 const SkMatrix& combinedMatrix,
797 bool useVertexCoverage) {
798 SkASSERT(combinedMatrix.rectStaysRect());
799 SkASSERT(!rects[1].isEmpty());
800
801 SkRect devOutside, devInside;
802 combinedMatrix.mapRect(&devOutside, rects[0]);
803 // can't call mapRect for devInside since it calls sort
804 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
805
806 if (devInside.isEmpty()) {
807 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
808 return;
809 }
810
811 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
812}