GrPathUtils.cpp revision 4dbbd04314cc0606f8d3bafe515c97e52c180f73
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
69d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org */
79d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
89d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org#include "GrPathUtils.h"
9fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org
10d537341e16524d1e22ac5e6c8b9c8f274ba1833crobertphillips#include "GrTypes.h"
1169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "SkGeometry.h"
124dbbd04314cc0606f8d3bafe515c97e52c180f73halcanary#include "SkMathPriv.h"
139d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.comSkScalar GrPathUtils::scaleToleranceToSrc(SkScalar devTol,
15b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com                                          const SkMatrix& viewM,
16fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                          const SkRect& pathBounds) {
17181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com    // In order to tesselate the path we get a bound on how much the matrix can
181878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org    // scale when mapping to screen coordinates.
191878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org    SkScalar stretch = viewM.getMaxScale();
2081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar srcTol = devTol;
21181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com
22181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com    if (stretch < 0) {
23383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com        // take worst case mapRadius amoung four corners.
24383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com        // (less than perfect)
25383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com        for (int i = 0; i < 4; ++i) {
26b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com            SkMatrix mat;
27383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com            mat.setTranslate((i % 2) ? pathBounds.fLeft : pathBounds.fRight,
28383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com                             (i < 2) ? pathBounds.fTop : pathBounds.fBottom);
29383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com            mat.postConcat(viewM);
30383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com            stretch = SkMaxScalar(stretch, mat.mapRadius(SK_Scalar1));
31383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com        }
32181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com    }
3380ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed    return srcTol / stretch;
34181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com}
35181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com
36b5b3168a645802f66233234a06dd5a3764f18018bsalomon@google.comstatic const int MAX_POINTS_PER_CURVE = 1 << 10;
374b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.orgstatic const SkScalar gMinCurveTol = 0.0001f;
389d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
39972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orguint32_t GrPathUtils::quadraticPointCount(const SkPoint points[],
4081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                          SkScalar tol) {
41c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    if (tol < gMinCurveTol) {
42afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com        tol = gMinCurveTol;
43c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    }
44f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(tol > 0);
45c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
4681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
47c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    if (d <= tol) {
489d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        return 1;
499d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    } else {
509d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // Each time we subdivide, d should be cut in 4. So we need to
519d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
529d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // points.
539d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // 2^(log4(x)) = sqrt(x);
5480ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed        SkScalar divSqrt = SkScalarSqrt(d / tol);
555a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel        if (((SkScalar)SK_MaxS32) <= divSqrt) {
565a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            return MAX_POINTS_PER_CURVE;
575a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel        } else {
585a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            int temp = SkScalarCeilToInt(divSqrt);
595a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            int pow2 = GrNextPow2(temp);
605a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // Because of NaNs & INFs we can wind up with a degenerate temp
615a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // such that pow2 comes out negative. Also, our point generator
625a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // will always output at least one pt.
635a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            if (pow2 < 1) {
645a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel                pow2 = 1;
655a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            }
665a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            return SkTMin(pow2, MAX_POINTS_PER_CURVE);
6761f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com        }
689d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
699d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
709d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
71972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orguint32_t GrPathUtils::generateQuadraticPoints(const SkPoint& p0,
72972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                              const SkPoint& p1,
73972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                              const SkPoint& p2,
7481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                              SkScalar tolSqd,
75972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                              SkPoint** points,
76c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com                                              uint32_t pointsLeft) {
779d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    if (pointsLeft < 2 ||
789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
799d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        (*points)[0] = p2;
809d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        *points += 1;
819d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        return 1;
829d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
839d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
84972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint q[] = {
8581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
8681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
879d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    };
88972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint r = { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) };
899d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
909d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    pointsLeft >>= 1;
919d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    uint32_t a = generateQuadraticPoints(p0, q[0], r, tolSqd, points, pointsLeft);
929d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    uint32_t b = generateQuadraticPoints(r, q[1], p2, tolSqd, points, pointsLeft);
939d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    return a + b;
949d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
959d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
96972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orguint32_t GrPathUtils::cubicPointCount(const SkPoint points[],
9781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                           SkScalar tol) {
98c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    if (tol < gMinCurveTol) {
99afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com        tol = gMinCurveTol;
100c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    }
101f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(tol > 0);
102c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
103972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkScalar d = SkTMax(
104c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com        points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
105c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com        points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
1062047f00e4698f83499ab91911999a65c21a951c9epoger@google.com    d = SkScalarSqrt(d);
107c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    if (d <= tol) {
1089d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        return 1;
1099d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    } else {
11080ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed        SkScalar divSqrt = SkScalarSqrt(d / tol);
1115a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel        if (((SkScalar)SK_MaxS32) <= divSqrt) {
1125a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            return MAX_POINTS_PER_CURVE;
1135a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel        } else {
11480ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            int temp = SkScalarCeilToInt(SkScalarSqrt(d / tol));
1155a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            int pow2 = GrNextPow2(temp);
1165a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // Because of NaNs & INFs we can wind up with a degenerate temp
1175a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // such that pow2 comes out negative. Also, our point generator
1185a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // will always output at least one pt.
1195a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            if (pow2 < 1) {
1205a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel                pow2 = 1;
1215a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            }
1225a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            return SkTMin(pow2, MAX_POINTS_PER_CURVE);
12361f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com        }
1249d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
1259d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
1269d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
127972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orguint32_t GrPathUtils::generateCubicPoints(const SkPoint& p0,
128972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                          const SkPoint& p1,
129972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                          const SkPoint& p2,
130972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                          const SkPoint& p3,
13181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                          SkScalar tolSqd,
132972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                          SkPoint** points,
133c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com                                          uint32_t pointsLeft) {
1349d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    if (pointsLeft < 2 ||
1359d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
1369d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org         p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
137f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips        (*points)[0] = p3;
138f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips        *points += 1;
139f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips        return 1;
140f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips    }
141972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint q[] = {
14281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
14381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
14481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
1459d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    };
146972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint r[] = {
14781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
14881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
1499d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    };
150972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
1519d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    pointsLeft >>= 1;
1529d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    uint32_t a = generateCubicPoints(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
1539d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    uint32_t b = generateCubicPoints(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
1549d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    return a + b;
1559d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
1569d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1578d033a1b125886c62906d975b5cc28a382064526bsalomon@google.comint GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths,
15881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                     SkScalar tol) {
159c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    if (tol < gMinCurveTol) {
160afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com        tol = gMinCurveTol;
161c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    }
162f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(tol > 0);
163c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
1649d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    int pointCount = 0;
1659d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    *subpaths = 1;
1669d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1679d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    bool first = true;
1689d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
169129b8e3237b80b9d258a8f48e8f54c0073cafbdcsenorblanco@chromium.org    SkPath::Iter iter(path, false);
17094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com    SkPath::Verb verb;
1719d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
172972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint pts[4];
17394b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
1749d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
17594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        switch (verb) {
17694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kLine_Verb:
1779d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                pointCount += 1;
1789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
179af18a09d13611526c4217656c98947f9067cb07aegdaniel            case SkPath::kConic_Verb: {
180af18a09d13611526c4217656c98947f9067cb07aegdaniel                SkScalar weight = iter.conicWeight();
181af18a09d13611526c4217656c98947f9067cb07aegdaniel                SkAutoConicToQuads converter;
182af18a09d13611526c4217656c98947f9067cb07aegdaniel                const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
183af18a09d13611526c4217656c98947f9067cb07aegdaniel                for (int i = 0; i < converter.countQuads(); ++i) {
184af18a09d13611526c4217656c98947f9067cb07aegdaniel                    pointCount += quadraticPointCount(quadPts + 2*i, tol);
185af18a09d13611526c4217656c98947f9067cb07aegdaniel                }
186af18a09d13611526c4217656c98947f9067cb07aegdaniel            }
18794b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kQuad_Verb:
1889d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                pointCount += quadraticPointCount(pts, tol);
1899d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
19094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kCubic_Verb:
1919d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                pointCount += cubicPointCount(pts, tol);
1929d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
19394b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kMove_Verb:
1949d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                pointCount += 1;
1959d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                if (!first) {
1969d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                    ++(*subpaths);
1979d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                }
1989d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
1999d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org            default:
2009d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
2019d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        }
2029d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        first = false;
2039d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
2049d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    return pointCount;
2059d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
20669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
207972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgvoid GrPathUtils::QuadUVMatrix::set(const SkPoint qPts[3]) {
2081971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    SkMatrix m;
209dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // We want M such that M * xy_pt = uv_pt
210dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // We know M * control_pts = [0  1/2 1]
211dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    //                           [0  0   1]
212dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    //                           [1  1   1]
213f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    // And control_pts = [x0 x1 x2]
214f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //                   [y0 y1 y2]
215f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //                   [1  1  1 ]
216dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // We invert the control pt matrix and post concat to both sides to get M.
217f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    // Using the known form of the control point matrix and the result, we can
218f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    // optimize and improve precision.
219f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
220f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double x0 = qPts[0].fX;
221f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double y0 = qPts[0].fY;
222f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double x1 = qPts[1].fX;
223f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double y1 = qPts[1].fY;
224f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double x2 = qPts[2].fX;
225f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double y2 = qPts[2].fY;
226f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double det = x0*y1 - y0*x1 + x2*y0 - y2*x0 + x1*y2 - y1*x2;
227f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
2288491d24bdc3f48f67475c12c60babb9f9dba8047skia.committer@gmail.com    if (!sk_float_isfinite(det)
229f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        || SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
230dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        // The quad is degenerate. Hopefully this is rare. Find the pts that are
231dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        // farthest apart to compute a line (unless it is really a pt).
232dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        SkScalar maxD = qPts[0].distanceToSqd(qPts[1]);
233dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        int maxEdge = 0;
234dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        SkScalar d = qPts[1].distanceToSqd(qPts[2]);
235dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        if (d > maxD) {
236dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            maxD = d;
237dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            maxEdge = 1;
238dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        }
239dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        d = qPts[2].distanceToSqd(qPts[0]);
240dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        if (d > maxD) {
241dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            maxD = d;
242dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            maxEdge = 2;
243dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        }
244dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        // We could have a tolerance here, not sure if it would improve anything
245dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        if (maxD > 0) {
246dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            // Set the matrix to give (u = 0, v = distance_to_line)
247972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            SkVector lineVec = qPts[(maxEdge + 1)%3] - qPts[maxEdge];
24820e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com            // when looking from the point 0 down the line we want positive
24920e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com            // distances to be to the left. This matches the non-degenerate
25020e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com            // case.
251972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            lineVec.setOrthog(lineVec, SkPoint::kLeft_Side);
252dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            lineVec.dot(qPts[0]);
2531971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            // first row
2541971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[0] = 0;
2551971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[1] = 0;
2561971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[2] = 0;
2571971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            // second row
2581971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[3] = lineVec.fX;
2591971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[4] = lineVec.fY;
2601971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[5] = -lineVec.dot(qPts[maxEdge]);
261dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        } else {
262dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            // It's a point. It should cover zero area. Just set the matrix such
263dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            // that (u, v) will always be far away from the quad.
2641971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[0] = 0; fM[1] = 0; fM[2] = 100.f;
2651971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[3] = 0; fM[4] = 0; fM[5] = 100.f;
266dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        }
267dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    } else {
268f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        double scale = 1.0/det;
269f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
270f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        // compute adjugate matrix
27187a223401d8575d398eb369f7be7afdabbdfab08robertphillips        double a2, a3, a4, a5, a6, a7, a8;
272f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a2 = x1*y2-x2*y1;
273f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
274f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a3 = y2-y0;
275f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a4 = x0-x2;
276f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a5 = x2*y0-x0*y2;
277f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
278f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a6 = y0-y1;
279f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a7 = x1-x0;
280f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a8 = x0*y1-x1*y0;
281f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
2828491d24bdc3f48f67475c12c60babb9f9dba8047skia.committer@gmail.com        // this performs the uv_pts*adjugate(control_pts) multiply,
283f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        // then does the scale by 1/det afterwards to improve precision
284f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMScaleX] = (float)((0.5*a3 + a6)*scale);
285f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMSkewX]  = (float)((0.5*a4 + a7)*scale);
286f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMTransX] = (float)((0.5*a5 + a8)*scale);
287f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
288f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMSkewY]  = (float)(a6*scale);
289f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMScaleY] = (float)(a7*scale);
290f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMTransY] = (float)(a8*scale);
291f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
29287a223401d8575d398eb369f7be7afdabbdfab08robertphillips        // kMPersp0 & kMPersp1 should algebraically be zero
29387a223401d8575d398eb369f7be7afdabbdfab08robertphillips        m[SkMatrix::kMPersp0] = 0.0f;
29487a223401d8575d398eb369f7be7afdabbdfab08robertphillips        m[SkMatrix::kMPersp1] = 0.0f;
295f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMPersp2] = (float)((a2 + a5 + a8)*scale);
2961971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
2971971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        // It may not be normalized to have 1.0 in the bottom right
2981971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        float m33 = m.get(SkMatrix::kMPersp2);
2991971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        if (1.f != m33) {
3001971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            m33 = 1.f / m33;
3011971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[0] = m33 * m.get(SkMatrix::kMScaleX);
3021971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[1] = m33 * m.get(SkMatrix::kMSkewX);
3031971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[2] = m33 * m.get(SkMatrix::kMTransX);
3041971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[3] = m33 * m.get(SkMatrix::kMSkewY);
3051971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[4] = m33 * m.get(SkMatrix::kMScaleY);
3061971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[5] = m33 * m.get(SkMatrix::kMTransY);
3071971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        } else {
3081971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[0] = m.get(SkMatrix::kMScaleX);
3091971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[1] = m.get(SkMatrix::kMSkewX);
3101971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[2] = m.get(SkMatrix::kMTransX);
3111971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[3] = m.get(SkMatrix::kMSkewY);
3121971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[4] = m.get(SkMatrix::kMScaleY);
3131971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[5] = m.get(SkMatrix::kMTransY);
3141971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        }
315dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    }
31669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
31769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
318139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
319139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
320139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// k = (y2 - y0, x0 - x2, (x2 - x0)*y0 - (y2 - y0)*x0 )
321139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// l = (2*w * (y1 - y0), 2*w * (x0 - x1), 2*w * (x1*y0 - x0*y1))
322139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// m = (2*w * (y2 - y1), 2*w * (x1 - x2), 2*w * (x2*y1 - x1*y2))
323139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.orgvoid GrPathUtils::getConicKLM(const SkPoint p[3], const SkScalar weight, SkScalar klm[9]) {
324139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    const SkScalar w2 = 2.f * weight;
325139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[0] = p[2].fY - p[0].fY;
326139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[1] = p[0].fX - p[2].fX;
327139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX;
328139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
329139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[3] = w2 * (p[1].fY - p[0].fY);
330139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[4] = w2 * (p[0].fX - p[1].fX);
331139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[5] = w2 * (p[1].fX * p[0].fY - p[0].fX * p[1].fY);
332139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
333139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[6] = w2 * (p[2].fY - p[1].fY);
334139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[7] = w2 * (p[1].fX - p[2].fX);
335139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[8] = w2 * (p[2].fX * p[1].fY - p[1].fX * p[2].fY);
336139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
337139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    // scale the max absolute value of coeffs to 10
338139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    SkScalar scale = 0.f;
339139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    for (int i = 0; i < 9; ++i) {
340139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org       scale = SkMaxScalar(scale, SkScalarAbs(klm[i]));
341139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    }
342139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    SkASSERT(scale > 0.f);
343139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    scale = 10.f / scale;
344139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    for (int i = 0; i < 9; ++i) {
345139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org        klm[i] *= scale;
346139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    }
347139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org}
348139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
349139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
350139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
35169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comnamespace {
352a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
353a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// a is the first control point of the cubic.
354a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// ab is the vector from a to the second control point.
355a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// dc is the vector from the fourth to the third control point.
356a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// d is the fourth control point.
357a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// p is the candidate quadratic control point.
358a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// this assumes that the cubic doesn't inflect and is simple
359a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.combool is_point_within_cubic_tangents(const SkPoint& a,
360a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                    const SkVector& ab,
361a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                    const SkVector& dc,
362a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                    const SkPoint& d,
363026beb52a29a620290fcfb24f1e7e9e75547b80freed                                    SkPathPriv::FirstDirection dir,
364a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                    const SkPoint p) {
365a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkVector ap = p - a;
366a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkScalar apXab = ap.cross(ab);
367026beb52a29a620290fcfb24f1e7e9e75547b80freed    if (SkPathPriv::kCW_FirstDirection == dir) {
368a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (apXab > 0) {
369a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return false;
370a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
371a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    } else {
372026beb52a29a620290fcfb24f1e7e9e75547b80freed        SkASSERT(SkPathPriv::kCCW_FirstDirection == dir);
373a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (apXab < 0) {
374a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return false;
375a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
376a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
377a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
378a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkVector dp = p - d;
379a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkScalar dpXdc = dp.cross(dc);
380026beb52a29a620290fcfb24f1e7e9e75547b80freed    if (SkPathPriv::kCW_FirstDirection == dir) {
381a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (dpXdc < 0) {
382a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return false;
383a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
384a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    } else {
385026beb52a29a620290fcfb24f1e7e9e75547b80freed        SkASSERT(SkPathPriv::kCCW_FirstDirection == dir);
386a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (dpXdc > 0) {
387a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return false;
388a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
389a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
390a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    return true;
391a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com}
392a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
39369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comvoid convert_noninflect_cubic_to_quads(const SkPoint p[4],
394a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                       SkScalar toleranceSqd,
395a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                       bool constrainWithinTangents,
396026beb52a29a620290fcfb24f1e7e9e75547b80freed                                       SkPathPriv::FirstDirection dir,
39769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                                       SkTArray<SkPoint, true>* quads,
39869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                                       int sublevel = 0) {
39954ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com
40054ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    // Notation: Point a is always p[0]. Point b is p[1] unless p[1] == p[0], in which case it is
40154ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    // p[2]. Point d is always p[3]. Point c is p[2] unless p[2] == p[3], in which case it is p[1].
40254ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com
403a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkVector ab = p[1] - p[0];
404a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkVector dc = p[2] - p[3];
405a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
406f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips    if (ab.lengthSqd() < SK_ScalarNearlyZero) {
407f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips        if (dc.lengthSqd() < SK_ScalarNearlyZero) {
408a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkPoint* degQuad = quads->push_back_n(3);
409a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            degQuad[0] = p[0];
410a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            degQuad[1] = p[0];
411a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            degQuad[2] = p[3];
412a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return;
413a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
414a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        ab = p[2] - p[0];
415a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
416f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips    if (dc.lengthSqd() < SK_ScalarNearlyZero) {
417a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        dc = p[1] - p[3];
418a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
419a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
4203935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // When the ab and cd tangents are degenerate or nearly parallel with vector from d to a the
4213935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // constraint that the quad point falls between the tangents becomes hard to enforce and we are
4223935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // likely to hit the max subdivision count. However, in this case the cubic is approaching a
4233935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // line and the accuracy of the quad point isn't so important. We check if the two middle cubic
4243935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // control points are very close to the baseline vector. If so then we just pick quadratic
4253935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // points on the control polygon.
42654ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com
42754ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    if (constrainWithinTangents) {
42854ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com        SkVector da = p[0] - p[3];
4293935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon        bool doQuads = dc.lengthSqd() < SK_ScalarNearlyZero ||
4303935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                       ab.lengthSqd() < SK_ScalarNearlyZero;
4313935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon        if (!doQuads) {
4323935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            SkScalar invDALengthSqd = da.lengthSqd();
4333935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            if (invDALengthSqd > SK_ScalarNearlyZero) {
4343935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                invDALengthSqd = SkScalarInvert(invDALengthSqd);
4353935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                // cross(ab, da)^2/length(da)^2 == sqd distance from b to line from d to a.
4363935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                // same goes for point c using vector cd.
4373935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                SkScalar detABSqd = ab.cross(da);
4383935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                detABSqd = SkScalarSquare(detABSqd);
4393935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                SkScalar detDCSqd = dc.cross(da);
4403935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                detDCSqd = SkScalarSquare(detDCSqd);
4413935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                if (SkScalarMul(detABSqd, invDALengthSqd) < toleranceSqd &&
4423935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                    SkScalarMul(detDCSqd, invDALengthSqd) < toleranceSqd) {
4433935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                    doQuads = true;
44454ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com                }
44554ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com            }
44654ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com        }
4473935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon        if (doQuads) {
4483935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            SkPoint b = p[0] + ab;
4493935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            SkPoint c = p[3] + dc;
4503935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            SkPoint mid = b + c;
4513935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            mid.scale(SK_ScalarHalf);
4523935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            // Insert two quadratics to cover the case when ab points away from d and/or dc
4533935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            // points away from a.
4543935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            if (SkVector::DotProduct(da, dc) < 0 || SkVector::DotProduct(ab,da) > 0) {
4553935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                SkPoint* qpts = quads->push_back_n(6);
4563935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[0] = p[0];
4573935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[1] = b;
4583935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[2] = mid;
4593935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[3] = mid;
4603935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[4] = c;
4613935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[5] = p[3];
4623935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            } else {
4633935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                SkPoint* qpts = quads->push_back_n(3);
4643935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[0] = p[0];
4653935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[1] = mid;
4663935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[2] = p[3];
4673935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            }
4683935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            return;
4693935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon        }
47054ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    }
47154ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com
472a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    static const SkScalar kLengthScale = 3 * SK_Scalar1 / 2;
47369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    static const int kMaxSubdivs = 10;
47469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
475a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    ab.scale(kLengthScale);
476a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    dc.scale(kLengthScale);
47769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
478a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    // e0 and e1 are extrapolations along vectors ab and dc.
47969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    SkVector c0 = p[0];
48069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    c0 += ab;
48169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    SkVector c1 = p[3];
48269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    c1 += dc;
48369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
48454ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    SkScalar dSqd = sublevel > kMaxSubdivs ? 0 : c0.distanceToSqd(c1);
485a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    if (dSqd < toleranceSqd) {
48669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        SkPoint cAvg = c0;
48769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        cAvg += c1;
48869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        cAvg.scale(SK_ScalarHalf);
48969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
490a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        bool subdivide = false;
491a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
492a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (constrainWithinTangents &&
493a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            !is_point_within_cubic_tangents(p[0], ab, dc, p[3], dir, cAvg)) {
49454ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com            // choose a new cAvg that is the intersection of the two tangent lines.
495a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            ab.setOrthog(ab);
496a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkScalar z0 = -ab.dot(p[0]);
497a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            dc.setOrthog(dc);
498a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkScalar z1 = -dc.dot(p[3]);
499a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            cAvg.fX = SkScalarMul(ab.fY, z1) - SkScalarMul(z0, dc.fY);
500a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            cAvg.fY = SkScalarMul(z0, dc.fX) - SkScalarMul(ab.fX, z1);
501a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkScalar z = SkScalarMul(ab.fX, dc.fY) - SkScalarMul(ab.fY, dc.fX);
502a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            z = SkScalarInvert(z);
503a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            cAvg.fX *= z;
504a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            cAvg.fY *= z;
505a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            if (sublevel <= kMaxSubdivs) {
506a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                SkScalar d0Sqd = c0.distanceToSqd(cAvg);
507a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                SkScalar d1Sqd = c1.distanceToSqd(cAvg);
50854ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com                // We need to subdivide if d0 + d1 > tolerance but we have the sqd values. We know
50954ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com                // the distances and tolerance can't be negative.
510a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                // (d0 + d1)^2 > toleranceSqd
511a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                // d0Sqd + 2*d0*d1 + d1Sqd > toleranceSqd
512a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                SkScalar d0d1 = SkScalarSqrt(SkScalarMul(d0Sqd, d1Sqd));
513a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                subdivide = 2 * d0d1 + d0Sqd + d1Sqd > toleranceSqd;
514a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            }
515a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
516a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (!subdivide) {
517a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkPoint* pts = quads->push_back_n(3);
518a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            pts[0] = p[0];
519a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            pts[1] = cAvg;
520a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            pts[2] = p[3];
521a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return;
522a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
52369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
524a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkPoint choppedPts[7];
525a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkChopCubicAtHalf(p, choppedPts);
526a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    convert_noninflect_cubic_to_quads(choppedPts + 0,
527a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      toleranceSqd,
528a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      constrainWithinTangents,
529a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      dir,
530a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      quads,
531a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      sublevel + 1);
532a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    convert_noninflect_cubic_to_quads(choppedPts + 3,
533a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      toleranceSqd,
534a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      constrainWithinTangents,
535a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      dir,
536a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      quads,
537a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      sublevel + 1);
53869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
53969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
54069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
541972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgvoid GrPathUtils::convertCubicToQuads(const SkPoint p[4],
54269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                                      SkScalar tolScale,
54369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                                      SkTArray<SkPoint, true>* quads) {
54469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    SkPoint chopped[10];
54569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    int count = SkChopCubicAtInflections(p, chopped);
54669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
54718fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    const SkScalar tolSqd = SkScalarSquare(tolScale);
548a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
54969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    for (int i = 0; i < count; ++i) {
55069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        SkPoint* cubic = chopped + 3*i;
55118fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon        // The direction param is ignored if the third param is false.
55218fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon        convert_noninflect_cubic_to_quads(cubic, tolSqd, false,
55318fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon                                          SkPathPriv::kCCW_FirstDirection, quads);
55469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
55518fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon}
55618fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon
55718fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomonvoid GrPathUtils::convertCubicToQuadsConstrainToTangents(const SkPoint p[4],
55818fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon                                                         SkScalar tolScale,
55918fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon                                                         SkPathPriv::FirstDirection dir,
56018fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon                                                         SkTArray<SkPoint, true>* quads) {
56118fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    SkPoint chopped[10];
56218fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    int count = SkChopCubicAtInflections(p, chopped);
56369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
56418fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    const SkScalar tolSqd = SkScalarSquare(tolScale);
56518fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon
56618fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    for (int i = 0; i < count; ++i) {
56718fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon        SkPoint* cubic = chopped + 3*i;
56818fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon        convert_noninflect_cubic_to_quads(cubic, tolSqd, true, dir, quads);
56918fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    }
57069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
571858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
572858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
573858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
574858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// Solves linear system to extract klm
575858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// P.K = k (similarly for l, m)
576858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// Where P is matrix of control points
577858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// K is coefficients for the line K
578858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// k is vector of values of K evaluated at the control points
579858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// Solving for K, thus K = P^(-1) . k
580858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void calc_cubic_klm(const SkPoint p[4], const SkScalar controlK[4],
581858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                           const SkScalar controlL[4], const SkScalar controlM[4],
582858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                           SkScalar k[3], SkScalar l[3], SkScalar m[3]) {
583858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkMatrix matrix;
584858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    matrix.setAll(p[0].fX, p[0].fY, 1.f,
585858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                  p[1].fX, p[1].fY, 1.f,
586858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                  p[2].fX, p[2].fY, 1.f);
587858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkMatrix inverse;
588858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    if (matrix.invert(&inverse)) {
589858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org       inverse.mapHomogeneousPoints(k, controlK, 1);
590858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org       inverse.mapHomogeneousPoints(l, controlL, 1);
591858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org       inverse.mapHomogeneousPoints(m, controlM, 1);
592858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
593858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
594858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
595858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
596858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void set_serp_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) {
597858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar tempSqrt = SkScalarSqrt(9.f * d[1] * d[1] - 12.f * d[0] * d[2]);
598858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar ls = 3.f * d[1] - tempSqrt;
599858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar lt = 6.f * d[0];
600858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar ms = 3.f * d[1] + tempSqrt;
601858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar mt = 6.f * d[0];
602858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
603858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[0] = ls * ms;
604858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[1] = (3.f * ls * ms - ls * mt - lt * ms) / 3.f;
605858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[2] = (lt * (mt - 2.f * ms) + ls * (3.f * ms - 2.f * mt)) / 3.f;
606858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[3] = (lt - ls) * (mt - ms);
607858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
608858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[0] = ls * ls * ls;
609858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar lt_ls = lt - ls;
610858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[1] = ls * ls * lt_ls * -1.f;
611858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[2] = lt_ls * lt_ls * ls;
612858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[3] = -1.f * lt_ls * lt_ls * lt_ls;
613858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
614858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[0] = ms * ms * ms;
615858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar mt_ms = mt - ms;
616858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[1] = ms * ms * mt_ms * -1.f;
617858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[2] = mt_ms * mt_ms * ms;
618858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[3] = -1.f * mt_ms * mt_ms * mt_ms;
619858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
620858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // If d0 < 0 we need to flip the orientation of our curve
621858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // This is done by negating the k and l values
622858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // We want negative distance values to be on the inside
623858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    if ( d[0] > 0) {
624858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        for (int i = 0; i < 4; ++i) {
625858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            k[i] = -k[i];
626858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            l[i] = -l[i];
627858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
628858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
629858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
630858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
631858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void set_loop_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) {
632858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]);
633858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar ls = d[1] - tempSqrt;
634858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar lt = 2.f * d[0];
635858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar ms = d[1] + tempSqrt;
636858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar mt = 2.f * d[0];
637858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
638858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[0] = ls * ms;
639858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[1] = (3.f * ls*ms - ls * mt - lt * ms) / 3.f;
640858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[2] = (lt * (mt - 2.f * ms) + ls * (3.f * ms - 2.f * mt)) / 3.f;
641858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[3] = (lt - ls) * (mt - ms);
642858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
643858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[0] = ls * ls * ms;
644858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[1] = (ls * (ls * (mt - 3.f * ms) + 2.f * lt * ms))/-3.f;
645858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[2] = ((lt - ls) * (ls * (2.f * mt - 3.f * ms) + lt * ms))/3.f;
646858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[3] = -1.f * (lt - ls) * (lt - ls) * (mt - ms);
647858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
648858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[0] = ls * ms * ms;
649858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[1] = (ms * (ls * (2.f * mt - 3.f * ms) + lt * ms))/-3.f;
650858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[2] = ((mt - ms) * (ls * (mt - 3.f * ms) + 2.f * lt * ms))/3.f;
651858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[3] = -1.f * (lt - ls) * (mt - ms) * (mt - ms);
652858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
653858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
654858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // If (d0 < 0 && sign(k1) > 0) || (d0 > 0 && sign(k1) < 0),
655858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // we need to flip the orientation of our curve.
656858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // This is done by negating the k and l values
65707e1c3fd5030869c480c15ff30d36bd161718262commit-bot@chromium.org    if ( (d[0] < 0 && k[1] > 0) || (d[0] > 0 && k[1] < 0)) {
658858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        for (int i = 0; i < 4; ++i) {
659858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            k[i] = -k[i];
660858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            l[i] = -l[i];
661858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
662858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
663858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
664858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
665858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void set_cusp_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) {
666858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar ls = d[2];
667858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar lt = 3.f * d[1];
668858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
669858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[0] = ls;
670858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[1] = ls - lt / 3.f;
671858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[2] = ls - 2.f * lt / 3.f;
672858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[3] = ls - lt;
673858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
674858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[0] = ls * ls * ls;
675858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar ls_lt = ls - lt;
676858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[1] = ls * ls * ls_lt;
677858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[2] = ls_lt * ls_lt * ls;
678858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[3] = ls_lt * ls_lt * ls_lt;
679858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
680858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[0] = 1.f;
681858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[1] = 1.f;
682858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[2] = 1.f;
683858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[3] = 1.f;
684858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
685858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
686858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// For the case when a cubic is actually a quadratic
687858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// M =
688858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// 0     0     0
689858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// 1/3   0     1/3
690858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// 2/3   1/3   2/3
691858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// 1     1     1
692858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void set_quadratic_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) {
693858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[0] = 0.f;
694858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[1] = 1.f/3.f;
695858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[2] = 2.f/3.f;
696858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[3] = 1.f;
697858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
698858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[0] = 0.f;
699858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[1] = 0.f;
700858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[2] = 1.f/3.f;
701858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[3] = 1.f;
702858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
703858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[0] = 0.f;
704858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[1] = 1.f/3.f;
705858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[2] = 2.f/3.f;
706858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[3] = 1.f;
707858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
708858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // If d2 < 0 we need to flip the orientation of our curve
709858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // This is done by negating the k and l values
710858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    if ( d[2] > 0) {
711858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        for (int i = 0; i < 4; ++i) {
712858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            k[i] = -k[i];
713858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            l[i] = -l[i];
714858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
715858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
716858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
717858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
718858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgint GrPathUtils::chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[10], SkScalar klm[9],
719858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                                             SkScalar klm_rev[3]) {
720858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // Variable to store the two parametric values at the loop double point
721858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar smallS = 0.f;
722858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar largeS = 0.f;
723858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
724858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar d[3];
7258dd31cf69e24ff82865309781107dfab948b6a02caryclark    SkCubicType cType = SkClassifyCubic(src, d);
726858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
727858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    int chop_count = 0;
7288dd31cf69e24ff82865309781107dfab948b6a02caryclark    if (kLoop_SkCubicType == cType) {
729858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]);
730858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar ls = d[1] - tempSqrt;
731858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar lt = 2.f * d[0];
732858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar ms = d[1] + tempSqrt;
733858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar mt = 2.f * d[0];
734858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        ls = ls / lt;
735858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        ms = ms / mt;
736858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        // need to have t values sorted since this is what is expected by SkChopCubicAt
737858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (ls <= ms) {
738858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            smallS = ls;
739858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            largeS = ms;
740858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        } else {
741858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            smallS = ms;
742858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            largeS = ls;
743858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
744858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
745858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar chop_ts[2];
746858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (smallS > 0.f && smallS < 1.f) {
747858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            chop_ts[chop_count++] = smallS;
748858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
749858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (largeS > 0.f && largeS < 1.f) {
750858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            chop_ts[chop_count++] = largeS;
751858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
752858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if(dst) {
753858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            SkChopCubicAt(src, dst, chop_ts, chop_count);
754858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
755858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    } else {
756858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (dst) {
757858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            memcpy(dst, src, sizeof(SkPoint) * 4);
758858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
759858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
760858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
761858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    if (klm && klm_rev) {
762858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        // Set klm_rev to to match the sub_section of cubic that needs to have its orientation
763858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        // flipped. This will always be the section that is the "loop"
764858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (2 == chop_count) {
765858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            klm_rev[0] = 1.f;
766858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            klm_rev[1] = -1.f;
767858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            klm_rev[2] = 1.f;
768858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        } else if (1 == chop_count) {
769858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            if (smallS < 0.f) {
770858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[0] = -1.f;
771858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[1] = 1.f;
772858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            } else {
773858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[0] = 1.f;
774858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[1] = -1.f;
775858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            }
776858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        } else {
777858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            if (smallS < 0.f && largeS > 1.f) {
778858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[0] = -1.f;
779858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            } else {
780858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[0] = 1.f;
781858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            }
782858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
783858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar controlK[4];
784858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar controlL[4];
785858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar controlM[4];
786858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
7878dd31cf69e24ff82865309781107dfab948b6a02caryclark        if (kSerpentine_SkCubicType == cType || (kCusp_SkCubicType == cType && 0.f != d[0])) {
788858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            set_serp_klm(d, controlK, controlL, controlM);
7898dd31cf69e24ff82865309781107dfab948b6a02caryclark        } else if (kLoop_SkCubicType == cType) {
790858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            set_loop_klm(d, controlK, controlL, controlM);
7918dd31cf69e24ff82865309781107dfab948b6a02caryclark        } else if (kCusp_SkCubicType == cType) {
792858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            SkASSERT(0.f == d[0]);
793858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            set_cusp_klm(d, controlK, controlL, controlM);
7948dd31cf69e24ff82865309781107dfab948b6a02caryclark        } else if (kQuadratic_SkCubicType == cType) {
795858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            set_quadratic_klm(d, controlK, controlL, controlM);
796858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
797858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
798858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        calc_cubic_klm(src, controlK, controlL, controlM, klm, &klm[3], &klm[6]);
799858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
800858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    return chop_count + 1;
801858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
802858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
803858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgvoid GrPathUtils::getCubicKLM(const SkPoint p[4], SkScalar klm[9]) {
804858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar d[3];
8058dd31cf69e24ff82865309781107dfab948b6a02caryclark    SkCubicType cType = SkClassifyCubic(p, d);
806858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
807858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar controlK[4];
808858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar controlL[4];
809858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar controlM[4];
810858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
8118dd31cf69e24ff82865309781107dfab948b6a02caryclark    if (kSerpentine_SkCubicType == cType || (kCusp_SkCubicType == cType && 0.f != d[0])) {
812858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        set_serp_klm(d, controlK, controlL, controlM);
8138dd31cf69e24ff82865309781107dfab948b6a02caryclark    } else if (kLoop_SkCubicType == cType) {
814858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        set_loop_klm(d, controlK, controlL, controlM);
8158dd31cf69e24ff82865309781107dfab948b6a02caryclark    } else if (kCusp_SkCubicType == cType) {
816858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkASSERT(0.f == d[0]);
817858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        set_cusp_klm(d, controlK, controlL, controlM);
8188dd31cf69e24ff82865309781107dfab948b6a02caryclark    } else if (kQuadratic_SkCubicType == cType) {
819858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        set_quadratic_klm(d, controlK, controlL, controlM);
820858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
821858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
822858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    calc_cubic_klm(p, controlK, controlL, controlM, klm, &klm[3], &klm[6]);
823858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
824