blob: 274dc49a57c61c03eb9fd0fec235ba758cf5090c [file] [log] [blame]
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrPathUtils.h"
18
19#include "GrPathIter.h"
20#include "GrPoint.h"
21
22const GrScalar GrPathUtils::gTolerance = GR_Scalar1;
23
24static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;
25
26uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[],
27 GrScalar tol) {
28 GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
29 if (d < tol) {
30 return 1;
31 } else {
32 // Each time we subdivide, d should be cut in 4. So we need to
33 // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
34 // points.
35 // 2^(log4(x)) = sqrt(x);
36 d = ceilf(sqrtf(d/tol));
37 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
38 }
39}
40
41uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0,
42 const GrPoint& p1,
43 const GrPoint& p2,
44 GrScalar tolSqd,
45 GrPoint** points,
46 uint32_t pointsLeft) {
47 if (pointsLeft < 2 ||
48 (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
49 (*points)[0] = p2;
50 *points += 1;
51 return 1;
52 }
53
54 GrPoint q[] = {
55 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
56 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
57 };
58 GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY));
59
60 pointsLeft >>= 1;
61 uint32_t a = generateQuadraticPoints(p0, q[0], r, tolSqd, points, pointsLeft);
62 uint32_t b = generateQuadraticPoints(r, q[1], p2, tolSqd, points, pointsLeft);
63 return a + b;
64}
65
66uint32_t GrPathUtils::cubicPointCount(const GrPoint points[],
67 GrScalar tol) {
68 GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
69 points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
70 d = sqrtf(d);
71 if (d < tol) {
72 return 1;
73 } else {
74 d = ceilf(sqrtf(d/tol));
75 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
76 }
77}
78
79uint32_t GrPathUtils::generateCubicPoints(const GrPoint& p0,
80 const GrPoint& p1,
81 const GrPoint& p2,
82 const GrPoint& p3,
83 GrScalar tolSqd,
84 GrPoint** points,
85 uint32_t pointsLeft) {
86 if (pointsLeft < 2 ||
87 (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
88 p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
89 (*points)[0] = p3;
90 *points += 1;
91 return 1;
92 }
93 GrPoint q[] = {
94 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
95 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
96 GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY))
97 };
98 GrPoint r[] = {
99 GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)),
100 GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY))
101 };
102 GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY));
103 pointsLeft >>= 1;
104 uint32_t a = generateCubicPoints(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
105 uint32_t b = generateCubicPoints(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
106 return a + b;
107}
108
109int GrPathUtils::worstCasePointCount(GrPathIter* path,
110 int* subpaths,
111 GrScalar tol) {
112 int pointCount = 0;
113 *subpaths = 1;
114
115 bool first = true;
116
117 GrPathCmd cmd;
118
119 GrPoint pts[4];
120 while ((cmd = path->next(pts)) != kEnd_PathCmd) {
121
122 switch (cmd) {
123 case kLine_PathCmd:
124 pointCount += 1;
125 break;
126 case kQuadratic_PathCmd:
127 pointCount += quadraticPointCount(pts, tol);
128 break;
129 case kCubic_PathCmd:
130 pointCount += cubicPointCount(pts, tol);
131 break;
132 case kMove_PathCmd:
133 pointCount += 1;
134 if (!first) {
135 ++(*subpaths);
136 }
137 break;
138 default:
139 break;
140 }
141 first = false;
142 }
143 return pointCount;
144}