Bug 1145195 part 2 - SVGFragmentIdentifier::ProcessSVGViewSpec() shouldn't actually let #svgView() affect attribute values r=dholbert

This commit is contained in:
Robert Longson 2015-12-14 00:58:01 +00:00
parent 45631955a0
commit ebdab47988
5 changed files with 215 additions and 354 deletions

View File

@ -40,109 +40,104 @@ GetViewElement(nsIDocument* aDocument, const nsAString& aId)
static_cast<SVGViewElement*>(element) : nullptr;
}
void
SVGFragmentIdentifier::SaveOldPreserveAspectRatio(SVGSVGElement* root)
// Handles setting/clearing the root's mSVGView pointer.
class MOZ_RAII AutoSVGViewHandler
{
if (root->mPreserveAspectRatio.IsExplicitlySet()) {
root->SetPreserveAspectRatioProperty(root->mPreserveAspectRatio.GetBaseValue());
public:
explicit AutoSVGViewHandler(SVGSVGElement* aRoot
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mRoot(aRoot), mValid(false) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mWasOverridden = mRoot->UseCurrentView();
mRoot->mSVGView = nullptr;
mRoot->mCurrentViewID = nullptr;
}
}
void
SVGFragmentIdentifier::RestoreOldPreserveAspectRatio(SVGSVGElement* root)
{
const SVGPreserveAspectRatio* oldPARPtr = root->GetPreserveAspectRatioProperty();
if (oldPARPtr) {
root->mPreserveAspectRatio.SetBaseValue(*oldPARPtr, root);
} else if (root->mPreserveAspectRatio.IsExplicitlySet()) {
ErrorResult error;
root->RemoveAttribute(NS_LITERAL_STRING("preserveAspectRatio"), error);
}
}
void
SVGFragmentIdentifier::SaveOldViewBox(SVGSVGElement* root)
{
if (root->mViewBox.IsExplicitlySet()) {
root->SetViewBoxProperty(root->mViewBox.GetBaseValue());
}
}
void
SVGFragmentIdentifier::RestoreOldViewBox(SVGSVGElement* root)
{
const nsSVGViewBoxRect* oldViewBoxPtr = root->GetViewBoxProperty();
if (oldViewBoxPtr) {
root->mViewBox.SetBaseValue(*oldViewBoxPtr, root);
} else if (root->mViewBox.IsExplicitlySet()) {
ErrorResult error;
root->RemoveAttribute(NS_LITERAL_STRING("viewBox"), error);
}
}
void
SVGFragmentIdentifier::SaveOldZoomAndPan(SVGSVGElement* root)
{
if (root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].IsExplicitlySet()) {
root->SetZoomAndPanProperty(root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].GetBaseValue());
}
}
void
SVGFragmentIdentifier::RestoreOldZoomAndPan(SVGSVGElement* root)
{
uint16_t oldZoomAndPan = root->GetZoomAndPanProperty();
if (oldZoomAndPan != SVG_ZOOMANDPAN_UNKNOWN) {
root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].SetBaseValue(oldZoomAndPan, root);
} else if (root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].IsExplicitlySet()) {
ErrorResult error;
root->RemoveAttribute(NS_LITERAL_STRING("zoomAndPan"), error);
}
}
void
SVGFragmentIdentifier::SaveOldTransform(SVGSVGElement* root)
{
nsSVGAnimatedTransformList* transformList = root->GetAnimatedTransformList();
if (transformList && transformList->IsExplicitlySet()) {
root->SetTransformProperty(transformList->GetBaseValue());
}
}
void
SVGFragmentIdentifier::RestoreOldTransform(SVGSVGElement* root)
{
const SVGTransformList* oldTransformPtr = root->GetTransformProperty();
if (oldTransformPtr) {
root->GetAnimatedTransformList(nsSVGElement::DO_ALLOCATE)->SetBaseValue(*oldTransformPtr);
} else {
nsSVGAnimatedTransformList* transformList = root->GetAnimatedTransformList();
if (transformList && transformList->IsExplicitlySet()) {
ErrorResult error;
root->RemoveAttribute(NS_LITERAL_STRING("transform"), error);
~AutoSVGViewHandler() {
if (!mWasOverridden && !mValid) {
// we weren't overridden before and we aren't
// overridden now so nothing has changed.
return;
}
if (mValid) {
mRoot->mSVGView = mSVGView;
}
mRoot->InvalidateTransformNotifyFrame();
}
}
void CreateSVGView() {
MOZ_ASSERT(!mSVGView, "CreateSVGView should not be called multiple times");
mSVGView = new SVGView();
}
bool ProcessAttr(const nsAString& aToken, const nsAString &aParams) {
MOZ_ASSERT(mSVGView, "CreateSVGView should have been called");
// SVGViewAttributes may occur in any order, but each type may only occur
// at most one time in a correctly formed SVGViewSpec.
// If we encounter any attribute more than once or get any syntax errors
// we're going to return false and cancel any changes.
if (IsMatchingParameter(aToken, NS_LITERAL_STRING("viewBox"))) {
if (mSVGView->mViewBox.IsExplicitlySet() ||
NS_FAILED(mSVGView->mViewBox.SetBaseValueString(
aParams, mRoot, false))) {
return false;
}
} else if (IsMatchingParameter(aToken, NS_LITERAL_STRING("preserveAspectRatio"))) {
if (mSVGView->mPreserveAspectRatio.IsExplicitlySet() ||
NS_FAILED(mSVGView->mPreserveAspectRatio.SetBaseValueString(
aParams, mRoot, false))) {
return false;
}
} else if (IsMatchingParameter(aToken, NS_LITERAL_STRING("transform"))) {
if (mSVGView->mTransforms) {
return false;
}
mSVGView->mTransforms = new nsSVGAnimatedTransformList();
if (NS_FAILED(mSVGView->mTransforms->SetBaseValueString(aParams))) {
return false;
}
} else if (IsMatchingParameter(aToken, NS_LITERAL_STRING("zoomAndPan"))) {
if (mSVGView->mZoomAndPan.IsExplicitlySet()) {
return false;
}
nsIAtom* valAtom = NS_GetStaticAtom(aParams);
if (!valAtom ||
NS_FAILED(mSVGView->mZoomAndPan.SetBaseValueAtom(
valAtom, mRoot))) {
return false;
}
} else {
// We don't support viewTarget currently
return false;
}
return true;
}
void SetValid() {
mValid = true;
}
private:
SVGSVGElement* mRoot;
nsAutoPtr<SVGView> mSVGView;
bool mValid;
bool mWasOverridden;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
bool
SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString& aViewSpec,
SVGSVGElement* root)
SVGSVGElement* aRoot)
{
AutoSVGViewHandler viewHandler(aRoot);
if (!IsMatchingParameter(aViewSpec, NS_LITERAL_STRING("svgView"))) {
return false;
}
// SVGViewAttributes may occur in any order, but each type may only occur
// at most one time in a correctly formed SVGViewSpec.
// If we encounter any attribute more than once or get any syntax errors
// we're going to return false and cancel any changes.
bool viewBoxFound = false;
bool preserveAspectRatioFound = false;
bool transformFound = false;
bool zoomAndPanFound = false;
// Each token is a SVGViewAttribute
int32_t bracketPos = aViewSpec.FindChar('(');
uint32_t lengthOfViewSpec = aViewSpec.Length() - bracketPos - 2;
@ -152,6 +147,8 @@ SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString& aViewSpec,
if (!tokenizer.hasMoreTokens()) {
return false;
}
viewHandler.CreateSVGView();
do {
nsAutoString token(tokenizer.nextToken());
@ -165,75 +162,13 @@ SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString& aViewSpec,
const nsAString &params =
Substring(token, bracketPos + 1, token.Length() - bracketPos - 2);
if (IsMatchingParameter(token, NS_LITERAL_STRING("viewBox"))) {
if (viewBoxFound ||
NS_FAILED(root->mViewBox.SetBaseValueString(
params, root, true))) {
return false;
}
viewBoxFound = true;
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("preserveAspectRatio"))) {
if (preserveAspectRatioFound ||
NS_FAILED(root->mPreserveAspectRatio.SetBaseValueString(
params, root, true))) {
return false;
}
preserveAspectRatioFound = true;
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("transform"))) {
if (transformFound ||
NS_FAILED(root->GetAnimatedTransformList(nsSVGElement::DO_ALLOCATE)->
SetBaseValueString(params))) {
return false;
}
transformFound = true;
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("zoomAndPan"))) {
if (zoomAndPanFound) {
return false;
}
nsIAtom* valAtom = NS_GetStaticAtom(params);
if (!valAtom) {
return false;
}
const nsSVGEnumMapping* mapping = SVGSVGElement::sZoomAndPanMap;
while (mapping->mKey) {
if (valAtom == *(mapping->mKey)) {
// If we've got a valid zoomAndPan value, then set it on our root element.
if (NS_FAILED(root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].SetBaseValue(
mapping->mVal, root))) {
return false;
}
break;
}
mapping++;
}
if (!mapping->mKey) {
// Unrecognised zoomAndPan value
return false;
}
zoomAndPanFound = true;
} else {
// We don't support viewTarget currently
if (!viewHandler.ProcessAttr(token, params)) {
return false;
}
} while (tokenizer.hasMoreTokens());
if (root->mUseCurrentView) {
// A previous SVGViewSpec may have overridden some attributes.
// If they are no longer overridden we need to restore the old values.
if (!transformFound) {
RestoreOldTransform(root);
}
if (!viewBoxFound) {
RestoreOldViewBox(root);
}
if (!preserveAspectRatioFound) {
RestoreOldPreserveAspectRatio(root);
}
if (!zoomAndPanFound) {
RestoreOldZoomAndPan(root);
}
}
viewHandler.SetValid();
return true;
}
@ -247,12 +182,6 @@ SVGFragmentIdentifier::ProcessFragmentIdentifier(nsIDocument* aDocument,
SVGSVGElement* rootElement =
static_cast<SVGSVGElement*>(aDocument->GetRootElement());
if (!rootElement->mUseCurrentView) {
SaveOldViewBox(rootElement);
SaveOldPreserveAspectRatio(rootElement);
SaveOldZoomAndPan(rootElement);
}
const SVGViewElement* viewElement = GetViewElement(aDocument, aAnchorName);
if (viewElement) {
@ -260,32 +189,14 @@ SVGFragmentIdentifier::ProcessFragmentIdentifier(nsIDocument* aDocument,
rootElement->mCurrentViewID = new nsString();
}
*rootElement->mCurrentViewID = aAnchorName;
rootElement->mUseCurrentView = true;
rootElement->mSVGView = nullptr;
rootElement->InvalidateTransformNotifyFrame();
// not an svgView()-style fragment identifier, return false so the caller
// continues processing to match any :target pseudo elements
return false;
}
bool wasOverridden = !!rootElement->mCurrentViewID;
rootElement->mCurrentViewID = nullptr;
rootElement->mUseCurrentView = ProcessSVGViewSpec(aAnchorName, rootElement);
if (rootElement->mUseCurrentView) {
return true;
}
RestoreOldViewBox(rootElement);
rootElement->ClearViewBoxProperty();
RestoreOldPreserveAspectRatio(rootElement);
rootElement->ClearPreserveAspectRatioProperty();
RestoreOldZoomAndPan(rootElement);
rootElement->ClearZoomAndPanProperty();
RestoreOldTransform(rootElement);
rootElement->ClearTransformProperty();
if (wasOverridden) {
rootElement->InvalidateTransformNotifyFrame();
}
return false;
return ProcessSVGViewSpec(aAnchorName, rootElement);
}
} // namespace mozilla

