1f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com/*
2f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Copyright 2011 Google Inc.
3f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com *
4f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be
5f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * found in the LICENSE file.
6f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com */
7f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com
8aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrAAHairLinePathRenderer.h"
9aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
107bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt#include "GrBatch.h"
117bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt#include "GrBatchTarget.h"
1240ded3241894076237844325c015fcc724e9d443joshualitt#include "GrBatchTest.h"
13aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrContext.h"
145478d427c6e67c986a3390162c8fec77c466058ajoshualitt#include "GrDefaultGeoProcFactory.h"
15c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h"
16aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrIndexBuffer.h"
17dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com#include "GrPathUtils.h"
188dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel#include "GrPipelineBuilder.h"
195478d427c6e67c986a3390162c8fec77c466058ajoshualitt#include "GrProcessor.h"
20ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon#include "GrResourceProvider.h"
2172e3ae486c66871c2043eac4f08d85d419fbca2absalomon#include "GrVertexBuffer.h"
22aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkGeometry.h"
2312b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com#include "SkStroke.h"
24aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkTemplates.h"
25aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
2607e1c3fd5030869c480c15ff30d36bd161718262commit-bot@chromium.org#include "effects/GrBezierEffect.h"
274647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
28ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
29ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon
30aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// quadratics are rendered as 5-sided polys in order to bound the
31aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// AA stroke around the center-curve. See comments in push_quad_index_buffer and
325383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// bloat_quad. Quadratics and conics share an index buffer
33aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
34ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// lines are rendered as:
35ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com//      *______________*
36ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com//      |\ -_______   /|
37ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com//      | \        \ / |
38ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com//      |  *--------*  |
39ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com//      | /  ______/ \ |
40ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com//      */_-__________\*
41ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// For: 6 vertices and 18 indices (for 6 triangles)
42681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com
435ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each quadratic is rendered as a five sided polygon. This poly bounds
445ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// the quadratic's bounding triangle but has been expanded so that the
455ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 1-pixel wide area around the curve is inside the poly.
465ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// If a,b,c are the original control points then the poly a0,b0,c0,c1,a1
475ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// that is rendered would look like this:
485ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//              b0
495ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//              b
505ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//
515ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//     a0              c0
525ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//      a            c
535ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//       a1       c1
5414afb43b01e178b50674d16a5a62d2b7dbd600dbegdaniel// Each is drawn as three triangles ((a0,a1,b0), (b0,c1,c0), (a1,c1,b0))
5514afb43b01e178b50674d16a5a62d2b7dbd600dbegdaniel// specified by these 9 indices:
565ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const uint16_t kQuadIdxBufPattern[] = {
575ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    0, 1, 2,
585ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    2, 4, 3,
595ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    1, 4, 2
605ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt};
615ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt
625ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIdxsPerQuad = SK_ARRAY_COUNT(kQuadIdxBufPattern);
635ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kQuadNumVertices = 5;
645ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kQuadsNumInIdxBuffer = 256;
65ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonGR_DECLARE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
66ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon
67ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic const GrIndexBuffer* ref_quads_index_buffer(GrResourceProvider* resourceProvider) {
68ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    GR_DEFINE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
69ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    return resourceProvider->refOrCreateInstancedIndexBuffer(
70ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices,
71ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        gQuadsIndexBufferKey);
72ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon}
735ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt
745ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt
755ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each line segment is rendered as two quads and two triangles.
765ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p0 and p1 have alpha = 1 while all other points have alpha = 0.
775ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// The four external points are offset 1 pixel perpendicular to the
785ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// line and half a pixel parallel to the line.
795ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//
805ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p4                  p5
815ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//      p0         p1
825ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p2                  p3
835ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt//
845ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each is drawn as six triangles specified by these 18 indices:
855ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt
865ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const uint16_t kLineSegIdxBufPattern[] = {
875ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    0, 1, 3,
885ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    0, 3, 2,
895ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    0, 4, 5,
905ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    0, 5, 1,
915ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    0, 2, 4,
925ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    1, 5, 3
935ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt};
945ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt
955ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIdxsPerLineSeg = SK_ARRAY_COUNT(kLineSegIdxBufPattern);
965ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kLineSegNumVertices = 6;
975ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kLineSegsNumInIdxBuffer = 256;
98aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
99ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonGR_DECLARE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
100aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
101ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic const GrIndexBuffer* ref_lines_index_buffer(GrResourceProvider* resourceProvider) {
102ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    GR_DEFINE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
103ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    return resourceProvider->refOrCreateInstancedIndexBuffer(
104ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        kLineSegIdxBufPattern, kIdxsPerLineSeg,  kLineSegsNumInIdxBuffer, kLineSegNumVertices,
105ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        gLinesIndexBufferKey);
106aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
107aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
108aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// Takes 178th time of logf on Z600 / VC2010
109ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int get_float_exp(float x) {
110aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    GR_STATIC_ASSERT(sizeof(int) == sizeof(float));
111515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
112aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    static bool tested;
113aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (!tested) {
114aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        tested = true;
115f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(0.25f) == -2);
116f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(0.3f) == -2);
117f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(0.5f) == -1);
118f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(1.f) == 0);
119f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(2.f) == 1);
120f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(2.5f) == 1);
121f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(8.f) == 3);
122f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(100.f) == 6);
123f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(1000.f) == 9);
124f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(1024.f) == 10);
125f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(get_float_exp(3000000.f) == 21);
126aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
127aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#endif
1282ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com    const int* iptr = (const int*)&x;
1292ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com    return (((*iptr) & 0x7f800000) >> 23) - 127;
130aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
131aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
1325383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Uses the max curvature function for quads to estimate
1335383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// where to chop the conic. If the max curvature is not
1345383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// found along the curve segment it will return 1 and
1353f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// dst[0] is the original conic. If it returns 2 the dst[0]
1365383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// and dst[1] are the two new conics.
137ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
1385383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    SkScalar t = SkFindQuadMaxCurvature(src);
1395383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    if (t == 0) {
1405383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        if (dst) {
1415383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com            dst[0].set(src, weight);
1425383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        }
1435383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        return 1;
1445383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    } else {
1455383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        if (dst) {
1465383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com            SkConic conic;
1475383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com            conic.set(src, weight);
1485383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com            conic.chopAt(t, dst);
1495383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        }
1505383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        return 2;
1515383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    }
1525383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com}
1535383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
1543f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Calls split_conic on the entire conic and then once more on each subsection.
1553f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Most cases will result in either 1 conic (chop point is not within t range)
1563f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// or 3 points (split once and then one subsection is split again).
157ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
1583f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com    SkConic dstTemp[2];
1593f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com    int conicCnt = split_conic(src, dstTemp, weight);
1603f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com    if (2 == conicCnt) {
1613f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com        int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
1623f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com        conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
1633f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com    } else {
1643f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com        dst[0] = dstTemp[0];
1653f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com    }
1663f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com    return conicCnt;
1673f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com}
1683f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com
1695383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// returns 0 if quad/conic is degen or close to it
1705383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// in this case approx the path with lines
1715383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// otherwise returns 1
172ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) {
173876f48b6cdae5a77770304ae77f42aff530fa90djvanverth    static const SkScalar gDegenerateToLineTol = GrPathUtils::kDefaultTolerance;
1745383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    static const SkScalar gDegenerateToLineTolSqd =
1755383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol);
1765383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
1775383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd ||
1785383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) {
1795383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        return 1;
1805383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    }
1815383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
1826364807151ddf51c4197603aa185b3336f325357joshualitt    *dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]);
1836364807151ddf51c4197603aa185b3336f325357joshualitt    if (*dsqd < gDegenerateToLineTolSqd) {
1845383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        return 1;
1855383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    }
1865383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
1875383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) {
1885383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        return 1;
1895383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    }
1905383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    return 0;
1915383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com}
1925383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
193ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int is_degen_quad_or_conic(const SkPoint p[3]) {
1946364807151ddf51c4197603aa185b3336f325357joshualitt    SkScalar dsqd;
1956364807151ddf51c4197603aa185b3336f325357joshualitt    return is_degen_quad_or_conic(p, &dsqd);
1966364807151ddf51c4197603aa185b3336f325357joshualitt}
1976364807151ddf51c4197603aa185b3336f325357joshualitt
198aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// we subdivide the quads to avoid huge overfill
199aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// if it returns -1 then should be drawn as lines
200ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int num_quad_subdivs(const SkPoint p[3]) {
2016364807151ddf51c4197603aa185b3336f325357joshualitt    SkScalar dsqd;
2026364807151ddf51c4197603aa185b3336f325357joshualitt    if (is_degen_quad_or_conic(p, &dsqd)) {
203aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return -1;
204aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
205aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
206aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // tolerance of triangle height in pixels
207aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // tuned on windows  Quadro FX 380 / Z600
208aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // trade off of fill vs cpu time on verts
209aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // maybe different when do this using gpu (geo or tess shaders)
210aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    static const SkScalar gSubdivTol = 175 * SK_Scalar1;
211aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
2127460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com    if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) {
213aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return 0;
214aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    } else {
21587379e17c5e95c6fe0d88b3b9ae134355cfafc66robertphillips@google.com        static const int kMaxSub = 4;
216aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // subdividing the quad reduces d by 4. so we want x = log4(d/tol)
217aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // = log4(d*d/tol*tol)/2
218aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // = log2(d*d/tol*tol)
219aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
220aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // +1 since we're ignoring the mantissa contribution.
221aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1;
222972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org        log = SkTMin(SkTMax(0, log), kMaxSub);
223aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        return log;
224aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
225aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
226aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
227dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com/**
228dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Generates the lines and quads to be rendered. Lines are always recorded in
229dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * device space. We will do a device space bloat to account for the 1pixel
230dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * thickness.
231dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Quads are recorded in device space unless m contains
232dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * perspective, then in they are in src space. We do this because we will
233dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * subdivide large quads to reduce over-fill. This subdivision has to be
234dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * performed before applying the perspective matrix.
235dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com */
236ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int gather_lines_and_quads(const SkPath& path,
237ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                  const SkMatrix& m,
238ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                  const SkIRect& devClipBounds,
239ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                  GrAAHairLinePathRenderer::PtArray* lines,
240ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                  GrAAHairLinePathRenderer::PtArray* quads,
241ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                  GrAAHairLinePathRenderer::PtArray* conics,
242ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                  GrAAHairLinePathRenderer::IntArray* quadSubdivCnts,
243ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                  GrAAHairLinePathRenderer::FloatArray* conicWeights) {
244aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkPath::Iter iter(path, false);
245aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
246aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    int totalQuadCount = 0;
247fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkRect bounds;
248fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkIRect ibounds;
249dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
250dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    bool persp = m.hasPerspective();
251dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
252aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    for (;;) {
253972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org        SkPoint pathPts[4];
254972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org        SkPoint devPts[4];
255912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org        SkPath::Verb verb = iter.next(pathPts);
25694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        switch (verb) {
2575383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com            case SkPath::kConic_Verb: {
2583f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com                SkConic dst[4];
2593f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com                // We chop the conics to create tighter clipping to hide error
2603f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com                // that appears near max curvature of very thin conics. Thin
2613f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com                // hyperbolas with high weight still show error.
2625383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                int conicCnt = chop_conic(pathPts, dst, iter.conicWeight());
2635383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                for (int i = 0; i < conicCnt; ++i) {
2645383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                    SkPoint* chopPnts = dst[i].fPts;
2655383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                    m.mapPoints(devPts, chopPnts, 3);
2665383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                    bounds.setBounds(devPts, 3);
2675383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                    bounds.outset(SK_Scalar1, SK_Scalar1);
2685383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                    bounds.roundOut(&ibounds);
2695383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                    if (SkIRect::Intersects(devClipBounds, ibounds)) {
2705383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                        if (is_degen_quad_or_conic(devPts)) {
2715383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            SkPoint* pts = lines->push_back_n(4);
2725383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            pts[0] = devPts[0];
2735383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            pts[1] = devPts[1];
2745383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            pts[2] = devPts[1];
2755383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            pts[3] = devPts[2];
2765383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                        } else {
2775383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            // when in perspective keep conics in src space
2785383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            SkPoint* cPts = persp ? chopPnts : devPts;
2795383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            SkPoint* pts = conics->push_back_n(3);
2805383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            pts[0] = cPts[0];
2815383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            pts[1] = cPts[1];
2825383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            pts[2] = cPts[2];
2835383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                            conicWeights->push_back() = dst[i].fW;
2845383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                        }
2855383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                    }
2865383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com                }
287277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com                break;
2885383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com            }
2895383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com            case SkPath::kMove_Verb:
290aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                break;
29194b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kLine_Verb:
292912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                m.mapPoints(devPts, pathPts, 2);
293dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                bounds.setBounds(devPts, 2);
294aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.outset(SK_Scalar1, SK_Scalar1);
295aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.roundOut(&ibounds);
2967b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                if (SkIRect::Intersects(devClipBounds, ibounds)) {
297a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                    SkPoint* pts = lines->push_back_n(2);
298a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                    pts[0] = devPts[0];
299a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                    pts[1] = devPts[1];
300aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                }
301aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                break;
302912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org            case SkPath::kQuad_Verb: {
303912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                SkPoint choppedPts[5];
304912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                // Chopping the quad helps when the quad is either degenerate or nearly degenerate.
305912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                // When it is degenerate it allows the approximation with lines to work since the
306912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                // chop point (if there is one) will be at the parabola's vertex. In the nearly
307912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                // degenerate the QuadUVMatrix computed for the points is almost singular which
308912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                // can cause rendering artifacts.
309912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                int n = SkChopQuadAtMaxCurvature(pathPts, choppedPts);
310912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                for (int i = 0; i < n; ++i) {
311912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                    SkPoint* quadPts = choppedPts + i * 2;
312912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                    m.mapPoints(devPts, quadPts, 3);
313912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                    bounds.setBounds(devPts, 3);
314912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                    bounds.outset(SK_Scalar1, SK_Scalar1);
315912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                    bounds.roundOut(&ibounds);
316912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org
317912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                    if (SkIRect::Intersects(devClipBounds, ibounds)) {
318912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                        int subdiv = num_quad_subdivs(devPts);
319f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org                        SkASSERT(subdiv >= -1);
320912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                        if (-1 == subdiv) {
321912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            SkPoint* pts = lines->push_back_n(4);
322912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            pts[0] = devPts[0];
323912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            pts[1] = devPts[1];
324912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            pts[2] = devPts[1];
325912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            pts[3] = devPts[2];
326912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                        } else {
327912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            // when in perspective keep quads in src space
328912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            SkPoint* qPts = persp ? quadPts : devPts;
329912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            SkPoint* pts = quads->push_back_n(3);
330912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            pts[0] = qPts[0];
331912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            pts[1] = qPts[1];
332912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            pts[2] = qPts[2];
333912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            quadSubdivCnts->push_back() = subdiv;
334912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                            totalQuadCount += 1 << subdiv;
335912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                        }
336aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    }
337aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                }
338a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                break;
339912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org            }
34094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kCubic_Verb:
341912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                m.mapPoints(devPts, pathPts, 4);
342dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                bounds.setBounds(devPts, 4);
343aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.outset(SK_Scalar1, SK_Scalar1);
344aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                bounds.roundOut(&ibounds);
3457b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                if (SkIRect::Intersects(devClipBounds, ibounds)) {
34692669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com                    PREALLOC_PTARRAY(32) q;
347a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                    // we don't need a direction if we aren't constraining the subdivision
348a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                    static const SkPath::Direction kDummyDir = SkPath::kCCW_Direction;
34969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                    // We convert cubics to quadratics (for now).
35069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                    // In perspective have to do conversion in src space.
351dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                    if (persp) {
352fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                        SkScalar tolScale =
353dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m,
354dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                                             path.getBounds());
355912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org                        GrPathUtils::convertCubicToQuads(pathPts, tolScale, false, kDummyDir, &q);
356dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                    } else {
357a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                        GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, false, kDummyDir, &q);
358dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                    }
359aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    for (int i = 0; i < q.count(); i += 3) {
360dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        SkPoint* qInDevSpace;
361dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        // bounds has to be calculated in device space, but q is
362dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        // in src space when there is perspective.
363dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        if (persp) {
364dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            m.mapPoints(devPts, &q[i], 3);
365dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            bounds.setBounds(devPts, 3);
366dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            qInDevSpace = devPts;
367dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        } else {
368dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            bounds.setBounds(&q[i], 3);
369dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            qInDevSpace = &q[i];
370dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                        }
371aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                        bounds.outset(SK_Scalar1, SK_Scalar1);
372aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                        bounds.roundOut(&ibounds);
3737b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                        if (SkIRect::Intersects(devClipBounds, ibounds)) {
374dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                            int subdiv = num_quad_subdivs(qInDevSpace);
375f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org                            SkASSERT(subdiv >= -1);
376aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                            if (-1 == subdiv) {
377a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                SkPoint* pts = lines->push_back_n(4);
378dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                // lines should always be in device coords
379a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[0] = qInDevSpace[0];
380a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[1] = qInDevSpace[1];
381a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[2] = qInDevSpace[1];
382a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[3] = qInDevSpace[2];
383aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                            } else {
384a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                SkPoint* pts = quads->push_back_n(3);
385dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                // q is already in src space when there is no
386dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com                                // perspective and dev coords otherwise.
387a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[0] = q[0 + i];
388a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[1] = q[1 + i];
389a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com                                pts[2] = q[2 + i];
390aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                quadSubdivCnts->push_back() = subdiv;
391aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                                totalQuadCount += 1 << subdiv;
392aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                            }
393aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                        }
394aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                    }
395aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                }
396a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                break;
39794b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kClose_Verb:
398aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                break;
39994b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kDone_Verb:
400aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com                return totalQuadCount;
401aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        }
402aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
403aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
404aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
405681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comstruct LineVertex {
406972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint fPos;
407e27065ae243575f6d5d545909ad3030773c14db8egdaniel    float fCoverage;
408681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com};
4097475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com
410681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comstruct BezierVertex {
411972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint fPos;
412aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    union {
413aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        struct {
4143f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com            SkScalar fK;
4153f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com            SkScalar fL;
4163f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com            SkScalar fM;
4175383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        } fConic;
418972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org        SkVector   fQuadCoord;
419aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        struct {
4203f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com            SkScalar fBogus[4];
421aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        };
422aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    };
423aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com};
4245383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
425972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgGR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(SkPoint));
426aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
427ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void intersect_lines(const SkPoint& ptA, const SkVector& normA,
428ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                            const SkPoint& ptB, const SkVector& normB,
429ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                            SkPoint* result) {
430aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
431aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkScalar lineAW = -normA.dot(ptA);
432aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkScalar lineBW = -normB.dot(ptB);
433aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
434aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkScalar wInv = SkScalarMul(normA.fX, normB.fY) -
4355383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        SkScalarMul(normA.fY, normB.fX);
436aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    wInv = SkScalarInvert(wInv);
437aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
438aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY);
439aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    result->fX = SkScalarMul(result->fX, wInv);
440fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
441aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW);
442aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    result->fY = SkScalarMul(result->fY, wInv);
443aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
444aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
445ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) {
44634b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com    // this should be in the src space, not dev coords, when we have perspective
44734b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com    GrPathUtils::QuadUVMatrix DevToUV(qpts);
4485ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts);
44934b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com}
45034b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com
451ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
452ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                       const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) {
453f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(!toDevice == !toSrc);
454aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // original quad is specified by tri a,b,c
455dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    SkPoint a = qpts[0];
456dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    SkPoint b = qpts[1];
457dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    SkPoint c = qpts[2];
458aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
459dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    if (toDevice) {
460dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        toDevice->mapPoints(&a, 1);
461dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        toDevice->mapPoints(&b, 1);
462dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        toDevice->mapPoints(&c, 1);
463dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    }
464dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // make a new poly where we replace a and c by a 1-pixel wide edges orthog
465dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // to edges ab and bc:
466dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //
467dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //   before       |        after
468dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //                |              b0
469dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //         b      |
470dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //                |
471dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //                |     a0            c0
472dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // a         c    |        a1       c1
473dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    //
474dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c,
475dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    // respectively.
476681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com    BezierVertex& a0 = verts[0];
477681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com    BezierVertex& a1 = verts[1];
478681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com    BezierVertex& b0 = verts[2];
479681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com    BezierVertex& c0 = verts[3];
480681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com    BezierVertex& c1 = verts[4];
481dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com
482aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector ab = b;
483aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    ab -= a;
484aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector ac = c;
485aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    ac -= a;
486aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector cb = b;
487aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    cb -= c;
488aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
489aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    // We should have already handled degenerates
490f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(ab.length() > 0 && cb.length() > 0);
491aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
492aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    ab.normalize();
493aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector abN;
494aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    abN.setOrthog(ab, SkVector::kLeft_Side);
495aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (abN.dot(ac) > 0) {
496aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        abN.negate();
497aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
498aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
499aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    cb.normalize();
500aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    SkVector cbN;
501aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    cbN.setOrthog(cb, SkVector::kLeft_Side);
502aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (cbN.dot(ac) < 0) {
503aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        cbN.negate();
504aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
505aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
506aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    a0.fPos = a;
507aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    a0.fPos += abN;
508aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    a1.fPos = a;
509aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    a1.fPos -= abN;
510aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
511aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    c0.fPos = c;
512aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    c0.fPos += cbN;
513aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    c1.fPos = c;
514aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    c1.fPos -= cbN;
515aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
516aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
517aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
518dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    if (toSrc) {
5195ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt        toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices);
520dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com    }
521aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
522aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
5233f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Equations based off of Loop-Blinn Quadratic GPU Rendering
5245383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Input Parametric:
5255383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2)
5265383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Output Implicit:
5273f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// f(x, y, w) = f(P) = K^2 - LM
5283f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// K = dot(k, P), L = dot(l, P), M = dot(m, P)
529139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// k, l, m are calculated in function GrPathUtils::getConicKLM
530ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices],
531ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                             const SkScalar weight) {
532139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    SkScalar klm[9];
5333f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com
534139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    GrPathUtils::getConicKLM(p, weight, klm);
5355383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
5365ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    for (int i = 0; i < kQuadNumVertices; ++i) {
5373f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com        const SkPoint pnt = verts[i].fPos;
538139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org        verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2];
539139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org        verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5];
540139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org        verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8];
5415383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    }
5425383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com}
5435383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
544ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void add_conics(const SkPoint p[3],
545ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                       const SkScalar weight,
546ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                       const SkMatrix* toDevice,
547ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                       const SkMatrix* toSrc,
548ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                       BezierVertex** vert) {
5497bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    bloat_quad(p, toDevice, toSrc, *vert);
5505383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    set_conic_coeffs(p, *vert, weight);
5515ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    *vert += kQuadNumVertices;
5525383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com}
5535383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com
554ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void add_quads(const SkPoint p[3],
555ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                      int subdiv,
556ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                      const SkMatrix* toDevice,
557ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                      const SkMatrix* toSrc,
558ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                      BezierVertex** vert) {
559f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(subdiv >= 0);
560aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    if (subdiv) {
561aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        SkPoint newP[5];
562aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        SkChopQuadAtHalf(p, newP);
5637bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert);
5647bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert);
565aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    } else {
5667bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        bloat_quad(p, toDevice, toSrc, *vert);
56734b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com        set_uv_quad(p, *vert);
5685ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt        *vert += kQuadNumVertices;
569aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
570aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
571aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
572ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void add_line(const SkPoint p[2],
573ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                     const SkMatrix* toSrc,
574ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                     uint8_t coverage,
575ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                     LineVertex** vert) {
576aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    const SkPoint& a = p[0];
577aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    const SkPoint& b = p[1];
578aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
579ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com    SkVector ortho, vec = b;
580ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com    vec -= a;
581ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com
582ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com    if (vec.setLength(SK_ScalarHalf)) {
583ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        // Create a vector orthogonal to 'vec' and of unit length
584ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        ortho.fX = 2.0f * vec.fY;
585ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        ortho.fY = -2.0f * vec.fX;
586ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com
587e27065ae243575f6d5d545909ad3030773c14db8egdaniel        float floatCoverage = GrNormalizeByteToFloat(coverage);
588e27065ae243575f6d5d545909ad3030773c14db8egdaniel
589ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[0].fPos = a;
590e27065ae243575f6d5d545909ad3030773c14db8egdaniel        (*vert)[0].fCoverage = floatCoverage;
591ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[1].fPos = b;
592e27065ae243575f6d5d545909ad3030773c14db8egdaniel        (*vert)[1].fCoverage = floatCoverage;
593ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[2].fPos = a - vec + ortho;
594ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[2].fCoverage = 0;
595ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[3].fPos = b + vec + ortho;
596ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[3].fCoverage = 0;
597ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[4].fPos = a - vec - ortho;
598ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[4].fCoverage = 0;
599ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[5].fPos = b + vec - ortho;
600ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com        (*vert)[5].fCoverage = 0;
601aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
60249f085dddff10473b6ebf832a974288300224e60bsalomon        if (toSrc) {
603dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com            toSrc->mapPointsWithStride(&(*vert)->fPos,
604681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com                                       sizeof(LineVertex),
6055ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt                                       kLineSegNumVertices);
606dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com        }
607aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    } else {
608aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com        // just make it degenerate and likely offscreen
6095ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt        for (int i = 0; i < kLineSegNumVertices; ++i) {
610681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com            (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax);
611681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com        }
612aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
613aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
6145ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt    *vert += kLineSegNumVertices;
615aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
616aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
61790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
61890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
6199853ccef19c200be93a6211f32589fa82a53067cjoshualittbool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target,
6208dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                           const GrPipelineBuilder* pipelineBuilder,
6218059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                           const SkMatrix& viewMatrix,
6229853ccef19c200be93a6211f32589fa82a53067cjoshualitt                                           const SkPath& path,
6231899651ffc459f5462aa989cd6d08507947b67e4kkinnunen                                           const GrStrokeInfo& stroke,
6248a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                           bool antiAlias) const {
625e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org    if (!antiAlias) {
626e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org        return false;
627e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org    }
628e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org
6298059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    if (!IsStrokeHairlineOrEquivalent(stroke, viewMatrix, NULL)) {
630c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return false;
631c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    }
632c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com
633e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    if (SkPath::kLine_SegmentMask == path.getSegmentMasks() ||
634e9c0fc616d2a1632c285885b9b656b68ca8d4f24jvanverth        target->caps()->shaderCaps()->shaderDerivativeSupport()) {
6353f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com        return true;
636c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    }
6373f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com    return false;
638c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com}
639aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
640681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comtemplate <class VertexType>
6418059eb9f6e24ed609393fbda4ad71edea03ac258joshualittbool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* vertices, int vCount)
642681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com{
6431dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    SkRect tolDevBounds = devBounds;
644b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org    // The bounds ought to be tight, but in perspective the below code runs the verts
645b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org    // through the view matrix to get back to dev coords, which can introduce imprecision.
6468059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    if (viewMatrix.hasPerspective()) {
647b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org        tolDevBounds.outset(SK_Scalar1 / 1000, SK_Scalar1 / 1000);
648b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org    } else {
649b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org        // Non-persp matrices cause this path renderer to draw in device space.
6508059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        SkASSERT(viewMatrix.isIdentity());
651b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org    }
6521dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    SkRect actualBounds;
6537475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com
654681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com    VertexType* verts = reinterpret_cast<VertexType*>(vertices);
6551dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    bool first = true;
6561dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    for (int i = 0; i < vCount; ++i) {
6571dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        SkPoint pos = verts[i].fPos;
6581dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        // This is a hack to workaround the fact that we move some degenerate segments offscreen.
6591dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        if (SK_ScalarMax == pos.fX) {
6601dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com            continue;
6611dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        }
6628059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        viewMatrix.mapPoints(&pos, 1);
6631dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        if (first) {
6641dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com            actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY);
6651dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com            first = false;
6661dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        } else {
6671dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com            actualBounds.growToInclude(pos.fX, pos.fY);
6681dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        }
6691dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    }
6701dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    if (!first) {
671681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com        return tolDevBounds.contains(actualBounds);
6721dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    }
6737475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com
674681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com    return true;
675681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com}
6761dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com
6777bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittclass AAHairlineBatch : public GrBatch {
6787bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittpublic:
6797bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    struct Geometry {
6807bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        GrColor fColor;
6817bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        uint8_t fCoverage;
6827bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        SkMatrix fViewMatrix;
6837bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        SkPath fPath;
6847bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        SkIRect fDevClipBounds;
6857bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    };
6867bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
687ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    static GrBatch* Create(const Geometry& geometry) {
688ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        return SkNEW_ARGS(AAHairlineBatch, (geometry));
689658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt    }
690658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt
69136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "AAHairlineBatch"; }
6927bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
69336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
6947bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // When this is called on a batch, there is only one geometry bundle
6957bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        out->setKnownFourComponents(fGeoData[0].fColor);
6967bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    }
69736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
6987bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        out->setUnknownSingleComponent();
6997bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    }
7007bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
70136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void initBatchTracker(const GrPipelineInfo& init) override {
7027bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // Handle any color overrides
7037bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        if (init.fColorIgnored) {
7047bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            fGeoData[0].fColor = GrColor_ILLEGAL;
7057bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
7067bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            fGeoData[0].fColor = init.fOverrideColor;
7077bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        }
7087bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7097bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // setup batch properties
7107bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        fBatch.fColorIgnored = init.fColorIgnored;
7117bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        fBatch.fColor = fGeoData[0].fColor;
7127bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
7137bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        fBatch.fCoverageIgnored = init.fCoverageIgnored;
7147bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        fBatch.fCoverage = fGeoData[0].fCoverage;
7157bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    }
7167bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
71736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override;
7187bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7197bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
7207bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7217bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittprivate:
7227bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    typedef SkTArray<SkPoint, true> PtArray;
7237bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    typedef SkTArray<int, true> IntArray;
7247bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    typedef SkTArray<float, true> FloatArray;
725658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt
726ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    AAHairlineBatch(const Geometry& geometry) {
7277bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        this->initClassID<AAHairlineBatch>();
7287bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        fGeoData.push_back(geometry);
72999c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt
73099c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        // compute bounds
73199c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        fBounds = geometry.fPath.getBounds();
73299c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        geometry.fViewMatrix.mapRect(&fBounds);
7334c977868bbe100d6d95f9e53cf176d611eceb3dcjoshualitt
7344c977868bbe100d6d95f9e53cf176d611eceb3dcjoshualitt        // This is b.c. hairlines are notionally infinitely thin so without expansion
7354c977868bbe100d6d95f9e53cf176d611eceb3dcjoshualitt        // two overlapping lines could be reordered even though they hit the same pixels.
7364c977868bbe100d6d95f9e53cf176d611eceb3dcjoshualitt        fBounds.outset(0.5f, 0.5f);
7377bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    }
7387bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
73936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onCombineIfPossible(GrBatch* t) override {
7407bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        AAHairlineBatch* that = t->cast<AAHairlineBatch>();
7417bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7427bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        if (this->viewMatrix().hasPerspective() != that->viewMatrix().hasPerspective()) {
7437bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            return false;
7447bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        }
7457bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7467bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // We go to identity if we don't have perspective
7477bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        if (this->viewMatrix().hasPerspective() &&
7487bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
7497bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            return false;
7507bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        }
7517bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7527bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // TODO we can actually batch hairlines if they are the same color in a kind of bulk method
7537bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // but we haven't implemented this yet
7547bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // TODO investigate going to vertex color and coverage?
7557bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        if (this->coverage() != that->coverage()) {
7567bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            return false;
7577bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        }
7587bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7597bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        if (this->color() != that->color()) {
7607bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            return false;
7617bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        }
7627bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7637bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
7647bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
7657bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            return false;
7667bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        }
7677bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7687bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
76999c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt        this->joinBounds(that->bounds());
7707bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        return true;
7717bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    }
7727bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7737bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    GrColor color() const { return fBatch.fColor; }
7747bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    uint8_t coverage() const { return fBatch.fCoverage; }
7757bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
7767bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
7777bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7787bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    struct BatchTracker {
7797bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        GrColor fColor;
7807bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        uint8_t fCoverage;
7817bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        SkRect fDevBounds;
7827bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        bool fUsesLocalCoords;
7837bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        bool fColorIgnored;
7847bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        bool fCoverageIgnored;
7857bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    };
7867bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7877bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    BatchTracker fBatch;
7887bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    SkSTArray<1, Geometry, true> fGeoData;
7897bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt};
7907bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7917bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittvoid AAHairlineBatch::generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) {
7927bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    // Setup the viewmatrix and localmatrix for the GrGeometryProcessor.
7937bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    SkMatrix invert;
7947bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    if (!this->viewMatrix().invert(&invert)) {
7957bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        return;
7967bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    }
7977bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
7987bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    // we will transform to identity space if the viewmatrix does not have perspective
7997bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    bool hasPerspective = this->viewMatrix().hasPerspective();
8007bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    const SkMatrix* geometryProcessorViewM = &SkMatrix::I();
8017bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    const SkMatrix* geometryProcessorLocalM = &invert;
8027bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    const SkMatrix* toDevice = NULL;
8037bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    const SkMatrix* toSrc = NULL;
8047bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    if (hasPerspective) {
8057bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        geometryProcessorViewM = &this->viewMatrix();
8067bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        geometryProcessorLocalM = &SkMatrix::I();
8077bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        toDevice = &this->viewMatrix();
8087bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        toSrc = &invert;
8097bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    }
8107bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8117bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    // Setup geometry processors for worst case
8127bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
8137bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                       GrDefaultGeoProcFactory::kCoverage_GPType;
8147bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8157bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    SkAutoTUnref<const GrGeometryProcessor> lineGP(
8167bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            GrDefaultGeoProcFactory::Create(gpFlags,
8177bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                            this->color(),
8187bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                            *geometryProcessorViewM,
8197bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                            *geometryProcessorLocalM,
8207bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                            this->coverage()));
8217bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8227bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    SkAutoTUnref<const GrGeometryProcessor> quadGP(
8237bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            GrQuadEffect::Create(this->color(),
8247bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                 *geometryProcessorViewM,
8257bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                 kHairlineAA_GrProcessorEdgeType,
8267bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                 batchTarget->caps(),
8277bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                 *geometryProcessorLocalM,
8287bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                 this->coverage()));
8297bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8307bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    SkAutoTUnref<const GrGeometryProcessor> conicGP(
8317bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            GrConicEffect::Create(this->color(),
8327bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                  *geometryProcessorViewM,
8337bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                  kHairlineAA_GrProcessorEdgeType,
8347bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                  batchTarget->caps(),
8357bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                  *geometryProcessorLocalM,
8367bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                  this->coverage()));
8377bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8387bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    // This is hand inlined for maximum performance.
83946c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt    PREALLOC_PTARRAY(128) lines;
84046c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt    PREALLOC_PTARRAY(128) quads;
84146c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt    PREALLOC_PTARRAY(128) conics;
84246c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt    IntArray qSubdivs;
84346c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt    FloatArray cWeights;
844351ba1b3218c436089805ebe8e72ad39020229f4joshualitt    int quadCount = 0;
8457bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8467bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    int instanceCount = fGeoData.count();
8477bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    for (int i = 0; i < instanceCount; i++) {
8487bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        const Geometry& args = fGeoData[i];
849351ba1b3218c436089805ebe8e72ad39020229f4joshualitt        quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds,
850351ba1b3218c436089805ebe8e72ad39020229f4joshualitt                                            &lines, &quads, &conics, &qSubdivs, &cWeights);
851658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt    }
852658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt
8537bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    int lineCount = lines.count() / 2;
8547bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    int conicCount = conics.count() / 3;
8557bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
85646c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt    // do lines first
8577bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    if (lineCount) {
858ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        SkAutoTUnref<const GrIndexBuffer> linesIndexBuffer(
859ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            ref_lines_index_buffer(batchTarget->resourceProvider()));
8607bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        batchTarget->initDraw(lineGP, pipeline);
8617bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8627bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // TODO remove this when batch is everywhere
8637bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        GrPipelineInfo init;
8647bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        init.fColorIgnored = fBatch.fColorIgnored;
8657bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        init.fOverrideColor = GrColor_ILLEGAL;
8667bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        init.fCoverageIgnored = fBatch.fCoverageIgnored;
8677bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        init.fUsesLocalCoords = this->usesLocalCoords();
8687bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        lineGP->initBatchTracker(batchTarget->currentBatchTracker(), init);
8697bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8707bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        const GrVertexBuffer* vertexBuffer;
8717bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        int firstVertex;
8727bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8737bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        size_t vertexStride = lineGP->getVertexStride();
8747bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        int vertexCount = kLineSegNumVertices * lineCount;
875e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon        LineVertex* verts = reinterpret_cast<LineVertex*>(
876e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon            batchTarget->makeVertSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex));
8777bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
878e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon        if (!verts|| !linesIndexBuffer) {
8794b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            SkDebugf("Could not allocate vertices\n");
8804b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
8814b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
8824b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
8837bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        SkASSERT(lineGP->getVertexStride() == sizeof(LineVertex));
8847bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
8857bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        for (int i = 0; i < lineCount; ++i) {
8867bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            add_line(&lines[2*i], toSrc, this->coverage(), &verts);
887eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com        }
888aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com
889681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com        {
890e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon            GrVertices vertices;
891e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon            vertices.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer,
892e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                                   firstVertex, kLineSegNumVertices, kIdxsPerLineSeg, lineCount,
893e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                                   kLineSegsNumInIdxBuffer);
894e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon            batchTarget->draw(vertices);
8955383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        }
8965383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    }
8977475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com
8987bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    if (quadCount || conicCount) {
8997bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        const GrVertexBuffer* vertexBuffer;
9007bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        int firstVertex;
9017bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
902ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        SkAutoTUnref<const GrIndexBuffer> quadsIndexBuffer(
903ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon            ref_quads_index_buffer(batchTarget->resourceProvider()));
904ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon
9057bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        size_t vertexStride = sizeof(BezierVertex);
9067bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount;
907e40d39725908d99d255496025411e5c9ca32663erobertphillips        void *vertices = batchTarget->makeVertSpace(vertexStride, vertexCount,
908e40d39725908d99d255496025411e5c9ca32663erobertphillips                                                    &vertexBuffer, &firstVertex);
9097bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
910ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon        if (!vertices || !quadsIndexBuffer) {
9114b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            SkDebugf("Could not allocate vertices\n");
9124b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
9134b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
9144b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
9157bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // Setup vertices
9167bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices);
9177bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
9187bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        int unsubdivQuadCnt = quads.count() / 3;
9197bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        for (int i = 0; i < unsubdivQuadCnt; ++i) {
9207bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            SkASSERT(qSubdivs[i] >= 0);
9217bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
922681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com        }
9237475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com
9247bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        // Start Conics
9257bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        for (int i = 0; i < conicCount; ++i) {
9267bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts);
927681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com        }
9287475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com
9297bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        if (quadCount > 0) {
9307bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            batchTarget->initDraw(quadGP, pipeline);
9317bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
9327bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            // TODO remove this when batch is everywhere
9337bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            GrPipelineInfo init;
9347bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            init.fColorIgnored = fBatch.fColorIgnored;
9357bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            init.fOverrideColor = GrColor_ILLEGAL;
9367bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            init.fCoverageIgnored = fBatch.fCoverageIgnored;
9377bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            init.fUsesLocalCoords = this->usesLocalCoords();
9387bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            quadGP->initBatchTracker(batchTarget->currentBatchTracker(), init);
9397bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
9407bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            {
941e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                GrVertices verts;
942e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                verts.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer,
943e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                                    firstVertex, kQuadNumVertices, kIdxsPerQuad, quadCount,
944e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                                    kQuadsNumInIdxBuffer);
945e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                batchTarget->draw(verts);
946e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                firstVertex += quadCount * kQuadNumVertices;
9477bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt           }
9487bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        }
9497bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
9507bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt        if (conicCount > 0) {
9517bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            batchTarget->initDraw(conicGP, pipeline);
9527bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
9537bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            // TODO remove this when batch is everywhere
9547bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            GrPipelineInfo init;
9557bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            init.fColorIgnored = fBatch.fColorIgnored;
9567bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            init.fOverrideColor = GrColor_ILLEGAL;
9577bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            init.fCoverageIgnored = fBatch.fCoverageIgnored;
9587bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            init.fUsesLocalCoords = this->usesLocalCoords();
9597bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            conicGP->initBatchTracker(batchTarget->currentBatchTracker(), init);
9607bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
9617bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt            {
962e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                GrVertices verts;
963e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                verts.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer,
964e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                                    firstVertex, kQuadNumVertices, kIdxsPerQuad, conicCount,
965e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                                    kQuadsNumInIdxBuffer);
966e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon                batchTarget->draw(verts);
967681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com            }
9685383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com        }
969aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com    }
9707bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt}
9717bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt
97240ded3241894076237844325c015fcc724e9d443joshualittstatic GrBatch* create_hairline_batch(GrColor color,
97340ded3241894076237844325c015fcc724e9d443joshualitt                                      const SkMatrix& viewMatrix,
97440ded3241894076237844325c015fcc724e9d443joshualitt                                      const SkPath& path,
97540ded3241894076237844325c015fcc724e9d443joshualitt                                      const GrStrokeInfo& stroke,
976ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                      const SkIRect& devClipBounds) {
97740ded3241894076237844325c015fcc724e9d443joshualitt    SkScalar hairlineCoverage;
97840ded3241894076237844325c015fcc724e9d443joshualitt    uint8_t newCoverage = 0xff;
97940ded3241894076237844325c015fcc724e9d443joshualitt    if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
98040ded3241894076237844325c015fcc724e9d443joshualitt        newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
98140ded3241894076237844325c015fcc724e9d443joshualitt    }
98240ded3241894076237844325c015fcc724e9d443joshualitt
98340ded3241894076237844325c015fcc724e9d443joshualitt    AAHairlineBatch::Geometry geometry;
98440ded3241894076237844325c015fcc724e9d443joshualitt    geometry.fColor = color;
98540ded3241894076237844325c015fcc724e9d443joshualitt    geometry.fCoverage = newCoverage;
98640ded3241894076237844325c015fcc724e9d443joshualitt    geometry.fViewMatrix = viewMatrix;
98740ded3241894076237844325c015fcc724e9d443joshualitt    geometry.fPath = path;
98840ded3241894076237844325c015fcc724e9d443joshualitt    geometry.fDevClipBounds = devClipBounds;
98940ded3241894076237844325c015fcc724e9d443joshualitt
990ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    return AAHairlineBatch::Create(geometry);
99140ded3241894076237844325c015fcc724e9d443joshualitt}
99240ded3241894076237844325c015fcc724e9d443joshualitt
9937bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittbool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target,
9947bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                          GrPipelineBuilder* pipelineBuilder,
9957bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                          GrColor color,
9967bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                          const SkMatrix& viewMatrix,
9977bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                          const SkPath& path,
9981899651ffc459f5462aa989cd6d08507947b67e4kkinnunen                                          const GrStrokeInfo& stroke,
9997bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt                                          bool) {
10007bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt    SkIRect devClipBounds;
100144701df5ce572ac3cccec785cf52103d3d5d14a5joshualitt    pipelineBuilder->clip().getConservativeBounds(pipelineBuilder->getRenderTarget(),
100244701df5ce572ac3cccec785cf52103d3d5d14a5joshualitt                                                  &devClipBounds);
10037475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com
100440ded3241894076237844325c015fcc724e9d443joshualitt    SkAutoTUnref<GrBatch> batch(create_hairline_batch(color, viewMatrix, path, stroke,
1005ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon                                                      devClipBounds));
100699c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt    target->drawBatch(pipelineBuilder, batch);
10074647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
1008c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    return true;
1009aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}
101040ded3241894076237844325c015fcc724e9d443joshualitt
101140ded3241894076237844325c015fcc724e9d443joshualitt///////////////////////////////////////////////////////////////////////////////////////////////////
101240ded3241894076237844325c015fcc724e9d443joshualitt
101340ded3241894076237844325c015fcc724e9d443joshualitt#ifdef GR_TEST_UTILS
101440ded3241894076237844325c015fcc724e9d443joshualitt
101540ded3241894076237844325c015fcc724e9d443joshualittBATCH_TEST_DEFINE(AAHairlineBatch) {
101640ded3241894076237844325c015fcc724e9d443joshualitt    GrColor color = GrRandomColor(random);
101740ded3241894076237844325c015fcc724e9d443joshualitt    SkMatrix viewMatrix = GrTest::TestMatrix(random);
101840ded3241894076237844325c015fcc724e9d443joshualitt    GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
101940ded3241894076237844325c015fcc724e9d443joshualitt    SkPath path = GrTest::TestPath(random);
102040ded3241894076237844325c015fcc724e9d443joshualitt    SkIRect devClipBounds;
102140ded3241894076237844325c015fcc724e9d443joshualitt    devClipBounds.setEmpty();
1022ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon    return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds);
102340ded3241894076237844325c015fcc724e9d443joshualitt}
102440ded3241894076237844325c015fcc724e9d443joshualitt
102540ded3241894076237844325c015fcc724e9d443joshualitt#endif
1026