Bug 1348489 - stylo: Implement :-moz-window-inactive. r?emilio draft
authorMatt Brubeck <mbrubeck@mozilla.com>
Wed, 28 Jun 2017 13:09:32 -0700
changeset 602042 a79a9345253de8bc6a80dd6a28ee172b4e0eeef2
parent 602041 08465078f3c2cb4a7baf310cb4ed39de07fcd4f3
child 635436 27e33f836ab0ccbca99f666f8f856b0a8d3b76bf
push id66251
push userbmo:mbrubeck@mozilla.com
push dateThu, 29 Jun 2017 14:48:51 +0000
reviewersemilio
bugs1348489
milestone56.0a1
Bug 1348489 - stylo: Implement :-moz-window-inactive. r?emilio MozReview-Commit-ID: Ga68eqQQoxN
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/test/stylo-failures.md
servo/components/style/element_state.rs
servo/components/style/gecko/non_ts_pseudo_class_list.rs
servo/components/style/gecko/wrapper.rs
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -819,16 +819,21 @@ Gecko_GetXMLLangValue(RawGeckoElementBor
 }
 
 nsIDocument::DocumentTheme
 Gecko_GetDocumentLWTheme(const nsIDocument *aDocument)
 {
   return aDocument->ThreadSafeGetDocumentLWTheme();
 }
 
+mozilla::EventStates
+Gecko_GetDocumentState(const nsIDocument *aDocument) {
+  return aDocument->ThreadSafeGetDocumentState();
+}
+
 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
@@ -11,16 +11,17 @@
 
 #include "mozilla/ServoTypes.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/ServoElementSnapshot.h"
 #include "mozilla/css/SheetParsingMode.h"
 #include "mozilla/css/URLMatchingFunction.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/ComputedTimingFunction.h"
+#include "mozilla/EventStates.h"
 #include "nsChangeHint.h"
 #include "nsCSSPseudoClasses.h"
 #include "nsIDocument.h"
 #include "nsStyleStruct.h"
 
 /*
  * 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.
@@ -160,16 +161,17 @@ bool Gecko_MatchesElement(mozilla::CSSPs
 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);
 nsIDocument::DocumentTheme Gecko_GetDocumentLWTheme(const nsIDocument *aDocument);
+mozilla::EventStates Gecko_GetDocumentState(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
@@ -445,16 +445,17 @@ structs-types = [
     "EffectCompositor_CascadeLevel",
     "UpdateAnimationsTasks",
     "ParsingMode",
     "InheritTarget",
     "URLMatchingFunction",
     "StyleRuleInclusion",
     "nsStyleTransformMatrix::MatrixTransformOperator",
     "RawGeckoGfxMatrix4x4",
+    "EventStates",
 ]
 array-types = [
     { cpp-type = "uintptr_t", rust-type = "usize" },
 ]
 servo-owned-types = [
     { name = "RawServoStyleSet", opaque = true },
     { name = "ServoElementSnapshot", opaque = false },
     { name = "RawServoAnimationValueMap", opaque = true },
--- a/layout/style/test/stylo-failures.md
+++ b/layout/style/test/stylo-failures.md
@@ -79,19 +79,16 @@ to mochitest command.
     * test_system_font_serialization.html [3]
   * 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-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]
 * browser_newtab_share_rule_processors.js: agent style sheet sharing [1]
 * :visited support (bug 1328509)
--- a/servo/components/style/element_state.rs
+++ b/servo/components/style/element_state.rs
@@ -133,8 +133,21 @@ bitflags! {
         /// case-insensitively equal to "auto") are in.
         const IN_HAS_DIR_ATTR_LIKE_AUTO_STATE = 1 << 49,
         /// Non-standard & undocumented.
         const IN_AUTOFILL_STATE = 1 << 50,
         /// Non-standard & undocumented.
         const IN_AUTOFILL_PREVIEW_STATE = 1 << 51,
     }
 }
+
+bitflags! {
+    /// Event-based document states.
+    ///
+    /// NB: Is important for this to remain in sync with Gecko's
+    /// dom/base/nsIDocument.h.
+    pub flags DocumentState: u64 {
+        /// RTL locale: specific to the XUL localedir attribute
+        const NS_DOCUMENT_STATE_RTL_LOCALE = 1 << 0,
+        /// Window activation status
+        const NS_DOCUMENT_STATE_WINDOW_INACTIVE = 1 << 1,
+    }
+}
--- a/servo/components/style/gecko/non_ts_pseudo_class_list.rs
+++ b/servo/components/style/gecko/non_ts_pseudo_class_list.rs
@@ -21,18 +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-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.
  * $state can be either "_" or an expression of type ElementState.  If present,
  *        the semantics are that the pseudo-class matches if any of the bits in
@@ -111,16 +109,17 @@ macro_rules! apply_non_ts_list {
                 ("-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, _, _),
+                ("-moz-window-inactive", MozWindowInactive, mozWindowInactive, _, _),
             ],
             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
@@ -17,26 +17,26 @@
 use CaseSensitivityExt;
 use app_units::Au;
 use applicable_declarations::ApplicableDeclarationBlock;
 use atomic_refcell::AtomicRefCell;
 use context::{QuirksMode, SharedStyleContext, UpdateAnimationsTasks};
 use data::ElementData;
 use dom::{self, DescendantsBit, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode};
 use dom::{OpaqueNode, PresentationalHintsSynthesizer};
-use element_state::ElementState;
+use element_state::{ElementState, DocumentState, NS_DOCUMENT_STATE_WINDOW_INACTIVE};
 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_ConstructStyleChildrenIterator, Gecko_DestroyStyleChildrenIterator};
-use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWTheme};
+use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWTheme, Gecko_GetDocumentState};
 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;
@@ -647,16 +647,24 @@ impl<'le> GeckoElement<'le> {
     #[inline]
     fn get_state_internal(&self) -> u64 {
         if !self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasLockedStyleStates) {
             return self.0.mState.mStates;
         }
         unsafe { Gecko_ElementState(self.0) }
     }
 
+    fn document_state(&self) -> DocumentState {
+        let node = self.as_node();
+        unsafe {
+            let states = Gecko_GetDocumentState(node.owner_doc());
+            DocumentState::from_bits_truncate(states.mStates)
+        }
+    }
+
     #[inline]
     fn may_have_class(&self) -> bool {
         self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveClass)
     }
 
     #[inline]
     fn has_properties(&self) -> bool {
         use gecko_bindings::structs::NODE_HAS_PROPERTIES;
@@ -1753,16 +1761,19 @@ impl<'le> ::selectors::Element for Gecko
                 self.get_document_theme() != DocumentTheme::Doc_Theme_None
             }
             NonTSPseudoClass::MozLWThemeBrightText => {
                 self.get_document_theme() == DocumentTheme::Doc_Theme_Bright
             }
             NonTSPseudoClass::MozLWThemeDarkText => {
                 self.get_document_theme() == DocumentTheme::Doc_Theme_Dark
             }
+            NonTSPseudoClass::MozWindowInactive => {
+                self.document_state().contains(NS_DOCUMENT_STATE_WINDOW_INACTIVE)
+            }
             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;