Bug 1367312 - stylo: Implement :-moz-lwtheme* pseudo-classes. r?emilio
MozReview-Commit-ID: 8ARU4iVDNtY
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2402,17 +2402,18 @@ public:
void SetStateObject(nsIStructuredCloneContainer *scContainer);
/**
* Returns Doc_Theme_None if there is no lightweight theme specified,
* Doc_Theme_Dark for a dark theme, Doc_Theme_Bright for a light theme, and
* Doc_Theme_Neutral for any other theme. This is used to determine the state
* of the pseudoclasses :-moz-lwtheme and :-moz-lwtheme-text.
*/
- virtual int GetDocumentLWTheme() { return Doc_Theme_None; }
+ virtual DocumentTheme GetDocumentLWTheme() { return Doc_Theme_None; }
+ virtual DocumentTheme ThreadSafeGetDocumentLWTheme() const { return Doc_Theme_None; }
/**
* Returns the document state.
* Document state bits have the form NS_DOCUMENT_STATE_* and are declared in
* nsIDocument.h.
*/
virtual mozilla::EventStates GetDocumentState() = 0;
virtual mozilla::EventStates ThreadSafeGetDocumentState() const = 0;
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -4549,40 +4549,50 @@ XULDocument::DirectionChanged(const char
{
// Reset the direction and restyle the document if necessary.
XULDocument* doc = (XULDocument *)aData;
if (doc) {
doc->ResetDocumentDirection();
}
}
-int
+nsIDocument::DocumentTheme
XULDocument::GetDocumentLWTheme()
{
if (mDocLWTheme == Doc_Theme_Uninitialized) {
- mDocLWTheme = Doc_Theme_None; // No lightweight theme by default
+ mDocLWTheme = ThreadSafeGetDocumentLWTheme();
+ }
+ return mDocLWTheme;
+}
+
+nsIDocument::DocumentTheme
+XULDocument::ThreadSafeGetDocumentLWTheme() const
+{
+ DocumentTheme theme = mDocLWTheme;
+ if (theme == Doc_Theme_Uninitialized) {
+ theme = Doc_Theme_None; // No lightweight theme by default
Element* element = GetRootElement();
nsAutoString hasLWTheme;
if (element &&
element->GetAttr(kNameSpaceID_None, nsGkAtoms::lwtheme, hasLWTheme) &&
!(hasLWTheme.IsEmpty()) &&
hasLWTheme.EqualsLiteral("true")) {
- mDocLWTheme = Doc_Theme_Neutral;
+ theme = Doc_Theme_Neutral;
nsAutoString lwTheme;
element->GetAttr(kNameSpaceID_None, nsGkAtoms::lwthemetextcolor, lwTheme);
if (!(lwTheme.IsEmpty())) {
if (lwTheme.EqualsLiteral("dark"))
- mDocLWTheme = Doc_Theme_Dark;
+ theme = Doc_Theme_Dark;
else if (lwTheme.EqualsLiteral("bright"))
- mDocLWTheme = Doc_Theme_Bright;
+ theme = Doc_Theme_Bright;
}
}
}
- return mDocLWTheme;
+ return theme;
}
NS_IMETHODIMP
XULDocument::GetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject** aResult)
{
ErrorResult rv;
nsCOMPtr<Element> el = do_QueryInterface(aElement);
*aResult = GetBoxObjectFor(el, rv).take();
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -168,17 +168,18 @@ public:
nsresult aStatus) override;
virtual void EndUpdate(nsUpdateType aUpdateType) override;
virtual bool IsDocumentRightToLeft() override;
virtual void ResetDocumentDirection() override;
- virtual int GetDocumentLWTheme() override;
+ virtual nsIDocument::DocumentTheme GetDocumentLWTheme() override;
+ virtual nsIDocument::DocumentTheme ThreadSafeGetDocumentLWTheme() const override;
virtual void ResetDocumentLWTheme() override { mDocLWTheme = Doc_Theme_Uninitialized; }
NS_IMETHOD OnScriptCompileComplete(JSScript* aScript, nsresult aStatus) override;
static bool
MatchAttribute(Element* aContent,
int32_t aNameSpaceID,
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -814,16 +814,21 @@ Gecko_GetXMLLangValue(RawGeckoElementBor
}
MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
nsCOMPtr<nsIAtom> atom = attr->GetAtomValue();
return atom.forget().take();
}
+int
+Gecko_GetDocumentLWTheme(const nsIDocument *aDocument) {
+ return aDocument->ThreadSafeGetDocumentLWTheme();
+}
+
template <typename Implementor>
static nsIAtom*
AtomAttrValue(Implementor* aElement, nsIAtom* aName)
{
const nsAttrValue* attr = aElement->GetParsedAttr(aName);
return attr ? attr->GetAtomValue() : nullptr;
}
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -24,16 +24,17 @@
* API for Servo to access Gecko data structures. This file must compile as valid
* C code in order for the binding generator to parse it.
*
* Functions beginning with Gecko_ are implemented in Gecko and invoked from Servo.
* Functions beginning with Servo_ are implemented in Servo and invoked from Gecko.
*/
class nsIAtom;
+class nsIDocument;
class nsIPrincipal;
class nsIURI;
struct nsFont;
namespace mozilla {
class FontFamilyList;
enum FontFamilyType : uint32_t;
enum class CSSPseudoElementType : uint8_t;
struct Keyframe;
@@ -159,16 +160,17 @@ bool Gecko_IsRootElement(RawGeckoElement
bool Gecko_MatchesElement(mozilla::CSSPseudoClassType type, RawGeckoElementBorrowed element);
nsIAtom* Gecko_LocalName(RawGeckoElementBorrowed element);
nsIAtom* Gecko_Namespace(RawGeckoElementBorrowed element);
nsIAtom* Gecko_GetElementId(RawGeckoElementBorrowed element);
bool Gecko_MatchLang(RawGeckoElementBorrowed element,
nsIAtom* override_lang, bool has_override_lang,
const char16_t* value);
nsIAtom* Gecko_GetXMLLangValue(RawGeckoElementBorrowed element);
+int Gecko_GetDocumentLWTheme(const nsIDocument *aDocument);
// Attributes.
#define SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
nsIAtom* prefix_##AtomAttrValue(implementor_ element, nsIAtom* attribute); \
nsIAtom* prefix_##LangValue(implementor_ element); \
bool prefix_##HasAttr(implementor_ element, nsIAtom* ns, nsIAtom* name); \
bool prefix_##AttrEquals(implementor_ element, nsIAtom* ns, nsIAtom* name, \
nsIAtom* str, bool ignoreCase); \
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -325,16 +325,17 @@ raw-lines = [
whitelist-functions = ["Servo_.*", "Gecko_.*"]
structs-types = [
"mozilla::css::GridTemplateAreasValue",
"mozilla::css::ImageValue",
"mozilla::css::URLValue",
"mozilla::MallocSizeOf",
"mozilla::Side",
"nsIContent",
+ "nsIDocument",
"RawGeckoAnimationPropertySegment",
"RawGeckoComputedTiming",
"RawGeckoCSSPropertyIDList",
"RawGeckoDocument",
"RawGeckoElement",
"RawGeckoKeyframeList",
"RawGeckoComputedKeyframeValuesList",
"RawGeckoFontFaceRuleList",
--- a/layout/style/test/stylo-failures.md
+++ b/layout/style/test/stylo-failures.md
@@ -82,18 +82,16 @@ to mochitest command.
* serialize subprops to -moz-use-system-font when using system font bug 1364289
* test_value_storage.html `'font'` [224]
* different serialization for gradient functions in computed value bug 1367274
* test_computed_style.html `gradient` [13]
* Unsupported pseudo-elements or anon boxes
* :-moz-tree bits bug 1348488
* test_selectors.html `:-moz-tree` [10]
* Unsupported pseudo-classes
- * :-moz-lwtheme-* bug 1367312
- * test_selectors.html `:-moz-lwtheme` [3]
* :-moz-window-inactive bug 1348489
* test_selectors.html `:-moz-window-inactive` [2]
* Unit should be preserved after parsing servo/servo#15346
* test_units_time.html [1]
* getComputedStyle style doesn't contain custom properties bug 1336891
* test_variables.html `custom property name` [2]
* test_css_supports.html: issues around @supports syntax servo/servo#15482 [2]
* test_author_specified_style.html: support serializing color as author specified bug 1348165 [27]
--- a/servo/components/style/gecko/non_ts_pseudo_class_list.rs
+++ b/servo/components/style/gecko/non_ts_pseudo_class_list.rs
@@ -21,17 +21,16 @@
* apply_non_ts_list!(pseudo_class_macro)
* ```
*
* The `string` and `keyword` variables will be applied to pseudoclasses that are of the form of
* functions with string or keyword arguments.
*
* Pending pseudo-classes:
*
- * :-moz-lwtheme, :-moz-lwtheme-brighttext, :-moz-lwtheme-darktext,
* :-moz-window-inactive.
*
* :scope -> <style scoped>, pending discussion.
*
* This follows the order defined in layout/style/nsCSSPseudoClassList.h when
* possible.
*
* $gecko_type can be either "_" or an ident in Gecko's CSSPseudoClassType.
@@ -109,16 +108,19 @@ macro_rules! apply_non_ts_list {
("-moz-first-node", MozFirstNode, firstNode, _, _),
("-moz-last-node", MozLastNode, lastNode, _, _),
("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),
("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_INTERNAL),
("-moz-use-shadow-tree-root", MozUseShadowTreeRoot, mozUseShadowTreeRoot, _, PSEUDO_CLASS_INTERNAL),
("-moz-is-html", MozIsHTML, mozIsHTML, _, _),
("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _),
+ ("-moz-lwtheme", MozLWTheme, mozLWTheme, _, _),
+ ("-moz-lwtheme-brighttext", MozLWThemeBrightText, mozLWThemeBrightText, _, _),
+ ("-moz-lwtheme-darktext", MozLWThemeDarktext, mozLWThemeDarkText, _, _),
],
string: [
("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL),
("-moz-empty-except-children-with-localname", MozEmptyExceptChildrenWithLocalname,
mozEmptyExceptChildrenWithLocalname, _, PSEUDO_CLASS_INTERNAL),
("lang", Lang, lang, _, _),
],
keyword: [
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -26,17 +26,18 @@ use element_state::ElementState;
use error_reporting::create_error_reporter;
use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
use gecko::data::PerDocumentStyleData;
use gecko::global_style_data::GLOBAL_STYLE_DATA;
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
use gecko::snapshot_helpers;
use gecko_bindings::bindings;
use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
-use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetLastChild, Gecko_GetNextStyleChild};
+use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWTheme};
+use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetNextStyleChild};
use gecko_bindings::bindings::{Gecko_IsRootElement, Gecko_MatchesElement, Gecko_Namespace};
use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_ElementHasAnimations;
use gecko_bindings::bindings::Gecko_ElementHasCSSAnimations;
use gecko_bindings::bindings::Gecko_ElementHasCSSTransitions;
use gecko_bindings::bindings::Gecko_GetActiveLinkAttrDeclarationBlock;
use gecko_bindings::bindings::Gecko_GetAnimationRule;
@@ -57,16 +58,17 @@ use gecko_bindings::structs::{RawGeckoEl
use gecko_bindings::structs::{nsIAtom, nsIContent, nsINode_BooleanFlag, nsStyleContext};
use gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
use gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
use gecko_bindings::structs::ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
use gecko_bindings::structs::ELEMENT_HAS_SNAPSHOT;
use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
+use gecko_bindings::structs::nsIDocument_DocumentTheme as DocumentTheme;
use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
use logical_geometry::WritingMode;
use media_queries::Device;
use properties::{ComputedValues, parse_style_attribute};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::animated_properties::{AnimatableLonghand, AnimationValue, AnimationValueMap};
use properties::animated_properties::TransitionProperty;
use properties::style_structs::Font;
@@ -80,16 +82,17 @@ use selectors::sink::Push;
use shared_lock::Locked;
use smallvec::VecLike;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::DerefMut;
+use std::os::raw::c_int;
use std::ptr;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use stylearc::Arc;
use stylesheets::UrlExtraData;
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
///
/// Important: We don't currently refcount the DOM, because the wrapper lifetime
@@ -581,16 +584,22 @@ impl<'le> GeckoElement<'le> {
.map(GeckoElement)
}
}
#[inline]
fn may_have_style_attribute(&self) -> bool {
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveStyle)
}
+
+ #[inline]
+ fn get_document_theme(&self) -> c_int {
+ let node = self.as_node();
+ unsafe { Gecko_GetDocumentLWTheme(node.owner_doc()) }
+ }
}
/// Converts flags from the layout used by rust-selectors to the layout used
/// by Gecko. We could align these and then do this without conditionals, but
/// it's probably not worth the trouble.
fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
use gecko_bindings::structs::*;
use selectors::matching::*;
@@ -1654,16 +1663,25 @@ impl<'le> ::selectors::Element for Gecko
NonTSPseudoClass::MozBrowserFrame |
NonTSPseudoClass::MozNativeAnonymous |
NonTSPseudoClass::MozUseShadowTreeRoot => unsafe {
Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0)
},
NonTSPseudoClass::MozIsHTML => {
self.is_html_element_in_html_document()
}
+ NonTSPseudoClass::MozLWTheme => {
+ self.get_document_theme() != DocumentTheme::Doc_Theme_None as c_int
+ }
+ NonTSPseudoClass::MozLWThemeBrightText => {
+ self.get_document_theme() == DocumentTheme::Doc_Theme_Bright as c_int
+ }
+ NonTSPseudoClass::MozLWThemeDarktext => {
+ self.get_document_theme() == DocumentTheme::Doc_Theme_Dark as c_int
+ }
NonTSPseudoClass::MozPlaceholder => false,
NonTSPseudoClass::MozAny(ref sels) => {
let old_value = context.hover_active_quirk_disabled;
context.hover_active_quirk_disabled = true;
let result = sels.iter().any(|s| {
matches_complex_selector(s.iter(), self, context, flags_setter)
});
context.hover_active_quirk_disabled = old_value;