mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
auto merge of #1087 : SimonSapin/servo/newnewcss, r=kmcallister
This is still not the big switch yet, but preparatory changes contained to the 'style' crate. The current status of the actual port can be seen here: https://github.com/SimonSapin/servo/compare/newnewcss...break-all-the-things (moving as I push and rebase stuff.)
This commit is contained in:
commit
8f7f70cb5c
7 changed files with 245 additions and 163 deletions
|
@ -4,34 +4,34 @@
|
|||
|
||||
pub use servo_util::geometry::Au;
|
||||
|
||||
pub type Float = f64;
|
||||
pub type CSSFloat = f64;
|
||||
|
||||
|
||||
pub mod specified {
|
||||
use std::ascii::StrAsciiExt;
|
||||
use cssparser::*;
|
||||
use super::{Au, Float};
|
||||
use super::{Au, CSSFloat};
|
||||
pub use CSSColor = cssparser::Color;
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub enum Length {
|
||||
Au_(Au), // application units
|
||||
Em(Float),
|
||||
Ex(Float),
|
||||
Em(CSSFloat),
|
||||
Ex(CSSFloat),
|
||||
// XXX uncomment when supported:
|
||||
// Ch(Float),
|
||||
// Rem(Float),
|
||||
// Vw(Float),
|
||||
// Vh(Float),
|
||||
// Vmin(Float),
|
||||
// Vmax(Float),
|
||||
// Ch(CSSFloat),
|
||||
// Rem(CSSFloat),
|
||||
// Vw(CSSFloat),
|
||||
// Vh(CSSFloat),
|
||||
// Vmin(CSSFloat),
|
||||
// Vmax(CSSFloat),
|
||||
}
|
||||
static AU_PER_PX: Float = 60.;
|
||||
static AU_PER_IN: Float = AU_PER_PX * 96.;
|
||||
static AU_PER_CM: Float = AU_PER_IN / 2.54;
|
||||
static AU_PER_MM: Float = AU_PER_IN / 25.4;
|
||||
static AU_PER_PT: Float = AU_PER_IN / 72.;
|
||||
static AU_PER_PC: Float = AU_PER_PT * 12.;
|
||||
static AU_PER_PX: CSSFloat = 60.;
|
||||
static AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
|
||||
static AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
|
||||
static AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
|
||||
static AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
|
||||
static AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
|
||||
impl Length {
|
||||
#[inline]
|
||||
fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Option<Length> {
|
||||
|
@ -48,7 +48,7 @@ pub mod specified {
|
|||
pub fn parse_non_negative(input: &ComponentValue) -> Option<Length> {
|
||||
Length::parse_internal(input, /* negative_ok = */ false)
|
||||
}
|
||||
pub fn parse_dimension(value: Float, unit: &str) -> Option<Length> {
|
||||
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Option<Length> {
|
||||
match unit.to_ascii_lower().as_slice() {
|
||||
"px" => Some(Length::from_px(value)),
|
||||
"in" => Some(Au_(Au((value * AU_PER_IN) as i32))),
|
||||
|
@ -62,7 +62,7 @@ pub mod specified {
|
|||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_px(px_value: Float) -> Length {
|
||||
pub fn from_px(px_value: CSSFloat) -> Length {
|
||||
Au_(Au((px_value * AU_PER_PX) as i32))
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ pub mod specified {
|
|||
#[deriving(Clone)]
|
||||
pub enum LengthOrPercentage {
|
||||
LP_Length(Length),
|
||||
LP_Percentage(Float), // [0 .. 100%] maps to [0.0 .. 1.0]
|
||||
LP_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
|
||||
}
|
||||
impl LengthOrPercentage {
|
||||
fn parse_internal(input: &ComponentValue, negative_ok: bool)
|
||||
|
@ -97,7 +97,7 @@ pub mod specified {
|
|||
#[deriving(Clone)]
|
||||
pub enum LengthOrPercentageOrAuto {
|
||||
LPA_Length(Length),
|
||||
LPA_Percentage(Float), // [0 .. 100%] maps to [0.0 .. 1.0]
|
||||
LPA_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
|
||||
LPA_Auto,
|
||||
}
|
||||
impl LengthOrPercentageOrAuto {
|
||||
|
@ -135,7 +135,7 @@ pub mod computed {
|
|||
pub struct Context {
|
||||
current_color: cssparser::RGBA,
|
||||
font_size: Au,
|
||||
font_weight: longhands::font_weight::ComputedValue,
|
||||
font_weight: longhands::font_weight::computed_value::T,
|
||||
position: longhands::position::SpecifiedValue,
|
||||
float: longhands::float::SpecifiedValue,
|
||||
is_root_element: bool,
|
||||
|
@ -147,7 +147,7 @@ pub mod computed {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn mul(a: Au, b: Float) -> Au { Au(((*a as Float) * b) as i32) }
|
||||
fn mul(a: Au, b: CSSFloat) -> Au { Au(((*a as CSSFloat) * b) as i32) }
|
||||
|
||||
pub fn compute_Au(value: specified::Length, context: &Context) -> Au {
|
||||
match value {
|
||||
|
@ -160,10 +160,10 @@ pub mod computed {
|
|||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum LengthOrPercentage {
|
||||
LP_Length(Au),
|
||||
LP_Percentage(Float),
|
||||
LP_Percentage(CSSFloat),
|
||||
}
|
||||
pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
|
||||
-> LengthOrPercentage {
|
||||
|
@ -173,10 +173,10 @@ pub mod computed {
|
|||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum LengthOrPercentageOrAuto {
|
||||
LPA_Length(Au),
|
||||
LPA_Percentage(Float),
|
||||
LPA_Percentage(CSSFloat),
|
||||
LPA_Auto,
|
||||
}
|
||||
pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
// This file is a Mako template: http://www.makotemplates.org/
|
||||
|
||||
use std::ascii::StrAsciiExt;
|
||||
use std::at_vec;
|
||||
pub use std::iterator;
|
||||
pub use cssparser::*;
|
||||
pub use errors::{ErrorLoggerIterator, log_css_error};
|
||||
|
@ -68,6 +67,7 @@ pub mod longhands {
|
|||
% if not no_super:
|
||||
use super::*;
|
||||
% endif
|
||||
pub use self::computed_value::*;
|
||||
${caller.body()}
|
||||
pub fn parse_declared(input: &[ComponentValue])
|
||||
-> Option<DeclaredValue<SpecifiedValue>> {
|
||||
|
@ -104,14 +104,16 @@ pub mod longhands {
|
|||
<%self:single_component_value name="${name}" inherited="${inherited}">
|
||||
// The computed value is the same as the specified value.
|
||||
pub use to_computed_value = super::computed_as_specified;
|
||||
#[deriving(Clone)]
|
||||
pub enum SpecifiedValue {
|
||||
% for value in values.split():
|
||||
${to_rust_ident(value)},
|
||||
% endfor
|
||||
pub mod computed_value {
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum T {
|
||||
% for value in values.split():
|
||||
${to_rust_ident(value)},
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
pub type ComputedValue = SpecifiedValue;
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue {
|
||||
pub type SpecifiedValue = computed_value::T;
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T {
|
||||
${to_rust_ident(values.split()[0])}
|
||||
}
|
||||
pub fn from_component_value(v: &ComponentValue) -> Option<SpecifiedValue> {
|
||||
|
@ -131,8 +133,10 @@ pub mod longhands {
|
|||
<%self:single_component_value name="${name}" inherited="${inherited}">
|
||||
pub use to_computed_value = super::super::common_types::computed::compute_${type};
|
||||
pub type SpecifiedValue = specified::${type};
|
||||
pub type ComputedValue = computed::${type};
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue { ${initial_value} }
|
||||
pub mod computed_value {
|
||||
pub type T = super::super::computed::${type};
|
||||
}
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
|
||||
#[inline] pub fn from_component_value(v: &ComponentValue) -> Option<SpecifiedValue> {
|
||||
specified::${type}::${parse_method}(v)
|
||||
}
|
||||
|
@ -163,13 +167,15 @@ pub mod longhands {
|
|||
${predefined_type("border-%s-color" % side, "CSSColor", "CurrentColor")}
|
||||
% endfor
|
||||
|
||||
// dotted dashed double groove ridge insed outset
|
||||
${single_keyword("border-top-style", "none solid hidden")}
|
||||
// double groove ridge insed outset
|
||||
${single_keyword("border-top-style", "none solid dotted dashed hidden")}
|
||||
% for side in ["right", "bottom", "left"]:
|
||||
<%self:longhand name="border-${side}-style", no_super="True">
|
||||
pub use super::border_top_style::*;
|
||||
pub type SpecifiedValue = super::border_top_style::SpecifiedValue;
|
||||
pub type ComputedValue = super::border_top_style::ComputedValue;
|
||||
pub mod computed_value {
|
||||
pub type T = super::super::border_top_style::computed_value::T;
|
||||
}
|
||||
</%self:longhand>
|
||||
% endfor
|
||||
|
||||
|
@ -187,15 +193,18 @@ pub mod longhands {
|
|||
% for side in ["top", "right", "bottom", "left"]:
|
||||
<%self:longhand name="border-${side}-width">
|
||||
pub type SpecifiedValue = specified::Length;
|
||||
pub type ComputedValue = Au;
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue {
|
||||
pub mod computed_value {
|
||||
use super::super::Au;
|
||||
pub type T = Au;
|
||||
}
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T {
|
||||
Au::from_px(3) // medium
|
||||
}
|
||||
pub fn parse(input: &[ComponentValue]) -> Option<SpecifiedValue> {
|
||||
one_component_value(input).chain(parse_border_width)
|
||||
}
|
||||
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
|
||||
-> ComputedValue {
|
||||
-> computed_value::T {
|
||||
if context.has_border_${side} { computed::compute_Au(value, context) }
|
||||
else { Au(0) }
|
||||
}
|
||||
|
@ -231,7 +240,7 @@ pub mod longhands {
|
|||
pub enum SpecifiedValue {
|
||||
SpecifiedNormal,
|
||||
SpecifiedLength(specified::Length),
|
||||
SpecifiedNumber(Float),
|
||||
SpecifiedNumber(CSSFloat),
|
||||
// percentage are the same as em.
|
||||
}
|
||||
/// normal | <number> | <length> | <percentage>
|
||||
|
@ -249,15 +258,18 @@ pub mod longhands {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
#[deriving(Clone)]
|
||||
pub enum ComputedValue {
|
||||
Normal,
|
||||
Length(Au),
|
||||
Number(Float),
|
||||
pub mod computed_value {
|
||||
use super::super::{Au, CSSFloat};
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum T {
|
||||
Normal,
|
||||
Length(Au),
|
||||
Number(CSSFloat),
|
||||
}
|
||||
}
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue { Normal }
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T { Normal }
|
||||
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
|
||||
-> ComputedValue {
|
||||
-> computed_value::T {
|
||||
match value {
|
||||
SpecifiedNormal => Normal,
|
||||
SpecifiedLength(value) => Length(computed::compute_Au(value, context)),
|
||||
|
@ -290,17 +302,20 @@ pub mod longhands {
|
|||
.map_move(SpecifiedLengthOrPercentage)
|
||||
}
|
||||
}
|
||||
#[deriving(Clone)]
|
||||
pub enum ComputedValue {
|
||||
% for keyword in vertical_align_keywords:
|
||||
${to_rust_ident(keyword)},
|
||||
% endfor
|
||||
Length(Au),
|
||||
Percentage(Float),
|
||||
pub mod computed_value {
|
||||
use super::super::{Au, CSSFloat};
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum T {
|
||||
% for keyword in vertical_align_keywords:
|
||||
${to_rust_ident(keyword)},
|
||||
% endfor
|
||||
Length(Au),
|
||||
Percentage(CSSFloat),
|
||||
}
|
||||
}
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue { baseline }
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T { baseline }
|
||||
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
|
||||
-> ComputedValue {
|
||||
-> computed_value::T {
|
||||
match value {
|
||||
% for keyword in vertical_align_keywords:
|
||||
Specified_${to_rust_ident(keyword)} => ${to_rust_ident(keyword)},
|
||||
|
@ -334,8 +349,10 @@ pub mod longhands {
|
|||
<%self:raw_longhand name="color" inherited="True">
|
||||
pub use to_computed_value = super::computed_as_specified;
|
||||
pub type SpecifiedValue = RGBA;
|
||||
pub type ComputedValue = SpecifiedValue;
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue {
|
||||
pub mod computed_value {
|
||||
pub type T = super::SpecifiedValue;
|
||||
}
|
||||
#[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]) -> Option<DeclaredValue<SpecifiedValue>> {
|
||||
|
@ -353,7 +370,7 @@ pub mod longhands {
|
|||
|
||||
<%self:longhand name="font-family" inherited="True">
|
||||
pub use to_computed_value = super::computed_as_specified;
|
||||
#[deriving(Clone)]
|
||||
#[deriving(Eq, Clone)]
|
||||
enum FontFamily {
|
||||
FamilyName(~str),
|
||||
// Generic
|
||||
|
@ -364,8 +381,10 @@ pub mod longhands {
|
|||
// Monospace,
|
||||
}
|
||||
pub type SpecifiedValue = ~[FontFamily];
|
||||
pub type ComputedValue = SpecifiedValue;
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue { ~[FamilyName(~"serif")] }
|
||||
pub mod computed_value {
|
||||
pub type T = super::SpecifiedValue;
|
||||
}
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T { ~[FamilyName(~"serif")] }
|
||||
/// <familiy-name>#
|
||||
/// <familiy-name> = <string> | [ <ident>+ ]
|
||||
/// TODO: <generic-familiy>
|
||||
|
@ -462,15 +481,17 @@ pub mod longhands {
|
|||
_ => None
|
||||
}
|
||||
}
|
||||
#[deriving(Clone)]
|
||||
pub enum ComputedValue {
|
||||
% for weight in range(100, 901, 100):
|
||||
Weight${weight},
|
||||
% endfor
|
||||
pub mod computed_value {
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum T {
|
||||
% for weight in range(100, 901, 100):
|
||||
Weight${weight},
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue { Weight400 } // normal
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T { Weight400 } // normal
|
||||
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
|
||||
-> ComputedValue {
|
||||
-> computed_value::T {
|
||||
match value {
|
||||
% for weight in range(100, 901, 100):
|
||||
SpecifiedWeight${weight} => Weight${weight},
|
||||
|
@ -504,8 +525,11 @@ pub mod longhands {
|
|||
<%self:single_component_value name="font-size" inherited="True">
|
||||
pub use to_computed_value = super::super::common_types::computed::compute_Au;
|
||||
pub type SpecifiedValue = specified::Length; // Percentages are the same as em.
|
||||
pub type ComputedValue = Au;
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue {
|
||||
pub mod computed_value {
|
||||
use super::super::Au;
|
||||
pub type T = Au;
|
||||
}
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T {
|
||||
Au::from_px(16) // medium
|
||||
}
|
||||
/// <length> | <percentage>
|
||||
|
@ -529,7 +553,7 @@ pub mod longhands {
|
|||
|
||||
<%self:longhand name="text-decoration">
|
||||
pub use to_computed_value = super::computed_as_specified;
|
||||
#[deriving(Clone)]
|
||||
#[deriving(Eq, Clone)]
|
||||
pub struct SpecifiedValue {
|
||||
underline: bool,
|
||||
overline: bool,
|
||||
|
@ -537,8 +561,10 @@ pub mod longhands {
|
|||
// 'blink' is accepted in the parser but ignored.
|
||||
// Just not blinking the text is a conforming implementation per CSS 2.1.
|
||||
}
|
||||
pub type ComputedValue = SpecifiedValue;
|
||||
#[inline] pub fn get_initial_value() -> ComputedValue {
|
||||
pub mod computed_value {
|
||||
pub type T = super::SpecifiedValue;
|
||||
}
|
||||
#[inline] pub fn get_initial_value() -> computed_value::T {
|
||||
SpecifiedValue { underline: false, overline: false, line_through: false } // none
|
||||
}
|
||||
/// none | [ underline || overline || line-through || blink ]
|
||||
|
@ -783,15 +809,20 @@ pub mod shorthands {
|
|||
|
||||
|
||||
pub struct PropertyDeclarationBlock {
|
||||
important: @[PropertyDeclaration],
|
||||
normal: @[PropertyDeclaration],
|
||||
important: ~[PropertyDeclaration],
|
||||
normal: ~[PropertyDeclaration],
|
||||
}
|
||||
|
||||
|
||||
pub fn parse_property_declaration_list(input: ~[Node]) -> PropertyDeclarationBlock {
|
||||
pub fn parse_style_attribute(input: &str) -> PropertyDeclarationBlock {
|
||||
parse_property_declaration_list(tokenize(input))
|
||||
}
|
||||
|
||||
|
||||
pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I) -> PropertyDeclarationBlock {
|
||||
let mut important = ~[];
|
||||
let mut normal = ~[];
|
||||
for item in ErrorLoggerIterator(parse_declaration_list(input.move_iter())) {
|
||||
for item in ErrorLoggerIterator(parse_declaration_list(input)) {
|
||||
match item {
|
||||
Decl_AtRule(rule) => log_css_error(
|
||||
rule.location, fmt!("Unsupported at-rule in declaration list: @%s", rule.name)),
|
||||
|
@ -805,9 +836,8 @@ pub fn parse_property_declaration_list(input: ~[Node]) -> PropertyDeclarationBlo
|
|||
}
|
||||
}
|
||||
PropertyDeclarationBlock {
|
||||
// TODO avoid copying?
|
||||
important: at_vec::to_managed_move(important),
|
||||
normal: at_vec::to_managed_move(normal),
|
||||
important: important,
|
||||
normal: normal,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -840,6 +870,7 @@ pub enum DeclaredValue<T> {
|
|||
CSSWideKeyword(CSSWideKeyword),
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub enum PropertyDeclaration {
|
||||
% for property in LONGHANDS:
|
||||
${property.ident}_declaration(DeclaredValue<longhands::${property.ident}::SpecifiedValue>),
|
||||
|
@ -900,20 +931,38 @@ impl PropertyDeclaration {
|
|||
pub mod style_structs {
|
||||
use super::longhands;
|
||||
% for name, longhands in LONGHANDS_PER_STYLE_STRUCT:
|
||||
#[deriving(Eq, Clone)]
|
||||
pub struct ${name} {
|
||||
% for longhand in longhands:
|
||||
${longhand.ident}: longhands::${longhand.ident}::ComputedValue,
|
||||
${longhand.ident}: longhands::${longhand.ident}::computed_value::T,
|
||||
% endfor
|
||||
}
|
||||
% endfor
|
||||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub struct ComputedValues {
|
||||
% for name, longhands in LONGHANDS_PER_STYLE_STRUCT:
|
||||
${name}: style_structs::${name},
|
||||
% endfor
|
||||
}
|
||||
|
||||
impl ComputedValues {
|
||||
/// Resolves the currentColor keyword.
|
||||
/// Any color value form computed values (except for the 'color' property itself)
|
||||
/// should go through this method.
|
||||
///
|
||||
/// Usage example:
|
||||
/// let top_color = style.resolve_color(style.Border.border_top_color);
|
||||
#[inline]
|
||||
pub fn resolve_color(&self, color: computed::CSSColor) -> RGBA {
|
||||
match color {
|
||||
RGBA(rgba) => rgba,
|
||||
CurrentColor => self.Color.color,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_initial_values() -> ComputedValues {
|
||||
ComputedValues {
|
||||
|
@ -929,7 +978,7 @@ fn get_initial_values() -> ComputedValues {
|
|||
|
||||
|
||||
// Most specific/important declarations last
|
||||
pub fn cascade(applicable_declarations: &[@[PropertyDeclaration]],
|
||||
pub fn cascade(applicable_declarations: &[~[PropertyDeclaration]],
|
||||
parent_style: Option< &ComputedValues>)
|
||||
-> ComputedValues {
|
||||
let initial_keep_alive;
|
||||
|
@ -1017,3 +1066,13 @@ pub fn cascade(applicable_declarations: &[@[PropertyDeclaration]],
|
|||
% endfor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Only re-export the types for computed values.
|
||||
pub mod computed_values {
|
||||
% for property in LONGHANDS:
|
||||
pub use ${property.ident} = super::longhands::${property.ident}::computed_value;
|
||||
% endfor
|
||||
// Don't use a side-specific name needlessly:
|
||||
pub use border_style = super::longhands::border_top_style::computed_value;
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
* 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/. */
|
||||
|
||||
use std::at_vec;
|
||||
use std::ascii::StrAsciiExt;
|
||||
use extra::sort::tim_sort;
|
||||
|
||||
use selectors::*;
|
||||
use stylesheets::parse_stylesheet;
|
||||
use stylesheets::Stylesheet;
|
||||
use media_queries::{Device, Screen};
|
||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use servo_util::tree::{TreeNodeRefAsElement, TreeNode, ElementLike};
|
||||
|
@ -36,8 +37,7 @@ impl Stylist {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_stylesheet(&mut self, css_source: &str, origin: StylesheetOrigin) {
|
||||
let stylesheet = parse_stylesheet(css_source);
|
||||
pub fn add_stylesheet(&mut self, stylesheet: Stylesheet, origin: StylesheetOrigin) {
|
||||
let rules = match origin {
|
||||
UserAgentOrigin => &mut self.ua_rules,
|
||||
AuthorOrigin => &mut self.author_rules,
|
||||
|
@ -51,9 +51,10 @@ impl Stylist {
|
|||
if style_rule.declarations.$priority.len() > 0 {
|
||||
$flag = true;
|
||||
for selector in style_rule.selectors.iter() {
|
||||
// TODO: avoid copying?
|
||||
rules.$priority.push(Rule {
|
||||
selector: *selector,
|
||||
declarations: style_rule.declarations.$priority,
|
||||
selector: @(*selector).clone(),
|
||||
declarations:at_vec::to_managed(style_rule.declarations.$priority),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -100,10 +101,12 @@ impl Stylist {
|
|||
|
||||
// Style attributes have author origin but higher specificity than style rules.
|
||||
append!(self.author_rules.normal);
|
||||
style_attribute.map(|sa| applicable_declarations.push(sa.normal));
|
||||
// TODO: avoid copying?
|
||||
style_attribute.map(|sa| applicable_declarations.push(at_vec::to_managed(sa.normal)));
|
||||
|
||||
append!(self.author_rules.important);
|
||||
style_attribute.map(|sa| applicable_declarations.push(sa.important));
|
||||
// TODO: avoid copying?
|
||||
style_attribute.map(|sa| applicable_declarations.push(at_vec::to_managed(sa.important)));
|
||||
|
||||
append!(self.user_rules.important);
|
||||
append!(self.ua_rules.important);
|
||||
|
|
|
@ -8,6 +8,7 @@ use cssparser::*;
|
|||
use namespaces::NamespaceMap;
|
||||
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct Selector {
|
||||
compound_selectors: CompoundSelector,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
|
@ -17,7 +18,7 @@ pub struct Selector {
|
|||
pub static STYLE_ATTRIBUTE_SPECIFICITY: u32 = 1 << 31;
|
||||
|
||||
|
||||
#[deriving(Eq)]
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum PseudoElement {
|
||||
Before,
|
||||
After,
|
||||
|
@ -26,11 +27,13 @@ pub enum PseudoElement {
|
|||
}
|
||||
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct CompoundSelector {
|
||||
simple_selectors: ~[SimpleSelector],
|
||||
next: Option<(~CompoundSelector, Combinator)>, // c.next is left of c
|
||||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum Combinator {
|
||||
Child, // >
|
||||
Descendant, // space
|
||||
|
@ -38,6 +41,7 @@ pub enum Combinator {
|
|||
LaterSibling, // ~
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub enum SimpleSelector {
|
||||
IDSelector(~str),
|
||||
ClassSelector(~str),
|
||||
|
@ -62,6 +66,7 @@ pub enum SimpleSelector {
|
|||
// ...
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct AttrSelector {
|
||||
name: ~str,
|
||||
namespace: Option<~str>,
|
||||
|
@ -73,7 +78,7 @@ type Iter = iterator::Peekable<ComponentValue, vec::MoveIterator<ComponentValue>
|
|||
|
||||
// None means invalid selector
|
||||
pub fn parse_selector_list(input: ~[ComponentValue], namespaces: &NamespaceMap)
|
||||
-> Option<~[@Selector]> {
|
||||
-> Option<~[Selector]> {
|
||||
let iter = &mut input.move_iter().peekable();
|
||||
let first = match parse_selector(iter, namespaces) {
|
||||
None => return None,
|
||||
|
@ -99,7 +104,7 @@ pub fn parse_selector_list(input: ~[ComponentValue], namespaces: &NamespaceMap)
|
|||
|
||||
// None means invalid selector
|
||||
fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||
-> Option<@Selector> {
|
||||
-> Option<Selector> {
|
||||
let (first, pseudo_element) = match parse_simple_selectors(iter, namespaces) {
|
||||
None => return None,
|
||||
Some(result) => result
|
||||
|
@ -130,7 +135,7 @@ fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
|||
}
|
||||
}
|
||||
}
|
||||
Some(@Selector {
|
||||
Some(Selector {
|
||||
specificity: compute_specificity(&compound, &pseudo_element),
|
||||
compound_selectors: compound,
|
||||
pseudo_element: pseudo_element,
|
||||
|
|
|
@ -18,11 +18,10 @@ extern mod servo_util (name = "util");
|
|||
|
||||
|
||||
// The "real" public API
|
||||
pub use self::selector_matching::{Stylist, StylesheetOrigin};
|
||||
pub use self::properties::cascade;
|
||||
pub use self::properties::{PropertyDeclarationBlock,
|
||||
parse_property_declaration_list}; // Style attributes
|
||||
|
||||
pub use stylesheets::Stylesheet;
|
||||
pub use selector_matching::{Stylist, StylesheetOrigin};
|
||||
pub use properties::{cascade, ComputedValues, computed_values};
|
||||
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
||||
|
||||
// Things that need to be public to make the compiler happy
|
||||
pub mod stylesheets;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
use std::str;
|
||||
use std::iterator::Iterator;
|
||||
use std::ascii::StrAsciiExt;
|
||||
use cssparser::*;
|
||||
|
@ -26,70 +27,85 @@ pub enum CSSRule {
|
|||
|
||||
|
||||
pub struct StyleRule {
|
||||
selectors: ~[@selectors::Selector],
|
||||
selectors: ~[selectors::Selector],
|
||||
declarations: properties::PropertyDeclarationBlock,
|
||||
}
|
||||
|
||||
|
||||
pub fn parse_stylesheet(css: &str) -> Stylesheet {
|
||||
static STATE_CHARSET: uint = 1;
|
||||
static STATE_IMPORTS: uint = 2;
|
||||
static STATE_NAMESPACES: uint = 3;
|
||||
static STATE_BODY: uint = 4;
|
||||
let mut state: uint = STATE_CHARSET;
|
||||
|
||||
let mut rules = ~[];
|
||||
let mut namespaces = NamespaceMap::new();
|
||||
|
||||
for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) {
|
||||
let next_state; // Unitialized to force each branch to set it.
|
||||
match rule {
|
||||
QualifiedRule(rule) => {
|
||||
next_state = STATE_BODY;
|
||||
parse_style_rule(rule, &mut rules, &namespaces)
|
||||
},
|
||||
AtRule(rule) => {
|
||||
let lower_name = rule.name.to_ascii_lower();
|
||||
match lower_name.as_slice() {
|
||||
"charset" => {
|
||||
if state > STATE_CHARSET {
|
||||
log_css_error(rule.location, "@charset must be the first rule")
|
||||
}
|
||||
// Valid @charset rules are just ignored
|
||||
next_state = STATE_IMPORTS;
|
||||
},
|
||||
"import" => {
|
||||
if state > STATE_IMPORTS {
|
||||
next_state = state;
|
||||
log_css_error(rule.location,
|
||||
"@import must be before any rule but @charset")
|
||||
} else {
|
||||
next_state = STATE_IMPORTS;
|
||||
log_css_error(rule.location, "@import is not supported yet") // TODO
|
||||
}
|
||||
},
|
||||
"namespace" => {
|
||||
if state > STATE_NAMESPACES {
|
||||
next_state = state;
|
||||
log_css_error(
|
||||
rule.location,
|
||||
"@namespace must be before any rule but @charset and @import"
|
||||
)
|
||||
} else {
|
||||
next_state = STATE_NAMESPACES;
|
||||
parse_namespace_rule(rule, &mut namespaces)
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
next_state = STATE_BODY;
|
||||
parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces)
|
||||
},
|
||||
}
|
||||
},
|
||||
impl Stylesheet {
|
||||
pub fn from_iter<I: Iterator<~[u8]>>(input: I) -> Stylesheet {
|
||||
let mut string = ~"";
|
||||
let mut input = input;
|
||||
// TODO: incremental tokinization/parsing
|
||||
for chunk in input {
|
||||
// Assume UTF-8. This fails on invalid UTF-8
|
||||
// TODO: support character encodings (use rust-encodings in rust-cssparser)
|
||||
string.push_str(str::from_utf8_owned(chunk))
|
||||
}
|
||||
state = next_state;
|
||||
Stylesheet::from_str(string)
|
||||
}
|
||||
|
||||
pub fn from_str(css: &str) -> Stylesheet {
|
||||
static STATE_CHARSET: uint = 1;
|
||||
static STATE_IMPORTS: uint = 2;
|
||||
static STATE_NAMESPACES: uint = 3;
|
||||
static STATE_BODY: uint = 4;
|
||||
let mut state: uint = STATE_CHARSET;
|
||||
|
||||
let mut rules = ~[];
|
||||
let mut namespaces = NamespaceMap::new();
|
||||
|
||||
for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) {
|
||||
let next_state; // Unitialized to force each branch to set it.
|
||||
match rule {
|
||||
QualifiedRule(rule) => {
|
||||
next_state = STATE_BODY;
|
||||
parse_style_rule(rule, &mut rules, &namespaces)
|
||||
},
|
||||
AtRule(rule) => {
|
||||
let lower_name = rule.name.to_ascii_lower();
|
||||
match lower_name.as_slice() {
|
||||
"charset" => {
|
||||
if state > STATE_CHARSET {
|
||||
log_css_error(rule.location, "@charset must be the first rule")
|
||||
}
|
||||
// Valid @charset rules are just ignored
|
||||
next_state = STATE_IMPORTS;
|
||||
},
|
||||
"import" => {
|
||||
if state > STATE_IMPORTS {
|
||||
next_state = state;
|
||||
log_css_error(rule.location,
|
||||
"@import must be before any rule but @charset")
|
||||
} else {
|
||||
next_state = STATE_IMPORTS;
|
||||
// TODO: support @import
|
||||
log_css_error(rule.location, "@import is not supported yet")
|
||||
}
|
||||
},
|
||||
"namespace" => {
|
||||
if state > STATE_NAMESPACES {
|
||||
next_state = state;
|
||||
log_css_error(
|
||||
rule.location,
|
||||
"@namespace must be before any rule but @charset and @import"
|
||||
)
|
||||
} else {
|
||||
next_state = STATE_NAMESPACES;
|
||||
parse_namespace_rule(rule, &mut namespaces)
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
next_state = STATE_BODY;
|
||||
parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
state = next_state;
|
||||
}
|
||||
Stylesheet{ rules: rules, namespaces: namespaces }
|
||||
}
|
||||
Stylesheet{ rules: rules, namespaces: namespaces }
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,7 +115,7 @@ pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule],
|
|||
match selectors::parse_selector_list(prelude, namespaces) {
|
||||
Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
|
||||
selectors: selectors,
|
||||
declarations: properties::parse_property_declaration_list(block)
|
||||
declarations: properties::parse_property_declaration_list(block.move_iter())
|
||||
})),
|
||||
None => log_css_error(location, "Unsupported CSS selector."),
|
||||
}
|
||||
|
@ -125,7 +141,7 @@ impl Stylesheet {
|
|||
|
||||
struct StyleRuleIterator<'self> {
|
||||
device: &'self media_queries::Device,
|
||||
// FIXME: I couldn’t get this to borrow-check with a stack of VecIterator
|
||||
// FIXME: I couldn't get this to borrow-check with a stack of VecIterator
|
||||
stack: ~[(&'self [CSSRule], uint)],
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
* 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/. */
|
||||
|
||||
use super::stylesheets::parse_stylesheet;
|
||||
use super::stylesheets::Stylesheet;
|
||||
|
||||
#[test]
|
||||
fn test_bootstrap() {
|
||||
// Test that parsing bootstrap does not trigger an assertion or otherwise fail.
|
||||
let stylesheet = parse_stylesheet(include_str!("bootstrap-v3.0.0.css"));
|
||||
let stylesheet = Stylesheet::from_str(include_str!("bootstrap-v3.0.0.css"));
|
||||
assert!(stylesheet.rules.len() > 100); // This depends on whet selectors are supported.
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue