зеркало из https://github.com/mozilla/gecko-dev.git
Bug 999964 part 1 - Patch for SVG 2 getBBox method; r=longsonr, r=bz
This commit is contained in:
Родитель
39b3a65e23
Коммит
29fc5495c2
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "gfx2DGlue.h"
|
#include "gfx2DGlue.h"
|
||||||
#include "mozilla/dom/SVGAnimatedTransformList.h"
|
#include "mozilla/dom/SVGAnimatedTransformList.h"
|
||||||
|
#include "mozilla/dom/SVGGraphicsElementBinding.h"
|
||||||
#include "mozilla/dom/SVGTransformableElement.h"
|
#include "mozilla/dom/SVGTransformableElement.h"
|
||||||
#include "mozilla/dom/SVGMatrix.h"
|
#include "mozilla/dom/SVGMatrix.h"
|
||||||
#include "mozilla/dom/SVGSVGElement.h"
|
#include "mozilla/dom/SVGSVGElement.h"
|
||||||
|
@ -182,7 +183,8 @@ SVGTransformableElement::GetFarthestViewportElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<SVGIRect>
|
already_AddRefed<SVGIRect>
|
||||||
SVGTransformableElement::GetBBox(ErrorResult& rv)
|
SVGTransformableElement::GetBBox(const SVGBoundingBoxOptions& aOptions,
|
||||||
|
ErrorResult& rv)
|
||||||
{
|
{
|
||||||
nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
|
nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
|
||||||
|
|
||||||
|
@ -190,14 +192,37 @@ SVGTransformableElement::GetBBox(ErrorResult& rv)
|
||||||
rv.Throw(NS_ERROR_FAILURE);
|
rv.Throw(NS_ERROR_FAILURE);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsISVGChildFrame* svgframe = do_QueryFrame(frame);
|
nsISVGChildFrame* svgframe = do_QueryFrame(frame);
|
||||||
if (!svgframe) {
|
if (!svgframe) {
|
||||||
rv.Throw(NS_ERROR_NOT_IMPLEMENTED); // XXX: outer svg
|
rv.Throw(NS_ERROR_NOT_IMPLEMENTED); // XXX: outer svg
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame)));
|
if (!NS_SVGNewGetBBoxEnabled()) {
|
||||||
|
return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame)));
|
||||||
|
} else {
|
||||||
|
uint32_t aFlags = 0;
|
||||||
|
if (aOptions.mFill) {
|
||||||
|
aFlags |= nsSVGUtils::eBBoxIncludeFill;
|
||||||
|
}
|
||||||
|
if (aOptions.mStroke) {
|
||||||
|
aFlags |= nsSVGUtils::eBBoxIncludeStroke;
|
||||||
|
}
|
||||||
|
if (aOptions.mMarkers) {
|
||||||
|
aFlags |= nsSVGUtils::eBBoxIncludeMarkers;
|
||||||
|
}
|
||||||
|
if (aOptions.mClipped) {
|
||||||
|
aFlags |= nsSVGUtils::eBBoxIncludeClipped;
|
||||||
|
}
|
||||||
|
if (aFlags == 0) {
|
||||||
|
return NS_NewSVGRect(this,0,0,0,0);
|
||||||
|
}
|
||||||
|
if (aFlags == nsSVGUtils::eBBoxIncludeMarkers ||
|
||||||
|
aFlags == nsSVGUtils::eBBoxIncludeClipped) {
|
||||||
|
aFlags |= nsSVGUtils::eBBoxIncludeFill;
|
||||||
|
}
|
||||||
|
return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame, aFlags)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<SVGMatrix>
|
already_AddRefed<SVGMatrix>
|
||||||
|
|
|
@ -19,6 +19,7 @@ class SVGAnimatedTransformList;
|
||||||
class SVGGraphicsElement;
|
class SVGGraphicsElement;
|
||||||
class SVGMatrix;
|
class SVGMatrix;
|
||||||
class SVGIRect;
|
class SVGIRect;
|
||||||
|
class SVGBoundingBoxOptions;
|
||||||
|
|
||||||
class SVGTransformableElement : public nsSVGElement
|
class SVGTransformableElement : public nsSVGElement
|
||||||
{
|
{
|
||||||
|
@ -33,7 +34,8 @@ public:
|
||||||
already_AddRefed<SVGAnimatedTransformList> Transform();
|
already_AddRefed<SVGAnimatedTransformList> Transform();
|
||||||
nsSVGElement* GetNearestViewportElement();
|
nsSVGElement* GetNearestViewportElement();
|
||||||
nsSVGElement* GetFarthestViewportElement();
|
nsSVGElement* GetFarthestViewportElement();
|
||||||
already_AddRefed<SVGIRect> GetBBox(ErrorResult& rv);
|
already_AddRefed<SVGIRect> GetBBox(const SVGBoundingBoxOptions& aOptions,
|
||||||
|
ErrorResult& rv);
|
||||||
already_AddRefed<SVGMatrix> GetCTM();
|
already_AddRefed<SVGMatrix> GetCTM();
|
||||||
already_AddRefed<SVGMatrix> GetScreenCTM();
|
already_AddRefed<SVGMatrix> GetScreenCTM();
|
||||||
already_AddRefed<SVGMatrix> GetTransformToElement(SVGGraphicsElement& aElement,
|
already_AddRefed<SVGMatrix> GetTransformToElement(SVGGraphicsElement& aElement,
|
||||||
|
|
|
@ -10,6 +10,13 @@
|
||||||
* liability, trademark and document use rules apply.
|
* liability, trademark and document use rules apply.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
dictionary SVGBoundingBoxOptions {
|
||||||
|
boolean fill = true;
|
||||||
|
boolean stroke = false;
|
||||||
|
boolean markers = false;
|
||||||
|
boolean clipped = false;
|
||||||
|
};
|
||||||
|
|
||||||
interface SVGGraphicsElement : SVGElement {
|
interface SVGGraphicsElement : SVGElement {
|
||||||
readonly attribute SVGAnimatedTransformList transform;
|
readonly attribute SVGAnimatedTransformList transform;
|
||||||
|
|
||||||
|
@ -17,7 +24,7 @@ interface SVGGraphicsElement : SVGElement {
|
||||||
readonly attribute SVGElement? farthestViewportElement;
|
readonly attribute SVGElement? farthestViewportElement;
|
||||||
|
|
||||||
[NewObject, Throws]
|
[NewObject, Throws]
|
||||||
SVGRect getBBox();
|
SVGRect getBBox(optional SVGBoundingBoxOptions aOptions);
|
||||||
// Not implemented
|
// Not implemented
|
||||||
// SVGRect getStrokeBBox();
|
// SVGRect getStrokeBBox();
|
||||||
SVGMatrix? getCTM();
|
SVGMatrix? getCTM();
|
||||||
|
|
|
@ -325,3 +325,45 @@ nsSVGClipPathFrame::GetCanvasTM(uint32_t aFor, nsIFrame* aTransformRoot)
|
||||||
&content->mEnumAttributes[SVGClipPathElement::CLIPPATHUNITS],
|
&content->mEnumAttributes[SVGClipPathElement::CLIPPATHUNITS],
|
||||||
mClipParent);
|
mClipParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SVGBBox
|
||||||
|
nsSVGClipPathFrame::GetBBoxForClipPathFrame(const SVGBBox &aBBox,
|
||||||
|
const gfxMatrix &aMatrix)
|
||||||
|
{
|
||||||
|
nsIContent* node = GetContent()->GetFirstChild();
|
||||||
|
SVGBBox unionBBox, tmpBBox;
|
||||||
|
for (; node; node = node->GetNextSibling()) {
|
||||||
|
nsIFrame *frame =
|
||||||
|
static_cast<nsSVGElement*>(node)->GetPrimaryFrame();
|
||||||
|
if (frame) {
|
||||||
|
nsISVGChildFrame *svg = do_QueryFrame(frame);
|
||||||
|
if (svg) {
|
||||||
|
tmpBBox = svg->GetBBoxContribution(mozilla::gfx::ToMatrix(aMatrix),
|
||||||
|
nsSVGUtils::eBBoxIncludeFill);
|
||||||
|
nsSVGEffects::EffectProperties effectProperties =
|
||||||
|
nsSVGEffects::GetEffectProperties(frame);
|
||||||
|
bool isOK = true;
|
||||||
|
nsSVGClipPathFrame *clipPathFrame =
|
||||||
|
effectProperties.GetClipPathFrame(&isOK);
|
||||||
|
if (clipPathFrame && isOK) {
|
||||||
|
tmpBBox = clipPathFrame->GetBBoxForClipPathFrame(tmpBBox, aMatrix);
|
||||||
|
}
|
||||||
|
tmpBBox.Intersect(aBBox);
|
||||||
|
unionBBox.UnionEdges(tmpBBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nsSVGEffects::EffectProperties props =
|
||||||
|
nsSVGEffects::GetEffectProperties(this);
|
||||||
|
if (props.mClipPath) {
|
||||||
|
bool isOK = true;
|
||||||
|
nsSVGClipPathFrame *clipPathFrame = props.GetClipPathFrame(&isOK);
|
||||||
|
if (clipPathFrame && isOK) {
|
||||||
|
tmpBBox = clipPathFrame->GetBBoxForClipPathFrame(aBBox, aMatrix);
|
||||||
|
unionBBox.Intersect(tmpBBox);
|
||||||
|
} else if (!isOK) {
|
||||||
|
unionBBox = SVGBBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unionBBox;
|
||||||
|
}
|
||||||
|
|
|
@ -75,6 +75,9 @@ public:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SVGBBox
|
||||||
|
GetBBoxForClipPathFrame(const SVGBBox &aBBox, const gfxMatrix &aMatrix);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// A helper class to allow us to paint clip paths safely. The helper
|
// A helper class to allow us to paint clip paths safely. The helper
|
||||||
// automatically sets and clears the mInUse flag on the clip path frame
|
// automatically sets and clears the mInUse flag on the clip path frame
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "nsSVGLength2.h"
|
#include "nsSVGLength2.h"
|
||||||
#include "nsSVGMaskFrame.h"
|
#include "nsSVGMaskFrame.h"
|
||||||
#include "nsSVGOuterSVGFrame.h"
|
#include "nsSVGOuterSVGFrame.h"
|
||||||
|
#include "mozilla/dom/SVGClipPathElement.h"
|
||||||
#include "mozilla/dom/SVGPathElement.h"
|
#include "mozilla/dom/SVGPathElement.h"
|
||||||
#include "nsSVGPathGeometryElement.h"
|
#include "nsSVGPathGeometryElement.h"
|
||||||
#include "nsSVGPathGeometryFrame.h"
|
#include "nsSVGPathGeometryFrame.h"
|
||||||
|
@ -57,6 +58,7 @@ using namespace mozilla::gfx;
|
||||||
|
|
||||||
static bool sSVGDisplayListHitTestingEnabled;
|
static bool sSVGDisplayListHitTestingEnabled;
|
||||||
static bool sSVGDisplayListPaintingEnabled;
|
static bool sSVGDisplayListPaintingEnabled;
|
||||||
|
static bool sSVGNewGetBBoxEnabled;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
NS_SVGDisplayListHitTestingEnabled()
|
NS_SVGDisplayListHitTestingEnabled()
|
||||||
|
@ -70,6 +72,13 @@ NS_SVGDisplayListPaintingEnabled()
|
||||||
return sSVGDisplayListPaintingEnabled;
|
return sSVGDisplayListPaintingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NS_SVGNewGetBBoxEnabled()
|
||||||
|
{
|
||||||
|
return sSVGNewGetBBoxEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// we only take the address of this:
|
// we only take the address of this:
|
||||||
static mozilla::gfx::UserDataKey sSVGAutoRenderStateKey;
|
static mozilla::gfx::UserDataKey sSVGAutoRenderStateKey;
|
||||||
|
|
||||||
|
@ -130,6 +139,9 @@ nsSVGUtils::Init()
|
||||||
|
|
||||||
Preferences::AddBoolVarCache(&sSVGDisplayListPaintingEnabled,
|
Preferences::AddBoolVarCache(&sSVGDisplayListPaintingEnabled,
|
||||||
"svg.display-lists.painting.enabled");
|
"svg.display-lists.painting.enabled");
|
||||||
|
|
||||||
|
Preferences::AddBoolVarCache(&sSVGNewGetBBoxEnabled,
|
||||||
|
"svg.new-getBBox.enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSVGDisplayContainerFrame*
|
nsSVGDisplayContainerFrame*
|
||||||
|
@ -885,7 +897,8 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags)
|
||||||
return bbox;
|
return bbox;
|
||||||
}
|
}
|
||||||
gfxMatrix matrix;
|
gfxMatrix matrix;
|
||||||
if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
|
if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame ||
|
||||||
|
aFrame->GetType() == nsGkAtoms::svgUseFrame) {
|
||||||
// The spec says getBBox "Returns the tight bounding box in *current user
|
// The spec says getBBox "Returns the tight bounding box in *current user
|
||||||
// space*". So we should really be doing this for all elements, but that
|
// space*". So we should really be doing this for all elements, but that
|
||||||
// needs investigation to check that we won't break too much content.
|
// needs investigation to check that we won't break too much content.
|
||||||
|
@ -896,7 +909,63 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags)
|
||||||
matrix = element->PrependLocalTransformsTo(matrix,
|
matrix = element->PrependLocalTransformsTo(matrix,
|
||||||
nsSVGElement::eChildToUserSpace);
|
nsSVGElement::eChildToUserSpace);
|
||||||
}
|
}
|
||||||
return svg->GetBBoxContribution(ToMatrix(matrix), aFlags).ToThebesRect();
|
bbox = svg->GetBBoxContribution(ToMatrix(matrix), aFlags).ToThebesRect();
|
||||||
|
// Account for 'clipped'.
|
||||||
|
if (aFlags & nsSVGUtils::eBBoxIncludeClipped) {
|
||||||
|
gfxRect clipRect(0, 0, 0, 0);
|
||||||
|
float x, y, width, height;
|
||||||
|
gfxMatrix tm;
|
||||||
|
gfxRect fillBBox =
|
||||||
|
svg->GetBBoxContribution(ToMatrix(tm),
|
||||||
|
nsSVGUtils::eBBoxIncludeFill).ToThebesRect();
|
||||||
|
x = fillBBox.x;
|
||||||
|
y = fillBBox.y;
|
||||||
|
width = fillBBox.width;
|
||||||
|
height = fillBBox.height;
|
||||||
|
bool hasClip = aFrame->StyleDisplay()->IsScrollableOverflow();
|
||||||
|
if (hasClip) {
|
||||||
|
clipRect =
|
||||||
|
nsSVGUtils::GetClipRectForFrame(aFrame, x, y, width, height);
|
||||||
|
if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame ||
|
||||||
|
aFrame->GetType() == nsGkAtoms::svgUseFrame) {
|
||||||
|
clipRect = matrix.TransformBounds(clipRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nsSVGEffects::EffectProperties effectProperties =
|
||||||
|
nsSVGEffects::GetEffectProperties(aFrame);
|
||||||
|
bool isOK = true;
|
||||||
|
nsSVGClipPathFrame *clipPathFrame =
|
||||||
|
effectProperties.GetClipPathFrame(&isOK);
|
||||||
|
if (clipPathFrame && isOK) {
|
||||||
|
SVGClipPathElement *clipContent =
|
||||||
|
static_cast<SVGClipPathElement*>(clipPathFrame->GetContent());
|
||||||
|
nsRefPtr<SVGAnimatedEnumeration> units = clipContent->ClipPathUnits();
|
||||||
|
if (units->AnimVal() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
||||||
|
matrix = gfxMatrix().Scale(width, height) *
|
||||||
|
gfxMatrix().Translate(gfxPoint(x, y)) *
|
||||||
|
matrix;
|
||||||
|
} else if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
|
||||||
|
matrix.Reset();
|
||||||
|
}
|
||||||
|
bbox =
|
||||||
|
clipPathFrame->GetBBoxForClipPathFrame(bbox, matrix).ToThebesRect();
|
||||||
|
if (hasClip) {
|
||||||
|
bbox = bbox.Intersect(clipRect);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isOK) {
|
||||||
|
bbox = gfxRect(0, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
if (hasClip) {
|
||||||
|
bbox = bbox.Intersect(clipRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bbox.IsEmpty()) {
|
||||||
|
bbox = gfxRect(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bbox;
|
||||||
}
|
}
|
||||||
return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
|
return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
|
||||||
}
|
}
|
||||||
|
@ -919,7 +988,8 @@ nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame *aFrame)
|
||||||
|
|
||||||
// For foreignObject frames, nsSVGUtils::GetBBox applies their local
|
// For foreignObject frames, nsSVGUtils::GetBBox applies their local
|
||||||
// transform, so we need to do the same here.
|
// transform, so we need to do the same here.
|
||||||
if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
|
if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame ||
|
||||||
|
aFrame->GetType() == nsGkAtoms::svgUseFrame) {
|
||||||
gfxMatrix transform = static_cast<nsSVGElement*>(aFrame->GetContent())->
|
gfxMatrix transform = static_cast<nsSVGElement*>(aFrame->GetContent())->
|
||||||
PrependLocalTransformsTo(gfxMatrix(),
|
PrependLocalTransformsTo(gfxMatrix(),
|
||||||
nsSVGElement::eChildToUserSpace);
|
nsSVGElement::eChildToUserSpace);
|
||||||
|
|
|
@ -37,6 +37,7 @@ class nsPresContext;
|
||||||
class nsRenderingContext;
|
class nsRenderingContext;
|
||||||
class nsStyleContext;
|
class nsStyleContext;
|
||||||
class nsStyleCoord;
|
class nsStyleCoord;
|
||||||
|
class nsSVGClipPathFrame;
|
||||||
class nsSVGDisplayContainerFrame;
|
class nsSVGDisplayContainerFrame;
|
||||||
class nsSVGElement;
|
class nsSVGElement;
|
||||||
class nsSVGEnum;
|
class nsSVGEnum;
|
||||||
|
@ -76,6 +77,7 @@ class SourceSurface;
|
||||||
|
|
||||||
bool NS_SVGDisplayListHitTestingEnabled();
|
bool NS_SVGDisplayListHitTestingEnabled();
|
||||||
bool NS_SVGDisplayListPaintingEnabled();
|
bool NS_SVGDisplayListPaintingEnabled();
|
||||||
|
bool NS_SVGNewGetBBoxEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sometimes we need to distinguish between an empty box and a box
|
* Sometimes we need to distinguish between an empty box and a box
|
||||||
|
@ -110,6 +112,19 @@ public:
|
||||||
mIsEmpty = false;
|
mIsEmpty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Intersect(const SVGBBox& aSVGBBox) {
|
||||||
|
if (!mIsEmpty && !aSVGBBox.mIsEmpty) {
|
||||||
|
mBBox = mBBox.Intersect(aSVGBBox.mBBox);
|
||||||
|
if (mBBox.IsEmpty()) {
|
||||||
|
mIsEmpty = true;
|
||||||
|
mBBox = Rect(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mIsEmpty = true;
|
||||||
|
mBBox = Rect(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Rect mBBox;
|
Rect mBBox;
|
||||||
bool mIsEmpty;
|
bool mIsEmpty;
|
||||||
|
@ -396,7 +411,8 @@ public:
|
||||||
eBBoxIncludeFillGeometry = 1 << 1,
|
eBBoxIncludeFillGeometry = 1 << 1,
|
||||||
eBBoxIncludeStroke = 1 << 2,
|
eBBoxIncludeStroke = 1 << 2,
|
||||||
eBBoxIncludeStrokeGeometry = 1 << 3,
|
eBBoxIncludeStrokeGeometry = 1 << 3,
|
||||||
eBBoxIncludeMarkers = 1 << 4
|
eBBoxIncludeMarkers = 1 << 4,
|
||||||
|
eBBoxIncludeClipped = 1 << 5
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Get the SVG bbox (the SVG spec's simplified idea of bounds) of aFrame in
|
* Get the SVG bbox (the SVG spec's simplified idea of bounds) of aFrame in
|
||||||
|
|
|
@ -2088,6 +2088,13 @@ pref("svg.svg-iframe.enabled", false);
|
||||||
pref("svg.svg-iframe.enabled", false);
|
pref("svg.svg-iframe.enabled", false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Is support for the new getBBox method from SVG 2 enabled?
|
||||||
|
// See https://svgwg.org/svg2-draft/single-page.html#types-SVGBoundingBoxOptions
|
||||||
|
#ifdef RELEASE_BUILD
|
||||||
|
pref("svg.new-getBBox.enabled", false);
|
||||||
|
#else
|
||||||
|
pref("svg.new-getBBox.enabled", true);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Default font types and sizes by locale
|
// Default font types and sizes by locale
|
||||||
pref("font.default.ar", "sans-serif");
|
pref("font.default.ar", "sans-serif");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче