CCPR: Check for flat lines before crunching on curves
Bug: skia: Change-Id: Ib99f3f83aee4c261ef1cfc4e1045b2be3113e1ae Reviewed-on: https://skia-review.googlesource.com/43100 Commit-Queue: Chris Dalton <csmartdalton@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
6c251d24cf
commit
900cd05037
@ -40,6 +40,7 @@ void GrCCPRGeometry::beginContour(const SkPoint& devPt) {
|
||||
|
||||
void GrCCPRGeometry::lineTo(const SkPoint& devPt) {
|
||||
SkASSERT(fBuildingContour);
|
||||
SkASSERT(fCurrFanPoint == fPoints.back());
|
||||
fCurrFanPoint = devPt;
|
||||
fPoints.push_back(devPt);
|
||||
fVerbs.push_back(Verb::kLineTo);
|
||||
@ -56,6 +57,22 @@ static inline float dot(const Sk2f& a, const Sk2f& b) {
|
||||
return product[0] + product[1];
|
||||
}
|
||||
|
||||
static inline bool are_collinear(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2) {
|
||||
static constexpr float kFlatnessTolerance = 16; // 1/16 of a pixel.
|
||||
|
||||
// Area (times 2) of the triangle.
|
||||
Sk2f a = (p0 - p1) * SkNx_shuffle<1,0>(p1 - p2);
|
||||
a = (a - SkNx_shuffle<1,0>(a)).abs();
|
||||
|
||||
// Bounding box of the triangle.
|
||||
Sk2f bbox0 = Sk2f::Min(Sk2f::Min(p0, p1), p2);
|
||||
Sk2f bbox1 = Sk2f::Max(Sk2f::Max(p0, p1), p2);
|
||||
|
||||
// The triangle is linear if its area is within a fraction of the largest bounding box
|
||||
// dimension, or else if its area is within a fraction of a pixel.
|
||||
return (a * (kFlatnessTolerance/2) < Sk2f::Max(bbox1 - bbox0, 1)).anyTrue();
|
||||
}
|
||||
|
||||
// Returns whether the (convex) curve segment is monotonic with respect to [endPt - startPt].
|
||||
static inline bool is_convex_curve_monotonic(const Sk2f& startPt, const Sk2f& startTan,
|
||||
const Sk2f& endPt, const Sk2f& endTan) {
|
||||
@ -75,12 +92,20 @@ static inline Sk2f lerp(const Sk2f& a, const Sk2f& b, const Sk2f& t) {
|
||||
|
||||
void GrCCPRGeometry::quadraticTo(const SkPoint& devP0, const SkPoint& devP1) {
|
||||
SkASSERT(fBuildingContour);
|
||||
SkASSERT(fCurrFanPoint == fPoints.back());
|
||||
|
||||
Sk2f p0 = Sk2f::Load(&fCurrFanPoint);
|
||||
Sk2f p1 = Sk2f::Load(&devP0);
|
||||
Sk2f p2 = Sk2f::Load(&devP1);
|
||||
fCurrFanPoint = devP1;
|
||||
|
||||
// Don't send curves to the GPU if we know they are flat (or just very small).
|
||||
if (are_collinear(p0, p1, p2)) {
|
||||
p2.store(&fPoints.push_back());
|
||||
fVerbs.push_back(Verb::kLineTo);
|
||||
return;
|
||||
}
|
||||
|
||||
Sk2f tan0 = p1 - p0;
|
||||
Sk2f tan1 = p2 - p1;
|
||||
// This should almost always be this case for well-behaved curves in the real world.
|
||||
@ -230,6 +255,7 @@ static inline void calc_loop_intersect_padding_pts(float padRadius, const Sk2f&
|
||||
void GrCCPRGeometry::cubicTo(const SkPoint& devP1, const SkPoint& devP2, const SkPoint& devP3,
|
||||
float inflectPad, float loopIntersectPad) {
|
||||
SkASSERT(fBuildingContour);
|
||||
SkASSERT(fCurrFanPoint == fPoints.back());
|
||||
|
||||
SkPoint devPts[4] = {fCurrFanPoint, devP1, devP2, devP3};
|
||||
Sk2f p0 = Sk2f::Load(&fCurrFanPoint);
|
||||
@ -238,6 +264,15 @@ void GrCCPRGeometry::cubicTo(const SkPoint& devP1, const SkPoint& devP2, const S
|
||||
Sk2f p3 = Sk2f::Load(&devP3);
|
||||
fCurrFanPoint = devP3;
|
||||
|
||||
// Don't crunch on the curve and inflate geometry if it is already flat (or just very small).
|
||||
if (are_collinear(p0, p1, p2) &&
|
||||
are_collinear(p1, p2, p3) &&
|
||||
are_collinear(p0, (p1 + p2) * .5f, p3)) {
|
||||
p3.store(&fPoints.push_back());
|
||||
fVerbs.push_back(Verb::kLineTo);
|
||||
return;
|
||||
}
|
||||
|
||||
double tt[2], ss[2];
|
||||
fCurrCubicType = SkClassifyCubic(devPts, tt, ss);
|
||||
if (SkCubicIsDegenerate(fCurrCubicType)) {
|
||||
@ -251,8 +286,8 @@ void GrCCPRGeometry::cubicTo(const SkPoint& devP1, const SkPoint& devP2, const S
|
||||
if (ExcludedTerm::kNonInvertible == skipTerm) {
|
||||
// This could technically also happen if the curve were a quadratic, but SkClassifyCubic
|
||||
// should have detected that case already with tolerance.
|
||||
fCurrCubicType = SkCubicType::kLineOrPoint;
|
||||
this->appendCubicApproximation(p0, p1, p2, p3, /*maxSubdivisions=*/0);
|
||||
p3.store(&fPoints.push_back());
|
||||
fVerbs.push_back(Verb::kLineTo);
|
||||
return;
|
||||
}
|
||||
SkASSERT(0 == CIT[6]);
|
||||
|
Loading…
Reference in New Issue
Block a user