Bug 1203973 - Move <style> and <link> attribute change handling to AfterSetAttr so that it doesn't trigger for no-op attribute changes. r=smaug

This commit is contained in:
Boris Zbarsky 2015-09-22 21:19:49 -04:00
parent 6189b4fd76
commit 5f821e4cf5
4 changed files with 72 additions and 125 deletions

View File

@ -326,96 +326,77 @@ HTMLLinkElement::UpdatePreconnect()
}
nsresult
HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify)
HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
{
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
aValue, aNotify);
// The ordering of the parent class's SetAttr call and Link::ResetLinkState
// is important here! The attribute is not set until SetAttr returns, and
// we will need the updated attribute value because notifying the document
// that content states have changed will call IntrinsicState, which will try
// to get updated information about the visitedness from Link.
// It's safe to call ResetLinkState here because our new attr value has
// already been set or unset. ResetLinkState needs the updated attribute
// value because notifying the document that content states have changed will
// call IntrinsicState, which will try to get updated information about the
// visitedness from Link.
if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
Link::ResetLinkState(!!aNotify, true);
bool hasHref = aValue;
Link::ResetLinkState(!!aNotify, hasHref);
if (IsInUncomposedDoc()) {
CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
}
}
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None &&
(aName == nsGkAtoms::href ||
aName == nsGkAtoms::rel ||
aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type)) {
bool dropSheet = false;
if (aName == nsGkAtoms::rel) {
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(aValue,
NodePrincipal());
if (GetSheet()) {
dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
} else if (linkTypes & eHTMLIMPORT) {
if (aValue) {
if (aNameSpaceID == kNameSpaceID_None &&
(aName == nsGkAtoms::href ||
aName == nsGkAtoms::rel ||
aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type)) {
bool dropSheet = false;
if (aName == nsGkAtoms::rel) {
nsAutoString value;
aValue->ToString(value);
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(value,
NodePrincipal());
if (GetSheet()) {
dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
} else if (linkTypes & eHTMLIMPORT) {
UpdateImport();
} else if ((linkTypes & ePRECONNECT) && IsInComposedDoc()) {
UpdatePreconnect();
}
}
if (aName == nsGkAtoms::href) {
UpdateImport();
if (IsInComposedDoc()) {
UpdatePreconnect();
}
}
UpdateStyleSheetInternal(nullptr, nullptr,
dropSheet ||
(aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type));
}
} else {
// Since removing href or rel makes us no longer link to a
// stylesheet, force updates for those too.
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::href ||
aName == nsGkAtoms::rel ||
aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
}
if (aName == nsGkAtoms::href ||
aName == nsGkAtoms::rel) {
UpdateImport();
} else if ((linkTypes & ePRECONNECT) && IsInComposedDoc()) {
UpdatePreconnect();
}
}
if (aName == nsGkAtoms::href) {
UpdateImport();
if (IsInComposedDoc()) {
UpdatePreconnect();
}
}
UpdateStyleSheetInternal(nullptr, nullptr,
dropSheet ||
(aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type));
}
return rv;
}
nsresult
HTMLLinkElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify)
{
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
aNotify);
// Since removing href or rel makes us no longer link to a
// stylesheet, force updates for those too.
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::href ||
aAttribute == nsGkAtoms::rel ||
aAttribute == nsGkAtoms::title ||
aAttribute == nsGkAtoms::media ||
aAttribute == nsGkAtoms::type) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
}
if (aAttribute == nsGkAtoms::href ||
aAttribute == nsGkAtoms::rel) {
UpdateImport();
}
}
// The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
// is important here! The attribute is not unset until UnsetAttr returns, and
// we will need the updated attribute value because notifying the document
// that content states have changed will call IntrinsicState, which will try
// to get updated information about the visitedness from Link.
if (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
Link::ResetLinkState(!!aNotify, false);
if (IsInUncomposedDoc()) {
CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
}
}
return rv;
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
aNotify);
}
nsresult

View File

@ -61,16 +61,9 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
}
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify) override;
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
bool aNotify) override;
virtual bool IsLink(nsIURI** aURI) const override;
virtual already_AddRefed<nsIURI> GetHrefURI() const override;

View File

@ -172,42 +172,22 @@ HTMLStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
nsresult
HTMLStyleElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify)
HTMLStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
{
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
aValue, aNotify);
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None) {
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
} else if (aName == nsGkAtoms::scoped) {
UpdateStyleSheetScopedness(true);
bool isScoped = aValue;
UpdateStyleSheetScopedness(isScoped);
}
}
return rv;
}
nsresult
HTMLStyleElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify)
{
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
aNotify);
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::title ||
aAttribute == nsGkAtoms::media ||
aAttribute == nsGkAtoms::type) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
} else if (aAttribute == nsGkAtoms::scoped) {
UpdateStyleSheetScopedness(false);
}
}
return rv;
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
aNotify);
}
NS_IMETHODIMP

View File

@ -46,16 +46,9 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
}
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify) override;
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;