servo: Merge
#14238 - Implement ToCss serialization for CSSRules (from canaltinova:cssom-tocss); r=Manishearth
<!-- Please describe your changes on the following line: -->
Implementation of ToCss serialization for CSSRules. It requires
#14190 to merge first to uncomment `CssRule::Style` branch in CssRule's ToCss implementation.
r? @Manishearth
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix
#14195 (github issue number if applicable).
- [X] These changes do not require tests because it's serialization changes and I'm not sure there is a test for that.
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Source-Repo:
https://github.com/servo/servo
Source-Revision:
731264f20e1f19687bf0d77fb364568bd1ac034e
--- a/servo/components/script/dom/cssfontfacerule.rs
+++ b/servo/components/script/dom/cssfontfacerule.rs
@@ -7,16 +7,17 @@ use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::font_face::FontFaceRule;
+use style_traits::ToCss;
#[dom_struct]
pub struct CSSFontFaceRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
fontfacerule: Arc<RwLock<FontFaceRule>>,
}
@@ -39,12 +40,11 @@ impl CSSFontFaceRule {
impl SpecificCSSRule for CSSFontFaceRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::FONT_FACE_RULE
}
fn get_css(&self) -> DOMString {
- // self.fontfacerule.read().to_css_string().into()
- "".into()
+ self.fontfacerule.read().to_css_string().into()
}
}
--- a/servo/components/script/dom/csskeyframesrule.rs
+++ b/servo/components/script/dom/csskeyframesrule.rs
@@ -7,16 +7,17 @@ use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::stylesheets::KeyframesRule;
+use style_traits::ToCss;
#[dom_struct]
pub struct CSSKeyframesRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
keyframesrule: Arc<RwLock<KeyframesRule>>,
}
@@ -39,12 +40,11 @@ impl CSSKeyframesRule {
impl SpecificCSSRule for CSSKeyframesRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::KEYFRAMES_RULE
}
fn get_css(&self) -> DOMString {
- // self.keyframesrule.read().to_css_string().into()
- "".into()
+ self.keyframesrule.read().to_css_string().into()
}
}
--- a/servo/components/script/dom/cssmediarule.rs
+++ b/servo/components/script/dom/cssmediarule.rs
@@ -8,16 +8,17 @@ use dom::bindings::reflector::reflect_do
use dom::bindings::str::DOMString;
use dom::cssgroupingrule::CSSGroupingRule;
use dom::cssrule::SpecificCSSRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::stylesheets::MediaRule;
+use style_traits::ToCss;
#[dom_struct]
pub struct CSSMediaRule {
cssrule: CSSGroupingRule,
#[ignore_heap_size_of = "Arc"]
mediarule: Arc<RwLock<MediaRule>>,
}
@@ -40,12 +41,11 @@ impl CSSMediaRule {
impl SpecificCSSRule for CSSMediaRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::MEDIA_RULE
}
fn get_css(&self) -> DOMString {
- // self.mediarule.read().to_css_string().into()
- "".into()
+ self.mediarule.read().to_css_string().into()
}
}
--- a/servo/components/script/dom/cssnamespacerule.rs
+++ b/servo/components/script/dom/cssnamespacerule.rs
@@ -7,16 +7,17 @@ use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::stylesheets::NamespaceRule;
+use style_traits::ToCss;
#[dom_struct]
pub struct CSSNamespaceRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
namespacerule: Arc<RwLock<NamespaceRule>>,
}
@@ -39,12 +40,11 @@ impl CSSNamespaceRule {
impl SpecificCSSRule for CSSNamespaceRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::NAMESPACE_RULE
}
fn get_css(&self) -> DOMString {
- // self.namespacerule.read().to_css_string().into()
- "".into()
+ self.namespacerule.read().to_css_string().into()
}
}
--- a/servo/components/script/dom/cssviewportrule.rs
+++ b/servo/components/script/dom/cssviewportrule.rs
@@ -7,16 +7,17 @@ use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::viewport::ViewportRule;
+use style_traits::ToCss;
#[dom_struct]
pub struct CSSViewportRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
viewportrule: Arc<RwLock<ViewportRule>>,
}
@@ -39,12 +40,11 @@ impl CSSViewportRule {
impl SpecificCSSRule for CSSViewportRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::VIEWPORT_RULE
}
fn get_css(&self) -> DOMString {
- // self.viewportrule.read().to_css_string().into()
- "".into()
+ self.viewportrule.read().to_css_string().into()
}
}
--- a/servo/components/style/font_face.rs
+++ b/servo/components/style/font_face.rs
@@ -5,40 +5,86 @@
//! The [`@font-face`][ff] at-rule.
//!
//! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule
use computed_values::font_family::FontFamily;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use parser::{ParserContext, log_css_error};
use properties::longhands::font_family::parse_one_family;
+use std::fmt;
use std::iter;
+use style_traits::ToCss;
use values::specified::url::SpecifiedUrl;
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub enum Source {
Url(UrlSource),
Local(FontFamily),
}
+impl ToCss for Source {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ Source::Url(ref url) => {
+ try!(dest.write_str("local(\""));
+ try!(url.to_css(dest));
+ },
+ Source::Local(ref family) => {
+ try!(dest.write_str("url(\""));
+ try!(family.to_css(dest));
+ },
+ }
+ dest.write_str("\")")
+ }
+}
+
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub struct UrlSource {
pub url: SpecifiedUrl,
pub format_hints: Vec<String>,
}
+impl ToCss for UrlSource {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ dest.write_str(self.url.as_str())
+ }
+}
+
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontFaceRule {
pub family: FontFamily,
pub sources: Vec<Source>,
}
+impl ToCss for FontFaceRule {
+ // Serialization of FontFaceRule is not specced.
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ try!(dest.write_str("@font-face { font-family: "));
+ try!(self.family.to_css(dest));
+ try!(dest.write_str(";"));
+
+ if self.sources.len() > 0 {
+ try!(dest.write_str(" src: "));
+ let mut iter = self.sources.iter();
+ try!(iter.next().unwrap().to_css(dest));
+ for source in iter {
+ try!(dest.write_str(", "));
+ try!(source.to_css(dest));
+ }
+ try!(dest.write_str(";"));
+ }
+
+ dest.write_str(" }")
+ }
+}
+
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
-> Result<FontFaceRule, ()> {
let mut family = None;
let mut src = None;
let mut iter = DeclarationListParser::new(input, FontFaceRuleParser { context: context });
while let Some(declaration) = iter.next() {
match declaration {
Err(range) => {
--- a/servo/components/style/keyframes.rs
+++ b/servo/components/style/keyframes.rs
@@ -4,17 +4,19 @@
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser};
use parking_lot::RwLock;
use parser::{ParserContext, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::PropertyDeclarationParseResult;
use properties::animated_properties::TransitionProperty;
+use std::fmt;
use std::sync::Arc;
+use style_traits::ToCss;
/// A number from 1 to 100, indicating the percentage of the animation where
/// this keyframe should run.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframePercentage(pub f32);
impl ::std::cmp::Ord for KeyframePercentage {
@@ -77,16 +79,31 @@ pub struct Keyframe {
/// `!important` is not allowed in keyframe declarations,
/// so the second value of these tuples is always `Importance::Normal`.
/// But including them enables `compute_style_for_animation_step` to create a `ApplicableDeclarationBlock`
/// by cloning an `Arc<_>` (incrementing a reference count) rather than re-creating a `Vec<_>`.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub block: Arc<RwLock<PropertyDeclarationBlock>>,
}
+impl ToCss for Keyframe {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ let mut iter = self.selector.percentages().iter();
+ try!(write!(dest, "{}%", iter.next().unwrap().0));
+ for percentage in iter {
+ try!(write!(dest, ", "));
+ try!(write!(dest, "{}%", percentage.0));
+ }
+ try!(dest.write_str(" { "));
+ try!(self.block.read().to_css(dest));
+ try!(dest.write_str(" }"));
+ Ok(())
+ }
+}
+
/// A keyframes step value. This can be a synthetised keyframes animation, that
/// is, one autogenerated from the current computed values, or a list of
/// declarations to apply.
// TODO: Find a better name for this?
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue {
/// See `Keyframe::declarations`’s docs about the presence of `Importance`.
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -102,36 +102,94 @@ impl CssRule {
let mq = media_rule.media_queries.read();
let rules = media_rule.rules.0.read();
f(&rules, Some(&mq))
}
}
}
}
+impl ToCss for CssRule {
+ // https://drafts.csswg.org/cssom/#serialize-a-css-rule
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ CssRule::Namespace(ref lock) => lock.read().to_css(dest),
+ CssRule::Style(ref lock) => lock.read().to_css(dest),
+ CssRule::FontFace(ref lock) => lock.read().to_css(dest),
+ CssRule::Viewport(ref lock) => lock.read().to_css(dest),
+ CssRule::Keyframes(ref lock) => lock.read().to_css(dest),
+ CssRule::Media(ref lock) => lock.read().to_css(dest),
+ }
+ }
+}
+
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct NamespaceRule {
/// `None` for the default Namespace
pub prefix: Option<Prefix>,
pub url: Namespace,
}
+impl ToCss for NamespaceRule {
+ // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ try!(dest.write_str("@namespace "));
+ if let Some(ref prefix) = self.prefix {
+ try!(dest.write_str(&*prefix.to_string()));
+ try!(dest.write_str(" "));
+ }
+ try!(dest.write_str("url(\""));
+ try!(dest.write_str(&*self.url.to_string()));
+ dest.write_str("\");")
+ }
+}
+
#[derive(Debug)]
pub struct KeyframesRule {
pub name: Atom,
pub keyframes: Vec<Arc<RwLock<Keyframe>>>,
}
+impl ToCss for KeyframesRule {
+ // Serialization of KeyframesRule is not specced.
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ try!(dest.write_str("@keyframes "));
+ try!(dest.write_str(&*self.name.to_string()));
+ try!(dest.write_str(" { "));
+ let iter = self.keyframes.iter();
+ for lock in iter {
+ let keyframe = lock.read();
+ try!(keyframe.to_css(dest));
+ }
+ dest.write_str(" }")
+ }
+}
+
#[derive(Debug)]
pub struct MediaRule {
pub media_queries: Arc<RwLock<MediaList>>,
pub rules: CssRules,
}
+impl ToCss for MediaRule {
+ // Serialization of MediaRule is not specced.
+ // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ try!(dest.write_str("@media ("));
+ try!(self.media_queries.read().to_css(dest));
+ try!(dest.write_str(") {"));
+ for rule in self.rules.0.read().iter() {
+ try!(dest.write_str(" "));
+ try!(rule.to_css(dest));
+ }
+ dest.write_str(" }")
+ }
+}
+
#[derive(Debug)]
pub struct StyleRule {
pub selectors: Vec<Selector<TheSelectorImpl>>,
pub block: Arc<RwLock<PropertyDeclarationBlock>>,
}
impl StyleRule {
/// Serialize the group of selectors for this rule.
--- a/servo/components/style/values/specified/url.rs
+++ b/servo/components/style/values/specified/url.rs
@@ -99,16 +99,23 @@ impl SpecifiedUrl {
pub fn extra_data(&self) -> &UrlExtraData {
&self.extra_data
}
pub fn url(&self) -> Option<&ServoUrl> {
self.resolved.as_ref()
}
+ pub fn as_str(&self) -> &str {
+ match self.resolved {
+ Some(ref url) => url.as_str(),
+ None => "",
+ }
+ }
+
/// Little helper for Gecko's ffi.
pub fn as_slice_components(&self) -> (*const u8, usize) {
match self.resolved {
Some(ref url) => (url.as_str().as_ptr(), url.as_str().len()),
None => (ptr::null(), 0),
}
}
--- a/servo/components/style/viewport.rs
+++ b/servo/components/style/viewport.rs
@@ -4,16 +4,17 @@
//! The [`@viewport`][at] at-rule and [`meta`][meta] element.
//!
//! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule
//! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta
use app_units::Au;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
+use cssparser::ToCss as ParserToCss;
use euclid::scale_factor::ScaleFactor;
use euclid::size::{Size2D, TypedSize2D};
use media_queries::Device;
use parser::{ParserContext, log_css_error};
use properties::ComputedValues;
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::fmt;
@@ -21,42 +22,44 @@ use std::iter::Enumerate;
use std::str::Chars;
use style_traits::{ToCss, ViewportPx};
use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
use stylesheets::{Stylesheet, Origin};
use values::computed::{Context, ToComputedValue};
use values::specified::{Length, LengthOrPercentageOrAuto, ViewportPercentageLength};
macro_rules! declare_viewport_descriptor {
- ( $( $variant: ident($data: ident), )+ ) => {
- declare_viewport_descriptor_inner!([] [ $( $variant($data), )+ ] 0);
+ ( $( $variant_name: expr => $variant: ident($data: ident), )+ ) => {
+ declare_viewport_descriptor_inner!([] [ $( $variant_name => $variant($data), )+ ] 0);
};
}
macro_rules! declare_viewport_descriptor_inner {
(
- [ $( $assigned_variant: ident($assigned_data: ident) = $assigned_discriminant: expr, )* ]
+ [ $( $assigned_variant_name: expr =>
+ $assigned_variant: ident($assigned_data: ident) = $assigned_discriminant: expr, )* ]
[
- $next_variant: ident($next_data: ident),
- $( $variant: ident($data: ident), )*
+ $next_variant_name: expr => $next_variant: ident($next_data: ident),
+ $( $variant_name: expr => $variant: ident($data: ident), )*
]
$next_discriminant: expr
) => {
declare_viewport_descriptor_inner! {
[
- $( $assigned_variant($assigned_data) = $assigned_discriminant, )*
- $next_variant($next_data) = $next_discriminant,
+ $( $assigned_variant_name => $assigned_variant($assigned_data) = $assigned_discriminant, )*
+ $next_variant_name => $next_variant($next_data) = $next_discriminant,
]
- [ $( $variant($data), )* ]
+ [ $( $variant_name => $variant($data), )* ]
$next_discriminant + 1
}
};
(
- [ $( $assigned_variant: ident($assigned_data: ident) = $assigned_discriminant: expr, )* ]
+ [ $( $assigned_variant_name: expr =>
+ $assigned_variant: ident($assigned_data: ident) = $assigned_discriminant: expr, )* ]
[ ]
$number_of_variants: expr
) => {
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum ViewportDescriptor {
$(
$assigned_variant($assigned_data),
@@ -69,32 +72,47 @@ macro_rules! declare_viewport_descriptor
fn discriminant_value(&self) -> usize {
match *self {
$(
ViewportDescriptor::$assigned_variant(..) => $assigned_discriminant,
)*
}
}
}
+
+ impl ToCss for ViewportDescriptor {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ $(
+ ViewportDescriptor::$assigned_variant(val) => {
+ try!(dest.write_str($assigned_variant_name));
+ try!(dest.write_str(": "));
+ try!(val.to_css(dest));
+ },
+ )*
+ }
+ dest.write_str(";")
+ }
+ }
};
}
declare_viewport_descriptor! {
- MinWidth(ViewportLength),
- MaxWidth(ViewportLength),
+ "min-width" => MinWidth(ViewportLength),
+ "max-width" => MaxWidth(ViewportLength),
- MinHeight(ViewportLength),
- MaxHeight(ViewportLength),
+ "min-height" => MinHeight(ViewportLength),
+ "max-height" => MaxHeight(ViewportLength),
- Zoom(Zoom),
- MinZoom(Zoom),
- MaxZoom(Zoom),
+ "zoom" => Zoom(Zoom),
+ "min-zoom" => MinZoom(Zoom),
+ "max-zoom" => MaxZoom(Zoom),
- UserZoom(UserZoom),
- Orientation(Orientation),
+ "user-zoom" => UserZoom(UserZoom),
+ "orientation" => Orientation(Orientation),
}
trait FromMeta: Sized {
fn from_meta(value: &str) -> Option<Self>;
}
// ViewportLength is a length | percentage | auto | extend-to-zoom
// See:
@@ -205,16 +223,26 @@ impl ViewportDescriptorDeclaration {
ViewportDescriptorDeclaration {
origin: origin,
descriptor: descriptor,
important: important
}
}
}
+impl ToCss for ViewportDescriptorDeclaration {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ try!(self.descriptor.to_css(dest));
+ if self.important {
+ try!(dest.write_str(" !important"));
+ }
+ dest.write_str(";")
+ }
+}
+
fn parse_shorthand(input: &mut Parser) -> Result<[ViewportLength; 2], ()> {
let min = try!(ViewportLength::parse(input));
match input.try(|input| ViewportLength::parse(input)) {
Err(()) => Ok([min, min]),
Ok(max) => Ok([min, max])
}
}
@@ -462,16 +490,30 @@ impl ViewportRule {
Some((end, _)) => &content[start..end],
_ => &content[start..]
};
Some((name, value))
}
}
+impl ToCss for ViewportRule {
+ // Serialization of ViewportRule is not specced.
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ try!(dest.write_str("@viewport { "));
+ let mut iter = self.declarations.iter();
+ try!(iter.next().unwrap().to_css(dest));
+ for declaration in iter {
+ try!(dest.write_str(" "));
+ try!(declaration.to_css(dest));
+ }
+ dest.write_str(" }")
+ }
+}
+
/// Computes the cascade precedence as according to
/// http://dev.w3.org/csswg/css-cascade/#cascade-origin
fn cascade_precendence(origin: Origin, important: bool) -> u8 {
match (origin, important) {
(Origin::UserAgent, true) => 1,
(Origin::User, true) => 2,
(Origin::Author, true) => 3,
(Origin::Author, false) => 4,