View File

@ -42,17 +42,6 @@ private:
* @return true if there is a valid ViewSpec
*/
static bool ProcessSVGViewSpec(const nsAString &aViewSpec, dom::SVGSVGElement *root);
// Save and restore things we override in case we want to go back e.g. the
// user presses the back button
static void SaveOldPreserveAspectRatio(dom::SVGSVGElement *root);
static void RestoreOldPreserveAspectRatio(dom::SVGSVGElement *root);
static void SaveOldViewBox(dom::SVGSVGElement *root);
static void RestoreOldViewBox(dom::SVGSVGElement *root);
static void SaveOldZoomAndPan(dom::SVGSVGElement *root);
static void RestoreOldZoomAndPan(dom::SVGSVGElement *root);
static void SaveOldTransform(dom::SVGSVGElement *root);
static void RestoreOldTransform(dom::SVGSVGElement *root);
};
} // namespace mozilla

View File

@ -111,6 +111,14 @@ DOMSVGTranslatePoint::MatrixTransform(SVGMatrix& matrix)
return point.forget();
}
SVGView::SVGView()
{
mZoomAndPan.Init(SVGSVGElement::ZOOMANDPAN,
SVG_ZOOMANDPAN_MAGNIFY);
mViewBox.Init();
mPreserveAspectRatio.Init();
}
nsSVGElement::LengthInfo SVGSVGElement::sLengthInfo[4] =
{
{ &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
@ -176,8 +184,7 @@ SVGSVGElement::SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo
aFromParser == FROM_PARSER_XSLT),
mImageNeedsTransformInvalidation(false),
mIsPaintingSVGImageElement(false),
mHasChildrenOnlyTransform(false),
mUseCurrentView(false)
mHasChildrenOnlyTransform(false)
{
}
@ -257,7 +264,7 @@ SVGSVGElement::ScreenPixelToMillimeterY()
bool
SVGSVGElement::UseCurrentView()
{
return mUseCurrentView;
return mSVGView || mCurrentViewID;
}
float
@ -452,12 +459,6 @@ SVGSVGElement::PreserveAspectRatio()
uint16_t
SVGSVGElement::ZoomAndPan()
{
SVGViewElement* viewElement = GetCurrentViewElement();
if (viewElement && viewElement->mEnumAttributes[
SVGViewElement::ZOOMANDPAN].IsExplicitlySet()) {
return viewElement->mEnumAttributes[
SVGViewElement::ZOOMANDPAN].GetAnimValue();
}
return mEnumAttributes[ZOOMANDPAN].GetAnimValue();
}
@ -841,6 +842,9 @@ SVGSVGElement::GetViewBoxWithSynthesis(
if (viewElement && viewElement->mViewBox.HasRect()) {
return viewElement->mViewBox.GetAnimValue();
}
if (mSVGView && mSVGView->mViewBox.HasRect()) {
return mSVGView->mViewBox.GetAnimValue();
}
if (mViewBox.HasRect()) {
return mViewBox.GetAnimValue();
}
@ -878,6 +882,7 @@ SVGSVGElement::GetPreserveAspectRatioWithOverride() const
// We're just holding onto the viewElement that HasViewBoxRect() would look up,
// so that we don't have to look it up again later.
if (!((viewElement && viewElement->mViewBox.HasRect()) ||
(mSVGView && mSVGView->mViewBox.HasRect()) ||
mViewBox.HasRect()) &&
ShouldSynthesizeViewBox()) {
// If we're synthesizing a viewBox, use preserveAspectRatio="none";
@ -887,6 +892,9 @@ SVGSVGElement::GetPreserveAspectRatioWithOverride() const
if (viewElement && viewElement->mPreserveAspectRatio.IsExplicitlySet()) {
return viewElement->mPreserveAspectRatio.GetAnimValue();
}
if (mSVGView && mSVGView->mPreserveAspectRatio.IsExplicitlySet()) {
return mSVGView->mPreserveAspectRatio.GetAnimValue();
}
return mPreserveAspectRatio.GetAnimValue();
}
@ -904,6 +912,8 @@ SVGSVGElement::GetLength(uint8_t aCtxType)
// The logic here should match HasViewBoxRect().
if (viewElement && viewElement->mViewBox.HasRect()) {
viewbox = &viewElement->mViewBox.GetAnimValue();
} else if (mSVGView && mSVGView->mViewBox.HasRect()) {
viewbox = &mSVGView->mViewBox.GetAnimValue();
} else if (mViewBox.HasRect()) {
viewbox = &mViewBox.GetAnimValue();
}
@ -946,9 +956,12 @@ SVGSVGElement::GetLength(uint8_t aCtxType)
SVGSVGElement::PrependLocalTransformsTo(
const gfxMatrix &aMatrix, SVGTransformTypes aWhich) const
{
// 'transform' attribute:
// 'transform' attribute (or an override from a fragment identifier):
gfxMatrix fromUserSpace =
SVGSVGElementBase::PrependLocalTransformsTo(aMatrix, aWhich);
SVGContentUtils::PrependLocalTransformsTo(
aMatrix, aWhich, mAnimateMotionTransform,
mSVGView && mSVGView->mTransforms ? mSVGView->mTransforms : mTransforms);
if (aWhich == eUserSpaceToParent) {
return fromUserSpace;
}
@ -975,6 +988,15 @@ SVGSVGElement::PrependLocalTransformsTo(
return ThebesMatrix(GetViewBoxTransform()) * fromUserSpace;
}
nsSVGAnimatedTransformList*
SVGSVGElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!(aFlags & DO_ALLOCATE) && mSVGView && mSVGView->mTransforms) {
return mSVGView->mTransforms;
}
return SVGSVGElementBase::GetAnimatedTransformList(aFlags);
}
/* virtual */ bool
SVGSVGElement::HasValidDimensions() const
{
@ -1015,7 +1037,8 @@ bool
SVGSVGElement::HasViewBoxRect() const
{
SVGViewElement* viewElement = GetCurrentViewElement();
if (viewElement && viewElement->mViewBox.HasRect()) {
if ((viewElement && viewElement->mViewBox.HasRect()) ||
(mSVGView && mSVGView->mViewBox.HasRect())) {
return true;
}
return mViewBox.HasRect();
@ -1136,106 +1159,6 @@ SVGSVGElement::FlushImageTransformInvalidation()
}
}
bool
SVGSVGElement::SetViewBoxProperty(const nsSVGViewBoxRect& aViewBox)
{
nsSVGViewBoxRect* pViewBoxOverridePtr = new nsSVGViewBoxRect(aViewBox);
nsresult rv = SetProperty(nsGkAtoms::viewBox,
pViewBoxOverridePtr,
nsINode::DeleteProperty<nsSVGViewBoxRect>,
true);
MOZ_ASSERT(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
"Setting override value when it's already set...?");
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
// property-insertion failed (e.g. OOM in property-table code)
delete pViewBoxOverridePtr;
return false;
}
return true;
}
const nsSVGViewBoxRect*
SVGSVGElement::GetViewBoxProperty() const
{
void* valPtr = GetProperty(nsGkAtoms::viewBox);
if (valPtr) {
return static_cast<nsSVGViewBoxRect*>(valPtr);
}
return nullptr;
}
bool
SVGSVGElement::ClearViewBoxProperty()
{
void* valPtr = UnsetProperty(nsGkAtoms::viewBox);
delete static_cast<nsSVGViewBoxRect*>(valPtr);
return valPtr;
}
bool
SVGSVGElement::SetZoomAndPanProperty(uint16_t aValue)
{
nsresult rv = SetProperty(nsGkAtoms::zoomAndPan,
reinterpret_cast<void*>(aValue),
nullptr, true);
MOZ_ASSERT(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
"Setting override value when it's already set...?");
return NS_SUCCEEDED(rv);
}
uint16_t
SVGSVGElement::GetZoomAndPanProperty() const
{
void* valPtr = GetProperty(nsGkAtoms::zoomAndPan);
if (valPtr) {
return reinterpret_cast<uintptr_t>(valPtr);
}
return SVG_ZOOMANDPAN_UNKNOWN;
}
bool
SVGSVGElement::ClearZoomAndPanProperty()
{
return UnsetProperty(nsGkAtoms::zoomAndPan);
}
bool
SVGSVGElement::SetTransformProperty(const SVGTransformList& aTransform)
{
SVGTransformList* pTransformOverridePtr = new SVGTransformList(aTransform);
nsresult rv = SetProperty(nsGkAtoms::transform,
pTransformOverridePtr,
nsINode::DeleteProperty<SVGTransformList>,
true);
MOZ_ASSERT(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
"Setting override value when it's already set...?");
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
// property-insertion failed (e.g. OOM in property-table code)
delete pTransformOverridePtr;
return false;
}
return true;
}
const SVGTransformList*
SVGSVGElement::GetTransformProperty() const
{
void* valPtr = GetProperty(nsGkAtoms::transform);
if (valPtr) {
return static_cast<SVGTransformList*>(valPtr);
}
return nullptr;
}
bool
SVGSVGElement::ClearTransformProperty()
{
return UnsetProperty(nsGkAtoms::transform);
}
int32_t
SVGSVGElement::GetIntrinsicWidth()
{

View File

@ -33,6 +33,7 @@ class DOMSVGLength;
class DOMSVGNumber;
class EventChainPreVisitor;
class SVGFragmentIdentifier;
class AutoSVGViewHandler;
namespace dom {
class SVGAngle;
@ -85,13 +86,29 @@ public:
float height;
};
// Stores svgView arguments of SVG fragment identifiers.
class SVGView {
friend class mozilla::AutoSVGViewHandler;
friend class mozilla::dom::SVGSVGElement;
public:
SVGView();
private:
nsSVGEnum mZoomAndPan;
nsSVGViewBox mViewBox;
SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
nsAutoPtr<nsSVGAnimatedTransformList> mTransforms;
};
typedef SVGGraphicsElement SVGSVGElementBase;
class SVGSVGElement final : public SVGSVGElementBase
{
friend class ::nsSVGOuterSVGFrame;
friend class ::nsSVGInnerSVGFrame;
friend class mozilla::dom::SVGView;
friend class mozilla::SVGFragmentIdentifier;
friend class mozilla::AutoSVGViewHandler;
friend class mozilla::AutoSVGRenderingState;
SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
@ -141,6 +158,8 @@ public:
virtual gfxMatrix PrependLocalTransformsTo(
const gfxMatrix &aMatrix,
SVGTransformTypes aWhich = eAllTransforms) const override;
virtual nsSVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0) override;
virtual bool HasValidDimensions() const override;
// SVGSVGElement methods:
@ -286,19 +305,11 @@ private:
void SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR);
void ClearImageOverridePreserveAspectRatio();
// Set/Clear properties to hold old or override versions of attributes
// Set/Clear properties to hold old version of preserveAspectRatio
// when it's being overridden by an <image> element that we are inside of.
bool SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR);
const SVGPreserveAspectRatio* GetPreserveAspectRatioProperty() const;
bool ClearPreserveAspectRatioProperty();
bool SetViewBoxProperty(const nsSVGViewBoxRect& aViewBox);
const nsSVGViewBoxRect* GetViewBoxProperty() const;
bool ClearViewBoxProperty();
bool SetZoomAndPanProperty(uint16_t aValue);
uint16_t GetZoomAndPanProperty() const;
bool ClearZoomAndPanProperty();
bool SetTransformProperty(const SVGTransformList& aValue);
const SVGTransformList* GetTransformProperty() const;
bool ClearTransformProperty();
bool IsRoot() const {
NS_ASSERTION((IsInDoc() && !GetParent()) ==
@ -369,7 +380,10 @@ private:
nsSVGViewBox mViewBox;
SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
// mCurrentViewID and mSVGView are mutually exclusive; we can have
// at most one non-null.
nsAutoPtr<nsString> mCurrentViewID;
nsAutoPtr<SVGView> mSVGView;
// The size of the rectangular SVG viewport into which we render. This is
// not (necessarily) the same as the content area. See:
@ -401,7 +415,6 @@ private:
bool mImageNeedsTransformInvalidation;
bool mIsPaintingSVGImageElement;
bool mHasChildrenOnlyTransform;
bool mUseCurrentView;
};
} // namespace dom

