forked from mirrors/gecko-dev
Bug 691187 - Prune zero-length segments for canvas strokes. r=lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D179462
This commit is contained in:
parent
19abba01c7
commit
9975cde84f
23 changed files with 140 additions and 100 deletions
|
|
@ -2955,7 +2955,7 @@ void CanvasRenderingContext2D::BeginPath() {
|
||||||
void CanvasRenderingContext2D::Fill(const CanvasWindingRule& aWinding) {
|
void CanvasRenderingContext2D::Fill(const CanvasWindingRule& aWinding) {
|
||||||
EnsureUserSpacePath(aWinding);
|
EnsureUserSpacePath(aWinding);
|
||||||
|
|
||||||
if (!mPath) {
|
if (!mPath || mPath->IsEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2991,7 +2991,7 @@ void CanvasRenderingContext2D::Fill(const CanvasPath& aPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<gfx::Path> gfxpath = aPath.GetPath(aWinding, mTarget);
|
RefPtr<gfx::Path> gfxpath = aPath.GetPath(aWinding, mTarget);
|
||||||
if (!gfxpath) {
|
if (!gfxpath || gfxpath->IsEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3022,7 +3022,7 @@ void CanvasRenderingContext2D::Fill(const CanvasPath& aPath,
|
||||||
void CanvasRenderingContext2D::Stroke() {
|
void CanvasRenderingContext2D::Stroke() {
|
||||||
EnsureUserSpacePath();
|
EnsureUserSpacePath();
|
||||||
|
|
||||||
if (!mPath) {
|
if (!mPath || mPath->IsEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3065,7 +3065,7 @@ void CanvasRenderingContext2D::Stroke(const CanvasPath& aPath) {
|
||||||
RefPtr<gfx::Path> gfxpath =
|
RefPtr<gfx::Path> gfxpath =
|
||||||
aPath.GetPath(CanvasWindingRule::Nonzero, mTarget);
|
aPath.GetPath(CanvasWindingRule::Nonzero, mTarget);
|
||||||
|
|
||||||
if (!gfxpath) {
|
if (!gfxpath || gfxpath->IsEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3219,6 +3219,10 @@ void CanvasRenderingContext2D::ArcTo(double aX1, double aY1, double aX2,
|
||||||
Point p1(aX1, aY1);
|
Point p1(aX1, aY1);
|
||||||
Point p2(aX2, aY2);
|
Point p2(aX2, aY2);
|
||||||
|
|
||||||
|
if (!p1.IsFinite() || !p2.IsFinite() || !std::isfinite(aRadius)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Execute these calculations in double precision to avoid cumulative
|
// Execute these calculations in double precision to avoid cumulative
|
||||||
// rounding errors.
|
// rounding errors.
|
||||||
double dir, a2, b2, c2, cosx, sinx, d, anx, any, bnx, bny, x3, y3, x4, y4, cx,
|
double dir, a2, b2, c2, cosx, sinx, d, anx, any, bnx, bny, x3, y3, x4, y4, cx,
|
||||||
|
|
@ -3226,7 +3230,7 @@ void CanvasRenderingContext2D::ArcTo(double aX1, double aY1, double aX2,
|
||||||
bool anticlockwise;
|
bool anticlockwise;
|
||||||
|
|
||||||
if (p0 == p1 || p1 == p2 || aRadius == 0) {
|
if (p0 == p1 || p1 == p2 || aRadius == 0) {
|
||||||
LineTo(p1.x, p1.y);
|
LineTo(p1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3234,7 +3238,7 @@ void CanvasRenderingContext2D::ArcTo(double aX1, double aY1, double aX2,
|
||||||
dir = (p2.x.value - p1.x.value) * (p0.y.value - p1.y.value) +
|
dir = (p2.x.value - p1.x.value) * (p0.y.value - p1.y.value) +
|
||||||
(p2.y.value - p1.y.value) * (p1.x.value - p0.x.value);
|
(p2.y.value - p1.y.value) * (p1.x.value - p0.x.value);
|
||||||
if (dir == 0) {
|
if (dir == 0) {
|
||||||
LineTo(p1.x, p1.y);
|
LineTo(p1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3285,8 +3289,16 @@ void CanvasRenderingContext2D::Rect(double aX, double aY, double aW,
|
||||||
double aH) {
|
double aH) {
|
||||||
EnsureWritablePath();
|
EnsureWritablePath();
|
||||||
|
|
||||||
|
if (!std::isfinite(aX) || !std::isfinite(aY) || !std::isfinite(aW) ||
|
||||||
|
!std::isfinite(aH)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mPathBuilder) {
|
if (mPathBuilder) {
|
||||||
mPathBuilder->MoveTo(Point(aX, aY));
|
mPathBuilder->MoveTo(Point(aX, aY));
|
||||||
|
if (aW == 0 && aH == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mPathBuilder->LineTo(Point(aX + aW, aY));
|
mPathBuilder->LineTo(Point(aX + aW, aY));
|
||||||
mPathBuilder->LineTo(Point(aX + aW, aY + aH));
|
mPathBuilder->LineTo(Point(aX + aW, aY + aH));
|
||||||
mPathBuilder->LineTo(Point(aX, aY + aH));
|
mPathBuilder->LineTo(Point(aX, aY + aH));
|
||||||
|
|
@ -3294,6 +3306,9 @@ void CanvasRenderingContext2D::Rect(double aX, double aY, double aW,
|
||||||
} else {
|
} else {
|
||||||
mDSPathBuilder->MoveTo(
|
mDSPathBuilder->MoveTo(
|
||||||
mTarget->GetTransform().TransformPoint(Point(aX, aY)));
|
mTarget->GetTransform().TransformPoint(Point(aX, aY)));
|
||||||
|
if (aW == 0 && aH == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mDSPathBuilder->LineTo(
|
mDSPathBuilder->LineTo(
|
||||||
mTarget->GetTransform().TransformPoint(Point(aX + aW, aY)));
|
mTarget->GetTransform().TransformPoint(Point(aX + aW, aY)));
|
||||||
mDSPathBuilder->LineTo(
|
mDSPathBuilder->LineTo(
|
||||||
|
|
@ -6310,21 +6325,30 @@ void CanvasPath::ClosePath() {
|
||||||
void CanvasPath::MoveTo(double aX, double aY) {
|
void CanvasPath::MoveTo(double aX, double aY) {
|
||||||
EnsurePathBuilder();
|
EnsurePathBuilder();
|
||||||
|
|
||||||
mPathBuilder->MoveTo(Point(ToFloat(aX), ToFloat(aY)));
|
Point pos(ToFloat(aX), ToFloat(aY));
|
||||||
|
if (!pos.IsFinite()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPathBuilder->MoveTo(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasPath::LineTo(double aX, double aY) {
|
void CanvasPath::LineTo(double aX, double aY) {
|
||||||
EnsurePathBuilder();
|
LineTo(Point(ToFloat(aX), ToFloat(aY)));
|
||||||
|
|
||||||
mPathBuilder->LineTo(Point(ToFloat(aX), ToFloat(aY)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasPath::QuadraticCurveTo(double aCpx, double aCpy, double aX,
|
void CanvasPath::QuadraticCurveTo(double aCpx, double aCpy, double aX,
|
||||||
double aY) {
|
double aY) {
|
||||||
EnsurePathBuilder();
|
EnsurePathBuilder();
|
||||||
|
|
||||||
mPathBuilder->QuadraticBezierTo(gfx::Point(ToFloat(aCpx), ToFloat(aCpy)),
|
Point cp1(ToFloat(aCpx), ToFloat(aCpy));
|
||||||
gfx::Point(ToFloat(aX), ToFloat(aY)));
|
Point cp2(ToFloat(aX), ToFloat(aY));
|
||||||
|
if (!cp1.IsFinite() || !cp2.IsFinite() ||
|
||||||
|
(cp1 == mPathBuilder->CurrentPoint() && cp1 == cp2)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPathBuilder->QuadraticBezierTo(cp1, cp2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasPath::BezierCurveTo(double aCp1x, double aCp1y, double aCp2x,
|
void CanvasPath::BezierCurveTo(double aCp1x, double aCp1y, double aCp2x,
|
||||||
|
|
@ -6347,6 +6371,10 @@ void CanvasPath::ArcTo(double aX1, double aY1, double aX2, double aY2,
|
||||||
Point p1(aX1, aY1);
|
Point p1(aX1, aY1);
|
||||||
Point p2(aX2, aY2);
|
Point p2(aX2, aY2);
|
||||||
|
|
||||||
|
if (!p1.IsFinite() || !p2.IsFinite() || !std::isfinite(aRadius)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Execute these calculations in double precision to avoid cumulative
|
// Execute these calculations in double precision to avoid cumulative
|
||||||
// rounding errors.
|
// rounding errors.
|
||||||
double dir, a2, b2, c2, cosx, sinx, d, anx, any, bnx, bny, x3, y3, x4, y4, cx,
|
double dir, a2, b2, c2, cosx, sinx, d, anx, any, bnx, bny, x3, y3, x4, y4, cx,
|
||||||
|
|
@ -6354,7 +6382,7 @@ void CanvasPath::ArcTo(double aX1, double aY1, double aX2, double aY2,
|
||||||
bool anticlockwise;
|
bool anticlockwise;
|
||||||
|
|
||||||
if (p0 == p1 || p1 == p2 || aRadius == 0) {
|
if (p0 == p1 || p1 == p2 || aRadius == 0) {
|
||||||
LineTo(p1.x, p1.y);
|
LineTo(p1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6362,7 +6390,7 @@ void CanvasPath::ArcTo(double aX1, double aY1, double aX2, double aY2,
|
||||||
dir = (p2.x.value - p1.x.value) * (p0.y.value - p1.y.value) +
|
dir = (p2.x.value - p1.x.value) * (p0.y.value - p1.y.value) +
|
||||||
(p2.y.value - p1.y.value) * (p1.x.value - p0.x.value);
|
(p2.y.value - p1.y.value) * (p1.x.value - p0.x.value);
|
||||||
if (dir == 0) {
|
if (dir == 0) {
|
||||||
LineTo(p1.x, p1.y);
|
LineTo(p1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6397,7 +6425,17 @@ void CanvasPath::ArcTo(double aX1, double aY1, double aX2, double aY2,
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasPath::Rect(double aX, double aY, double aW, double aH) {
|
void CanvasPath::Rect(double aX, double aY, double aW, double aH) {
|
||||||
|
EnsurePathBuilder();
|
||||||
|
|
||||||
|
if (!std::isfinite(aX) || !std::isfinite(aY) || !std::isfinite(aW) ||
|
||||||
|
!std::isfinite(aH)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MoveTo(aX, aY);
|
MoveTo(aX, aY);
|
||||||
|
if (aW == 0 && aH == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
LineTo(aX + aW, aY);
|
LineTo(aX + aW, aY);
|
||||||
LineTo(aX + aW, aY + aH);
|
LineTo(aX + aW, aY + aH);
|
||||||
LineTo(aX, aY + aH);
|
LineTo(aX, aY + aH);
|
||||||
|
|
@ -6443,6 +6481,10 @@ void CanvasPath::Ellipse(double x, double y, double radiusX, double radiusY,
|
||||||
void CanvasPath::LineTo(const gfx::Point& aPoint) {
|
void CanvasPath::LineTo(const gfx::Point& aPoint) {
|
||||||
EnsurePathBuilder();
|
EnsurePathBuilder();
|
||||||
|
|
||||||
|
if (!aPoint.IsFinite() || aPoint == mPathBuilder->CurrentPoint()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mPathBuilder->LineTo(aPoint);
|
mPathBuilder->LineTo(aPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6450,6 +6492,11 @@ void CanvasPath::BezierTo(const gfx::Point& aCP1, const gfx::Point& aCP2,
|
||||||
const gfx::Point& aCP3) {
|
const gfx::Point& aCP3) {
|
||||||
EnsurePathBuilder();
|
EnsurePathBuilder();
|
||||||
|
|
||||||
|
if (!aCP1.IsFinite() || !aCP2.IsFinite() || !aCP3.IsFinite() ||
|
||||||
|
(aCP1 == mPathBuilder->CurrentPoint() && aCP1 == aCP2 && aCP1 == aCP3)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
|
mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -337,11 +337,17 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
|
||||||
void MoveTo(double aX, double aY) override {
|
void MoveTo(double aX, double aY) override {
|
||||||
EnsureWritablePath();
|
EnsureWritablePath();
|
||||||
|
|
||||||
|
mozilla::gfx::Point pos(ToFloat(aX), ToFloat(aY));
|
||||||
|
if (!pos.IsFinite()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mPathBuilder) {
|
if (mPathBuilder) {
|
||||||
mPathBuilder->MoveTo(mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
|
mPathBuilder->MoveTo(pos);
|
||||||
} else {
|
} else {
|
||||||
mDSPathBuilder->MoveTo(mTarget->GetTransform().TransformPoint(
|
mozilla::gfx::Point transformedPos =
|
||||||
mozilla::gfx::Point(ToFloat(aX), ToFloat(aY))));
|
mTarget->GetTransform().TransformPoint(pos);
|
||||||
|
mDSPathBuilder->MoveTo(transformedPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -355,17 +361,25 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
|
||||||
double aY) override {
|
double aY) override {
|
||||||
EnsureWritablePath();
|
EnsureWritablePath();
|
||||||
|
|
||||||
|
mozilla::gfx::Point cp1(ToFloat(aCpx), ToFloat(aCpy));
|
||||||
|
mozilla::gfx::Point cp2(ToFloat(aX), ToFloat(aY));
|
||||||
|
if (!cp1.IsFinite() || !cp2.IsFinite()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mPathBuilder) {
|
if (mPathBuilder) {
|
||||||
mPathBuilder->QuadraticBezierTo(
|
if (cp1 == mPathBuilder->CurrentPoint() && cp1 == cp2) {
|
||||||
mozilla::gfx::Point(ToFloat(aCpx), ToFloat(aCpy)),
|
return;
|
||||||
mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
|
}
|
||||||
|
mPathBuilder->QuadraticBezierTo(cp1, cp2);
|
||||||
} else {
|
} else {
|
||||||
mozilla::gfx::Matrix transform = mTarget->GetTransform();
|
mozilla::gfx::Matrix transform = mTarget->GetTransform();
|
||||||
mDSPathBuilder->QuadraticBezierTo(
|
mozilla::gfx::Point transformedPos = transform.TransformPoint(cp1);
|
||||||
transform.TransformPoint(
|
if (transformedPos == mDSPathBuilder->CurrentPoint() && cp1 == cp2) {
|
||||||
mozilla::gfx::Point(ToFloat(aCpx), ToFloat(aCpy))),
|
return;
|
||||||
transform.TransformPoint(
|
}
|
||||||
mozilla::gfx::Point(ToFloat(aX), ToFloat(aY))));
|
mDSPathBuilder->QuadraticBezierTo(transformedPos,
|
||||||
|
transform.TransformPoint(cp2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -501,22 +515,45 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
|
||||||
enum class Style : uint8_t { STROKE = 0, FILL, MAX };
|
enum class Style : uint8_t { STROKE = 0, FILL, MAX };
|
||||||
|
|
||||||
void LineTo(const mozilla::gfx::Point& aPoint) {
|
void LineTo(const mozilla::gfx::Point& aPoint) {
|
||||||
|
if (!aPoint.IsFinite()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (mPathBuilder) {
|
if (mPathBuilder) {
|
||||||
|
if (mPathBuilder->CurrentPoint() == aPoint) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mPathBuilder->LineTo(aPoint);
|
mPathBuilder->LineTo(aPoint);
|
||||||
} else {
|
} else {
|
||||||
mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(aPoint));
|
mozilla::gfx::Point transformedPt =
|
||||||
|
mTarget->GetTransform().TransformPoint(aPoint);
|
||||||
|
if (mDSPathBuilder->CurrentPoint() == transformedPt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mDSPathBuilder->LineTo(transformedPt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BezierTo(const mozilla::gfx::Point& aCP1,
|
void BezierTo(const mozilla::gfx::Point& aCP1,
|
||||||
const mozilla::gfx::Point& aCP2,
|
const mozilla::gfx::Point& aCP2,
|
||||||
const mozilla::gfx::Point& aCP3) {
|
const mozilla::gfx::Point& aCP3) {
|
||||||
|
if (!aCP1.IsFinite() || !aCP2.IsFinite() || !aCP3.IsFinite()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mPathBuilder) {
|
if (mPathBuilder) {
|
||||||
|
if (aCP1 == mPathBuilder->CurrentPoint() && aCP1 == aCP2 &&
|
||||||
|
aCP1 == aCP3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
|
mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
|
||||||
} else {
|
} else {
|
||||||
mozilla::gfx::Matrix transform = mTarget->GetTransform();
|
mozilla::gfx::Matrix transform = mTarget->GetTransform();
|
||||||
mDSPathBuilder->BezierTo(transform.TransformPoint(aCP1),
|
mozilla::gfx::Point transformedPos = transform.TransformPoint(aCP1);
|
||||||
transform.TransformPoint(aCP2),
|
if (transformedPos == mDSPathBuilder->CurrentPoint() && aCP1 == aCP2 &&
|
||||||
|
aCP1 == aCP3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mDSPathBuilder->BezierTo(transformedPos, transform.TransformPoint(aCP2),
|
||||||
transform.TransformPoint(aCP3));
|
transform.TransformPoint(aCP3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14252,7 +14252,7 @@ ctx.lineTo(50, 25);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
|
isPixel(ctx, 50,25, 0,255,0,255, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -14324,7 +14324,7 @@ ctx.moveTo(50, 25);
|
||||||
ctx.bezierCurveTo(50, 25, 50, 25, 50, 25);
|
ctx.bezierCurveTo(50, 25, 50, 25, 50, 25);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
|
isPixel(ctx, 50,25, 0,255,0,255, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -14356,7 +14356,7 @@ ctx.moveTo(50, 25);
|
||||||
ctx.lineTo(50, 25);
|
ctx.lineTo(50, 25);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
|
isPixel(ctx, 50,25, 0,255,0,255, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -14389,7 +14389,7 @@ ctx.stroke();
|
||||||
|
|
||||||
ctx.strokeRect(50, 25, 0, 0);
|
ctx.strokeRect(50, 25, 0, 0);
|
||||||
|
|
||||||
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
|
isPixel(ctx, 50,25, 0,255,0,255, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1007,6 +1007,8 @@ class Path : public external::AtomicRefCounted<Path> {
|
||||||
|
|
||||||
virtual Point ComputePointAtLength(Float aLength, Point* aTangent = nullptr);
|
virtual Point ComputePointAtLength(Float aLength, Point* aTangent = nullptr);
|
||||||
|
|
||||||
|
virtual bool IsEmpty() const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Path();
|
Path();
|
||||||
void EnsureFlattenedPath();
|
void EnsureFlattenedPath();
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ void PathBuilderD2D::LineTo(const Point& aPoint) {
|
||||||
mSink->AddLine(D2DPoint(aPoint));
|
mSink->AddLine(D2DPoint(aPoint));
|
||||||
|
|
||||||
mCurrentPoint = aPoint;
|
mCurrentPoint = aPoint;
|
||||||
|
mFigureEmpty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathBuilderD2D::BezierTo(const Point& aCP1, const Point& aCP2,
|
void PathBuilderD2D::BezierTo(const Point& aCP1, const Point& aCP2,
|
||||||
|
|
@ -143,6 +144,7 @@ void PathBuilderD2D::BezierTo(const Point& aCP1, const Point& aCP2,
|
||||||
D2D1::BezierSegment(D2DPoint(aCP1), D2DPoint(aCP2), D2DPoint(aCP3)));
|
D2D1::BezierSegment(D2DPoint(aCP1), D2DPoint(aCP2), D2DPoint(aCP3)));
|
||||||
|
|
||||||
mCurrentPoint = aCP3;
|
mCurrentPoint = aCP3;
|
||||||
|
mFigureEmpty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathBuilderD2D::QuadraticBezierTo(const Point& aCP1, const Point& aCP2) {
|
void PathBuilderD2D::QuadraticBezierTo(const Point& aCP1, const Point& aCP2) {
|
||||||
|
|
@ -151,6 +153,7 @@ void PathBuilderD2D::QuadraticBezierTo(const Point& aCP1, const Point& aCP2) {
|
||||||
D2D1::QuadraticBezierSegment(D2DPoint(aCP1), D2DPoint(aCP2)));
|
D2D1::QuadraticBezierSegment(D2DPoint(aCP1), D2DPoint(aCP2)));
|
||||||
|
|
||||||
mCurrentPoint = aCP2;
|
mCurrentPoint = aCP2;
|
||||||
|
mFigureEmpty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathBuilderD2D::Close() {
|
void PathBuilderD2D::Close() {
|
||||||
|
|
@ -248,6 +251,7 @@ void PathBuilderD2D::Arc(const Point& aOrigin, Float aRadius, Float aStartAngle,
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentPoint = endPoint;
|
mCurrentPoint = endPoint;
|
||||||
|
mFigureEmpty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathBuilderD2D::EnsureActive(const Point& aPoint) {
|
void PathBuilderD2D::EnsureActive(const Point& aPoint) {
|
||||||
|
|
@ -269,8 +273,8 @@ already_AddRefed<Path> PathBuilderD2D::Finish() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeAndAddRef<PathD2D>(mGeometry, mFigureActive, mCurrentPoint,
|
return MakeAndAddRef<PathD2D>(mGeometry, mFigureActive, mFigureEmpty,
|
||||||
mFillRule, mBackendType);
|
mCurrentPoint, mFillRule, mBackendType);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<PathBuilder> PathD2D::CopyToBuilder(FillRule aFillRule) const {
|
already_AddRefed<PathBuilder> PathD2D::CopyToBuilder(FillRule aFillRule) const {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ class PathBuilderD2D : public PathBuilder {
|
||||||
RefPtr<ID2D1PathGeometry> mGeometry;
|
RefPtr<ID2D1PathGeometry> mGeometry;
|
||||||
|
|
||||||
bool mFigureActive;
|
bool mFigureActive;
|
||||||
|
bool mFigureEmpty = true;
|
||||||
FillRule mFillRule;
|
FillRule mFillRule;
|
||||||
BackendType mBackendType;
|
BackendType mBackendType;
|
||||||
};
|
};
|
||||||
|
|
@ -63,10 +64,11 @@ class PathBuilderD2D : public PathBuilder {
|
||||||
class PathD2D : public Path {
|
class PathD2D : public Path {
|
||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathD2D, override)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathD2D, override)
|
||||||
PathD2D(ID2D1PathGeometry* aGeometry, bool aEndedActive,
|
PathD2D(ID2D1PathGeometry* aGeometry, bool aEndedActive, bool aIsEmpty,
|
||||||
const Point& aEndPoint, FillRule aFillRule, BackendType aBackendType)
|
const Point& aEndPoint, FillRule aFillRule, BackendType aBackendType)
|
||||||
: mGeometry(aGeometry),
|
: mGeometry(aGeometry),
|
||||||
mEndedActive(aEndedActive),
|
mEndedActive(aEndedActive),
|
||||||
|
mIsEmpty(aIsEmpty),
|
||||||
mEndPoint(aEndPoint),
|
mEndPoint(aEndPoint),
|
||||||
mFillRule(aFillRule),
|
mFillRule(aFillRule),
|
||||||
mBackendType(aBackendType) {}
|
mBackendType(aBackendType) {}
|
||||||
|
|
@ -93,6 +95,8 @@ class PathD2D : public Path {
|
||||||
|
|
||||||
virtual FillRule GetFillRule() const { return mFillRule; }
|
virtual FillRule GetFillRule() const { return mFillRule; }
|
||||||
|
|
||||||
|
bool IsEmpty() const override { return mIsEmpty; }
|
||||||
|
|
||||||
ID2D1Geometry* GetGeometry() { return mGeometry; }
|
ID2D1Geometry* GetGeometry() { return mGeometry; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -101,6 +105,7 @@ class PathD2D : public Path {
|
||||||
|
|
||||||
mutable RefPtr<ID2D1PathGeometry> mGeometry;
|
mutable RefPtr<ID2D1PathGeometry> mGeometry;
|
||||||
bool mEndedActive;
|
bool mEndedActive;
|
||||||
|
bool mIsEmpty;
|
||||||
Point mEndPoint;
|
Point mEndPoint;
|
||||||
FillRule mFillRule;
|
FillRule mFillRule;
|
||||||
BackendType mBackendType;
|
BackendType mBackendType;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "PathSkia.h"
|
#include "PathSkia.h"
|
||||||
#include "HelpersSkia.h"
|
#include "HelpersSkia.h"
|
||||||
#include "PathHelpers.h"
|
#include "PathHelpers.h"
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "skia/include/core/SkPathUtils.h"
|
#include "skia/include/core/SkPathUtils.h"
|
||||||
#include "skia/src/core/SkGeometry.h"
|
#include "skia/src/core/SkGeometry.h"
|
||||||
|
|
||||||
|
|
@ -270,4 +271,11 @@ Maybe<Rect> PathSkia::AsRect() const {
|
||||||
}
|
}
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PathSkia::IsEmpty() const {
|
||||||
|
// Move/Close/Done segments are not included in the mask so as long as any
|
||||||
|
// flag is set, we know that the path is non-empty.
|
||||||
|
return mPath.getSegmentMasks() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla::gfx
|
} // namespace mozilla::gfx
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ class PathSkia : public Path {
|
||||||
const Matrix& aTransform, SkPath& aFillPath,
|
const Matrix& aTransform, SkPath& aFillPath,
|
||||||
const Maybe<Rect>& aClipRect = Nothing()) const;
|
const Maybe<Rect>& aClipRect = Nothing()) const;
|
||||||
|
|
||||||
|
bool IsEmpty() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DrawTargetSkia;
|
friend class DrawTargetSkia;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.path.stroke.prune.arc.html]
|
|
||||||
expected:
|
|
||||||
if (os == "android") and fission: [OK, TIMEOUT]
|
|
||||||
[Zero-length line segments from arcTo and arc are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.path.stroke.prune.closed.html]
|
|
||||||
expected:
|
|
||||||
if (os == "android") and fission: [OK, TIMEOUT]
|
|
||||||
[Zero-length line segments from closed paths are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.path.stroke.prune.curve.html]
|
|
||||||
expected:
|
|
||||||
if (os == "android") and fission: [OK, TIMEOUT]
|
|
||||||
[Zero-length line segments from quadraticCurveTo and bezierCurveTo are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.path.stroke.prune.line.html]
|
|
||||||
expected:
|
|
||||||
if (os == "android") and fission: [OK, TIMEOUT]
|
|
||||||
[Zero-length line segments from lineTo are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.path.stroke.prune.rect.html]
|
|
||||||
expected:
|
|
||||||
if (os == "android") and fission: [OK, TIMEOUT]
|
|
||||||
[Zero-length line segments from rect and strokeRect are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.arc.html]
|
|
||||||
[Zero-length line segments from arcTo and arc are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.arc.worker.html]
|
|
||||||
[Zero-length line segments from arcTo and arc are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.closed.html]
|
|
||||||
[Zero-length line segments from closed paths are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.closed.worker.html]
|
|
||||||
[Zero-length line segments from closed paths are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.curve.html]
|
|
||||||
[Zero-length line segments from quadraticCurveTo and bezierCurveTo are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.curve.worker.html]
|
|
||||||
[Zero-length line segments from quadraticCurveTo and bezierCurveTo are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.line.html]
|
|
||||||
[Zero-length line segments from lineTo are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.line.worker.html]
|
|
||||||
[Zero-length line segments from lineTo are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.rect.html]
|
|
||||||
[Zero-length line segments from rect and strokeRect are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.path.stroke.prune.rect.worker.html]
|
|
||||||
[Zero-length line segments from rect and strokeRect are removed before stroking]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
Loading…
Reference in a new issue