mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 04:15:43 +00:00
Bug 471281. Reimplement arcTo() to match Canvas spec. r=jrmuizel
This is based on Philip Taylor's emulation written in JavasScript.
This commit is contained in:
parent
2b712738f6
commit
b8ea13fb7a
@ -1751,83 +1751,53 @@ nsCanvasRenderingContext2D::ArcTo(float x1, float y1, float x2, float y2, float
|
|||||||
if (!FloatValidate(x1,y1,x2,y2,radius))
|
if (!FloatValidate(x1,y1,x2,y2,radius))
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
|
|
||||||
if (radius <= 0)
|
if (radius < 0)
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
|
|
||||||
/* This is an adaptation of the cairo_arc_to patch from Behdad
|
|
||||||
* Esfahbod; once that patch is accepted, we should remove this
|
|
||||||
* and just call cairo_arc_to() directly.
|
|
||||||
*/
|
|
||||||
|
|
||||||
double angle0, angle1, angle2, angled;
|
|
||||||
double d0, d2;
|
|
||||||
double sin_, cos_;
|
|
||||||
double dc;
|
|
||||||
int forward;
|
|
||||||
|
|
||||||
gfxPoint p0 = mThebes->CurrentPoint();
|
gfxPoint p0 = mThebes->CurrentPoint();
|
||||||
|
|
||||||
angle0 = atan2 (p0.y - y1, p0.x - x1); /* angle from (x1,y1) to (p0.x,p0.y) */
|
double dir, a2, b2, c2, cosx, sinx, d, anx, any, bnx, bny, x3, y3, x4, y4, cx, cy, angle0, angle1;
|
||||||
angle2 = atan2 (y2 - y1, x2 - x1); /* angle from (x1,y1) to (x2,y2) */
|
bool anticlockwise;
|
||||||
angle1 = (angle0 + angle2) / 2; /* angle from (x1,y1) to (xc,yc) */
|
|
||||||
|
|
||||||
angled = angle2 - angle0; /* the angle (p0.x,p0.y)--(x1,y1)--(x2,y2) */
|
if ((x1 == p0.x && y1 == p0.y) || (x1 == x2 && y1 == y2) || radius == 0) {
|
||||||
|
mThebes->LineTo(gfxPoint(x1, y1));
|
||||||
/* Shall we go forward or backward? */
|
return NS_OK;
|
||||||
if (angled > M_PI || (angled < 0 && angled > -M_PI)) {
|
|
||||||
angle1 += M_PI;
|
|
||||||
angled = 2 * M_PI - angled;
|
|
||||||
forward = 1;
|
|
||||||
} else {
|
|
||||||
double tmp;
|
|
||||||
tmp = angle0;
|
|
||||||
angle0 = angle2;
|
|
||||||
angle2 = tmp;
|
|
||||||
forward = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
angle0 += M_PI_2; /* angle from (xc,yc) to (p0.x,p0.y) */
|
dir = (x2-x1)*(p0.y-y1) + (y2-y1)*(x1-p0.x);
|
||||||
angle2 -= M_PI_2; /* angle from (xc,yc) to (x2,y2) */
|
if (dir == 0) {
|
||||||
angled /= 2; /* the angle (p0.x,p0.y)--(x1,y1)--(xc,yc) */
|
mThebes->LineTo(gfxPoint(x1, y1));
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
/* distance from (x1,y1) to (p0.x,p0.y) */
|
|
||||||
d0 = sqrt ((p0.x-x1)*(p0.x-x1)+(p0.y-y1)*(p0.y-y1));
|
|
||||||
/* distance from (x2,y2) to (p0.x,p0.y) */
|
|
||||||
d2 = sqrt ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
|
|
||||||
|
|
||||||
dc = -1;
|
|
||||||
sin_ = sin(angled);
|
|
||||||
cos_ = cos(angled);
|
|
||||||
if (fabs(cos_) >= 1e-5) { /* the arc may not fit */
|
|
||||||
/* min distance of end-points from corner */
|
|
||||||
double min_d = d0 < d2 ? d0 : d2;
|
|
||||||
/* max radius of an arc that fits */
|
|
||||||
double max_r = min_d * sin_ / cos_;
|
|
||||||
|
|
||||||
if (radius > max_r) {
|
|
||||||
/* arc with requested radius doesn't fit */
|
|
||||||
radius = (float) max_r;
|
|
||||||
dc = min_d / cos_; /* distance of (xc,yc) from (x1,y1) */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dc < 0)
|
a2 = (p0.x-x1)*(p0.x-x1) + (p0.y-y1)*(p0.y-y1);
|
||||||
dc = radius / sin_; /* distance of (xc,yc) from (x1,y1) */
|
b2 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
|
||||||
|
c2 = (p0.x-x2)*(p0.x-x2) + (p0.y-y2)*(p0.y-y2);
|
||||||
|
cosx = (a2+b2-c2)/(2*sqrt(a2*b2));
|
||||||
|
|
||||||
|
sinx = sqrt(1 - cosx*cosx);
|
||||||
|
d = radius / ((1 - cosx) / sinx);
|
||||||
|
|
||||||
/* find (cx,cy), the center of the arc */
|
anx = (x1-p0.x) / sqrt(a2);
|
||||||
gfxPoint c(x1 + sin(angle1) * dc, y1 + cos(angle1) * dc);
|
any = (y1-p0.y) / sqrt(a2);
|
||||||
|
bnx = (x1-x2) / sqrt(b2);
|
||||||
|
bny = (y1-y2) / sqrt(b2);
|
||||||
|
x3 = x1 - anx*d;
|
||||||
|
y3 = y1 - any*d;
|
||||||
|
x4 = x1 - bnx*d;
|
||||||
|
y4 = y1 - bny*d;
|
||||||
|
anticlockwise = (dir < 0);
|
||||||
|
cx = x3 + any*radius*(anticlockwise ? 1 : -1);
|
||||||
|
cy = y3 - anx*radius*(anticlockwise ? 1 : -1);
|
||||||
|
angle0 = atan2((y3-cy), (x3-cx));
|
||||||
|
angle1 = atan2((y4-cy), (x4-cx));
|
||||||
|
|
||||||
/* the arc operation draws the line from current point (p0.x,p0.y)
|
mThebes->LineTo(gfxPoint(x3, y3));
|
||||||
* to arc center too. */
|
|
||||||
|
|
||||||
if (forward)
|
if (anticlockwise)
|
||||||
mThebes->Arc(c, radius, angle0, angle2);
|
mThebes->NegativeArc(gfxPoint(cx, cy), radius, angle0, angle1);
|
||||||
else
|
else
|
||||||
mThebes->NegativeArc(c, radius, angle2, angle0);
|
mThebes->Arc(gfxPoint(cx, cy), radius, angle0, angle1);
|
||||||
|
|
||||||
mThebes->LineTo(gfxPoint(x2, y2));
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,9 @@ ctx.moveTo(50, 25);
|
|||||||
ctx.arcTo(50, 25, 100, 25, 1);
|
ctx.arcTo(50, 25, 100, 25, 1);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
todo_isPixel(ctx, 50,1, 0,255,0,255, "50,1", "0,255,0,255", 0);
|
isPixel(ctx, 50,1, 0,255,0,255, "50,1", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 50,48, 0,255,0,255, "50,48", "0,255,0,255", 0);
|
isPixel(ctx, 50,48, 0,255,0,255, "50,48", "0,255,0,255", 0);
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ ctx.moveTo(-100, 25);
|
|||||||
ctx.arcTo(0, 25, 100, 25, 1);
|
ctx.arcTo(0, 25, 100, 25, 1);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
todo_isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
|
||||||
|
@ -69,8 +69,8 @@ isPixel(ctx, 73,27, 0,255,0,255, "73,27", "0,255,0,255", 0);
|
|||||||
isPixel(ctx, 78,36, 0,255,0,255, "78,36", "0,255,0,255", 0);
|
isPixel(ctx, 78,36, 0,255,0,255, "78,36", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 79,35, 0,255,0,255, "79,35", "0,255,0,255", 0);
|
isPixel(ctx, 79,35, 0,255,0,255, "79,35", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 80,44, 0,255,0,255, "80,44", "0,255,0,255", 0);
|
isPixel(ctx, 80,44, 0,255,0,255, "80,44", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 80,45, 0,255,0,255, "80,45", "0,255,0,255", 0);
|
isPixel(ctx, 80,45, 0,255,0,255, "80,45", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 80,46, 0,255,0,255, "80,46", "0,255,0,255", 0);
|
isPixel(ctx, 80,46, 0,255,0,255, "80,46", "0,255,0,255", 0);
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
|
||||||
|
@ -58,13 +58,13 @@ ctx.moveTo(10, 25);
|
|||||||
ctx.arcTo(75, 25, 75, 60, 20);
|
ctx.arcTo(75, 25, 75, 60, 20);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
todo_isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 55,19, 0,255,0,255, "55,19", "0,255,0,255", 0);
|
isPixel(ctx, 55,19, 0,255,0,255, "55,19", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 55,20, 0,255,0,255, "55,20", "0,255,0,255", 0);
|
isPixel(ctx, 55,20, 0,255,0,255, "55,20", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 55,21, 0,255,0,255, "55,21", "0,255,0,255", 0);
|
isPixel(ctx, 55,21, 0,255,0,255, "55,21", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 64,22, 0,255,0,255, "64,22", "0,255,0,255", 0);
|
isPixel(ctx, 64,22, 0,255,0,255, "64,22", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 65,21, 0,255,0,255, "65,21", "0,255,0,255", 0);
|
isPixel(ctx, 65,21, 0,255,0,255, "65,21", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 72,28, 0,255,0,255, "72,28", "0,255,0,255", 0);
|
isPixel(ctx, 72,28, 0,255,0,255, "72,28", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 73,27, 0,255,0,255, "73,27", "0,255,0,255", 0);
|
isPixel(ctx, 73,27, 0,255,0,255, "73,27", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 78,36, 0,255,0,255, "78,36", "0,255,0,255", 0);
|
isPixel(ctx, 78,36, 0,255,0,255, "78,36", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 79,35, 0,255,0,255, "79,35", "0,255,0,255", 0);
|
isPixel(ctx, 79,35, 0,255,0,255, "79,35", "0,255,0,255", 0);
|
||||||
|
@ -48,10 +48,10 @@ ctx.arcTo(-100, 25, 200, 25, 10);
|
|||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
isPixel(ctx, 1,1, 0,255,0,255, "1,1", "0,255,0,255", 0);
|
isPixel(ctx, 1,1, 0,255,0,255, "1,1", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 1,48, 0,255,0,255, "1,48", "0,255,0,255", 0);
|
isPixel(ctx, 1,48, 0,255,0,255, "1,48", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 98,1, 0,255,0,255, "98,1", "0,255,0,255", 0);
|
isPixel(ctx, 98,1, 0,255,0,255, "98,1", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 98,48, 0,255,0,255, "98,48", "0,255,0,255", 0);
|
isPixel(ctx, 98,48, 0,255,0,255, "98,48", "0,255,0,255", 0);
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
|
||||||
|
@ -48,10 +48,10 @@ ctx.arcTo(200, 25, 200, 50, 10);
|
|||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
isPixel(ctx, 1,1, 0,255,0,255, "1,1", "0,255,0,255", 0);
|
isPixel(ctx, 1,1, 0,255,0,255, "1,1", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 1,48, 0,255,0,255, "1,48", "0,255,0,255", 0);
|
isPixel(ctx, 1,48, 0,255,0,255, "1,48", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
||||||
isPixel(ctx, 98,1, 0,255,0,255, "98,1", "0,255,0,255", 0);
|
isPixel(ctx, 98,1, 0,255,0,255, "98,1", "0,255,0,255", 0);
|
||||||
todo_isPixel(ctx, 98,48, 0,255,0,255, "98,48", "0,255,0,255", 0);
|
isPixel(ctx, 98,48, 0,255,0,255, "98,48", "0,255,0,255", 0);
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
_thrown_outer = true;
|
_thrown_outer = true;
|
||||||
}
|
}
|
||||||
todo(!_thrown_outer, 'should not throw exception');
|
ok(!_thrown_outer, 'should not throw exception');
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ isPixel(ctx, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 0);
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
_thrown_outer = true;
|
_thrown_outer = true;
|
||||||
}
|
}
|
||||||
todo(!_thrown_outer, 'should not throw exception');
|
ok(!_thrown_outer, 'should not throw exception');
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user