View File

@ -24,67 +24,92 @@ function Test(svgFragmentIdentifier, valid, viewBoxString,
{
this.svgFragmentIdentifier = svgFragmentIdentifier;
this.valid = valid;
this.viewBoxString = viewBoxString;
this.preserveAspectRatioString = preserveAspectRatioString;
this.zoomAndPanString = zoomAndPanString;
}
function runTests()
{
var svg = $("svg");
var doc = svg.contentWindow.document;
var rootElement = doc.rootElement;
var tests = [
new Test("unknown", false, null, null, null),
new Test("svgView(viewBox(0,0,200,200))", true, "0 0 200 200", null, null),
new Test("svgView(preserveAspectRatio(xMaxYMin slice))", true, null, "xMaxYMin slice", null),
new Test("svgView(viewBox(1,2,3,4);preserveAspectRatio(xMinYMax))", true, "1 2 3 4", "xMinYMax meet", null),
new Test("svgView(viewBox(none))", true, "none", null, null),
new Test("svgView(zoomAndPan(disable))", true, null, null, "disable"),
new Test("svgView(transform(translate(-10,-20) scale(2) rotate(45) translate(5,10)))", true, null, null, null),
new Test("unknown", false),
new Test("svgView(viewBox(0,0,200,200))", true),
new Test("svgView(preserveAspectRatio(xMaxYMin slice))", true),
new Test("svgView(viewBox(1,2,3,4);preserveAspectRatio(xMinYMax))", true),
new Test("svgView(viewBox(none))", true),
new Test("svgView(zoomAndPan(disable))", true),
new Test("svgView(transform(translate(-10,-20) scale(2) rotate(45) translate(5,10)))", true),
// No duplicates allowed
new Test("svgView(zoomAndPan(disable);zoomAndPan(disable))", false, null, null, null),
new Test("svgView(viewBox(0,0,200,200);viewBox(0,0,200,200))", false, null, null, null),
new Test("svgView(preserveAspectRatio(xMaxYMin);preserveAspectRatio(xMaxYMin))", false, null, null, null),
new Test("svgView(transform(translate(0,200));transform(translate(0,200)))", false, null, null, null),
new Test("svgView(zoomAndPan(disable);zoomAndPan(disable))", false),
new Test("svgView(viewBox(0,0,200,200);viewBox(0,0,200,200))", false),
new Test("svgView(preserveAspectRatio(xMaxYMin);preserveAspectRatio(xMaxYMin))", false),
new Test("svgView(transform(translate(0,200));transform(translate(0,200)))", false),
// No invalid values allowed
new Test("svgView(viewBox(bad)", false, null, null, null),
new Test("svgView(preserveAspectRatio(bad))", false, null, null, null),
new Test("svgView(zoomAndPan(bad))", false, null, null, null),
new Test("svgView(transform(bad))", false, null, null, null),
new Test("svgView", false, null, null, null),
new Test("svgView(", false, null, null, null),
new Test("svgView()", false, null, null, null),
new Test("svgView(viewBox(bad)", false),
new Test("svgView(preserveAspectRatio(bad))", false),
new Test("svgView(zoomAndPan(bad))", false),
new Test("svgView(transform(bad))", false),
new Test("svgView", false),
new Test("svgView(", false),
new Test("svgView()", false),
// Be sure we verify that there's a closing paren for svgView()
// (and not too many closing parens)
new Test("svgView(zoomAndPan(disable)", false, null, null, null),
new Test("svgView(zoomAndPan(disable) ", false, null, null, null),
new Test("svgView(zoomAndPan(disable)]", false, null, null, null),
new Test("svgView(zoomAndPan(disable)))", false, null, null, null)
new Test("svgView(zoomAndPan(disable)", false),
new Test("svgView(zoomAndPan(disable) ", false),
new Test("svgView(zoomAndPan(disable)]", false),
new Test("svgView(zoomAndPan(disable)))", false)
];
var src = svg.getAttribute("src");
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
svg.setAttribute("src", src + "#" + test.svgFragmentIdentifier);
is(doc.rootElement.useCurrentView, test.valid,
"Expected " + test.svgFragmentIdentifier + " to be " +
(test.valid ? "valid" : "invalid"));
is(doc.rootElement.getAttribute("viewBox"),
test.viewBoxString, "unexpected viewBox");
is(false, rootElement.hasAttribute("viewBox"),
"expecting to start without a viewBox set");
is(false, rootElement.hasAttribute("preserveAspectRatio"),
"expecting to start without preserveAspectRatio set");
is(false, rootElement.hasAttribute("zoomAndPan"),
"expecting to start without zoomAndPan set");
is(doc.rootElement.getAttribute("preserveAspectRatio"),
test.preserveAspectRatioString, "unexpected preserveAspectRatio");
for (var j = 0; j < 2; j++) {
var initialViewBox = rootElement.getAttribute("viewBox");
var initialPreserveAspectRatio =
rootElement.getAttribute("preserveAspectRatio");
var initialZoomAndPan = rootElement.getAttribute("zoomAndPan");
var initialTransform = rootElement.getAttribute("transform");
is(doc.rootElement.getAttribute("zoomAndPan"),
test.zoomAndPanString, "unexpected zoomAndPan");
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
svg.setAttribute("src", src + "#" + test.svgFragmentIdentifier);
is(rootElement.useCurrentView, test.valid,
"Expected " + test.svgFragmentIdentifier + " to be " +
(test.valid ? "valid" : "invalid"));
// check that assigning a viewSpec does not modify the underlying
// attribute values.
is(rootElement.getAttribute("viewBox"),
initialViewBox, "unexpected viewBox");
is(rootElement.getAttribute("preserveAspectRatio"),
initialPreserveAspectRatio, "unexpected preserveAspectRatio");
is(rootElement.getAttribute("zoomAndPan"),
initialZoomAndPan, "unexpected zoomAndPan");
is(rootElement.getAttribute("transform"),
initialTransform, "unexpected transform");
}
// repeat tests with underlying attributes set to values
rootElement.setAttribute("viewBox", "0 0 100 100");
rootElement.setAttribute("preserveAspectRatio", "none");
rootElement.setAttribute("zoomAndPan", "disable");
rootElement.setAttribute("transform", "translate(10,10)");
}
SimpleTest.finish();
}
window.addEventListener("load", runTests, false);
$(svg).addEventListener("load", runTests, false);
</script>
</pre>
</body>