Reland of ix zero-length tangent (patchset #1 id:1 of https://codereview.chromium.org/1312243002/ )
Reason for revert: Layout suppression has landed, and verified that Skia gm test changes are correct. Original issue's description: > Revert of fix zero-length tangent (patchset #2 id:20001 of https://codereview.chromium.org/1311273002/ ) > > Reason for revert: > causes layout test to draw differently -- new drawing is more correct. Reverting until layout test ignore is landed. > > Original issue's description: > > fix zero-length tangent > > > > If the end point and the control point are the same, computing > > the tangent will result in (0, 0). In this case, use the prior > > control point instead. > > > > R=reed@google.com > > > > BUG=skia:4191 > > > > Committed: https://skia.googlesource.com/skia/+/7544124fb8ee744f68f549a353f8a9163cd7432d > > TBR=reed@google.com > NOPRESUBMIT=true > NOTREECHECKS=true > NOTRY=true > BUG=skia:4191 > > Committed: https://skia.googlesource.com/skia/+/91298b47c547b2ab4697038c04685af957bd1416 TBR=reed@google.com NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=skia:4191 Review URL: https://codereview.chromium.org/1320473002
This commit is contained in:
parent
b5fb5af573
commit
45398dff71
@ -266,6 +266,60 @@ private:
|
||||
typedef skiagm::GM INHERITED;
|
||||
};
|
||||
|
||||
// Test stroking for curves that produce degenerate tangents when t is 0 or 1 (see bug 4191)
|
||||
class Strokes5GM : public skiagm::GM {
|
||||
public:
|
||||
Strokes5GM() {}
|
||||
|
||||
protected:
|
||||
|
||||
SkString onShortName() override {
|
||||
return SkString("zero_control_stroke");
|
||||
}
|
||||
|
||||
SkISize onISize() override {
|
||||
return SkISize::Make(W, H*2);
|
||||
}
|
||||
|
||||
void onDraw(SkCanvas* canvas) override {
|
||||
SkPaint p;
|
||||
p.setColor(SK_ColorRED);
|
||||
p.setAntiAlias(true);
|
||||
p.setStyle(SkPaint::kStroke_Style);
|
||||
p.setStrokeWidth(40);
|
||||
p.setStrokeCap(SkPaint::kButt_Cap);
|
||||
|
||||
SkPath path;
|
||||
path.moveTo(157.474f,111.753f);
|
||||
path.cubicTo(128.5f,111.5f,35.5f,29.5f,35.5f,29.5f);
|
||||
canvas->drawPath(path, p);
|
||||
path.reset();
|
||||
path.moveTo(250, 50);
|
||||
path.quadTo(280, 80, 280, 80);
|
||||
canvas->drawPath(path, p);
|
||||
path.reset();
|
||||
path.moveTo(150, 50);
|
||||
path.conicTo(180, 80, 180, 80, 0.707f);
|
||||
canvas->drawPath(path, p);
|
||||
|
||||
path.reset();
|
||||
path.moveTo(157.474f,311.753f);
|
||||
path.cubicTo(157.474f,311.753f,85.5f,229.5f,35.5f,229.5f);
|
||||
canvas->drawPath(path, p);
|
||||
path.reset();
|
||||
path.moveTo(280, 250);
|
||||
path.quadTo(280, 250, 310, 280);
|
||||
canvas->drawPath(path, p);
|
||||
path.reset();
|
||||
path.moveTo(180, 250);
|
||||
path.conicTo(180, 250, 210, 280, 0.707f);
|
||||
canvas->drawPath(path, p);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef skiagm::GM INHERITED;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -273,8 +327,10 @@ static skiagm::GM* F0(void*) { return new StrokesGM; }
|
||||
static skiagm::GM* F1(void*) { return new Strokes2GM; }
|
||||
static skiagm::GM* F2(void*) { return new Strokes3GM; }
|
||||
static skiagm::GM* F3(void*) { return new Strokes4GM; }
|
||||
static skiagm::GM* F4(void*) { return new Strokes5GM; }
|
||||
|
||||
static skiagm::GMRegistry R0(F0);
|
||||
static skiagm::GMRegistry R1(F1);
|
||||
static skiagm::GMRegistry R2(F2);
|
||||
static skiagm::GMRegistry R3(F3);
|
||||
static skiagm::GMRegistry R4(F4);
|
||||
|
@ -130,13 +130,6 @@ static SkScalar eval_quad(const SkScalar src[], SkScalar t) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static SkScalar eval_quad_derivative(const SkScalar src[], SkScalar t) {
|
||||
SkScalar A = src[4] - 2 * src[2] + src[0];
|
||||
SkScalar B = src[2] - src[0];
|
||||
|
||||
return 2 * SkScalarMulAdd(A, t, B);
|
||||
}
|
||||
|
||||
void SkQuadToCoeff(const SkPoint pts[3], SkPoint coeff[3]) {
|
||||
Sk2s p0 = from_point(pts[0]);
|
||||
Sk2s p1 = from_point(pts[1]);
|
||||
@ -157,8 +150,7 @@ void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tange
|
||||
pt->set(eval_quad(&src[0].fX, t), eval_quad(&src[0].fY, t));
|
||||
}
|
||||
if (tangent) {
|
||||
tangent->set(eval_quad_derivative(&src[0].fX, t),
|
||||
eval_quad_derivative(&src[0].fY, t));
|
||||
*tangent = SkEvalQuadTangentAt(src, t);
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,6 +171,12 @@ SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) {
|
||||
}
|
||||
|
||||
SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) {
|
||||
// The derivative equation is 2(b - a +(a - 2b +c)t). This returns a
|
||||
// zero tangent vector when t is 0 or 1, and the control point is equal
|
||||
// to the end point. In this case, use the quad end points to compute the tangent.
|
||||
if ((t == 0 && src[0] == src[1]) || (t == 1 && src[1] == src[2])) {
|
||||
return src[2] - src[0];
|
||||
}
|
||||
SkASSERT(src);
|
||||
SkASSERT(t >= 0 && t <= SK_Scalar1);
|
||||
|
||||
@ -398,8 +396,22 @@ void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc,
|
||||
loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t));
|
||||
}
|
||||
if (tangent) {
|
||||
tangent->set(eval_cubic_derivative(&src[0].fX, t),
|
||||
eval_cubic_derivative(&src[0].fY, t));
|
||||
// The derivative equation returns a zero tangent vector when t is 0 or 1, and the
|
||||
// adjacent control point is equal to the end point. In this case, use the
|
||||
// next control point or the end points to compute the tangent.
|
||||
if ((t == 0 && src[0] == src[1]) || (t == 1 && src[2] == src[3])) {
|
||||
if (t == 0) {
|
||||
*tangent = src[2] - src[0];
|
||||
} else {
|
||||
*tangent = src[3] - src[1];
|
||||
}
|
||||
if (!tangent->fX && !tangent->fY) {
|
||||
*tangent = src[3] - src[0];
|
||||
}
|
||||
} else {
|
||||
tangent->set(eval_cubic_derivative(&src[0].fX, t),
|
||||
eval_cubic_derivative(&src[0].fY, t));
|
||||
}
|
||||
}
|
||||
if (curvature) {
|
||||
curvature->set(eval_cubic_2ndDerivative(&src[0].fX, t),
|
||||
@ -1176,12 +1188,6 @@ static void conic_deriv_coeff(const SkScalar src[],
|
||||
coeff[2] = wP10;
|
||||
}
|
||||
|
||||
static SkScalar conic_eval_tan(const SkScalar coord[], SkScalar w, SkScalar t) {
|
||||
SkScalar coeff[3];
|
||||
conic_deriv_coeff(coord, w, coeff);
|
||||
return t * (t * coeff[0] + coeff[1]) + coeff[2];
|
||||
}
|
||||
|
||||
static bool conic_find_extrema(const SkScalar src[], SkScalar w, SkScalar* t) {
|
||||
SkScalar coeff[3];
|
||||
conic_deriv_coeff(src, w, coeff);
|
||||
@ -1232,8 +1238,7 @@ void SkConic::evalAt(SkScalar t, SkPoint* pt, SkVector* tangent) const {
|
||||
conic_eval_pos(&fPts[0].fY, fW, t));
|
||||
}
|
||||
if (tangent) {
|
||||
tangent->set(conic_eval_tan(&fPts[0].fX, fW, t),
|
||||
conic_eval_tan(&fPts[0].fY, fW, t));
|
||||
*tangent = evalTangentAt(t);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1291,6 +1296,12 @@ SkPoint SkConic::evalAt(SkScalar t) const {
|
||||
}
|
||||
|
||||
SkVector SkConic::evalTangentAt(SkScalar t) const {
|
||||
// The derivative equation returns a zero tangent vector when t is 0 or 1,
|
||||
// and the control point is equal to the end point.
|
||||
// In this case, use the conic endpoints to compute the tangent.
|
||||
if ((t == 0 && fPts[0] == fPts[1]) || (t == 1 && fPts[1] == fPts[2])) {
|
||||
return fPts[2] - fPts[0];
|
||||
}
|
||||
Sk2s p0 = from_point(fPts[0]);
|
||||
Sk2s p1 = from_point(fPts[1]);
|
||||
Sk2s p2 = from_point(fPts[2]);
|
||||
|
@ -105,6 +105,67 @@ static void test_conic(skiatest::Reporter* reporter) {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_quad_tangents(skiatest::Reporter* reporter) {
|
||||
SkPoint pts[] = {
|
||||
{10, 20}, {10, 20}, {20, 30},
|
||||
{10, 20}, {15, 25}, {20, 30},
|
||||
{10, 20}, {20, 30}, {20, 30},
|
||||
};
|
||||
int count = (int) SK_ARRAY_COUNT(pts) / 3;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
SkConic conic(&pts[index * 3], 0.707f);
|
||||
SkVector start = SkEvalQuadTangentAt(&pts[index * 3], 0);
|
||||
SkVector mid = SkEvalQuadTangentAt(&pts[index * 3], .5f);
|
||||
SkVector end = SkEvalQuadTangentAt(&pts[index * 3], 1);
|
||||
REPORTER_ASSERT(reporter, start.fX && start.fY);
|
||||
REPORTER_ASSERT(reporter, mid.fX && mid.fY);
|
||||
REPORTER_ASSERT(reporter, end.fX && end.fY);
|
||||
REPORTER_ASSERT(reporter, SkScalarNearlyZero(start.cross(mid)));
|
||||
REPORTER_ASSERT(reporter, SkScalarNearlyZero(mid.cross(end)));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_conic_tangents(skiatest::Reporter* reporter) {
|
||||
SkPoint pts[] = {
|
||||
{ 10, 20}, {10, 20}, {20, 30},
|
||||
{ 10, 20}, {15, 25}, {20, 30},
|
||||
{ 10, 20}, {20, 30}, {20, 30}
|
||||
};
|
||||
int count = (int) SK_ARRAY_COUNT(pts) / 3;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
SkConic conic(&pts[index * 3], 0.707f);
|
||||
SkVector start = conic.evalTangentAt(0);
|
||||
SkVector mid = conic.evalTangentAt(.5f);
|
||||
SkVector end = conic.evalTangentAt(1);
|
||||
REPORTER_ASSERT(reporter, start.fX && start.fY);
|
||||
REPORTER_ASSERT(reporter, mid.fX && mid.fY);
|
||||
REPORTER_ASSERT(reporter, end.fX && end.fY);
|
||||
REPORTER_ASSERT(reporter, SkScalarNearlyZero(start.cross(mid)));
|
||||
REPORTER_ASSERT(reporter, SkScalarNearlyZero(mid.cross(end)));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_cubic_tangents(skiatest::Reporter* reporter) {
|
||||
SkPoint pts[] = {
|
||||
{ 10, 20}, {10, 20}, {20, 30}, {30, 40},
|
||||
{ 10, 20}, {15, 25}, {20, 30}, {30, 40},
|
||||
{ 10, 20}, {20, 30}, {30, 40}, {30, 40},
|
||||
};
|
||||
int count = (int) SK_ARRAY_COUNT(pts) / 4;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
SkConic conic(&pts[index * 3], 0.707f);
|
||||
SkVector start, mid, end;
|
||||
SkEvalCubicAt(&pts[index * 4], 0, NULL, &start, NULL);
|
||||
SkEvalCubicAt(&pts[index * 4], .5f, NULL, &mid, NULL);
|
||||
SkEvalCubicAt(&pts[index * 4], 1, NULL, &end, NULL);
|
||||
REPORTER_ASSERT(reporter, start.fX && start.fY);
|
||||
REPORTER_ASSERT(reporter, mid.fX && mid.fY);
|
||||
REPORTER_ASSERT(reporter, end.fX && end.fY);
|
||||
REPORTER_ASSERT(reporter, SkScalarNearlyZero(start.cross(mid)));
|
||||
REPORTER_ASSERT(reporter, SkScalarNearlyZero(mid.cross(end)));
|
||||
}
|
||||
}
|
||||
|
||||
DEF_TEST(Geometry, reporter) {
|
||||
SkPoint pts[3], dst[5];
|
||||
|
||||
@ -129,4 +190,7 @@ DEF_TEST(Geometry, reporter) {
|
||||
testChopCubic(reporter);
|
||||
test_evalquadat(reporter);
|
||||
test_conic(reporter);
|
||||
test_cubic_tangents(reporter);
|
||||
test_quad_tangents(reporter);
|
||||
test_conic_tangents(reporter);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user