mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1577721 - Unify attribute cloning between XUL / HTML and everything else. r=bzbarsky
This contains an (intentional) behavior change, which is that we always copy (i.e. don't reparse) style attributes, even across documents. XUL and HTML already had this behavior. This makes stuff like SVG and MathML consistent with that. Depends on D44128 Differential Revision: https://phabricator.services.mozilla.com/D44129 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
58d9be367b
commit
c25009c80b
@ -3226,19 +3226,39 @@ nsDOMTokenList* Element::GetTokenList(
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult Element::CopyInnerTo(Element* aDst) {
|
nsresult Element::CopyInnerTo(Element* aDst, ReparseAttributes aReparse) {
|
||||||
nsresult rv = aDst->mAttrs.EnsureCapacityToClone(mAttrs);
|
nsresult rv = aDst->mAttrs.EnsureCapacityToClone(mAttrs);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
uint32_t i, count = mAttrs.AttrCount();
|
const bool reparse = aReparse == ReparseAttributes::Yes;
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
const nsAttrName* name = mAttrs.AttrNameAt(i);
|
uint32_t count = mAttrs.AttrCount();
|
||||||
const nsAttrValue* value = mAttrs.AttrAt(i);
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
BorrowedAttrInfo info = mAttrs.AttrInfoAt(i);
|
||||||
|
const nsAttrName* name = info.mName;
|
||||||
|
const nsAttrValue* value = info.mValue;
|
||||||
|
if (value->Type() == nsAttrValue::eCSSDeclaration) {
|
||||||
|
MOZ_ASSERT(name->Equals(nsGkAtoms::style, kNameSpaceID_None));
|
||||||
|
// We still clone CSS attributes, even in the `reparse` (cross-document)
|
||||||
|
// case. https://github.com/w3c/webappsec-csp/issues/212
|
||||||
|
nsAttrValue valueCopy(*value);
|
||||||
|
rv = aDst->SetParsedAttr(name->NamespaceID(), name->LocalName(),
|
||||||
|
name->GetPrefix(), valueCopy, false);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
value->GetCSSDeclarationValue()->SetImmutable();
|
||||||
|
} else if (reparse) {
|
||||||
nsAutoString valStr;
|
nsAutoString valStr;
|
||||||
value->ToString(valStr);
|
value->ToString(valStr);
|
||||||
rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
|
rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
|
||||||
name->GetPrefix(), valStr, false);
|
name->GetPrefix(), valStr, false);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
} else {
|
||||||
|
nsAttrValue valueCopy(*value);
|
||||||
|
rv = aDst->SetParsedAttr(name->NamespaceID(), name->LocalName(),
|
||||||
|
name->GetPrefix(), valueCopy, false);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -1910,11 +1910,13 @@ class Element : public FragmentOrElement {
|
|||||||
nsAtom* aAtom,
|
nsAtom* aAtom,
|
||||||
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
|
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
|
||||||
|
|
||||||
|
enum class ReparseAttributes { No, Yes };
|
||||||
/**
|
/**
|
||||||
* Copy attributes and state to another element
|
* Copy attributes and state to another element
|
||||||
* @param aDest the object to copy to
|
* @param aDest the object to copy to
|
||||||
*/
|
*/
|
||||||
nsresult CopyInnerTo(Element* aDest);
|
nsresult CopyInnerTo(Element* aDest,
|
||||||
|
ReparseAttributes = ReparseAttributes::Yes);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
@ -111,49 +111,9 @@ nsresult nsGenericHTMLElement::CopyInnerTo(Element* aDst) {
|
|||||||
MOZ_ASSERT(!aDst->GetUncomposedDoc(),
|
MOZ_ASSERT(!aDst->GetUncomposedDoc(),
|
||||||
"Should not CopyInnerTo an Element in a document");
|
"Should not CopyInnerTo an Element in a document");
|
||||||
|
|
||||||
bool reparse = (aDst->OwnerDoc() != OwnerDoc());
|
auto reparse = aDst->OwnerDoc() == OwnerDoc() ? ReparseAttributes::No
|
||||||
|
: ReparseAttributes::Yes;
|
||||||
nsresult rv =
|
return Element::CopyInnerTo(aDst, reparse);
|
||||||
static_cast<nsGenericHTMLElement*>(aDst)->mAttrs.EnsureCapacityToClone(
|
|
||||||
mAttrs);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
int32_t i, count = GetAttrCount();
|
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
const nsAttrName* name = mAttrs.AttrNameAt(i);
|
|
||||||
const nsAttrValue* value = mAttrs.AttrAt(i);
|
|
||||||
|
|
||||||
if (name->Equals(nsGkAtoms::style, kNameSpaceID_None) &&
|
|
||||||
value->Type() == nsAttrValue::eCSSDeclaration) {
|
|
||||||
// We still clone CSS attributes, even in the cross-document case.
|
|
||||||
// https://github.com/w3c/webappsec-csp/issues/212
|
|
||||||
|
|
||||||
// We can't just set this as a string, because that will fail
|
|
||||||
// to reparse the string into style data until the node is
|
|
||||||
// inserted into the document. Clone the Rule instead.
|
|
||||||
nsAttrValue valueCopy(*value);
|
|
||||||
rv = aDst->SetParsedAttr(name->NamespaceID(), name->LocalName(),
|
|
||||||
name->GetPrefix(), valueCopy, false);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
DeclarationBlock* cssDeclaration = value->GetCSSDeclarationValue();
|
|
||||||
cssDeclaration->SetImmutable();
|
|
||||||
} else if (reparse) {
|
|
||||||
nsAutoString valStr;
|
|
||||||
value->ToString(valStr);
|
|
||||||
|
|
||||||
rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
|
|
||||||
name->GetPrefix(), valStr, false);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
} else {
|
|
||||||
nsAttrValue valueCopy(*value);
|
|
||||||
rv = aDst->SetParsedAttr(name->NamespaceID(), name->LocalName(),
|
|
||||||
name->GetPrefix(), valueCopy, false);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const nsAttrValue::EnumTable kDirTable[] = {
|
static const nsAttrValue::EnumTable kDirTable[] = {
|
||||||
|
@ -307,60 +307,12 @@ nsresult nsXULElement::Clone(mozilla::dom::NodeInfo* aNodeInfo,
|
|||||||
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
|
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
|
||||||
RefPtr<nsXULElement> element = Construct(ni.forget());
|
RefPtr<nsXULElement> element = Construct(ni.forget());
|
||||||
|
|
||||||
nsresult rv = element->mAttrs.EnsureCapacityToClone(mAttrs);
|
nsresult rv = const_cast<nsXULElement*>(this)->CopyInnerTo(
|
||||||
|
element, ReparseAttributes::No);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Note that we're _not_ copying mControllers.
|
// Note that we're _not_ copying mControllers.
|
||||||
|
|
||||||
uint32_t count = mAttrs.AttrCount();
|
|
||||||
rv = NS_OK;
|
|
||||||
// FIXME(emilio): This setup looks somewhat error prone. Other than the
|
|
||||||
// AddListenerFor bit (what is that for?), everything else could be handled by
|
|
||||||
// the generic Element::CopyInnerTo, or the equivalent in
|
|
||||||
// nsGenericHTMLElement (somehow), both of which go through AfterSetAttr...
|
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
|
||||||
const nsAttrName* originalName = mAttrs.AttrNameAt(i);
|
|
||||||
const nsAttrValue* originalValue = mAttrs.AttrAt(i);
|
|
||||||
nsAttrValue attrValue;
|
|
||||||
|
|
||||||
// Style rules need to be cloned.
|
|
||||||
if (originalValue->Type() == nsAttrValue::eCSSDeclaration) {
|
|
||||||
DeclarationBlock* decl = originalValue->GetCSSDeclarationValue();
|
|
||||||
RefPtr<DeclarationBlock> declClone = decl->Clone();
|
|
||||||
|
|
||||||
nsString stringValue;
|
|
||||||
originalValue->ToString(stringValue);
|
|
||||||
|
|
||||||
attrValue.SetTo(declClone.forget(), &stringValue);
|
|
||||||
} else {
|
|
||||||
attrValue.SetTo(*originalValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool oldValueSet;
|
|
||||||
if (originalName->IsAtom()) {
|
|
||||||
rv = element->mAttrs.SetAndSwapAttr(originalName->Atom(), attrValue,
|
|
||||||
&oldValueSet);
|
|
||||||
} else {
|
|
||||||
rv = element->mAttrs.SetAndSwapAttr(originalName->NodeInfo(), attrValue,
|
|
||||||
&oldValueSet);
|
|
||||||
}
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
element->AddListenerFor(*originalName);
|
|
||||||
if (originalName->Equals(nsGkAtoms::id) &&
|
|
||||||
!originalValue->IsEmptyString()) {
|
|
||||||
element->SetHasID();
|
|
||||||
}
|
|
||||||
if (originalName->Equals(nsGkAtoms::_class)) {
|
|
||||||
element->SetMayHaveClass();
|
|
||||||
}
|
|
||||||
if (originalName->Equals(nsGkAtoms::style)) {
|
|
||||||
element->SetMayHaveStyle();
|
|
||||||
}
|
|
||||||
if (originalName->Equals(nsGkAtoms::part)) {
|
|
||||||
element->SetHasPartAttribute(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
element.forget(aResult);
|
element.forget(aResult);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,14 @@
|
|||||||
test(function() {
|
test(function() {
|
||||||
assert_equals(ops.id, clonedOps.id)
|
assert_equals(ops.id, clonedOps.id)
|
||||||
});
|
});
|
||||||
|
test(function() {
|
||||||
|
let el = document.getElementById("svg");
|
||||||
|
assert_equals(el.getAttribute("style"), "");
|
||||||
|
el.style.background = violetOps.style.background;
|
||||||
|
assert_not_equals(el.style.background, "");
|
||||||
|
let clone = el.cloneNode(true);
|
||||||
|
assert_equals(el.style.background, clone.style.background)
|
||||||
|
}, "non-HTML namespace");
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@ -131,6 +139,7 @@
|
|||||||
<div id="violetOps">
|
<div id="violetOps">
|
||||||
Yet another div.
|
Yet another div.
|
||||||
</div>
|
</div>
|
||||||
|
<svg id="svg" style="background: rgb(238, 130, 238)"></svg>
|
||||||
<div id="log"></div>
|
<div id="log"></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user