Bug 1329093 - Part 6: stylo: Handle cross-document node adoption in scheduled SVG content decl blocks;
MozReview-Commit-ID: 6tXWRle5XCE
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1106,17 +1106,23 @@ public:
* namespace ID must not be kNameSpaceID_Unknown and the name must not be
* null. Note that this can only return info on attributes that actually
* live on this element (and is only virtual to handle XUL prototypes). That
* is, this should only be called from methods that only care about attrs
* that effectively live in mAttrsAndChildren.
*/
virtual BorrowedAttrInfo GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const;
- virtual void NodeInfoChanged()
+ /**
+ * Called when we have been adopted, and the information of the
+ * node has been changed.
+ *
+ * The new document can be reached via OwnerDoc().
+ */
+ virtual void NodeInfoChanged(nsIDocument* aOldDoc)
{
}
/**
* Parse a string into an nsAttrValue for a CORS attribute. This
* never fails. The resulting value is an enumerated value whose
* GetEnumValue() returns one of the above constants.
*/
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -513,17 +513,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
if (aNode->IsElement()) {
Element* element = aNode->AsElement();
oldDoc->ClearBoxObjectFor(element);
wasRegistered = oldDoc->UnregisterActivityObserver(element);
}
aNode->mNodeInfo.swap(newNodeInfo);
if (elem) {
- elem->NodeInfoChanged();
+ elem->NodeInfoChanged(oldDoc);
}
nsIDocument* newDoc = aNode->OwnerDoc();
if (newDoc) {
// XXX what if oldDoc is null, we don't know if this should be
// registered or not! Can that really happen?
if (wasRegistered) {
newDoc->RegisterActivityObserver(aNode->AsElement());
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -705,17 +705,17 @@ HTMLImageElement::MaybeLoadImage()
EventStates
HTMLImageElement::IntrinsicState() const
{
return nsGenericHTMLElement::IntrinsicState() |
nsImageLoadingContent::ImageState();
}
void
-HTMLImageElement::NodeInfoChanged()
+HTMLImageElement::NodeInfoChanged(nsIDocument* aOldDoc)
{
// Resetting the last selected source if adoption steps are run.
mLastSelectedSource = nullptr;
}
// static
already_AddRefed<HTMLImageElement>
HTMLImageElement::Image(const GlobalObject& aGlobal,
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -89,17 +89,17 @@ public:
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual EventStates IntrinsicState() const override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
- virtual void NodeInfoChanged() override;
+ virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
nsresult CopyInnerTo(Element* aDest);
void MaybeLoadImage();
bool IsMap()
{
return GetBoolAttr(nsGkAtoms::ismap);
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2845,17 +2845,17 @@ nsGenericHTMLFormElementWithState::Resto
history->RemoveState(mStateKey);
return result;
}
return false;
}
void
-nsGenericHTMLFormElementWithState::NodeInfoChanged()
+nsGenericHTMLFormElementWithState::NodeInfoChanged(nsIDocument* aOldDoc)
{
mStateKey.SetIsVoid(true);
}
nsSize
nsGenericHTMLElement::GetWidthHeightForImage(RefPtr<imgRequestProxy>& aImageRequest)
{
nsSize size(0,0);
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -1394,17 +1394,17 @@ public:
* value of RestoreState() otherwise.
*/
bool RestoreFormControlState();
/**
* Called when we have been cloned and adopted, and the information of the
* node has been changed.
*/
- virtual void NodeInfoChanged() override;
+ virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
protected:
/* Generates the state key for saving the form state in the session if not
computed already. The result is stored in mStateKey on success */
nsresult GenerateStateKey();
/* Used to store the key to that element in the session. Is void until
GenerateStateKey has been used */
new file mode 100644
--- /dev/null
+++ b/dom/svg/crashtests/1329093-2.html
@@ -0,0 +1,28 @@
+<html class="reftest-wait">
+
+<head>
+</head>
+<body>
+
+Loading the below iframe should not crash Firefox in Stylo mode.
+<svg height="100" width="100" id="svgElement">
+ <circle cx="50" cy="50" r="40" stroke="yellow" stroke-width="2" fill="green"/>
+</svg>
+
+<iframe src="" id="myFrame"></iframe>
+<div style="display: none" id="triggerRestyle"></div>
+<script type="text/javascript">
+let frame = document.getElementById("myFrame");
+frame.onload = function() {
+ let baz = frame.contentDocument.adoptNode(document.getElementById("svgElement"));
+ frame.contentDocument.body.appendChild(baz);
+ baz = null;
+ frame.remove();
+ frame = null;
+ SpecialPowers.gc();
+ let color = getComputedStyle(document.getElementById('triggerRestyle')).color;
+ document.documentElement.className = "";
+}
+</script>
+</body>
+</html>
--- a/dom/svg/crashtests/crashtests.list
+++ b/dom/svg/crashtests/crashtests.list
@@ -84,8 +84,9 @@ load zero-size-image.svg
load 1322286.html
load 1329849-1.svg
load 1329849-2.svg
load 1329849-3.svg
load 1329849-4.svg
load 1329849-5.svg
load 1329849-6.svg
load 1329093-1.html
+load 1329093-2.html
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -902,16 +902,24 @@ nsSVGElement::GetAttributeChangeHint(con
}
bool
nsSVGElement::IsNodeOfType(uint32_t aFlags) const
{
return !(aFlags & ~eCONTENT);
}
+void
+nsSVGElement::NodeInfoChanged(nsIDocument* aOldDoc)
+{
+ aOldDoc->UnscheduleSVGForPresAttrEvaluation(this);
+ mContentDeclarationBlock = nullptr;
+ OwnerDoc()->ScheduleSVGForPresAttrEvaluation(this);
+}
+
NS_IMETHODIMP
nsSVGElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
{
#ifdef DEBUG
// printf("nsSVGElement(%p)::WalkContentStyleRules()\n", this);
#endif
if (!mContentDeclarationBlock) {
UpdateContentDeclarationBlock(StyleBackendType::Gecko);
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -109,16 +109,22 @@ public:
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify) override;
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
int32_t aModType) const override;
virtual bool IsNodeOfType(uint32_t aFlags) const override;
+ /**
+ * We override the default to unschedule computation of Servo declaration blocks
+ * when adopted across documents.
+ */
+ virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
+
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
void WalkAnimatedContentStyleRules(nsRuleWalker* aRuleWalker);
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
static const MappedAttributeEntry sFillStrokeMap[];
static const MappedAttributeEntry sGraphicsMap[];
static const MappedAttributeEntry sTextContentElementsMap[];