Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/pathops/SkPathOpsConic.cpp
Line
Count
Source
1
/*
2
 * Copyright 2015 Google Inc.
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
#include "src/pathops/SkPathOpsConic.h"
8
9
#include "include/core/SkTypes.h"
10
#include "include/private/base/SkFloatingPoint.h"
11
#include "src/pathops/SkIntersections.h"
12
#include "src/pathops/SkPathOpsCubic.h"
13
#include "src/pathops/SkPathOpsQuad.h"
14
#include "src/pathops/SkPathOpsRect.h"
15
#include "src/pathops/SkPathOpsTypes.h"
16
17
#include <cmath>
18
19
struct SkDLine;
20
21
// cribbed from the float version in SkGeometry.cpp
22
static void conic_deriv_coeff(const double src[],
23
                              SkScalar w,
24
49.8M
                              double coeff[3]) {
25
49.8M
    const double P20 = src[4] - src[0];
26
49.8M
    const double P10 = src[2] - src[0];
27
49.8M
    const double wP10 = w * P10;
28
49.8M
    coeff[0] = w * P20 - P20;
29
49.8M
    coeff[1] = P20 - 2 * wP10;
30
49.8M
    coeff[2] = wP10;
31
49.8M
}
32
33
41.0M
static double conic_eval_tan(const double coord[], SkScalar w, double t) {
34
41.0M
    double coeff[3];
35
41.0M
    conic_deriv_coeff(coord, w, coeff);
36
41.0M
    return t * (t * coeff[0] + coeff[1]) + coeff[2];
37
41.0M
}
38
39
8.82M
int SkDConic::FindExtrema(const double src[], SkScalar w, double t[1]) {
40
8.82M
    double coeff[3];
41
8.82M
    conic_deriv_coeff(src, w, coeff);
42
43
8.82M
    double tValues[2];
44
8.82M
    int roots = SkDQuad::RootsValidT(coeff[0], coeff[1], coeff[2], tValues);
45
    // In extreme cases, the number of roots returned can be 2. Pathops
46
    // will fail later on, so there's no advantage to plumbing in an error
47
    // return here.
48
    // SkASSERT(0 == roots || 1 == roots);
49
50
8.82M
    if (1 == roots) {
51
8.45M
        t[0] = tValues[0];
52
8.45M
        return 1;
53
8.45M
    }
54
368k
    return 0;
55
8.82M
}
56
57
20.5M
SkDVector SkDConic::dxdyAtT(double t) const {
58
20.5M
    SkDVector result = {
59
20.5M
        conic_eval_tan(&fPts[0].fX, fWeight, t),
60
20.5M
        conic_eval_tan(&fPts[0].fY, fWeight, t)
61
20.5M
    };
62
20.5M
    if (result.fX == 0 && result.fY == 0) {
63
2.38k
        if (zero_or_one(t)) {
64
1.44k
            result = fPts[2] - fPts[0];
65
1.44k
        } else {
66
            // incomplete
67
942
            SkDebugf("!k");
68
942
        }
69
2.38k
    }
70
20.5M
    return result;
71
20.5M
}
72
73
835M
static double conic_eval_numerator(const double src[], SkScalar w, double t) {
74
835M
    SkASSERT(src);
75
835M
    SkASSERT(t >= 0 && t <= 1);
76
835M
    double src2w = src[2] * w;
77
835M
    double C = src[0];
78
835M
    double A = src[4] - 2 * src2w + C;
79
835M
    double B = 2 * (src2w - C);
80
835M
    return (A * t + B) * t + C;
81
835M
}
82
83
84
417M
static double conic_eval_denominator(SkScalar w, double t) {
85
417M
    double B = 2 * (w - 1);
86
417M
    double C = 1;
87
417M
    double A = -B;
88
417M
    return (A * t + B) * t + C;
89
417M
}
90
91
2.86M
bool SkDConic::hullIntersects(const SkDCubic& cubic, bool* isLinear) const {
92
2.86M
    return cubic.hullIntersects(*this, isLinear);
93
2.86M
}
94
95
130M
SkDPoint SkDConic::ptAtT(double t) const {
96
130M
    if (t == 0) {
97
16.7M
        return fPts[0];
98
16.7M
    }
99
113M
    if (t == 1) {
100
15.6M
        return fPts[2];
101
15.6M
    }
102
97.8M
    double denominator = conic_eval_denominator(fWeight, t);
103
97.8M
    SkDPoint result = {
104
97.8M
        sk_ieee_double_divide(conic_eval_numerator(&fPts[0].fX, fWeight, t), denominator),
105
97.8M
        sk_ieee_double_divide(conic_eval_numerator(&fPts[0].fY, fWeight, t), denominator)
106
97.8M
    };
107
97.8M
    return result;
108
113M
}
109
110
/* see quad subdivide for point rationale */
111
/* w rationale : the mid point between t1 and t2 could be determined from the computed a/b/c
112
   values if the computed w was known. Since we know the mid point at (t1+t2)/2, we'll assume
113
   that it is the same as the point on the new curve t==(0+1)/2.
114
115
    d / dz == conic_poly(dst, unknownW, .5) / conic_weight(unknownW, .5);
116
117
    conic_poly(dst, unknownW, .5)
118
                  =   a / 4 + (b * unknownW) / 2 + c / 4
119
                  =  (a + c) / 4 + (bx * unknownW) / 2
120
121
    conic_weight(unknownW, .5)
122
                  =   unknownW / 2 + 1 / 2
123
124
    d / dz                  == ((a + c) / 2 + b * unknownW) / (unknownW + 1)
125
    d / dz * (unknownW + 1) ==  (a + c) / 2 + b * unknownW
126
              unknownW       = ((a + c) / 2 - d / dz) / (d / dz - b)
127
128
    Thus, w is the ratio of the distance from the mid of end points to the on-curve point, and the
129
    distance of the on-curve point to the control point.
130
 */
