summaryrefslogtreecommitdiffstats
path: root/servo/components/style/gecko/data.rs
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/gecko/data.rs')
-rw-r--r--servo/components/style/gecko/data.rs198
1 files changed, 198 insertions, 0 deletions
diff --git a/servo/components/style/gecko/data.rs b/servo/components/style/gecko/data.rs
new file mode 100644
index 0000000000..c4a5554c5e
--- /dev/null
+++ b/servo/components/style/gecko/data.rs
@@ -0,0 +1,198 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+//! Data needed to style a Gecko document.
+
+use crate::dom::TElement;
+use crate::gecko_bindings::bindings;
+use crate::gecko_bindings::structs::{
+ self, ServoStyleSetSizes, StyleSheet as DomStyleSheet, StyleSheetInfo,
+};
+use crate::invalidation::media_queries::{MediaListKey, ToMediaListKey};
+use crate::media_queries::{Device, MediaList};
+use crate::properties::ComputedValues;
+use crate::selector_parser::SnapshotMap;
+use crate::shared_lock::{SharedRwLockReadGuard, StylesheetGuards};
+use crate::stylesheets::{StylesheetContents, StylesheetInDocument};
+use crate::stylist::Stylist;
+use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
+use malloc_size_of::MallocSizeOfOps;
+use servo_arc::Arc;
+use std::fmt;
+
+/// Little wrapper to a Gecko style sheet.
+#[derive(Eq, PartialEq)]
+pub struct GeckoStyleSheet(*const DomStyleSheet);
+
+// NOTE(emilio): These are kind of a lie. We allow to make these Send + Sync so that other data
+// structures can also be Send and Sync, but Gecko's stylesheets are main-thread-reference-counted.
+//
+// We assert that we reference-count in the right thread (in the Addref/Release implementations).
+// Sending these to a different thread can't really happen (it could theoretically really happen if
+// we allowed @import rules inside a nested style rule, but that can't happen per spec and would be
+// a parser bug, caught by the asserts).
+unsafe impl Send for GeckoStyleSheet {}
+unsafe impl Sync for GeckoStyleSheet {}
+
+impl fmt::Debug for GeckoStyleSheet {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let contents = self.contents();
+ formatter
+ .debug_struct("GeckoStyleSheet")
+ .field("origin", &contents.origin)
+ .field("url_data", &*contents.url_data.read())
+ .finish()
+ }
+}
+
+impl ToMediaListKey for crate::gecko::data::GeckoStyleSheet {
+ fn to_media_list_key(&self) -> MediaListKey {
+ use std::mem;
+ unsafe { MediaListKey::from_raw(mem::transmute(self.0)) }
+ }
+}
+
+impl GeckoStyleSheet {
+ /// Create a `GeckoStyleSheet` from a raw `DomStyleSheet` pointer.
+ #[inline]
+ pub unsafe fn new(s: *const DomStyleSheet) -> Self {
+ debug_assert!(!s.is_null());
+ bindings::Gecko_StyleSheet_AddRef(s);
+ Self::from_addrefed(s)
+ }
+
+ /// Create a `GeckoStyleSheet` from a raw `DomStyleSheet` pointer that
+ /// already holds a strong reference.
+ #[inline]
+ pub unsafe fn from_addrefed(s: *const DomStyleSheet) -> Self {
+ assert!(!s.is_null());
+ GeckoStyleSheet(s)
+ }
+
+ /// HACK(emilio): This is so that we can avoid crashing release due to
+ /// bug 1719963 and can hopefully get a useful report from fuzzers.
+ #[inline]
+ pub fn hack_is_null(&self) -> bool {
+ self.0.is_null()
+ }
+
+ /// Get the raw `StyleSheet` that we're wrapping.
+ pub fn raw(&self) -> &DomStyleSheet {
+ unsafe { &*self.0 }
+ }
+
+ fn inner(&self) -> &StyleSheetInfo {
+ unsafe { &*(self.raw().mInner as *const StyleSheetInfo) }
+ }
+}
+
+impl Drop for GeckoStyleSheet {
+ fn drop(&mut self) {
+ unsafe { bindings::Gecko_StyleSheet_Release(self.0) };
+ }
+}
+
+impl Clone for GeckoStyleSheet {
+ fn clone(&self) -> Self {
+ unsafe { bindings::Gecko_StyleSheet_AddRef(self.0) };
+ GeckoStyleSheet(self.0)
+ }
+}
+
+impl StylesheetInDocument for GeckoStyleSheet {
+ fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
+ use crate::gecko_bindings::structs::mozilla::dom::MediaList as DomMediaList;
+ unsafe {
+ let dom_media_list = self.raw().mMedia.mRawPtr as *const DomMediaList;
+ if dom_media_list.is_null() {
+ return None;
+ }
+ let list = &*(*dom_media_list).mRawList.mRawPtr;
+ Some(list.read_with(guard))
+ }
+ }
+
+ // All the stylesheets Servo knows about are enabled, because that state is
+ // handled externally by Gecko.
+ #[inline]
+ fn enabled(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn contents(&self) -> &StylesheetContents {
+ debug_assert!(!self.inner().mContents.mRawPtr.is_null());
+ unsafe { &*self.inner().mContents.mRawPtr }
+ }
+}
+
+/// The container for data that a Servo-backed Gecko document needs to style
+/// itself.
+pub struct PerDocumentStyleDataImpl {
+ /// Rule processor.
+ pub stylist: Stylist,
+
+ /// A cache from element to resolved style.
+ pub undisplayed_style_cache: crate::traversal::UndisplayedStyleCache,
+
+ /// The generation for which our cache is valid.
+ pub undisplayed_style_cache_generation: u64,
+}
+
+/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
+/// and unexpected races while trying to mutate it.
+pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);
+
+impl PerDocumentStyleData {
+ /// Create a `PerDocumentStyleData`.
+ pub fn new(document: *const structs::Document) -> Self {
+ let device = Device::new(document);
+ let quirks_mode = device.document().mCompatMode;
+
+ PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
+ stylist: Stylist::new(device, quirks_mode.into()),
+ undisplayed_style_cache: Default::default(),
+ undisplayed_style_cache_generation: 0,
+ }))
+ }
+
+ /// Get an immutable reference to this style data.
+ pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
+ self.0.borrow()
+ }
+
+ /// Get an mutable reference to this style data.
+ pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
+ self.0.borrow_mut()
+ }
+}
+
+impl PerDocumentStyleDataImpl {
+ /// Recreate the style data if the stylesheets have changed.
+ pub fn flush_stylesheets<E>(
+ &mut self,
+ guard: &SharedRwLockReadGuard,
+ document_element: Option<E>,
+ snapshots: Option<&SnapshotMap>,
+ ) -> bool
+ where
+ E: TElement,
+ {
+ self.stylist
+ .flush(&StylesheetGuards::same(guard), document_element, snapshots)
+ }
+
+ /// Get the default computed values for this document.
+ pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
+ self.stylist.device().default_computed_values_arc()
+ }
+
+ /// Measure heap usage.
+ pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
+ self.stylist.add_size_of(ops, sizes);
+ }
+}
+
+/// The gecko-specific AuthorStyles instantiation.
+pub type AuthorStyles = crate::author_styles::AuthorStyles<GeckoStyleSheet>;