GrAAHairLinePathRenderer.cpp revision 3b0d631cdfe2dcf59e7b7ea60d92566eade7bfc0
1f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com
2f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com/*
3f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Copyright 2011 Google Inc.
4f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com *
5f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be
6f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * found in the LICENSE file.
7f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com */
8f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com
9aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrAAHairLinePathRenderer.h"
10aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
11aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrContext.h"
129381363050ec9d3e724076a8e9152bfa9a8de1d1tomhudson@google.com#include "GrDrawState.h"
13aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrGpu.h"
14aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrIndexBuffer.h"
15dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com#include "GrPathUtils.h"
16aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkGeometry.h"
1712b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com#include "SkStroke.h"
18aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkTemplates.h"
19aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
20aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comnamespace {
21aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// quadratics are rendered as 5-sided polys in order to bound the
22aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// AA stroke around the center-curve. See comments in push_quad_index_buffer and
23aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// bloat_quad.
24aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kVertsPerQuad = 5;
25aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kIdxsPerQuad = 9;
26aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
27aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kVertsPerLineSeg = 4;
28aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kIdxsPerLineSeg = 6;
29aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
30aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kNumQuadsInIdxBuffer = 256;
31aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const size_t kQuadIdxSBufize = kIdxsPerQuad *
32aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                      sizeof(uint16_t) *
33aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                      kNumQuadsInIdxBuffer;
34aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
35aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.combool push_quad_index_data(GrIndexBuffer* qIdxBuffer) {
36aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    uint16_t* data = (uint16_t*) qIdxBuffer->lock();
37aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    bool tempData = NULL == data;
38aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (tempData) {
39c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com        data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad);
40aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
41aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) {
42aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
43aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // Each quadratic is rendered as a five sided polygon. This poly bounds
44aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // the quadratic's bounding triangle but has been expanded so that the
45aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // 1-pixel wide area around the curve is inside the poly.
46aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // If a,b,c are the original control points then the poly a0,b0,c0,c1,a1
47aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // that is rendered would look like this:
48aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        //              b0
49aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        //              b
50aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        //
51aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        //     a0              c0
52aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        //      a            c
53aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        //       a1       c1
540e5104c1570de4709e04720e62d80a0ca8970260bsalomon@google.com        // Each is drawn as three triangles specified by these 9 indices:
55aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        int baseIdx = i * kIdxsPerQuad;
56aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        uint16_t baseVert = (uint16_t)(i * kVertsPerQuad);
57aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[0 + baseIdx] = baseVert + 0; // a0
58aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[1 + baseIdx] = baseVert + 1; // a1
59aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[2 + baseIdx] = baseVert + 2; // b0
60aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[3 + baseIdx] = baseVert + 2; // b0
61aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[4 + baseIdx] = baseVert + 4; // c1
62aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[5 + baseIdx] = baseVert + 3; // c0
63aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[6 + baseIdx] = baseVert + 1; // a1
64aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[7 + baseIdx] = baseVert + 4; // c1
65aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        data[8 + baseIdx] = baseVert + 2; // b0
66aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
67aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (tempData) {
68aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize);
69aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        delete[] data;
70aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return ret;
71aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    } else {
72aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        qIdxBuffer->unlock();
73aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return true;
74aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
75aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
76aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
77aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
78aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) {
79a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com    const GrIndexBuffer* lIdxBuffer = context->getQuadIndexBuffer();
80a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com    if (NULL == lIdxBuffer) {
81aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return NULL;
82aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
83a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com    GrGpu* gpu = context->getGpu();
84a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com    GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false);
85a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com    SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf);
86a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com    if (NULL == qIdxBuf ||
87a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com        !push_quad_index_data(qIdxBuf)) {
88a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com        return NULL;
89a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com    }
90c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com    return SkNEW_ARGS(GrAAHairLinePathRenderer,
91c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com                      (context, lIdxBuffer, qIdxBuf));
92aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
93aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
94aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrAAHairLinePathRenderer::GrAAHairLinePathRenderer(
95aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                        const GrContext* context,
96aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                        const GrIndexBuffer* linesIndexBuffer,
97aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                        const GrIndexBuffer* quadsIndexBuffer) {
98aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    fLinesIndexBuffer = linesIndexBuffer;
99aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    linesIndexBuffer->ref();
100aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    fQuadsIndexBuffer = quadsIndexBuffer;
101aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    quadsIndexBuffer->ref();
102aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
103aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
104aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() {
105aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    fLinesIndexBuffer->unref();
106aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    fQuadsIndexBuffer->unref();
107aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
108aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
109aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comnamespace {
110aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
11149313f6b4391d0f74ab1964c295634e8830680f6bsalomon@google.comtypedef SkTArray<SkPoint, true> PtArray;
11292669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
11349313f6b4391d0f74ab1964c295634e8830680f6bsalomon@google.comtypedef SkTArray<int, true> IntArray;
114aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
115aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// Takes 178th time of logf on Z600 / VC2010
116aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comint get_float_exp(float x) {
117aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    GR_STATIC_ASSERT(sizeof(int) == sizeof(float));
118aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#if GR_DEBUG
119aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    static bool tested;
120aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (!tested) {
121aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        tested = true;
122aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(0.25f) == -2);
123aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(0.3f) == -2);
124aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(0.5f) == -1);
125aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(1.f) == 0);
126aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(2.f) == 1);
127aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(2.5f) == 1);
128aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(8.f) == 3);
129aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(100.f) == 6);
130aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(1000.f) == 9);
131aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(1024.f) == 10);
132aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(get_float_exp(3000000.f) == 21);
133aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
134aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#endif
1352ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com    const int* iptr = (const int*)&x;
1362ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com    return (((*iptr) & 0x7f800000) >> 23) - 127;
137aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
138aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
139aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// we subdivide the quads to avoid huge overfill
140aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// if it returns -1 then should be drawn as lines
141aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comint num_quad_subdivs(const SkPoint p[3]) {
142aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    static const SkScalar gDegenerateToLineTol = SK_Scalar1;
143fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    static const SkScalar gDegenerateToLineTolSqd =
14446a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com        SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol);
14546a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com
14646a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com    if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd ||
14746a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com        p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) {
14846a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com        return -1;
14946a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com    }
150aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
15181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]);
15246a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com    if (dsqd < gDegenerateToLineTolSqd) {
153aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return -1;
154aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
15546a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com
15646a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com    if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) {
157aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return -1;
158aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
159aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
160aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    static const int kMaxSub = 4;
161aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // tolerance of triangle height in pixels
162aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // tuned on windows  Quadro FX 380 / Z600
163aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // trade off of fill vs cpu time on verts
164aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // maybe different when do this using gpu (geo or tess shaders)
165aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    static const SkScalar gSubdivTol = 175 * SK_Scalar1;
166aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
1677460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com    if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) {
168aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return 0;
169aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    } else {
170aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // subdividing the quad reduces d by 4. so we want x = log4(d/tol)
171aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // = log4(d*d/tol*tol)/2
172aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // = log2(d*d/tol*tol)
173aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
174aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#ifdef SK_SCALAR_IS_FLOAT
175aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // +1 since we're ignoring the mantissa contribution.
176aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1;
177aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        log = GrMin(GrMax(0, log), kMaxSub);
178aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return log;
179aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#else
1807460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com        SkScalar log = SkScalarLog(
181fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                          SkScalarDiv(dsqd,
1827460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com                                      SkScalarMul(gSubdivTol, gSubdivTol)));
183aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        static const SkScalar conv = SkScalarInvert(SkScalarLog(2));
184aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        log = SkScalarMul(log, conv);
185aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return  GrMin(GrMax(0, SkScalarCeilToInt(log)),kMaxSub);
186aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#endif
187aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
188aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
189aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
190dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com/**
191dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Generates the lines and quads to be rendered. Lines are always recorded in
192dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * device space. We will do a device space bloat to account for the 1pixel
193dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * thickness.
194dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Quads are recorded in device space unless m contains
195dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * perspective, then in they are in src space. We do this because we will
196dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * subdivide large quads to reduce over-fill. This subdivision has to be
197dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * performed before applying the perspective matrix.
198dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com */
199dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.comint generate_lines_and_quads(const SkPath& path,
200dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                             const SkMatrix& m,
2017b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                             const GrIRect& devClipBounds,
202dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                             PtArray* lines,
203dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                             PtArray* quads,
204dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                             IntArray* quadSubdivCnts) {
205aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkPath::Iter iter(path, false);
206aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
207aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    int totalQuadCount = 0;
208aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    GrRect bounds;
209aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    GrIRect ibounds;
210dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
211dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    bool persp = m.hasPerspective();
212dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
213aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    for (;;) {
214aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrPoint pts[4];
215dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        GrPoint devPts[4];
216aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrPathCmd cmd = (GrPathCmd)iter.next(pts);
217aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        switch (cmd) {
218aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            case kMove_PathCmd:
219aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                break;
220aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            case kLine_PathCmd:
221dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                m.mapPoints(devPts, pts, 2);
222dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                bounds.setBounds(devPts, 2);
223aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.outset(SK_Scalar1, SK_Scalar1);
224aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.roundOut(&ibounds);
2257b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                if (SkIRect::Intersects(devClipBounds, ibounds)) {
226a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                    SkPoint* pts = lines->push_back_n(2);
227a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                    pts[0] = devPts[0];
228a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                    pts[1] = devPts[1];
229aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                }
230aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                break;
231dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com            case kQuadratic_PathCmd:
232dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                m.mapPoints(devPts, pts, 3);
233dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                bounds.setBounds(devPts, 3);
234aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.outset(SK_Scalar1, SK_Scalar1);
235aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.roundOut(&ibounds);
2367b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                if (SkIRect::Intersects(devClipBounds, ibounds)) {
237dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                    int subdiv = num_quad_subdivs(devPts);
238aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    GrAssert(subdiv >= -1);
239aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    if (-1 == subdiv) {
240a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        SkPoint* pts = lines->push_back_n(4);
241a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        pts[0] = devPts[0];
242a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        pts[1] = devPts[1];
243a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        pts[2] = devPts[1];
244a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        pts[3] = devPts[2];
245aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    } else {
246dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        // when in perspective keep quads in src space
247dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        SkPoint* qPts = persp ? pts : devPts;
248a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        SkPoint* pts = quads->push_back_n(3);
249a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        pts[0] = qPts[0];
250a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        pts[1] = qPts[1];
251a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                        pts[2] = qPts[2];
252aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                        quadSubdivCnts->push_back() = subdiv;
253aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                        totalQuadCount += 1 << subdiv;
254aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    }
255aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                }
256a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                break;
257dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com            case kCubic_PathCmd:
258dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                m.mapPoints(devPts, pts, 4);
259dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                bounds.setBounds(devPts, 4);
260aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.outset(SK_Scalar1, SK_Scalar1);
261aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.roundOut(&ibounds);
2627b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                if (SkIRect::Intersects(devClipBounds, ibounds)) {
26392669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com                    PREALLOC_PTARRAY(32) q;
264a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                    // we don't need a direction if we aren't constraining the subdivision
265a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                    static const SkPath::Direction kDummyDir = SkPath::kCCW_Direction;
26669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                    // We convert cubics to quadratics (for now).
26769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                    // In perspective have to do conversion in src space.
268dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                    if (persp) {
269fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                        SkScalar tolScale =
270dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m,
271dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                                             path.getBounds());
272a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                        GrPathUtils::convertCubicToQuads(pts, tolScale, false, kDummyDir, &q);
273dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                    } else {
274a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                        GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, false, kDummyDir, &q);
275dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                    }
276aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    for (int i = 0; i < q.count(); i += 3) {
277dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        SkPoint* qInDevSpace;
278dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        // bounds has to be calculated in device space, but q is
279dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        // in src space when there is perspective.
280dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        if (persp) {
281dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            m.mapPoints(devPts, &q[i], 3);
282dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            bounds.setBounds(devPts, 3);
283dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            qInDevSpace = devPts;
284dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        } else {
285dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            bounds.setBounds(&q[i], 3);
286dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            qInDevSpace = &q[i];
287dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        }
288aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                        bounds.outset(SK_Scalar1, SK_Scalar1);
289aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                        bounds.roundOut(&ibounds);
2907b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                        if (SkIRect::Intersects(devClipBounds, ibounds)) {
291dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            int subdiv = num_quad_subdivs(qInDevSpace);
292aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                            GrAssert(subdiv >= -1);
293aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                            if (-1 == subdiv) {
294a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                SkPoint* pts = lines->push_back_n(4);
295dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                // lines should always be in device coords
296a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[0] = qInDevSpace[0];
297a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[1] = qInDevSpace[1];
298a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[2] = qInDevSpace[1];
299a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[3] = qInDevSpace[2];
300aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                            } else {
301a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                SkPoint* pts = quads->push_back_n(3);
302dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                // q is already in src space when there is no
303dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                // perspective and dev coords otherwise.
304a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[0] = q[0 + i];
305a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[1] = q[1 + i];
306a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[2] = q[2 + i];
307aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                quadSubdivCnts->push_back() = subdiv;
308aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                totalQuadCount += 1 << subdiv;
309aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                            }
310aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                        }
311aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    }
312aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                }
313a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                break;
314aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            case kClose_PathCmd:
315aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                break;
316aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            case kEnd_PathCmd:
317aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                return totalQuadCount;
318aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        }
319aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
320aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
321aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
322aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstruct Vertex {
323aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    GrPoint fPos;
324aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    union {
325aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        struct {
32681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalar fA;
32781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalar fB;
32881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalar fC;
329aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        } fLine;
330aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrVec   fQuadCoord;
331aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        struct {
33281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalar fBogus[4];
333aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        };
334aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    };
335aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com};
336aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint));
337aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
338aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid intersect_lines(const SkPoint& ptA, const SkVector& normA,
339aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                     const SkPoint& ptB, const SkVector& normB,
340aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                     SkPoint* result) {
341aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
342aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkScalar lineAW = -normA.dot(ptA);
343aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkScalar lineBW = -normB.dot(ptB);
344aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
345aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkScalar wInv = SkScalarMul(normA.fX, normB.fY) -
346aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    SkScalarMul(normA.fY, normB.fX);
347aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    wInv = SkScalarInvert(wInv);
348aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
349aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY);
350aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    result->fX = SkScalarMul(result->fX, wInv);
351fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
352aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW);
353aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    result->fY = SkScalarMul(result->fY, wInv);
354aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
355aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
356b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.comvoid bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
357b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com                const SkMatrix* toSrc, Vertex verts[kVertsPerQuad]) {
358dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    GrAssert(!toDevice == !toSrc);
359aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // original quad is specified by tri a,b,c
360dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    SkPoint a = qpts[0];
361dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    SkPoint b = qpts[1];
362dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    SkPoint c = qpts[2];
363aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
364dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // this should be in the src space, not dev coords, when we have perspective
3651971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    GrPathUtils::QuadUVMatrix DevToUV(qpts);
366aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
367dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    if (toDevice) {
368dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        toDevice->mapPoints(&a, 1);
369dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        toDevice->mapPoints(&b, 1);
370dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        toDevice->mapPoints(&c, 1);
371dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    }
372dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // make a new poly where we replace a and c by a 1-pixel wide edges orthog
373dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // to edges ab and bc:
374dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //
375dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //   before       |        after
376dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //                |              b0
377dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //         b      |
378dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //                |
379dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //                |     a0            c0
380dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // a         c    |        a1       c1
381dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //
382dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c,
383dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // respectively.
384dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    Vertex& a0 = verts[0];
385dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    Vertex& a1 = verts[1];
386dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    Vertex& b0 = verts[2];
387dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    Vertex& c0 = verts[3];
388dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    Vertex& c1 = verts[4];
389dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
390aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector ab = b;
391aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    ab -= a;
392aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector ac = c;
393aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    ac -= a;
394aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector cb = b;
395aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    cb -= c;
396aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
397aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // We should have already handled degenerates
398aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    GrAssert(ab.length() > 0 && cb.length() > 0);
399aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
400aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    ab.normalize();
401aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector abN;
402aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    abN.setOrthog(ab, SkVector::kLeft_Side);
403aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (abN.dot(ac) > 0) {
404aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        abN.negate();
405aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
406aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
407aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    cb.normalize();
408aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector cbN;
409aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    cbN.setOrthog(cb, SkVector::kLeft_Side);
410aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (cbN.dot(ac) < 0) {
411aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        cbN.negate();
412aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
413aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
414aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    a0.fPos = a;
415aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    a0.fPos += abN;
416aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    a1.fPos = a;
417aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    a1.fPos -= abN;
418aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
419aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    c0.fPos = c;
420aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    c0.fPos += cbN;
421aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    c1.fPos = c;
422aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    c1.fPos -= cbN;
423aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
424aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
425aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
426dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    if (toSrc) {
427dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad);
428dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    }
4291971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts);
430aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
431aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
432aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid add_quads(const SkPoint p[3],
433aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com               int subdiv,
434b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com               const SkMatrix* toDevice,
435b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com               const SkMatrix* toSrc,
436aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com               Vertex** vert) {
437aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    GrAssert(subdiv >= 0);
438aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (subdiv) {
439aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        SkPoint newP[5];
440aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        SkChopQuadAtHalf(p, newP);
441dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert);
442dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert);
443aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    } else {
444dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        bloat_quad(p, toDevice, toSrc, *vert);
445aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        *vert += kVertsPerQuad;
446aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
447aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
448aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
449aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid add_line(const SkPoint p[2],
450aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com              int rtHeight,
451dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com              const SkMatrix* toSrc,
452aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com              Vertex** vert) {
453aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    const SkPoint& a = p[0];
454aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    const SkPoint& b = p[1];
455aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
456aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector orthVec = b;
457aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    orthVec -= a;
458aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
459aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (orthVec.setLength(SK_Scalar1)) {
460aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        orthVec.setOrthog(orthVec);
461aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
462706f66831a575bdc2b1ab1331b48b793cd487356bsalomon@google.com        SkScalar lineC = -(a.dot(orthVec));
463aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        for (int i = 0; i < kVertsPerLineSeg; ++i) {
464aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            (*vert)[i].fPos = (i < 2) ? a : b;
465aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            if (0 == i || 3 == i) {
466aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                (*vert)[i].fPos -= orthVec;
467aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            } else {
468aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                (*vert)[i].fPos += orthVec;
469aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            }
470706f66831a575bdc2b1ab1331b48b793cd487356bsalomon@google.com            (*vert)[i].fLine.fA = orthVec.fX;
471706f66831a575bdc2b1ab1331b48b793cd487356bsalomon@google.com            (*vert)[i].fLine.fB = orthVec.fY;
472aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com            (*vert)[i].fLine.fC = lineC;
473aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        }
474dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        if (NULL != toSrc) {
475dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com            toSrc->mapPointsWithStride(&(*vert)->fPos,
476dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                       sizeof(Vertex),
477dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                       kVertsPerLineSeg);
478dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        }
479aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    } else {
480aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // just make it degenerate and likely offscreen
481aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax);
482aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax);
483aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax);
484aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax);
485aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
486aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
487aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    *vert += kVertsPerLineSeg;
488aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
489aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
490aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
491aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
492b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.combool GrAAHairLinePathRenderer::createGeom(
493b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com            const SkPath& path,
494b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com            GrDrawTarget* target,
495b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com            int* lineCnt,
496b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com            int* quadCnt,
497b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com            GrDrawTarget::AutoReleaseGeometry* arg) {
4989b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    GrDrawState* drawState = target->drawState();
4999b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    int rtHeight = drawState->getRenderTarget()->height();
500aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
5017b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    GrIRect devClipBounds;
5029b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    target->getClip()->getConservativeBounds(drawState->getRenderTarget(),
5037b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                             &devClipBounds);
504aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
5059b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    // position + edge
5069b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    static const GrVertexAttrib kAttribs[] = {
5073b0d631cdfe2dcf59e7b7ea60d92566eade7bfc0jvanverth@google.com        {kVec2f_GrVertexAttribType, 0},
5083b0d631cdfe2dcf59e7b7ea60d92566eade7bfc0jvanverth@google.com        {kVec4f_GrVertexAttribType, sizeof(GrPoint)}
5099b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    };
5109b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    static const GrAttribBindings kBindings = GrDrawState::kEdge_AttribBindingsBit;
5119b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    SkMatrix viewM = drawState->getViewMatrix();
512aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
51392669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com    PREALLOC_PTARRAY(128) lines;
51492669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com    PREALLOC_PTARRAY(128) quads;
515aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    IntArray qSubdivs;
5160f11e1ab5b6e53f6176dde2dbb25a8e3ae34858fbsalomon@google.com    *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds,
517dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                        &lines, &quads, &qSubdivs);
518aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
519c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    *lineCnt = lines.count() / 2;
520c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt;
521aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
5229b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    target->drawState()->setVertexAttribs(kAttribs, SK_ARRAY_COUNT(kAttribs));
5239b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    target->drawState()->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
5249b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    target->drawState()->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1);
5259b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    target->drawState()->setAttribBindings(kBindings);
526b75b0a0b8492e14c7728e0a0881f87dc64ce60f9jvanverth@google.com    GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize());
527aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
528b75b0a0b8492e14c7728e0a0881f87dc64ce60f9jvanverth@google.com    if (!arg->set(target, vertCnt, 0)) {
529aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return false;
530aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
531dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
532b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com    Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices());
533b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com
534b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    const SkMatrix* toDevice = NULL;
535b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    const SkMatrix* toSrc = NULL;
536b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix ivm;
537dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
538dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    if (viewM.hasPerspective()) {
539dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        if (viewM.invert(&ivm)) {
540dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com            toDevice = &viewM;
541dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com            toSrc = &ivm;
542dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        }
543dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    }
544aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
545c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    for (int i = 0; i < *lineCnt; ++i) {
546dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        add_line(&lines[2*i], rtHeight, toSrc, &verts);
547aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
548dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
549aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    int unsubdivQuadCnt = quads.count() / 3;
550aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    for (int i = 0; i < unsubdivQuadCnt; ++i) {
551aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        GrAssert(qSubdivs[i] >= 0);
552dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
553aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
554aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
555aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    return true;
556aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
557aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
5588a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.combool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path,
5595f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                                           const SkStrokeRec& stroke,
5608a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                           const GrDrawTarget* target,
5618a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                           bool antiAlias) const {
5625f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    if (!stroke.isHairlineStyle() || !antiAlias) {
563c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return false;
564c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    }
565c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com
566c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask |
567c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                                          SkPath::kQuad_SegmentMask;
568f66018798099750e639a8fa131fece492a050997bsalomon@google.com    if (!target->getCaps().shaderDerivativeSupport() &&
569c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        (gReqDerivMask & path.getSegmentMasks())) {
570c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return false;
571c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    }
572c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    return true;
573c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com}
574aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
575c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.combool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
5765f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                                          const SkStrokeRec&,
577c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                                          GrDrawTarget* target,
578c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                                          bool antiAlias) {
579c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com
580c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    int lineCnt;
581c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    int quadCnt;
582b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com    GrDrawTarget::AutoReleaseGeometry arg;
583c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    if (!this->createGeom(path,
584c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                          target,
585c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                          &lineCnt,
586b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com                          &quadCnt,
587b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com                          &arg)) {
588c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return false;
589aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
590aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
591a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com    GrDrawState::AutoDeviceCoordDraw adcd;
592873ea0c93f202600ec2591bc1e2e5d7a1e05f59dbsalomon@google.com    GrDrawState* drawState = target->drawState();
593a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com    // createGeom transforms the geometry to device space when the matrix does not have
594a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com    // perspective.
5958f9cbd62ec108d410b91155dcf6a4789c641246fbsalomon@google.com    if (!drawState->getViewMatrix().hasPerspective()) {
596a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com        adcd.set(drawState);
597a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com        if (!adcd.succeeded()) {
598e3d3216fe17b6afb2e613271b5246a2766e12df6bsalomon@google.com            return false;
599dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        }
600aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
601fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
602aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // TODO: See whether rendering lines as degenerate quads improves perf
603aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // when we have a mix
604a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com
605a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com    GrDrawState::VertexEdgeType oldEdgeType = drawState->getVertexEdgeType();
606a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com
607c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    target->setIndexSourceToBuffer(fLinesIndexBuffer);
608aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    int lines = 0;
609aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    int nBufLines = fLinesIndexBuffer->maxQuads();
610a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com    drawState->setVertexEdgeType(GrDrawState::kHairLine_EdgeType);
611c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    while (lines < lineCnt) {
612c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        int n = GrMin(lineCnt - lines, nBufLines);
61347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com        target->drawIndexed(kTriangles_GrPrimitiveType,
614c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                            kVertsPerLineSeg*lines,    // startV
615c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                            0,                         // startI
616c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                            kVertsPerLineSeg*n,        // vCount
617c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                            kIdxsPerLineSeg*n);        // iCount
618aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        lines += n;
619aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
620aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
621c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    target->setIndexSourceToBuffer(fQuadsIndexBuffer);
622aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    int quads = 0;
623a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com    drawState->setVertexEdgeType(GrDrawState::kHairQuad_EdgeType);
624c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    while (quads < quadCnt) {
625c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer);
62647059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com        target->drawIndexed(kTriangles_GrPrimitiveType,
627c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                            4 * lineCnt + kVertsPerQuad*quads, // startV
628c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                            0,                                 // startI
629c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                            kVertsPerQuad*n,                   // vCount
630c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                            kIdxsPerQuad*n);                   // iCount
631aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        quads += n;
632aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
633a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com    drawState->setVertexEdgeType(oldEdgeType);
634c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    return true;
635aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
636