Port to the new cssparser.

https://github.com/servo/rust-cssparser/pull/68
This commit is contained in:
Simon Sapin 2015-01-06 20:34:46 +00:00
parent ad328fda65
commit d034a6c6bc
20 changed files with 2018 additions and 2388 deletions

View file

@ -1,958 +0,0 @@
/* 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/. */
#![allow(non_camel_case_types)]
#![macro_escape]
use url::{Url, UrlParser};
pub use servo_util::geometry::Au;
macro_rules! define_css_keyword_enum {
($name: ident: $( $css: expr => $variant: ident ),+,) => {
define_css_keyword_enum!($name: $( $css => $variant ),+)
};
($name: ident: $( $css: expr => $variant: ident ),+) => {
#[allow(non_camel_case_types)]
#[deriving(Clone, Eq, PartialEq, FromPrimitive, Copy)]
pub enum $name {
$( $variant ),+
}
impl $name {
pub fn parse(component_value: &::cssparser::ast::ComponentValue) -> Result<$name, ()> {
match component_value {
&::cssparser::ast::ComponentValue::Ident(ref value) => {
match_ignore_ascii_case! { value:
$( $css => Ok($name::$variant) ),+
_ => Err(())
}
}
_ => Err(())
}
}
}
impl ::std::fmt::Show for $name {
#[inline]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
use cssparser::ToCss;
self.fmt_to_css(f)
}
}
impl ::cssparser::ToCss for $name {
fn to_css<W>(&self, dest: &mut W) -> ::text_writer::Result
where W: ::text_writer::TextWriter {
match self {
$( &$name::$variant => dest.write_str($css) ),+
}
}
}
}
}
pub type CSSFloat = f64;
pub mod specified {
use std::ascii::AsciiExt;
use std::f64::consts::PI;
use std::fmt;
use std::fmt::{Formatter, Show};
use url::Url;
use cssparser::{mod, ToCss, CssStringWriter};
use cssparser::ast::*;
use cssparser::ast::ComponentValue::*;
use text_writer::{mod, TextWriter};
use parsing_utils::{mod, BufferedIter, ParserIter};
use super::{Au, CSSFloat};
#[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 {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for CSSColor {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self.authored {
Some(ref s) => dest.write_str(s.as_slice()),
None => self.parsed.to_css(dest),
}
}
}
#[deriving(Clone)]
pub struct CSSRGBA {
pub parsed: cssparser::RGBA,
pub authored: Option<String>,
}
impl fmt::Show for CSSRGBA {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for CSSRGBA {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self.authored {
Some(ref s) => dest.write_str(s.as_slice()),
None => self.parsed.to_css(dest),
}
}
}
#[deriving(Clone, PartialEq)]
pub struct CSSImage(pub Option<Image>);
impl fmt::Show for CSSImage {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for CSSImage {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self {
&CSSImage(Some(ref image)) => image.to_css(dest),
&CSSImage(None) => dest.write_str("none"),
}
}
}
#[deriving(Clone, PartialEq, Copy)]
pub enum Length {
Au(Au), // application units
Em(CSSFloat),
Ex(CSSFloat),
Rem(CSSFloat),
/// HTML5 "character width", as defined in HTML5 § 14.5.4.
///
/// This cannot be specified by the user directly and is only generated by
/// `Stylist::synthesize_rules_for_legacy_attributes()`.
ServoCharacterWidth(i32),
// XXX uncomment when supported:
// Ch(CSSFloat),
// Vw(CSSFloat),
// Vh(CSSFloat),
// Vmin(CSSFloat),
// Vmax(CSSFloat),
}
impl fmt::Show for Length {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for Length {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self {
&Length::Au(length) => write!(dest, "{}px", length.to_subpx()),
&Length::Em(length) => write!(dest, "{}em", length),
&Length::Ex(length) => write!(dest, "{}ex", length),
&Length::Rem(length) => write!(dest, "{}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;
const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
impl Length {
#[inline]
fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Result<Length, ()> {
match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()),
&Number(ref value) if value.value == 0. => Ok(Length::Au(Au(0))),
_ => Err(())
}
}
#[allow(dead_code)]
pub fn parse(input: &ComponentValue) -> Result<Length, ()> {
Length::parse_internal(input, /* negative_ok = */ true)
}
pub fn parse_non_negative(input: &ComponentValue) -> Result<Length, ()> {
Length::parse_internal(input, /* negative_ok = */ false)
}
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
match unit.to_ascii_lower().as_slice() {
"px" => Ok(Length::from_px(value)),
"in" => Ok(Length::Au(Au((value * AU_PER_IN) as i32))),
"cm" => Ok(Length::Au(Au((value * AU_PER_CM) as i32))),
"mm" => Ok(Length::Au(Au((value * AU_PER_MM) as i32))),
"pt" => Ok(Length::Au(Au((value * AU_PER_PT) as i32))),
"pc" => Ok(Length::Au(Au((value * AU_PER_PC) as i32))),
"em" => Ok(Length::Em(value)),
"ex" => Ok(Length::Ex(value)),
"rem" => Ok(Length::Rem(value)),
_ => Err(())
}
}
#[inline]
pub fn from_px(px_value: CSSFloat) -> Length {
Length::Au(Au((px_value * AU_PER_PX) as i32))
}
}
#[deriving(Clone, PartialEq, Copy)]
pub enum LengthOrPercentage {
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
}
impl fmt::Show for LengthOrPercentage {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for LengthOrPercentage {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self {
&LengthOrPercentage::Length(length) => length.to_css(dest),
&LengthOrPercentage::Percentage(percentage)
=> write!(dest, "{}%", percentage * 100.),
}
}
}
impl LengthOrPercentage {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentage, ()> {
match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. =>
Length::parse_dimension(value.value, unit.as_slice())
.map(LengthOrPercentage::Length),
&Percentage(ref value) if negative_ok || value.value >= 0. =>
Ok(LengthOrPercentage::Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. =>
Ok(LengthOrPercentage::Length(Length::Au(Au(0)))),
_ => Err(())
}
}
#[allow(dead_code)]
#[inline]
pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentage, ()> {
LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
}
#[inline]
pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentage, ()> {
LengthOrPercentage::parse_internal(input, /* negative_ok = */ false)
}
}
#[deriving(Clone, PartialEq, Copy)]
pub enum LengthOrPercentageOrAuto {
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Auto,
}
impl fmt::Show for LengthOrPercentageOrAuto {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for LengthOrPercentageOrAuto {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self {
&LengthOrPercentageOrAuto::Length(length) => length.to_css(dest),
&LengthOrPercentageOrAuto::Percentage(percentage)
=> write!(dest, "{}%", percentage * 100.),
&LengthOrPercentageOrAuto::Auto => dest.write_str("auto"),
}
}
}
impl LengthOrPercentageOrAuto {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentageOrAuto, ()> {
match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. =>
Length::parse_dimension(value.value, unit.as_slice()).map(LengthOrPercentageOrAuto::Length),
&Percentage(ref value) if negative_ok || value.value >= 0. =>
Ok(LengthOrPercentageOrAuto::Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. =>
Ok(LengthOrPercentageOrAuto::Length(Length::Au(Au(0)))),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("auto") =>
Ok(LengthOrPercentageOrAuto::Auto),
_ => Err(())
}
}
#[inline]
pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentageOrAuto, ()> {
LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true)
}
#[inline]
pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentageOrAuto, ()> {
LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false)
}
}
#[deriving(Clone, PartialEq, Copy)]
pub enum LengthOrPercentageOrNone {
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
None,
}
impl fmt::Show for LengthOrPercentageOrNone {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for LengthOrPercentageOrNone {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self {
&LengthOrPercentageOrNone::Length(length) => length.to_css(dest),
&LengthOrPercentageOrNone::Percentage(percentage)
=> write!(dest, "{}%", percentage * 100.),
&LengthOrPercentageOrNone::None => dest.write_str("none"),
}
}
}
impl LengthOrPercentageOrNone {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentageOrNone, ()> {
match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()).map(LengthOrPercentageOrNone::Length),
&Percentage(ref value) if negative_ok || value.value >= 0.
=> Ok(LengthOrPercentageOrNone::Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Ok(LengthOrPercentageOrNone::Length(Length::Au(Au(0)))),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => Ok(LengthOrPercentageOrNone::None),
_ => Err(())
}
}
#[allow(dead_code)]
#[inline]
pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentageOrNone, ()> {
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true)
}
#[inline]
pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentageOrNone, ()> {
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ false)
}
}
// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position
#[deriving(Clone, PartialEq, Copy)]
pub enum PositionComponent {
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Center,
Left,
Right,
Top,
Bottom,
}
impl PositionComponent {
pub fn parse(input: &ComponentValue) -> Result<PositionComponent, ()> {
match input {
&Dimension(ref value, ref unit) =>
Length::parse_dimension(value.value, unit.as_slice()).map(PositionComponent::Length),
&Percentage(ref value) => Ok(PositionComponent::Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Ok(PositionComponent::Length(Length::Au(Au(0)))),
&Ident(ref value) => {
if value.as_slice().eq_ignore_ascii_case("center") { Ok(PositionComponent::Center) }
else if value.as_slice().eq_ignore_ascii_case("left") { Ok(PositionComponent::Left) }
else if value.as_slice().eq_ignore_ascii_case("right") { Ok(PositionComponent::Right) }
else if value.as_slice().eq_ignore_ascii_case("top") { Ok(PositionComponent::Top) }
else if value.as_slice().eq_ignore_ascii_case("bottom") { Ok(PositionComponent::Bottom) }
else { Err(()) }
}
_ => Err(())
}
}
#[inline]
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
match self {
PositionComponent::Length(x) => LengthOrPercentage::Length(x),
PositionComponent::Percentage(x) => LengthOrPercentage::Percentage(x),
PositionComponent::Center => LengthOrPercentage::Percentage(0.5),
PositionComponent::Left | PositionComponent::Top => LengthOrPercentage::Percentage(0.0),
PositionComponent::Right | PositionComponent::Bottom => LengthOrPercentage::Percentage(1.0),
}
}
}
#[deriving(Clone, PartialEq, PartialOrd, Copy)]
pub struct Angle(pub CSSFloat);
impl fmt::Show for Angle {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for Angle {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
let Angle(value) = *self;
write!(dest, "{}rad", value)
}
}
impl Angle {
pub fn radians(self) -> f64 {
let Angle(radians) = self;
radians
}
}
static DEG_TO_RAD: CSSFloat = PI / 180.0;
static GRAD_TO_RAD: CSSFloat = PI / 200.0;
impl Angle {
/// Parses an angle according to CSS-VALUES § 6.1.
fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle,()> {
if unit.eq_ignore_ascii_case("deg") {
Ok(Angle(value * DEG_TO_RAD))
} else if unit.eq_ignore_ascii_case("grad") {
Ok(Angle(value * GRAD_TO_RAD))
} else if unit.eq_ignore_ascii_case("rad") {
Ok(Angle(value))
} else if unit.eq_ignore_ascii_case("turn") {
Ok(Angle(value * 2.0 * PI))
} else {
Err(())
}
}
/// Parses an angle from a token according to CSS-VALUES § 6.1.
pub fn parse(value: &ComponentValue) -> Result<Angle,()> {
match *value {
Dimension(ref value, ref unit) => {
Angle::parse_dimension(value.value, unit.as_slice())
}
_ => Err(())
}
}
}
/// Specified values for an image according to CSS-IMAGES.
#[deriving(Clone, PartialEq)]
pub enum Image {
Url(Url),
LinearGradient(LinearGradient),
}
impl fmt::Show for Image {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for Image {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self {
&Image::Url(ref url) => {
try!(dest.write_str("url(\""));
try!(write!(&mut CssStringWriter::new(dest), "{}", url));
try!(dest.write_str("\")"));
Ok(())
}
&Image::LinearGradient(ref gradient) => gradient.to_css(dest)
}
}
}
impl Image {
pub fn from_component_value(component_value: &ComponentValue, base_url: &Url)
-> Result<Image,()> {
match component_value {
&URL(ref url) => {
let image_url = super::parse_url(url.as_slice(), base_url);
Ok(Image::Url(image_url))
},
&Function(ref name, ref args) => {
if name.as_slice().eq_ignore_ascii_case("linear-gradient") {
Ok(Image::LinearGradient(try!(
super::specified::LinearGradient::parse_function(
args.as_slice()))))
} else {
Err(())
}
}
_ => Err(()),
}
}
pub fn to_computed_value(self, context: &super::computed::Context)
-> super::computed::Image {
match self {
Image::Url(url) => super::computed::Image::Url(url),
Image::LinearGradient(linear_gradient) => {
super::computed::Image::LinearGradient(
super::computed::LinearGradient::compute(linear_gradient, context))
}
}
}
}
/// Specified values for a CSS linear gradient.
#[deriving(Clone, PartialEq)]
pub struct LinearGradient {
/// The angle or corner of the gradient.
pub angle_or_corner: AngleOrCorner,
/// The color stops.
pub stops: Vec<ColorStop>,
}
impl fmt::Show for LinearGradient {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for LinearGradient {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
try!(dest.write_str("linear-gradient("));
try!(self.angle_or_corner.to_css(dest));
for stop in self.stops.iter() {
try!(dest.write_str(", "));
try!(stop.to_css(dest));
}
try!(dest.write_char(')'));
Ok(())
}
}
/// Specified values for an angle or a corner in a linear gradient.
#[deriving(Clone, PartialEq, Copy)]
pub enum AngleOrCorner {
Angle(Angle),
Corner(HorizontalDirection, VerticalDirection),
}
impl fmt::Show for AngleOrCorner {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for AngleOrCorner {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self {
&AngleOrCorner::Angle(angle) => angle.to_css(dest),
&AngleOrCorner::Corner(horizontal, vertical) => {
try!(dest.write_str("to "));
try!(horizontal.to_css(dest));
try!(dest.write_char(' '));
try!(vertical.to_css(dest));
Ok(())
}
}
}
}
/// Specified values for one color stop in a linear gradient.
#[deriving(Clone, PartialEq)]
pub struct ColorStop {
/// The color of this stop.
pub color: CSSColor,
/// The position of this stop. If not specified, this stop is placed halfway between the
/// point that precedes it and the point that follows it.
pub position: Option<LengthOrPercentage>,
}
impl fmt::Show for ColorStop {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
}
impl ToCss for ColorStop {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
try!(self.color.to_css(dest));
if let Some(position) = self.position {
try!(dest.write_char(' '));
try!(position.to_css(dest));
}
Ok(())
}
}
define_css_keyword_enum!(HorizontalDirection: "left" => Left, "right" => Right)
define_css_keyword_enum!(VerticalDirection: "top" => Top, "bottom" => Bottom)
fn parse_color_stop(source: ParserIter) -> Result<ColorStop,()> {
let color = match source.next() {
Some(color) => try!(CSSColor::parse(color)),
None => return Err(()),
};
let position = match source.next() {
None => None,
Some(value) => {
match *value {
Comma => {
source.push_back(value);
None
}
ref position => Some(try!(LengthOrPercentage::parse(position))),
}
}
};
Ok(ColorStop {
color: color,
position: position,
})
}
impl LinearGradient {
/// Parses a linear gradient from the given arguments.
pub fn parse_function(args: &[ComponentValue]) -> Result<LinearGradient,()> {
let mut source = BufferedIter::new(args.skip_whitespace());
// Parse the angle.
let (angle_or_corner, need_to_parse_comma) = match source.next() {
None => return Err(()),
Some(token) => {
match *token {
Dimension(ref value, ref unit) => {
match Angle::parse_dimension(value.value, unit.as_slice()) {
Ok(angle) => {
(AngleOrCorner::Angle(angle), true)
}
Err(()) => {
source.push_back(token);
(AngleOrCorner::Angle(Angle(PI)), false)
}
}
}
Ident(ref ident) if ident.as_slice().eq_ignore_ascii_case("to") => {
let (mut horizontal, mut vertical) = (None, None);
loop {
match source.next() {
None => break,
Some(token) => {
match *token {
Ident(ref ident) => {
let ident = ident.as_slice();
if ident.eq_ignore_ascii_case("top") &&
vertical.is_none() {
vertical = Some(VerticalDirection::Top)
} else if ident.eq_ignore_ascii_case("bottom") &&
vertical.is_none() {
vertical = Some(VerticalDirection::Bottom)
} else if ident.eq_ignore_ascii_case("left") &&
horizontal.is_none() {
horizontal = Some(HorizontalDirection::Left)
} else if ident.eq_ignore_ascii_case("right") &&
horizontal.is_none() {
horizontal = Some(HorizontalDirection::Right)
} else {
return Err(())
}
}
Comma => {
source.push_back(token);
break
}
_ => return Err(()),
}
}
}
}
(match (horizontal, vertical) {
(None, Some(VerticalDirection::Top)) => {
AngleOrCorner::Angle(Angle(0.0))
},
(Some(HorizontalDirection::Right), None) => {
AngleOrCorner::Angle(Angle(PI * 0.5))
},
(None, Some(VerticalDirection::Bottom)) => {
AngleOrCorner::Angle(Angle(PI))
},
(Some(HorizontalDirection::Left), None) => {
AngleOrCorner::Angle(Angle(PI * 1.5))
},
(Some(horizontal), Some(vertical)) => {
AngleOrCorner::Corner(horizontal, vertical)
}
(None, None) => return Err(()),
}, true)
}
_ => {
source.push_back(token);
(AngleOrCorner::Angle(Angle(PI)), false)
}
}
}
};
// Parse the color stops.
let stops = if need_to_parse_comma {
match source.next() {
Some(&Comma) => {
try!(parsing_utils::parse_comma_separated(&mut source, parse_color_stop))
}
None => Vec::new(),
Some(_) => return Err(()),
}
} else {
try!(parsing_utils::parse_comma_separated(&mut source, parse_color_stop))
};
if stops.len() < 2 {
return Err(())
}
Ok(LinearGradient {
angle_or_corner: angle_or_corner,
stops: stops,
})
}
}
}
pub mod computed {
pub use super::specified::{Angle, AngleOrCorner, HorizontalDirection};
pub use super::specified::{VerticalDirection};
pub use cssparser::Color as CSSColor;
use super::*;
use super::super::longhands;
use std::fmt;
use url::Url;
#[allow(missing_copy_implementations)] // Its kinda big
pub struct Context {
pub inherited_font_weight: longhands::font_weight::computed_value::T,
pub inherited_font_size: longhands::font_size::computed_value::T,
pub inherited_text_decorations_in_effect: longhands::_servo_text_decorations_in_effect::T,
pub inherited_height: longhands::height::T,
pub color: longhands::color::computed_value::T,
pub text_decoration: longhands::text_decoration::computed_value::T,
pub font_size: longhands::font_size::computed_value::T,
pub root_font_size: longhands::font_size::computed_value::T,
pub display: longhands::display::computed_value::T,
pub positioned: bool,
pub floated: bool,
pub border_top_present: bool,
pub border_right_present: bool,
pub border_bottom_present: bool,
pub border_left_present: bool,
pub is_root_element: bool,
// 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 {
compute_Au_with_font_size(value, context.font_size, context.root_font_size)
}
/// A special version of `compute_Au` used for `font-size`.
#[allow(non_snake_case)]
#[inline]
pub fn compute_Au_with_font_size(value: specified::Length, reference_font_size: Au, root_font_size: Au) -> Au {
match value {
specified::Length::Au(value) => value,
specified::Length::Em(value) => reference_font_size.scale_by(value),
specified::Length::Ex(value) => {
let x_height = 0.5; // TODO: find that from the font
reference_font_size.scale_by(value * x_height)
},
specified::Length::Rem(value) => root_font_size.scale_by(value),
specified::Length::ServoCharacterWidth(value) => {
// This applies the *converting a character width to pixels* algorithm as specified
// in HTML5 § 14.5.4.
//
// TODO(pcwalton): Find these from the font.
let average_advance = reference_font_size.scale_by(0.5);
let max_advance = reference_font_size;
average_advance.scale_by(value as CSSFloat - 1.0) + max_advance
}
}
}
#[deriving(PartialEq, Clone, Copy)]
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)
-> LengthOrPercentage {
match value {
specified::LengthOrPercentage::Length(value) =>
LengthOrPercentage::Length(compute_Au(value, context)),
specified::LengthOrPercentage::Percentage(value) =>
LengthOrPercentage::Percentage(value),
}
}
#[deriving(PartialEq, Clone, Copy)]
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 {
match value {
specified::LengthOrPercentageOrAuto::Length(value) =>
LengthOrPercentageOrAuto::Length(compute_Au(value, context)),
specified::LengthOrPercentageOrAuto::Percentage(value) =>
LengthOrPercentageOrAuto::Percentage(value),
specified::LengthOrPercentageOrAuto::Auto =>
LengthOrPercentageOrAuto::Auto,
}
}
#[deriving(PartialEq, Clone, Copy)]
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 {
match value {
specified::LengthOrPercentageOrNone::Length(value) =>
LengthOrPercentageOrNone::Length(compute_Au(value, context)),
specified::LengthOrPercentageOrNone::Percentage(value) =>
LengthOrPercentageOrNone::Percentage(value),
specified::LengthOrPercentageOrNone::None =>
LengthOrPercentageOrNone::None,
}
}
/// Computed values for an image according to CSS-IMAGES.
#[deriving(Clone, PartialEq)]
pub enum Image {
Url(Url),
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 {
/// The angle or corner of the gradient.
pub angle_or_corner: AngleOrCorner,
/// The color stops.
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, Copy)]
pub struct ColorStop {
/// The color of this stop.
pub color: CSSColor,
/// The position of this stop. If not specified, this stop is placed halfway between the
/// point that precedes it and the point that follows it per CSS-IMAGES § 3.4.
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 {
angle_or_corner,
stops
} = value;
LinearGradient {
angle_or_corner: angle_or_corner,
stops: stops.into_iter().map(|stop| {
ColorStop {
color: stop.color.parsed,
position: match stop.position {
None => None,
Some(value) => Some(compute_LengthOrPercentage(value, context)),
},
}
}).collect()
}
}
}
#[allow(non_snake_case)]
#[inline]
pub fn compute_Length(value: specified::Length, context: &Context) -> Au {
compute_Au(value, context)
}
pub type Length = Au;
}
pub fn parse_url(input: &str, base_url: &Url) -> Url {
UrlParser::new().base_url(base_url).parse(input)
.unwrap_or_else(|_| Url::parse("about:invalid").unwrap())
}

File diff suppressed because it is too large Load diff