GrPathUtils.cpp revision b6a40b83f36b905cf85e2e3dcd88d6423938b505
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]);
47b6a40b83f36b905cf85e2e3dcd88d6423938b505senorblanco    if (!SkScalarIsFinite(d)) {
48b6a40b83f36b905cf85e2e3dcd88d6423938b505senorblanco        return MAX_POINTS_PER_CURVE;
49b6a40b83f36b905cf85e2e3dcd88d6423938b505senorblanco    } else if (d <= tol) {
509d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        return 1;
519d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    } else {
529d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // Each time we subdivide, d should be cut in 4. So we need to
539d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
549d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // points.
559d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        // 2^(log4(x)) = sqrt(x);
5680ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed        SkScalar divSqrt = SkScalarSqrt(d / tol);
575a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel        if (((SkScalar)SK_MaxS32) <= divSqrt) {
585a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            return MAX_POINTS_PER_CURVE;
595a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel        } else {
605a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            int temp = SkScalarCeilToInt(divSqrt);
615a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            int pow2 = GrNextPow2(temp);
625a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // Because of NaNs & INFs we can wind up with a degenerate temp
635a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // such that pow2 comes out negative. Also, our point generator
645a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // will always output at least one pt.
655a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            if (pow2 < 1) {
665a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel                pow2 = 1;
675a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            }
685a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            return SkTMin(pow2, MAX_POINTS_PER_CURVE);
6961f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com        }
709d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
719d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
729d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
73972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orguint32_t GrPathUtils::generateQuadraticPoints(const SkPoint& p0,
74972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                              const SkPoint& p1,
75972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                              const SkPoint& p2,
7681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                              SkScalar tolSqd,
77972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                              SkPoint** points,
78c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com                                              uint32_t pointsLeft) {
799d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    if (pointsLeft < 2 ||
809d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
819d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        (*points)[0] = p2;
829d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        *points += 1;
839d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        return 1;
849d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
859d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
86972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint q[] = {
8781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
8881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
899d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    };
90972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint r = { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) };
919d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
929d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    pointsLeft >>= 1;
939d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    uint32_t a = generateQuadraticPoints(p0, q[0], r, tolSqd, points, pointsLeft);
949d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    uint32_t b = generateQuadraticPoints(r, q[1], p2, tolSqd, points, pointsLeft);
959d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    return a + b;
969d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
979d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
98972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orguint32_t GrPathUtils::cubicPointCount(const SkPoint points[],
9981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                           SkScalar tol) {
100c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    if (tol < gMinCurveTol) {
101afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com        tol = gMinCurveTol;
102c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    }
103f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(tol > 0);
104c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
105972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkScalar d = SkTMax(
106c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com        points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
107c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com        points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
1082047f00e4698f83499ab91911999a65c21a951c9epoger@google.com    d = SkScalarSqrt(d);
109b6a40b83f36b905cf85e2e3dcd88d6423938b505senorblanco    if (!SkScalarIsFinite(d)) {
110b6a40b83f36b905cf85e2e3dcd88d6423938b505senorblanco        return MAX_POINTS_PER_CURVE;
111b6a40b83f36b905cf85e2e3dcd88d6423938b505senorblanco    } else if (d <= tol) {
1129d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        return 1;
1139d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    } else {
11480ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed        SkScalar divSqrt = SkScalarSqrt(d / tol);
1155a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel        if (((SkScalar)SK_MaxS32) <= divSqrt) {
1165a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            return MAX_POINTS_PER_CURVE;
1175a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel        } else {
11880ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            int temp = SkScalarCeilToInt(SkScalarSqrt(d / tol));
1195a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            int pow2 = GrNextPow2(temp);
1205a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // Because of NaNs & INFs we can wind up with a degenerate temp
1215a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // such that pow2 comes out negative. Also, our point generator
1225a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            // will always output at least one pt.
1235a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            if (pow2 < 1) {
1245a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel                pow2 = 1;
1255a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            }
1265a23a14b1fbc7503bdeff83e4b45ae7c258c6e96egdaniel            return SkTMin(pow2, MAX_POINTS_PER_CURVE);
12761f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com        }
1289d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
1299d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
1309d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
131972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orguint32_t GrPathUtils::generateCubicPoints(const SkPoint& p0,
132972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                          const SkPoint& p1,
133972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                          const SkPoint& p2,
134972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                          const SkPoint& p3,
13581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                          SkScalar tolSqd,
136972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org                                          SkPoint** points,
137c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com                                          uint32_t pointsLeft) {
1389d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    if (pointsLeft < 2 ||
1399d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
1409d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org         p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
141f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips        (*points)[0] = p3;
142f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips        *points += 1;
143f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips        return 1;
144f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips    }
145972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint q[] = {
14681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
14781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
14881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
1499d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    };
150972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint r[] = {
15181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
15281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
1539d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    };
154972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
1559d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    pointsLeft >>= 1;
1569d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    uint32_t a = generateCubicPoints(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
1579d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    uint32_t b = generateCubicPoints(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
1589d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    return a + b;
1599d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
1609d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1618d033a1b125886c62906d975b5cc28a382064526bsalomon@google.comint GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths,
16281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com                                     SkScalar tol) {
163c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    if (tol < gMinCurveTol) {
164afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com        tol = gMinCurveTol;
165c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    }
166f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(tol > 0);
167c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
1689d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    int pointCount = 0;
1699d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    *subpaths = 1;
1709d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1719d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    bool first = true;
1729d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
173129b8e3237b80b9d258a8f48e8f54c0073cafbdcsenorblanco@chromium.org    SkPath::Iter iter(path, false);
17494b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com    SkPath::Verb verb;
1759d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
176972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    SkPoint pts[4];
17794b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
1789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
17994b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        switch (verb) {
18094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kLine_Verb:
1819d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                pointCount += 1;
1829d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
183af18a09d13611526c4217656c98947f9067cb07aegdaniel            case SkPath::kConic_Verb: {
184af18a09d13611526c4217656c98947f9067cb07aegdaniel                SkScalar weight = iter.conicWeight();
185af18a09d13611526c4217656c98947f9067cb07aegdaniel                SkAutoConicToQuads converter;
186af18a09d13611526c4217656c98947f9067cb07aegdaniel                const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
187af18a09d13611526c4217656c98947f9067cb07aegdaniel                for (int i = 0; i < converter.countQuads(); ++i) {
188af18a09d13611526c4217656c98947f9067cb07aegdaniel                    pointCount += quadraticPointCount(quadPts + 2*i, tol);
189af18a09d13611526c4217656c98947f9067cb07aegdaniel                }
190af18a09d13611526c4217656c98947f9067cb07aegdaniel            }
19194b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kQuad_Verb:
1929d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                pointCount += quadraticPointCount(pts, tol);
1939d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
19494b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kCubic_Verb:
1959d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                pointCount += cubicPointCount(pts, tol);
1969d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
19794b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            case SkPath::kMove_Verb:
1989d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                pointCount += 1;
1999d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                if (!first) {
2009d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                    ++(*subpaths);
2019d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                }
2029d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
2039d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org            default:
2049d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org                break;
2059d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        }
2069d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        first = false;
2079d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
2089d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    return pointCount;
2099d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
21069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
211972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgvoid GrPathUtils::QuadUVMatrix::set(const SkPoint qPts[3]) {
2121971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    SkMatrix m;
213dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // We want M such that M * xy_pt = uv_pt
214dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // We know M * control_pts = [0  1/2 1]
215dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    //                           [0  0   1]
216dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    //                           [1  1   1]
217f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    // And control_pts = [x0 x1 x2]
218f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //                   [y0 y1 y2]
219f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //                   [1  1  1 ]
220dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // We invert the control pt matrix and post concat to both sides to get M.
221f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    // Using the known form of the control point matrix and the result, we can
222f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    // optimize and improve precision.
223f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
224f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double x0 = qPts[0].fX;
225f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double y0 = qPts[0].fY;
226f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double x1 = qPts[1].fX;
227f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double y1 = qPts[1].fY;
228f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double x2 = qPts[2].fX;
229f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double y2 = qPts[2].fY;
230f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    double det = x0*y1 - y0*x1 + x2*y0 - y2*x0 + x1*y2 - y1*x2;
231f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
2328491d24bdc3f48f67475c12c60babb9f9dba8047skia.committer@gmail.com    if (!sk_float_isfinite(det)
233f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        || SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
234dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        // The quad is degenerate. Hopefully this is rare. Find the pts that are
235dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        // farthest apart to compute a line (unless it is really a pt).
236dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        SkScalar maxD = qPts[0].distanceToSqd(qPts[1]);
237dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        int maxEdge = 0;
238dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        SkScalar d = qPts[1].distanceToSqd(qPts[2]);
239dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        if (d > maxD) {
240dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            maxD = d;
241dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            maxEdge = 1;
242dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        }
243dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        d = qPts[2].distanceToSqd(qPts[0]);
244dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        if (d > maxD) {
245dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            maxD = d;
246dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            maxEdge = 2;
247dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        }
248dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        // We could have a tolerance here, not sure if it would improve anything
249dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        if (maxD > 0) {
250dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            // Set the matrix to give (u = 0, v = distance_to_line)
251972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            SkVector lineVec = qPts[(maxEdge + 1)%3] - qPts[maxEdge];
25220e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com            // when looking from the point 0 down the line we want positive
25320e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com            // distances to be to the left. This matches the non-degenerate
25420e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com            // case.
255972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            lineVec.setOrthog(lineVec, SkPoint::kLeft_Side);
2561971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            // first row
2571971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[0] = 0;
2581971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[1] = 0;
2591971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[2] = 0;
2601971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            // second row
2611971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[3] = lineVec.fX;
2621971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[4] = lineVec.fY;
2631971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[5] = -lineVec.dot(qPts[maxEdge]);
264dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        } else {
265dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            // It's a point. It should cover zero area. Just set the matrix such
266dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com            // that (u, v) will always be far away from the quad.
2671971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[0] = 0; fM[1] = 0; fM[2] = 100.f;
2681971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[3] = 0; fM[4] = 0; fM[5] = 100.f;
269dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com        }
270dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    } else {
271f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        double scale = 1.0/det;
272f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
273f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        // compute adjugate matrix
27487a223401d8575d398eb369f7be7afdabbdfab08robertphillips        double a2, a3, a4, a5, a6, a7, a8;
275f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a2 = x1*y2-x2*y1;
276f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
277f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a3 = y2-y0;
278f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a4 = x0-x2;
279f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a5 = x2*y0-x0*y2;
280f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
281f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a6 = y0-y1;
282f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a7 = x1-x0;
283f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        a8 = x0*y1-x1*y0;
284f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
2858491d24bdc3f48f67475c12c60babb9f9dba8047skia.committer@gmail.com        // this performs the uv_pts*adjugate(control_pts) multiply,
286f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        // then does the scale by 1/det afterwards to improve precision
287f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMScaleX] = (float)((0.5*a3 + a6)*scale);
288f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMSkewX]  = (float)((0.5*a4 + a7)*scale);
289f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMTransX] = (float)((0.5*a5 + a8)*scale);
290f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
291f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMSkewY]  = (float)(a6*scale);
292f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMScaleY] = (float)(a7*scale);
293f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMTransY] = (float)(a8*scale);
294f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
29587a223401d8575d398eb369f7be7afdabbdfab08robertphillips        // kMPersp0 & kMPersp1 should algebraically be zero
29687a223401d8575d398eb369f7be7afdabbdfab08robertphillips        m[SkMatrix::kMPersp0] = 0.0f;
29787a223401d8575d398eb369f7be7afdabbdfab08robertphillips        m[SkMatrix::kMPersp1] = 0.0f;
298f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org        m[SkMatrix::kMPersp2] = (float)((a2 + a5 + a8)*scale);
2991971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com
3001971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        // It may not be normalized to have 1.0 in the bottom right
3011971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        float m33 = m.get(SkMatrix::kMPersp2);
3021971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        if (1.f != m33) {
3031971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            m33 = 1.f / m33;
3041971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[0] = m33 * m.get(SkMatrix::kMScaleX);
3051971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[1] = m33 * m.get(SkMatrix::kMSkewX);
3061971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[2] = m33 * m.get(SkMatrix::kMTransX);
3071971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[3] = m33 * m.get(SkMatrix::kMSkewY);
3081971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[4] = m33 * m.get(SkMatrix::kMScaleY);
3091971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[5] = m33 * m.get(SkMatrix::kMTransY);
3101971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        } else {
3111971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[0] = m.get(SkMatrix::kMScaleX);
3121971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[1] = m.get(SkMatrix::kMSkewX);
3131971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[2] = m.get(SkMatrix::kMTransX);
3141971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[3] = m.get(SkMatrix::kMSkewY);
3151971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[4] = m.get(SkMatrix::kMScaleY);
3161971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com            fM[5] = m.get(SkMatrix::kMTransY);
3171971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com        }
318dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    }
31969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
32069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
321139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
322139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
323139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// k = (y2 - y0, x0 - x2, (x2 - x0)*y0 - (y2 - y0)*x0 )
324139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// l = (2*w * (y1 - y0), 2*w * (x0 - x1), 2*w * (x1*y0 - x0*y1))
325139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// m = (2*w * (y2 - y1), 2*w * (x1 - x2), 2*w * (x2*y1 - x1*y2))
326139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.orgvoid GrPathUtils::getConicKLM(const SkPoint p[3], const SkScalar weight, SkScalar klm[9]) {
327139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    const SkScalar w2 = 2.f * weight;
328139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[0] = p[2].fY - p[0].fY;
329139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[1] = p[0].fX - p[2].fX;
330139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX;
331139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
332139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[3] = w2 * (p[1].fY - p[0].fY);
333139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[4] = w2 * (p[0].fX - p[1].fX);
334139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[5] = w2 * (p[1].fX * p[0].fY - p[0].fX * p[1].fY);
335139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
336139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[6] = w2 * (p[2].fY - p[1].fY);
337139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[7] = w2 * (p[1].fX - p[2].fX);
338139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    klm[8] = w2 * (p[2].fX * p[1].fY - p[1].fX * p[2].fY);
339139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
340139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    // scale the max absolute value of coeffs to 10
341139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    SkScalar scale = 0.f;
342139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    for (int i = 0; i < 9; ++i) {
343139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org       scale = SkMaxScalar(scale, SkScalarAbs(klm[i]));
344139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    }
345139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    SkASSERT(scale > 0.f);
346139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    scale = 10.f / scale;
347139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    for (int i = 0; i < 9; ++i) {
348139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org        klm[i] *= scale;
349139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org    }
350139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org}
351139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
352139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
353139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org
35469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comnamespace {
355a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
356a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// a is the first control point of the cubic.
357a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// ab is the vector from a to the second control point.
358a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// dc is the vector from the fourth to the third control point.
359a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// d is the fourth control point.
360a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// p is the candidate quadratic control point.
361a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com// this assumes that the cubic doesn't inflect and is simple
362a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.combool is_point_within_cubic_tangents(const SkPoint& a,
363a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                    const SkVector& ab,
364a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                    const SkVector& dc,
365a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                    const SkPoint& d,
366026beb52a29a620290fcfb24f1e7e9e75547b80freed                                    SkPathPriv::FirstDirection dir,
367a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                    const SkPoint p) {
368a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkVector ap = p - a;
369a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkScalar apXab = ap.cross(ab);
370026beb52a29a620290fcfb24f1e7e9e75547b80freed    if (SkPathPriv::kCW_FirstDirection == dir) {
371a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (apXab > 0) {
372a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return false;
373a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
374a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    } else {
375026beb52a29a620290fcfb24f1e7e9e75547b80freed        SkASSERT(SkPathPriv::kCCW_FirstDirection == dir);
376a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (apXab < 0) {
377a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return false;
378a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
379a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
380a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
381a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkVector dp = p - d;
382a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkScalar dpXdc = dp.cross(dc);
383026beb52a29a620290fcfb24f1e7e9e75547b80freed    if (SkPathPriv::kCW_FirstDirection == dir) {
384a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (dpXdc < 0) {
385a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return false;
386a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
387a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    } else {
388026beb52a29a620290fcfb24f1e7e9e75547b80freed        SkASSERT(SkPathPriv::kCCW_FirstDirection == dir);
389a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (dpXdc > 0) {
390a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return false;
391a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
392a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
393a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    return true;
394a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com}
395a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
39669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comvoid convert_noninflect_cubic_to_quads(const SkPoint p[4],
397a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                       SkScalar toleranceSqd,
398a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                       bool constrainWithinTangents,
399026beb52a29a620290fcfb24f1e7e9e75547b80freed                                       SkPathPriv::FirstDirection dir,
40069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                                       SkTArray<SkPoint, true>* quads,
40169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                                       int sublevel = 0) {
40254ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com
40354ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    // Notation: Point a is always p[0]. Point b is p[1] unless p[1] == p[0], in which case it is
40454ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@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].
40554ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com
406a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkVector ab = p[1] - p[0];
407a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkVector dc = p[2] - p[3];
408a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
409f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips    if (ab.lengthSqd() < SK_ScalarNearlyZero) {
410f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips        if (dc.lengthSqd() < SK_ScalarNearlyZero) {
411a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkPoint* degQuad = quads->push_back_n(3);
412a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            degQuad[0] = p[0];
413a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            degQuad[1] = p[0];
414a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            degQuad[2] = p[3];
415a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return;
416a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
417a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        ab = p[2] - p[0];
418a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
419f08ce6cd53c5607ed068f755036b062a8693a8dcrobertphillips    if (dc.lengthSqd() < SK_ScalarNearlyZero) {
420a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        dc = p[1] - p[3];
421a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    }
422a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
4233935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // When the ab and cd tangents are degenerate or nearly parallel with vector from d to a the
4243935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // constraint that the quad point falls between the tangents becomes hard to enforce and we are
4253935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // likely to hit the max subdivision count. However, in this case the cubic is approaching a
4263935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // line and the accuracy of the quad point isn't so important. We check if the two middle cubic
4273935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // control points are very close to the baseline vector. If so then we just pick quadratic
4283935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon    // points on the control polygon.
42954ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com
43054ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    if (constrainWithinTangents) {
43154ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com        SkVector da = p[0] - p[3];
4323935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon        bool doQuads = dc.lengthSqd() < SK_ScalarNearlyZero ||
4333935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                       ab.lengthSqd() < SK_ScalarNearlyZero;
4343935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon        if (!doQuads) {
4353935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            SkScalar invDALengthSqd = da.lengthSqd();
4363935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            if (invDALengthSqd > SK_ScalarNearlyZero) {
4373935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                invDALengthSqd = SkScalarInvert(invDALengthSqd);
4383935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                // cross(ab, da)^2/length(da)^2 == sqd distance from b to line from d to a.
4393935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                // same goes for point c using vector cd.
4403935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                SkScalar detABSqd = ab.cross(da);
4413935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                detABSqd = SkScalarSquare(detABSqd);
4423935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                SkScalar detDCSqd = dc.cross(da);
4433935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                detDCSqd = SkScalarSquare(detDCSqd);
4443935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                if (SkScalarMul(detABSqd, invDALengthSqd) < toleranceSqd &&
4453935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                    SkScalarMul(detDCSqd, invDALengthSqd) < toleranceSqd) {
4463935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                    doQuads = true;
44754ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com                }
44854ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com            }
44954ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com        }
4503935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon        if (doQuads) {
4513935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            SkPoint b = p[0] + ab;
4523935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            SkPoint c = p[3] + dc;
4533935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            SkPoint mid = b + c;
4543935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            mid.scale(SK_ScalarHalf);
4553935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            // Insert two quadratics to cover the case when ab points away from d and/or dc
4563935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            // points away from a.
4573935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            if (SkVector::DotProduct(da, dc) < 0 || SkVector::DotProduct(ab,da) > 0) {
4583935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                SkPoint* qpts = quads->push_back_n(6);
4593935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[0] = p[0];
4603935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[1] = b;
4613935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[2] = mid;
4623935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[3] = mid;
4633935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[4] = c;
4643935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[5] = p[3];
4653935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            } else {
4663935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                SkPoint* qpts = quads->push_back_n(3);
4673935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[0] = p[0];
4683935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[1] = mid;
4693935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon                qpts[2] = p[3];
4703935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            }
4713935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon            return;
4723935a7bfe64293edf9b06527f59d657ff4e280cbbsalomon        }
47354ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    }
47454ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com
475a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    static const SkScalar kLengthScale = 3 * SK_Scalar1 / 2;
47669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    static const int kMaxSubdivs = 10;
47769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
478a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    ab.scale(kLengthScale);
479a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    dc.scale(kLengthScale);
48069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
481a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    // e0 and e1 are extrapolations along vectors ab and dc.
48269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    SkVector c0 = p[0];
48369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    c0 += ab;
48469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    SkVector c1 = p[3];
48569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    c1 += dc;
48669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
48754ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com    SkScalar dSqd = sublevel > kMaxSubdivs ? 0 : c0.distanceToSqd(c1);
488a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    if (dSqd < toleranceSqd) {
48969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        SkPoint cAvg = c0;
49069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        cAvg += c1;
49169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        cAvg.scale(SK_ScalarHalf);
49269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
493a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        bool subdivide = false;
494a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
495a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (constrainWithinTangents &&
496a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            !is_point_within_cubic_tangents(p[0], ab, dc, p[3], dir, cAvg)) {
49754ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com            // choose a new cAvg that is the intersection of the two tangent lines.
498a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            ab.setOrthog(ab);
499a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkScalar z0 = -ab.dot(p[0]);
500a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            dc.setOrthog(dc);
501a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkScalar z1 = -dc.dot(p[3]);
502a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            cAvg.fX = SkScalarMul(ab.fY, z1) - SkScalarMul(z0, dc.fY);
503a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            cAvg.fY = SkScalarMul(z0, dc.fX) - SkScalarMul(ab.fX, z1);
504a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkScalar z = SkScalarMul(ab.fX, dc.fY) - SkScalarMul(ab.fY, dc.fX);
505a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            z = SkScalarInvert(z);
506a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            cAvg.fX *= z;
507a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            cAvg.fY *= z;
508a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            if (sublevel <= kMaxSubdivs) {
509a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                SkScalar d0Sqd = c0.distanceToSqd(cAvg);
510a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                SkScalar d1Sqd = c1.distanceToSqd(cAvg);
51154ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com                // We need to subdivide if d0 + d1 > tolerance but we have the sqd values. We know
51254ad851361c55466f1e4950585afc2aa6cf173c5bsalomon@google.com                // the distances and tolerance can't be negative.
513a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                // (d0 + d1)^2 > toleranceSqd
514a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                // d0Sqd + 2*d0*d1 + d1Sqd > toleranceSqd
515a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                SkScalar d0d1 = SkScalarSqrt(SkScalarMul(d0Sqd, d1Sqd));
516a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                subdivide = 2 * d0d1 + d0Sqd + d1Sqd > toleranceSqd;
517a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            }
518a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
519a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        if (!subdivide) {
520a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            SkPoint* pts = quads->push_back_n(3);
521a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            pts[0] = p[0];
522a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            pts[1] = cAvg;
523a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            pts[2] = p[3];
524a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com            return;
525a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com        }
52669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
527a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkPoint choppedPts[7];
528a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    SkChopCubicAtHalf(p, choppedPts);
529a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    convert_noninflect_cubic_to_quads(choppedPts + 0,
530a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      toleranceSqd,
531a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      constrainWithinTangents,
532a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      dir,
533a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      quads,
534a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      sublevel + 1);
535a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com    convert_noninflect_cubic_to_quads(choppedPts + 3,
536a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      toleranceSqd,
537a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      constrainWithinTangents,
538a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      dir,
539a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      quads,
540a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com                                      sublevel + 1);
54169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
54269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
54369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
544972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgvoid GrPathUtils::convertCubicToQuads(const SkPoint p[4],
54569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                                      SkScalar tolScale,
54669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com                                      SkTArray<SkPoint, true>* quads) {
54769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    SkPoint chopped[10];
54869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    int count = SkChopCubicAtInflections(p, chopped);
54969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
55018fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    const SkScalar tolSqd = SkScalarSquare(tolScale);
551a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com
55269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    for (int i = 0; i < count; ++i) {
55369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com        SkPoint* cubic = chopped + 3*i;
55418fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon        // The direction param is ignored if the third param is false.
55518fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon        convert_noninflect_cubic_to_quads(cubic, tolSqd, false,
55618fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon                                          SkPathPriv::kCCW_FirstDirection, quads);
55769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    }
55818fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon}
55918fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon
56018fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomonvoid GrPathUtils::convertCubicToQuadsConstrainToTangents(const SkPoint p[4],
56118fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon                                                         SkScalar tolScale,
56218fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon                                                         SkPathPriv::FirstDirection dir,
56318fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon                                                         SkTArray<SkPoint, true>* quads) {
56418fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    SkPoint chopped[10];
56518fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    int count = SkChopCubicAtInflections(p, chopped);
56669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com
56718fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    const SkScalar tolSqd = SkScalarSquare(tolScale);
56818fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon
56918fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    for (int i = 0; i < count; ++i) {
57018fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon        SkPoint* cubic = chopped + 3*i;
57118fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon        convert_noninflect_cubic_to_quads(cubic, tolSqd, true, dir, quads);
57218fab30d7c4858ef2521e0380573aac5a21b2ed9bsalomon    }
57369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}
574858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
575858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
576858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
577858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// Solves linear system to extract klm
578858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// P.K = k (similarly for l, m)
579858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// Where P is matrix of control points
580858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// K is coefficients for the line K
581858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// k is vector of values of K evaluated at the control points
582858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// Solving for K, thus K = P^(-1) . k
583858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void calc_cubic_klm(const SkPoint p[4], const SkScalar controlK[4],
584858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                           const SkScalar controlL[4], const SkScalar controlM[4],
585858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                           SkScalar k[3], SkScalar l[3], SkScalar m[3]) {
586858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkMatrix matrix;
587858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    matrix.setAll(p[0].fX, p[0].fY, 1.f,
588858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                  p[1].fX, p[1].fY, 1.f,
589858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                  p[2].fX, p[2].fY, 1.f);
590858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkMatrix inverse;
591858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    if (matrix.invert(&inverse)) {
592858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org       inverse.mapHomogeneousPoints(k, controlK, 1);
593858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org       inverse.mapHomogeneousPoints(l, controlL, 1);
594858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org       inverse.mapHomogeneousPoints(m, controlM, 1);
595858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
596858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
597858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
598858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
599858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void set_serp_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) {
600858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar tempSqrt = SkScalarSqrt(9.f * d[1] * d[1] - 12.f * d[0] * d[2]);
601858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar ls = 3.f * d[1] - tempSqrt;
602858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar lt = 6.f * d[0];
603858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar ms = 3.f * d[1] + tempSqrt;
604858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar mt = 6.f * d[0];
605858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
606858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[0] = ls * ms;
607858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[1] = (3.f * ls * ms - ls * mt - lt * ms) / 3.f;
608858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[2] = (lt * (mt - 2.f * ms) + ls * (3.f * ms - 2.f * mt)) / 3.f;
609858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[3] = (lt - ls) * (mt - ms);
610858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
611858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[0] = ls * ls * ls;
612858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar lt_ls = lt - ls;
613858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[1] = ls * ls * lt_ls * -1.f;
614858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[2] = lt_ls * lt_ls * ls;
615858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[3] = -1.f * lt_ls * lt_ls * lt_ls;
616858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
617858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[0] = ms * ms * ms;
618858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar mt_ms = mt - ms;
619858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[1] = ms * ms * mt_ms * -1.f;
620858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[2] = mt_ms * mt_ms * ms;
621858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[3] = -1.f * mt_ms * mt_ms * mt_ms;
622858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
623858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // If d0 < 0 we need to flip the orientation of our curve
624858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // This is done by negating the k and l values
625858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // We want negative distance values to be on the inside
626858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    if ( d[0] > 0) {
627858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        for (int i = 0; i < 4; ++i) {
628858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            k[i] = -k[i];
629858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            l[i] = -l[i];
630858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
631858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
632858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
633858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
634858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void set_loop_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) {
635858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]);
636858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar ls = d[1] - tempSqrt;
637858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar lt = 2.f * d[0];
638858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar ms = d[1] + tempSqrt;
639858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar mt = 2.f * d[0];
640858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
641858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[0] = ls * ms;
642858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[1] = (3.f * ls*ms - ls * mt - lt * ms) / 3.f;
643858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[2] = (lt * (mt - 2.f * ms) + ls * (3.f * ms - 2.f * mt)) / 3.f;
644858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[3] = (lt - ls) * (mt - ms);
645858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
646858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[0] = ls * ls * ms;
647858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[1] = (ls * (ls * (mt - 3.f * ms) + 2.f * lt * ms))/-3.f;
648858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[2] = ((lt - ls) * (ls * (2.f * mt - 3.f * ms) + lt * ms))/3.f;
649858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[3] = -1.f * (lt - ls) * (lt - ls) * (mt - ms);
650858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
651858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[0] = ls * ms * ms;
652858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[1] = (ms * (ls * (2.f * mt - 3.f * ms) + lt * ms))/-3.f;
653858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[2] = ((mt - ms) * (ls * (mt - 3.f * ms) + 2.f * lt * ms))/3.f;
654858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[3] = -1.f * (lt - ls) * (mt - ms) * (mt - ms);
655858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
656858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
657858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // If (d0 < 0 && sign(k1) > 0) || (d0 > 0 && sign(k1) < 0),
658858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // we need to flip the orientation of our curve.
659858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // This is done by negating the k and l values
66007e1c3fd5030869c480c15ff30d36bd161718262commit-bot@chromium.org    if ( (d[0] < 0 && k[1] > 0) || (d[0] > 0 && k[1] < 0)) {
661858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        for (int i = 0; i < 4; ++i) {
662858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            k[i] = -k[i];
663858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            l[i] = -l[i];
664858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
665858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
666858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
667858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
668858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void set_cusp_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) {
669858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar ls = d[2];
670858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar lt = 3.f * d[1];
671858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
672858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[0] = ls;
673858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[1] = ls - lt / 3.f;
674858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[2] = ls - 2.f * lt / 3.f;
675858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[3] = ls - lt;
676858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
677858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[0] = ls * ls * ls;
678858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    const SkScalar ls_lt = ls - lt;
679858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[1] = ls * ls * ls_lt;
680858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[2] = ls_lt * ls_lt * ls;
681858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[3] = ls_lt * ls_lt * ls_lt;
682858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
683858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[0] = 1.f;
684858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[1] = 1.f;
685858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[2] = 1.f;
686858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[3] = 1.f;
687858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
688858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
689858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// For the case when a cubic is actually a quadratic
690858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// M =
691858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// 0     0     0
692858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// 1/3   0     1/3
693858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// 2/3   1/3   2/3
694858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org// 1     1     1
695858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgstatic void set_quadratic_klm(const SkScalar d[3], SkScalar k[4], SkScalar l[4], SkScalar m[4]) {
696858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[0] = 0.f;
697858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[1] = 1.f/3.f;
698858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[2] = 2.f/3.f;
699858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    k[3] = 1.f;
700858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
701858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[0] = 0.f;
702858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[1] = 0.f;
703858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[2] = 1.f/3.f;
704858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    l[3] = 1.f;
705858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
706858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[0] = 0.f;
707858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[1] = 1.f/3.f;
708858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[2] = 2.f/3.f;
709858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    m[3] = 1.f;
710858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
711858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // If d2 < 0 we need to flip the orientation of our curve
712858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // This is done by negating the k and l values
713858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    if ( d[2] > 0) {
714858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        for (int i = 0; i < 4; ++i) {
715858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            k[i] = -k[i];
716858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            l[i] = -l[i];
717858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
718858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
719858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
720858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
721858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgint GrPathUtils::chopCubicAtLoopIntersection(const SkPoint src[4], SkPoint dst[10], SkScalar klm[9],
722858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                                             SkScalar klm_rev[3]) {
723858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    // Variable to store the two parametric values at the loop double point
724858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar smallS = 0.f;
725858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar largeS = 0.f;
726858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
727858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar d[3];
7288dd31cf69e24ff82865309781107dfab948b6a02caryclark    SkCubicType cType = SkClassifyCubic(src, d);
729858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
730858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    int chop_count = 0;
7318dd31cf69e24ff82865309781107dfab948b6a02caryclark    if (kLoop_SkCubicType == cType) {
732858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]);
733858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar ls = d[1] - tempSqrt;
734858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar lt = 2.f * d[0];
735858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar ms = d[1] + tempSqrt;
736858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar mt = 2.f * d[0];
737858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        ls = ls / lt;
738858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        ms = ms / mt;
739858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        // need to have t values sorted since this is what is expected by SkChopCubicAt
740858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (ls <= ms) {
741858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            smallS = ls;
742858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            largeS = ms;
743858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        } else {
744858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            smallS = ms;
745858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            largeS = ls;
746858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
747858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
748858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar chop_ts[2];
749858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (smallS > 0.f && smallS < 1.f) {
750858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            chop_ts[chop_count++] = smallS;
751858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
752858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (largeS > 0.f && largeS < 1.f) {
753858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            chop_ts[chop_count++] = largeS;
754858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
755858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if(dst) {
756858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            SkChopCubicAt(src, dst, chop_ts, chop_count);
757858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
758858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    } else {
759858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (dst) {
760858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            memcpy(dst, src, sizeof(SkPoint) * 4);
761858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
762858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
763858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
764858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    if (klm && klm_rev) {
765858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        // Set klm_rev to to match the sub_section of cubic that needs to have its orientation
766858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        // flipped. This will always be the section that is the "loop"
767858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        if (2 == chop_count) {
768858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            klm_rev[0] = 1.f;
769858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            klm_rev[1] = -1.f;
770858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            klm_rev[2] = 1.f;
771858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        } else if (1 == chop_count) {
772858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            if (smallS < 0.f) {
773858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[0] = -1.f;
774858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[1] = 1.f;
775858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            } else {
776858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[0] = 1.f;
777858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[1] = -1.f;
778858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            }
779858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        } else {
780858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            if (smallS < 0.f && largeS > 1.f) {
781858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[0] = -1.f;
782858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            } else {
783858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org                klm_rev[0] = 1.f;
784858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            }
785858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
786858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar controlK[4];
787858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar controlL[4];
788858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkScalar controlM[4];
789858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
7908dd31cf69e24ff82865309781107dfab948b6a02caryclark        if (kSerpentine_SkCubicType == cType || (kCusp_SkCubicType == cType && 0.f != d[0])) {
791858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            set_serp_klm(d, controlK, controlL, controlM);
7928dd31cf69e24ff82865309781107dfab948b6a02caryclark        } else if (kLoop_SkCubicType == cType) {
793858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            set_loop_klm(d, controlK, controlL, controlM);
7948dd31cf69e24ff82865309781107dfab948b6a02caryclark        } else if (kCusp_SkCubicType == cType) {
795858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            SkASSERT(0.f == d[0]);
796858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            set_cusp_klm(d, controlK, controlL, controlM);
7978dd31cf69e24ff82865309781107dfab948b6a02caryclark        } else if (kQuadratic_SkCubicType == cType) {
798858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org            set_quadratic_klm(d, controlK, controlL, controlM);
799858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        }
800858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
801858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        calc_cubic_klm(src, controlK, controlL, controlM, klm, &klm[3], &klm[6]);
802858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
803858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    return chop_count + 1;
804858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
805858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
806858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.orgvoid GrPathUtils::getCubicKLM(const SkPoint p[4], SkScalar klm[9]) {
807858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar d[3];
8088dd31cf69e24ff82865309781107dfab948b6a02caryclark    SkCubicType cType = SkClassifyCubic(p, d);
809858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
810858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar controlK[4];
811858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar controlL[4];
812858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    SkScalar controlM[4];
813858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
8148dd31cf69e24ff82865309781107dfab948b6a02caryclark    if (kSerpentine_SkCubicType == cType || (kCusp_SkCubicType == cType && 0.f != d[0])) {
815858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        set_serp_klm(d, controlK, controlL, controlM);
8168dd31cf69e24ff82865309781107dfab948b6a02caryclark    } else if (kLoop_SkCubicType == cType) {
817858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        set_loop_klm(d, controlK, controlL, controlM);
8188dd31cf69e24ff82865309781107dfab948b6a02caryclark    } else if (kCusp_SkCubicType == cType) {
819858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        SkASSERT(0.f == d[0]);
820858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        set_cusp_klm(d, controlK, controlL, controlM);
8218dd31cf69e24ff82865309781107dfab948b6a02caryclark    } else if (kQuadratic_SkCubicType == cType) {
822858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org        set_quadratic_klm(d, controlK, controlL, controlM);
823858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    }
824858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org
825858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org    calc_cubic_klm(p, controlK, controlL, controlM, klm, &klm[3], &klm[6]);
826858638d8a5bef8f9940ccec2346a9bcc5f804979commit-bot@chromium.org}
827