subdivide path when side-clipping fails
Please review concept; I'm OK not to check this in. If the root finder fails, subdivide the curve and try again. This is complicated by the reversed nature of the curves; maybe it can be simpler, but how to do that escapes me. R=reed@google.com BUG=514246 Review URL: https://codereview.chromium.org/1299243002
This commit is contained in:
parent
725c620543
commit
7d173403f4
@ -53,6 +53,58 @@ private:
|
||||
typedef skiagm::GM INHERITED;
|
||||
};
|
||||
|
||||
|
||||
class ClippedCubic2GM : public skiagm::GM {
|
||||
public:
|
||||
ClippedCubic2GM() {}
|
||||
|
||||
protected:
|
||||
|
||||
SkString onShortName() {
|
||||
return SkString("clippedcubic2");
|
||||
}
|
||||
|
||||
SkISize onISize() { return SkISize::Make(1240, 390); }
|
||||
|
||||
void onDraw(SkCanvas* canvas) override {
|
||||
canvas->save();
|
||||
canvas->translate(-2, 20);
|
||||
drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 150));
|
||||
canvas->translate(0, 170);
|
||||
drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 100));
|
||||
canvas->translate(0, 170);
|
||||
drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 30, 150));
|
||||
canvas->translate(0, 170);
|
||||
drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 10, 150));
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
void drawOne(SkCanvas* canvas, const SkPath& path, const SkRect& clip) {
|
||||
SkPaint framePaint, fillPaint;
|
||||
framePaint.setStyle(SkPaint::kStroke_Style);
|
||||
canvas->drawRect(clip, framePaint);
|
||||
canvas->drawPath(path, framePaint);
|
||||
canvas->save();
|
||||
canvas->clipRect(clip);
|
||||
canvas->drawPath(path, fillPaint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
fPath.moveTo(69.7030518991886f, 0);
|
||||
fPath.cubicTo( 69.7030518991886f, 21.831149999999997f,
|
||||
58.08369508178456f, 43.66448333333333f, 34.8449814469765f, 65.5f);
|
||||
fPath.cubicTo( 11.608591683531916f, 87.33115f, -0.010765133872116195f, 109.16448333333332f,
|
||||
-0.013089005235602302f, 131);
|
||||
fPath.close();
|
||||
}
|
||||
|
||||
SkPath fPath;
|
||||
private:
|
||||
typedef skiagm::GM INHERITED;
|
||||
};
|
||||
|
||||
|
||||
class CubicPathGM : public skiagm::GM {
|
||||
public:
|
||||
CubicPathGM() {}
|
||||
@ -347,3 +399,4 @@ private:
|
||||
DEF_GM( return new CubicPathGM; )
|
||||
DEF_GM( return new CubicClosePathGM; )
|
||||
DEF_GM( return new ClippedCubicGM; )
|
||||
DEF_GM( return new ClippedCubic2GM; )
|
||||
|
@ -270,6 +270,34 @@ static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
|
||||
}
|
||||
}
|
||||
|
||||
static void chop_mono_cubic_at_x(SkPoint pts[4], SkScalar x, SkPoint tmp[7]) {
|
||||
if (SkChopMonoCubicAtX(pts, x, tmp)) {
|
||||
return;
|
||||
}
|
||||
SkScalar t = 0.5f;
|
||||
SkScalar lastT;
|
||||
SkScalar bestT SK_INIT_TO_AVOID_WARNING;
|
||||
SkScalar step = 0.25f;
|
||||
SkScalar D = pts[0].fX;
|
||||
SkScalar A = pts[3].fX + 3*(pts[1].fX - pts[2].fX) - D;
|
||||
SkScalar B = 3*(pts[2].fX - pts[1].fX - pts[1].fX + D);
|
||||
SkScalar C = 3*(pts[1].fX - D);
|
||||
x -= D;
|
||||
SkScalar closest = SK_ScalarMax;
|
||||
do {
|
||||
SkScalar loc = ((A * t + B) * t + C) * t;
|
||||
SkScalar dist = SkScalarAbs(loc - x);
|
||||
if (closest > dist) {
|
||||
closest = dist;
|
||||
bestT = t;
|
||||
}
|
||||
lastT = t;
|
||||
t += loc < x ? step : -step;
|
||||
step *= 0.5f;
|
||||
} while (closest > 0.25f && lastT != t);
|
||||
SkChopCubicAt(pts, tmp, bestT);
|
||||
}
|
||||
|
||||
// srcPts[] must be monotonic in X and Y
|
||||
void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
|
||||
SkPoint pts[4];
|
||||
@ -305,40 +333,29 @@ void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
|
||||
// are we partially to the left
|
||||
if (pts[0].fX < clip.fLeft) {
|
||||
SkPoint tmp[7];
|
||||
if (SkChopMonoCubicAtX(pts, clip.fLeft, tmp)) {
|
||||
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
|
||||
chop_mono_cubic_at_x(pts, clip.fLeft, tmp);
|
||||
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
|
||||
|
||||
// tmp[3, 4].fX should all be to the right of clip.fLeft.
|
||||
// Since we can't trust the numerics of
|
||||
// the chopper, we force those conditions now
|
||||
tmp[3].fX = clip.fLeft;
|
||||
clamp_ge(tmp[4].fX, clip.fLeft);
|
||||
// tmp[3, 4].fX should all be to the right of clip.fLeft.
|
||||
// Since we can't trust the numerics of
|
||||
// the chopper, we force those conditions now
|
||||
tmp[3].fX = clip.fLeft;
|
||||
clamp_ge(tmp[4].fX, clip.fLeft);
|
||||
|
||||
pts[0] = tmp[3];
|
||||
pts[1] = tmp[4];
|
||||
pts[2] = tmp[5];
|
||||
} else {
|
||||
// if chopMonocubicAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
|
||||
return;
|
||||
}
|
||||
pts[0] = tmp[3];
|
||||
pts[1] = tmp[4];
|
||||
pts[2] = tmp[5];
|
||||
}
|
||||
|
||||
// are we partially to the right
|
||||
if (pts[3].fX > clip.fRight) {
|
||||
SkPoint tmp[7];
|
||||
if (SkChopMonoCubicAtX(pts, clip.fRight, tmp)) {
|
||||
tmp[3].fX = clip.fRight;
|
||||
clamp_le(tmp[2].fX, clip.fRight);
|
||||
chop_mono_cubic_at_x(pts, clip.fRight, tmp);
|
||||
tmp[3].fX = clip.fRight;
|
||||
clamp_le(tmp[2].fX, clip.fRight);
|
||||
|
||||
this->appendCubic(tmp, reverse);
|
||||
this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
|
||||
} else {
|
||||
// if chopMonoCubicAtX failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
|
||||
}
|
||||
this->appendCubic(tmp, reverse);
|
||||
this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
|
||||
} else { // wholly inside the clip
|
||||
this->appendCubic(pts, reverse);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user