gecko-dev/dom/svg/SVGUseElement.cpp

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

554 строки
19 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/. */
#include "mozilla/dom/SVGUseElement.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/SVGLengthBinding.h"
#include "mozilla/dom/SVGUseElementBinding.h"
#include "nsGkAtoms.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "nsContentUtils.h"
#include "nsIURI.h"
#include "mozilla/URLExtraData.h"
#include "SVGObserverUtils.h"
#include "nsSVGUseFrame.h"
NS_IMPL_NS_NEW_SVG_ELEMENT(Use)
namespace mozilla {
namespace dom {
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv The only manual changes here are to BindingUtils.h, BindingUtils.cpp, Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp, dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp, Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp, Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The rest of this diff was generated by running the following commands: find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
JSObject* SVGUseElement::WrapNode(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return SVGUseElement_Binding::Wrap(aCx, this, aGivenProto);
}
////////////////////////////////////////////////////////////////////////
// implementation
SVGElement::LengthInfo SVGUseElement::sLengthInfo[4] = {
{nsGkAtoms::x, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
SVGContentUtils::X},
{nsGkAtoms::y, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
SVGContentUtils::Y},
{nsGkAtoms::width, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
SVGContentUtils::X},
{nsGkAtoms::height, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
SVGContentUtils::Y},
};
SVGElement::StringInfo SVGUseElement::sStringInfo[2] = {
{nsGkAtoms::href, kNameSpaceID_None, true},
{nsGkAtoms::href, kNameSpaceID_XLink, true}};
//----------------------------------------------------------------------
// nsISupports methods
NS_IMPL_CYCLE_COLLECTION_CLASS(SVGUseElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGUseElement,
SVGUseElementBase)
nsAutoScriptBlocker scriptBlocker;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginal)
tmp->UnlinkSource();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGUseElement,
SVGUseElementBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginal)
tmp->mReferencedElementTracker.Traverse(&cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(SVGUseElement, SVGUseElementBase,
nsIMutationObserver)
//----------------------------------------------------------------------
// Implementation
SVGUseElement::SVGUseElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
: SVGUseElementBase(std::move(aNodeInfo)),
mReferencedElementTracker(this) {}
SVGUseElement::~SVGUseElement() {
UnlinkSource();
MOZ_DIAGNOSTIC_ASSERT(!OwnerDoc()->SVGUseElementNeedsShadowTreeUpdate(*this),
"Dying without unbinding?");
}
//----------------------------------------------------------------------
// nsINode methods
void SVGUseElement::ProcessAttributeChange(int32_t aNamespaceID,
nsAtom* aAttribute) {
if (aNamespaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y) {
if (auto* frame = GetFrame()) {
frame->PositionAttributeChanged();
}
} else if (aAttribute == nsGkAtoms::width ||
aAttribute == nsGkAtoms::height) {
const bool hadValidDimensions = HasValidDimensions();
const bool isUsed = OurWidthAndHeightAreUsed();
if (isUsed) {
SyncWidthOrHeight(aAttribute);
}
if (auto* frame = GetFrame()) {
frame->DimensionAttributeChanged(hadValidDimensions, isUsed);
}
}
}
if ((aNamespaceID == kNameSpaceID_XLink ||
aNamespaceID == kNameSpaceID_None) &&
aAttribute == nsGkAtoms::href) {
// We're changing our nature, clear out the clone information.
if (auto* frame = GetFrame()) {
frame->HrefChanged();
}
mOriginal = nullptr;
UnlinkSource();
TriggerReclone();
}
}
nsresult SVGUseElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aAttribute,
const nsAttrValue* aValue,
const nsAttrValue* aOldValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) {
ProcessAttributeChange(aNamespaceID, aAttribute);
return SVGUseElementBase::AfterSetAttr(aNamespaceID, aAttribute, aValue,
aOldValue, aSubjectPrincipal, aNotify);
}
nsresult SVGUseElement::Clone(dom::NodeInfo* aNodeInfo,
nsINode** aResult) const {
*aResult = nullptr;
SVGUseElement* it =
new (aNodeInfo->NodeInfoManager()) SVGUseElement(do_AddRef(aNodeInfo));
nsCOMPtr<nsINode> kungFuDeathGrip(it);
nsresult rv1 = it->Init();
nsresult rv2 = const_cast<SVGUseElement*>(this)->CopyInnerTo(it);
// SVGUseElement specific portion - record who we cloned from
it->mOriginal = const_cast<SVGUseElement*>(this);
if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
kungFuDeathGrip.swap(*aResult);
}
return NS_FAILED(rv1) ? rv1 : rv2;
}
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 SVGUseElement::BindToTree(BindContext& aContext, nsINode& aParent) {
nsresult rv = SVGUseElementBase::BindToTree(aContext, aParent);
NS_ENSURE_SUCCESS(rv, rv);
TriggerReclone();
return NS_OK;
}
void SVGUseElement::UnbindFromTree(bool aNullParent) {
SVGUseElementBase::UnbindFromTree(aNullParent);
OwnerDoc()->UnscheduleSVGUseElementShadowTreeUpdate(*this);
}
already_AddRefed<DOMSVGAnimatedString> SVGUseElement::Href() {
return mStringAttributes[HREF].IsExplicitlySet()
? mStringAttributes[HREF].ToDOMAnimatedString(this)
: mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
}
//----------------------------------------------------------------------
already_AddRefed<DOMSVGAnimatedLength> SVGUseElement::X() {
return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
}
already_AddRefed<DOMSVGAnimatedLength> SVGUseElement::Y() {
return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
}
already_AddRefed<DOMSVGAnimatedLength> SVGUseElement::Width() {
return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
}
already_AddRefed<DOMSVGAnimatedLength> SVGUseElement::Height() {
return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
}
//----------------------------------------------------------------------
// nsIMutationObserver methods
void SVGUseElement::CharacterDataChanged(nsIContent* aContent,
const CharacterDataChangeInfo&) {
if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
aContent)) {
TriggerReclone();
}
}
void SVGUseElement::AttributeChanged(Element* aElement, int32_t aNamespaceID,
nsAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue) {
if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
aElement)) {
TriggerReclone();
}
}
void SVGUseElement::ContentAppended(nsIContent* aFirstNewContent) {
// FIXME(emilio, bug 1442336): Why does this check the parent but
// ContentInserted the child?
if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
aFirstNewContent->GetParent())) {
TriggerReclone();
}
}
void SVGUseElement::ContentInserted(nsIContent* aChild) {
// FIXME(emilio, bug 1442336): Why does this check the child but
// ContentAppended the parent?
if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
aChild)) {
TriggerReclone();
}
}
void SVGUseElement::ContentRemoved(nsIContent* aChild,
nsIContent* aPreviousSibling) {
if (nsContentUtils::IsInSameAnonymousTree(mReferencedElementTracker.get(),
aChild)) {
TriggerReclone();
}
}
void SVGUseElement::NodeWillBeDestroyed(const nsINode* aNode) {
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
UnlinkSource();
}
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
// Returns whether this node could ever be displayed.
static bool NodeCouldBeRendered(const nsINode& aNode) {
if (aNode.IsSVGElement(nsGkAtoms::symbol)) {
// Only <symbol> elements in the root of a <svg:use> shadow tree are
// displayed.
auto* shadowRoot = ShadowRoot::FromNodeOrNull(aNode.GetParentNode());
return shadowRoot && shadowRoot->Host()->IsSVGElement(nsGkAtoms::use);
}
// TODO: Do we have other cases we can optimize out easily?
return true;
}
// Circular loop detection, plus detection of whether this shadow tree is
// rendered at all.
auto SVGUseElement::ScanAncestors(const Element& aTarget) const -> ScanResult {
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
if (&aTarget == this) {
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
return ScanResult::CyclicReference;
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
}
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
if (mOriginal &&
mOriginal->ScanAncestors(aTarget) == ScanResult::CyclicReference) {
return ScanResult::CyclicReference;
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
}
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
auto result = ScanResult::Ok;
for (nsINode* parent = GetParentOrShadowHostNode(); parent;
parent = parent->GetParentOrShadowHostNode()) {
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
if (parent == &aTarget) {
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
return ScanResult::CyclicReference;
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
}
if (auto* use = SVGUseElement::FromNode(*parent)) {
if (mOriginal && use->mOriginal == mOriginal) {
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
return ScanResult::CyclicReference;
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
}
}
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
// Do we have other similar cases we can optimize out easily?
if (!NodeCouldBeRendered(*parent)) {
// NOTE(emilio): We can't just return here. If we're cyclic, we need to
// know.
result = ScanResult::Invisible;
}
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
}
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
return result;
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
}
//----------------------------------------------------------------------
void SVGUseElement::UpdateShadowTree() {
MOZ_ASSERT(IsInComposedDoc());
if (mReferencedElementTracker.get()) {
mReferencedElementTracker.get()->RemoveMutationObserver(this);
}
LookupHref();
RefPtr<ShadowRoot> shadow = GetShadowRoot();
if (!shadow) {
shadow = AttachShadowWithoutNameChecks(ShadowRootMode::Closed);
}
MOZ_ASSERT(shadow);
Element* targetElement = mReferencedElementTracker.get();
RefPtr<Element> newElement;
auto UpdateShadowTree = mozilla::MakeScopeExit([&]() {
nsIContent* firstChild = shadow->GetFirstChild();
if (firstChild) {
MOZ_ASSERT(!firstChild->GetNextSibling());
shadow->RemoveChildNode(firstChild, /* aNotify = */ true);
}
if (newElement) {
shadow->AppendChildTo(newElement, /* aNotify = */ true);
}
});
// make sure target is valid type for <use>
// QIable nsSVGGraphicsElement would eliminate enumerating all elements
if (!targetElement ||
!targetElement->IsAnyOfSVGElements(
nsGkAtoms::svg, nsGkAtoms::symbol, nsGkAtoms::g, nsGkAtoms::path,
nsGkAtoms::text, nsGkAtoms::rect, nsGkAtoms::circle,
nsGkAtoms::ellipse, nsGkAtoms::line, nsGkAtoms::polyline,
nsGkAtoms::polygon, nsGkAtoms::image, nsGkAtoms::use)) {
return;
}
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
if (ScanAncestors(*targetElement) != ScanResult::Ok) {
return;
}
nsCOMPtr<nsIURI> baseURI = targetElement->GetBaseURI();
if (!baseURI) {
return;
}
{
nsNodeInfoManager* nodeInfoManager = targetElement->OwnerDoc() == OwnerDoc()
? nullptr
: OwnerDoc()->NodeInfoManager();
nsCOMPtr<nsINode> newNode =
targetElement->Clone(true, nodeInfoManager, IgnoreErrors());
if (!newNode) {
return;
}
MOZ_ASSERT(newNode->IsElement());
newElement = newNode.forget().downcast<Element>();
}
if (newElement->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol)) {
auto* newSVGElement = static_cast<SVGElement*>(newElement.get());
if (mLengthAttributes[ATTR_WIDTH].IsExplicitlySet())
newSVGElement->SetLength(nsGkAtoms::width, mLengthAttributes[ATTR_WIDTH]);
if (mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet())
newSVGElement->SetLength(nsGkAtoms::height,
mLengthAttributes[ATTR_HEIGHT]);
}
// Bug 1415044 the specs do not say which referrer information we should use.
// This may change if there's any spec comes out.
nsCOMPtr<nsIReferrerInfo> referrerInfo = new mozilla::dom::ReferrerInfo();
referrerInfo->InitWithNode(this);
mContentURLData = new URLExtraData(baseURI.forget(), referrerInfo.forget(),
do_AddRef(NodePrincipal()));
targetElement->AddMutationObserver(this);
}
nsIURI* SVGUseElement::GetSourceDocURI() {
nsIContent* targetElement = mReferencedElementTracker.get();
if (!targetElement) {
return nullptr;
}
return targetElement->OwnerDoc()->GetDocumentURI();
}
static nsINode* GetClonedChild(const SVGUseElement& aUseElement) {
const ShadowRoot* shadow = aUseElement.GetShadowRoot();
return shadow ? shadow->GetFirstChild() : nullptr;
}
bool SVGUseElement::OurWidthAndHeightAreUsed() const {
nsINode* clonedChild = GetClonedChild(*this);
return clonedChild &&
clonedChild->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol);
}
//----------------------------------------------------------------------
// implementation helpers
void SVGUseElement::SyncWidthOrHeight(nsAtom* aName) {
NS_ASSERTION(aName == nsGkAtoms::width || aName == nsGkAtoms::height,
"The clue is in the function name");
NS_ASSERTION(OurWidthAndHeightAreUsed(), "Don't call this");
if (!OurWidthAndHeightAreUsed()) {
return;
}
auto* target = SVGElement::FromNode(GetClonedChild(*this));
uint32_t index =
sLengthInfo[ATTR_WIDTH].mName == aName ? ATTR_WIDTH : ATTR_HEIGHT;
if (mLengthAttributes[index].IsExplicitlySet()) {
target->SetLength(aName, mLengthAttributes[index]);
return;
}
if (target->IsSVGElement(nsGkAtoms::svg)) {
// Our width/height attribute is now no longer explicitly set, so we
// need to revert the clone's width/height to the width/height of the
// content that's being cloned.
TriggerReclone();
return;
}
// Our width/height attribute is now no longer explicitly set, so we
// need to set the value to 100%
SVGAnimatedLength length;
length.Init(SVGContentUtils::XY, 0xff, 100,
SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE);
target->SetLength(aName, length);
}
void SVGUseElement::LookupHref() {
nsAutoString href;
if (mStringAttributes[HREF].IsExplicitlySet()) {
mStringAttributes[HREF].GetAnimValue(href, this);
} else {
mStringAttributes[XLINK_HREF].GetAnimValue(href, this);
}
if (href.IsEmpty()) {
return;
}
nsCOMPtr<nsIURI> originURI =
mOriginal ? mOriginal->GetBaseURI() : GetBaseURI();
nsCOMPtr<nsIURI> baseURI =
nsContentUtils::IsLocalRefURL(href)
? SVGObserverUtils::GetBaseURLForLocalRef(this, originURI)
: originURI;
nsCOMPtr<nsIURI> targetURI;
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
GetComposedDoc(), baseURI);
nsCOMPtr<nsIReferrerInfo> referrerInfo =
ReferrerInfo::CreateForSVGResources(OwnerDoc());
mReferencedElementTracker.ResetToURIFragmentID(this, targetURI, referrerInfo);
}
void SVGUseElement::TriggerReclone() {
if (Document* doc = GetComposedDoc()) {
doc->ScheduleSVGUseElementShadowTreeUpdate(*this);
}
}
void SVGUseElement::UnlinkSource() {
if (mReferencedElementTracker.get()) {
mReferencedElementTracker.get()->RemoveMutationObserver(this);
}
mReferencedElementTracker.Unlink();
}
//----------------------------------------------------------------------
// SVGElement methods
/* virtual */
gfxMatrix SVGUseElement::PrependLocalTransformsTo(
const gfxMatrix& aMatrix, SVGTransformTypes aWhich) const {
// 'transform' attribute:
gfxMatrix userToParent;
if (aWhich == eUserSpaceToParent || aWhich == eAllTransforms) {
userToParent = GetUserToParentTransform(mAnimateMotionTransform.get(),
mTransforms.get());
if (aWhich == eUserSpaceToParent) {
return userToParent * aMatrix;
}
}
// our 'x' and 'y' attributes:
float x, y;
const_cast<SVGUseElement*>(this)->GetAnimatedLengthValues(&x, &y, nullptr);
gfxMatrix childToUser = gfxMatrix::Translation(x, y);
if (aWhich == eAllTransforms) {
return childToUser * userToParent * aMatrix;
}
MOZ_ASSERT(aWhich == eChildToUserSpace, "Unknown TransformTypes");
// The following may look broken because pre-multiplying our eChildToUserSpace
// transform with another matrix without including our eUserSpaceToParent
// transform between the two wouldn't make sense. We don't expect that to
// ever happen though. We get here either when the identity matrix has been
// passed because our caller just wants our eChildToUserSpace transform, or
// when our eUserSpaceToParent transform has already been multiplied into the
// matrix that our caller passes (such as when we're called from PaintSVG).
return childToUser * aMatrix;
}
/* virtual */
bool SVGUseElement::HasValidDimensions() const {
return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
(!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0);
}
SVGElement::LengthAttributesInfo SVGUseElement::GetLengthInfo() {
return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
ArrayLength(sLengthInfo));
}
SVGElement::StringAttributesInfo SVGUseElement::GetStringInfo() {
return StringAttributesInfo(mStringAttributes, sStringInfo,
ArrayLength(sStringInfo));
}
nsSVGUseFrame* SVGUseElement::GetFrame() const {
nsIFrame* frame = GetPrimaryFrame();
// We might be a plain nsSVGContainerFrame if we didn't pass the conditional
// processing checks.
if (!frame || !frame->IsSVGUseFrame()) {
MOZ_ASSERT_IF(frame, frame->Type() == LayoutFrameType::None);
return nullptr;
}
return static_cast<nsSVGUseFrame*>(frame);
}
//----------------------------------------------------------------------
// nsIContent methods
NS_IMETHODIMP_(bool)
SVGUseElement::IsAttributeMapped(const nsAtom* name) const {
static const MappedAttributeEntry* const map[] = {sFEFloodMap,
sFiltersMap,
sFontSpecificationMap,
sGradientStopMap,
sLightingEffectsMap,
sMarkersMap,
sTextContentElementsMap,
sViewportsMap};
return FindAttributeDependence(name, map) ||
SVGUseElementBase::IsAttributeMapped(name);
}
} // namespace dom
} // namespace mozilla