Bug 1735574 - Cleanup HTMLMetaElement handling of <meta name content>. r=smaug

This shouldn't change behavior, but I find it a bit easier to reason
about (and should be marginally faster by not doing double attribute
lookups, but not like the should usually matter).

Differential Revision: https://phabricator.services.mozilla.com/D128389
This commit is contained in:
Emilio Cobos Álvarez 2021-10-14 18:56:15 +00:00
Родитель 13f18064b3
Коммит 7e67655c8d
4 изменённых файлов: 66 добавлений и 73 удалений

Просмотреть файл

@ -10579,11 +10579,11 @@ ViewportMetaData Document::GetViewportMetaData() const {
: ViewportMetaData();
}
void Document::AddMetaViewportElement(HTMLMetaElement* aElement,
void Document::AddMetaViewportElement(HTMLMetaElement& aElement,
ViewportMetaData&& aData) {
for (size_t i = 0; i < mMetaViewports.Length(); i++) {
MetaViewportElementAndData& viewport = mMetaViewports[i];
if (viewport.mElement == aElement) {
if (viewport.mElement == &aElement) {
if (viewport.mData == aData) {
return;
}
@ -10594,7 +10594,7 @@ void Document::AddMetaViewportElement(HTMLMetaElement* aElement,
}
}
mMetaViewports.AppendElement(MetaViewportElementAndData{aElement, aData});
mMetaViewports.AppendElement(MetaViewportElementAndData{&aElement, aData});
// Trigger recomputation of the nsViewportInfo the next time it's queried.
mViewportType = Unknown;
@ -10604,9 +10604,9 @@ void Document::AddMetaViewportElement(HTMLMetaElement* aElement,
asyncDispatcher->RunDOMEventWhenSafe();
}
void Document::RemoveMetaViewportElement(HTMLMetaElement* aElement) {
void Document::RemoveMetaViewportElement(HTMLMetaElement& aElement) {
for (MetaViewportElementAndData& viewport : mMetaViewports) {
if (viewport.mElement == aElement) {
if (viewport.mElement == &aElement) {
mMetaViewports.RemoveElement(viewport);
// Trigger recomputation of the nsViewportInfo the next time it's queried.
mViewportType = Unknown;

Просмотреть файл

@ -1291,9 +1291,8 @@ class Document : public nsINode,
*/
nsViewportInfo GetViewportInfo(const ScreenIntSize& aDisplaySize);
void AddMetaViewportElement(HTMLMetaElement* aElement,
ViewportMetaData&& aData);
void RemoveMetaViewportElement(HTMLMetaElement* aElement);
void AddMetaViewportElement(HTMLMetaElement& aElement, ViewportMetaData&& aData);
void RemoveMetaViewportElement(HTMLMetaElement& aElement);
// Returns a ViewportMetaData for this document.
ViewportMetaData GetViewportMetaData() const;
@ -5177,6 +5176,10 @@ class Document : public nsINode,
struct MetaViewportElementAndData;
// An array of <meta name="viewport"> elements and their data.
//
// NOTE(emilio): We only need this array to deal with removal somewhat
// sanely. But other browsers don't do that and removal just seems to leave
// the last "viewport data" applying.
nsTArray<MetaViewportElementAndData> mMetaViewports;
// These member variables cache information about the viewport so we don't

Просмотреть файл

@ -34,42 +34,28 @@ HTMLMetaElement::~HTMLMetaElement() = default;
NS_IMPL_ELEMENT_CLONE(HTMLMetaElement)
void HTMLMetaElement::SetMetaReferrer(Document* aDocument) {
if (!aDocument || !AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
nsGkAtoms::referrer, eIgnoreCase)) {
return;
}
nsAutoString content;
GetContent(content);
content =
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(content);
aDocument->UpdateReferrerInfoFromMeta(content, false);
}
nsresult HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
const nsAttrValue* aValue,
const nsAttrValue* aOldValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) {
if (aNameSpaceID == kNameSpaceID_None) {
Document* document = GetUncomposedDoc();
if (aName == nsGkAtoms::content) {
if (document && AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
nsGkAtoms::viewport, eIgnoreCase)) {
ProcessViewportContent(document);
if (Document* document = GetUncomposedDoc()) {
if (aName == nsGkAtoms::content) {
if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
MetaAddedOrChanged(*document, *name, FromChange::Yes);
}
CreateAndDispatchEvent(*document, u"DOMMetaChanged"_ns);
} else if (aName == nsGkAtoms::name) {
if (aOldValue) {
MetaRemoved(*document, *aOldValue, FromChange::Yes);
}
if (aValue) {
MetaAddedOrChanged(*document, *aValue, FromChange::Yes);
}
CreateAndDispatchEvent(*document, u"DOMMetaChanged"_ns);
}
CreateAndDispatchEvent(document, u"DOMMetaChanged"_ns);
} else if (document && aName == nsGkAtoms::name) {
if (aValue && aValue->Equals(nsGkAtoms::viewport, eIgnoreCase)) {
ProcessViewportContent(document);
} else if (aOldValue &&
aOldValue->Equals(nsGkAtoms::viewport, eIgnoreCase)) {
DiscardViewportContent(document);
}
CreateAndDispatchEvent(document, u"DOMMetaChanged"_ns);
}
// Update referrer policy when it got changed from JS
SetMetaReferrer(document);
}
return nsGenericHTMLElement::AfterSetAttr(
@ -101,11 +87,6 @@ nsresult HTMLMetaElement::BindToTree(BindContext& aContext, nsINode& aParent) {
doc.ProcessMETATag(this);
}
if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::viewport,
eIgnoreCase)) {
ProcessViewportContent(&doc);
}
if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::httpEquiv, nsGkAtoms::headerCSP,
eIgnoreCase)) {
// only accept <meta http-equiv="Content-Security-Policy" content=""> if it
@ -131,25 +112,25 @@ nsresult HTMLMetaElement::BindToTree(BindContext& aContext, nsINode& aParent) {
}
}
SetMetaReferrer(&doc);
CreateAndDispatchEvent(&doc, u"DOMMetaAdded"_ns);
if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
MetaAddedOrChanged(doc, *name, FromChange::No);
}
CreateAndDispatchEvent(doc, u"DOMMetaAdded"_ns);
return rv;
}
void HTMLMetaElement::UnbindFromTree(bool aNullParent) {
nsCOMPtr<Document> oldDoc = GetUncomposedDoc();
if (oldDoc && AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
nsGkAtoms::viewport, eIgnoreCase)) {
DiscardViewportContent(oldDoc);
if (Document* oldDoc = GetUncomposedDoc()) {
if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
MetaRemoved(*oldDoc, *name, FromChange::No);
}
CreateAndDispatchEvent(*oldDoc, u"DOMMetaRemoved"_ns);
}
CreateAndDispatchEvent(oldDoc, u"DOMMetaRemoved"_ns);
nsGenericHTMLElement::UnbindFromTree(aNullParent);
}
void HTMLMetaElement::CreateAndDispatchEvent(Document* aDoc,
void HTMLMetaElement::CreateAndDispatchEvent(Document&,
const nsAString& aEventName) {
if (!aDoc) return;
RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
this, aEventName, CanBubble::eYes, ChromeOnlyDispatch::eYes);
asyncDispatcher->RunDOMEventWhenSafe();
@ -160,29 +141,36 @@ JSObject* HTMLMetaElement::WrapNode(JSContext* aCx,
return HTMLMetaElement_Binding::Wrap(aCx, this, aGivenProto);
}
void HTMLMetaElement::ProcessViewportContent(Document* aDocument) {
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::content)) {
// Call Document::RemoveMetaViewportElement for cases that the content
// attribute is removed.
// NOTE: RemoveMetaViewportElement enumerates all existing meta viewport
// tags in the case where this element hasn't been there, i.e. this element
// is newly added to the document, but it should be fine because a document
// unlikely has a bunch of meta viewport tags.
aDocument->RemoveMetaViewportElement(this);
void HTMLMetaElement::MetaAddedOrChanged(Document& aDoc,
const nsAttrValue& aName,
FromChange aFromChange) {
nsAutoString content;
const bool hasContent = GetAttr(nsGkAtoms::content, content);
if (aName.Equals(nsGkAtoms::viewport, eIgnoreCase)) {
if (hasContent) {
aDoc.SetHeaderData(nsGkAtoms::viewport, content);
aDoc.AddMetaViewportElement(*this, ViewportMetaData(content));
} else if (aFromChange == FromChange::Yes) {
aDoc.RemoveMetaViewportElement(*this);
}
return;
}
nsAutoString content;
GetContent(content);
aDocument->SetHeaderData(nsGkAtoms::viewport, content);
ViewportMetaData data(content);
aDocument->AddMetaViewportElement(this, std::move(data));
if (aName.Equals(nsGkAtoms::referrer, eIgnoreCase)) {
content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
content);
return aDoc.UpdateReferrerInfoFromMeta(content,
/* aPreload = */ false);
}
}
void HTMLMetaElement::DiscardViewportContent(Document* aDocument) {
aDocument->RemoveMetaViewportElement(this);
void HTMLMetaElement::MetaRemoved(Document& aDoc, const nsAttrValue& aName,
FromChange aFromChange) {
if (aName.Equals(nsGkAtoms::viewport, eIgnoreCase)) {
return aDoc.RemoveMetaViewportElement(*this);
}
// FIXME: referrer doesn't do anything on removal or when its name changes to
// something else?
}
} // namespace mozilla::dom

Просмотреть файл

@ -30,7 +30,7 @@ class HTMLMetaElement final : public nsGenericHTMLElement {
nsIPrincipal* aSubjectPrincipal,
bool aNotify) override;
void CreateAndDispatchEvent(Document* aDoc, const nsAString& aEventName);
void CreateAndDispatchEvent(Document&, const nsAString& aEventName);
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
@ -62,9 +62,11 @@ class HTMLMetaElement final : public nsGenericHTMLElement {
virtual ~HTMLMetaElement();
private:
void SetMetaReferrer(Document* aDocument);
void ProcessViewportContent(Document* aDocument);
void DiscardViewportContent(Document* aDocument);
enum class FromChange : bool { No, Yes };
void MetaRemoved(Document& aDoc, const nsAttrValue& aName,
FromChange aFromChange);
void MetaAddedOrChanged(Document& aDoc, const nsAttrValue& aName,
FromChange aFromChange);
};
} // namespace dom