Very tiny paths are subsumed by the Convexicator
and are treated as convex when they are not. Allow the SkPath::Iter to leave degenerate path segments unmolested by passing an additional exact bool to next(). Treat any non-zero length as significant in addPt(). R=reed@google.com,robertphillips@google.com BUG=493450 Review URL: https://codereview.chromium.org/1228383002
This commit is contained in:
parent
5ca41c1647
commit
e8c5666e03
@ -206,8 +206,8 @@ public:
|
||||
|
||||
@return true if the line is of zero length; otherwise false.
|
||||
*/
|
||||
static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) {
|
||||
return p1.equalsWithinTolerance(p2);
|
||||
static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact) {
|
||||
return exact ? p1 == p2 : p1.equalsWithinTolerance(p2);
|
||||
}
|
||||
|
||||
/** Test a quad for zero length
|
||||
@ -215,8 +215,8 @@ public:
|
||||
@return true if the quad is of zero length; otherwise false.
|
||||
*/
|
||||
static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
|
||||
const SkPoint& p3) {
|
||||
return p1.equalsWithinTolerance(p2) &&
|
||||
const SkPoint& p3, bool exact) {
|
||||
return exact ? p1 == p2 && p2 == p3 : p1.equalsWithinTolerance(p2) &&
|
||||
p2.equalsWithinTolerance(p3);
|
||||
}
|
||||
|
||||
@ -225,8 +225,8 @@ public:
|
||||
@return true if the cubic is of zero length; otherwise false.
|
||||
*/
|
||||
static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
|
||||
const SkPoint& p3, const SkPoint& p4) {
|
||||
return p1.equalsWithinTolerance(p2) &&
|
||||
const SkPoint& p3, const SkPoint& p4, bool exact) {
|
||||
return exact ? p1 == p2 && p2 == p3 && p3 == p4 : p1.equalsWithinTolerance(p2) &&
|
||||
p2.equalsWithinTolerance(p3) &&
|
||||
p3.equalsWithinTolerance(p4);
|
||||
}
|
||||
@ -800,11 +800,15 @@ public:
|
||||
@param pts The points representing the current verb and/or segment
|
||||
@param doConsumeDegerates If true, first scan for segments that are
|
||||
deemed degenerate (too short) and skip those.
|
||||
@param exact if doConsumeDegenerates is true and exact is true, skip only
|
||||
degenerate elements with lengths exactly equal to zero. If exact
|
||||
is false, skip degenerate elements with lengths close to zero. If
|
||||
doConsumeDegenerates is false, exact has no effect.
|
||||
@return The verb for the current segment
|
||||
*/
|
||||
Verb next(SkPoint pts[4], bool doConsumeDegerates = true) {
|
||||
Verb next(SkPoint pts[4], bool doConsumeDegerates = true, bool exact = false) {
|
||||
if (doConsumeDegerates) {
|
||||
this->consumeDegenerateSegments();
|
||||
this->consumeDegenerateSegments(exact);
|
||||
}
|
||||
return this->doNext(pts);
|
||||
}
|
||||
@ -844,7 +848,7 @@ public:
|
||||
|
||||
inline const SkPoint& cons_moveTo();
|
||||
Verb autoClose(SkPoint pts[2]);
|
||||
void consumeDegenerateSegments();
|
||||
void consumeDegenerateSegments(bool exact);
|
||||
Verb doNext(SkPoint pts[4]);
|
||||
};
|
||||
|
||||
|
@ -1612,7 +1612,7 @@ const SkPoint& SkPath::Iter::cons_moveTo() {
|
||||
}
|
||||
}
|
||||
|
||||
void SkPath::Iter::consumeDegenerateSegments() {
|
||||
void SkPath::Iter::consumeDegenerateSegments(bool exact) {
|
||||
// We need to step over anything that will not move the current draw point
|
||||
// forward before the next move is seen
|
||||
const uint8_t* lastMoveVerb = 0;
|
||||
@ -1643,7 +1643,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
|
||||
break;
|
||||
|
||||
case kLine_Verb:
|
||||
if (!IsLineDegenerate(lastPt, fPts[0])) {
|
||||
if (!IsLineDegenerate(lastPt, fPts[0], exact)) {
|
||||
if (lastMoveVerb) {
|
||||
fVerbs = lastMoveVerb;
|
||||
fPts = lastMovePt;
|
||||
@ -1659,7 +1659,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
|
||||
|
||||
case kConic_Verb:
|
||||
case kQuad_Verb:
|
||||
if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) {
|
||||
if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1], exact)) {
|
||||
if (lastMoveVerb) {
|
||||
fVerbs = lastMoveVerb;
|
||||
fPts = lastMovePt;
|
||||
@ -1675,7 +1675,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
|
||||
break;
|
||||
|
||||
case kCubic_Verb:
|
||||
if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2])) {
|
||||
if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2], exact)) {
|
||||
if (lastMoveVerb) {
|
||||
fVerbs = lastMoveVerb;
|
||||
fPts = lastMovePt;
|
||||
@ -2116,7 +2116,7 @@ struct Convexicator {
|
||||
SkScalar lengthSqd = vec.lengthSqd();
|
||||
if (!SkScalarIsFinite(lengthSqd)) {
|
||||
fIsFinite = false;
|
||||
} else if (!SkScalarNearlyZero(lengthSqd, SK_ScalarNearlyZero*SK_ScalarNearlyZero)) {
|
||||
} else if (lengthSqd) {
|
||||
fPriorPt = fLastPt;
|
||||
fLastPt = fCurrPt;
|
||||
fCurrPt = pt;
|
||||
@ -2253,7 +2253,7 @@ SkPath::Convexity SkPath::internalGetConvexity() const {
|
||||
if (!isFinite()) {
|
||||
return kUnknown_Convexity;
|
||||
}
|
||||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
while ((verb = iter.next(pts, true, true)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case kMove_Verb:
|
||||
if (++contourCount > 1) {
|
||||
|
@ -356,7 +356,7 @@ void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) {
|
||||
}
|
||||
|
||||
void SkPathStroker::lineTo(const SkPoint& currPt) {
|
||||
if (SkPath::IsLineDegenerate(fPrevPt, currPt)) {
|
||||
if (SkPath::IsLineDegenerate(fPrevPt, currPt, false)) {
|
||||
return;
|
||||
}
|
||||
SkVector normal, unitNormal;
|
||||
|
@ -419,6 +419,68 @@ static void test_crbug_170666() {
|
||||
surface->getCanvas()->drawPath(path, paint);
|
||||
}
|
||||
|
||||
|
||||
static void test_tiny_path_convexity(skiatest::Reporter* reporter, const char* pathBug,
|
||||
SkScalar tx, SkScalar ty, SkScalar scale) {
|
||||
SkPath smallPath;
|
||||
SkAssertResult(SkParsePath::FromSVGString(pathBug, &smallPath));
|
||||
bool smallConvex = smallPath.isConvex();
|
||||
SkPath largePath;
|
||||
SkAssertResult(SkParsePath::FromSVGString(pathBug, &largePath));
|
||||
SkMatrix matrix;
|
||||
matrix.reset();
|
||||
matrix.preTranslate(100, 100);
|
||||
matrix.preScale(scale, scale);
|
||||
largePath.transform(matrix);
|
||||
bool largeConvex = largePath.isConvex();
|
||||
REPORTER_ASSERT(reporter, smallConvex == largeConvex);
|
||||
}
|
||||
|
||||
static void test_crbug_493450(skiatest::Reporter* reporter) {
|
||||
const char reducedCase[] =
|
||||
"M0,0"
|
||||
"L0.0002, 0"
|
||||
"L0.0002, 0.0002"
|
||||
"L0.0001, 0.0001"
|
||||
"L0,0.0002"
|
||||
"Z";
|
||||
test_tiny_path_convexity(reporter, reducedCase, 100, 100, 100000);
|
||||
const char originalFiddleData[] =
|
||||
"M-0.3383152268862998,-0.11217565719203619L-0.33846085183212765,-0.11212264406895281"
|
||||
"L-0.338509393480737,-0.11210607966681395L-0.33857792286700894,-0.1121889121487573"
|
||||
"L-0.3383866116636664,-0.11228834570924921L-0.33842087635680235,-0.11246078673250548"
|
||||
"L-0.33809536177201055,-0.11245415228342878L-0.33797257995493996,-0.11216571641452182"
|
||||
"L-0.33802112160354925,-0.11201996164188659L-0.33819815585141844,-0.11218559834671019Z";
|
||||
test_tiny_path_convexity(reporter, originalFiddleData, 280081.4116670522f, 93268.04618493588f,
|
||||
826357.3384828606f);
|
||||
}
|
||||
|
||||
static void test_crbug_495894(skiatest::Reporter* reporter) {
|
||||
const char originalFiddleData[] =
|
||||
"M-0.34004273849857214,-0.11332803232216355L-0.34008271397389744,-0.11324483772714951"
|
||||
"L-0.3401940742265893,-0.11324483772714951L-0.34017694188002134,-0.11329807920275889"
|
||||
"L-0.3402026403998733,-0.11333468903941245L-0.34029972369709194,-0.11334134592705701"
|
||||
"L-0.3403054344792813,-0.11344121970007795L-0.3403140006525653,-0.11351115418399343"
|
||||
"L-0.34024261587519866,-0.11353446986281181L-0.3402197727464413,-0.11360442946144192"
|
||||
"L-0.34013696640469604,-0.11359110237029302L-0.34009128014718143,-0.1135877707043939"
|
||||
"L-0.3400598708451401,-0.11360776134112742L-0.34004273849857214,-0.11355112520064405"
|
||||
"L-0.3400113291965308,-0.11355112520064405L-0.3399970522410575,-0.11359110237029302"
|
||||
"L-0.33997135372120546,-0.11355112520064405L-0.3399627875479215,-0.11353780084493197"
|
||||
"L-0.3399485105924481,-0.11350782354357004L-0.3400027630232468,-0.11346452910331437"
|
||||
"L-0.3399485105924481,-0.11340126558629839L-0.33993994441916414,-0.11340126558629839"
|
||||
"L-0.33988283659727087,-0.11331804756574679L-0.33989140277055485,-0.11324483772714951"
|
||||
"L-0.33997991989448945,-0.11324483772714951L-0.3399856306766788,-0.11324483772714951"
|
||||
"L-0.34002560615200417,-0.11334467443478255ZM-0.3400684370184241,-0.11338461985124307"
|
||||
"L-0.340154098751264,-0.11341791238732665L-0.340162664924548,-0.1134378899559977"
|
||||
"L-0.34017979727111597,-0.11340126558629839L-0.3401655203156427,-0.11338129083212668"
|
||||
"L-0.34012268944922275,-0.11332137577529414L-0.34007414780061346,-0.11334467443478255Z"
|
||||
"M-0.3400027630232468,-0.11290567901106024L-0.3400113291965308,-0.11298876531245433"
|
||||
"L-0.33997991989448945,-0.11301535852306784L-0.33990282433493346,-0.11296217481488612"
|
||||
"L-0.33993994441916414,-0.11288906492739594Z";
|
||||
test_tiny_path_convexity(reporter, originalFiddleData, 22682.240000000005f,7819.72220766405f,
|
||||
65536);
|
||||
}
|
||||
|
||||
static void test_addrect(skiatest::Reporter* reporter) {
|
||||
SkPath path;
|
||||
path.lineTo(0, 0);
|
||||
@ -3758,6 +3820,8 @@ DEF_TEST(Paths, reporter) {
|
||||
test_tricky_cubic();
|
||||
test_clipped_cubic();
|
||||
test_crbug_170666();
|
||||
test_crbug_493450(reporter);
|
||||
test_crbug_495894(reporter);
|
||||
test_bad_cubic_crbug229478();
|
||||
test_bad_cubic_crbug234190();
|
||||
test_gen_id(reporter);
|
||||
|
Loading…
Reference in New Issue
Block a user