closes #473: implement Canvas Ellipse + M1239835

This commit is contained in:
Cameron Kaiser 2018-02-11 17:44:42 -08:00
parent 46b6faa6b2
commit aebc3385bd
5 changed files with 65 additions and 18 deletions

View File

@ -51,6 +51,9 @@ public:
void Arc(double x, double y, double radius,
double startAngle, double endAngle, bool anticlockwise,
ErrorResult& error);
void Ellipse(double x, double y, double radiusX, double radiusY,
double rotation, double startAngle, double endAngle,
bool anticlockwise, ErrorResult& error);
void LineTo(const gfx::Point& aPoint);
void BezierTo(const gfx::Point& aCP1,

View File

@ -2498,8 +2498,11 @@ CanvasRenderingContext2D::UpdateFilter()
//
static bool
ValidateRect(double& aX, double& aY, double& aWidth, double& aHeight)
ValidateRect(double& aX, double& aY, double& aWidth, double& aHeight, bool aIsZeroSizeValid)
{
if (!aIsZeroSizeValid && (aWidth == 0.0 || aHeight == 0.0)) {
return false;
}
// bug 1018527
// The values of canvas API input are in double precision, but Moz2D APIs are
@ -2530,7 +2533,8 @@ void
CanvasRenderingContext2D::ClearRect(double x, double y, double w,
double h)
{
if(!ValidateRect(x, y, w, h)) {
// Do not allow zeros - it's a no-op at that point per spec.
if (!ValidateRect(x, y, w, h, false)) {
return;
}
@ -2547,7 +2551,7 @@ CanvasRenderingContext2D::FillRect(double x, double y, double w,
{
const ContextState &state = CurrentState();
if(!ValidateRect(x, y, w, h)) {
if(!ValidateRect(x, y, w, h, true)) {
return;
}
@ -2625,7 +2629,7 @@ CanvasRenderingContext2D::StrokeRect(double x, double y, double w,
return;
}
if(!ValidateRect(x, y, w, h)) {
if(!ValidateRect(x, y, w, h, true)) {
return;
}
@ -2991,7 +2995,7 @@ CanvasRenderingContext2D::Arc(double x, double y, double r,
double startAngle, double endAngle,
bool anticlockwise, ErrorResult& error)
{
if (r < 0.0) {
if (MOZ_UNLIKELY(r < 0.0)) {
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
@ -3021,6 +3025,22 @@ CanvasRenderingContext2D::Rect(double x, double y, double w, double h)
}
}
void
CanvasRenderingContext2D::Ellipse(double aX, double aY, double aRadiusX, double aRadiusY,
double aRotation, double aStartAngle, double aEndAngle,
bool aAnticlockwise, ErrorResult& aError)
{
if (MOZ_UNLIKELY(aRadiusX < 0.0 || aRadiusY < 0.0)) {
aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
EnsureWritablePath();
ArcToBezier(this, Point(aX, aY), Size(aRadiusX, aRadiusY), aStartAngle, aEndAngle,
aAnticlockwise, aRotation);
}
void
CanvasRenderingContext2D::EnsureWritablePath()
{
@ -4402,8 +4422,8 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image,
MOZ_ASSERT(optional_argc == 0 || optional_argc == 2 || optional_argc == 6);
if (optional_argc == 6) {
if (!ValidateRect(sx, sy, sw, sh) ||
!ValidateRect(dx, dy, dw, dh)) {
if (!ValidateRect(sx, sy, sw, sh, true) ||
!ValidateRect(dx, dy, dw, dh, true)) {
return;
}
}
@ -5918,6 +5938,22 @@ CanvasPath::Arc(double x, double y, double radius,
ArcToBezier(this, Point(x, y), Size(radius, radius), startAngle, endAngle, anticlockwise);
}
void
CanvasPath::Ellipse(double x, double y, double radiusX, double radiusY,
double rotation, double startAngle, double endAngle,
bool anticlockwise, ErrorResult& error)
{
if (MOZ_UNLIKELY(radiusX < 0.0 || radiusY < 0.0)) {
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
EnsurePathBuilder();
ArcToBezier(this, Point(x, y), Size(radiusX, radiusY), startAngle, endAngle,
anticlockwise, rotation);
}
void
CanvasPath::LineTo(const gfx::Point& aPoint)
{

View File

@ -347,6 +347,9 @@ public:
void Rect(double x, double y, double w, double h);
void Arc(double x, double y, double radius, double startAngle,
double endAngle, bool anticlockwise, mozilla::ErrorResult& error);
void Ellipse(double aX, double aY, double aRadiusX, double aRadiusY,
double aRotation, double aStartAngle, double aEndAngle,
bool aAnticlockwise, ErrorResult& aError);
void GetMozCurrentTransform(JSContext* cx,
JS::MutableHandle<JSObject*> result,

View File

@ -298,7 +298,9 @@ interface CanvasPathMethods {
[Throws, LenientFloat]
void arc(double x, double y, double radius, double startAngle, double endAngle, optional boolean anticlockwise = false);
// NOT IMPLEMENTED [LenientFloat] void ellipse(double x, double y, double radiusX, double radiusY, double rotation, double startAngle, double endAngle, boolean anticlockwise);
[Throws, LenientFloat]
void ellipse(double x, double y, double radiusX, double radiusY, double rotation, double startAngle, double endAngle, optional boolean anticlockwise = false);
};
interface CanvasGradient {

View File

@ -34,7 +34,8 @@ inline void PartialArcToBezier(T* aSink,
const Size& aRadius,
const Point& aStartPoint, const Point& aEndPoint,
const Point& aStartOffset, const Point& aEndOffset,
Float aKappaFactor = kKappaFactor)
Float aKappaFactor = kKappaFactor,
const Matrix& aTransform = Matrix())
{
Float kappaX = aKappaFactor * aRadius.width;
Float kappaY = aKappaFactor * aRadius.height;
@ -45,7 +46,7 @@ inline void PartialArcToBezier(T* aSink,
Point cp2 =
aEndPoint + Point(aEndOffset.y * kappaX, -aEndOffset.x * kappaY);
aSink->BezierTo(cp1, cp2, aEndPoint);
aSink->BezierTo(aTransform * cp1, aTransform * cp2, aTransform * aEndPoint);
}
/**
@ -90,7 +91,8 @@ inline void AcuteArcToBezier(T* aSink,
template <typename T>
void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius,
float aStartAngle, float aEndAngle, bool aAntiClockwise)
float aStartAngle, float aEndAngle, bool aAntiClockwise,
float aRotation = 0.0f)
{
Float sweepDirection = aAntiClockwise ? -1.0f : 1.0f;
@ -111,23 +113,24 @@ void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius,
Float currentStartAngle = aStartAngle;
Point currentStartOffset(cosf(aStartAngle), sinf(aStartAngle));
Point currentStartPoint(aOrigin.x + currentStartOffset.x * aRadius.width,
aOrigin.y + currentStartOffset.y * aRadius.height);
aSink->LineTo(currentStartPoint);
Point currentStartPoint(currentStartOffset.x * aRadius.width,
currentStartOffset.y * aRadius.height);
Matrix transform(cosf(aRotation), sinf(aRotation), -sinf(aRotation), cosf(aRotation), aOrigin.x, aOrigin.y);
aSink->LineTo(transform * currentStartPoint);
while (arcSweepLeft > 0) {
Float currentEndAngle =
currentStartAngle + std::min(arcSweepLeft, Float(M_PI / 2.0f)) * sweepDirection;
Point currentEndOffset(cosf(currentEndAngle), sinf(currentEndAngle));
Point currentEndPoint(aOrigin.x + currentEndOffset.x * aRadius.width,
aOrigin.y + currentEndOffset.y * aRadius.height);
Point currentEndPoint(currentEndOffset.x * aRadius.width,
currentEndOffset.y * aRadius.height);
PartialArcToBezier(aSink, aRadius,
currentStartPoint, currentEndPoint,
currentStartOffset, currentEndOffset,
ComputeKappaFactor(currentEndAngle - currentStartAngle));
ComputeKappaFactor(currentEndAngle - currentStartAngle),
transform);
// We guarantee here the current point is the start point of the next
// curve segment.