Bug 1525107 - Implement <meta name=color-scheme>. r=dholbert

There are still tests failing because
https://bugzilla.mozilla.org/show_bug.cgi?id=1736034 hasn't been synced
yet.

Once that lands, they will still fail because we don't change
Canvas/CanvasText based on color-scheme, but that I'm attaching
patches for after this one.

Differential Revision: https://phabricator.services.mozilla.com/D129743
This commit is contained in:
Emilio Cobos Álvarez 2021-10-29 19:58:24 +00:00
Родитель c5e7ceef0c
Коммит f85c48f96d
15 изменённых файлов: 108 добавлений и 56 удалений

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

@ -220,7 +220,6 @@
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/TreeOrderedArray.h"
#include "mozilla/dom/TreeOrderedArrayInlines.h"
#include "mozilla/dom/TreeWalker.h"
#include "mozilla/dom/URL.h"
@ -10768,6 +10767,45 @@ void Document::GetXMLDeclaration(nsAString& aVersion, nsAString& aEncoding,
}
}
void Document::AddColorSchemeMeta(HTMLMetaElement& aMeta) {
mColorSchemeMetaTags.Insert(aMeta);
RecomputeColorScheme();
}
void Document::RemoveColorSchemeMeta(HTMLMetaElement& aMeta) {
mColorSchemeMetaTags.RemoveElement(aMeta);
RecomputeColorScheme();
}
void Document::RecomputeColorScheme() {
if (!StaticPrefs::layout_css_color_scheme_enabled()) {
return;
}
auto oldColorScheme = mColorSchemeBits;
mColorSchemeBits = 0;
const nsTArray<HTMLMetaElement*>& elements = mColorSchemeMetaTags;
for (const HTMLMetaElement* el : elements) {
nsAutoString content;
if (!el->GetAttr(nsGkAtoms::content, content)) {
continue;
}
NS_ConvertUTF16toUTF8 contentU8(content);
if (Servo_ColorScheme_Parse(&contentU8, &mColorSchemeBits)) {
break;
}
}
if (mColorSchemeBits == oldColorScheme) {
return;
}
if (nsPresContext* pc = GetPresContext()) {
// This affects system colors, which are inherited, so we need to recascade.
pc->RebuildAllStyleData(nsChangeHint(0), RestyleHint::RecascadeSubtree());
}
}
bool Document::IsScriptEnabled() {
// If this document is sandboxed without 'allow-scripts'
// script is not enabled

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

@ -50,6 +50,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/dom/TreeOrderedArray.h"
#include "mozilla/dom/ViewportMetaData.h"
#include "nsAtom.h"
#include "nsCOMArray.h"
@ -2179,11 +2180,17 @@ class Document : public nsINode,
/**
* Returns the bits for the color-scheme specified by the
* <meta name="color-scheme">.
*
* TODO(emilio): Actually process the meta tag.
*/
uint8_t GetColorSchemeBits() const { return mColorSchemeBits; }
/**
* Traverses the DOM and computes the supported color schemes as per
* https://html.spec.whatwg.org/#meta-color-scheme
*/
void RecomputeColorScheme();
void AddColorSchemeMeta(HTMLMetaElement&);
void RemoveColorSchemeMeta(HTMLMetaElement&);
/**
* Returns true if this is what HTML 5 calls an "HTML document" (for example
* regular HTML document with Content-Type "text/html", image documents and
@ -5188,6 +5195,13 @@ class Document : public nsINode,
// element.
UniquePtr<ViewportMetaData> mLastModifiedViewportMetaData;
// A tree ordered list of all color-scheme meta tags in this document.
//
// TODO(emilio): There are other meta tags in the spec that have a similar
// processing model to color-scheme. We could store all in-document meta tags
// here to get sane and fast <meta> element processing.
TreeOrderedArray<HTMLMetaElement> mColorSchemeMetaTags;
// These member variables cache information about the viewport so we don't
// have to recalculate it each time.
LayoutDeviceToScreenScale mScaleMinFloat;

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

@ -43,15 +43,15 @@ nsresult HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
if (Document* document = GetUncomposedDoc()) {
if (aName == nsGkAtoms::content) {
if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
MetaAddedOrChanged(*document, *name, FromChange::Yes);
MetaAddedOrChanged(*document, *name, ChangeKind::ContentChange);
}
CreateAndDispatchEvent(*document, u"DOMMetaChanged"_ns);
} else if (aName == nsGkAtoms::name) {
if (aOldValue) {
MetaRemoved(*document, *aOldValue, FromChange::Yes);
MetaRemoved(*document, *aOldValue, ChangeKind::NameChange);
}
if (aValue) {
MetaAddedOrChanged(*document, *aValue, FromChange::Yes);
MetaAddedOrChanged(*document, *aValue, ChangeKind::NameChange);
}
CreateAndDispatchEvent(*document, u"DOMMetaChanged"_ns);
}
@ -113,7 +113,7 @@ nsresult HTMLMetaElement::BindToTree(BindContext& aContext, nsINode& aParent) {
}
if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
MetaAddedOrChanged(doc, *name, FromChange::No);
MetaAddedOrChanged(doc, *name, ChangeKind::TreeChange);
}
CreateAndDispatchEvent(doc, u"DOMMetaAdded"_ns);
return rv;
@ -122,7 +122,7 @@ nsresult HTMLMetaElement::BindToTree(BindContext& aContext, nsINode& aParent) {
void HTMLMetaElement::UnbindFromTree(bool aNullParent) {
if (Document* oldDoc = GetUncomposedDoc()) {
if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
MetaRemoved(*oldDoc, *name, FromChange::No);
MetaRemoved(*oldDoc, *name, ChangeKind::TreeChange);
}
CreateAndDispatchEvent(*oldDoc, u"DOMMetaRemoved"_ns);
}
@ -143,7 +143,7 @@ JSObject* HTMLMetaElement::WrapNode(JSContext* aCx,
void HTMLMetaElement::MetaAddedOrChanged(Document& aDoc,
const nsAttrValue& aName,
FromChange aFromChange) {
ChangeKind aChangeKind) {
nsAutoString content;
const bool hasContent = GetAttr(nsGkAtoms::content, content);
if (aName.Equals(nsGkAtoms::viewport, eIgnoreCase)) {
@ -159,12 +159,21 @@ void HTMLMetaElement::MetaAddedOrChanged(Document& aDoc,
return aDoc.UpdateReferrerInfoFromMeta(content,
/* aPreload = */ false);
}
if (aName.Equals(nsGkAtoms::color_scheme, eIgnoreCase)) {
if (aChangeKind != ChangeKind::ContentChange) {
return aDoc.AddColorSchemeMeta(*this);
}
return aDoc.RecomputeColorScheme();
}
}
void HTMLMetaElement::MetaRemoved(Document& aDoc, const nsAttrValue& aName,
FromChange aFromChange) {
// TODO(emilio): We probably want to deal with <meta name=color-scheme> and co
// here.
ChangeKind aChangeKind) {
MOZ_ASSERT(aChangeKind != ChangeKind::ContentChange,
"Content change can't trigger removal");
if (aName.Equals(nsGkAtoms::color_scheme, eIgnoreCase)) {
return aDoc.RemoveColorSchemeMeta(*this);
}
}
} // namespace mozilla::dom

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

