1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/SVGUseElement.h"
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/ErrorResult.h"
11 #include "mozilla/ScopeExit.h"
12 #include "mozilla/StaticPrefs_svg.h"
13 #include "mozilla/SVGObserverUtils.h"
14 #include "mozilla/SVGUseFrame.h"
15 #include "mozilla/URLExtraData.h"
16 #include "mozilla/dom/Document.h"
17 #include "mozilla/dom/ReferrerInfo.h"
18 #include "mozilla/dom/ShadowIncludingTreeIterator.h"
19 #include "mozilla/dom/SVGGraphicsElement.h"
20 #include "mozilla/dom/SVGLengthBinding.h"
21 #include "mozilla/dom/SVGSVGElement.h"
22 #include "mozilla/dom/SVGSymbolElement.h"
23 #include "mozilla/dom/SVGUseElementBinding.h"
24 #include "nsGkAtoms.h"
25 #include "nsContentUtils.h"
26 #include "nsIReferrerInfo.h"
28 #include "SVGGeometryProperty.h"
30 NS_IMPL_NS_NEW_SVG_ELEMENT(Use
)
32 namespace mozilla::dom
{
34 JSObject
* SVGUseElement::WrapNode(JSContext
* aCx
,
35 JS::Handle
<JSObject
*> aGivenProto
) {
36 return SVGUseElement_Binding::Wrap(aCx
, this, aGivenProto
);
39 ////////////////////////////////////////////////////////////////////////
42 SVGElement::LengthInfo
SVGUseElement::sLengthInfo
[4] = {
43 {nsGkAtoms::x
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
45 {nsGkAtoms::y
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
47 {nsGkAtoms::width
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
49 {nsGkAtoms::height
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
53 SVGElement::StringInfo
SVGUseElement::sStringInfo
[2] = {
54 {nsGkAtoms::href
, kNameSpaceID_None
, true},
55 {nsGkAtoms::href
, kNameSpaceID_XLink
, true}};
57 //----------------------------------------------------------------------
58 // nsISupports methods
60 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGUseElement
)
62 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGUseElement
,
64 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginal
)
66 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
67 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGUseElement
,
69 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginal
)
70 tmp
->mReferencedElementTracker
.Traverse(&cb
);
71 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
73 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(SVGUseElement
, SVGUseElementBase
,
76 //----------------------------------------------------------------------
79 SVGUseElement::SVGUseElement(
80 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
81 : SVGUseElementBase(std::move(aNodeInfo
)), mReferencedElementTracker(this) {
82 SetEnabledCallbacks(kCharacterDataChanged
| kAttributeChanged
|
83 kContentAppended
| kContentInserted
| kContentRemoved
|
84 kNodeWillBeDestroyed
);
87 SVGUseElement::~SVGUseElement() {
89 MOZ_DIAGNOSTIC_ASSERT(!OwnerDoc()->SVGUseElementNeedsShadowTreeUpdate(*this),
90 "Dying without unbinding?");
93 namespace SVGT
= SVGGeometryProperty::Tags
;
95 //----------------------------------------------------------------------
98 void SVGUseElement::ProcessAttributeChange(int32_t aNamespaceID
,
100 if (OwnerDoc()->CloningForSVGUse()) {
103 if (aNamespaceID
== kNameSpaceID_None
) {
104 if (aAttribute
== nsGkAtoms::width
|| aAttribute
== nsGkAtoms::height
) {
105 const bool hadValidDimensions
= HasValidDimensions();
106 const bool isUsed
= OurWidthAndHeightAreUsed();
108 SyncWidthOrHeight(aAttribute
);
111 if (auto* frame
= GetFrame()) {
112 frame
->DimensionAttributeChanged(hadValidDimensions
, isUsed
);
117 if ((aNamespaceID
== kNameSpaceID_XLink
||
118 aNamespaceID
== kNameSpaceID_None
) &&
119 aAttribute
== nsGkAtoms::href
) {
120 // We're changing our nature, clear out the clone information.
121 if (auto* frame
= GetFrame()) {
122 frame
->HrefChanged();
129 void SVGUseElement::AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aAttribute
,
130 const nsAttrValue
* aValue
,
131 const nsAttrValue
* aOldValue
,
132 nsIPrincipal
* aSubjectPrincipal
,
134 ProcessAttributeChange(aNamespaceID
, aAttribute
);
135 return SVGUseElementBase::AfterSetAttr(aNamespaceID
, aAttribute
, aValue
,
136 aOldValue
, aSubjectPrincipal
, aNotify
);
139 nsresult
SVGUseElement::Clone(dom::NodeInfo
* aNodeInfo
,
140 nsINode
** aResult
) const {
143 new (aNodeInfo
->NodeInfoManager()) SVGUseElement(do_AddRef(aNodeInfo
));
145 nsCOMPtr
<nsINode
> kungFuDeathGrip(it
);
146 nsresult rv1
= it
->Init();
147 nsresult rv2
= const_cast<SVGUseElement
*>(this)->CopyInnerTo(it
);
149 if (aNodeInfo
->GetDocument()->CloningForSVGUse()) {
150 // SVGUseElement specific portion - record who we cloned from
151 it
->mOriginal
= const_cast<SVGUseElement
*>(this);
154 if (NS_SUCCEEDED(rv1
) && NS_SUCCEEDED(rv2
)) {
155 kungFuDeathGrip
.swap(*aResult
);
158 return NS_FAILED(rv1
) ? rv1
: rv2
;
161 nsresult
SVGUseElement::BindToTree(BindContext
& aContext
, nsINode
& aParent
) {
162 nsresult rv
= SVGUseElementBase::BindToTree(aContext
, aParent
);
163 NS_ENSURE_SUCCESS(rv
, rv
);
169 void SVGUseElement::UnbindFromTree(bool aNullParent
) {
170 SVGUseElementBase::UnbindFromTree(aNullParent
);
171 OwnerDoc()->UnscheduleSVGUseElementShadowTreeUpdate(*this);
174 already_AddRefed
<DOMSVGAnimatedString
> SVGUseElement::Href() {
175 return mStringAttributes
[HREF
].IsExplicitlySet()
176 ? mStringAttributes
[HREF
].ToDOMAnimatedString(this)
177 : mStringAttributes
[XLINK_HREF
].ToDOMAnimatedString(this);
180 //----------------------------------------------------------------------
182 already_AddRefed
<DOMSVGAnimatedLength
> SVGUseElement::X() {
183 return mLengthAttributes
[ATTR_X
].ToDOMAnimatedLength(this);
186 already_AddRefed
<DOMSVGAnimatedLength
> SVGUseElement::Y() {
187 return mLengthAttributes
[ATTR_Y
].ToDOMAnimatedLength(this);
190 already_AddRefed
<DOMSVGAnimatedLength
> SVGUseElement::Width() {
191 return mLengthAttributes
[ATTR_WIDTH
].ToDOMAnimatedLength(this);
194 already_AddRefed
<DOMSVGAnimatedLength
> SVGUseElement::Height() {
195 return mLengthAttributes
[ATTR_HEIGHT
].ToDOMAnimatedLength(this);
198 //----------------------------------------------------------------------
199 // nsIMutationObserver methods
201 void SVGUseElement::CharacterDataChanged(nsIContent
* aContent
,
202 const CharacterDataChangeInfo
&) {
203 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker
.get(),
209 void SVGUseElement::AttributeChanged(Element
* aElement
, int32_t aNamespaceID
,
210 nsAtom
* aAttribute
, int32_t aModType
,
211 const nsAttrValue
* aOldValue
) {
212 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker
.get(),
218 void SVGUseElement::ContentAppended(nsIContent
* aFirstNewContent
) {
219 // FIXME(emilio, bug 1442336): Why does this check the parent but
220 // ContentInserted the child?
221 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker
.get(),
222 aFirstNewContent
->GetParent())) {
227 void SVGUseElement::ContentInserted(nsIContent
* aChild
) {
228 // FIXME(emilio, bug 1442336): Why does this check the child but
229 // ContentAppended the parent?
230 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker
.get(),
236 void SVGUseElement::ContentRemoved(nsIContent
* aChild
,
237 nsIContent
* aPreviousSibling
) {
238 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker
.get(),
244 void SVGUseElement::NodeWillBeDestroyed(nsINode
* aNode
) {
245 nsCOMPtr
<nsIMutationObserver
> kungFuDeathGrip(this);
249 // Returns whether this node could ever be displayed.
250 static bool NodeCouldBeRendered(const nsINode
& aNode
) {
251 if (const auto* symbol
= SVGSymbolElement::FromNode(aNode
)) {
252 return symbol
->CouldBeRendered();
254 // TODO: Do we have other cases we can optimize out easily?
258 // <svg:use> can be used (no pun intended) to trivially cause an explosion of
259 // clones that could potentially DoS the browser. We have a configurable limit
261 static bool IsTooMuchRecursion(uint32_t aCount
) {
262 switch (StaticPrefs::svg_use_element_recursive_clone_limit_enabled()) {
268 if (!XRE_IsParentProcess()) {
273 return aCount
>= StaticPrefs::svg_use_element_recursive_clone_limit();
276 // Circular loop detection, plus detection of whether this shadow tree is
278 auto SVGUseElement::ScanAncestors(const Element
& aTarget
) const -> ScanResult
{
280 return ScanAncestorsInternal(aTarget
, count
);
283 auto SVGUseElement::ScanAncestorsInternal(const Element
& aTarget
,
284 uint32_t& aCount
) const
286 if (&aTarget
== this) {
287 return ScanResult::CyclicReference
;
290 if (IsTooMuchRecursion(++aCount
)) {
291 return ScanResult::TooDeep
;
293 auto result
= mOriginal
->ScanAncestorsInternal(aTarget
, aCount
);
295 case ScanResult::TooDeep
:
296 case ScanResult::CyclicReference
:
299 case ScanResult::Invisible
:
304 auto result
= ScanResult::Ok
;
305 for (nsINode
* parent
= GetParentOrShadowHostNode(); parent
;
306 parent
= parent
->GetParentOrShadowHostNode()) {
307 if (parent
== &aTarget
) {
308 return ScanResult::CyclicReference
;
310 if (auto* use
= SVGUseElement::FromNode(*parent
)) {
311 if (IsTooMuchRecursion(++aCount
)) {
312 return ScanResult::TooDeep
;
314 if (mOriginal
&& use
->mOriginal
== mOriginal
) {
315 return ScanResult::CyclicReference
;
318 // Do we have other similar cases we can optimize out easily?
319 if (!NodeCouldBeRendered(*parent
)) {
320 // NOTE(emilio): We can't just return here. If we're cyclic, we need to
322 result
= ScanResult::Invisible
;
328 //----------------------------------------------------------------------
330 static bool IsForbiddenUseNode(const nsINode
& aNode
) {
331 if (!aNode
.IsElement()) {
334 const auto* svg
= SVGElement::FromNode(aNode
);
335 return !svg
|| !svg
->IsSVGGraphicsElement();
338 static void CollectForbiddenNodes(Element
& aRoot
,
339 nsTArray
<RefPtr
<nsINode
>>& aNodes
) {
340 auto iter
= dom::ShadowIncludingTreeIterator(aRoot
);
342 nsINode
* node
= *iter
;
343 if (IsForbiddenUseNode(*node
)) {
344 aNodes
.AppendElement(node
);
352 // SVG1 restricted <use> trees to SVGGraphicsElements.
353 // https://www.w3.org/TR/SVG11/struct.html#UseElement:
355 // Any ‘svg’, ‘symbol’, ‘g’, graphics element or other ‘use’ is potentially a
356 // template object that can be re-used (i.e., "instanced") in the SVG
357 // document via a ‘use’ element. The ‘use’ element references another element
358 // and indicates that the graphical contents of that element is
359 // included/drawn at that given point in the document.
361 // SVG2 doesn't have that same restriction.
362 // https://www.w3.org/TR/SVG2/struct.html#UseShadowTree:
364 // Previous versions of SVG restricted the contents of the shadow tree to SVG
365 // graphics elements. This specification allows any valid SVG document
366 // subtree to be cloned. Cloning non-graphical content, however, will not
367 // usually have any visible effect.
369 // But it's pretty ambiguous as to what the behavior should be for some
370 // elements, because <script> is inert, but <iframe> is not, see:
371 // https://github.com/w3c/svgwg/issues/876
373 // So, fairly confusing, all-in-all.
374 static void RemoveForbiddenNodes(Element
& aRoot
, bool aIsCrossDocument
) {
375 switch (StaticPrefs::svg_use_element_graphics_element_restrictions()) {
379 if (!aIsCrossDocument
) {
387 AutoTArray
<RefPtr
<nsINode
>, 10> unsafeNodes
;
388 CollectForbiddenNodes(aRoot
, unsafeNodes
);
389 for (auto& unsafeNode
: unsafeNodes
) {
390 unsafeNode
->Remove();
394 void SVGUseElement::UpdateShadowTree() {
395 MOZ_ASSERT(IsInComposedDoc());
397 if (mReferencedElementTracker
.get()) {
398 mReferencedElementTracker
.get()->RemoveMutationObserver(this);
403 RefPtr
<ShadowRoot
> shadow
= GetShadowRoot();
405 shadow
= AttachShadowWithoutNameChecks(ShadowRootMode::Closed
);
409 auto* targetElement
=
410 SVGGraphicsElement::FromNodeOrNull(mReferencedElementTracker
.get());
411 RefPtr
<Element
> newElement
;
413 auto UpdateShadowTree
= mozilla::MakeScopeExit([&]() {
414 if (nsIContent
* firstChild
= shadow
->GetFirstChild()) {
415 MOZ_ASSERT(!firstChild
->GetNextSibling());
416 shadow
->RemoveChildNode(firstChild
, /* aNotify = */ true);
420 shadow
->AppendChildTo(newElement
, /* aNotify = */ true, IgnoreErrors());
424 // make sure target is valid type for <use>
425 if (!targetElement
) {
429 if (ScanAncestors(*targetElement
) != ScanResult::Ok
) {
433 nsCOMPtr
<nsIURI
> baseURI
= targetElement
->GetBaseURI();
439 const bool isCrossDocument
= targetElement
->OwnerDoc() != OwnerDoc();
441 nsNodeInfoManager
* nodeInfoManager
=
442 isCrossDocument
? OwnerDoc()->NodeInfoManager() : nullptr;
444 nsCOMPtr
<nsINode
> newNode
=
445 targetElement
->Clone(true, nodeInfoManager
, IgnoreErrors());
450 MOZ_ASSERT(newNode
->IsElement());
451 newElement
= newNode
.forget().downcast
<Element
>();
452 RemoveForbiddenNodes(*newElement
, isCrossDocument
);
455 if (newElement
->IsAnyOfSVGElements(nsGkAtoms::svg
, nsGkAtoms::symbol
)) {
456 auto* newSVGElement
= static_cast<SVGElement
*>(newElement
.get());
457 if (mLengthAttributes
[ATTR_WIDTH
].IsExplicitlySet())
458 newSVGElement
->SetLength(nsGkAtoms::width
, mLengthAttributes
[ATTR_WIDTH
]);
459 if (mLengthAttributes
[ATTR_HEIGHT
].IsExplicitlySet())
460 newSVGElement
->SetLength(nsGkAtoms::height
,
461 mLengthAttributes
[ATTR_HEIGHT
]);
464 // Bug 1415044 the specs do not say which referrer information we should use.
465 // This may change if there's any spec comes out.
466 auto referrerInfo
= MakeRefPtr
<ReferrerInfo
>(*this);
467 mContentURLData
= new URLExtraData(baseURI
.forget(), referrerInfo
.forget(),
468 do_AddRef(NodePrincipal()));
470 targetElement
->AddMutationObserver(this);
473 nsIURI
* SVGUseElement::GetSourceDocURI() {
474 nsIContent
* targetElement
= mReferencedElementTracker
.get();
475 if (!targetElement
) {
479 return targetElement
->OwnerDoc()->GetDocumentURI();
482 const Encoding
* SVGUseElement::GetSourceDocCharacterSet() {
483 nsIContent
* targetElement
= mReferencedElementTracker
.get();
484 if (!targetElement
) {
488 return targetElement
->OwnerDoc()->GetDocumentCharacterSet();
491 static nsINode
* GetClonedChild(const SVGUseElement
& aUseElement
) {
492 const ShadowRoot
* shadow
= aUseElement
.GetShadowRoot();
493 return shadow
? shadow
->GetFirstChild() : nullptr;
496 bool SVGUseElement::OurWidthAndHeightAreUsed() const {
497 nsINode
* clonedChild
= GetClonedChild(*this);
498 return clonedChild
&&
499 clonedChild
->IsAnyOfSVGElements(nsGkAtoms::svg
, nsGkAtoms::symbol
);
502 //----------------------------------------------------------------------
503 // implementation helpers
505 void SVGUseElement::SyncWidthOrHeight(nsAtom
* aName
) {
506 NS_ASSERTION(aName
== nsGkAtoms::width
|| aName
== nsGkAtoms::height
,
507 "The clue is in the function name");
508 NS_ASSERTION(OurWidthAndHeightAreUsed(), "Don't call this");
510 if (!OurWidthAndHeightAreUsed()) {
514 auto* target
= SVGElement::FromNode(GetClonedChild(*this));
516 sLengthInfo
[ATTR_WIDTH
].mName
== aName
? ATTR_WIDTH
: ATTR_HEIGHT
;
518 if (mLengthAttributes
[index
].IsExplicitlySet()) {
519 target
->SetLength(aName
, mLengthAttributes
[index
]);
522 if (target
->IsSVGElement(nsGkAtoms::svg
)) {
523 // Our width/height attribute is now no longer explicitly set, so we
524 // need to revert the clone's width/height to the width/height of the
525 // content that's being cloned.
529 // Our width/height attribute is now no longer explicitly set, so we
530 // need to set the value to 100%
531 SVGAnimatedLength length
;
532 length
.Init(SVGContentUtils::XY
, 0xff, 100,
533 SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE
);
534 target
->SetLength(aName
, length
);
537 void SVGUseElement::LookupHref() {
539 if (mStringAttributes
[HREF
].IsExplicitlySet()) {
540 mStringAttributes
[HREF
].GetAnimValue(href
, this);
542 mStringAttributes
[XLINK_HREF
].GetAnimValue(href
, this);
545 if (href
.IsEmpty()) {
549 Element
* treeToWatch
= mOriginal
? mOriginal
.get() : this;
550 if (nsContentUtils::IsLocalRefURL(href
)) {
551 mReferencedElementTracker
.ResetWithLocalRef(*treeToWatch
, href
);
555 nsCOMPtr
<nsIURI
> baseURI
= treeToWatch
->GetBaseURI();
556 nsCOMPtr
<nsIURI
> targetURI
;
557 nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI
), href
,
558 GetComposedDoc(), baseURI
);
563 // Don't allow <use href="data:...">. Using "#ref" inside a data: document is
565 if (targetURI
->SchemeIs("data") &&
566 !StaticPrefs::svg_use_element_data_url_href_allowed()) {
570 nsIReferrerInfo
* referrer
=
571 OwnerDoc()->ReferrerInfoForInternalCSSAndSVGResources();
572 mReferencedElementTracker
.ResetToURIFragmentID(treeToWatch
, targetURI
,
576 void SVGUseElement::TriggerReclone() {
577 if (Document
* doc
= GetComposedDoc()) {
578 doc
->ScheduleSVGUseElementShadowTreeUpdate(*this);
582 void SVGUseElement::UnlinkSource() {
583 if (mReferencedElementTracker
.get()) {
584 mReferencedElementTracker
.get()->RemoveMutationObserver(this);
586 mReferencedElementTracker
.Unlink();
589 //----------------------------------------------------------------------
590 // SVGElement methods
593 gfxMatrix
SVGUseElement::PrependLocalTransformsTo(
594 const gfxMatrix
& aMatrix
, SVGTransformTypes aWhich
) const {
595 // 'transform' attribute:
596 gfxMatrix userToParent
;
598 if (aWhich
== eUserSpaceToParent
|| aWhich
== eAllTransforms
) {
599 userToParent
= GetUserToParentTransform(mAnimateMotionTransform
.get(),
601 if (aWhich
== eUserSpaceToParent
) {
602 return userToParent
* aMatrix
;
606 // our 'x' and 'y' attributes:
608 if (!SVGGeometryProperty::ResolveAll
<SVGT::X
, SVGT::Y
>(this, &x
, &y
)) {
609 const_cast<SVGUseElement
*>(this)->GetAnimatedLengthValues(&x
, &y
, nullptr);
612 gfxMatrix childToUser
= gfxMatrix::Translation(x
, y
);
614 if (aWhich
== eAllTransforms
) {
615 return childToUser
* userToParent
* aMatrix
;
618 MOZ_ASSERT(aWhich
== eChildToUserSpace
, "Unknown TransformTypes");
620 // The following may look broken because pre-multiplying our eChildToUserSpace
621 // transform with another matrix without including our eUserSpaceToParent
622 // transform between the two wouldn't make sense. We don't expect that to
623 // ever happen though. We get here either when the identity matrix has been
624 // passed because our caller just wants our eChildToUserSpace transform, or
625 // when our eUserSpaceToParent transform has already been multiplied into the
626 // matrix that our caller passes (such as when we're called from PaintSVG).
627 return childToUser
* aMatrix
;
631 bool SVGUseElement::HasValidDimensions() const {
632 if (!OurWidthAndHeightAreUsed()) {
636 return (!mLengthAttributes
[ATTR_WIDTH
].IsExplicitlySet() ||
637 mLengthAttributes
[ATTR_WIDTH
].GetAnimValInSpecifiedUnits() > 0) &&
638 (!mLengthAttributes
[ATTR_HEIGHT
].IsExplicitlySet() ||
639 mLengthAttributes
[ATTR_HEIGHT
].GetAnimValInSpecifiedUnits() > 0);
642 SVGElement::LengthAttributesInfo
SVGUseElement::GetLengthInfo() {
643 return LengthAttributesInfo(mLengthAttributes
, sLengthInfo
,
644 ArrayLength(sLengthInfo
));
647 SVGElement::StringAttributesInfo
SVGUseElement::GetStringInfo() {
648 return StringAttributesInfo(mStringAttributes
, sStringInfo
,
649 ArrayLength(sStringInfo
));
652 SVGUseFrame
* SVGUseElement::GetFrame() const {
653 nsIFrame
* frame
= GetPrimaryFrame();
654 // We might be a plain SVGContainerFrame if we didn't pass the conditional
655 // processing checks.
656 if (!frame
|| !frame
->IsSVGUseFrame()) {
657 MOZ_ASSERT_IF(frame
, frame
->Type() == LayoutFrameType::None
);
660 return static_cast<SVGUseFrame
*>(frame
);
663 //----------------------------------------------------------------------
664 // nsIContent methods
667 SVGUseElement::IsAttributeMapped(const nsAtom
* name
) const {
668 return name
== nsGkAtoms::x
|| name
== nsGkAtoms::y
||
669 SVGUseElementBase::IsAttributeMapped(name
);
672 nsCSSPropertyID
SVGUseElement::GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum
) {
675 return eCSSProperty_x
;
677 return eCSSProperty_y
;
679 // Currently we don't map width or height to style
680 return eCSSProperty_UNKNOWN
;
684 } // namespace mozilla::dom