1/*
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 "GrGpu.h"
10#include "gl/GrGLEffect.h"
11#include "gl/GrGLVertexEffect.h"
12#include "GrTBackendEffectFactory.h"
13#include "SkColorPriv.h"
14#include "effects/GrVertexEffect.h"
15
16///////////////////////////////////////////////////////////////////////////////
17class GrGLAlignedRectEffect;
18
19// Axis Aligned special case
20class GrAlignedRectEffect : public GrVertexEffect {
21public:
22    static GrEffectRef* Create() {
23        GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
24        gAlignedRectEffect->ref();
25        return gAlignedRectEffect;
26    }
27
28    virtual ~GrAlignedRectEffect() {}
29
30    static const char* Name() { return "AlignedRectEdge"; }
31
32    virtual void getConstantColorComponents(GrColor* color,
33                                            uint32_t* validFlags) const SK_OVERRIDE {
34        *validFlags = 0;
35    }
36
37    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
38        return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
39    }
40
41    class GLEffect : public GrGLVertexEffect {
42    public:
43        GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
44        : INHERITED (factory) {}
45
46        virtual void emitCode(GrGLFullShaderBuilder* builder,
47                              const GrDrawEffect& drawEffect,
48                              EffectKey key,
49                              const char* outputColor,
50                              const char* inputColor,
51                              const TransformedCoordsArray&,
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
62            // 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.
73            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");
75
76            // Compute the coverage for the rect's width
77            builder->fsCodeAppendf(
78                "\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
81            builder->fsCodeAppendf(
82                "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
83                fsRectName, fsRectName);
84
85
86            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
87                                   (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).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 GrGLVertexEffect INHERITED;
98    };
99
100
101private:
102    GrAlignedRectEffect() : GrVertexEffect() {
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 GrVertexEffect INHERITED;
111};
112
113
114GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
115
116GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random,
117                                             GrContext* context,
118                                             const GrDrawTargetCaps&,
119                                             GrTexture* textures[]) {
120    return GrAlignedRectEffect::Create();
121}
122
123///////////////////////////////////////////////////////////////////////////////
124class GrGLRectEffect;
125
126/**
127 * The output of this effect is a modulation of the input color and coverage
128 * 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 GrVertexEffect {
139public:
140    static GrEffectRef* Create() {
141        GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
142        gRectEffect->ref();
143        return gRectEffect;
144    }
145
146    virtual ~GrRectEffect() {}
147
148    static const char* Name() { return "RectEdge"; }
149
150    virtual void getConstantColorComponents(GrColor* color,
151                                            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 GrGLVertexEffect {
160    public:
161        GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
162        : INHERITED (factory) {}
163
164        virtual void emitCode(GrGLFullShaderBuilder* builder,
165                              const GrDrawEffect& drawEffect,
166                              EffectKey key,
167                              const char* outputColor,
168                              const char* inputColor,
169                              const TransformedCoordsArray&,
170                              const TextureSamplerArray& samplers) SK_OVERRIDE {
171            // setup the varying for the center point and the unit vector
172            // that points down the height of the rect
173            const char *vsRectEdgeName, *fsRectEdgeName;
174            builder->addVarying(kVec4f_GrSLType, "RectEdge",
175                                &vsRectEdgeName, &fsRectEdgeName);
176            const SkString* attr0Name =
177                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
178            builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
179
180            // setup the varying for width/2+.5 and height/2+.5
181            const char *vsWidthHeightName, *fsWidthHeightName;
182            builder->addVarying(kVec2f_GrSLType, "WidthHeight",
183                                &vsWidthHeightName, &fsWidthHeightName);
184            const SkString* attr1Name =
185                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
186            builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
187
188            // TODO: compute all these offsets, spans, and scales in the VS
189            builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
190            builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
191            builder->fsCodeAppend("\tfloat outset = 0.5;\n");
192            // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
193            // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
194            builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
195            builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
196            // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
197            // value of coverage that is used. In other words it is the coverage that is
198            // used in the interior of the rect after the ramp.
199            builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
200            builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
201
202            // Compute the coverage for the rect's width
203            builder->fsCodeAppendf("\tvec2 offset = %s - %s.xy;\n",
204                                   builder->fragmentPosition(), fsRectEdgeName);
205            builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
206                                   fsRectEdgeName, fsRectEdgeName);
207            builder->fsCodeAppendf(
208                "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
209                fsWidthHeightName);
210
211            // Compute the coverage for the rect's height and merge with the width
212            builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
213                                   fsRectEdgeName);
214            builder->fsCodeAppendf(
215                    "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
216                    fsWidthHeightName);
217
218
219            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
220                                   (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
221        }
222
223        static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
224            return 0;
225        }
226
227        virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
228
229    private:
230        typedef GrGLVertexEffect INHERITED;
231    };
232
233
234private:
235    GrRectEffect() : GrVertexEffect() {
236        this->addVertexAttrib(kVec4f_GrSLType);
237        this->addVertexAttrib(kVec2f_GrSLType);
238        this->setWillReadFragmentPosition();
239    }
240
241    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
242
243    GR_DECLARE_EFFECT_TEST;
244
245    typedef GrVertexEffect INHERITED;
246};
247
248
249GR_DEFINE_EFFECT_TEST(GrRectEffect);
250
251GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
252                                      GrContext* context,
253                                      const GrDrawTargetCaps&,
254                                      GrTexture* textures[]) {
255    return GrRectEffect::Create();
256}
257
258///////////////////////////////////////////////////////////////////////////////
259
260namespace {
261
262extern const GrVertexAttrib gAARectCoverageAttribs[] = {
263    {kVec2f_GrVertexAttribType,  0,               kPosition_GrVertexAttribBinding},
264    {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kCoverage_GrVertexAttribBinding},
265};
266
267extern const GrVertexAttrib gAARectColorAttribs[] = {
268    {kVec2f_GrVertexAttribType,  0,               kPosition_GrVertexAttribBinding},
269    {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
270};
271
272static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
273    if (useCoverage) {
274        drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
275    } else {
276        drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
277    }
278}
279
280static void set_inset_fan(SkPoint* pts, size_t stride,
281                          const SkRect& r, SkScalar dx, SkScalar dy) {
282    pts->setRectFan(r.fLeft + dx, r.fTop + dy,
283                    r.fRight - dx, r.fBottom - dy, stride);
284}
285
286};
287
288void GrAARectRenderer::reset() {
289    SkSafeSetNull(fAAFillRectIndexBuffer);
290    SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
291    SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
292}
293
294static const uint16_t gFillAARectIdx[] = {
295    0, 1, 5, 5, 4, 0,
296    1, 2, 6, 6, 5, 1,
297    2, 3, 7, 7, 6, 2,
298    3, 0, 4, 4, 7, 3,
299    4, 5, 6, 6, 7, 4,
300};
301
302static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
303static const int kVertsPerAAFillRect = 8;
304static const int kNumAAFillRectsInIndexBuffer = 256;
305
306GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
307    static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
308                                                     sizeof(uint16_t) *
309                                                     kNumAAFillRectsInIndexBuffer;
310
311    if (NULL == fAAFillRectIndexBuffer) {
312        fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
313        if (NULL != fAAFillRectIndexBuffer) {
314            uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map();
315            bool useTempData = (NULL == data);
316            if (useTempData) {
317                data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
318            }
319            for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
320                // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
321                // the inner rect (for AA) and 2 for the inner rect.
322                int baseIdx = i * kIndicesPerAAFillRect;
323                uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
324                for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
325                    data[baseIdx+j] = baseVert + gFillAARectIdx[j];
326                }
327            }
328            if (useTempData) {
329                if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
330                    SkFAIL("Can't get AA Fill Rect indices into buffer!");
331                }
332                SkDELETE_ARRAY(data);
333            } else {
334                fAAFillRectIndexBuffer->unmap();
335            }
336        }
337    }
338
339    return fAAFillRectIndexBuffer;
340}
341
342static const uint16_t gMiterStrokeAARectIdx[] = {
343    0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
344    1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
345    2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
346    3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
347
348    0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
349    1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
350    2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
351    3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
352
353    0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
354    1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
355    2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
356    3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
357};
358
359/**
360 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
361 * from the first index. The index layout:
362 * outer AA line: 0~3, 4~7
363 * outer edge:    8~11, 12~15
364 * inner edge:    16~19
365 * inner AA line: 20~23
366 * Following comes a bevel-stroke rect and its indices:
367 *
368 *           4                                 7
369 *            *********************************
370 *          *   ______________________________  *
371 *         *  / 12                          15 \  *
372 *        *  /                                  \  *
373 *     0 *  |8     16_____________________19  11 |  * 3
374 *       *  |       |                    |       |  *
375 *       *  |       |  ****************  |       |  *
376 *       *  |       |  * 20        23 *  |       |  *
377 *       *  |       |  *              *  |       |  *
378 *       *  |       |  * 21        22 *  |       |  *
379 *       *  |       |  ****************  |       |  *
380 *       *  |       |____________________|       |  *
381 *     1 *  |9    17                      18   10|  * 2
382 *        *  \                                  /  *
383 *         *  \13 __________________________14/  *
384 *          *                                   *
385 *           **********************************
386 *          5                                  6
387 */
388static const uint16_t gBevelStrokeAARectIdx[] = {
389    // Draw outer AA, from outer AA line to outer edge, shift is 0.
390    0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
391    1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
392    5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
393    6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
394    2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
395    3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
396    7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
397    4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
398
399    // Draw the stroke, from outer edge to inner edge, shift is 8.
400    0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
401    1 + 8, 5 + 8, 9 + 8,
402    5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
403    6 + 8, 2 + 8, 10 + 8,
404    2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
405    3 + 8, 7 + 8, 11 + 8,
406    7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
407    4 + 8, 0 + 8, 8 + 8,
408
409    // Draw the inner AA, from inner edge to inner AA line, shift is 16.
410    0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
411    1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
412    2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
413    3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
414};
415
416int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
417    return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
418                         SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
419}
420
421GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
422    if (miterStroke) {
423        if (NULL == fAAMiterStrokeRectIndexBuffer) {
424            fAAMiterStrokeRectIndexBuffer =
425                gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
426            if (NULL != fAAMiterStrokeRectIndexBuffer) {
427#ifdef SK_DEBUG
428                bool updated =
429#endif
430                fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
431                                                          sizeof(gMiterStrokeAARectIdx));
432                GR_DEBUGASSERT(updated);
433            }
434        }
435        return fAAMiterStrokeRectIndexBuffer;
436    } else {
437        if (NULL == fAABevelStrokeRectIndexBuffer) {
438            fAABevelStrokeRectIndexBuffer =
439                gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
440            if (NULL != fAABevelStrokeRectIndexBuffer) {
441#ifdef SK_DEBUG
442                bool updated =
443#endif
444                fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
445                                                          sizeof(gBevelStrokeAARectIdx));
446                GR_DEBUGASSERT(updated);
447            }
448        }
449        return fAABevelStrokeRectIndexBuffer;
450    }
451}
452
453void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
454                                          GrDrawTarget* target,
455                                          const SkRect& rect,
456                                          const SkMatrix& combinedMatrix,
457                                          const SkRect& devRect,
458                                          bool useVertexCoverage) {
459    GrDrawState* drawState = target->drawState();
460
461    set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
462
463    GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
464    if (!geo.succeeded()) {
465        GrPrintf("Failed to get space for vertices!\n");
466        return;
467    }
468
469    GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
470    if (NULL == indexBuffer) {
471        GrPrintf("Failed to create index buffer!\n");
472        return;
473    }
474
475    intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
476    size_t vsize = drawState->getVertexSize();
477    SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize);
478
479    SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
480    SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
481
482    SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
483    inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
484
485    if (combinedMatrix.rectStaysRect()) {
486        // Temporarily #if'ed out. We don't want to pass in the devRect but
487        // right now it is computed in GrContext::apply_aa_to_rect and we don't
488        // want to throw away the work
489#if 0
490        SkRect devRect;
491        combinedMatrix.mapRect(&devRect, rect);
492#endif
493
494        set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
495        set_inset_fan(fan1Pos, vsize, devRect, inset,  inset);
496    } else {
497        // compute transformed (1, 0) and (0, 1) vectors
498        SkVector vec[2] = {
499          { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
500          { combinedMatrix[SkMatrix::kMSkewX],  combinedMatrix[SkMatrix::kMScaleY] }
501        };
502
503        vec[0].normalize();
504        vec[0].scale(SK_ScalarHalf);
505        vec[1].normalize();
506        vec[1].scale(SK_ScalarHalf);
507
508        // create the rotated rect
509        fan0Pos->setRectFan(rect.fLeft, rect.fTop,
510                            rect.fRight, rect.fBottom, vsize);
511        combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
512
513        // Now create the inset points and then outset the original
514        // rotated points
515
516        // TL
517        *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
518            *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
519        *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
520        // BL
521        *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
522            *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
523        *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
524        // BR
525        *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
526            *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
527        *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
528        // TR
529        *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
530            *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
531        *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
532    }
533
534    verts += sizeof(SkPoint);
535    for (int i = 0; i < 4; ++i) {
536        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
537    }
538
539    int scale;
540    if (inset < SK_ScalarHalf) {
541        scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
542        SkASSERT(scale >= 0 && scale <= 255);
543    } else {
544        scale = 0xff;
545    }
546
547    GrColor innerColor;
548    if (useVertexCoverage) {
549        innerColor = GrColorPackRGBA(scale, scale, scale, scale);
550    } else {
551        if (0xff == scale) {
552            innerColor = target->getDrawState().getColor();
553        } else {
554            innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
555        }
556    }
557
558    verts += 4 * vsize;
559    for (int i = 0; i < 4; ++i) {
560        *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
561    }
562
563    target->setIndexSourceToBuffer(indexBuffer);
564    target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
565                                 kVertsPerAAFillRect,
566                                 kIndicesPerAAFillRect);
567    target->resetIndexSource();
568}
569
570namespace {
571
572// Rotated
573struct RectVertex {
574    SkPoint fPos;
575    SkPoint fCenter;
576    SkPoint fDir;
577    SkPoint fWidthHeight;
578};
579
580// Rotated
581extern const GrVertexAttrib gAARectVertexAttribs[] = {
582    { kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding },
583    { kVec4f_GrVertexAttribType, sizeof(SkPoint),   kEffect_GrVertexAttribBinding },
584    { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding }
585};
586
587// Axis Aligned
588struct AARectVertex {
589    SkPoint fPos;
590    SkPoint fOffset;
591    SkPoint fWidthHeight;
592};
593
594// Axis Aligned
595extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
596    { kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding },
597    { kVec4f_GrVertexAttribType, sizeof(SkPoint),   kEffect_GrVertexAttribBinding },
598};
599
600};
601
602void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
603                                        GrDrawTarget* target,
604                                        const SkRect& rect,
605                                        const SkMatrix& combinedMatrix) {
606    GrDrawState* drawState = target->drawState();
607
608    SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
609    combinedMatrix.mapPoints(&center, 1);
610
611    // compute transformed (0, 1) vector
612    SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
613    dir.normalize();
614
615    // compute transformed (width, 0) and (0, height) vectors
616    SkVector vec[2] = {
617      { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
618      { combinedMatrix[SkMatrix::kMSkewX],  combinedMatrix[SkMatrix::kMScaleY] }
619    };
620
621    SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
622    SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
623    drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
624    SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
625
626    GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
627    if (!geo.succeeded()) {
628        GrPrintf("Failed to get space for vertices!\n");
629        return;
630    }
631
632    RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
633
634    GrEffectRef* effect = GrRectEffect::Create();
635    static const int kRectAttrIndex = 1;
636    static const int kWidthIndex = 2;
637    drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
638
639    for (int i = 0; i < 4; ++i) {
640        verts[i].fCenter = center;
641        verts[i].fDir = dir;
642        verts[i].fWidthHeight.fX = newWidth;
643        verts[i].fWidthHeight.fY = newHeight;
644    }
645
646    SkRect devRect;
647    combinedMatrix.mapRect(&devRect, rect);
648
649    SkRect devBounds = {
650        devRect.fLeft   - SK_ScalarHalf,
651        devRect.fTop    - SK_ScalarHalf,
652        devRect.fRight  + SK_ScalarHalf,
653        devRect.fBottom + SK_ScalarHalf
654    };
655
656    verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
657    verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
658    verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
659    verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
660
661    target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
662    target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
663    target->resetIndexSource();
664}
665
666void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
667                                               GrDrawTarget* target,
668                                               const SkRect& rect,
669                                               const SkMatrix& combinedMatrix) {
670    GrDrawState* drawState = target->drawState();
671    SkASSERT(combinedMatrix.rectStaysRect());
672
673    drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
674    SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
675
676    GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
677    if (!geo.succeeded()) {
678        GrPrintf("Failed to get space for vertices!\n");
679        return;
680    }
681
682    AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
683
684    GrEffectRef* effect = GrAlignedRectEffect::Create();
685    static const int kOffsetIndex = 1;
686    drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
687
688    SkRect devRect;
689    combinedMatrix.mapRect(&devRect, rect);
690
691    SkRect devBounds = {
692        devRect.fLeft   - SK_ScalarHalf,
693        devRect.fTop    - SK_ScalarHalf,
694        devRect.fRight  + SK_ScalarHalf,
695        devRect.fBottom + SK_ScalarHalf
696    };
697
698    SkPoint widthHeight = {
699        SkScalarHalf(devRect.width()) + SK_ScalarHalf,
700        SkScalarHalf(devRect.height()) + SK_ScalarHalf
701    };
702
703    verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
704    verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
705    verts[0].fWidthHeight = widthHeight;
706
707    verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
708    verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
709    verts[1].fWidthHeight = widthHeight;
710
711    verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
712    verts[2].fOffset = widthHeight;
713    verts[2].fWidthHeight = widthHeight;
714
715    verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
716    verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
717    verts[3].fWidthHeight = widthHeight;
718
719    target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
720    target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
721    target->resetIndexSource();
722}
723
724void GrAARectRenderer::strokeAARect(GrGpu* gpu,
725                                    GrDrawTarget* target,
726                                    const SkRect& rect,
727                                    const SkMatrix& combinedMatrix,
728                                    const SkRect& devRect,
729                                    const SkStrokeRec& stroke,
730                                    bool useVertexCoverage) {
731    SkVector devStrokeSize;
732    SkScalar width = stroke.getWidth();
733    if (width > 0) {
734        devStrokeSize.set(width, width);
735        combinedMatrix.mapVectors(&devStrokeSize, 1);
736        devStrokeSize.setAbs(devStrokeSize);
737    } else {
738        devStrokeSize.set(SK_Scalar1, SK_Scalar1);
739    }
740
741    const SkScalar dx = devStrokeSize.fX;
742    const SkScalar dy = devStrokeSize.fY;
743    const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
744    const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
745
746    // Temporarily #if'ed out. We don't want to pass in the devRect but
747    // right now it is computed in GrContext::apply_aa_to_rect and we don't
748    // want to throw away the work
749#if 0
750    SkRect devRect;
751    combinedMatrix.mapRect(&devRect, rect);
752#endif
753
754    SkScalar spare;
755    {
756        SkScalar w = devRect.width() - dx;
757        SkScalar h = devRect.height() - dy;
758        spare = SkTMin(w, h);
759    }
760
761    SkRect devOutside(devRect);
762    devOutside.outset(rx, ry);
763
764    bool miterStroke = true;
765    // small miter limit means right angles show bevel...
766    if (stroke.getJoin() != SkPaint::kMiter_Join || stroke.getMiter() < SK_ScalarSqrt2) {
767        miterStroke = false;
768    }
769
770    if (spare <= 0 && miterStroke) {
771        this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
772                         devOutside, useVertexCoverage);
773        return;
774    }
775
776    SkRect devInside(devRect);
777    devInside.inset(rx, ry);
778
779    SkRect devOutsideAssist(devRect);
780
781    // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
782    // to draw the outer of the rect. Because there are 8 vertices on the outer
783    // edge, while vertex number of inner edge is 4, the same as miter-stroke.
784    if (!miterStroke) {
785        devOutside.inset(0, ry);
786        devOutsideAssist.outset(0, ry);
787    }
788
789    this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
790                               devInside, useVertexCoverage, miterStroke);
791}
792
793void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
794                                            GrDrawTarget* target,
795                                            const SkRect& devOutside,
796                                            const SkRect& devOutsideAssist,
797                                            const SkRect& devInside,
798                                            bool useVertexCoverage,
799                                            bool miterStroke) {
800    GrDrawState* drawState = target->drawState();
801
802    set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
803
804    int innerVertexNum = 4;
805    int outerVertexNum = miterStroke ? 4 : 8;
806    int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
807
808    GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
809    if (!geo.succeeded()) {
810        GrPrintf("Failed to get space for vertices!\n");
811        return;
812    }
813    GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
814    if (NULL == indexBuffer) {
815        GrPrintf("Failed to create index buffer!\n");
816        return;
817    }
818
819    intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
820    size_t vsize = drawState->getVertexSize();
821    SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize);
822
823    // We create vertices for four nested rectangles. There are two ramps from 0 to full
824    // coverage, one on the exterior of the stroke and the other on the interior.
825    // The following pointers refer to the four rects, from outermost to innermost.
826    SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
827    SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vsize);
828    SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vsize);
829    SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
830
831#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
832    // TODO: this only really works if the X & Y margins are the same all around
833    // the rect
834    SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
835    inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
836    inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
837    if (miterStroke) {
838        inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
839    } else {
840        inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
841    }
842    SkASSERT(inset >= 0);
843#else
844    SkScalar inset = SK_ScalarHalf;
845#endif
846
847    if (miterStroke) {
848        // outermost
849        set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
850        // inner two
851        set_inset_fan(fan1Pos, vsize, devOutside,  inset,  inset);
852        set_inset_fan(fan2Pos, vsize, devInside,  -inset, -inset);
853        // innermost
854        set_inset_fan(fan3Pos, vsize, devInside,   SK_ScalarHalf,  SK_ScalarHalf);
855    } else {
856        SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
857        SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vsize);
858        // outermost
859        set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
860        set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
861        // outer one of the inner two
862        set_inset_fan(fan1Pos, vsize, devOutside,  inset,  inset);
863        set_inset_fan(fan1AssistPos, vsize, devOutsideAssist,  inset,  inset);
864        // inner one of the inner two
865        set_inset_fan(fan2Pos, vsize, devInside,  -inset, -inset);
866        // innermost
867        set_inset_fan(fan3Pos, vsize, devInside,   SK_ScalarHalf,  SK_ScalarHalf);
868    }
869
870    // The outermost rect has 0 coverage
871    verts += sizeof(SkPoint);
872    for (int i = 0; i < outerVertexNum; ++i) {
873        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
874    }
875
876    int scale;
877    if (inset < SK_ScalarHalf) {
878        scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
879        SkASSERT(scale >= 0 && scale <= 255);
880    } else {
881        scale = 0xff;
882    }
883
884    // The inner two rects have full coverage
885    GrColor innerColor;
886    if (useVertexCoverage) {
887        innerColor = GrColorPackRGBA(scale, scale, scale, scale);
888    } else {
889        if (0xff == scale) {
890            innerColor = target->getDrawState().getColor();
891        } else {
892            innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
893        }
894    }
895
896    verts += outerVertexNum * vsize;
897    for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
898        *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
899    }
900
901    // The innermost rect has 0 coverage
902    verts += (outerVertexNum + innerVertexNum) * vsize;
903    for (int i = 0; i < innerVertexNum; ++i) {
904        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
905    }
906
907    target->setIndexSourceToBuffer(indexBuffer);
908    target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
909                        totalVertexNum, aaStrokeRectIndexCount(miterStroke));
910}
911
912void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
913                                         GrDrawTarget* target,
914                                         const SkRect rects[2],
915                                         const SkMatrix& combinedMatrix,
916                                         bool useVertexCoverage) {
917    SkASSERT(combinedMatrix.rectStaysRect());
918    SkASSERT(!rects[1].isEmpty());
919
920    SkRect devOutside, devOutsideAssist, devInside;
921    combinedMatrix.mapRect(&devOutside, rects[0]);
922    // can't call mapRect for devInside since it calls sort
923    combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
924
925    if (devInside.isEmpty()) {
926        this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
927        return;
928    }
929
930    this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
931                               devInside, useVertexCoverage, true);
932}
933