aboutsummaryrefslogtreecommitdiffstats
path: root/components/style
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2017-01-14 23:34:49 +0100
committerEmilio Cobos Álvarez <emilio@crisal.io>2017-01-17 14:05:23 +0100
commit5b5243b8afa3c3a757c892285fffb65354fc429d (patch)
tree98311fbd8ad88f9b0b4d529c07b57fa9c83dc105 /components/style
parent5d6ac65e04f4d03d2b1fbbe45cd1a01dbc6bbe28 (diff)
downloadservo-5b5243b8afa3c3a757c892285fffb65354fc429d.tar.gz
servo-5b5243b8afa3c3a757c892285fffb65354fc429d.zip
Bug 1331213: Bootstrap a Gecko-side Device, and track it's dirtiness manually in the per-doc data. r=heycam
The setup is quite different to Servo-land, so add a comment about the different setup. Also, check viewport rules when flushing stylesheets. I believe that the previous behavior is plain wrong, though I haven't taken the time to come up with a test case. In any case, it doesn't hurt any of both back-ends. MozReview-Commit-ID: 46gtTkesOsr Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
Diffstat (limited to 'components/style')
-rw-r--r--components/style/build_gecko.rs1
-rw-r--r--components/style/gecko/data.rs50
-rw-r--r--components/style/gecko/media_queries.rs359
-rw-r--r--components/style/gecko/mod.rs5
-rw-r--r--components/style/gecko_bindings/bindings.rs8
-rw-r--r--components/style/gecko_bindings/structs_debug.rs123
-rw-r--r--components/style/gecko_bindings/structs_release.rs120
-rw-r--r--components/style/media_queries.rs4
-rw-r--r--components/style/servo/media_queries.rs31
-rw-r--r--components/style/stylist.rs33
10 files changed, 668 insertions, 66 deletions
diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs
index 6bb3b4aeddb..930f751567d 100644
--- a/components/style/build_gecko.rs
+++ b/components/style/build_gecko.rs
@@ -497,6 +497,7 @@ mod bindings {
"RawGeckoAnimationValueList",
"RawServoAnimationValue",
"RawGeckoPresContext",
+ "RawGeckoPresContextOwned",
"ThreadSafeURIHolder",
"ThreadSafePrincipalHolder",
"CSSPseudoClassType",
diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs
index dd4ae30a429..f4182d365e2 100644
--- a/components/style/gecko/data.rs
+++ b/components/style/gecko/data.rs
@@ -7,11 +7,10 @@
use animation::Animation;
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use dom::OpaqueNode;
-use euclid::size::TypedSize2D;
-use gecko_bindings::bindings::RawGeckoPresContextBorrowed;
use gecko_bindings::bindings::RawServoStyleSet;
+use gecko_bindings::structs::RawGeckoPresContextOwned;
use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
-use media_queries::{Device, MediaType};
+use media_queries::Device;
use num_cpus;
use parking_lot::RwLock;
use properties::ComputedValues;
@@ -21,7 +20,6 @@ use std::collections::HashMap;
use std::env;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender, channel};
-use style_traits::ViewportPx;
use stylesheets::Stylesheet;
use stylist::Stylist;
@@ -37,6 +35,9 @@ pub struct PerDocumentStyleDataImpl {
/// Whether the stylesheets list above has changed since the last restyle.
pub stylesheets_changed: bool,
+ /// Whether the device has changed since the last restyle.
+ pub device_changed: bool,
+
// FIXME(bholley): Hook these up to something.
/// Unused. Will go away when we actually implement transitions and
/// animations properly.
@@ -57,9 +58,6 @@ pub struct PerDocumentStyleDataImpl {
/// The number of threads of the work queue.
pub num_threads: usize,
-
- /// Default computed values for this document.
- pub default_computed_values: Arc<ComputedValues>
}
/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
@@ -78,15 +76,8 @@ lazy_static! {
impl PerDocumentStyleData {
/// Create a dummy `PerDocumentStyleData`.
- pub fn new(pres_context: RawGeckoPresContextBorrowed) -> Self {
- // FIXME(bholley): Real window size.
- let window_size: TypedSize2D<f32, ViewportPx> = TypedSize2D::new(800.0, 600.0);
- let default_computed_values = ComputedValues::default_values(pres_context);
-
- // FIXME(bz): We're going to need to either update the computed values
- // in the Stylist's Device or give the Stylist a new Device when our
- // default_computed_values changes.
- let device = Device::new(MediaType::Screen, window_size, &default_computed_values);
+ pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
+ let device = Device::new(pres_context);
let (new_anims_sender, new_anims_receiver) = channel();
@@ -94,6 +85,7 @@ impl PerDocumentStyleData {
stylist: Arc::new(Stylist::new(device)),
stylesheets: vec![],
stylesheets_changed: true,
+ device_changed: true,
new_animations_sender: new_anims_sender,
new_animations_receiver: new_anims_receiver,
running_animations: Arc::new(RwLock::new(HashMap::new())),
@@ -106,7 +98,6 @@ impl PerDocumentStyleData {
rayon::ThreadPool::new(configuration).ok()
},
num_threads: *NUM_THREADS,
- default_computed_values: default_computed_values,
}))
}
@@ -124,15 +115,30 @@ impl PerDocumentStyleData {
impl PerDocumentStyleDataImpl {
/// Recreate the style data if the stylesheets have changed.
pub fn flush_stylesheets(&mut self) {
- // The stylist wants to be flushed if either the stylesheets change or the
- // device dimensions change. When we add support for media queries, we'll
- // need to detect the latter case and trigger a flush as well.
+ let mut stylist = if self.device_changed || self.stylesheets_changed {
+ Some(Arc::get_mut(&mut self.stylist).unwrap())
+ } else {
+ None
+ };
+
+ if self.device_changed {
+ Arc::get_mut(&mut stylist.as_mut().unwrap().device).unwrap().reset();
+ self.device_changed = false;
+ // Force a stylesheet flush if the device has changed.
+ self.stylesheets_changed = true;
+ }
+
if self.stylesheets_changed {
- let _ = Arc::get_mut(&mut self.stylist).unwrap()
- .update(&self.stylesheets, None, true);
+ let _ = stylist.unwrap().update(&self.stylesheets, None, true);
self.stylesheets_changed = false;
}
}
+
+ /// Get the default computed values for this document.
+ pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
+ debug_assert!(!self.device_changed, "A device flush was pending");
+ self.stylist.device.default_values_arc()
+ }
}
unsafe impl HasFFI for PerDocumentStyleData {
diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs
new file mode 100644
index 00000000000..f7462772d27
--- /dev/null
+++ b/components/style/gecko/media_queries.rs
@@ -0,0 +1,359 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+//! Gecko's media-query device and expression representation.
+
+use app_units::Au;
+use cssparser::{Parser, Token};
+use euclid::Size2D;
+use gecko_bindings::bindings;
+use gecko_bindings::structs::{nsMediaExpression_Range, nsMediaFeature};
+use gecko_bindings::structs::{nsMediaFeature_ValueType, nsMediaFeature_RangeType, nsMediaFeature_RequirementFlags};
+use gecko_bindings::structs::RawGeckoPresContextOwned;
+use media_queries::MediaType;
+use properties::ComputedValues;
+use std::ascii::AsciiExt;
+use std::fmt;
+use std::sync::Arc;
+use string_cache::Atom;
+use style_traits::ToCss;
+use style_traits::viewport::ViewportConstraints;
+use values::{CSSFloat, specified};
+
+/// The `Device` in Gecko wraps a pres context, has a default values computed,
+/// and contains all the viewport rule state.
+pub struct Device {
+ /// NB: The pres context lifetime is tied to the styleset, who owns the
+ /// stylist, and thus the `Device`, so having a raw pres context pointer
+ /// here is fine.
+ pres_context: RawGeckoPresContextOwned,
+ default_values: Arc<ComputedValues>,
+ viewport_override: Option<ViewportConstraints>,
+}
+
+impl Device {
+ /// Trivially constructs a new `Device`.
+ pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
+ assert!(!pres_context.is_null());
+ Device {
+ pres_context: pres_context,
+ default_values: ComputedValues::default_values(unsafe { &*pres_context }),
+ viewport_override: None,
+ }
+ }
+
+ /// Tells the device that a new viewport rule has been found, and stores the
+ /// relevant viewport constraints.
+ pub fn account_for_viewport_rule(&mut self,
+ constraints: &ViewportConstraints) {
+ self.viewport_override = Some(constraints.clone());
+ }
+
+ /// Returns the default computed values as a reference, in order to match
+ /// Servo.
+ pub fn default_values(&self) -> &ComputedValues {
+ &*self.default_values
+ }
+
+ /// Returns the default computed values as an `Arc`, in order to avoid
+ /// clones.
+ pub fn default_values_arc(&self) -> &Arc<ComputedValues> {
+ &self.default_values
+ }
+
+ /// Recreates all the temporary state that the `Device` stores.
+ ///
+ /// This includes the viewport override from `@viewport` rules, and also the
+ /// default computed values.
+ pub fn reset(&mut self) {
+ // NB: A following stylesheet flush will populate this if appropriate.
+ self.viewport_override = None;
+ self.default_values = ComputedValues::default_values(unsafe { &*self.pres_context });
+ }
+
+ /// Returns the current media type of the device.
+ pub fn media_type(&self) -> MediaType {
+ // TODO
+ MediaType::Screen
+ }
+
+ /// Returns the current viewport size in app units.
+ pub fn au_viewport_size(&self) -> Size2D<Au> {
+ self.viewport_override.as_ref().map(|v| {
+ Size2D::new(Au::from_f32_px(v.size.width),
+ Au::from_f32_px(v.size.height))
+ }).unwrap_or_else(|| {
+ // TODO(emilio): Grab from pres context.
+ Size2D::new(Au::from_f32_px(1024.0),
+ Au::from_f32_px(768.0))
+ })
+ }
+}
+
+unsafe impl Sync for Device {}
+unsafe impl Send for Device {}
+
+/// A expression for gecko contains a reference to the media feature, the value
+/// the media query contained, and the range to evaluate.
+#[derive(Debug, Clone)]
+pub struct Expression {
+ feature: &'static nsMediaFeature,
+ value: MediaExpressionValue,
+ range: nsMediaExpression_Range
+}
+
+impl ToCss for Expression {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where W: fmt::Write,
+ {
+ dest.write_str("(")?;
+ match self.range {
+ nsMediaExpression_Range::eMin => dest.write_str("min-")?,
+ nsMediaExpression_Range::eMax => dest.write_str("max-")?,
+ nsMediaExpression_Range::eEqual => {},
+ }
+ // NB: CSSStringWriter not needed, features are under control.
+ write!(dest, "{}", Atom::from(unsafe { *self.feature.mName }))?;
+ dest.write_str(": ")?;
+
+ self.value.to_css(dest)?;
+ dest.write_str(")")
+ }
+}
+
+/// A resolution.
+#[derive(Debug, Clone)]
+pub enum Resolution {
+ /// Dots per inch.
+ Dpi(CSSFloat),
+ /// Dots per pixel.
+ Dppx(CSSFloat),
+ /// Dots per centimeter.
+ Dpcm(CSSFloat),
+}
+
+impl Resolution {
+ fn parse(input: &mut Parser) -> Result<Self, ()> {
+ let (value, unit) = match try!(input.next()) {
+ Token::Dimension(value, unit) => {
+ (value.value, unit)
+ },
+ _ => return Err(()),
+ };
+
+ Ok(match_ignore_ascii_case! { unit,
+ "dpi" => Resolution::Dpi(value),
+ "dppx" => Resolution::Dppx(value),
+ "dpcm" => Resolution::Dpcm(value),
+ _ => return Err(())
+ })
+ }
+}
+
+impl ToCss for Resolution {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where W: fmt::Write,
+ {
+ match *self {
+ Resolution::Dpi(v) => write!(dest, "{}dpi", v),
+ Resolution::Dppx(v) => write!(dest, "{}dppx", v),
+ Resolution::Dpcm(v) => write!(dest, "{}dpcm", v),
+ }
+ }
+}
+
+/// A value found or expected in a media expression.
+#[derive(Debug, Clone)]
+pub enum MediaExpressionValue {
+ /// A length.
+ Length(specified::Length),
+ /// A (non-negative) integer.
+ Integer(u32),
+ /// A floating point value.
+ Float(CSSFloat),
+ /// A boolean value, specified as an integer (i.e., either 0 or 1).
+ BoolInteger(bool),
+ /// Two integers separated by '/', with optional whitespace on either side
+ /// of the '/'.
+ IntRatio(u32, u32),
+ /// A resolution.
+ Resolution(Resolution),
+ /// An enumerated index into the variant keyword table.
+ Enumerated(u32),
+ /// An identifier.
+ Ident(Atom),
+}
+
+impl ToCss for MediaExpressionValue {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where W: fmt::Write,
+ {
+ match *self {
+ MediaExpressionValue::Length(ref l) => l.to_css(dest),
+ MediaExpressionValue::Integer(v) => write!(dest, "{}", v),
+ MediaExpressionValue::Float(v) => write!(dest, "{}", v),
+ MediaExpressionValue::BoolInteger(v) => {
+ dest.write_str(if v { "1" } else { "0" })
+ },
+ MediaExpressionValue::IntRatio(a, b) => {
+ write!(dest, "{}/{}", a, b)
+ },
+ MediaExpressionValue::Resolution(ref r) => r.to_css(dest),
+ MediaExpressionValue::Enumerated(..) |
+ MediaExpressionValue::Ident(..) => {
+ // TODO(emilio)
+ unimplemented!()
+ }
+ }
+ }
+}
+
+fn starts_with_ignore_ascii_case(string: &str, prefix: &str) -> bool {
+ string.len() > prefix.len() &&
+ string[0..prefix.len()].eq_ignore_ascii_case(prefix)
+}
+
+#[allow(warnings)]
+fn find_feature<F>(mut f: F) -> Option<&'static nsMediaFeature>
+ where F: FnMut(&'static nsMediaFeature) -> bool,
+{
+ // FIXME(emilio): With build-time bindgen, we would be able to use
+ // structs::nsMediaFeatures_features. That would unfortunately break MSVC
+ // builds, or require one bindings file per platform.
+ //
+ // I'm not into any of those, so meanwhile let's use a FFI function.
+ unsafe {
+ let mut features = bindings::Gecko_GetMediaFeatures();
+ while !(*features).mName.is_null() {
+ if f(&*features) {
+ return Some(&*features);
+ }
+ features = features.offset(1);
+ }
+ }
+
+ None
+}
+
+impl Expression {
+ /// Trivially construct a new expression.
+ fn new(feature: &'static nsMediaFeature,
+ value: MediaExpressionValue,
+ range: nsMediaExpression_Range) -> Self {
+ Expression {
+ feature: feature,
+ value: value,
+ range: range,
+ }
+ }
+
+ /// Parse a media expression of the form:
+ ///
+ /// ```
+ /// (media-feature: media-value)
+ /// ```
+ #[allow(warnings)]
+ pub fn parse(input: &mut Parser) -> Result<Self, ()> {
+ try!(input.expect_parenthesis_block());
+ input.parse_nested_block(|input| {
+ let ident = try!(input.expect_ident());
+ try!(input.expect_colon());
+
+ let mut flags = 0;
+ let mut feature_name = &*ident;
+
+ // TODO(emilio): this is under a pref in Gecko.
+ if starts_with_ignore_ascii_case(feature_name, "-webkit-") {
+ feature_name = &feature_name[8..];
+ flags |= nsMediaFeature_RequirementFlags::eHasWebkitPrefix as u8;
+ }
+
+ let range = if starts_with_ignore_ascii_case(feature_name, "min-") {
+ feature_name = &feature_name[4..];
+ nsMediaExpression_Range::eMin
+ } else if starts_with_ignore_ascii_case(feature_name, "max-") {
+ feature_name = &feature_name[4..];
+ nsMediaExpression_Range::eMax
+ } else {
+ nsMediaExpression_Range::eEqual
+ };
+
+ let atom = Atom::from(feature_name);
+ let feature =
+ match find_feature(|f| atom.as_ptr() == unsafe { *f.mName }) {
+ Some(f) => f,
+ None => return Err(()),
+ };
+
+ if (feature.mReqFlags & !flags) != 0 {
+ return Err(());
+ }
+
+ if range != nsMediaExpression_Range::eEqual &&
+ feature.mRangeType != nsMediaFeature_RangeType::eMinMaxAllowed {
+ return Err(());
+ }
+
+ let value = match feature.mValueType {
+ nsMediaFeature_ValueType::eLength => {
+ MediaExpressionValue::Length(
+ specified::Length::parse_non_negative(input)?)
+ },
+ nsMediaFeature_ValueType::eInteger => {
+ let i = input.expect_integer()?;
+ if i < 0 {
+ return Err(())
+ }
+ MediaExpressionValue::Integer(i as u32)
+ }
+ nsMediaFeature_ValueType::eBoolInteger => {
+ let i = input.expect_integer()?;
+ if i < 0 || i > 1 {
+ return Err(())
+ }
+ MediaExpressionValue::BoolInteger(i == 1)
+ }
+ nsMediaFeature_ValueType::eFloat => {
+ MediaExpressionValue::Float(input.expect_number()?)
+ }
+ nsMediaFeature_ValueType::eIntRatio => {
+ let a = input.expect_integer()?;
+ if a <= 0 {
+ return Err(())
+ }
+
+ input.expect_delim('/')?;
+
+ let b = input.expect_integer()?;
+ if b <= 0 {
+ return Err(())
+ }
+ MediaExpressionValue::IntRatio(a as u32, b as u32)
+ }
+ nsMediaFeature_ValueType::eResolution => {
+ MediaExpressionValue::Resolution(Resolution::parse(input)?)
+ }
+ nsMediaFeature_ValueType::eEnumerated => {
+ let index = unsafe {
+ let _table = feature.mData.mKeywordTable.as_ref();
+ 0
+ };
+ MediaExpressionValue::Enumerated(index)
+ }
+ nsMediaFeature_ValueType::eIdent => {
+ MediaExpressionValue::Ident(input.expect_ident()?.into())
+ }
+ };
+
+ Ok(Expression::new(feature, value, range))
+ })
+ }
+
+ /// Returns whether this media query evaluates to true for the given
+ /// device.
+ pub fn matches(&self, _device: &Device) -> bool {
+ // TODO
+ false
+ }
+}
diff --git a/components/style/gecko/mod.rs b/components/style/gecko/mod.rs
index 6166a64bea3..ca87d081ef7 100644
--- a/components/style/gecko/mod.rs
+++ b/components/style/gecko/mod.rs
@@ -6,12 +6,7 @@
pub mod conversions;
pub mod data;
-
-// TODO(emilio): Implement Gecko media query parsing and evaluation using
-// nsMediaFeatures.
-#[path = "../servo/media_queries.rs"]
pub mod media_queries;
-
pub mod restyle_damage;
pub mod selector_parser;
pub mod snapshot;
diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs
index 19635b5af26..89089efca0d 100644
--- a/components/style/gecko_bindings/bindings.rs
+++ b/components/style/gecko_bindings/bindings.rs
@@ -9,6 +9,7 @@ use gecko_bindings::structs::RawGeckoNode;
use gecko_bindings::structs::RawGeckoAnimationValueList;
use gecko_bindings::structs::RawServoAnimationValue;
use gecko_bindings::structs::RawGeckoPresContext;
+use gecko_bindings::structs::RawGeckoPresContextOwned;
use gecko_bindings::structs::ThreadSafeURIHolder;
use gecko_bindings::structs::ThreadSafePrincipalHolder;
use gecko_bindings::structs::CSSPseudoClassType;
@@ -1118,14 +1119,11 @@ extern "C" {
-> ServoCssRulesStrong;
}
extern "C" {
- pub fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextBorrowed)
+ pub fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned)
-> RawServoStyleSetOwned;
}
extern "C" {
- pub fn Servo_StyleSet_RecomputeDefaultStyles(set:
- RawServoStyleSetBorrowed,
- pres_context:
- RawGeckoPresContextBorrowed);
+ pub fn Servo_StyleSet_RebuildData(set: RawServoStyleSetBorrowed);
}
extern "C" {
pub fn Servo_StyleSet_AppendStyleSheet(set: RawServoStyleSetBorrowed,
diff --git a/components/style/gecko_bindings/structs_debug.rs b/components/style/gecko_bindings/structs_debug.rs
index 9972511f5e4..619553c2e74 100644
--- a/components/style/gecko_bindings/structs_debug.rs
+++ b/components/style/gecko_bindings/structs_debug.rs
@@ -2957,7 +2957,7 @@ pub mod root {
* The FramePropertyTable is optimized for storing 0 or 1 properties on
* a given frame. Storing very large numbers of properties on a single
* frame will not be efficient.
- *
+ *
* Property values are passed as void* but do not actually have to be
* valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to
* store int32_t values. Null/zero values can be stored and retrieved.
@@ -12149,9 +12149,11 @@ pub mod root {
pub type RawGeckoElementBorrowedOrNull = *const root::RawGeckoElement;
pub type RawGeckoDocumentBorrowed = *const root::RawGeckoDocument;
pub type RawGeckoDocumentBorrowedOrNull = *const root::RawGeckoDocument;
+ pub type RawGeckoPresContextOwned = *mut [u64; 162usize];
pub type RawGeckoPresContextBorrowed = *const [u64; 162usize];
pub type RawGeckoAnimationValueListBorrowedMut =
*mut root::RawGeckoAnimationValueList;
+ pub type RawGeckoPresContextBorrowedMut = *mut [u64; 162usize];
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum nsCSSTokenSerializationType {
@@ -13600,6 +13602,125 @@ pub mod root {
pub type ThreadSafePrincipalHolder =
root::nsMainThreadPtrHolder<root::nsIPrincipal>;
pub type ThreadSafeURIHolder = root::nsMainThreadPtrHolder<root::nsIURI>;
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct nsMediaFeature {
+ pub mName: *mut *mut root::nsIAtom,
+ pub mRangeType: root::nsMediaFeature_RangeType,
+ pub mValueType: root::nsMediaFeature_ValueType,
+ pub mReqFlags: u8,
+ pub mData: root::nsMediaFeature__bindgen_ty_1,
+ pub mGetter: root::nsMediaFeatureValueGetter,
+ }
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum nsMediaFeature_RangeType {
+ eMinMaxAllowed = 0,
+ eMinMaxNotAllowed = 1,
+ }
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum nsMediaFeature_ValueType {
+ eLength = 0,
+ eInteger = 1,
+ eFloat = 2,
+ eBoolInteger = 3,
+ eIntRatio = 4,
+ eResolution = 5,
+ eEnumerated = 6,
+ eIdent = 7,
+ }
+ #[repr(u8)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum nsMediaFeature_RequirementFlags {
+ eNoRequirements = 0,
+ eHasWebkitPrefix = 1,
+ eWebkitDevicePixelRatioPrefEnabled = 2,
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct nsMediaFeature__bindgen_ty_1 {
+ pub mInitializer_: root::__BindgenUnionField<*const ::std::os::raw::c_void>,
+ pub mKeywordTable: root::__BindgenUnionField<*const root::nsCSSProps_KTableEntry>,
+ pub mMetric: root::__BindgenUnionField<*const *const root::nsIAtom>,
+ pub bindgen_union_field: u64,
+ }
+ #[test]
+ fn bindgen_test_layout_nsMediaFeature__bindgen_ty_1() {
+ assert_eq!(::std::mem::size_of::<nsMediaFeature__bindgen_ty_1>() ,
+ 8usize);
+ assert_eq!(::std::mem::align_of::<nsMediaFeature__bindgen_ty_1>() ,
+ 8usize);
+ }
+ impl Clone for nsMediaFeature__bindgen_ty_1 {
+ fn clone(&self) -> Self { *self }
+ }
+ #[test]
+ fn bindgen_test_layout_nsMediaFeature() {
+ assert_eq!(::std::mem::size_of::<nsMediaFeature>() , 40usize);
+ assert_eq!(::std::mem::align_of::<nsMediaFeature>() , 8usize);
+ }
+ impl Clone for nsMediaFeature {
+ fn clone(&self) -> Self { *self }
+ }
+ pub type ThreadSafePrincipalHolder =
+ root::nsMainThreadPtrHolder<root::nsIPrincipal>;
+ pub type ThreadSafeURIHolder = root::nsMainThreadPtrHolder<root::nsIURI>;
+ pub type nsMediaFeatureValueGetter =
+ ::std::option::Option<unsafe extern "C" fn(aPresContext:
+ *mut root::nsPresContext,
+ aFeature:
+ *const root::nsMediaFeature,
+ aResult:
+ *mut root::nsCSSValue)
+ -> root::nsresult>;
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct nsMediaFeatures {
+ pub _address: u8,
+ }
+ extern "C" {
+ #[link_name = "_ZN15nsMediaFeatures8featuresE"]
+ pub static mut nsMediaFeatures_features: *const root::nsMediaFeature;
+ }
+ #[test]
+ fn bindgen_test_layout_nsMediaFeatures() {
+ assert_eq!(::std::mem::size_of::<nsMediaFeatures>() , 1usize);
+ assert_eq!(::std::mem::align_of::<nsMediaFeatures>() , 1usize);
+ }
+ impl Clone for nsMediaFeatures {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug)]
+ pub struct nsMediaExpression {
+ pub mFeature: *const root::nsMediaFeature,
+ pub mRange: root::nsMediaExpression_Range,
+ pub mValue: root::nsCSSValue,
+ }
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum nsMediaExpression_Range { eMin = 0, eMax = 1, eEqual = 2, }
+ #[test]
+ fn bindgen_test_layout_nsMediaExpression() {
+ assert_eq!(::std::mem::size_of::<nsMediaExpression>() , 32usize);
+ assert_eq!(::std::mem::align_of::<nsMediaExpression>() , 8usize);
+ }
+ #[repr(C)]
+ #[derive(Debug)]
+ pub struct nsMediaQuery {
+ pub mNegated: bool,
+ pub mHasOnly: bool,
+ pub mTypeOmitted: bool,
+ pub mHadUnknownExpression: bool,
+ pub mMediaType: root::nsCOMPtr<root::nsIAtom>,
+ pub mExpressions: root::nsTArray<root::nsMediaExpression>,
+ }
+ #[test]
+ fn bindgen_test_layout_nsMediaQuery() {
+ assert_eq!(::std::mem::size_of::<nsMediaQuery>() , 24usize);
+ assert_eq!(::std::mem::align_of::<nsMediaQuery>() , 8usize);
+ }
#[test]
fn __bindgen_test_layout_template_11() {
assert_eq!(::std::mem::size_of::<root::JS::TenuredHeap<*mut root::JSObject>>()
diff --git a/components/style/gecko_bindings/structs_release.rs b/components/style/gecko_bindings/structs_release.rs
index e7b8fdc5ff2..7d3a1a5caf1 100644
--- a/components/style/gecko_bindings/structs_release.rs
+++ b/components/style/gecko_bindings/structs_release.rs
@@ -2944,7 +2944,7 @@ pub mod root {
* The FramePropertyTable is optimized for storing 0 or 1 properties on
* a given frame. Storing very large numbers of properties on a single
* frame will not be efficient.
- *
+ *
* Property values are passed as void* but do not actually have to be
* valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to
* store int32_t values. Null/zero values can be stored and retrieved.
@@ -12076,9 +12076,11 @@ pub mod root {
pub type RawGeckoElementBorrowedOrNull = *const root::RawGeckoElement;
pub type RawGeckoDocumentBorrowed = *const root::RawGeckoDocument;
pub type RawGeckoDocumentBorrowedOrNull = *const root::RawGeckoDocument;
+ pub type RawGeckoPresContextOwned = *mut [u64; 158usize];
pub type RawGeckoPresContextBorrowed = *const [u64; 158usize];
pub type RawGeckoAnimationValueListBorrowedMut =
*mut root::RawGeckoAnimationValueList;
+ pub type RawGeckoPresContextBorrowedMut = *mut [u64; 158usize];
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum nsCSSTokenSerializationType {
@@ -13524,9 +13526,125 @@ pub mod root {
pub struct nsTArray<T> {
pub mBuffer: *mut T,
}
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct nsMediaFeature {
+ pub mName: *mut *mut root::nsIAtom,
+ pub mRangeType: root::nsMediaFeature_RangeType,
+ pub mValueType: root::nsMediaFeature_ValueType,
+ pub mReqFlags: u8,
+ pub mData: root::nsMediaFeature__bindgen_ty_1,
+ pub mGetter: root::nsMediaFeatureValueGetter,
+ }
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum nsMediaFeature_RangeType {
+ eMinMaxAllowed = 0,
+ eMinMaxNotAllowed = 1,
+ }
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum nsMediaFeature_ValueType {
+ eLength = 0,
+ eInteger = 1,
+ eFloat = 2,
+ eBoolInteger = 3,
+ eIntRatio = 4,
+ eResolution = 5,
+ eEnumerated = 6,
+ eIdent = 7,
+ }
+ #[repr(u8)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum nsMediaFeature_RequirementFlags {
+ eNoRequirements = 0,
+ eHasWebkitPrefix = 1,
+ eWebkitDevicePixelRatioPrefEnabled = 2,
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct nsMediaFeature__bindgen_ty_1 {
+ pub mInitializer_: root::__BindgenUnionField<*const ::std::os::raw::c_void>,
+ pub mKeywordTable: root::__BindgenUnionField<*const root::nsCSSProps_KTableEntry>,
+ pub mMetric: root::__BindgenUnionField<*const *const root::nsIAtom>,
+ pub bindgen_union_field: u64,
+ }
+ #[test]
+ fn bindgen_test_layout_nsMediaFeature__bindgen_ty_1() {
+ assert_eq!(::std::mem::size_of::<nsMediaFeature__bindgen_ty_1>() ,
+ 8usize);
+ assert_eq!(::std::mem::align_of::<nsMediaFeature__bindgen_ty_1>() ,
+ 8usize);
+ }
+ impl Clone for nsMediaFeature__bindgen_ty_1 {
+ fn clone(&self) -> Self { *self }
+ }
+ #[test]
+ fn bindgen_test_layout_nsMediaFeature() {
+ assert_eq!(::std::mem::size_of::<nsMediaFeature>() , 40usize);
+ assert_eq!(::std::mem::align_of::<nsMediaFeature>() , 8usize);
+ }
+ impl Clone for nsMediaFeature {
+ fn clone(&self) -> Self { *self }
+ }
pub type ThreadSafePrincipalHolder =
root::nsMainThreadPtrHolder<root::nsIPrincipal>;
pub type ThreadSafeURIHolder = root::nsMainThreadPtrHolder<root::nsIURI>;
+ pub type nsMediaFeatureValueGetter =
+ ::std::option::Option<unsafe extern "C" fn(aPresContext:
+ *mut root::nsPresContext,
+ aFeature:
+ *const root::nsMediaFeature,
+ aResult:
+ *mut root::nsCSSValue)
+ -> root::nsresult>;
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct nsMediaFeatures {
+ pub _address: u8,
+ }
+ extern "C" {
+ #[link_name = "_ZN15nsMediaFeatures8featuresE"]
+ pub static mut nsMediaFeatures_features: *const root::nsMediaFeature;
+ }
+ #[test]
+ fn bindgen_test_layout_nsMediaFeatures() {
+ assert_eq!(::std::mem::size_of::<nsMediaFeatures>() , 1usize);
+ assert_eq!(::std::mem::align_of::<nsMediaFeatures>() , 1usize);
+ }
+ impl Clone for nsMediaFeatures {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug)]
+ pub struct nsMediaExpression {
+ pub mFeature: *const root::nsMediaFeature,
+ pub mRange: root::nsMediaExpression_Range,
+ pub mValue: root::nsCSSValue,
+ }
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum nsMediaExpression_Range { eMin = 0, eMax = 1, eEqual = 2, }
+ #[test]
+ fn bindgen_test_layout_nsMediaExpression() {
+ assert_eq!(::std::mem::size_of::<nsMediaExpression>() , 32usize);
+ assert_eq!(::std::mem::align_of::<nsMediaExpression>() , 8usize);
+ }
+ #[repr(C)]
+ #[derive(Debug)]
+ pub struct nsMediaQuery {
+ pub mNegated: bool,
+ pub mHasOnly: bool,
+ pub mTypeOmitted: bool,
+ pub mHadUnknownExpression: bool,
+ pub mMediaType: root::nsCOMPtr<root::nsIAtom>,
+ pub mExpressions: root::nsTArray<root::nsMediaExpression>,
+ }
+ #[test]
+ fn bindgen_test_layout_nsMediaQuery() {
+ assert_eq!(::std::mem::size_of::<nsMediaQuery>() , 24usize);
+ assert_eq!(::std::mem::align_of::<nsMediaQuery>() , 8usize);
+ }
#[test]
fn __bindgen_test_layout_template_11() {
assert_eq!(::std::mem::size_of::<root::JS::TenuredHeap<*mut root::JSObject>>()
diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs
index daac8bed876..19a7fd41b39 100644
--- a/components/style/media_queries.rs
+++ b/components/style/media_queries.rs
@@ -19,7 +19,7 @@ pub use servo::media_queries::{Device, Expression};
pub use gecko::media_queries::{Device, Expression};
/// A type that encapsulates a media query list.
-#[derive(Debug, PartialEq)]
+#[derive(Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct MediaList {
/// The list of media queries.
@@ -66,7 +66,7 @@ impl ToCss for Qualifier {
/// A [media query][mq].
///
/// [mq]: https://drafts.csswg.org/mediaqueries/
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct MediaQuery {
/// The qualifier for this query.
diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs
index 6dbd78d1587..6c2a4309ddb 100644
--- a/components/style/servo/media_queries.rs
+++ b/components/style/servo/media_queries.rs
@@ -10,8 +10,6 @@ use euclid::{Size2D, TypedSize2D};
use media_queries::MediaType;
use properties::ComputedValues;
use std::fmt;
-#[cfg(feature = "gecko")]
-use std::sync::Arc;
use style_traits::{ToCss, ViewportPx};
use style_traits::viewport::ViewportConstraints;
use values::computed::{self, ToComputedValue};
@@ -21,24 +19,16 @@ use values::specified;
/// is displayed in.
///
/// This is the struct against which media queries are evaluated.
-#[derive(Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Debug, HeapSizeOf)]
pub struct Device {
/// The current media type used by de device.
media_type: MediaType,
/// The current viewport size, in viewport pixels.
viewport_size: TypedSize2D<f32, ViewportPx>,
- /// A set of default computed values for this document.
- ///
- /// This allows handling zoom correctly, among other things. Gecko-only for
- /// now, see #14773.
- #[cfg(feature = "gecko")]
- default_values: Arc<ComputedValues>,
}
impl Device {
/// Trivially construct a new `Device`.
- #[cfg(feature = "servo")]
pub fn new(media_type: MediaType,
viewport_size: TypedSize2D<f32, ViewportPx>)
-> Device {
@@ -48,30 +38,11 @@ impl Device {
}
}
- /// Trivially construct a new `Device`.
- #[cfg(feature = "gecko")]
- pub fn new(media_type:
- MediaType, viewport_size: TypedSize2D<f32, ViewportPx>,
- default_values: &Arc<ComputedValues>) -> Device {
- Device {
- media_type: media_type,
- viewport_size: viewport_size,
- default_values: default_values.clone(),
- }
- }
-
/// Return the default computed values for this device.
- #[cfg(feature = "servo")]
pub fn default_values(&self) -> &ComputedValues {
ComputedValues::initial_values()
}
- /// Return the default computed values for this device.
- #[cfg(feature = "gecko")]
- pub fn default_values(&self) -> &ComputedValues {
- &*self.default_values
- }
-
/// Returns the viewport size of the current device in app units, needed,
/// among other things, to resolve viewport units.
#[inline]
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index 45e6b0f9529..27ffea363d1 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -49,6 +49,20 @@ pub use ::fnv::FnvHashMap;
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Stylist {
/// Device that the stylist is currently evaluating against.
+ ///
+ /// This field deserves a bigger comment due to the different use that Gecko
+ /// and Servo give to it (that we should eventually unify).
+ ///
+ /// With Gecko, the device is never changed. Gecko manually tracks whether
+ /// the device data should be reconstructed, and "resets" the state of the
+ /// device.
+ ///
+ /// On Servo, on the other hand, the device is a really cheap representation
+ /// that is recreated each time some constraint changes and calling
+ /// `set_device`.
+ ///
+ /// In both cases, the device is actually _owned_ by the Stylist, and it's
+ /// only an `Arc` so we can implement `add_stylesheet` more idiomatically.
pub device: Arc<Device>,
/// Viewport constraints based on the current device.
@@ -146,6 +160,18 @@ impl Stylist {
return false;
}
+ let cascaded_rule = ViewportRule {
+ declarations: viewport::Cascade::from_stylesheets(doc_stylesheets, &self.device).finish(),
+ };
+
+ self.viewport_constraints =
+ ViewportConstraints::maybe_new(&self.device, &cascaded_rule);
+
+ if let Some(ref constraints) = self.viewport_constraints {
+ Arc::get_mut(&mut self.device).unwrap()
+ .account_for_viewport_rule(constraints);
+ }
+
self.element_map = PerPseudoElementSelectorMap::new();
self.pseudos_map = Default::default();
self.animations = Default::default();
@@ -394,6 +420,13 @@ impl Stylist {
///
/// Probably worth to make the stylist own a single `Device`, and have a
/// `update_device` function?
+ ///
+ /// feature = "servo" because gecko only has one device, and manually tracks
+ /// when the device is dirty.
+ ///
+ /// FIXME(emilio): The semantics of the device for Servo and Gecko are
+ /// different enough we may want to unify them.
+ #[cfg(feature = "servo")]
pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc<Stylesheet>]) {
let cascaded_rule = ViewportRule {
declarations: viewport::Cascade::from_stylesheets(stylesheets, &device).finish(),