mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 999964 part 1 - Patch for SVG 2 getBBox method; r=longsonr, r=bz
This commit is contained in:
parent
1021555d7c
commit
4a3b14fabe
@ -5,6 +5,7 @@
|
||||
|
||||
#include "gfx2DGlue.h"
|
||||
#include "mozilla/dom/SVGAnimatedTransformList.h"
|
||||
#include "mozilla/dom/SVGGraphicsElementBinding.h"
|
||||
#include "mozilla/dom/SVGTransformableElement.h"
|
||||
#include "mozilla/dom/SVGMatrix.h"
|
||||
#include "mozilla/dom/SVGSVGElement.h"
|
||||
@ -182,7 +183,8 @@ SVGTransformableElement::GetFarthestViewportElement()
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect>
|
||||
SVGTransformableElement::GetBBox(ErrorResult& rv)
|
||||
SVGTransformableElement::GetBBox(const SVGBoundingBoxOptions& aOptions,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
|
||||
|
||||
@ -190,14 +192,37 @@ SVGTransformableElement::GetBBox(ErrorResult& rv)
|
||||
rv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsISVGChildFrame* svgframe = do_QueryFrame(frame);
|
||||
if (!svgframe) {
|
||||
rv.Throw(NS_ERROR_NOT_IMPLEMENTED); // XXX: outer svg
|
||||
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>
|
||||
|
@ -19,6 +19,7 @@ class SVGAnimatedTransformList;
|
||||
class SVGGraphicsElement;
|
||||
class SVGMatrix;
|
||||
class SVGIRect;
|
||||
class SVGBoundingBoxOptions;
|
||||
|
||||
class SVGTransformableElement : public nsSVGElement
|
||||
{
|
||||
@ -33,7 +34,8 @@ public:
|
||||
already_AddRefed<SVGAnimatedTransformList> Transform();
|
||||
nsSVGElement* GetNearestViewportElement();
|
||||
nsSVGElement* GetFarthestViewportElement();
|
||||
already_AddRefed<SVGIRect> GetBBox(ErrorResult& rv);
|
||||
already_AddRefed<SVGIRect> GetBBox(const SVGBoundingBoxOptions& aOptions,
|
||||
ErrorResult& rv);
|
||||
already_AddRefed<SVGMatrix> GetCTM();
|
||||
already_AddRefed<SVGMatrix> GetScreenCTM();
|
||||
already_AddRefed<SVGMatrix> GetTransformToElement(SVGGraphicsElement& aElement,
|
||||
|
@ -10,6 +10,13 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
dictionary SVGBoundingBoxOptions {
|
||||
boolean fill = true;
|
||||
boolean stroke = false;
|
||||
boolean markers = false;
|
||||
boolean clipped = false;
|
||||
};
|
||||
|
||||
interface SVGGraphicsElement : SVGElement {
|
||||
readonly attribute SVGAnimatedTransformList transform;
|
||||
|
||||
@ -17,7 +24,7 @@ interface SVGGraphicsElement : SVGElement {
|
||||
readonly attribute SVGElement? farthestViewportElement;
|
||||
|
||||
[NewObject, Throws]
|
||||
SVGRect getBBox();
|
||||
SVGRect getBBox(optional SVGBoundingBoxOptions aOptions);
|
||||
// Not implemented
|
||||
// SVGRect getStrokeBBox();
|
||||
SVGMatrix? getCTM();
|
||||
|
@ -325,3 +325,45 @@ nsSVGClipPathFrame::GetCanvasTM(uint32_t aFor, nsIFrame* aTransformRoot)
|
||||
&content->mEnumAttributes[SVGClipPathElement::CLIPPATHUNITS],
|
||||
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
|
||||
|
||||
SVGBBox
|
||||
GetBBoxForClipPathFrame(const SVGBBox &aBBox, const gfxMatrix &aMatrix);
|
||||
|
||||
private:
|
||||
// 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
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "nsSVGLength2.h"
|
||||
#include "nsSVGMaskFrame.h"
|
||||
#include "nsSVGOuterSVGFrame.h"
|
||||
#include "mozilla/dom/SVGClipPathElement.h"
|
||||
#include "mozilla/dom/SVGPathElement.h"
|
||||
#include "nsSVGPathGeometryElement.h"
|
||||
#include "nsSVGPathGeometryFrame.h"
|
||||
@ -57,6 +58,7 @@ using namespace mozilla::gfx;
|
||||
|
||||
static bool sSVGDisplayListHitTestingEnabled;
|
||||
static bool sSVGDisplayListPaintingEnabled;
|
||||
static bool sSVGNewGetBBoxEnabled;
|
||||
|
||||
bool
|
||||
NS_SVGDisplayListHitTestingEnabled()
|
||||
@ -70,6 +72,13 @@ NS_SVGDisplayListPaintingEnabled()
|
||||
return sSVGDisplayListPaintingEnabled;
|
||||
}
|
||||
|
||||
bool
|
||||
NS_SVGNewGetBBoxEnabled()
|
||||
{
|
||||
return sSVGNewGetBBoxEnabled;
|
||||
}
|
||||
|
||||
|
||||
// we only take the address of this:
|
||||
static mozilla::gfx::UserDataKey sSVGAutoRenderStateKey;
|
||||
|
||||
@ -130,6 +139,9 @@ nsSVGUtils::Init()
|
||||
|
||||
Preferences::AddBoolVarCache(&sSVGDisplayListPaintingEnabled,
|
||||
"svg.display-lists.painting.enabled");
|
||||
|
||||
Preferences::AddBoolVarCache(&sSVGNewGetBBoxEnabled,
|
||||
"svg.new-getBBox.enabled");
|
||||
}
|
||||
|
||||
nsSVGDisplayContainerFrame*
|
||||
@ -885,7 +897,8 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags)
|
||||
return bbox;
|
||||
}
|
||||
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
|
||||
// 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.
|
||||
@ -896,7 +909,63 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags)
|
||||
matrix = element->PrependLocalTransformsTo(matrix,
|
||||
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);
|
||||
}
|
||||
@ -919,7 +988,8 @@ nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame *aFrame)
|
||||
|
||||
// For foreignObject frames, nsSVGUtils::GetBBox applies their local
|
||||
// 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())->
|
||||
PrependLocalTransformsTo(gfxMatrix(),
|
||||
nsSVGElement::eChildToUserSpace);
|
||||
|
@ -37,6 +37,7 @@ class nsPresContext;
|
||||
class nsRenderingContext;
|
||||
class nsStyleContext;
|
||||
class nsStyleCoord;
|
||||
class nsSVGClipPathFrame;
|
||||
class nsSVGDisplayContainerFrame;
|
||||
class nsSVGElement;
|
||||
class nsSVGEnum;
|
||||
@ -76,6 +77,7 @@ class SourceSurface;
|
||||
|
||||
bool NS_SVGDisplayListHitTestingEnabled();
|
||||
bool NS_SVGDisplayListPaintingEnabled();
|
||||
bool NS_SVGNewGetBBoxEnabled();
|
||||
|
||||
/**
|
||||
* Sometimes we need to distinguish between an empty box and a box
|
||||
@ -110,6 +112,19 @@ public:
|
||||
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:
|
||||
Rect mBBox;
|
||||
bool mIsEmpty;
|
||||
@ -396,7 +411,8 @@ public:
|
||||
eBBoxIncludeFillGeometry = 1 << 1,
|
||||
eBBoxIncludeStroke = 1 << 2,
|
||||
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
|
||||
|
@ -2088,6 +2088,13 @@ pref("svg.svg-iframe.enabled", false);
|
||||
pref("svg.svg-iframe.enabled", false);
|
||||
#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
|
||||
pref("font.default.ar", "sans-serif");
|
||||
|
Loading…
Reference in New Issue
Block a user