diff --git a/components/style/gecko_bindings/sugar/mod.rs b/components/style/gecko_bindings/sugar/mod.rs index 1d4208f5421..a455cf2b714 100644 --- a/components/style/gecko_bindings/sugar/mod.rs +++ b/components/style/gecko_bindings/sugar/mod.rs @@ -13,7 +13,7 @@ mod ns_style_auto_array; pub mod ns_style_coord; mod ns_t_array; mod ns_timing_function; -mod origin_flags; +pub mod origin_flags; pub mod ownership; pub mod refptr; mod style_complex_color; diff --git a/components/style/gecko_bindings/sugar/origin_flags.rs b/components/style/gecko_bindings/sugar/origin_flags.rs index 1a121ee98ad..60cc9084459 100644 --- a/components/style/gecko_bindings/sugar/origin_flags.rs +++ b/components/style/gecko_bindings/sugar/origin_flags.rs @@ -8,43 +8,24 @@ use gecko_bindings::structs::OriginFlags; use gecko_bindings::structs::OriginFlags_Author; use gecko_bindings::structs::OriginFlags_User; use gecko_bindings::structs::OriginFlags_UserAgent; -use stylesheets::Origin; +use stylesheets::OriginSet; -impl OriginFlags { - /// Returns an iterator over the origins present in the `OriginFlags`, - /// in order from highest priority (author) to lower (user agent). - pub fn iter(self) -> OriginFlagsIter { - OriginFlagsIter { - origin_flags: self, - cur: 0, - } +/// Checks that the values for OriginFlags are the ones we expect. +pub fn assert_flags_match() { + use stylesheets::origin::*; + debug_assert_eq!(OriginFlags_UserAgent.0, ORIGIN_USER_AGENT.bits()); + debug_assert_eq!(OriginFlags_Author.0, ORIGIN_AUTHOR.bits()); + debug_assert_eq!(OriginFlags_User.0, ORIGIN_USER.bits()); +} + +impl From for OriginSet { + fn from(flags: OriginFlags) -> Self { + Self::from_bits_truncate(flags.0) } } -/// Iterates over the origins present in an `OriginFlags`, in order from -/// highest priority (author) to lower (user agent). -pub struct OriginFlagsIter { - origin_flags: OriginFlags, - cur: usize, -} - -impl Iterator for OriginFlagsIter { - type Item = Origin; - - fn next(&mut self) -> Option { - loop { - let (bit, origin) = match self.cur { - 0 => (OriginFlags_Author, Origin::Author), - 1 => (OriginFlags_User, Origin::User), - 2 => (OriginFlags_UserAgent, Origin::UserAgent), - _ => return None, - }; - - self.cur += 1; - - if (self.origin_flags & bit).0 != 0 { - return Some(origin); - } - } +impl From for OriginFlags { + fn from(set: OriginSet) -> Self { + OriginFlags(set.bits()) } } diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index 469fefe3934..e52fcf17887 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -14,7 +14,7 @@ mod loader; mod media_rule; mod memory; mod namespace_rule; -mod origin; +pub mod origin; mod page_rule; mod rule_list; mod rule_parser; @@ -44,7 +44,7 @@ pub use self::memory::{MallocSizeOf, MallocSizeOfFn, MallocSizeOfWithGuard}; #[cfg(feature = "gecko")] pub use self::memory::{MallocSizeOfWithRepeats, SizeOfState}; pub use self::namespace_rule::NamespaceRule; -pub use self::origin::{Origin, PerOrigin, PerOriginClear}; +pub use self::origin::{Origin, OriginSet, PerOrigin, PerOriginClear}; pub use self::page_rule::PageRule; pub use self::rule_parser::{State, TopLevelRuleParser}; pub use self::rule_list::{CssRules, CssRulesHelpers}; diff --git a/components/style/stylesheets/origin.rs b/components/style/stylesheets/origin.rs index ba598fede2b..2e178d00e8b 100644 --- a/components/style/stylesheets/origin.rs +++ b/components/style/stylesheets/origin.rs @@ -2,24 +2,103 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -///! [CSS cascade origins](https://drafts.csswg.org/css-cascade/#cascading-origins). +//! [CSS cascade origins](https://drafts.csswg.org/css-cascade/#cascading-origins). use std::marker::PhantomData; +use std::ops::BitOrAssign; /// Each style rule has an origin, which determines where it enters the cascade. /// /// https://drafts.csswg.org/css-cascade/#cascading-origins #[derive(Clone, PartialEq, Eq, Copy, Debug)] +#[repr(u8)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum Origin { - /// https://drafts.csswg.org/css-cascade/#cascade-origin-us - UserAgent, + /// https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent + UserAgent = 1 << 0, /// https://drafts.csswg.org/css-cascade/#cascade-origin-user - User, + User = 1 << 1, /// https://drafts.csswg.org/css-cascade/#cascade-origin-author - Author, + Author = 1 << 2, +} + +impl Origin { + /// Returns an origin that goes in order for `index`. + /// + /// This is used for iterating across origins. + fn from_index(index: i8) -> Option { + Some(match index { + 0 => Origin::Author, + 1 => Origin::User, + 2 => Origin::UserAgent, + _ => return None, + }) + } +} + +bitflags! { + /// A set of origins. This is equivalent to Gecko's OriginFlags. + pub flags OriginSet: u8 { + /// https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent + const ORIGIN_USER_AGENT = Origin::UserAgent as u8, + /// https://drafts.csswg.org/css-cascade/#cascade-origin-user + const ORIGIN_USER = Origin::User as u8, + /// https://drafts.csswg.org/css-cascade/#cascade-origin-author + const ORIGIN_AUTHOR = Origin::Author as u8, + } +} + +impl OriginSet { + /// Returns an iterator over the origins present in this `OriginSet`. + /// + /// See the `OriginSet` documentation for information about the order + /// origins are iterated. + pub fn iter(&self) -> OriginSetIterator { + OriginSetIterator { + set: *self, + cur: 0, + } + } +} + +impl From for OriginSet { + fn from(origin: Origin) -> Self { + Self::from_bits_truncate(origin as u8) + } +} + +impl BitOrAssign for OriginSet { + fn bitor_assign(&mut self, origin: Origin) { + *self |= OriginSet::from(origin); + } +} + +/// Iterates over the origins present in an `OriginSet`, in order from +/// highest priority (author) to lower (user agent). +pub struct OriginSetIterator { + set: OriginSet, + cur: i8, +} + +impl Iterator for OriginSetIterator { + type Item = Origin; + + fn next(&mut self) -> Option { + loop { + let origin = match Origin::from_index(self.cur) { + Some(origin) => origin, + None => return None, + }; + + self.cur += 1; + + if self.set.contains(origin.into()) { + return Some(origin) + } + } + } } /// An object that stores a `T` for each origin of the CSS cascade. @@ -118,14 +197,14 @@ impl<'a, T> Iterator for PerOriginIter<'a, T> where T: 'a { type Item = (&'a T, Origin); fn next(&mut self) -> Option { - let result = match self.cur { - 0 => (&self.data.author, Origin::Author), - 1 => (&self.data.user, Origin::User), - 2 => (&self.data.user_agent, Origin::UserAgent), - _ => return None, + let origin = match Origin::from_index(self.cur) { + Some(origin) => origin, + None => return None, }; + self.cur += if self.rev { -1 } else { 1 }; - Some(result) + + Some((self.data.borrow_for_origin(&origin), origin)) } } @@ -145,13 +224,13 @@ impl<'a, T> Iterator for PerOriginIterMut<'a, T> where T: 'a { type Item = (&'a mut T, Origin); fn next(&mut self) -> Option { - let result = match self.cur { - 0 => (unsafe { &mut (*self.data).author }, Origin::Author), - 1 => (unsafe { &mut (*self.data).user }, Origin::User), - 2 => (unsafe { &mut (*self.data).user_agent }, Origin::UserAgent), - _ => return None, + let origin = match Origin::from_index(self.cur) { + Some(origin) => origin, + None => return None, }; + self.cur += 1; - Some(result) + + Some((unsafe { (*self.data).borrow_mut_for_origin(&origin) }, origin)) } } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 512aa561f3b..d483bd323bc 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -115,7 +115,7 @@ use style::string_cache::Atom; use style::style_adjuster::StyleAdjuster; use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers, DocumentRule}; use style::stylesheets::{FontFeatureValuesRule, ImportRule, KeyframesRule, MallocSizeOfWithGuard}; -use style::stylesheets::{MediaRule, NamespaceRule, Origin, PageRule, SizeOfState, StyleRule}; +use style::stylesheets::{MediaRule, NamespaceRule, Origin, OriginSet, PageRule, SizeOfState, StyleRule}; use style::stylesheets::{StylesheetContents, StylesheetInDocument, SupportsRule}; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue}; @@ -148,6 +148,8 @@ static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut URLExtraData; #[no_mangle] pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) { + use style::gecko_bindings::sugar::origin_flags; + // Initialize logging. let mut builder = LogBuilder::new(); let default_level = if cfg!(debug_assertions) { "warn" } else { "error" }; @@ -161,6 +163,7 @@ pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) { // Perform some debug-only runtime assertions. restyle_hints::assert_restyle_hints_match(); + origin_flags::assert_flags_match(); parser::assert_parsing_mode_match(); traversal_flags::assert_traversal_flags_match(); @@ -994,7 +997,7 @@ pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged( changed_origins: OriginFlags, ) { let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - for origin in changed_origins.iter() { + for origin in OriginSet::from(changed_origins).iter() { data.stylesheets.force_dirty_origin(&origin); data.clear_stylist_origin(&origin); }