131
262M
SkDConic SkDConic::subDivide(double t1, double t2) const {
132
262M
    double ax, ay, az;
133
262M
    if (t1 == 0) {
134
73.6M
        ax = fPts[0].fX;
135
73.6M
        ay = fPts[0].fY;
136
73.6M
        az = 1;
137
188M
    } else if (t1 != 1) {
138
187M
        ax = conic_eval_numerator(&fPts[0].fX, fWeight, t1);
139
187M
        ay = conic_eval_numerator(&fPts[0].fY, fWeight, t1);
140
187M
        az = conic_eval_denominator(fWeight, t1);
141
187M
    } else {
142
1.22M
        ax = fPts[2].fX;
143
1.22M
        ay = fPts[2].fY;
144
1.22M
        az = 1;
145
1.22M
    }
146
262M
    double midT = (t1 + t2) / 2;
147
262M
    double dx = conic_eval_numerator(&fPts[0].fX, fWeight, midT);
148
262M
    double dy = conic_eval_numerator(&fPts[0].fY, fWeight, midT);
149
262M
    double dz = conic_eval_denominator(fWeight, midT);
150
262M
    double cx, cy, cz;
151
262M
    if (t2 == 1) {
152
71.7M
        cx = fPts[2].fX;
153
71.7M
        cy = fPts[2].fY;
154
71.7M
        cz = 1;
155
190M
    } else if (t2 != 0) {
156
189M
        cx = conic_eval_numerator(&fPts[0].fX, fWeight, t2);
157
189M
        cy = conic_eval_numerator(&fPts[0].fY, fWeight, t2);
158
189M
        cz = conic_eval_denominator(fWeight, t2);
159
189M
    } else {
160
1.68M
        cx = fPts[0].fX;
161
1.68M
        cy = fPts[0].fY;
162
1.68M
        cz = 1;
163
1.68M
    }
164
262M
    double bx = 2 * dx - (ax + cx) / 2;
165
262M
    double by = 2 * dy - (ay + cy) / 2;
166
262M
    double bz = 2 * dz - (az + cz) / 2;
167
262M
    if (!bz) {
168
47.1k
        bz = 1; // if bz is 0, weight is 0, control point has no effect: any value will do
169
47.1k
    }
170
262M
    SkDConic dst = {{{{ax / az, ay / az}, {bx / bz, by / bz}, {cx / cz, cy / cz}}
171
262M
            SkDEBUGPARAMS(fPts.fDebugGlobalState) },
172
262M
            SkDoubleToScalar(bz / sqrt(az * cz)) };
173
262M
    return dst;
174
262M
}
SkDConic::subDivide(double, double) const
Line
Count
Source
131
131M
SkDConic SkDConic::subDivide(double t1, double t2) const {
132
131M
    double ax, ay, az;
133
131M
    if (t1 == 0) {
134
36.8M
        ax = fPts[0].fX;
135
36.8M
        ay = fPts[0].fY;
136
36.8M
        az = 1;
137
94.4M
    } else if (t1 != 1) {
138
93.8M
        ax = conic_eval_numerator(&fPts[0].fX, fWeight, t1);
139
93.8M
        ay = conic_eval_numerator(&fPts[0].fY, fWeight, t1);
140
93.8M
        az = conic_eval_denominator(fWeight, t1);
141
93.8M
    } else {
142
610k
        ax = fPts[2].fX;
143
610k
        ay = fPts[2].fY;
144
610k
        az = 1;
145
610k
    }
146
131M
    double midT = (t1 + t2) / 2;
147
131M
    double dx = conic_eval_numerator(&fPts[0].fX, fWeight, midT);
148
131M
    double dy = conic_eval_numerator(&fPts[0].fY, fWeight, midT);
149
131M
    double dz = conic_eval_denominator(fWeight, midT);
150
131M
    double cx, cy, cz;
151
131M
    if (t2 == 1) {
152
35.8M
        cx = fPts[2].fX;
153
35.8M
        cy = fPts[2].fY;
154
35.8M
        cz = 1;
155
95.4M
    } else if (t2 != 0) {
156
94.6M
        cx = conic_eval_numerator(&fPts[0].fX, fWeight, t2);
157
94.6M
        cy = conic_eval_numerator(&fPts[0].fY, fWeight, t2);
158
94.6M
        cz = conic_eval_denominator(fWeight, t2);
159
94.6M
    } else {
160
841k
        cx = fPts[0].fX;
161
841k
        cy = fPts[0].fY;
162
841k
        cz = 1;
163
841k
    }
164
131M
    double bx = 2 * dx - (ax + cx) / 2;
165
131M
    double by = 2 * dy - (ay + cy) / 2;
166
131M
    double bz = 2 * dz - (az + cz) / 2;
167
131M
    if (!bz) {
168
23.5k
        bz = 1; // if bz is 0, weight is 0, control point has no effect: any value will do
169
23.5k
    }
170
131M
    SkDConic dst = {{{{ax / az, ay / az}, {bx / bz, by / bz}, {cx / cz, cy / cz}}
171
131M
            SkDEBUGPARAMS(fPts.fDebugGlobalState) },
172
131M
            SkDoubleToScalar(bz / sqrt(az * cz)) };
173
131M
    return dst;
174
131M
}
SkDConic::subDivide(double, double) const
Line
Count
Source
131
131M
SkDConic SkDConic::subDivide(double t1, double t2) const {
132
131M
    double ax, ay, az;
133
131M
    if (t1 == 0) {
134
36.8M
        ax = fPts[0].fX;
135
36.8M
        ay = fPts[0].fY;
136
36.8M
        az = 1;
137
94.4M
    } else if (t1 != 1) {
138
93.8M
        ax = conic_eval_numerator(&fPts[0].fX, fWeight, t1);
139
93.8M
        ay = conic_eval_numerator(&fPts[0].fY, fWeight, t1);
140
93.8M
        az = conic_eval_denominator(fWeight, t1);
141
93.8M
    } else {
142
610k
        ax = fPts[2].fX;
143
610k
        ay = fPts[2].fY;
144
610k
        az = 1;
145
610k
    }
146
131M
    double midT = (t1 + t2) / 2;
147
131M
    double dx = conic_eval_numerator(&fPts[0].fX, fWeight, midT);
148
131M
    double dy = conic_eval_numerator(&fPts[0].fY, fWeight, midT);
149
131M
    double dz = conic_eval_denominator(fWeight, midT);
150
131M
    double cx, cy, cz;
151
131M
    if (t2 == 1) {
152
35.8M
        cx = fPts[2].fX;
153
35.8M
        cy = fPts[2].fY;
154
35.8M
        cz = 1;
155
95.4M
    } else if (t2 != 0) {
156
94.6M
        cx = conic_eval_numerator(&fPts[0].fX, fWeight, t2);
157
94.6M
        cy = conic_eval_numerator(&fPts[0].fY, fWeight, t2);
158
94.6M
        cz = conic_eval_denominator(fWeight, t2);
159
94.6M
    } else {
160
841k
        cx = fPts[0].fX;
161
841k
        cy = fPts[0].fY;
162
841k
        cz = 1;
163
841k
    }
164
131M
    double bx = 2 * dx - (ax + cx) / 2;
165
131M
    double by = 2 * dy - (ay + cy) / 2;
166
131M
    double bz = 2 * dz - (az + cz) / 2;
167
131M
    if (!bz) {
168
23.5k
        bz = 1; // if bz is 0, weight is 0, control point has no effect: any value will do
169
23.5k
    }
170
131M
    SkDConic dst = {{{{ax / az, ay / az}, {bx / bz, by / bz}, {cx / cz, cy / cz}}
171
131M
            SkDEBUGPARAMS(fPts.fDebugGlobalState) },
172
131M
            SkDoubleToScalar(bz / sqrt(az * cz)) };
173
131M
    return dst;
174
131M
}
175
176
SkDPoint SkDConic::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, double t2,
177
3.80M
        SkScalar* weight) const {
178
3.80M
    SkDConic chopped = this->subDivide(t1, t2);
179
3.80M
    *weight = chopped.fWeight;
180
3.80M
    return chopped[1];
181
3.80M
}
182
183
69.3M
int SkTConic::intersectRay(SkIntersections* i, const SkDLine& line) const {
184
69.3M
    return i->intersectRay(fConic, line);
185
69.3M
}
186
187
5.44M
bool SkTConic::hullIntersects(const SkDQuad& quad, bool* isLinear) const  {
188
5.44M
    return quad.hullIntersects(fConic, isLinear);
189
5.44M
}
190
191
4.67M
bool SkTConic::hullIntersects(const SkDCubic& cubic, bool* isLinear) const {
192
4.67M
    return cubic.hullIntersects(fConic, isLinear);
193
4.67M
}
194
195
127M
void SkTConic::setBounds(SkDRect* rect) const {
196
127M
    rect->setBounds(fConic);
197
127M
}