auto merge of #4342 : jdm/servo/cssom, r=jdm,metajack

This does not implement any notion of CSSStyleDeclaration objects that do not have an owning element; there's no actual CSS object model in play here. This does support setting and getting properties of the style attribute for HTMLElement, and tries to implement the ambiguous CSS value serialization spec.
This commit is contained in:
bors-servo 2014-12-18 11:54:52 -07:00
commit 824788649c
16 changed files with 1705 additions and 47 deletions

View file

@ -6,6 +6,7 @@
//! `<input size>`, and so forth.
use node::{TElement, TElementAttributes, TNode};
use properties::common_types::specified::CSSColor;
use properties::DeclaredValue::SpecifiedValue;
use properties::PropertyDeclaration::*;
use properties::{CSSFloat, specified};
@ -211,7 +212,7 @@ impl PresentationalHintSynthesis for Stylist {
None => {}
Some(color) => {
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
BackgroundColorDeclaration(SpecifiedValue(Color::RGBA(color)))));
BackgroundColorDeclaration(SpecifiedValue(CSSColor { parsed: Color::RGBA(color), authored: None }))));
*shareable = false
}
}

View file

@ -5,7 +5,7 @@
#![comment = "The Servo Parallel Browser Project"]
#![license = "MPL"]
#![feature(globs, macro_rules)]
#![feature(globs, macro_rules, if_let)]
#![deny(unused_imports)]
#![deny(unused_variables)]
@ -42,7 +42,8 @@ pub use selector_matching::{CommonStyleAffectingAttributeInfo, CommonStyleAffect
pub use selector_matching::{matches, matches_simple_selector, common_style_affecting_attributes};
pub use selector_matching::{rare_style_affecting_attributes};
pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE};
pub use properties::{cascade, cascade_anonymous, computed};
pub use properties::{cascade, cascade_anonymous, computed, longhands_from_shorthand};
pub use properties::is_supported_property;
pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult};

View file

