GrAAConvexPathRenderer.cpp revision 515dcd36032997ce335daa0163c6d67e851bcad1
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"
1490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "GrEffect.h"
1569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrPathUtils.h"
1690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "GrTBackendEffectFactory.h"
1769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "SkString.h"
185f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStrokeRec.h"
1969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "SkTrace.h"
2069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
2190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "gl/GrGLEffect.h"
2290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "gl/GrGLSL.h"
234647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
2469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comGrAAConvexPathRenderer::GrAAConvexPathRenderer() {
2569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
2669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
2769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comstruct Segment {
2869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    enum {
299b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        // These enum values are assumed in member functions below.
309b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        kLine = 0,
319b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        kQuad = 1,
3269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    } fType;
339b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com
349aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // line uses one pt, quad uses 2 pts
359aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    GrPoint fPts[2];
369aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // normal to edge ending at each pt
379aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    GrVec fNorms[2];
389aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // is the corner where the previous segment meets this segment
399aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // sharp. If so, fMid is a normalized bisector facing outward.
409aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    GrVec fMid;
419aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
429aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int countPoints() {
439b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
449b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        return fType + 1;
459aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    }
469aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    const SkPoint& endPt() const {
479b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
489b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        return fPts[fType];
499aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    };
509aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    const SkPoint& endNorm() const {
519b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
529b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com        return fNorms[fType];
539aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    };
5469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com};
5569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
5669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comtypedef SkTArray<Segment, true> SegmentArray;
5769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
58fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void center_of_mass(const SegmentArray& segments, SkPoint* c) {
5981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar area = 0;
606390c72cfb3e371a774a627d5f496dc67558e119vandebo@chromium.org    SkPoint center = {0, 0};
619aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int count = segments.count();
626390c72cfb3e371a774a627d5f496dc67558e119vandebo@chromium.org    SkPoint p0 = {0, 0};
635b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com    if (count > 2) {
645b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // We translate the polygon so that the first point is at the origin.
655b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // This avoids some precision issues with small area polygons far away
665b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // from the origin.
675b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        p0 = segments[0].endPt();
685b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        SkPoint pi;
695b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        SkPoint pj;
70a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        // the first and last iteration of the below loop would compute
715b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // zeros since the starting / ending point is (0,0). So instead we start
725b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // at i=1 and make the last iteration i=count-2.
735b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        pj = segments[1].endPt() - p0;
745b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        for (int i = 1; i < count - 1; ++i) {
755b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            pi = pj;
765b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            const SkPoint pj = segments[i + 1].endPt() - p0;
775b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com
7881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalar t = SkScalarMul(pi.fX, pj.fY) - SkScalarMul(pj.fX, pi.fY);
795b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            area += t;
805b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            center.fX += (pi.fX + pj.fX) * t;
815b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com            center.fY += (pi.fY + pj.fY) * t;
825b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com
835b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        }
849aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    }
85278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    // If the poly has no area then we instead return the average of
86278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    // its points.
875b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com    if (SkScalarNearlyZero(area)) {
88278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        SkPoint avg;
89278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        avg.set(0, 0);
90278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        for (int i = 0; i < count; ++i) {
91278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com            const SkPoint& pt = segments[i].endPt();
92278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com            avg.fX += pt.fX;
93278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com            avg.fY += pt.fY;
94278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        }
95278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        SkScalar denom = SK_Scalar1 / count;
96278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        avg.scale(denom);
97278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        *c = avg;
98278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    } else {
99278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        area *= 3;
10081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        area = SkScalarDiv(SK_Scalar1, area);
10181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        center.fX = SkScalarMul(center.fX, area);
10281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        center.fY = SkScalarMul(center.fY, area);
1035b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        // undo the translate of p0 to the origin.
1045b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com        *c = center + p0;
105278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    }
106f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
1079aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com}
1089aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
109fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void compute_vectors(SegmentArray* segments,
110fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            SkPoint* fanPt,
111fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            SkPath::Direction dir,
112fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            int* vCount,
113fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            int* iCount) {
1149aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    center_of_mass(*segments, fanPt);
1159aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int count = segments->count();
1169aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
117278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    // Make the normals point towards the outside
1189aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    GrPoint::Side normSide;
119278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    if (dir == SkPath::kCCW_Direction) {
120278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        normSide = GrPoint::kRight_Side;
121278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    } else {
122278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com        normSide = GrPoint::kLeft_Side;
123278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com    }
1249aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
1259aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    *vCount = 0;
1269aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    *iCount = 0;
1279aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // compute normals at all points
1289aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    for (int a = 0; a < count; ++a) {
1297d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        Segment& sega = (*segments)[a];
1309aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        int b = (a + 1) % count;
1319aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        Segment& segb = (*segments)[b];
1329aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
1339aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        const GrPoint* prevPt = &sega.endPt();
1349aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        int n = segb.countPoints();
1359aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        for (int p = 0; p < n; ++p) {
1369aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            segb.fNorms[p] = segb.fPts[p] - *prevPt;
1379aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            segb.fNorms[p].normalize();
1389aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
1399aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            prevPt = &segb.fPts[p];
1409aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        }
1419aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        if (Segment::kLine == segb.fType) {
1429aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            *vCount += 5;
1439aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            *iCount += 9;
1449aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        } else {
1459aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            *vCount += 6;
1469aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            *iCount += 12;
1479aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        }
1489aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    }
1499aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
1509aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // compute mid-vectors where segments meet. TODO: Detect shallow corners
1519aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    // and leave out the wedges and close gaps by stitching segments together.
1529aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    for (int a = 0; a < count; ++a) {
1539aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        const Segment& sega = (*segments)[a];
1549aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        int b = (a + 1) % count;
1559aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        Segment& segb = (*segments)[b];
1569aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        segb.fMid = segb.fNorms[0] + sega.endNorm();
1579aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        segb.fMid.normalize();
1589aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        // corner wedges
1599aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        *vCount += 4;
1609aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        *iCount += 6;
1619aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    }
1629aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com}
1639aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
1649732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.comstruct DegenerateTestData {
1659732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    DegenerateTestData() { fStage = kInitial; }
1669732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    bool isDegenerate() const { return kNonDegenerate != fStage; }
1679732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    enum {
1689732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        kInitial,
1699732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        kPoint,
1709732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        kLine,
1719732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        kNonDegenerate
1729732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    }           fStage;
1739732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    GrPoint     fFirstPoint;
1749732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    GrVec       fLineNormal;
17581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar    fLineC;
1769732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com};
1779732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com
178fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic const SkScalar kClose = (SK_Scalar1 / 16);
179fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
1809732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com
181fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void update_degenerate_test(DegenerateTestData* data, const GrPoint& pt) {
1829732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    switch (data->fStage) {
1839732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        case DegenerateTestData::kInitial:
1849732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            data->fFirstPoint = pt;
1859732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            data->fStage = DegenerateTestData::kPoint;
1869732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            break;
1879732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        case DegenerateTestData::kPoint:
188fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org            if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
1899732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fLineNormal = pt - data->fFirstPoint;
1909732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fLineNormal.normalize();
1919732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fLineNormal.setOrthog(data->fLineNormal);
1929732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
1939732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fStage = DegenerateTestData::kLine;
1949732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            }
1959732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            break;
1969732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        case DegenerateTestData::kLine:
197fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org            if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
1989732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                data->fStage = DegenerateTestData::kNonDegenerate;
1999732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            }
2009732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        case DegenerateTestData::kNonDegenerate:
2019732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            break;
2029732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com        default:
2039732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com            GrCrash("Unexpected degenerate test stage.");
2049732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    }
2059732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com}
2069732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com
207fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) {
208a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    if (!path.cheapComputeDirection(dir)) {
209a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        return false;
210a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
211af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    // check whether m reverses the orientation
212f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(!m.hasPerspective());
21381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
21481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                      SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
215af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    if (det2x2 < 0) {
21630c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com        *dir = SkPath::OppositeDirection(*dir);
217af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    }
218a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    return true;
219af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com}
220af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com
221fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic inline void add_line_to_segment(const SkPoint& pt, SegmentArray* segments) {
222fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    segments->push_back();
223fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    segments->back().fType = Segment::kLine;
224fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    segments->back().fPts[0] = pt;
225fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org}
226fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org
227fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic inline void add_quad_segment(const SkPoint pts[3], SegmentArray* segments) {
228fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
229fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        if (pts[0] != pts[2]) {
230fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org            add_line_to_segment(pts[2], segments);
231fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        }
232fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    } else {
233fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        segments->push_back();
234fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        segments->back().fType = Segment::kQuad;
235fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        segments->back().fPts[0] = pts[1];
236fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        segments->back().fPts[1] = pts[2];
237fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    }
238fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org}
239fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org
240fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic inline void add_cubic_segments(const SkPoint pts[4],
241fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                                      SkPath::Direction dir,
242fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                                      SegmentArray* segments) {
243fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    SkSTArray<15, SkPoint, true> quads;
244fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
245fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    int count = quads.count();
246fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    for (int q = 0; q < count; q += 3) {
247fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org        add_quad_segment(&quads[q], segments);
248fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org    }
249fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org}
250fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org
251fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic bool get_segments(const SkPath& path,
252fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         const SkMatrix& m,
253fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         SegmentArray* segments,
254fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         SkPoint* fanPt,
255fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         int* vCount,
256fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                         int* iCount) {
25769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    SkPath::Iter iter(path, true);
25830c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com    // This renderer over-emphasizes very thin path regions. We use the distance
2595cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // to the path from the sample to compute coverage. Every pixel intersected
2605cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
261fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    // notice that the sample may be close to a very thin area of the path and
2625cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // thus should be very light. This is particularly egregious for degenerate
2635cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // line paths. We detect paths that are very close to a line (zero area) and
2645cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com    // draw nothing.
2659732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com    DegenerateTestData degenerateData;
266a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkPath::Direction dir;
267a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    // get_direction can fail for some degenerate paths.
268a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    if (!get_direction(path, m, &dir)) {
269a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        return false;
270a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
2719732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com
27269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    for (;;) {
27369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        GrPoint pts[4];
27494b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        SkPath::Verb verb = iter.next(pts);
27594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        switch (verb) {
27694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kMove_Verb:
2771a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com                m.mapPoints(pts, 1);
2789732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[0]);
2799732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                break;
28094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kLine_Verb: {
281fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                m.mapPoints(&pts[1], 1);
2821a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com                update_degenerate_test(&degenerateData, pts[1]);
283fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                add_line_to_segment(pts[1], segments);
28469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                break;
28569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            }
28694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kQuad_Verb:
287fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                m.mapPoints(pts, 3);
2889732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[1]);
2899732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[2]);
290fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                add_quad_segment(pts, segments);
29169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                break;
29294b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kCubic_Verb: {
2931a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com                m.mapPoints(pts, 4);
2949732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[1]);
2959732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[2]);
2969732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                update_degenerate_test(&degenerateData, pts[3]);
297fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                add_cubic_segments(pts, dir, segments);
29869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                break;
29969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            };
30094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kDone_Verb:
3019732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                if (degenerateData.isDegenerate()) {
3029732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                    return false;
3039732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                } else {
304278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com                    compute_vectors(segments, fanPt, dir, vCount, iCount);
3059732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                    return true;
3069732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com                }
30769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com            default:
30869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                break;
30969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        }
31069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
31169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
31269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
31369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comstruct QuadVertex {
31469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    GrPoint  fPos;
3159aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    GrPoint  fUV;
31681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar fD0;
31781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar fD1;
31869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com};
319fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3207d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.comstruct Draw {
3217d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    Draw() : fVertexCnt(0), fIndexCnt(0) {}
3227d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int fVertexCnt;
3237d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int fIndexCnt;
3247d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com};
3257d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
3267d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.comtypedef SkTArray<Draw, true> DrawArray;
3277d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
328fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void create_vertices(const SegmentArray&  segments,
329fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            const SkPoint& fanPt,
330fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            DrawArray*     draws,
331fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            QuadVertex*    verts,
332fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org                            uint16_t*      idxs) {
3337d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    Draw* draw = &draws->push_back();
3347d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    // alias just to make vert/index assignments easier to read.
3357d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int* v = &draw->fVertexCnt;
3367d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int* i = &draw->fIndexCnt;
33769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
3389aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int count = segments.count();
3399aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    for (int a = 0; a < count; ++a) {
3409aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        const Segment& sega = segments[a];
3419aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        int b = (a + 1) % count;
3429aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        const Segment& segb = segments[b];
343fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3447d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        // Check whether adding the verts for this segment to the current draw would cause index
3457d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        // values to overflow.
3467d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        int vCount = 4;
3477d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        if (Segment::kLine == segb.fType) {
3487d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            vCount += 5;
3497d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        } else {
3507d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            vCount += 6;
3517d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        }
3527d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        if (draw->fVertexCnt + vCount > (1 << 16)) {
3537d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts += *v;
3547d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs += *i;
3557d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            draw = &draws->push_back();
3567d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            v = &draw->fVertexCnt;
3577d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            i = &draw->fIndexCnt;
3587d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        }
3597d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
3609aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        // FIXME: These tris are inset in the 1 unit arc around the corner
3617d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 0].fPos = sega.endPt();
3627d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm();
3637d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid;
3647d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0];
3657d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 0].fUV.set(0,0);
3667d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 1].fUV.set(0,-SK_Scalar1);
3677d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 2].fUV.set(0,-SK_Scalar1);
3687d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 3].fUV.set(0,-SK_Scalar1);
3697d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
3707d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
3717d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
3727d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
3737d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
3747d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 0] = *v + 0;
3757d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 1] = *v + 2;
3767d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 2] = *v + 1;
3777d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 3] = *v + 0;
3787d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 4] = *v + 3;
3797d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        idxs[*i + 5] = *v + 2;
3807d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
3817d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        *v += 4;
3827d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        *i += 6;
38369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
3849aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com        if (Segment::kLine == segb.fType) {
3857d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fPos = fanPt;
3867d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fPos = sega.endPt();
3877d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fPos = segb.fPts[0];
3889aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
3897d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
3907d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
3919aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
3929aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            // we draw the line edge as a degenerate quad (u is 0, v is the
3939aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            // signed distance to the edge)
3947d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos,
3957d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com                                                        verts[*v + 2].fPos);
3967d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fUV.set(0, dist);
3977d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fUV.set(0, 0);
3987d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fUV.set(0, 0);
3997d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fUV.set(0, -SK_Scalar1);
4007d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fUV.set(0, -SK_Scalar1);
4017d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4027d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
4037d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
4047d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
4057d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
4067d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1;
4077d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4087d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 0] = *v + 0;
4097d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 1] = *v + 2;
4107d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 2] = *v + 1;
4117d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4127d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 3] = *v + 3;
4137d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 4] = *v + 1;
4147d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 5] = *v + 2;
4157d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4167d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 6] = *v + 4;
4177d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 7] = *v + 3;
4187d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 8] = *v + 2;
4197d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
4207d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            *v += 5;
4217d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            *i += 9;
422068096148179062c4343138c112b87518e4ab3b1bsalomon@google.com        } else {
4239aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            GrPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
4249aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4259aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            GrVec midVec = segb.fNorms[0] + segb.fNorms[1];
4269aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            midVec.normalize();
4279aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4287d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fPos = fanPt;
4297d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fPos = qpts[0];
4307d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fPos = qpts[2];
4317d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fPos = qpts[0] + segb.fNorms[0];
4327d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fPos = qpts[2] + segb.fNorms[1];
4337d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 5].fPos = qpts[1] + midVec;
4349aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
43581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalar c = segb.fNorms[0].dot(qpts[0]);
4367d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fD0 =  -segb.fNorms[0].dot(fanPt) + c;
4377d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fD0 =  0.f;
4387d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fD0 =  -segb.fNorms[0].dot(qpts[2]) + c;
4397d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fD0 = -SK_ScalarMax/100;
4407d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fD0 = -SK_ScalarMax/100;
4417d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 5].fD0 = -SK_ScalarMax/100;
4429aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4439aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com            c = segb.fNorms[1].dot(qpts[2]);
4447d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 0].fD1 =  -segb.fNorms[1].dot(fanPt) + c;
4457d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 1].fD1 =  -segb.fNorms[1].dot(qpts[0]) + c;
4467d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 2].fD1 =  0.f;
4477d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 3].fD1 = -SK_ScalarMax/100;
4487d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 4].fD1 = -SK_ScalarMax/100;
4497d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            verts[*v + 5].fD1 = -SK_ScalarMax/100;
4509aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4511971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            GrPathUtils::QuadUVMatrix toUV(qpts);
4527d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            toUV.apply<6, sizeof(QuadVertex), sizeof(GrPoint)>(verts + *v);
4539aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4547d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 0] = *v + 3;
4557d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 1] = *v + 1;
4567d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 2] = *v + 2;
4577d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 3] = *v + 4;
4587d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 4] = *v + 3;
4597d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 5] = *v + 2;
4609aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4617d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 6] = *v + 5;
4627d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 7] = *v + 3;
4637d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 8] = *v + 4;
4649aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4657d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i +  9] = *v + 0;
4667d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 10] = *v + 2;
4677d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            idxs[*i + 11] = *v + 1;
4689aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com
4697d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            *v += 6;
4707d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com            *i += 12;
47169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        }
47269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
47369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
47469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
47590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
47690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
47790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/*
47890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
47990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * two components of the vertex attribute. Coverage is based on signed
48090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * distance with negative being inside, positive outside. The edge is specified in
48190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * window space (y-down). If either the third or fourth component of the interpolated
48290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
483041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * attempt to trim to a portion of the infinite quad.
484041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * Requires shader derivative instruction support.
48590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */
48690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
48790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgclass QuadEdgeEffect : public GrEffect {
48890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic:
48990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
49090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    static GrEffectRef* Create() {
491d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com        GR_CREATE_STATIC_EFFECT(gQuadEdgeEffect, QuadEdgeEffect, ());
492d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com        gQuadEdgeEffect->ref();
493d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com        return gQuadEdgeEffect;
49490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
49590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
49690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    virtual ~QuadEdgeEffect() {}
49790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
49890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    static const char* Name() { return "QuadEdge"; }
49990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
500041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com    virtual void getConstantColorComponents(GrColor* color,
50190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                            uint32_t* validFlags) const SK_OVERRIDE {
50290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        *validFlags = 0;
50390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
50490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
50590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
50690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        return GrTBackendEffectFactory<QuadEdgeEffect>::getInstance();
50790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
50890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
50990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    class GLEffect : public GrGLEffect {
51090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    public:
51190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
51290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            : INHERITED (factory) {}
51390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
51490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        virtual void emitCode(GrGLShaderBuilder* builder,
51590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                              const GrDrawEffect& drawEffect,
51690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                              EffectKey key,
51790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                              const char* outputColor,
51890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                              const char* inputColor,
51990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                              const TextureSamplerArray& samplers) SK_OVERRIDE {
52090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            const char *vsName, *fsName;
52190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            const SkString* attrName =
52290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
52390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
52490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
52590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            SkAssertResult(builder->enableFeature(
52690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                              GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
52790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
52890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
52990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            // keep the derivative instructions outside the conditional
53090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
53190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
53290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
53390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            // today we know z and w are in device space. We could use derivatives
53490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
53590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                    fsName);
53690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf ("\t\t} else {\n");
53790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
53890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                   "\t\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
53990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                   fsName, fsName);
54090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
54190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                    fsName);
54290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t\t\tedgeAlpha = "
54390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                   "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n\t\t}\n");
54490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
54590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            SkString modulate;
546018f179efb2413431bdb1a9e6701eb44ef36b792bsalomon@google.com            GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
54790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
54890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
54990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
55090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
55190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
55290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
55390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            return 0x0;
55490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
55590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
55690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
55790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
55890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    private:
55990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        typedef GrGLEffect INHERITED;
56090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    };
561041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com
56290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate:
563041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com    QuadEdgeEffect() {
564041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com        this->addVertexAttrib(kVec4f_GrSLType);
56590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
56690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
56790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
56890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        return true;
56990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
57090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
57190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    GR_DECLARE_EFFECT_TEST;
57290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
57390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    typedef GrEffect INHERITED;
57490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org};
57590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
57690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgGR_DEFINE_EFFECT_TEST(QuadEdgeEffect);
57790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
57890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgGrEffectRef* QuadEdgeEffect::TestCreate(SkMWCRandom* random,
57990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                        GrContext*,
58090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                        const GrDrawTargetCaps& caps,
58190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org                                        GrTexture*[]) {
58290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    // Doesn't work without derivative instructions.
58390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    return caps.shaderDerivativeSupport() ? QuadEdgeEffect::Create() : NULL;
58490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}
58590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
58690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
58790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
5888a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.combool GrAAConvexPathRenderer::canDrawPath(const SkPath& path,
5895f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                                         const SkStrokeRec& stroke,
5908a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                         const GrDrawTarget* target,
5918a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                         bool antiAlias) const {
592bcce8926524827775539874346dd424a9510dbc9bsalomon@google.com    return (target->caps()->shaderDerivativeSupport() && antiAlias &&
5935f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            stroke.isFillStyle() && !path.isInverseFillType() && path.isConvex());
594c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com}
595c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com
596429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.comnamespace {
597429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com
598429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com// position + edge
599429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.comextern const GrVertexAttrib gPathAttribs[] = {
600429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com    {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
601429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com    {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
602429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com};
603429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com
604429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com};
605429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com
606c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.combool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
6075f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                                        const SkStrokeRec&,
608c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                                        GrDrawTarget* target,
609c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com                                        bool antiAlias) {
610c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com
611af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    const SkPath* path = &origPath;
612af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    if (path->isEmpty()) {
613c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return true;
61469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
6154647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
616137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    SkMatrix viewMatrix = target->getDrawState().getViewMatrix();
617137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawTarget::AutoStateRestore asr;
618137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
619e3d3216fe17b6afb2e613271b5246a2766e12df6bsalomon@google.com        return false;
62069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
621137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawState* drawState = target->drawState();
62269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
623af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    // We use the fact that SkPath::transform path does subdivision based on
624af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    // perspective. Otherwise, we apply the view matrix when copying to the
625af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    // segment representation.
626af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    SkPath tmpPath;
627137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    if (viewMatrix.hasPerspective()) {
628137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        origPath.transform(viewMatrix, &tmpPath);
629af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com        path = &tmpPath;
630137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        viewMatrix = SkMatrix::I();
631af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com    }
632af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com
63369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    QuadVertex *verts;
63469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    uint16_t* idxs;
63569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
6369aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int vCount;
6379aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    int iCount;
63868a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com    enum {
63968a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com        kPreallocSegmentCnt = 512 / sizeof(Segment),
6407d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        kPreallocDrawCnt = 4,
64168a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com    };
64268a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com    SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
6439aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com    SkPoint fanPt;
644af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com
645137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount)) {
646c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return false;
64769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
64869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
649429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com    drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs));
6504647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
6514647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com    static const int kEdgeAttrIndex = 1;
65290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    GrEffectRef* quadEffect = QuadEdgeEffect::Create();
653eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com    drawState->addCoverageEffect(quadEffect, kEdgeAttrIndex)->unref();
6544647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com
655b75b0a0b8492e14c7728e0a0881f87dc64ce60f9jvanverth@google.com    GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount);
656b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com    if (!arg.succeeded()) {
657c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com        return false;
65869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
659f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(sizeof(QuadVertex) == drawState->getVertexSize());
660b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com    verts = reinterpret_cast<QuadVertex*>(arg.vertices());
661b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com    idxs = reinterpret_cast<uint16_t*>(arg.indices());
66269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
6637d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    SkSTArray<kPreallocDrawCnt, Draw, true> draws;
6647d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    create_vertices(segments, fanPt, &draws, verts, idxs);
6657d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com
6661dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    // This is valid because all the computed verts are within 1 pixel of the path control points.
6671dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    SkRect devBounds;
668137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    devBounds = path->getBounds();
669137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    viewMatrix.mapRect(&devBounds);
6701dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    devBounds.outset(SK_Scalar1, SK_Scalar1);
6711dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com
6721dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    // Check devBounds
673515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
6741dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    SkRect tolDevBounds = devBounds;
6751dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
6761dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    SkRect actualBounds;
6771dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    actualBounds.set(verts[0].fPos, verts[1].fPos);
6781dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    for (int i = 2; i < vCount; ++i) {
6791dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com        actualBounds.growToInclude(verts[i].fPos.fX, verts[i].fPos.fY);
6801dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com    }
681f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(tolDevBounds.contains(actualBounds));
6821dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com#endif
6831dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com
6847d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    int vOffset = 0;
6857d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    for (int i = 0; i < draws.count(); ++i) {
6867d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        const Draw& draw = draws[i];
6877d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        target->drawIndexed(kTriangles_GrPrimitiveType,
6887d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com                            vOffset,  // start vertex
6897d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com                            0,        // start index
6907d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com                            draw.fVertexCnt,
6911dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com                            draw.fIndexCnt,
6921dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com                            &devBounds);
6937d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com        vOffset += draw.fVertexCnt;
6947d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com    }
695a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com
696c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com    return true;
69769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
698