зеркало из https://github.com/mozilla/gecko-dev.git
Bug 684479 - Bounding boxes for strokes are unnecessarily big for many shapes. r=roc
This commit is contained in:
Родитель
e47cab333b
Коммит
af30ad46e4
|
@ -60,6 +60,7 @@ _TEST_FILES = \
|
|||
test_animLengthUnits.xhtml \
|
||||
test_bbox.xhtml \
|
||||
test_bbox-with-invalid-viewBox.xhtml \
|
||||
test_bounds.html \
|
||||
bbox-helper.svg \
|
||||
bounds-helper.svg \
|
||||
test_dataTypes.html \
|
||||
|
|
|
@ -7,24 +7,23 @@ text { font: 20px monospace; }
|
|||
|
||||
<g id="g">
|
||||
<text id="text1" x="25" y="25">abc</text>
|
||||
<text id="text1a" x="85" y="25" stroke="black" stroke-width="4">abc</text>
|
||||
<rect id="rect1" x="50" y="50" width="50" height="50" fill="green"/>
|
||||
<rect id="rect1a" x="50" y="50" width="50" height="50" fill="none" stroke-width="2" stroke="yellow"/>
|
||||
<rect id="rect1a" x="50" y="50" width="50" height="50" fill="none" stroke-width="4" stroke="yellow"/>
|
||||
<text id="text2" x="125" y="25">abc</text>
|
||||
<text id="text2a" x="185" y="25" stroke="black" stroke-width="10">abc</text>
|
||||
<g transform="rotate(45 175 75)">
|
||||
<rect id="rect2" x="150" y="50" width="50" height="50" fill="yellow"/>
|
||||
<rect id="rect2a" x="150" y="50" width="50" height="50" fill="none" stroke-width="2" stroke="blue"/>
|
||||
<rect id="rect2a" x="150" y="50" width="50" height="50" fill="none" stroke-width="4" stroke="blue"/>
|
||||
<text id="text3" x="150" y="50" text-anchor="middle">abc</text>
|
||||
</g>
|
||||
<g transform="scale(2)">
|
||||
<rect id="rect3" x="25" y="80" width="50" height="50" fill="green"/>
|
||||
<rect id="rect3a" x="25" y="80" width="50" height="50" fill="none" stroke-width="2" stroke="blue"/>
|
||||
<rect id="rect3a" x="25" y="80" width="50" height="50" fill="none" stroke-width="4" stroke="blue"/>
|
||||
</g>
|
||||
<g transform="scale(2) rotate(45 175 75)">
|
||||
<rect id="rect4" x="150" y="50" width="50" height="50" fill="yellow"/>
|
||||
<rect id="rect4a" x="150" y="50" width="50" height="50" fill="none" stroke-width="2" stroke="blue"/>
|
||||
<text id="text4" x="125" y="125">abc</text>
|
||||
<rect id="rect4a" x="150" y="50" width="50" height="50" fill="none" stroke-width="4" stroke="blue"/>
|
||||
</g>
|
||||
<text id="text1a" x="85" y="25" stroke="black" stroke-width="1">M</text>
|
||||
<text id="text2a" x="185" y="25" stroke="black" stroke-width="10">M</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 1.4 KiB После Ширина: | Высота: | Размер: 1.4 KiB |
|
@ -19,101 +19,120 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=463934
|
|||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function Rect(left, top, width, height)
|
||||
{
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
Rect.prototype.roundOut = function()
|
||||
{
|
||||
this.width = Math.ceil(this.left + this.width) - Math.floor(this.left);
|
||||
this.height = Math.ceil(this.top + this.height) - Math.floor(this.top);
|
||||
this.left = Math.floor(this.left);
|
||||
this.top = Math.floor(this.top);
|
||||
}
|
||||
|
||||
var delta = 1;
|
||||
|
||||
function isApproximately(a, b, message)
|
||||
{
|
||||
ok(delta >= Math.abs(a - b), message + " - got " + a + ", expected " + b + " ± " + delta);
|
||||
}
|
||||
|
||||
function runTest()
|
||||
{
|
||||
function isRounded(a, b, message) {
|
||||
is (Math.round(a), Math.round(b), message);
|
||||
}
|
||||
|
||||
var doc = $("svg").contentWindow.document;
|
||||
|
||||
var text1 = doc.getElementById("text1");
|
||||
|
||||
var len = text1.getComputedTextLength();
|
||||
|
||||
var text1Bounds = text1.getBoundingClientRect();
|
||||
var text2Bounds = doc.getElementById("text2").getBoundingClientRect();
|
||||
var text3Bounds = doc.getElementById("text3").getBoundingClientRect();
|
||||
var text4Bounds = doc.getElementById("text4").getBoundingClientRect();
|
||||
|
||||
var sin45 = Math.sin(Math.PI / 4);
|
||||
|
||||
isRounded(text1Bounds.left, 25, "text1.getBoundingClientRect().left");
|
||||
isRounded(text1Bounds.width, len, "text1.getBoundingClientRect().width");
|
||||
isApproximately(text1Bounds.left, 24, "text1.getBoundingClientRect().left");
|
||||
|
||||
isRounded(text2Bounds.left, text1Bounds.left + 100, "text2.getBoundingClientRect().left");
|
||||
isRounded(text2Bounds.top, text1Bounds.top, "text2.getBoundingClientRect().top");
|
||||
isRounded(text2Bounds.width, text1Bounds.width, "text2.getBoundingClientRect().width");
|
||||
isRounded(text2Bounds.height, text1Bounds.height, "text2.getBoundingClientRect().height");
|
||||
is(text2Bounds.left, text1Bounds.left + 100, "text2.getBoundingClientRect().left");
|
||||
is(text2Bounds.top, text1Bounds.top, "text2.getBoundingClientRect().top");
|
||||
is(text2Bounds.width, text1Bounds.width, "text2.getBoundingClientRect().width");
|
||||
is(text2Bounds.height, text1Bounds.height, "text2.getBoundingClientRect().height");
|
||||
|
||||
isRounded(text3Bounds.width, (text1Bounds.width + text1Bounds.height) * sin45 + .5, "text3.getBoundingClientRect().width");
|
||||
isRounded(text3Bounds.height, (text1Bounds.height + text1Bounds.width) * sin45 + .5, "text3.getBoundingClientRect().height");
|
||||
|
||||
isRounded(text4Bounds.width, 2 * (text1Bounds.width + text1Bounds.height) * sin45, "text4.getBoundingClientRect().width");
|
||||
isRounded(text4Bounds.height, 2 * ((text1Bounds.height + text1Bounds.width) * sin45 - .5), "text4.getBoundingClientRect().height");
|
||||
var r = (text1Bounds.width + text1Bounds.height) * sin45;
|
||||
isApproximately(text3Bounds.width, Math.ceil(r), "text3.getBoundingClientRect().width");
|
||||
isApproximately(text3Bounds.height, Math.ceil(r), "text3.getBoundingClientRect().height");
|
||||
|
||||
var rect1Bounds = doc.getElementById("rect1").getBoundingClientRect();
|
||||
var rect2Bounds = doc.getElementById("rect2").getBoundingClientRect();
|
||||
var rect3Bounds = doc.getElementById("rect3").getBoundingClientRect();
|
||||
var rect4Bounds = doc.getElementById("rect4").getBoundingClientRect();
|
||||
|
||||
isRounded(rect1Bounds.left, 50, "rect1.getBoundingClientRect().left");
|
||||
isRounded(rect1Bounds.top, 50, "rect1.getBoundingClientRect().top");
|
||||
isRounded(rect1Bounds.width, 50, "rect1.getBoundingClientRect().width");
|
||||
isRounded(rect1Bounds.height, 50, "rect1.getBoundingClientRect().height");
|
||||
is(rect1Bounds.left, 50, "rect1.getBoundingClientRect().left");
|
||||
is(rect1Bounds.top, 50, "rect1.getBoundingClientRect().top");
|
||||
is(rect1Bounds.width, 50, "rect1.getBoundingClientRect().width");
|
||||
is(rect1Bounds.height, 50, "rect1.getBoundingClientRect().height");
|
||||
|
||||
isRounded(rect2Bounds.left, 175 - 50 * sin45 - .5, "rect2.getBoundingClientRect().left");
|
||||
isRounded(rect2Bounds.top, 75 - 50 * sin45 - .5, "rect2.getBoundingClientRect().top");
|
||||
isRounded(rect2Bounds.width, (50 * sin45 + .5) * 2, "rect2.getBoundingClientRect().width");
|
||||
isRounded(rect2Bounds.height, (50 * sin45 + .5) * 2, "rect2.getBoundingClientRect().height");
|
||||
rect = new Rect(175 - 50 * sin45, 75 - 50 * sin45, 50 * sin45 * 2, 50 * sin45 * 2);
|
||||
rect.roundOut();
|
||||
is(rect2Bounds.left, rect.left, "rect2.getBoundingClientRect().left");
|
||||
is(rect2Bounds.top, rect.top, "rect2.getBoundingClientRect().top");
|
||||
is(rect2Bounds.width, rect.width, "rect2.getBoundingClientRect().width");
|
||||
is(rect2Bounds.height, rect.height, "rect2.getBoundingClientRect().height");
|
||||
|
||||
isRounded(rect3Bounds.left, 50, "rect3.getBoundingClientRect().left");
|
||||
isRounded(rect3Bounds.top, 160, "rect3.getBoundingClientRect().top");
|
||||
isRounded(rect3Bounds.width, 100, "rect3.getBoundingClientRect().width");
|
||||
isRounded(rect3Bounds.height, 100, "rect3.getBoundingClientRect().height");
|
||||
is(rect3Bounds.left, 50, "rect3.getBoundingClientRect().left");
|
||||
is(rect3Bounds.top, 160, "rect3.getBoundingClientRect().top");
|
||||
is(rect3Bounds.width, 100, "rect3.getBoundingClientRect().width");
|
||||
is(rect3Bounds.height, 100, "rect3.getBoundingClientRect().height");
|
||||
|
||||
isRounded(rect4Bounds.left, 350 - 100 * sin45 - .5, "rect4.getBoundingClientRect().left");
|
||||
isRounded(rect4Bounds.top, 150 - 100 * sin45 - .5, "rect4.getBoundingClientRect().top");
|
||||
isRounded(rect4Bounds.width, (100 * sin45 + .5) * 2, "rect4.getBoundingClientRect().width");
|
||||
isRounded(rect4Bounds.height, (100 * sin45 + .5) * 2, "rect4.getBoundingClientRect().height");
|
||||
rect = new Rect(350 - 100 * sin45, 150 - 100 * sin45, 100 * sin45 * 2, 100 * sin45 * 2);
|
||||
rect.roundOut();
|
||||
is(rect4Bounds.left, rect.left, "rect4.getBoundingClientRect().left");
|
||||
is(rect4Bounds.top, rect.top, "rect4.getBoundingClientRect().top");
|
||||
is(rect4Bounds.width, rect.width, "rect4.getBoundingClientRect().width");
|
||||
is(rect4Bounds.height, rect.height, "rect4.getBoundingClientRect().height");
|
||||
|
||||
var rect1aBounds = doc.getElementById("rect1a").getBoundingClientRect();
|
||||
var rect2aBounds = doc.getElementById("rect2a").getBoundingClientRect();
|
||||
var rect3aBounds = doc.getElementById("rect3a").getBoundingClientRect();
|
||||
var rect4aBounds = doc.getElementById("rect4a").getBoundingClientRect();
|
||||
|
||||
isRounded(rect1aBounds.left, 49, "rect1a.getBoundingClientRect().left");
|
||||
isRounded(rect1aBounds.top, 49, "rect1a.getBoundingClientRect().top");
|
||||
isRounded(rect1aBounds.width, 52, "rect1a.getBoundingClientRect().width");
|
||||
isRounded(rect1aBounds.height, 52, "rect1a.getBoundingClientRect().height");
|
||||
is(rect1aBounds.left, 48, "rect1a.getBoundingClientRect().left");
|
||||
is(rect1aBounds.top, 48, "rect1a.getBoundingClientRect().top");
|
||||
is(rect1aBounds.width, 54, "rect1a.getBoundingClientRect().width");
|
||||
is(rect1aBounds.height, 54, "rect1a.getBoundingClientRect().height");
|
||||
|
||||
isRounded(rect2aBounds.left, 175 - 52 * sin45 - .5, "rect2a.getBoundingClientRect().left");
|
||||
isRounded(rect2aBounds.top, 75 - 52 * sin45 - .5, "rect2a.getBoundingClientRect().top");
|
||||
isRounded(rect2aBounds.width, 52 * sin45 * 2, "rect2a.getBoundingClientRect().width");
|
||||
isRounded(rect2aBounds.height, 52 * sin45 * 2, "rect2a.getBoundingClientRect().height");
|
||||
rect = new Rect(175 - 54 * sin45, 75 - 54 * sin45, 54 * sin45 * 2, 54 * sin45 * 2);
|
||||
rect.roundOut();
|
||||
is(rect2aBounds.left, rect.left, "rect2a.getBoundingClientRect().left");
|
||||
is(rect2aBounds.top, rect.top, "rect2a.getBoundingClientRect().top");
|
||||
is(rect2aBounds.width, rect.width, "rect2a.getBoundingClientRect().width");
|
||||
is(rect2aBounds.height, rect.height, "rect2a.getBoundingClientRect().height");
|
||||
|
||||
isRounded(rect3aBounds.left, 48, "rect3a.getBoundingClientRect().left");
|
||||
isRounded(rect3aBounds.top, 158, "rect3a.getBoundingClientRect().top");
|
||||
isRounded(rect3aBounds.width, 104, "rect3a.getBoundingClientRect().width");
|
||||
isRounded(rect3aBounds.height, 104, "rect3a.getBoundingClientRect().height");
|
||||
is(rect3aBounds.left, 46, "rect3a.getBoundingClientRect().left");
|
||||
is(rect3aBounds.top, 156, "rect3a.getBoundingClientRect().top");
|
||||
is(rect3aBounds.width, 108, "rect3a.getBoundingClientRect().width");
|
||||
is(rect3aBounds.height, 108, "rect3a.getBoundingClientRect().height");
|
||||
|
||||
isRounded(rect4aBounds.left, 350 - 104 * sin45 - .5, "rect4a.getBoundingClientRect().left");
|
||||
isRounded(rect4aBounds.top, 150 - 104 * sin45 - .5, "rect4a.getBoundingClientRect().top");
|
||||
isRounded(rect4aBounds.width, (104 * sin45 + .5) * 2, "rect4a.getBoundingClientRect().width");
|
||||
isRounded(rect4aBounds.height, (104 * sin45 + .5) * 2, "rect4a.getBoundingClientRect().height");
|
||||
rect = new Rect(350 - 108 * sin45, 150 - 108 * sin45, 108 * sin45 * 2, 108 * sin45 * 2);
|
||||
rect.roundOut();
|
||||
is(rect4aBounds.left, rect.left, "rect4a.getBoundingClientRect().left");
|
||||
is(rect4aBounds.top, rect.top, "rect4a.getBoundingClientRect().top");
|
||||
is(rect4aBounds.width, rect.width, "rect4a.getBoundingClientRect().width");
|
||||
is(rect4aBounds.height, rect.height, "rect4a.getBoundingClientRect().height");
|
||||
|
||||
var text1a = doc.getElementById("text1a");
|
||||
|
||||
var text1aBounds = text1a.getBoundingClientRect();
|
||||
var text2aBounds = doc.getElementById("text2a").getBoundingClientRect();
|
||||
|
||||
var len = text1a.getComputedTextLength();
|
||||
isApproximately(text1aBounds.left, 82, "text1a.getBoundingClientRect().left");
|
||||
is(text1aBounds.width, text1Bounds.width + 4, "text1a.getBoundingClientRect().width");
|
||||
|
||||
isRounded(text1aBounds.left, 85 - 1, "text1a.getBoundingClientRect().left");
|
||||
isRounded(text1aBounds.width, len + 1, "text1a.getBoundingClientRect().width");
|
||||
|
||||
isRounded(text2aBounds.left, text1aBounds.left + 100 - 4, "text2a.getBoundingClientRect().left");
|
||||
isRounded(text2aBounds.width, text1aBounds.width + 9, "text2a.getBoundingClientRect().width");
|
||||
is(text2aBounds.left, text1aBounds.left + 100 - 3, "text2a.getBoundingClientRect().left");
|
||||
is(text2aBounds.width, text1aBounds.width + 6, "text2a.getBoundingClientRect().width");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -69,7 +69,6 @@
|
|||
#include "nsGenericElement.h"
|
||||
#include "nsSVGGraphicElement.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsSVGGeometryFrame.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxMatrix.h"
|
||||
|
@ -85,6 +84,7 @@
|
|||
#include "nsSVGGeometryFrame.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsSVGPathGeometryFrame.h"
|
||||
#include "nsSVGPathGeometryElement.h"
|
||||
#include "prdtoa.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "gfxUtils.h"
|
||||
|
@ -1431,26 +1431,14 @@ nsSVGUtils::WritePPM(const char *fname, gfxImageSurface *aSurface)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*static*/ gfxRect
|
||||
nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
|
||||
nsSVGGeometryFrame* aFrame)
|
||||
// The logic here comes from _cairo_stroke_style_max_distance_from_path
|
||||
static gfxRect
|
||||
PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
|
||||
nsSVGGeometryFrame* aFrame,
|
||||
double styleExpansionFactor)
|
||||
{
|
||||
// The logic here comes from _cairo_stroke_style_max_distance_from_path
|
||||
|
||||
double style_expansion = 0.5;
|
||||
|
||||
const nsStyleSVG* style = aFrame->GetStyleSVG();
|
||||
|
||||
if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
|
||||
style_expansion = M_SQRT1_2;
|
||||
}
|
||||
|
||||
if (style->mStrokeLinejoin == NS_STYLE_STROKE_LINEJOIN_MITER &&
|
||||
style_expansion < style->mStrokeMiterlimit) {
|
||||
style_expansion = style->mStrokeMiterlimit;
|
||||
}
|
||||
|
||||
style_expansion *= aFrame->GetStrokeWidth();
|
||||
double style_expansion =
|
||||
styleExpansionFactor * aFrame->GetStrokeWidth();
|
||||
|
||||
gfxMatrix ctm = aFrame->GetCanvasTM();
|
||||
|
||||
|
@ -1462,6 +1450,38 @@ nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
|
|||
return strokeExtents;
|
||||
}
|
||||
|
||||
/*static*/ gfxRect
|
||||
nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
|
||||
nsSVGGeometryFrame* aFrame)
|
||||
{
|
||||
return ::PathExtentsToMaxStrokeExtents(aPathExtents, aFrame, 0.5);
|
||||
}
|
||||
|
||||
/*static*/ gfxRect
|
||||
nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
|
||||
nsSVGPathGeometryFrame* aFrame)
|
||||
{
|
||||
double styleExpansionFactor = 0.5;
|
||||
|
||||
if (static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
|
||||
const nsStyleSVG* style = aFrame->GetStyleSVG();
|
||||
|
||||
if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
|
||||
styleExpansionFactor = M_SQRT1_2;
|
||||
}
|
||||
|
||||
if (style->mStrokeLinejoin == NS_STYLE_STROKE_LINEJOIN_MITER &&
|
||||
styleExpansionFactor < style->mStrokeMiterlimit &&
|
||||
aFrame->GetContent()->Tag() != nsGkAtoms::line) {
|
||||
styleExpansionFactor = style->mStrokeMiterlimit;
|
||||
}
|
||||
}
|
||||
|
||||
return ::PathExtentsToMaxStrokeExtents(aPathExtents,
|
||||
aFrame,
|
||||
styleExpansionFactor);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
nsSVGRenderState::nsSVGRenderState(nsRenderingContext *aContext) :
|
||||
|
|
|
@ -76,6 +76,7 @@ struct nsStyleFont;
|
|||
class nsSVGEnum;
|
||||
class nsISVGChildFrame;
|
||||
class nsSVGGeometryFrame;
|
||||
class nsSVGPathGeometryFrame;
|
||||
class nsSVGDisplayContainerFrame;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -564,6 +565,8 @@ public:
|
|||
*/
|
||||
static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
|
||||
nsSVGGeometryFrame* aFrame);
|
||||
static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
|
||||
nsSVGPathGeometryFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Convert a floating-point value to a 32-bit integer value, clamping to
|
||||
|
|
Загрузка…
Ссылка в новой задаче