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:
caryclark 2015-07-14 11:19:26 -07:00 committed by Commit bot
parent 5ca41c1647
commit e8c5666e03
4 changed files with 84 additions and 16 deletions

View File

@ -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]);
};

View File

@ -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) {

View File

@ -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;

View File

@ -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);