Bug 1941128 - Turn off network.dns.native_https_query on Mac again
[gecko.git] / dom / svg / SVGUseElement.cpp
blobbe830d610b481b787f8cf583601762f049a65ca3
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/SVGSwitchElement.h"
23 #include "mozilla/dom/SVGSymbolElement.h"
24 #include "mozilla/dom/SVGUseElementBinding.h"
25 #include "nsGkAtoms.h"
26 #include "nsContentUtils.h"
27 #include "nsIReferrerInfo.h"
28 #include "nsIURI.h"
29 #include "SVGGeometryProperty.h"
31 NS_IMPL_NS_NEW_SVG_ELEMENT(Use)
33 namespace mozilla::dom {
35 JSObject* SVGUseElement::WrapNode(JSContext* aCx,
36 JS::Handle<JSObject*> aGivenProto) {
37 return SVGUseElement_Binding::Wrap(aCx, this, aGivenProto);
40 ////////////////////////////////////////////////////////////////////////
41 // implementation
43 SVGElement::LengthInfo SVGUseElement::sLengthInfo[4] = {
44 {nsGkAtoms::x, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
45 SVGContentUtils::X},
46 {nsGkAtoms::y, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
47 SVGContentUtils::Y},
48 {nsGkAtoms::width, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
49 SVGContentUtils::X},
50 {nsGkAtoms::height, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
51 SVGContentUtils::Y},
54 SVGElement::StringInfo SVGUseElement::sStringInfo[2] = {
55 {nsGkAtoms::href, kNameSpaceID_None, true},
56 {nsGkAtoms::href, kNameSpaceID_XLink, true}};
58 //----------------------------------------------------------------------
59 // nsISupports methods
61 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGUseElement)
63 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGUseElement,
64 SVGUseElementBase)
65 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginal)
66 tmp->UnlinkSource();
67 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
68 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGUseElement,
69 SVGUseElementBase)
70 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginal)
71 tmp->mReferencedElementTracker.Traverse(&cb);
72 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
74 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(SVGUseElement, SVGUseElementBase,
75 nsIMutationObserver)
77 //----------------------------------------------------------------------
78 // Implementation
80 SVGUseElement::SVGUseElement(
81 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
82 : SVGUseElementBase(std::move(aNodeInfo)), mReferencedElementTracker(this) {
83 SetEnabledCallbacks(kCharacterDataChanged | kAttributeChanged |
84 kContentAppended | kContentInserted |
85 kContentWillBeRemoved | kNodeWillBeDestroyed);
88 SVGUseElement::~SVGUseElement() {
89 UnlinkSource();
90 MOZ_DIAGNOSTIC_ASSERT(!OwnerDoc()->SVGUseElementNeedsShadowTreeUpdate(*this),
91 "Dying without unbinding?");
94 namespace SVGT = SVGGeometryProperty::Tags;
96 //----------------------------------------------------------------------
97 // nsINode methods
99 void SVGUseElement::ProcessAttributeChange(int32_t aNamespaceID,
100 nsAtom* aAttribute) {
101 if (OwnerDoc()->CloningForSVGUse()) {
102 return;
104 if (aNamespaceID == kNameSpaceID_None) {
105 if (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height) {
106 const bool hadValidDimensions = HasValidDimensions();
107 const bool isUsed = OurWidthAndHeightAreUsed();
108 if (isUsed) {
109 SyncWidthOrHeight(aAttribute);
112 if (auto* frame = GetFrame()) {
113 frame->DimensionAttributeChanged(hadValidDimensions, isUsed);
118 if ((aNamespaceID == kNameSpaceID_XLink ||
119 aNamespaceID == kNameSpaceID_None) &&
120 aAttribute == nsGkAtoms::href) {
121 // We're changing our nature, clear out the clone information.
122 if (auto* frame = GetFrame()) {
123 frame->HrefChanged();
125 UnlinkSource();
126 TriggerReclone();
130 void SVGUseElement::DidAnimateAttribute(int32_t aNameSpaceID,
131 nsAtom* aAttribute) {
132 ProcessAttributeChange(aNameSpaceID, aAttribute);
135 void SVGUseElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aAttribute,
136 const nsAttrValue* aValue,
137 const nsAttrValue* aOldValue,
138 nsIPrincipal* aSubjectPrincipal,
139 bool aNotify) {
140 ProcessAttributeChange(aNamespaceID, aAttribute);
141 return SVGUseElementBase::AfterSetAttr(aNamespaceID, aAttribute, aValue,
142 aOldValue, aSubjectPrincipal, aNotify);
145 nsresult SVGUseElement::Clone(dom::NodeInfo* aNodeInfo,
146 nsINode** aResult) const {
147 *aResult = nullptr;
148 SVGUseElement* it =
149 new (aNodeInfo->NodeInfoManager()) SVGUseElement(do_AddRef(aNodeInfo));
151 nsCOMPtr<nsINode> kungFuDeathGrip(it);
152 nsresult rv1 = it->Init();
153 nsresult rv2 = const_cast<SVGUseElement*>(this)->CopyInnerTo(it);
155 if (aNodeInfo->GetDocument()->CloningForSVGUse()) {
156 // SVGUseElement specific portion - record who we cloned from
157 it->mOriginal = const_cast<SVGUseElement*>(this);
160 if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
161 kungFuDeathGrip.swap(*aResult);
164 return NS_FAILED(rv1) ? rv1 : rv2;
167 nsresult SVGUseElement::BindToTree(BindContext& aContext, nsINode& aParent) {
168 nsresult rv = SVGUseElementBase::BindToTree(aContext, aParent);
169 NS_ENSURE_SUCCESS(rv, rv);
171 TriggerReclone();
172 return NS_OK;
175 void SVGUseElement::UnbindFromTree(UnbindContext& aContext) {
176 SVGUseElementBase::UnbindFromTree(aContext);
177 OwnerDoc()->UnscheduleSVGUseElementShadowTreeUpdate(*this);
180 already_AddRefed<DOMSVGAnimatedString> SVGUseElement::Href() {
181 return mStringAttributes[HREF].IsExplicitlySet()
182 ? mStringAttributes[HREF].ToDOMAnimatedString(this)
183 : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
186 //----------------------------------------------------------------------
188 already_AddRefed<DOMSVGAnimatedLength> SVGUseElement::X() {
189 return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
192 already_AddRefed<DOMSVGAnimatedLength> SVGUseElement::Y() {
193 return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
196 already_AddRefed<DOMSVGAnimatedLength> SVGUseElement::Width() {
197 return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
200 already_AddRefed<DOMSVGAnimatedLength> SVGUseElement::Height() {
201 return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
204 //----------------------------------------------------------------------
205 // nsIMutationObserver methods
207 void SVGUseElement::CharacterDataChanged(nsIContent* aContent,
208 const CharacterDataChangeInfo&) {
209 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
210 aContent)) {
211 TriggerReclone();
215 void SVGUseElement::AttributeChanged(Element* aElement, int32_t aNamespaceID,
216 nsAtom* aAttribute, int32_t aModType,
217 const nsAttrValue* aOldValue) {
218 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
219 aElement)) {
220 TriggerReclone();
224 void SVGUseElement::ContentAppended(nsIContent* aFirstNewContent) {
225 // FIXME(emilio, bug 1442336): Why does this check the parent but
226 // ContentInserted the child?
227 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
228 aFirstNewContent->GetParent())) {
229 TriggerReclone();
233 void SVGUseElement::ContentInserted(nsIContent* aChild) {
234 // FIXME(emilio, bug 1442336): Why does this check the child but
235 // ContentAppended the parent?
236 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
237 aChild)) {
238 TriggerReclone();
242 void SVGUseElement::ContentWillBeRemoved(nsIContent* aChild) {
243 if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
244 aChild)) {
245 TriggerReclone();
249 void SVGUseElement::NodeWillBeDestroyed(nsINode* aNode) {
250 nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
251 UnlinkSource();
254 // Returns whether this node could ever be displayed.
255 static bool NodeCouldBeRendered(const nsINode& aNode) {
256 if (const auto* symbol = SVGSymbolElement::FromNode(aNode)) {
257 return symbol->CouldBeRendered();
259 if (auto* svgSwitch =
260 SVGSwitchElement::FromNodeOrNull(aNode.GetParentNode())) {
261 if (&aNode != svgSwitch->GetActiveChild()) {
262 return false;
264 } else if (const auto* svgGraphics = SVGGraphicsElement::FromNode(aNode)) {
265 if (!svgGraphics->PassesConditionalProcessingTests()) {
266 return false;
269 return true;
272 // <svg:use> can be used (no pun intended) to trivially cause an explosion of
273 // clones that could potentially DoS the browser. We have a configurable limit
274 // to control this.
275 static bool IsTooMuchRecursion(uint32_t aCount) {
276 switch (StaticPrefs::svg_use_element_recursive_clone_limit_enabled()) {
277 case 0:
278 return false;
279 case 1:
280 break;
281 default:
282 if (!XRE_IsParentProcess()) {
283 return false;
285 break;
287 return aCount >= StaticPrefs::svg_use_element_recursive_clone_limit();
290 // Circular loop detection, plus detection of whether this shadow tree is
291 // rendered at all.
292 auto SVGUseElement::ScanAncestors(const Element& aTarget) const -> ScanResult {
293 uint32_t count = 0;
294 return ScanAncestorsInternal(aTarget, count);
297 auto SVGUseElement::ScanAncestorsInternal(
298 const Element& aTarget, uint32_t& aCount) const -> ScanResult {
299 if (&aTarget == this) {
300 return ScanResult::CyclicReference;
302 if (mOriginal) {
303 if (IsTooMuchRecursion(++aCount)) {
304 return ScanResult::TooDeep;
306 auto result = mOriginal->ScanAncestorsInternal(aTarget, aCount);
307 switch (result) {
308 case ScanResult::TooDeep:
309 case ScanResult::CyclicReference:
310 return result;
311 case ScanResult::Ok:
312 case ScanResult::Invisible:
313 break;
317 auto result = ScanResult::Ok;
318 for (nsINode* parent = GetParentOrShadowHostNode(); parent;
319 parent = parent->GetParentOrShadowHostNode()) {
320 if (parent == &aTarget) {
321 return ScanResult::CyclicReference;
323 if (auto* use = SVGUseElement::FromNode(*parent)) {
324 if (IsTooMuchRecursion(++aCount)) {
325 return ScanResult::TooDeep;
327 if (mOriginal && use->mOriginal == mOriginal) {
328 return ScanResult::CyclicReference;
331 // Do we have other similar cases we can optimize out easily?
332 if (!NodeCouldBeRendered(*parent)) {
333 // NOTE(emilio): We can't just return here. If we're cyclic, we need to
334 // know.
335 result = ScanResult::Invisible;
338 return result;
341 //----------------------------------------------------------------------
343 static bool IsForbiddenUseNode(const nsINode& aNode) {
344 if (!aNode.IsElement()) {
345 return false;
347 const auto* svg = SVGElement::FromNode(aNode);
348 return !svg || !svg->IsSVGGraphicsElement();
351 static void CollectForbiddenNodes(Element& aRoot,
352 nsTArray<RefPtr<nsINode>>& aNodes) {
353 auto iter = dom::ShadowIncludingTreeIterator(aRoot);
354 while (iter) {
355 nsINode* node = *iter;
356 if (IsForbiddenUseNode(*node)) {
357 aNodes.AppendElement(node);
358 iter.SkipChildren();
359 continue;
361 ++iter;
365 // SVG1 restricted <use> trees to SVGGraphicsElements.
366 // https://www.w3.org/TR/SVG11/struct.html#UseElement:
368 // Any ‘svg’, ‘symbol’, ‘g’, graphics element or other ‘use’ is potentially a
369 // template object that can be re-used (i.e., "instanced") in the SVG
370 // document via a ‘use’ element. The ‘use’ element references another element
371 // and indicates that the graphical contents of that element is
372 // included/drawn at that given point in the document.
374 // SVG2 doesn't have that same restriction.
375 // https://www.w3.org/TR/SVG2/struct.html#UseShadowTree:
377 // Previous versions of SVG restricted the contents of the shadow tree to SVG
378 // graphics elements. This specification allows any valid SVG document
379 // subtree to be cloned. Cloning non-graphical content, however, will not
380 // usually have any visible effect.
382 // But it's pretty ambiguous as to what the behavior should be for some
383 // elements, because <script> is inert, but <iframe> is not, see:
384 // https://github.com/w3c/svgwg/issues/876
386 // So, fairly confusing, all-in-all.
387 static void RemoveForbiddenNodes(Element& aRoot, bool aIsCrossDocument) {
388 switch (StaticPrefs::svg_use_element_graphics_element_restrictions()) {
389 case 0:
390 return;
391 case 1:
392 if (!aIsCrossDocument) {
393 return;
395 break;
396 default:
397 break;
400 AutoTArray<RefPtr<nsINode>, 10> unsafeNodes;
401 CollectForbiddenNodes(aRoot, unsafeNodes);
402 for (auto& unsafeNode : unsafeNodes) {
403 unsafeNode->Remove();
407 void SVGUseElement::UpdateShadowTree() {
408 MOZ_ASSERT(IsInComposedDoc());
410 if (mReferencedElementTracker.get()) {
411 mReferencedElementTracker.get()->RemoveMutationObserver(this);
414 LookupHref();
416 RefPtr<ShadowRoot> shadow = GetShadowRoot();
417 if (!shadow) {
418 shadow = AttachShadowWithoutNameChecks(ShadowRootMode::Closed);
420 MOZ_ASSERT(shadow);
422 auto* targetElement =
423 SVGGraphicsElement::FromNodeOrNull(mReferencedElementTracker.get());
424 RefPtr<Element> newElement;
426 auto UpdateShadowTree = mozilla::MakeScopeExit([&]() {
427 if (nsIContent* firstChild = shadow->GetFirstChild()) {
428 MOZ_ASSERT(!firstChild->GetNextSibling());
429 shadow->RemoveChildNode(firstChild, /* aNotify = */ true);
432 if (newElement) {
433 shadow->AppendChildTo(newElement, /* aNotify = */ true, IgnoreErrors());
437 // make sure target is valid type for <use>
438 if (!targetElement) {
439 return;
442 if (ScanAncestors(*targetElement) != ScanResult::Ok) {
443 return;
446 nsCOMPtr<nsIURI> baseURI = targetElement->GetBaseURI();
447 if (!baseURI) {
448 return;
452 const bool isCrossDocument = targetElement->OwnerDoc() != OwnerDoc();
454 nsNodeInfoManager* nodeInfoManager =
455 isCrossDocument ? OwnerDoc()->NodeInfoManager() : nullptr;
457 nsCOMPtr<nsINode> newNode =
458 targetElement->Clone(true, nodeInfoManager, IgnoreErrors());
459 if (!newNode) {
460 return;
463 MOZ_ASSERT(newNode->IsElement());
464 newElement = newNode.forget().downcast<Element>();
465 RemoveForbiddenNodes(*newElement, isCrossDocument);
468 if (newElement->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol)) {
469 auto* newSVGElement = static_cast<SVGElement*>(newElement.get());
470 if (mLengthAttributes[ATTR_WIDTH].IsExplicitlySet())
471 newSVGElement->SetLength(nsGkAtoms::width, mLengthAttributes[ATTR_WIDTH]);
472 if (mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet())
473 newSVGElement->SetLength(nsGkAtoms::height,
474 mLengthAttributes[ATTR_HEIGHT]);
477 // Bug 1415044 the specs do not say which referrer information we should use.
478 // This may change if there's any spec comes out.
479 auto referrerInfo = MakeRefPtr<ReferrerInfo>(*this);
480 mContentURLData = new URLExtraData(baseURI.forget(), referrerInfo.forget(),
481 do_AddRef(NodePrincipal()));
483 targetElement->AddMutationObserver(this);
486 nsIURI* SVGUseElement::GetSourceDocURI() {
487 nsIContent* targetElement = mReferencedElementTracker.get();
488 if (!targetElement) {
489 return nullptr;
492 return targetElement->OwnerDoc()->GetDocumentURI();
495 const Encoding* SVGUseElement::GetSourceDocCharacterSet() {
496 nsIContent* targetElement = mReferencedElementTracker.get();
497 if (!targetElement) {
498 return nullptr;
501 return targetElement->OwnerDoc()->GetDocumentCharacterSet();
504 static nsINode* GetClonedChild(const SVGUseElement& aUseElement) {
505 const ShadowRoot* shadow = aUseElement.GetShadowRoot();
506 return shadow ? shadow->GetFirstChild() : nullptr;
509 bool SVGUseElement::OurWidthAndHeightAreUsed() const {
510 nsINode* clonedChild = GetClonedChild(*this);
511 return clonedChild &&
512 clonedChild->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol);
515 //----------------------------------------------------------------------
516 // implementation helpers
518 void SVGUseElement::SyncWidthOrHeight(nsAtom* aName) {
519 NS_ASSERTION(aName == nsGkAtoms::width || aName == nsGkAtoms::height,
520 "The clue is in the function name");
521 NS_ASSERTION(OurWidthAndHeightAreUsed(), "Don't call this");
523 if (!OurWidthAndHeightAreUsed()) {
524 return;
527 auto* target = SVGElement::FromNode(GetClonedChild(*this));
528 uint32_t index =
529 sLengthInfo[ATTR_WIDTH].mName == aName ? ATTR_WIDTH : ATTR_HEIGHT;
531 if (mLengthAttributes[index].IsExplicitlySet()) {
532 target->SetLength(aName, mLengthAttributes[index]);
533 return;
535 if (target->IsSVGElement(nsGkAtoms::svg)) {
536 // Our width/height attribute is now no longer explicitly set, so we
537 // need to revert the clone's width/height to the width/height of the
538 // content that's being cloned.
539 TriggerReclone();
540 return;
542 // Our width/height attribute is now no longer explicitly set, so we
543 // need to set the value to 100%
544 SVGAnimatedLength length;
545 length.Init(SVGContentUtils::XY, 0xff, 100,
546 SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE);
547 target->SetLength(aName, length);
550 void SVGUseElement::LookupHref() {
551 nsAutoString href;
552 if (mStringAttributes[HREF].IsExplicitlySet()) {
553 mStringAttributes[HREF].GetAnimValue(href, this);
554 } else {
555 mStringAttributes[XLINK_HREF].GetAnimValue(href, this);
558 if (href.IsEmpty()) {
559 return;
562 Element* treeToWatch = mOriginal ? mOriginal.get() : this;
563 if (nsContentUtils::IsLocalRefURL(href)) {
564 mReferencedElementTracker.ResetToLocalFragmentID(*treeToWatch, href);
565 return;
568 nsCOMPtr<nsIURI> baseURI = treeToWatch->GetBaseURI();
569 nsCOMPtr<nsIURI> targetURI;
570 nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
571 GetComposedDoc(), baseURI);
572 if (!targetURI) {
573 return;
576 // Don't allow <use href="data:...">. Using "#ref" inside a data: document is
577 // handled above.
578 if (targetURI->SchemeIs("data") &&
579 !StaticPrefs::svg_use_element_data_url_href_allowed()) {
580 return;
583 nsIReferrerInfo* referrer =
584 OwnerDoc()->ReferrerInfoForInternalCSSAndSVGResources();
585 mReferencedElementTracker.ResetToURIWithFragmentID(treeToWatch, targetURI,
586 referrer);
589 void SVGUseElement::TriggerReclone() {
590 if (Document* doc = GetComposedDoc()) {
591 doc->ScheduleSVGUseElementShadowTreeUpdate(*this);
595 void SVGUseElement::UnlinkSource() {
596 if (mReferencedElementTracker.get()) {
597 mReferencedElementTracker.get()->RemoveMutationObserver(this);
599 mReferencedElementTracker.Unlink();
602 //----------------------------------------------------------------------
603 // SVGElement methods
605 /* virtual */
606 gfxMatrix SVGUseElement::ChildToUserSpaceTransform() const {
607 float x, y;
608 if (!SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y>(this, &x, &y)) {
609 const_cast<SVGUseElement*>(this)->GetAnimatedLengthValues(&x, &y, nullptr);
611 return gfxMatrix::Translation(x, y);
614 /* virtual */
615 bool SVGUseElement::HasValidDimensions() const {
616 if (!OurWidthAndHeightAreUsed()) {
617 return true;
620 return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
621 mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
622 (!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
623 mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0);
626 SVGElement::LengthAttributesInfo SVGUseElement::GetLengthInfo() {
627 return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
628 std::size(sLengthInfo));
631 SVGElement::StringAttributesInfo SVGUseElement::GetStringInfo() {
632 return StringAttributesInfo(mStringAttributes, sStringInfo,
633 std::size(sStringInfo));
636 SVGUseFrame* SVGUseElement::GetFrame() const {
637 nsIFrame* frame = GetPrimaryFrame();
638 // We might be a plain SVGContainerFrame if we didn't pass the conditional
639 // processing checks.
640 if (!frame || !frame->IsSVGUseFrame()) {
641 MOZ_ASSERT_IF(frame, frame->Type() == LayoutFrameType::None);
642 return nullptr;
644 return static_cast<SVGUseFrame*>(frame);
647 //----------------------------------------------------------------------
648 // nsIContent methods
650 NS_IMETHODIMP_(bool)
651 SVGUseElement::IsAttributeMapped(const nsAtom* name) const {
652 return name == nsGkAtoms::x || name == nsGkAtoms::y ||
653 SVGUseElementBase::IsAttributeMapped(name);
656 nsCSSPropertyID SVGUseElement::GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum) {
657 switch (aAttrEnum) {
658 case ATTR_X:
659 return eCSSProperty_x;
660 case ATTR_Y:
661 return eCSSProperty_y;
662 default:
663 // Currently we don't map width or height to style
664 return eCSSProperty_UNKNOWN;
668 } // namespace mozilla::dom