GrAAConvexPathRenderer.cpp revision c369e7c9992a86151a3ea0516ce5308c211b196b
169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com/*
369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com * Copyright 2012 Google Inc.
469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com *
569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com * Use of this source code is governed by a BSD-style license that can be
669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com * found in the LICENSE file.
769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com */
869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrAAConvexPathRenderer.h"
1069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
1169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrContext.h"
1269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrDrawState.h"
13c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h"
14b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrProcessor.h"
1569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrPathUtils.h"
16b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrTBackendProcessorFactory.h"
1769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "SkString.h"
185f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStrokeRec.h"
19933e65d914eb86b1fbbf8ea9cf1da58ac7c42500commit-bot@chromium.org#include "SkTraceEvent.h"
2069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
2147bb38283072dc87dc93220cd2f370ca109972ffjoshualitt#include "gl/builders/GrGLProgramBuilder.h"
22b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "gl/GrGLProcessor.h"
2390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "gl/GrGLSL.h"
24249af15fb82833d2274850c589812b6e69df0033joshualitt#include "gl/GrGLGeometryProcessor.h"
254647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
26b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrGeometryProcessor.h"
27234d4fba75aac009e34c088037fcd9e244798c40commit-bot@chromium.org
2869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comGrAAConvexPathRenderer::GrAAConvexPathRenderer() {
2969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
3069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
3169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comstruct Segment {
3269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    enum {
339b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        // These enum values are assumed in member functions below.
349b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        kLine = 0,
359b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        kQuad = 1,
3669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    } fType;
379b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com
389aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // line uses one pt, quad uses 2 pts
39972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint fPts[2];
409aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // normal to edge ending at each pt
41972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkVector fNorms[2];
429aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // is the corner where the previous segment meets this segment
439aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // sharp. If so, fMid is a normalized bisector facing outward.
44972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkVector fMid;
459aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
469aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int countPoints() {
479b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
489b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        return fType + 1;
499aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    }
509aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    const SkPoint& endPt() const {
519b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
529b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        return fPts[fType];
539aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    };
549aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    const SkPoint& endNorm() const {
559b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
569b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        return fNorms[fType];
579aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    };
5869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com};
5969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
6069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comtypedef SkTArray<Segment, true> SegmentArray;
6169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
62fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void center_of_mass(const SegmentArray& segments, SkPoint* c) {
6381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar area = 0;
646390c72cfb3e371a774a627d5f496dc67558e119vandebo@chromium.org    SkPoint center = {0, 0};
659aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int count = segments.count();
666390c72cfb3e371a774a627d5f496dc67558e119vandebo@chromium.org    SkPoint p0 = {0, 0};
675b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com    if (count > 2) {
685b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // We translate the polygon so that the first point is at the origin.
695b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // This avoids some precision issues with small area polygons far away
705b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // from the origin.
715b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        p0 = segments[0].endPt();
725b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        SkPoint pi;
735b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        SkPoint pj;
74a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        // the first and last iteration of the below loop would compute
755b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // zeros since the starting / ending point is (0,0). So instead we start
765b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // at i=1 and make the last iteration i=count-2.
775b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        pj = segments[1].endPt() - p0;
785b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        for (int i = 1; i < count - 1; ++i) {
795b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            pi = pj;
805b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            const SkPoint pj = segments[i + 1].endPt() - p0;
815b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com
8281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalar t = SkScalarMul(pi.fX, pj.fY) - SkScalarMul(pj.fX, pi.fY);
835b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            area += t;
845b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            center.fX += (pi.fX + pj.fX) * t;
855b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            center.fY += (pi.fY + pj.fY) * t;
865b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com
875b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        }
889aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    }
89278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    // If the poly has no area then we instead return the average of
90278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    // its points.
915b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com    if (SkScalarNearlyZero(area)) {
92278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        SkPoint avg;
93278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        avg.set(0, 0);
94278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        for (int i = 0; i < count; ++i) {
95278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com            const SkPoint& pt = segments[i].endPt();
96278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com            avg.fX += pt.fX;
97278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com            avg.fY += pt.fY;
98278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        }
99278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        SkScalar denom = SK_Scalar1 / count;
100278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        avg.scale(denom);
101278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        *c = avg;
102278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    } else {
103278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        area *= 3;
10481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        area = SkScalarDiv(SK_Scalar1, area);
10581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        center.fX = SkScalarMul(center.fX, area);
10681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        center.fY = SkScalarMul(center.fY, area);
1075b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // undo the translate of p0 to the origin.
1085b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        *c = center + p0;
109278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    }
110f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
1119aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com}
1129aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
113fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void compute_vectors(SegmentArray* segments,
114fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            SkPoint* fanPt,
115fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            SkPath::Direction dir,
116fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            int* vCount,
117fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            int* iCount) {
1189aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    center_of_mass(*segments, fanPt);
1199aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int count = segments->count();
1209aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
121278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    // Make the normals point towards the outside
122972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint::Side normSide;
123278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    if (dir == SkPath::kCCW_Direction) {
124972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org        normSide = SkPoint::kRight_Side;
125278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    } else {
126972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org        normSide = SkPoint::kLeft_Side;
127278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    }
1289aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
1299aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    *vCount = 0;
1309aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    *iCount = 0;
1319aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // compute normals at all points
1329aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    for (int a = 0; a < count; ++a) {
1337d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        Segment& sega = (*segments)[a];
1349aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        int b = (a + 1) % count;
1359aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        Segment& segb = (*segments)[b];
1369aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
137972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org        const SkPoint* prevPt = &sega.endPt();
1389aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        int n = segb.countPoints();
1399aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        for (int p = 0; p < n; ++p) {
1409aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            segb.fNorms[p] = segb.fPts[p] - *prevPt;
1419aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            segb.fNorms[p].normalize();
1429aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
1439aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            prevPt = &segb.fPts[p];
1449aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        }
1459aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        if (Segment::kLine == segb.fType) {
1469aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            *vCount += 5;
1479aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            *iCount += 9;
1489aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        } else {
1499aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            *vCount += 6;
1509aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            *iCount += 12;
1519aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        }
1529aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    }
1539aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
1549aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // compute mid-vectors where segments meet. TODO: Detect shallow corners
1559aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // and leave out the wedges and close gaps by stitching segments together.
1569aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    for (int a = 0; a < count; ++a) {
1579aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        const Segment& sega = (*segments)[a];
1589aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        int b = (a + 1) % count;
1599aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        Segment& segb = (*segments)[b];
1609aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        segb.fMid = segb.fNorms[0] + sega.endNorm();
1619aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        segb.fMid.normalize();
1629aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        // corner wedges
1639aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        *vCount += 4;
1649aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        *iCount += 6;
1659aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    }
1669aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com}
1679aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
1689732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.comstruct DegenerateTestData {
1699732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    DegenerateTestData() { fStage = kInitial; }
1709732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    bool isDegenerate() const { return kNonDegenerate != fStage; }
1719732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    enum {
1729732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        kInitial,
1739732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        kPoint,
1749732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        kLine,
1759732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        kNonDegenerate
1769732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    }           fStage;
177972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint     fFirstPoint;
178972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkVector    fLineNormal;
17981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar    fLineC;
1809732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com};
1819732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com
182fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic const SkScalar kClose = (SK_Scalar1 / 16);
183fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
1849732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com
185972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgstatic void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
1869732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    switch (data->fStage) {
1879732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        case DegenerateTestData::kInitial:
1889732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            data->fFirstPoint = pt;
1899732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            data->fStage = DegenerateTestData::kPoint;
1909732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            break;
1919732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        case DegenerateTestData::kPoint:
192fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org            if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
1939732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fLineNormal = pt - data->fFirstPoint;
1949732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fLineNormal.normalize();
1959732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fLineNormal.setOrthog(data->fLineNormal);
1969732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
1979732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fStage = DegenerateTestData::kLine;
1989732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            }
1999732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            break;
2009732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        case DegenerateTestData::kLine:
201fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org            if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
2029732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fStage = DegenerateTestData::kNonDegenerate;
2039732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            }
2049732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        case DegenerateTestData::kNonDegenerate:
2059732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            break;
2069732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        default:
20788cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org            SkFAIL("Unexpected degenerate test stage.");
2089732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    }
2099732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com}
2109732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com
211fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) {
212a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    if (!path.cheapComputeDirection(dir)) {
213a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        return false;
214a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
215af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    // check whether m reverses the orientation
216f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(!m.hasPerspective());
21781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
21881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                      SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
219af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    if (det2x2 < 0) {
22030c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com        *dir = SkPath::OppositeDirection(*dir);
221af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    }
222a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    return true;
223af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com}
224af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com
225106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.orgstatic inline void add_line_to_segment(const SkPoint& pt,
226106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                                       SegmentArray* segments,
227106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                                       SkRect* devBounds) {
228fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    segments->push_back();
229fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    segments->back().fType = Segment::kLine;
230fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    segments->back().fPts[0] = pt;
231106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org    devBounds->growToInclude(pt.fX, pt.fY);
232fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org}
233fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org
2344b7d6730898abc9e02d1e12c2fd732945f4c1ab4commit-bot@chromium.org#ifdef SK_DEBUG
235106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.orgstatic inline bool contains_inclusive(const SkRect& rect, const SkPoint& p) {
236106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org    return p.fX >= rect.fLeft && p.fX <= rect.fRight && p.fY >= rect.fTop && p.fY <= rect.fBottom;
237106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org}
2384b7d6730898abc9e02d1e12c2fd732945f4c1ab4commit-bot@chromium.org#endif
2394b7d6730898abc9e02d1e12c2fd732945f4c1ab4commit-bot@chromium.org
240106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.orgstatic inline void add_quad_segment(const SkPoint pts[3],
241106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                                    SegmentArray* segments,
242106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                                    SkRect* devBounds) {
243fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
244fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        if (pts[0] != pts[2]) {
245106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org            add_line_to_segment(pts[2], segments, devBounds);
246fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        }
247fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    } else {
248fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        segments->push_back();
249fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        segments->back().fType = Segment::kQuad;
250fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        segments->back().fPts[0] = pts[1];
251fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        segments->back().fPts[1] = pts[2];
252106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org        SkASSERT(contains_inclusive(*devBounds, pts[0]));
253106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org        devBounds->growToInclude(pts + 1, 2);
254fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    }
255fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org}
256fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org
257fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic inline void add_cubic_segments(const SkPoint pts[4],
258fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                                      SkPath::Direction dir,
259106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                                      SegmentArray* segments,
260106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                                      SkRect* devBounds) {
261fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    SkSTArray<15, SkPoint, true> quads;
262fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
263fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    int count = quads.count();
264fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    for (int q = 0; q < count; q += 3) {
265106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org        add_quad_segment(&quads[q], segments, devBounds);
266fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    }
267fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org}
268fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org
269fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic bool get_segments(const SkPath& path,
270fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         const SkMatrix& m,
271fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         SegmentArray* segments,
272fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         SkPoint* fanPt,
273fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         int* vCount,
274106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                         int* iCount,
275106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                         SkRect* devBounds) {
27669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    SkPath::Iter iter(path, true);
27730c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com    // This renderer over-emphasizes very thin path regions. We use the distance
2785cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // to the path from the sample to compute coverage. Every pixel intersected
2795cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
280fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    // notice that the sample may be close to a very thin area of the path and
2815cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // thus should be very light. This is particularly egregious for degenerate
2825cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // line paths. We detect paths that are very close to a line (zero area) and
2835cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // draw nothing.
2849732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    DegenerateTestData degenerateData;
285a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkPath::Direction dir;
286a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    // get_direction can fail for some degenerate paths.
287a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    if (!get_direction(path, m, &dir)) {
288a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        return false;
289a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
2909732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com
29169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    for (;;) {
292972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org        SkPoint pts[4];
29394b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        SkPath::Verb verb = iter.next(pts);
29494b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        switch (verb) {
29594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kMove_Verb:
2961a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com                m.mapPoints(pts, 1);
2979732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[0]);
298106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                devBounds->set(pts->fX, pts->fY, pts->fX, pts->fY);
2999732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                break;
30094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kLine_Verb: {
301fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                m.mapPoints(&pts[1], 1);
3021a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com                update_degenerate_test(&degenerateData, pts[1]);
303106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                add_line_to_segment(pts[1], segments, devBounds);
30469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                break;
30569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            }
30694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kQuad_Verb:
307fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                m.mapPoints(pts, 3);
3089732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[1]);
3099732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[2]);
310106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                add_quad_segment(pts, segments, devBounds);
31169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                break;
31294b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kCubic_Verb: {
3131a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com                m.mapPoints(pts, 4);
3149732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[1]);
3159732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[2]);
3169732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[3]);
317106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org                add_cubic_segments(pts, dir, segments, devBounds);
31869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                break;
31969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            };
32094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kDone_Verb:
3219732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                if (degenerateData.isDegenerate()) {
3229732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                    return false;
3239732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                } else {
324278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com                    compute_vectors(segments, fanPt, dir, vCount, iCount);
3259732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                    return true;
3269732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                }
32769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            default:
32869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                break;
32969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        }
33069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
33169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
33269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
33369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comstruct QuadVertex {
334972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fPos;
335972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint  fUV;
33681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar fD0;
33781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar fD1;
33869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com};
339fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3407d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.comstruct Draw {
3417d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    Draw() : fVertexCnt(0), fIndexCnt(0) {}
3427d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int fVertexCnt;
3437d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int fIndexCnt;
3447d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com};
3457d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
3467d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.comtypedef SkTArray<Draw, true> DrawArray;
3477d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
348fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void create_vertices(const SegmentArray&  segments,
349fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            const SkPoint& fanPt,
350fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            DrawArray*     draws,
351fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            QuadVertex*    verts,
352fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            uint16_t*      idxs) {
3537d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    Draw* draw = &draws->push_back();
3547d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    // alias just to make vert/index assignments easier to read.
3557d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int* v = &draw->fVertexCnt;
3567d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int* i = &draw->fIndexCnt;
35769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
3589aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int count = segments.count();
3599aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    for (int a = 0; a < count; ++a) {
3609aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        const Segment& sega = segments[a];
3619aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        int b = (a + 1) % count;
3629aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        const Segment& segb = segments[b];
363fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3647d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        // Check whether adding the verts for this segment to the current draw would cause index
3657d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        // values to overflow.
3667d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        int vCount = 4;
3677d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        if (Segment::kLine == segb.fType) {
3687d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            vCount += 5;
3697d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        } else {
3707d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            vCount += 6;
3717d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        }
3727d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        if (draw->fVertexCnt + vCount > (1 << 16)) {
3737d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts += *v;
3747d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs += *i;
3757d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            draw = &draws->push_back();
3767d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            v = &draw->fVertexCnt;
3777d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            i = &draw->fIndexCnt;
3787d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        }
3797d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
3809aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        // FIXME: These tris are inset in the 1 unit arc around the corner
3817d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 0].fPos = sega.endPt();
3827d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm();
3837d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid;
3847d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0];
3857d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 0].fUV.set(0,0);
3867d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 1].fUV.set(0,-SK_Scalar1);
3877d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 2].fUV.set(0,-SK_Scalar1);
3887d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 3].fUV.set(0,-SK_Scalar1);
3897d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
3907d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
3917d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
3927d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
3937d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
3947d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 0] = *v + 0;
3957d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 1] = *v + 2;
3967d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 2] = *v + 1;
3977d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 3] = *v + 0;
3987d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 4] = *v + 3;
3997d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 5] = *v + 2;
4007d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4017d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        *v += 4;
4027d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        *i += 6;
40369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
4049aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        if (Segment::kLine == segb.fType) {
4057d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fPos = fanPt;
4067d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fPos = sega.endPt();
4077d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fPos = segb.fPts[0];
4089aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4097d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
4107d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
4119aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4129aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            // we draw the line edge as a degenerate quad (u is 0, v is the
4139aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            // signed distance to the edge)
4147d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos,
4157d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com                                                        verts[*v + 2].fPos);
4167d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fUV.set(0, dist);
4177d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fUV.set(0, 0);
4187d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fUV.set(0, 0);
4197d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fUV.set(0, -SK_Scalar1);
4207d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fUV.set(0, -SK_Scalar1);
4217d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4227d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
4237d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
4247d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
4257d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
4267d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1;
4277d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4287d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 0] = *v + 0;
4297d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 1] = *v + 2;
4307d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 2] = *v + 1;
4317d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4327d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 3] = *v + 3;
4337d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 4] = *v + 1;
4347d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 5] = *v + 2;
4357d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4367d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 6] = *v + 4;
4377d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 7] = *v + 3;
4387d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 8] = *v + 2;
4397d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4407d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            *v += 5;
4417d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            *i += 9;
442068096148179062c4343138c112b87518e4ab3b1bsalomon@google.com        } else {
443972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
4449aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
445972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            SkVector midVec = segb.fNorms[0] + segb.fNorms[1];
4469aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            midVec.normalize();
4479aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4487d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fPos = fanPt;
4497d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fPos = qpts[0];
4507d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fPos = qpts[2];
4517d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fPos = qpts[0] + segb.fNorms[0];
4527d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fPos = qpts[2] + segb.fNorms[1];
4537d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 5].fPos = qpts[1] + midVec;
4549aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
45581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalar c = segb.fNorms[0].dot(qpts[0]);
4567d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fD0 =  -segb.fNorms[0].dot(fanPt) + c;
4577d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fD0 =  0.f;
4587d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fD0 =  -segb.fNorms[0].dot(qpts[2]) + c;
4597d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fD0 = -SK_ScalarMax/100;
4607d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fD0 = -SK_ScalarMax/100;
4617d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 5].fD0 = -SK_ScalarMax/100;
4629aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4639aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            c = segb.fNorms[1].dot(qpts[2]);
4647d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fD1 =  -segb.fNorms[1].dot(fanPt) + c;
4657d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fD1 =  -segb.fNorms[1].dot(qpts[0]) + c;
4667d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fD1 =  0.f;
4677d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fD1 = -SK_ScalarMax/100;
4687d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fD1 = -SK_ScalarMax/100;
4697d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 5].fD1 = -SK_ScalarMax/100;
4709aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4711971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            GrPathUtils::QuadUVMatrix toUV(qpts);
472972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            toUV.apply<6, sizeof(QuadVertex), sizeof(SkPoint)>(verts + *v);
4739aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4747d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 0] = *v + 3;
4757d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 1] = *v + 1;
4767d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 2] = *v + 2;
4777d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 3] = *v + 4;
4787d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 4] = *v + 3;
4797d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 5] = *v + 2;
4809aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4817d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 6] = *v + 5;
4827d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 7] = *v + 3;
4837d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 8] = *v + 4;
4849aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4857d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i +  9] = *v + 0;
4867d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 10] = *v + 2;
4877d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 11] = *v + 1;
4889aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4897d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            *v += 6;
4907d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            *i += 12;
49169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        }
49269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
49369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
49469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
49590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
49690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
49790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/*
49890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
49990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * two components of the vertex attribute. Coverage is based on signed
50090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * distance with negative being inside, positive outside. The edge is specified in
50190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * window space (y-down). If either the third or fourth component of the interpolated
50290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
503041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * attempt to trim to a portion of the infinite quad.
504041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * Requires shader derivative instruction support.
50590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */
50690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
507249af15fb82833d2274850c589812b6e69df0033joshualittclass QuadEdgeEffect : public GrGeometryProcessor {
50890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic:
50990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
510b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static GrGeometryProcessor* Create() {
51198b33ebe6f66ed59b023cf16a09c0a40eb4510cebsalomon        GR_CREATE_STATIC_PROCESSOR(gQuadEdgeEffect, QuadEdgeEffect, ());
512d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com        gQuadEdgeEffect->ref();
513d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com        return gQuadEdgeEffect;
51490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
51590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
51690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    virtual ~QuadEdgeEffect() {}
51790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
51890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    static const char* Name() { return "QuadEdge"; }
51990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
520249af15fb82833d2274850c589812b6e69df0033joshualitt    const GrShaderVar& inQuadEdge() const { return fInQuadEdge; }
521249af15fb82833d2274850c589812b6e69df0033joshualitt
522b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
523b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        return GrTBackendGeometryProcessorFactory<QuadEdgeEffect>::getInstance();
52490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
52590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
526b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    class GLProcessor : public GrGLGeometryProcessor {
52790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    public:
528b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
52990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            : INHERITED (factory) {}
53090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
531c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt        virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
53290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            const char *vsName, *fsName;
533c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt            args.fPB->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
53490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
535c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt            GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
53630ba436f04e61d4505fb854d5fc56079636e0788joshualitt
53730ba436f04e61d4505fb854d5fc56079636e0788joshualitt            SkAssertResult(fsBuilder->enableFeature(
53830ba436f04e61d4505fb854d5fc56079636e0788joshualitt                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
53930ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\tfloat edgeAlpha;\n");
54030ba436f04e61d4505fb854d5fc56079636e0788joshualitt
54190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            // keep the derivative instructions outside the conditional
54230ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
54330ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
54430ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
54590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            // today we know z and w are in device space. We could use derivatives
54630ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
54790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                    fsName);
54830ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf ("\t\t} else {\n");
54930ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
55090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                   "\t\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
55190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                   fsName, fsName);
55230ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
55390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                    fsName);
55430ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\t\tedgeAlpha = "
55590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                   "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n\t\t}\n");
55690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
557824c346b6e0e114063c1a8ad4ba7c3a669ee2cffcommit-bot@chromium.org
558c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt            fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
559c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt                                   (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("edgeAlpha")).c_str());
56090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
561c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt            const GrShaderVar& inQuadEdge = args.fGP.cast<QuadEdgeEffect>().inQuadEdge();
562c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt            GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
563249af15fb82833d2274850c589812b6e69df0033joshualitt            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, inQuadEdge.c_str());
56490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
56590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
566b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
56790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
568b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
56990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
57090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    private:
571249af15fb82833d2274850c589812b6e69df0033joshualitt        typedef GrGLGeometryProcessor INHERITED;
57290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    };
573041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com
57490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate:
575249af15fb82833d2274850c589812b6e69df0033joshualitt    QuadEdgeEffect()
576249af15fb82833d2274850c589812b6e69df0033joshualitt        : fInQuadEdge(this->addVertexAttrib(GrShaderVar("inQuadEdge",
577249af15fb82833d2274850c589812b6e69df0033joshualitt                                                        kVec4f_GrSLType,
578249af15fb82833d2274850c589812b6e69df0033joshualitt                                                        GrShaderVar::kAttribute_TypeModifier))) {
57990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
58090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
5810e08fc17e4718f7ce4e38f793695896473e96948bsalomon    virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE {
58290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        return true;
58390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
58490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
5851a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel    virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
586ccb2e384a036f29d989d3c1468f879324e81a678egdaniel        inout->mulByUnknownAlpha();
5871a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel    }
5881a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel
589249af15fb82833d2274850c589812b6e69df0033joshualitt    const GrShaderVar& fInQuadEdge;
590249af15fb82833d2274850c589812b6e69df0033joshualitt
591b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
59290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
593b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrFragmentProcessor INHERITED;
59490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org};
59590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
596b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect);
59790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
598b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrGeometryProcessor* QuadEdgeEffect::TestCreate(SkRandom* random,
599b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                GrContext*,
600b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                const GrDrawTargetCaps& caps,
601b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                GrTexture*[]) {
60290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    // Doesn't work without derivative instructions.
60390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    return caps.shaderDerivativeSupport() ? QuadEdgeEffect::Create() : NULL;
60490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}
60590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
60690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
60790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
608e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.combool GrAAConvexPathRenderer::canDrawPath(const SkPath& path,
609e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                                         const SkStrokeRec& stroke,
6108a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                         const GrDrawTarget* target,
6118a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                         bool antiAlias) const {
612bcce8926524827775539874346dd424a9510dbc9bsalomon@google.com    return (target->caps()->shaderDerivativeSupport() && antiAlias &&
613e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            stroke.isFillStyle() && !path.isInverseFillType() && path.isConvex());
614c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com}
615c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com
616429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.comnamespace {
617429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com
618429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com// position + edge
619429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.comextern const GrVertexAttrib gPathAttribs[] = {
620429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com    {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
621b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    {kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
622429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com};
623429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com
624429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com};
625429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com
626e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.combool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
627e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                                        const SkStrokeRec&,
628c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                                        GrDrawTarget* target,
629c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                                        bool antiAlias) {
630c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com
631e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    const SkPath* path = &origPath;
632af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    if (path->isEmpty()) {
633c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return true;
63469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
6354647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
636137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    SkMatrix viewMatrix = target->getDrawState().getViewMatrix();
637137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawTarget::AutoStateRestore asr;
638137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
639e3d3216fe17b6afb2e613271b5246a2766e12df6bsalomon@google.com        return false;
64069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
641137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawState* drawState = target->drawState();
64269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
643af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    // We use the fact that SkPath::transform path does subdivision based on
644af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    // perspective. Otherwise, we apply the view matrix when copying to the
645af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    // segment representation.
646af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    SkPath tmpPath;
647137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    if (viewMatrix.hasPerspective()) {
648e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com        origPath.transform(viewMatrix, &tmpPath);
649af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com        path = &tmpPath;
650137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        viewMatrix = SkMatrix::I();
651af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    }
652af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com
65369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    QuadVertex *verts;
65469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    uint16_t* idxs;
65569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
6569aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int vCount;
6579aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int iCount;
65868a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com    enum {
65968a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com        kPreallocSegmentCnt = 512 / sizeof(Segment),
6607d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        kPreallocDrawCnt = 4,
66168a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com    };
66268a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com    SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
6639aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    SkPoint fanPt;
664af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com
665106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org    // We can't simply use the path bounds because we may degenerate cubics to quads which produces
666106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org    // new control points outside the original convex hull.
667106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org    SkRect devBounds;
668106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org    if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount, &devBounds)) {
669c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return false;
67069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
67169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
672106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org    // Our computed verts should all be within one pixel of the segment control points.
673106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org    devBounds.outset(SK_Scalar1, SK_Scalar1);
674106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org
6757b3d5ee72c2238aa239bce4d5b3aea98a437ca7aegdaniel    drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs), sizeof(QuadVertex));
6764647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
677b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrGeometryProcessor* quadProcessor = QuadEdgeEffect::Create();
678b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    drawState->setGeometryProcessor(quadProcessor)->unref();
6794647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
680b75b0a0b8492e14c7728e0a0881f87dc64ce60f9jvanverth@google.com    GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount);
681b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com    if (!arg.succeeded()) {
682c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return false;
68369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
684b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com    verts = reinterpret_cast<QuadVertex*>(arg.vertices());
685b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com    idxs = reinterpret_cast<uint16_t*>(arg.indices());
68669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
6877d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    SkSTArray<kPreallocDrawCnt, Draw, true> draws;
6887d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    create_vertices(segments, fanPt, &draws, verts, idxs);
6897d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
6901dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    // Check devBounds
691515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
6921dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    SkRect tolDevBounds = devBounds;
6931dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
6941dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    SkRect actualBounds;
6951dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    actualBounds.set(verts[0].fPos, verts[1].fPos);
6961dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    for (int i = 2; i < vCount; ++i) {
6971dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        actualBounds.growToInclude(verts[i].fPos.fX, verts[i].fPos.fY);
6981dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    }
699f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(tolDevBounds.contains(actualBounds));
7001dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com#endif
7011dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com
7027d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int vOffset = 0;
7037d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    for (int i = 0; i < draws.count(); ++i) {
7047d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        const Draw& draw = draws[i];
7057d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        target->drawIndexed(kTriangles_GrPrimitiveType,
7067d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com                            vOffset,  // start vertex
7077d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com                            0,        // start index
7087d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com                            draw.fVertexCnt,
7091dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com                            draw.fIndexCnt,
7101dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com                            &devBounds);
7117d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        vOffset += draw.fVertexCnt;
7127d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    }
713a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com
714c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    return true;
71569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
716