diff options
Diffstat (limited to '')
-rw-r--r-- | dom/svg/SVGUseElement.h | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/dom/svg/SVGUseElement.h b/dom/svg/SVGUseElement.h new file mode 100644 index 0000000000..9c71a45be0 --- /dev/null +++ b/dom/svg/SVGUseElement.h @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_SVG_SVGUSEELEMENT_H_ +#define DOM_SVG_SVGUSEELEMENT_H_ + +#include "mozilla/dom/FromParser.h" +#include "mozilla/dom/IDTracker.h" +#include "mozilla/dom/SVGGraphicsElement.h" +#include "mozilla/RefPtr.h" +#include "nsCOMPtr.h" +#include "nsStubMutationObserver.h" +#include "SVGAnimatedLength.h" +#include "SVGAnimatedString.h" +#include "nsTArray.h" + +class nsIContent; + +nsresult NS_NewSVGSVGElement( + nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, + mozilla::dom::FromParser aFromParser); +nsresult NS_NewSVGUseElement( + nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); + +namespace mozilla { +class Encoding; +class SVGUseFrame; +struct URLExtraData; + +namespace dom { + +using SVGUseElementBase = SVGGraphicsElement; + +class SVGUseElement final : public SVGUseElementBase, + public nsStubMutationObserver { + friend class mozilla::SVGUseFrame; + + protected: + friend nsresult(::NS_NewSVGUseElement( + nsIContent** aResult, + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)); + explicit SVGUseElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); + virtual ~SVGUseElement(); + JSObject* WrapNode(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; + + public: + NS_IMPL_FROMNODE_WITH_TAG(SVGUseElement, kNameSpaceID_SVG, use) + + bool IsNodeOfType(uint32_t aFlags) const override; + nsresult BindToTree(BindContext&, nsINode& aParent) override; + void UnbindFromTree(bool aNullParent = true) override; + + // interfaces: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGUseElement, SVGUseElementBase) + + NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED + + // SVGElement specializations: + gfxMatrix PrependLocalTransformsTo( + const gfxMatrix& aMatrix, + SVGTransformTypes aWhich = eAllTransforms) const override; + bool HasValidDimensions() const override; + + // nsIContent interface + nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; + NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override; + + static nsCSSPropertyID GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum); + + // WebIDL + already_AddRefed<DOMSVGAnimatedString> Href(); + already_AddRefed<DOMSVGAnimatedLength> X(); + already_AddRefed<DOMSVGAnimatedLength> Y(); + already_AddRefed<DOMSVGAnimatedLength> Width(); + already_AddRefed<DOMSVGAnimatedLength> Height(); + + nsIURI* GetSourceDocURI(); + const Encoding* GetSourceDocCharacterSet(); + URLExtraData* GetContentURLData() const { return mContentURLData; } + + // Updates the internal shadow tree to be an up-to-date clone of the + // referenced element. + void UpdateShadowTree(); + + // Shared code between AfterSetAttr and SVGUseFrame::AttributeChanged. + // + // This is needed because SMIL doesn't go through AfterSetAttr unfortunately. + void ProcessAttributeChange(int32_t aNamespaceID, nsAtom* aAttribute); + + nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aAttribute, + const nsAttrValue* aValue, const nsAttrValue* aOldValue, + nsIPrincipal* aSubjectPrincipal, bool aNotify) final; + + protected: + // Information from walking our ancestors and a given target. + enum class ScanResult { + // Nothing that should stop us from rendering the shadow tree. + Ok, + // We're never going to be displayed, so no point in updating the shadow + // tree. + // + // However if we're referenced from another tree that tree may need to be + // rendered. + Invisible, + // We're a cyclic reference to either an ancestor or another shadow tree. We + // shouldn't render this <use> element. + CyclicReference, + }; + ScanResult ScanAncestors(const Element& aTarget) const; + + /** + * Helper that provides a reference to the element with the ID that is + * referenced by the 'use' element's 'href' attribute, and that will update + * the 'use' element if the element that that ID identifies changes to a + * different element (or none). + */ + class ElementTracker final : public IDTracker { + public: + explicit ElementTracker(SVGUseElement* aOwningUseElement) + : mOwningUseElement(aOwningUseElement) {} + + private: + void ElementChanged(Element* aFrom, Element* aTo) override { + IDTracker::ElementChanged(aFrom, aTo); + if (aFrom) { + aFrom->RemoveMutationObserver(mOwningUseElement); + } + mOwningUseElement->TriggerReclone(); + } + + SVGUseElement* mOwningUseElement; + }; + + SVGUseFrame* GetFrame() const; + + LengthAttributesInfo GetLengthInfo() override; + StringAttributesInfo GetStringInfo() override; + + /** + * Returns true if our width and height should be used, or false if they + * should be ignored. As per the spec, this depends on the type of the + * element that we're referencing. + */ + bool OurWidthAndHeightAreUsed() const; + void SyncWidthOrHeight(nsAtom* aName); + void LookupHref(); + void TriggerReclone(); + void UnlinkSource(); + + enum { ATTR_X, ATTR_Y, ATTR_WIDTH, ATTR_HEIGHT }; + SVGAnimatedLength mLengthAttributes[4]; + static LengthInfo sLengthInfo[4]; + + enum { HREF, XLINK_HREF }; + SVGAnimatedString mStringAttributes[2]; + static StringInfo sStringInfo[2]; + + RefPtr<SVGUseElement> mOriginal; // if we've been cloned, our "real" copy + ElementTracker mReferencedElementTracker; + RefPtr<URLExtraData> mContentURLData; // URL data for its anonymous content +}; + +} // namespace dom +} // namespace mozilla + +#endif // DOM_SVG_SVGUSEELEMENT_H_ |