@ -62,11 +62,11 @@ class HTMLMetaElement final : public nsGenericHTMLElement {
virtual ~HTMLMetaElement();
private:
enum class FromChange : bool { No, Yes };
enum class ChangeKind : uint8_t { TreeChange, NameChange, ContentChange };
void MetaRemoved(Document& aDoc, const nsAttrValue& aName,
FromChange aFromChange);
ChangeKind aChangeKind);
void MetaAddedOrChanged(Document& aDoc, const nsAttrValue& aName,
FromChange aFromChange);
ChangeKind aChangeKind);
};
} // namespace dom

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

@ -935,6 +935,11 @@ impl ColorScheme {
bits: ColorSchemeFlags::empty(),
}
}
/// Returns the raw bitfield.
pub fn raw_bits(&self) -> u8 {
self.bits.bits
}
}
impl Parse for ColorScheme {

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

@ -7214,3 +7214,27 @@ pub extern "C" fn Servo_GenericFontFamily_Parse(input: &nsACString) -> GenericFo
let mut input = Parser::new(&mut input);
GenericFontFamily::parse(&context, &mut input).unwrap_or(GenericFontFamily::None)
}
#[no_mangle]
pub extern "C" fn Servo_ColorScheme_Parse(input: &nsACString, out: &mut u8) -> bool {
use style::values::specified::ColorScheme;
let context = ParserContext::new(
Origin::Author,
unsafe { dummy_url_data() },
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
let input = unsafe { input.as_str_unchecked() };
let mut input = ParserInput::new(&input);
let mut input = Parser::new(&mut input);
let scheme = match input.parse_entirely(|i| ColorScheme::parse(&context, i)) {
Ok(scheme) => scheme,
Err(..) => return false,
};
*out = scheme.raw_bits();
true
}

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

@ -0,0 +1 @@
prefs: [layout.css.color-scheme.enabled:true]

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

@ -1,24 +1,9 @@
[meta-color-scheme-attribute-changes.html]
[Removed name attribute from meta color-scheme.]
expected: FAIL
[Set content attribute of meta color-scheme to empty string.]
expected: FAIL
[Set content attribute of meta color-scheme to 'light'.]
expected: FAIL
[Removed the content attribute of meta color-scheme.]
expected: FAIL
[Set meta name to color-scheme.]
expected: FAIL
[Meta color-scheme initially 'dark'.]
expected: FAIL
[Set content attribute of meta color-scheme to an invalid value.]
expected: FAIL
[Set content attribute of meta color-scheme to 'dark'.]
expected: FAIL

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

@ -1,4 +0,0 @@
[meta-color-scheme-empty-content-value.html]
[Meta color-scheme with empty content attribute has no effect.]
expected: FAIL

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

@ -4,7 +4,3 @@
[Inserted meta color-scheme before existing in head applies]
expected: FAIL
[Initial color-scheme]
expected: FAIL

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

@ -1,4 +0,0 @@
[meta-color-scheme-no-content-value.html]
[Meta color-scheme without content attribute has no effect.]
expected: FAIL

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

@ -1,7 +1,3 @@
[meta-color-scheme-remove-head.html]
[Initial value after removing head including meta color-scheme.]
expected: FAIL
[Meta color-scheme applies.]
expected: FAIL

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

@ -1,10 +1,6 @@
[meta-color-scheme-remove.html]
[Initial color-scheme with both meta elements removed.]
expected: FAIL
[Second meta applies after first one is removed.]
expected: FAIL
[First meta applies.]
expected: FAIL

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

@ -1,4 +0,0 @@
[meta-color-scheme-single-value-in-shadow-tree.html]
[Meta color-scheme in shadow tree does not apply.]
expected: FAIL

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

@ -251,8 +251,8 @@ STATIC_ATOMS = [
Atom("collapse", "collapse"),
Atom("collapsed", "collapsed"),
Atom("color", "color"),
Atom("colorIndex", "color-index"),
Atom("colorScheme", "color-scheme"),
Atom("color_index", "color-index"),
Atom("color_scheme", "color-scheme"),
Atom("cols", "cols"),
Atom("colspan", "colspan"),
Atom("combobox", "combobox"),