gecko-dev/dom/svg/SVGUseElement.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

172 строки
5.8 KiB
C
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2012-05-21 15:12:37 +04:00
/* 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 mozilla_dom_SVGUseElement_h
#define mozilla_dom_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;
class nsSVGUseFrame;
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 {
struct URLExtraData;
namespace dom {
typedef SVGGraphicsElement SVGUseElementBase;
class SVGUseElement final : public SVGUseElementBase,
public nsStubMutationObserver {
friend class ::nsSVGUseFrame;
protected:
friend nsresult(::NS_NewSVGUseElement(
nsIContent** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
explicit SVGUseElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
virtual ~SVGUseElement();
virtual JSObject* WrapNode(JSContext* cx,
JS::Handle<JSObject*> aGivenProto) override;
public:
NS_IMPL_FROMNODE_WITH_TAG(SVGUseElement, kNameSpaceID_SVG, use)
Bug 1555216 - Change the signature of BindToTree to be (BindContext&, nsINode& aParentNode). r=bzbarsky BindContext was going to have way more information at first, but then I realized that most of the things I wanted to know were basically a flag away using the parent node. Still I think it's worth it, now experimenting with BindToTree will only mean adding a field to a struct that's included from a couple cpp files, instead of a massive pain. I also think this is clearer, and doing this highlights quite a few inconsistencies in our code which I've left untouched, but commented with FIXMEs. Steps are: $ for file in $(rg 'nsresult BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#nsresult BindToTree(Document\* aDocument, nsIContent\* aParent,#nsresult BindToTree(BindContext\&, nsINode\& aParent)#g' $file; done $ for file in $(rg 'nsresult BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's# nsIContent\* aBindingParent) override#override#g' $file; done $ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#::BindToTree(Document\* aDocument, nsIContent\* aParent,#::BindToTree(BindContext\& aContext, nsINode\& aParent)#g' $file; done $ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#nsIContent\* aBindingParent)##g' $file; done $ for file in $(rg '::BindToTree\(' | cut -d : -f 1 | sort | uniq); do sed -i 's#::BindToTree(aDocument, aParent, aBindingParent)#::BindToTree(aContext, aParent)#g' $file; done $ ./mach clang-format Then manual fixups. Depends on D32948 Differential Revision: https://phabricator.services.mozilla.com/D32949
2019-05-29 07:27:04 +03:00
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:
virtual gfxMatrix PrependLocalTransformsTo(
const gfxMatrix& aMatrix,
SVGTransformTypes aWhich = eAllTransforms) const override;
virtual bool HasValidDimensions() const override;
// nsIContent interface
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
// WebIDL
already_AddRefed<DOMSVGAnimatedString> Href();
already_AddRefed<DOMSVGAnimatedLength> X();
already_AddRefed<DOMSVGAnimatedLength> Y();
already_AddRefed<DOMSVGAnimatedLength> Width();
already_AddRefed<DOMSVGAnimatedLength> Height();
nsIURI* GetSourceDocURI();
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 nsSVGUseFrame::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:
Bug 1579181 - Don't keep <use> shadow trees which we know we'll never render. r=longsonr This partially addresses the regression, but not fully. With this patch we don't maintain shadow trees for nodes that we know won't get rendered. This works fast in WebKit / Blink because of a bug in their implementation which doesn't synchronize style attributes, introduced in [1]. You can see this clearly if you click on the bug's test-case and inspect the <use> shadow trees (there's no style="stroke:orange" whatsoever). They can kinda get away with it because they don't properly implement SVG 2. In particular, in Blink / WebKit, the style of the element in the <use> shadow tree is the style of the referenced element, which means that even if the style attribute isn't properly synced it's ~ok since it doesn't end up mattering for styling. Easiest test-case for the behavior difference is: ``` <!doctype html> <style> rect:hover { fill: green; } </style> <svg width=300 height=300> <g id="canvas"> <rect fill=red width=100 height=100></rect> </g> <g> <use x=200 href="#canvas"></use> </g> </svg> ``` Where Firefox will properly update each square independently when hovered, but Blink / WebKit won't. This used to work faster because in this particular test-case we have 3 hidden <use> elements whose href is the #canvas, which is basically everything. Before moving to shadow trees we'd do it using anonymous content, and since we never got a frame we'd never clone the subtree in the first case. This case was faster before bug 1450250, but this approach makes other cases slow that were fixed by that bug, like bug 1485402. So I'll try to optimize shadow tree syncing instead, I guess, but there's no good reason not to land this in the meantime IMHO. [1]: https://chromium.googlesource.com/chromium/src/+/f4b022e64bbe0c74f07ee9209aa4033bddece145%5E%21/third_party/WebKit/WebCore/svg/SVGElement.cpp Differential Revision: https://phabricator.services.mozilla.com/D45953 --HG-- extra : moz-landing-system : lando
2019-09-15 19:09:28 +03:00
// 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;
Bug 1531333 - Fix <svg:use> cycle detection. r=longsonr With the current code we'll eventually detect the cycle, but will take much more, creating many shadow trees unnecessarily. Take for example the following: <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133" height="232774"> <style> symbol { display: block } </style> <symbol id="svg-sprite" viewBox="0 0 133 230866"> <title>svg-sprite</title> <symbol id="svg-sprite" viewBox="0 0 133 230866"> <title>svg-sprite</title> <use xlink:href="#svg-sprite" width="500" height="500" /> </symbol> <use xlink:href="#svg-sprite" y="1601" width="133" height="228958" /> </symbol> <use xlink:href="#svg-sprite" y="1601" width="133" height="230866" /> </svg> Before this patch, we'd create an svg use element subtree for #svg-sprite. That subtree will contain two other <use> elements, one under the <symbol>, one not under it. Both point to #svg-sprite, but we fail to detect we're an ancestor since the element #svg-sprite we're looking at is the clone of the #svg-sprite element. Thus we need to take a look at mOriginal instead (which is the <use> element under #svg-sprite) rather than at the clone. Yeah, I had to draw the trees, it's messy :) Blink and WebKit do something slightly different (they check the element id directly[1]). That's not 100% correct, since you can have multiple elements with the same ID. [1]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/svg/svg_use_element.cc?l=560&rcl=861855dcb8c39ba8d42497247d433277858df79b Differential Revision: https://phabricator.services.mozilla.com/D24565 --HG-- extra : moz-landing-system : lando
2019-03-23 01:26:53 +03:00
/**
* 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);
2008-07-09 14:50:48 +04:00
if (aFrom) {
aFrom->RemoveMutationObserver(mOwningUseElement);
2008-07-09 14:50:48 +04:00
}
mOwningUseElement->TriggerReclone();
}
SVGUseElement* mOwningUseElement;
};
nsSVGUseFrame* GetFrame() const;
virtual LengthAttributesInfo GetLengthInfo() override;
virtual 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];
Bug 1531333 - Fix <svg:use> cycle detection. r=longsonr With the current code we'll eventually detect the cycle, but will take much more, creating many shadow trees unnecessarily. Take for example the following: <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133" height="232774"> <style> symbol { display: block } </style> <symbol id="svg-sprite" viewBox="0 0 133 230866"> <title>svg-sprite</title> <symbol id="svg-sprite" viewBox="0 0 133 230866"> <title>svg-sprite</title> <use xlink:href="#svg-sprite" width="500" height="500" /> </symbol> <use xlink:href="#svg-sprite" y="1601" width="133" height="228958" /> </symbol> <use xlink:href="#svg-sprite" y="1601" width="133" height="230866" /> </svg> Before this patch, we'd create an svg use element subtree for #svg-sprite. That subtree will contain two other <use> elements, one under the <symbol>, one not under it. Both point to #svg-sprite, but we fail to detect we're an ancestor since the element #svg-sprite we're looking at is the clone of the #svg-sprite element. Thus we need to take a look at mOriginal instead (which is the <use> element under #svg-sprite) rather than at the clone. Yeah, I had to draw the trees, it's messy :) Blink and WebKit do something slightly different (they check the element id directly[1]). That's not 100% correct, since you can have multiple elements with the same ID. [1]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/svg/svg_use_element.cc?l=560&rcl=861855dcb8c39ba8d42497247d433277858df79b Differential Revision: https://phabricator.services.mozilla.com/D24565 --HG-- extra : moz-landing-system : lando
2019-03-23 01:26:53 +03:00
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 // mozilla_dom_SVGUseElement_h