@ -13,14 +13,71 @@ pub type CSSFloat = f64;
pub mod specified {
use std::ascii::AsciiExt;
use std::f64::consts::PI;
use std::fmt;
use std::fmt::{Formatter, FormatError, Show};
use url::Url;
use cssparser;
use cssparser::ast;
use cssparser::ast::*;
use parsing_utils::{mod, BufferedIter, ParserIter};
use super::{Au, CSSFloat};
pub use cssparser::Color as CSSColor;
#[deriving(Clone, Show)]
#[deriving(Clone, PartialEq)]
pub struct CSSColor {
pub parsed: cssparser::Color,
pub authored: Option<String>,
}
impl CSSColor {
pub fn parse(component_value: &ComponentValue) -> Result<CSSColor, ()> {
let parsed = cssparser::Color::parse(component_value);
parsed.map(|parsed| {
let authored = match component_value {
&Ident(ref s) => Some(s.clone()),
_ => None,
};
CSSColor {
parsed: parsed,
authored: authored,
}
})
}
}
impl fmt::Show for CSSColor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.authored {
Some(ref s) => write!(f, "{}", s),
None => write!(f, "{}", self.parsed),
}
}
}
#[deriving(Clone)]
pub struct CSSRGBA {
pub parsed: cssparser::RGBA,
pub authored: Option<String>,
}
impl fmt::Show for CSSRGBA {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.authored {
Some(ref s) => write!(f, "{}", s),
None => write!(f, "{}", self.parsed),
}
}
}
#[deriving(Clone, PartialEq)]
pub struct CSSImage(pub Option<Image>);
impl fmt::Show for CSSImage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let &CSSImage(ref url) = self;
match url {
&Some(ref image) => write!(f, "{}", image),
&None => write!(f, "none"),
}
}
}
#[deriving(Clone, PartialEq)]
pub enum Length {
Au(Au), // application units
Em(CSSFloat),
@ -40,6 +97,17 @@ pub mod specified {
// Vmin(CSSFloat),
// Vmax(CSSFloat),
}
impl fmt::Show for Length {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
&Length::Au(length) => write!(f, "{}", length),
&Length::Em(length) => write!(f, "{}em", length),
&Length::Ex(length) => write!(f, "{}ex", length),
&Length::Rem(length) => write!(f, "{}rem", length),
&Length::ServoCharacterWidth(_) => panic!("internal CSS values should never be serialized"),
}
}
}
const AU_PER_PX: CSSFloat = 60.;
const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
@ -83,12 +151,19 @@ pub mod specified {
}
}
#[deriving(Clone, Show)]
#[deriving(Clone, PartialEq)]
pub enum LengthOrPercentage {
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
}
impl fmt::Show for LengthOrPercentage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&LengthOrPercentage::Length(length) => write!(f, "{}", length),
&LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
}
}
}
impl LengthOrPercentage {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentage, ()> {
@ -120,6 +195,15 @@ pub mod specified {
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Auto,
}
impl fmt::Show for LengthOrPercentageOrAuto {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&LengthOrPercentageOrAuto::Length(length) => write!(f, "{}", length),
&LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
&LengthOrPercentageOrAuto::Auto => write!(f, "auto"),
}
}
}
impl LengthOrPercentageOrAuto {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentageOrAuto, ()> {
@ -151,6 +235,15 @@ pub mod specified {
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
None,
}
impl fmt::Show for LengthOrPercentageOrNone {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&LengthOrPercentageOrNone::Length(length) => write!(f, "{}", length),
&LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
&LengthOrPercentageOrNone::None => write!(f, "none"),
}
}
}
impl LengthOrPercentageOrNone {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentageOrNone, ()> {
@ -219,6 +312,13 @@ pub mod specified {
#[deriving(Clone, PartialEq, PartialOrd)]
pub struct Angle(pub CSSFloat);
impl Show for Angle {
fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
let Angle(value) = *self;
write!(f, "{}", value)
}
}
impl Angle {
pub fn radians(self) -> f64 {
let Angle(radians) = self;
@ -247,12 +347,21 @@ pub mod specified {
}
/// Specified values for an image according to CSS-IMAGES.
#[deriving(Clone)]
#[deriving(Clone, PartialEq)]
pub enum Image {
Url(Url),
LinearGradient(LinearGradient),
}
impl Show for Image {
fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
match self {
&Image::Url(ref url) => write!(f, "url(\"{}\")", url),
&Image::LinearGradient(ref grad) => write!(f, "linear-gradient({})", grad),
}
}
}
impl Image {
pub fn from_component_value(component_value: &ComponentValue, base_url: &Url)
-> Result<Image,()> {
@ -287,7 +396,7 @@ pub mod specified {
}
/// Specified values for a CSS linear gradient.
#[deriving(Clone)]
#[deriving(Clone, PartialEq)]
pub struct LinearGradient {
/// The angle or corner of the gradient.
pub angle_or_corner: AngleOrCorner,
@ -296,6 +405,16 @@ pub mod specified {
pub stops: Vec<ColorStop>,
}
impl Show for LinearGradient {
fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
let _ = write!(f, "{}", self.angle_or_corner);
for stop in self.stops.iter() {
let _ = write!(f, ", {}", stop);
}
Ok(())
}
}
/// Specified values for an angle or a corner in a linear gradient.
#[deriving(Clone, PartialEq)]
pub enum AngleOrCorner {
@ -303,8 +422,17 @@ pub mod specified {
Corner(HorizontalDirection, VerticalDirection),
}
impl Show for AngleOrCorner {
fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
match self {
&AngleOrCorner::Angle(angle) => write!(f, "{}", angle),
&AngleOrCorner::Corner(horiz, vert) => write!(f, "to {} {}", horiz, vert),
}
}
}
/// Specified values for one color stop in a linear gradient.
#[deriving(Clone)]
#[deriving(Clone, PartialEq)]
pub struct ColorStop {
/// The color of this stop.
pub color: CSSColor,
@ -314,18 +442,46 @@ pub mod specified {
pub position: Option<LengthOrPercentage>,
}
impl Show for ColorStop {
fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
let _ = write!(f, "{}", self.color);
self.position.map(|pos| {
let _ = write!(f, " {}", pos);
});
Ok(())
}
}
#[deriving(Clone, PartialEq)]
pub enum HorizontalDirection {
Left,
Right,
}
impl Show for HorizontalDirection {
fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
match self {
&HorizontalDirection::Left => write!(f, "left"),
&HorizontalDirection::Right => write!(f, "right"),
}
}
}
#[deriving(Clone, PartialEq)]
pub enum VerticalDirection {
Top,
Bottom,
}
impl Show for VerticalDirection {
fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
match self {
&VerticalDirection::Top => write!(f, "top"),
&VerticalDirection::Bottom => write!(f, "bottom"),
}
}
}
fn parse_color_stop(source: ParserIter) -> Result<ColorStop,()> {
let color = match source.next() {
Some(color) => try!(CSSColor::parse(color)),
@ -463,9 +619,9 @@ pub mod computed {
pub use super::specified::{Angle, AngleOrCorner, HorizontalDirection};
pub use super::specified::{VerticalDirection};
pub use cssparser::Color as CSSColor;
pub use super::super::longhands::computed_as_specified as compute_CSSColor;
use super::*;
use super::super::longhands;
use std::fmt;
use url::Url;
pub struct Context {
@ -488,6 +644,12 @@ pub mod computed {
// TODO, as needed: viewport size, etc.
}
#[allow(non_snake_case)]
#[inline]
pub fn compute_CSSColor(value: specified::CSSColor, _context: &computed::Context) -> CSSColor {
value.parsed
}
#[allow(non_snake_case)]
#[inline]
pub fn compute_Au(value: specified::Length, context: &Context) -> Au {
@ -518,11 +680,19 @@ pub mod computed {
}
}
#[deriving(PartialEq, Clone, Show)]
#[deriving(PartialEq, Clone)]
pub enum LengthOrPercentage {
Length(Au),
Percentage(CSSFloat),
}
impl fmt::Show for LengthOrPercentage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&LengthOrPercentage::Length(length) => write!(f, "{}", length),
&LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
}
}
}
#[allow(non_snake_case)]
pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
@ -535,12 +705,21 @@ pub mod computed {
}
}
#[deriving(PartialEq, Clone, Show)]
#[deriving(PartialEq, Clone)]
pub enum LengthOrPercentageOrAuto {
Length(Au),
Percentage(CSSFloat),
Auto,
}
impl fmt::Show for LengthOrPercentageOrAuto {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&LengthOrPercentageOrAuto::Length(length) => write!(f, "{}", length),
&LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
&LengthOrPercentageOrAuto::Auto => write!(f, "auto"),
}
}
}
#[allow(non_snake_case)]
pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
context: &Context) -> LengthOrPercentageOrAuto {
@ -554,12 +733,21 @@ pub mod computed {
}
}
#[deriving(PartialEq, Clone, Show)]
#[deriving(PartialEq, Clone)]
pub enum LengthOrPercentageOrNone {
Length(Au),
Percentage(CSSFloat),
None,
}
impl fmt::Show for LengthOrPercentageOrNone {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&LengthOrPercentageOrNone::Length(length) => write!(f, "{}", length),
&LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
&LengthOrPercentageOrNone::None => write!(f, "none"),
}
}
}
#[allow(non_snake_case)]
pub fn compute_LengthOrPercentageOrNone(value: specified::LengthOrPercentageOrNone,
context: &Context) -> LengthOrPercentageOrNone {
@ -580,6 +768,15 @@ pub mod computed {
LinearGradient(LinearGradient),
}
impl fmt::Show for Image {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Image::Url(ref url) => write!(f, "url(\"{}\")", url),
&Image::LinearGradient(ref grad) => write!(f, "linear-gradient({})", grad),
}
}
}
/// Computed values for a CSS linear gradient.
#[deriving(Clone, PartialEq)]
pub struct LinearGradient {
@ -590,6 +787,16 @@ pub mod computed {
pub stops: Vec<ColorStop>,
}
impl fmt::Show for LinearGradient {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let _ = write!(f, "{}", self.angle_or_corner);
for stop in self.stops.iter() {
let _ = write!(f, ", {}", stop);
}
Ok(())
}
}
/// Computed values for one color stop in a linear gradient.
#[deriving(Clone, PartialEq)]
pub struct ColorStop {
@ -601,6 +808,16 @@ pub mod computed {
pub position: Option<LengthOrPercentage>,
}
impl fmt::Show for ColorStop {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let _ = write!(f, "{}", self.color);
self.position.map(|pos| {
let _ = write!(f, " {}", pos);
});
Ok(())
}
}
impl LinearGradient {
pub fn compute(value: specified::LinearGradient, context: &Context) -> LinearGradient {
let specified::LinearGradient {
@ -611,7 +828,7 @@ pub mod computed {
angle_or_corner: angle_or_corner,
stops: stops.into_iter().map(|stop| {
ColorStop {
color: stop.color,
color: stop.color.parsed,
position: match stop.position {
None => None,
Some(value) => Some(compute_LengthOrPercentage(value, context)),

View file

@ -5,6 +5,8 @@
// This file is a Mako template: http://www.makotemplates.org/
pub use std::ascii::AsciiExt;
use std::fmt;
use std::fmt::Show;
use servo_util::logical_geometry::{WritingMode, LogicalMargin};
use sync::Arc;
@ -159,13 +161,23 @@ pub mod longhands {
<%self:single_component_value name="${name}" experimental="${experimental}">
${caller.body()}
pub mod computed_value {
use std::fmt;
#[allow(non_camel_case_types)]
#[deriving(PartialEq, Clone, FromPrimitive, Show)]
#[deriving(PartialEq, Clone, FromPrimitive)]
pub enum T {
% for value in values.split():
${to_rust_ident(value)},
% endfor
}
impl fmt::Show for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
% for value in values.split():
&T::${to_rust_ident(value)} => write!(f, "${value}"),
% endfor
}
}
}
}
pub type SpecifiedValue = computed_value::T;
#[inline] pub fn get_initial_value() -> computed_value::T {
@ -455,11 +467,21 @@ pub mod longhands {
pub use super::computed_as_specified as to_computed_value;
pub type SpecifiedValue = computed_value::T;
pub mod computed_value {
use std::fmt;
#[deriving(PartialEq, Clone)]
pub enum T {
Auto,
Number(i32),
}
impl fmt::Show for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&T::Auto => write!(f, "auto"),
&T::Number(number) => write!(f, "{}", number),
}
}
}
impl T {
pub fn number_or_zero(self) -> i32 {
@ -538,12 +560,23 @@ pub mod longhands {
${switch_to_style_struct("InheritedBox")}
<%self:single_component_value name="line-height">
use std::fmt;
#[deriving(Clone)]
pub enum SpecifiedValue {
Normal,
Length(specified::Length),
Number(CSSFloat),
// percentage are the same as em.
Percentage(CSSFloat),
}
impl fmt::Show for SpecifiedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&SpecifiedValue::Normal => write!(f, "normal"),
&SpecifiedValue::Length(length) => write!(f, "{}", length),
&SpecifiedValue::Number(number) => write!(f, "{}", number),
&SpecifiedValue::Percentage(number) => write!(f, "{}%", number * 100.),
}
}
}
/// normal | <number> | <length> | <percentage>
pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
@ -552,7 +585,7 @@ pub mod longhands {
&ast::Number(ref value) if value.value >= 0. =>
Ok(SpecifiedValue::Number(value.value)),
&ast::Percentage(ref value) if value.value >= 0. =>
Ok(SpecifiedValue::Length(specified::Length::Em(value.value / 100.))),
Ok(SpecifiedValue::Percentage(value.value / 100.)),
&Dimension(ref value, ref unit) if value.value >= 0. =>
specified::Length::parse_dimension(value.value, unit.as_slice())
.map(SpecifiedValue::Length),
@ -563,12 +596,22 @@ pub mod longhands {
}
pub mod computed_value {
use super::super::{Au, CSSFloat};
use std::fmt;
#[deriving(PartialEq, Clone)]
pub enum T {
Normal,
Length(Au),
Number(CSSFloat),
}
impl fmt::Show for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&T::Normal => write!(f, "normal"),
&T::Length(length) => write!(f, "{}%", length),
&T::Number(number) => write!(f, "{}", number),
}
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T { T::Normal }
@ -579,6 +622,7 @@ pub mod longhands {
SpecifiedValue::Normal => T::Normal,
SpecifiedValue::Length(value) => T::Length(computed::compute_Au(value, context)),
SpecifiedValue::Number(value) => T::Number(value),
SpecifiedValue::Percentage(value) => T::Length(computed::compute_Au(specified::Length::Em(value), context)),
}
}
</%self:single_component_value>
@ -586,6 +630,7 @@ pub mod longhands {
${switch_to_style_struct("Box")}
<%self:single_component_value name="vertical-align">
use std::fmt;
<% vertical_align_keywords = (
"baseline sub super top text-top middle bottom text-bottom".split()) %>
#[allow(non_camel_case_types)]
@ -596,6 +641,16 @@ pub mod longhands {
% endfor
LengthOrPercentage(specified::LengthOrPercentage),
}
impl fmt::Show for SpecifiedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
% for keyword in vertical_align_keywords:
&SpecifiedValue::${to_rust_ident(keyword)} => write!(f, "${keyword}"),
% endfor
&SpecifiedValue::LengthOrPercentage(lop) => write!(f, "{}", lop),
}
}
}
/// baseline | sub | super | top | text-top | middle | bottom | text-bottom
/// | <percentage> | <length>
pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
@ -615,6 +670,7 @@ pub mod longhands {
}
pub mod computed_value {
use super::super::{Au, CSSFloat};
use std::fmt;
#[allow(non_camel_case_types)]
#[deriving(PartialEq, Clone)]
pub enum T {
@ -624,6 +680,17 @@ pub mod longhands {
Length(Au),
Percentage(CSSFloat),
}
impl fmt::Show for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
% for keyword in vertical_align_keywords:
&T::${to_rust_ident(keyword)} => write!(f, "${keyword}"),
% endfor
&T::Length(length) => write!(f, "{}", length),
&T::Percentage(number) => write!(f, "{}%", number),
}
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T { T::baseline }
@ -660,10 +727,18 @@ pub mod longhands {
<%self:longhand name="content">
pub use super::computed_as_specified as to_computed_value;
pub mod computed_value {
use std::fmt;
#[deriving(PartialEq, Clone)]
pub enum ContentItem {
StringContent(String),
}
impl fmt::Show for ContentItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ContentItem::StringContent(ref s) => write!(f, "\"{}\"", s),
}
}
}
#[allow(non_camel_case_types)]
#[deriving(PartialEq, Clone)]
pub enum T {
@ -671,6 +746,20 @@ pub mod longhands {
none,
Content(Vec<ContentItem>),
}
impl fmt::Show for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&T::normal => write!(f, "normal"),
&T::none => write!(f, "none"),
&T::Content(ref content) => {
for c in content.iter() {
let _ = write!(f, "{}", c);
}
Ok(())
}
}
}
}
}
pub type SpecifiedValue = computed_value::T;
#[inline] pub fn get_initial_value() -> computed_value::T { T::normal }
@ -748,13 +837,13 @@ pub mod longhands {
<%self:single_component_value name="background-image">
use super::common_types::specified as common_specified;
use super::super::common_types::specified::CSSImage as CSSImage;
pub mod computed_value {
use super::super::super::common_types::computed;
#[deriving(Clone, PartialEq)]
pub type T = Option<computed::Image>;
}
#[deriving(Clone)]
pub type SpecifiedValue = Option<common_specified::Image>;
pub type SpecifiedValue = common_specified::CSSImage;
#[inline]
pub fn get_initial_value() -> computed_value::T {
None
@ -763,13 +852,13 @@ pub mod longhands {
-> Result<SpecifiedValue, ()> {
match component_value {
&ast::Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => {
Ok(None)
Ok(CSSImage(None))
}
_ => {
match common_specified::Image::from_component_value(component_value,
base_url) {
Err(err) => Err(err),
Ok(result) => Ok(Some(result)),
Ok(result) => Ok(CSSImage(Some(result))),
}
}
}
@ -777,21 +866,29 @@ pub mod longhands {
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T {
match value {
None => None,
Some(image) => Some(image.to_computed_value(context)),
CSSImage(None) => None,
CSSImage(Some(image)) => Some(image.to_computed_value(context)),
}
}
</%self:single_component_value>
<%self:longhand name="background-position">
use std::fmt;
pub mod computed_value {
use super::super::super::common_types::computed::LengthOrPercentage;
use std::fmt;
#[deriving(PartialEq, Clone)]
pub struct T {
pub horizontal: LengthOrPercentage,
pub vertical: LengthOrPercentage,
}
impl fmt::Show for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.horizontal, self.vertical)
}
}
}
#[deriving(Clone)]
@ -799,6 +896,11 @@ pub mod longhands {
pub horizontal: specified::LengthOrPercentage,
pub vertical: specified::LengthOrPercentage,
}
impl fmt::Show for SpecifiedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.horizontal, self.vertical)
}
}
impl SpecifiedValue {
fn new(first: specified::PositionComponent, second: specified::PositionComponent)
@ -902,19 +1004,32 @@ pub mod longhands {
${new_style_struct("Color", is_inherited=True)}
<%self:raw_longhand name="color">
pub use super::computed_as_specified as to_computed_value;
pub type SpecifiedValue = RGBA;
use super::super::common_types::specified::{CSSColor, CSSRGBA};
#[inline]
pub fn to_computed_value(value: SpecifiedValue, _context: &computed::Context)
-> computed_value::T {
value.parsed
}
pub type SpecifiedValue = CSSRGBA;
pub mod computed_value {
pub type T = super::SpecifiedValue;
use cssparser;
pub type T = cssparser::RGBA;
}
#[inline] pub fn get_initial_value() -> computed_value::T {
RGBA { red: 0., green: 0., blue: 0., alpha: 1. } /* black */
}
pub fn parse_specified(input: &[ComponentValue], _base_url: &Url)
-> Result<DeclaredValue<SpecifiedValue>, ()> {
match one_component_value(input).and_then(Color::parse) {
Ok(Color::RGBA(rgba)) => Ok(DeclaredValue::SpecifiedValue(rgba)),
Ok(Color::CurrentColor) => Ok(DeclaredValue::Inherit),
match one_component_value(input).and_then(CSSColor::parse) {
Ok(CSSColor { parsed: Color::RGBA(rgba), authored }) => {
let rgba = CSSRGBA {
parsed: rgba,
authored: authored,
};
Ok(DeclaredValue::SpecifiedValue(rgba))
}
Ok(CSSColor { parsed: Color::CurrentColor, .. }) => Ok(DeclaredValue::Inherit),
Err(()) => Err(()),
}
}
@ -927,6 +1042,7 @@ pub mod longhands {
<%self:longhand name="font-family">
pub use super::computed_as_specified as to_computed_value;
pub mod computed_value {
use std::fmt;
#[deriving(PartialEq, Clone)]
pub enum FontFamily {
FamilyName(String),
@ -944,7 +1060,22 @@ pub mod longhands {
}
}
}
impl fmt::Show for FontFamily {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&FontFamily::FamilyName(ref name) => write!(f, "{}", name),
}
}
}
pub type T = Vec<FontFamily>;
/*impl fmt::Show for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for font in self.iter() {
write!(f, "{}", font);
}
Ok(())
}
}*/
}
pub type SpecifiedValue = computed_value::T;
@ -998,6 +1129,7 @@ pub mod longhands {
${single_keyword("font-variant", "normal small-caps")}
<%self:single_component_value name="font-weight">
use std::fmt;
#[deriving(Clone)]
pub enum SpecifiedValue {
Bolder,
@ -1006,6 +1138,17 @@ pub mod longhands {
SpecifiedWeight${weight},
% endfor
}
impl fmt::Show for SpecifiedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&SpecifiedValue::Bolder => write!(f, "bolder"),
&SpecifiedValue::Lighter => write!(f, "lighter"),
% for weight in range(100, 901, 100):
&SpecifiedValue::SpecifiedWeight${weight} => write!(f, "{}", ${weight}i),
% endfor
}
}
}
/// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Result<SpecifiedValue, ()> {
@ -1035,12 +1178,22 @@ pub mod longhands {
}
}
pub mod computed_value {
use std::fmt;
#[deriving(PartialEq, Clone)]
pub enum T {
% for weight in range(100, 901, 100):
Weight${weight},
% endfor
}
impl fmt::Show for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
% for weight in range(100, 901, 100):
&T::Weight${weight} => write!(f, "{}", ${weight}i),
% endfor
}
}
}
impl T {
pub fn is_bold(self) -> bool {
match self {
@ -1193,6 +1346,7 @@ pub mod longhands {
<%self:longhand name="text-decoration">
pub use super::computed_as_specified as to_computed_value;
use std::fmt;
#[deriving(PartialEq, Clone)]
pub struct SpecifiedValue {
pub underline: bool,
@ -1201,6 +1355,29 @@ pub mod longhands {
// 'blink' is accepted in the parser but ignored.
// Just not blinking the text is a conforming implementation per CSS 2.1.
}
impl fmt::Show for SpecifiedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut space = false;
if self.underline {
let _ = write!(f, "underline");
space = true;
}
if self.overline {
if space {
let _ = write!(f, " ");
}
let _ = write!(f, "overline");
space = true;
}
if self.line_through {
if space {
let _ = write!(f, " ");
}
let _ = write!(f, "line-through");
}
Ok(())
}
}
pub mod computed_value {
pub type T = super::SpecifiedValue;
#[allow(non_upper_case_globals)]
@ -1518,6 +1695,7 @@ pub mod longhands {
<%self:longhand name="box-shadow">
use cssparser;
use std::fmt;
pub type SpecifiedValue = Vec<SpecifiedBoxShadow>;
@ -1531,9 +1709,24 @@ pub mod longhands {
pub inset: bool,
}
impl fmt::Show for SpecifiedBoxShadow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.inset {
let _ = write!(f, "inset ");
}
let _ = write!(f, "{} {} {} {}", self.offset_x, self.offset_y,
self.blur_radius, self.spread_radius);
if let Some(ref color) = self.color {
let _ = write!(f, "{}", color);
}
Ok(())
}
}
pub mod computed_value {
use super::super::Au;
use super::super::super::computed;
use std::fmt;
pub type T = Vec<BoxShadow>;
@ -1546,6 +1739,17 @@ pub mod longhands {
pub color: computed::CSSColor,
pub inset: bool,
}
impl fmt::Show for BoxShadow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.inset {
let _ = write!(f, "inset ");
}
let _ = write!(f, "{} {} {} {} {}", self.offset_x, self.offset_y,
self.blur_radius, self.spread_radius, self.color);
Ok(())
}
}
}
#[inline]
@ -1571,7 +1775,7 @@ pub mod longhands {
offset_y: computed::compute_Au(value.offset_y, context),
blur_radius: computed::compute_Au(value.blur_radius, context),
spread_radius: computed::compute_Au(value.spread_radius, context),
color: value.color.unwrap_or(cssparser::Color::CurrentColor),
color: value.color.map(|color| color.parsed).unwrap_or(cssparser::Color::CurrentColor),
inset: value.inset,
}
}).collect()
@ -1627,8 +1831,8 @@ pub mod longhands {
// Try to parse a color.
match specified::CSSColor::parse(value) {
Ok(the_color) if color.is_none() => {
color = Some(the_color);
Ok(ref the_color) if color.is_none() => {
color = Some(the_color.clone());
continue
}
Ok(_) => return Err(()),
@ -1693,9 +1897,9 @@ pub mod shorthands {
// three values set top, (left, right) and bottom
// four values set them in order
let top = iter.next().unwrap_or(None);
let right = iter.next().unwrap_or(top);
let bottom = iter.next().unwrap_or(top);
let left = iter.next().unwrap_or(right);
let right = iter.next().unwrap_or(top.clone());
let bottom = iter.next().unwrap_or(top.clone());
let left = iter.next().unwrap_or(right.clone());
if top.is_some() && right.is_some() && bottom.is_some() && left.is_some()
&& iter.next().is_none() {
Ok(Longhands {
@ -1896,7 +2100,7 @@ pub mod shorthands {
Longhands {
% for side in ["top", "right", "bottom", "left"]:
% for prop in ["color", "style", "width"]:
${"border_%s_%s: %s," % (side, prop, prop)}
${"border_%s_%s: %s.clone()," % (side, prop, prop)}
% endfor
% endfor
}
@ -2314,6 +2518,16 @@ pub enum DeclaredValue<T> {
// depending on whether the property is inherited.
}
impl<T: Show> DeclaredValue<T> {
pub fn specified_value(&self) -> Option<String> {
match self {
&DeclaredValue::SpecifiedValue(ref inner) => Some(format!("{}", inner)),
&DeclaredValue::Initial => None,
&DeclaredValue::Inherit => Some("inherit".to_string()),
}
}
}
#[deriving(Clone)]
pub enum PropertyDeclaration {
% for property in LONGHANDS:
@ -2329,8 +2543,43 @@ pub enum PropertyDeclarationParseResult {
ValidOrIgnoredDeclaration,
}
impl PropertyDeclaration {
pub fn name(&self) -> String {
match self {
% for property in LONGHANDS:
% if property.derived_from is None:
&PropertyDeclaration::${property.camel_case}Declaration(..) => "${property.name}".to_string(),
% endif
% endfor
_ => "".to_string(),
}
}
pub fn value(&self) -> String {
match self {
% for property in LONGHANDS:
% if property.derived_from is None:
&PropertyDeclaration::${property.camel_case}Declaration(ref value) =>
value.specified_value()
.unwrap_or_else(|| format!("{}", longhands::${property.ident}::get_initial_value())),
% endif
% endfor
decl => panic!("unsupported property declaration: {}", decl.name()),
}
}
pub fn matches(&self, name: &str) -> bool {
let name_lower = name.as_slice().to_ascii_lower();
match (self, name_lower.as_slice()) {
% for property in LONGHANDS:
% if property.derived_from is None:
(&PropertyDeclaration::${property.camel_case}Declaration(..), "${property.name}") => true,
% endif
% endfor
_ => false,
}
}
pub fn parse(name: &str, value: &[ComponentValue],
result_list: &mut Vec<PropertyDeclaration>,
base_url: &Url,
@ -2425,6 +2674,12 @@ impl PropertyDeclaration {
}
}
impl Show for PropertyDeclaration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.name(), self.value())
}
}
pub mod style_structs {
use super::longhands;
@ -2786,7 +3041,11 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock],
}
}
PropertyDeclaration::ColorDeclaration(ref value) => {
context.color = get_specified!(get_color, color, value);
context.color = match *value {
DeclaredValue::SpecifiedValue(ref specified_value) => specified_value.parsed,
DeclaredValue::Initial => longhands::color::get_initial_value(),
DeclaredValue::Inherit => inherited_style.get_color().color.clone(),
};
}
PropertyDeclaration::DisplayDeclaration(ref value) => {
context.display = get_specified!(get_box, display, value);
@ -2964,6 +3223,30 @@ pub fn cascade_anonymous(parent_style: &ComputedValues) -> ComputedValues {
result
}
pub fn is_supported_property(property: &str) -> bool {
match property {
% for property in SHORTHANDS:
"${property.name}" => true,
% endfor
% for property in LONGHANDS:
"${property.name}" => true,
% endfor
_ => false,
}
}
pub fn longhands_from_shorthand(shorthand: &str) -> Option<Vec<String>> {
match shorthand {
% for property in SHORTHANDS:
"${property.name}" => Some(vec!(
% for sub in property.sub_properties:
"${sub.name}".to_string(),
% endfor
)),
% endfor
_ => None,
}
}
// Only re-export the types for computed values.
pub mod computed_values {