Bug 459148 - use thebes primitives for SVG rounded rects - r=longsonr,vlad sr=roc

This commit is contained in:
Zack Weinberg 2008-12-04 21:01:37 -08:00
Родитель d6e15171a0
Коммит 5f09cf12fb
5 изменённых файлов: 87 добавлений и 47 удалений

Просмотреть файл

@ -210,37 +210,7 @@ nsSVGRectElement::ConstructPath(gfxContext *aCtx)
else if (ry > halfHeight)
rx = ry = halfHeight;
// Conversion factor used for ellipse to bezier conversion.
// Gives radial error of 0.0273% in circular case.
// See comp.graphics.algorithms FAQ 4.04
const float magic = 4*(sqrt(2.)-1)/3;
const float magic_x = magic*rx;
const float magic_y = magic*ry;
aCtx->MoveTo(gfxPoint(x + rx, y));
aCtx->LineTo(gfxPoint(x + width - rx, y));
aCtx->CurveTo(gfxPoint(x + width - rx + magic_x, y),
gfxPoint(x + width, y + ry - magic_y),
gfxPoint(x + width, y + ry));
aCtx->LineTo(gfxPoint(x + width, y + height - ry));
aCtx->CurveTo(gfxPoint(x + width, y + height - ry + magic_y),
gfxPoint(x + width - rx + magic_x, y+height),
gfxPoint(x + width - rx, y + height));
aCtx->LineTo(gfxPoint(x + rx, y + height));
aCtx->CurveTo(gfxPoint(x + rx - magic_x, y + height),
gfxPoint(x, y + height - ry + magic_y),
gfxPoint(x, y + height - ry));
aCtx->LineTo(gfxPoint(x, y + ry));
aCtx->CurveTo(gfxPoint(x, y + ry - magic_y),
gfxPoint(x + rx - magic_x, y),
gfxPoint(x + rx, y));
aCtx->ClosePath();
gfxSize corner(rx, ry);
aCtx->RoundedRectangle(gfxRect(x, y, width, height),
gfxCornerSizes(corner, corner, corner, corner));
}

Просмотреть файл

@ -817,11 +817,8 @@ gfxContext::RoundedRectangle(const gfxRect& rect,
// *
// *
//
// Where 0, 1, 2, 3 are the control points of the Bezier curve for the corner,
// and C is the actual corner point.
//
// For details about representing an elliptical arc as a cubic Bezier curve,
// see http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
// Where 0, 1, 2, 3 are the control points of the Bezier curve for
// the corner, and C is the actual corner point.
//
// At the start of the loop, the current point is assumed to be
// the point adjacent to the top left corner on the top
@ -829,15 +826,54 @@ gfxContext::RoundedRectangle(const gfxRect& rect,
// continue clockwise, whereas in our loop i = 0 refers to the top
// right corner.
//
// When going CCW, the control points are swapped, and the first corner
// that's drawn is the top left (along with the top segment).
// This is (sqrt(7) - 1) / 3; this ends up falling out of the equations
// given in the above paper -- it's the value of alpha at the end of section
// 3.4.1 when n2 and n1 are 90 degrees apart. For the various corners, the
// axes the sign of this value changes, or it might be 0 -- it's multiplied by
// the appropriate multiplier from the list before using.
const gfxFloat alpha = 0.54858377035486361;
// When going CCW, the control points are swapped, and the first
// corner that's drawn is the top left (along with the top segment).
//
// There is considerable latitude in how one chooses the four
// control points for a Bezier curve approximation to an ellipse.
// For the overall path to be continuous and show no corner at the
// endpoints of the arc, points 0 and 3 must be at the ends of the
// straight segments of the rectangle; points 0, 1, and C must be
// collinear; and points 3, 2, and C must also be collinear. This
// leaves only two free parameters: the ratio of the line segments
// 01 and 0C, and the ratio of the line segments 32 and 3C. See
// the following papers for extensive discussion of how to choose
// these ratios:
//
// Dokken, Tor, et al. "Good approximation of circles by
// curvature-continuous Bezier curves." Computer-Aided
// Geometric Design 7(1990) 33--41.
// Goldapp, Michael. "Approximation of circular arcs by cubic
// polynomials." Computer-Aided Geometric Design 8(1991) 227--238.
// Maisonobe, Luc. "Drawing an elliptical arc using polylines,
// quadratic, or cubic Bezier curves."
// http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
//
// We follow the approach in section 2 of Goldapp (least-error,
// Hermite-type approximation) and make both ratios equal to
//
// 2 2 + n - sqrt(2n + 28)
// alpha = - * ---------------------
// 3 n - 4
//
// where n = 3( cbrt(sqrt(2)+1) - cbrt(sqrt(2)-1) ).
//
// This is the result of Goldapp's equation (10b) when the angle
// swept out by the arc is pi/2, and the parameter "a-bar" is the
// expression given immediately below equation (21).
//
// Using this value, the maximum radial error for a circle, as a
// fraction of the radius, is on the order of 0.2 x 10^-3.
// Neither Dokken nor Goldapp discusses error for a general
// ellipse; Maisonobe does, but his choice of control points
// follows different constraints, and Goldapp's expression for
// 'alpha' gives much smaller radial error, even for very flat
// ellipses, than Maisonobe's equivalent.
//
// For the various corners and for each axis, the sign of this
// constant changes, or it might be 0 -- it's multiplied by the
// appropriate multiplier from the list before using.
const gfxFloat alpha = 0.55191497064665766025;
typedef struct { gfxFloat a, b; } twoFloats;

Просмотреть файл

@ -0,0 +1,11 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<body style="margin: 0">
<svg width="100px" height="100px" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<rect style="fill: black; stroke: none"
width="70" height="70"
x="8" y="8"
rx="10" ry="10"/>
</svg>
</body>
</html>

Просмотреть файл

@ -0,0 +1,20 @@
<!doctype html>
<html><head>
<title>Circular border</title>
<style>
body { margin: 0 }
div {
margin-left: 8px; margin-top: 8px;
width: 50px; height: 50px;
border: 10px solid black;
-moz-border-radius: 10px;
}
div > div {
margin: 0; width: 50px; height: 50px;
-moz-border-radius: 0;
background: black;
border: none;
}
</style>
</head>
<body><div><div></div></div></body></html>

Просмотреть файл

@ -13,3 +13,6 @@
!= outline-square.html outline-circle.html
!= outline-square.html outline-ellips.html
!= outline-circle.html outline-ellips.html
# more serious tests, using SVG reference
== border-circle-2.html border-circle-2-ref.xhtml