diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index d1eb7a1b2da..a9596f099a2 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -547,6 +547,14 @@ impl<'le> TElement for ServoLayoutElement<'le> { }; extended_filtering(&element_lang, &*value) } + + fn is_html_document_body_element(&self) -> bool { + // This is only used for the "tables inherit from body" quirk, which we + // don't implement. + // + // FIXME(emilio): We should be able to give the right answer though! + false + } } impl<'le> PartialEq for ServoLayoutElement<'le> { diff --git a/components/style/dom.rs b/components/style/dom.rs index 8b0988145d8..18ee81d7b8d 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -727,6 +727,10 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + override_lang: Option>, value: &PseudoClassStringArg ) -> bool; + + /// Returns whether this element is the main body element of the HTML + /// document it is on. + fn is_html_document_body_element(&self) -> bool; } /// TNode and TElement aren't Send because we want to be careful and explicit diff --git a/components/style/gecko/generated/bindings.rs b/components/style/gecko/generated/bindings.rs index 01a8711cf0b..7ea76521558 100644 --- a/components/style/gecko/generated/bindings.rs +++ b/components/style/gecko/generated/bindings.rs @@ -1551,8 +1551,7 @@ extern "C" { *mut nsCSSCounterStyleRule); } extern "C" { - pub fn Gecko_GetBody(pres_context: RawGeckoPresContextBorrowed) - -> RawGeckoElementBorrowedOrNull; + pub fn Gecko_IsDocumentBody(element: RawGeckoElementBorrowed) -> bool; } extern "C" { pub fn Gecko_GetLookAndFeelSystemColor(color_id: i32, diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 7ff3b816cff..415700fef6d 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -11,7 +11,7 @@ use cssparser::{CssStringWriter, Parser, RGBA, Token, BasicParseError}; use euclid::ScaleFactor; use euclid::Size2D; use font_metrics::get_metrics_provider_for_product; -use gecko::values::convert_nscolor_to_rgba; +use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; use gecko_bindings::bindings; use gecko_bindings::structs; use gecko_bindings::structs::{nsCSSKeyword, nsCSSProps_KTableEntry, nsCSSValue, nsCSSUnit}; @@ -27,7 +27,7 @@ use rule_cache::RuleCacheConditions; use servo_arc::Arc; use std::cell::RefCell; use std::fmt::{self, Write}; -use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}; use str::starts_with_ignore_ascii_case; use string_cache::Atom; use style_traits::{CSSPixel, DevicePixel}; @@ -54,6 +54,11 @@ pub struct Device { /// the parent to compute everything else. So it is correct to just use /// a relaxed atomic here. root_font_size: AtomicIsize, + /// The body text color, stored as an `nscolor`, used for the "tables + /// inherit from body" quirk. + /// + /// https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk + body_text_color: AtomicUsize, /// Whether any styles computed in the document relied on the root font-size /// by using rem units. used_root_font_size: AtomicBool, @@ -74,6 +79,7 @@ impl Device { default_values: ComputedValues::default_values(unsafe { &*pres_context }), // FIXME(bz): Seems dubious? root_font_size: AtomicIsize::new(font_size::get_initial_value().0.to_i32_au() as isize), + body_text_color: AtomicUsize::new(unsafe { &*pres_context }.mDefaultColor as usize), used_root_font_size: AtomicBool::new(false), used_viewport_size: AtomicBool::new(false), } @@ -110,6 +116,18 @@ impl Device { self.root_font_size.store(size.0 as isize, Ordering::Relaxed) } + /// Sets the body text color for the "inherit color from body" quirk. + /// + /// https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk + pub fn set_body_text_color(&self, color: RGBA) { + self.body_text_color.store(convert_rgba_to_nscolor(&color) as usize, Ordering::Relaxed) + } + + /// Returns the body text color. + pub fn body_text_color(&self) -> RGBA { + convert_nscolor_to_rgba(self.body_text_color.load(Ordering::Relaxed) as u32) + } + /// Gets the pres context associated with this document. pub fn pres_context(&self) -> &nsPresContext { unsafe { &*self.pres_context } diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 9feb6be4571..641aafbb31a 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -593,6 +593,10 @@ impl<'le> GeckoElement<'le> { self.as_node().node_info().mInner.mNamespaceID } + fn is_html_element(&self) -> bool { + self.namespace_id() == (structs::root::kNameSpaceID_XHTML as i32) + } + fn is_xul_element(&self) -> bool { self.namespace_id() == (structs::root::kNameSpaceID_XUL as i32) } @@ -1502,6 +1506,18 @@ impl<'le> TElement for GeckoElement<'le> { Gecko_MatchLang(self.0, override_lang_ptr, override_lang.is_some(), value.as_ptr()) } } + + fn is_html_document_body_element(&self) -> bool { + if self.get_local_name() != &*local_name!("body") { + return false; + } + + if !self.is_html_element() { + return false; + } + + unsafe { bindings::Gecko_IsDocumentBody(self.0) } + } } impl<'le> PartialEq for GeckoElement<'le> { @@ -2011,10 +2027,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } fn is_html_element_in_html_document(&self) -> bool { - let node = self.as_node(); - let node_info = node.node_info(); - node_info.mInner.mNamespaceID == (structs::root::kNameSpaceID_XHTML as i32) && - node.owner_doc().mType == structs::root::nsIDocument_Type::eHTML + self.is_html_element() && + self.as_node().owner_doc().mType == structs::root::nsIDocument_Type::eHTML } fn ignores_nth_child_selectors(&self) -> bool { diff --git a/components/style/matching.rs b/components/style/matching.rs index 39594af7af8..62777e70d96 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -7,7 +7,8 @@ #![allow(unsafe_code)] #![deny(missing_docs)] -use context::{ElementCascadeInputs, SelectorFlagsMap, SharedStyleContext, StyleContext}; +use context::{ElementCascadeInputs, QuirksMode, SelectorFlagsMap}; +use context::{SharedStyleContext, StyleContext}; use data::ElementData; use dom::TElement; use invalidation::element::restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS}; @@ -586,6 +587,21 @@ pub trait MatchMethods : TElement { } } + if context.shared.stylist.quirks_mode() == QuirksMode::Quirks { + if self.is_html_document_body_element() { + // NOTE(emilio): We _could_ handle dynamic changes to it if it + // changes and before we reach our children the cascade stops, + // but we don't track right now whether we use the document body + // color, and nobody else handles that properly anyway. + + let device = context.shared.stylist.device(); + + // Needed for the "inherit from body" quirk. + let text_color = new_primary_style.get_color().clone_color(); + device.set_body_text_color(text_color); + } + } + // Don't accumulate damage if we're in a forgetful traversal. if context.shared.traversal_flags.contains(traversal_flags::Forgetful) { return ChildCascadeRequirement::MustCascadeChildren; diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index 244a67871fa..f3a8670adcf 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -92,6 +92,13 @@ impl Device { self.root_font_size.store(size.0 as isize, Ordering::Relaxed) } + /// Sets the body text color for the "inherit color from body" quirk. + /// + /// https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk + pub fn set_body_text_color(&self, _color: RGBA) { + // Servo doesn't implement this quirk (yet) + } + /// Returns whether we ever looked up the root font size of the Device. pub fn used_root_font_size(&self) -> bool { self.used_root_font_size.load(Ordering::Relaxed) diff --git a/components/style/values/specified/color.rs b/components/style/values/specified/color.rs index df4b0565182..306aa0b31c1 100644 --- a/components/style/values/specified/color.rs +++ b/components/style/values/specified/color.rs @@ -289,19 +289,7 @@ impl ToComputedValue for Color { } #[cfg(feature = "gecko")] Color::InheritFromBodyQuirk => { - use dom::TElement; - use gecko::wrapper::GeckoElement; - use gecko_bindings::bindings::Gecko_GetBody; - let pres_context = context.device().pres_context(); - let body = unsafe { Gecko_GetBody(pres_context) }.map(GeckoElement); - let data = body.as_ref().and_then(|wrap| wrap.borrow_data()); - if let Some(data) = data { - ComputedColor::rgba(data.styles.primary() - .get_color() - .clone_color()) - } else { - convert_nscolor_to_computedcolor(pres_context.mDefaultColor) - } + ComputedColor::rgba(context.device().body_text_color()) }, } }