diff options
Diffstat (limited to 'servo/components/style/stylesheets/page_rule.rs')
-rw-r--r-- | servo/components/style/stylesheets/page_rule.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/servo/components/style/stylesheets/page_rule.rs b/servo/components/style/stylesheets/page_rule.rs new file mode 100644 index 0000000000..5cd2458aa2 --- /dev/null +++ b/servo/components/style/stylesheets/page_rule.rs @@ -0,0 +1,145 @@ +/* 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/. */ + +//! A [`@page`][page] rule. +//! +//! [page]: https://drafts.csswg.org/css2/page.html#page-box + +use crate::parser::{Parse, ParserContext}; +use crate::properties::PropertyDeclarationBlock; +use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked}; +use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; +use crate::str::CssStringWriter; +use crate::values::{AtomIdent, CustomIdent}; +use cssparser::{Parser, SourceLocation}; +#[cfg(feature = "gecko")] +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; +use servo_arc::Arc; +use std::fmt::{self, Write}; +use style_traits::{CssWriter, ParseError, ToCss}; + +/// Type of a single [`@page`][page selector] +/// +/// We do not support pseudo selectors yet. +/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +pub struct PageSelector(pub AtomIdent); + +impl PageSelector { + /// Checks if the ident matches a page-name's ident. + /// + /// This does not currently take pseudo selectors into account. + #[inline] + pub fn ident_matches(&self, other: &CustomIdent) -> bool { + self.0 .0 == other.0 + } +} + +impl Parse for PageSelector { + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + let s = input.expect_ident()?; + Ok(PageSelector(AtomIdent::from(&**s))) + } +} + +/// A list of [`@page`][page selectors] +/// +/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors +#[derive(Clone, Debug, Default, MallocSizeOf, ToCss, ToShmem)] +#[css(comma)] +pub struct PageSelectors(#[css(iterable)] pub Box<[PageSelector]>); + +impl PageSelectors { + /// Creates a new PageSelectors from a Vec, as from parse_comma_separated + #[inline] + pub fn new(s: Vec<PageSelector>) -> Self { + PageSelectors(s.into()) + } + /// Returns true iff there are any page selectors + #[inline] + pub fn is_empty(&self) -> bool { + self.as_slice().is_empty() + } + /// Get the underlying PageSelector data as a slice + #[inline] + pub fn as_slice(&self) -> &[PageSelector] { + &*self.0 + } +} + +impl Parse for PageSelectors { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + Ok(PageSelectors::new(input.parse_comma_separated(|i| { + PageSelector::parse(context, i) + })?)) + } +} + +/// A [`@page`][page] rule. +/// +/// This implements only a limited subset of the CSS +/// 2.2 syntax. +/// +/// [page]: https://drafts.csswg.org/css2/page.html#page-box +/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors +#[derive(Clone, Debug, ToShmem)] +pub struct PageRule { + /// Selectors of the page-rule + pub selectors: PageSelectors, + /// The declaration block this page rule contains. + pub block: Arc<Locked<PropertyDeclarationBlock>>, + /// The source position this rule was found at. + pub source_location: SourceLocation, +} + +impl PageRule { + /// Measure heap usage. + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { + // Measurement of other fields may be added later. + self.block.unconditional_shallow_size_of(ops) + + self.block.read_with(guard).size_of(ops) + + self.selectors.size_of(ops) + } +} + +impl ToCssWithGuard for PageRule { + /// Serialization of PageRule is not specced, adapted from steps for + /// StyleRule. + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result { + dest.write_str("@page ")?; + if !self.selectors.is_empty() { + self.selectors.to_css(&mut CssWriter::new(dest))?; + dest.write_char(' ')?; + } + dest.write_str("{ ")?; + let declaration_block = self.block.read_with(guard); + declaration_block.to_css(dest)?; + if !declaration_block.declarations().is_empty() { + dest.write_char(' ')?; + } + dest.write_char('}') + } +} + +impl DeepCloneWithLock for PageRule { + fn deep_clone_with_lock( + &self, + lock: &SharedRwLock, + guard: &SharedRwLockReadGuard, + _params: &DeepCloneParams, + ) -> Self { + PageRule { + selectors: self.selectors.clone(), + block: Arc::new(lock.wrap(self.block.read_with(&guard).clone())), + source_location: self.source_location.clone(), + } + } +} |