mirror of
https://github.com/servo/servo.git
synced 2025-06-19 22:59:03 +01:00
auto merge of #1631 : recrack/servo/background-image, r=SimonSapin
for #777 #800 - support(http://www.w3.org/TR/CSS21/colors.html#background) - background: url(foo.png) - background: url(data:image/png;base64...) - background-image: url(foo.png) - background-image: url(data:image/png;base64...) - not support(http://www.w3.org/TR/css3-background/)
This commit is contained in:
commit
dedecec0e3
11 changed files with 249 additions and 28 deletions
|
@ -22,6 +22,7 @@ use servo_util::geometry::Au;
|
||||||
use servo_util::geometry;
|
use servo_util::geometry;
|
||||||
use servo_util::range::*;
|
use servo_util::range::*;
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::ApproxEq;
|
use std::cmp::ApproxEq;
|
||||||
|
@ -937,6 +938,7 @@ impl Box {
|
||||||
/// necessary.
|
/// necessary.
|
||||||
pub fn paint_background_if_applicable<E:ExtraDisplayListData>(
|
pub fn paint_background_if_applicable<E:ExtraDisplayListData>(
|
||||||
&self,
|
&self,
|
||||||
|
builder: &DisplayListBuilder,
|
||||||
index: uint,
|
index: uint,
|
||||||
lists: &RefCell<DisplayListCollection<E>>,
|
lists: &RefCell<DisplayListCollection<E>>,
|
||||||
absolute_bounds: &Rect<Au>) {
|
absolute_bounds: &Rect<Au>) {
|
||||||
|
@ -959,6 +961,39 @@ impl Box {
|
||||||
lists.lists[index].append_item(SolidColorDisplayItemClass(solid_color_display_item))
|
lists.lists[index].append_item(SolidColorDisplayItemClass(solid_color_display_item))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The background image is painted on top of the background color.
|
||||||
|
// Implements background image, per spec:
|
||||||
|
// http://www.w3.org/TR/CSS21/colors.html#background
|
||||||
|
match style.Background.get().background_image {
|
||||||
|
Some(ref image_url) => {
|
||||||
|
let mut holder = ImageHolder::new(image_url.clone(), builder.ctx.image_cache.clone());
|
||||||
|
match holder.get_image() {
|
||||||
|
Some(image) => {
|
||||||
|
debug!("(building display list) building background image");
|
||||||
|
|
||||||
|
// Place the image into the display list.
|
||||||
|
lists.with_mut(|lists| {
|
||||||
|
let image_display_item = ~ImageDisplayItem {
|
||||||
|
base: BaseDisplayItem {
|
||||||
|
bounds: *absolute_bounds,
|
||||||
|
extra: ExtraDisplayListData::new(self),
|
||||||
|
},
|
||||||
|
image: image.clone(),
|
||||||
|
};
|
||||||
|
lists.lists[index].append_item(ImageDisplayItemClass(image_display_item));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// No image data at all? Do nothing.
|
||||||
|
//
|
||||||
|
// TODO: Add some kind of placeholder background image.
|
||||||
|
debug!("(building display list) no background image :(");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the display items necessary to paint the borders of this box to a display list if
|
/// Adds the display items necessary to paint the borders of this box to a display list if
|
||||||
|
@ -1052,7 +1087,7 @@ impl Box {
|
||||||
|
|
||||||
self.paint_inline_background_border_if_applicable(index, lists, &absolute_box_bounds, &offset);
|
self.paint_inline_background_border_if_applicable(index, lists, &absolute_box_bounds, &offset);
|
||||||
// Add the background to the list, if applicable.
|
// Add the background to the list, if applicable.
|
||||||
self.paint_background_if_applicable(index, lists, &absolute_box_bounds);
|
self.paint_background_if_applicable(builder, index, lists, &absolute_box_bounds);
|
||||||
|
|
||||||
match self.specific {
|
match self.specific {
|
||||||
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
|
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
|
||||||
|
@ -1259,7 +1294,6 @@ impl Box {
|
||||||
//
|
//
|
||||||
// TODO: Outlines.
|
// TODO: Outlines.
|
||||||
self.paint_borders_if_applicable(index, lists, &absolute_box_bounds);
|
self.paint_borders_if_applicable(index, lists, &absolute_box_bounds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the *minimum width* and *preferred width* of this box as defined by CSS 2.1.
|
/// Returns the *minimum width* and *preferred width* of this box as defined by CSS 2.1.
|
||||||
|
|
|
@ -221,7 +221,9 @@ impl Element {
|
||||||
|
|
||||||
match local_name.as_slice() {
|
match local_name.as_slice() {
|
||||||
"style" => {
|
"style" => {
|
||||||
self.style_attribute = Some(style::parse_style_attribute(value))
|
let doc = self.node.owner_doc();
|
||||||
|
let base_url = doc.document().url.clone();
|
||||||
|
self.style_attribute = Some(style::parse_style_attribute(value, &base_url))
|
||||||
}
|
}
|
||||||
"id" if abstract_self.is_in_doc() => {
|
"id" if abstract_self.is_in_doc() => {
|
||||||
// XXX: this dual declaration are workaround to avoid the compile error:
|
// XXX: this dual declaration are workaround to avoid the compile error:
|
||||||
|
|
|
@ -26,7 +26,6 @@ use servo_util::url::parse_url;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::comm::{Port, SharedChan};
|
use std::comm::{Port, SharedChan};
|
||||||
use std::from_str::FromStr;
|
|
||||||
use std::str;
|
use std::str;
|
||||||
use style::Stylesheet;
|
use style::Stylesheet;
|
||||||
|
|
||||||
|
@ -277,7 +276,8 @@ pub fn parse_html(cx: *JSContext,
|
||||||
|
|
||||||
debug!("Fetched page; metadata is {:?}", load_response.metadata);
|
debug!("Fetched page; metadata is {:?}", load_response.metadata);
|
||||||
|
|
||||||
let url2 = load_response.metadata.final_url.clone();
|
let base_url = load_response.metadata.final_url.clone();
|
||||||
|
let url2 = base_url.clone();
|
||||||
let url3 = url2.clone();
|
let url3 = url2.clone();
|
||||||
|
|
||||||
// Store the final URL before we start parsing, so that DOM routines
|
// Store the final URL before we start parsing, so that DOM routines
|
||||||
|
@ -485,7 +485,6 @@ pub fn parse_html(cx: *JSContext,
|
||||||
// We've reached the end of a <style> so we can submit all the text to the parser.
|
// We've reached the end of a <style> so we can submit all the text to the parser.
|
||||||
unsafe {
|
unsafe {
|
||||||
let style: AbstractNode = NodeWrapping::from_hubbub_node(style);
|
let style: AbstractNode = NodeWrapping::from_hubbub_node(style);
|
||||||
let url = FromStr::from_str("http://example.com/"); // FIXME
|
|
||||||
let mut data = ~[];
|
let mut data = ~[];
|
||||||
debug!("iterating over children {:?}", style.first_child());
|
debug!("iterating over children {:?}", style.first_child());
|
||||||
for child in style.children() {
|
for child in style.children() {
|
||||||
|
@ -496,7 +495,7 @@ pub fn parse_html(cx: *JSContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("style data = {:?}", data);
|
debug!("style data = {:?}", data);
|
||||||
let provenance = InlineProvenance(url.unwrap(), data.concat());
|
let provenance = InlineProvenance(base_url.clone(), data.concat());
|
||||||
css_chan3.send(CSSTaskNewFile(provenance));
|
css_chan3.send(CSSTaskNewFile(provenance));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,6 +9,7 @@ use cssparser::ast::*;
|
||||||
use errors::{ErrorLoggerIterator, log_css_error};
|
use errors::{ErrorLoggerIterator, log_css_error};
|
||||||
use stylesheets::{CSSRule, CSSMediaRule, parse_style_rule, parse_nested_at_rule};
|
use stylesheets::{CSSRule, CSSMediaRule, parse_style_rule, parse_nested_at_rule};
|
||||||
use namespaces::NamespaceMap;
|
use namespaces::NamespaceMap;
|
||||||
|
use extra::url::Url;
|
||||||
|
|
||||||
|
|
||||||
pub struct MediaRule {
|
pub struct MediaRule {
|
||||||
|
@ -48,7 +49,7 @@ pub struct Device {
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_media_rule(rule: AtRule, parent_rules: &mut ~[CSSRule],
|
pub fn parse_media_rule(rule: AtRule, parent_rules: &mut ~[CSSRule],
|
||||||
namespaces: &NamespaceMap) {
|
namespaces: &NamespaceMap, base_url: &Url) {
|
||||||
let media_queries = parse_media_query_list(rule.prelude);
|
let media_queries = parse_media_query_list(rule.prelude);
|
||||||
let block = match rule.block {
|
let block = match rule.block {
|
||||||
Some(block) => block,
|
Some(block) => block,
|
||||||
|
@ -60,9 +61,9 @@ pub fn parse_media_rule(rule: AtRule, parent_rules: &mut ~[CSSRule],
|
||||||
let mut rules = ~[];
|
let mut rules = ~[];
|
||||||
for rule in ErrorLoggerIterator(parse_rule_list(block.move_iter())) {
|
for rule in ErrorLoggerIterator(parse_rule_list(block.move_iter())) {
|
||||||
match rule {
|
match rule {
|
||||||
QualifiedRule(rule) => parse_style_rule(rule, &mut rules, namespaces),
|
QualifiedRule(rule) => parse_style_rule(rule, &mut rules, namespaces, base_url),
|
||||||
AtRule(rule) => parse_nested_at_rule(
|
AtRule(rule) => parse_nested_at_rule(
|
||||||
rule.name.to_ascii_lower(), rule, &mut rules, namespaces),
|
rule.name.to_ascii_lower(), rule, &mut rules, namespaces, base_url),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parent_rules.push(CSSMediaRule(MediaRule {
|
parent_rules.push(CSSMediaRule(MediaRule {
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
// This file is a Mako template: http://www.makotemplates.org/
|
// This file is a Mako template: http://www.makotemplates.org/
|
||||||
|
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::StrAsciiExt;
|
||||||
|
pub use servo_util::url::parse_url;
|
||||||
pub use extra::arc::Arc;
|
pub use extra::arc::Arc;
|
||||||
|
pub use extra::url::Url;
|
||||||
use servo_util::cowarc::CowArc;
|
use servo_util::cowarc::CowArc;
|
||||||
|
|
||||||
pub use cssparser::*;
|
pub use cssparser::*;
|
||||||
pub use cssparser::ast::*;
|
pub use cssparser::ast::*;
|
||||||
|
|
||||||
|
@ -48,7 +51,9 @@ STYLE_STRUCTS = []
|
||||||
THIS_STYLE_STRUCT = None
|
THIS_STYLE_STRUCT = None
|
||||||
LONGHANDS = []
|
LONGHANDS = []
|
||||||
LONGHANDS_BY_NAME = {}
|
LONGHANDS_BY_NAME = {}
|
||||||
|
LONGHANDS_WITH_URL = []
|
||||||
SHORTHANDS = []
|
SHORTHANDS = []
|
||||||
|
SHORTHANDS_WITH_URL = []
|
||||||
|
|
||||||
def new_style_struct(name, is_inherited):
|
def new_style_struct(name, is_inherited):
|
||||||
global THIS_STYLE_STRUCT
|
global THIS_STYLE_STRUCT
|
||||||
|
@ -101,6 +106,32 @@ pub mod longhands {
|
||||||
}
|
}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="url_longhand(name, no_super=False)">
|
||||||
|
<%
|
||||||
|
property = Longhand(name)
|
||||||
|
THIS_STYLE_STRUCT.longhands.append(property)
|
||||||
|
LONGHANDS_WITH_URL.append(property)
|
||||||
|
LONGHANDS_BY_NAME[name] = property
|
||||||
|
%>
|
||||||
|
pub mod ${property.ident} {
|
||||||
|
% if not no_super:
|
||||||
|
use super::*;
|
||||||
|
% endif
|
||||||
|
pub use self::computed_value::*;
|
||||||
|
${caller.body()}
|
||||||
|
|
||||||
|
pub fn parse_declared(input: &[ComponentValue], base_url: &Url)
|
||||||
|
-> Option<DeclaredValue<SpecifiedValue>> {
|
||||||
|
match CSSWideKeyword::parse(input) {
|
||||||
|
Some(Some(keyword)) => Some(CSSWideKeyword(keyword)),
|
||||||
|
Some(None) => Some(CSSWideKeyword(${
|
||||||
|
"Inherit" if THIS_STYLE_STRUCT.inherited else "Initial"})),
|
||||||
|
None => parse_specified(input, base_url),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%def>
|
||||||
|
|
||||||
<%def name="longhand(name, no_super=False)">
|
<%def name="longhand(name, no_super=False)">
|
||||||
<%self:raw_longhand name="${name}">
|
<%self:raw_longhand name="${name}">
|
||||||
${caller.body()}
|
${caller.body()}
|
||||||
|
@ -470,10 +501,44 @@ pub mod longhands {
|
||||||
// CSS 2.1, Section 14 - Colors and Backgrounds
|
// CSS 2.1, Section 14 - Colors and Backgrounds
|
||||||
|
|
||||||
${new_style_struct("Background", is_inherited=False)}
|
${new_style_struct("Background", is_inherited=False)}
|
||||||
|
|
||||||
${predefined_type("background-color", "CSSColor",
|
${predefined_type("background-color", "CSSColor",
|
||||||
"RGBA(RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */")}
|
"RGBA(RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */")}
|
||||||
|
|
||||||
|
<%self:url_longhand name="background-image">
|
||||||
|
// The computed value is the same as the specified value.
|
||||||
|
pub use to_computed_value = super::computed_as_specified;
|
||||||
|
pub mod computed_value {
|
||||||
|
pub use extra::url::Url;
|
||||||
|
pub type T = Option<Url>;
|
||||||
|
}
|
||||||
|
pub type SpecifiedValue = computed_value::T;
|
||||||
|
#[inline] pub fn get_initial_value() -> SpecifiedValue {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pub fn parse(input: &[ComponentValue], base_url: &Url) -> Option<SpecifiedValue> {
|
||||||
|
from_iter(input.skip_whitespace(), base_url)
|
||||||
|
}
|
||||||
|
pub fn from_iter<'a>(mut iter: SkipWhitespaceIterator<'a>, base_url: &Url) -> Option<SpecifiedValue> {
|
||||||
|
match iter.next() {
|
||||||
|
Some(v) => from_component_value_with_url(v, base_url),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_component_value_with_url(component_value: &ComponentValue, base_url: &Url) -> Option<SpecifiedValue> {
|
||||||
|
match component_value {
|
||||||
|
&ast::URL(ref url) => {
|
||||||
|
let image_url = parse_url(url.as_slice(), Some(base_url.clone()));
|
||||||
|
Some(Some(image_url))
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn parse_specified(input: &[ComponentValue], base_url: &Url)
|
||||||
|
-> Option<DeclaredValue<SpecifiedValue>> {
|
||||||
|
parse(input, base_url).map(super::SpecifiedValue)
|
||||||
|
}
|
||||||
|
</%self:url_longhand>
|
||||||
|
|
||||||
|
|
||||||
${new_style_struct("Color", is_inherited=True)}
|
${new_style_struct("Color", is_inherited=True)}
|
||||||
|
|
||||||
|
@ -782,6 +847,24 @@ pub mod shorthands {
|
||||||
}
|
}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="url_shorthand(name, sub_properties)">
|
||||||
|
<%
|
||||||
|
shorthand = Shorthand(name, sub_properties.split())
|
||||||
|
SHORTHANDS_WITH_URL.append(shorthand)
|
||||||
|
%>
|
||||||
|
pub mod ${shorthand.ident} {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
struct Longhands {
|
||||||
|
% for sub_property in shorthand.sub_properties:
|
||||||
|
${sub_property.ident}: Option<${sub_property.ident}::SpecifiedValue>,
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
pub fn parse(input: &[ComponentValue], base_url: &Url) -> Option<Longhands> {
|
||||||
|
${caller.body()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%def>
|
||||||
<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function)">
|
<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function)">
|
||||||
<%self:shorthand name="${name}" sub_properties="${
|
<%self:shorthand name="${name}" sub_properties="${
|
||||||
' '.join(sub_property_pattern % side
|
' '.join(sub_property_pattern % side
|
||||||
|
@ -809,13 +892,31 @@ pub mod shorthands {
|
||||||
</%self:shorthand>
|
</%self:shorthand>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
|
||||||
// TODO: other background-* properties
|
// TODO: other background-* properties
|
||||||
<%self:shorthand name="background" sub_properties="background-color">
|
<%self:url_shorthand name="background" sub_properties="background-color background-image">
|
||||||
one_component_value(input).and_then(specified::CSSColor::parse).map(|color| {
|
let mut color = None;
|
||||||
Longhands { background_color: Some(color) }
|
let mut image = None;
|
||||||
})
|
let mut any = false;
|
||||||
</%self:shorthand>
|
|
||||||
|
for component_value in input.skip_whitespace() {
|
||||||
|
if color.is_none() {
|
||||||
|
match background_color::from_component_value(component_value) {
|
||||||
|
Some(v) => { color = Some(v); any = true; continue },
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if image.is_none() {
|
||||||
|
match background_image::from_component_value_with_url(component_value, base_url) {
|
||||||
|
Some(v) => { image = Some(v); any = true; continue },
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if any { Some(Longhands { background_color: color, background_image: image }) }
|
||||||
|
else { None }
|
||||||
|
</%self:url_shorthand>
|
||||||
|
|
||||||
${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")}
|
${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")}
|
||||||
${four_sides_shorthand("padding", "padding-%s", "padding_top::from_component_value")}
|
${four_sides_shorthand("padding", "padding-%s", "padding_top::from_component_value")}
|
||||||
|
@ -973,12 +1074,12 @@ pub struct PropertyDeclarationBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_style_attribute(input: &str) -> PropertyDeclarationBlock {
|
pub fn parse_style_attribute(input: &str, base_url: &Url) -> PropertyDeclarationBlock {
|
||||||
parse_property_declaration_list(tokenize(input))
|
parse_property_declaration_list(tokenize(input), base_url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I) -> PropertyDeclarationBlock {
|
pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I, base_url: &Url) -> PropertyDeclarationBlock {
|
||||||
let mut important = ~[];
|
let mut important = ~[];
|
||||||
let mut normal = ~[];
|
let mut normal = ~[];
|
||||||
for item in ErrorLoggerIterator(parse_declaration_list(input)) {
|
for item in ErrorLoggerIterator(parse_declaration_list(input)) {
|
||||||
|
@ -988,7 +1089,7 @@ pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I) -> PropertyD
|
||||||
Declaration(Declaration{ location: l, name: n, value: v, important: i}) => {
|
Declaration(Declaration{ location: l, name: n, value: v, important: i}) => {
|
||||||
// TODO: only keep the last valid declaration for a given name.
|
// TODO: only keep the last valid declaration for a given name.
|
||||||
let list = if i { &mut important } else { &mut normal };
|
let list = if i { &mut important } else { &mut normal };
|
||||||
match PropertyDeclaration::parse(n, v, list) {
|
match PropertyDeclaration::parse(n, v, list, base_url) {
|
||||||
UnknownProperty => log_css_error(l, format!(
|
UnknownProperty => log_css_error(l, format!(
|
||||||
"Unsupported property: {}:{}", n, v.iter().to_css())),
|
"Unsupported property: {}:{}", n, v.iter().to_css())),
|
||||||
InvalidValue => log_css_error(l, format!(
|
InvalidValue => log_css_error(l, format!(
|
||||||
|
@ -1036,6 +1137,9 @@ pub enum PropertyDeclaration {
|
||||||
% for property in LONGHANDS:
|
% for property in LONGHANDS:
|
||||||
${property.ident}_declaration(DeclaredValue<longhands::${property.ident}::SpecifiedValue>),
|
${property.ident}_declaration(DeclaredValue<longhands::${property.ident}::SpecifiedValue>),
|
||||||
% endfor
|
% endfor
|
||||||
|
% for property in LONGHANDS_WITH_URL:
|
||||||
|
${property.ident}_declaration(DeclaredValue<longhands::${property.ident}::SpecifiedValue>),
|
||||||
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1045,9 +1149,11 @@ enum PropertyDeclarationParseResult {
|
||||||
ValidDeclaration,
|
ValidDeclaration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl PropertyDeclaration {
|
impl PropertyDeclaration {
|
||||||
pub fn parse(name: &str, value: &[ComponentValue],
|
pub fn parse(name: &str, value: &[ComponentValue],
|
||||||
result_list: &mut ~[PropertyDeclaration]) -> PropertyDeclarationParseResult {
|
result_list: &mut ~[PropertyDeclaration],
|
||||||
|
base_url: &Url) -> PropertyDeclarationParseResult {
|
||||||
// FIXME: local variable to work around Rust #10683
|
// FIXME: local variable to work around Rust #10683
|
||||||
let name_lower = name.to_ascii_lower();
|
let name_lower = name.to_ascii_lower();
|
||||||
match name_lower.as_slice() {
|
match name_lower.as_slice() {
|
||||||
|
@ -1059,6 +1165,14 @@ impl PropertyDeclaration {
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
% endfor
|
% endfor
|
||||||
|
% for property in LONGHANDS_WITH_URL:
|
||||||
|
"${property.name}" => result_list.push(${property.ident}_declaration(
|
||||||
|
match longhands::${property.ident}::parse_declared(value, base_url) {
|
||||||
|
Some(value) => value,
|
||||||
|
None => return InvalidValue,
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
% endfor
|
||||||
% for shorthand in SHORTHANDS:
|
% for shorthand in SHORTHANDS:
|
||||||
"${shorthand.name}" => match CSSWideKeyword::parse(value) {
|
"${shorthand.name}" => match CSSWideKeyword::parse(value) {
|
||||||
Some(Some(keyword)) => {
|
Some(Some(keyword)) => {
|
||||||
|
@ -1091,6 +1205,38 @@ impl PropertyDeclaration {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
% endfor
|
% endfor
|
||||||
|
% for shorthand in SHORTHANDS_WITH_URL:
|
||||||
|
"${shorthand.name}" => match CSSWideKeyword::parse(value) {
|
||||||
|
Some(Some(keyword)) => {
|
||||||
|
% for sub_property in shorthand.sub_properties:
|
||||||
|
result_list.push(${sub_property.ident}_declaration(
|
||||||
|
CSSWideKeyword(keyword)
|
||||||
|
));
|
||||||
|
% endfor
|
||||||
|
},
|
||||||
|
Some(None) => {
|
||||||
|
% for sub_property in shorthand.sub_properties:
|
||||||
|
result_list.push(${sub_property.ident}_declaration(
|
||||||
|
CSSWideKeyword(${
|
||||||
|
"Inherit" if sub_property.style_struct.inherited else "Initial"})
|
||||||
|
));
|
||||||
|
% endfor
|
||||||
|
},
|
||||||
|
None => match shorthands::${shorthand.ident}::parse(value, base_url) {
|
||||||
|
Some(result) => {
|
||||||
|
% for sub_property in shorthand.sub_properties:
|
||||||
|
result_list.push(${sub_property.ident}_declaration(
|
||||||
|
match result.${sub_property.ident} {
|
||||||
|
Some(value) => SpecifiedValue(value),
|
||||||
|
None => CSSWideKeyword(Initial),
|
||||||
|
}
|
||||||
|
));
|
||||||
|
% endfor
|
||||||
|
},
|
||||||
|
None => return InvalidValue,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
% endfor
|
||||||
_ => return UnknownProperty,
|
_ => return UnknownProperty,
|
||||||
}
|
}
|
||||||
ValidDeclaration
|
ValidDeclaration
|
||||||
|
|
|
@ -75,7 +75,7 @@ impl Stylesheet {
|
||||||
match rule {
|
match rule {
|
||||||
QualifiedRule(rule) => {
|
QualifiedRule(rule) => {
|
||||||
next_state = STATE_BODY;
|
next_state = STATE_BODY;
|
||||||
parse_style_rule(rule, &mut rules, &namespaces)
|
parse_style_rule(rule, &mut rules, &namespaces, &base_url)
|
||||||
},
|
},
|
||||||
AtRule(rule) => {
|
AtRule(rule) => {
|
||||||
let lower_name = rule.name.to_ascii_lower();
|
let lower_name = rule.name.to_ascii_lower();
|
||||||
|
@ -112,7 +112,7 @@ impl Stylesheet {
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
next_state = STATE_BODY;
|
next_state = STATE_BODY;
|
||||||
parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces)
|
parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces, &base_url)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -125,14 +125,14 @@ impl Stylesheet {
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule],
|
pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule],
|
||||||
namespaces: &NamespaceMap) {
|
namespaces: &NamespaceMap, base_url: &Url) {
|
||||||
let QualifiedRule{location: location, prelude: prelude, block: block} = rule;
|
let QualifiedRule{location: location, prelude: prelude, block: block} = rule;
|
||||||
// FIXME: avoid doing this for valid selectors
|
// FIXME: avoid doing this for valid selectors
|
||||||
let serialized = prelude.iter().to_css();
|
let serialized = prelude.iter().to_css();
|
||||||
match selectors::parse_selector_list(prelude, namespaces) {
|
match selectors::parse_selector_list(prelude, namespaces) {
|
||||||
Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
|
Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
|
||||||
selectors: selectors,
|
selectors: selectors,
|
||||||
declarations: properties::parse_property_declaration_list(block.move_iter())
|
declarations: properties::parse_property_declaration_list(block.move_iter(), base_url)
|
||||||
})),
|
})),
|
||||||
None => log_css_error(location, format!(
|
None => log_css_error(location, format!(
|
||||||
"Invalid/unsupported selector: {}", serialized)),
|
"Invalid/unsupported selector: {}", serialized)),
|
||||||
|
@ -142,9 +142,9 @@ pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule],
|
||||||
|
|
||||||
// lower_name is passed explicitly to avoid computing it twice.
|
// lower_name is passed explicitly to avoid computing it twice.
|
||||||
pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
|
pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
|
||||||
parent_rules: &mut ~[CSSRule], namespaces: &NamespaceMap) {
|
parent_rules: &mut ~[CSSRule], namespaces: &NamespaceMap, base_url: &Url) {
|
||||||
match lower_name {
|
match lower_name {
|
||||||
"media" => parse_media_rule(rule, parent_rules, namespaces),
|
"media" => parse_media_rule(rule, parent_rules, namespaces, base_url),
|
||||||
_ => log_css_error(rule.location, format!("Unsupported at-rule: @{:s}", lower_name))
|
_ => log_css_error(rule.location, format!("Unsupported at-rule: @{:s}", lower_name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
src/test/html/background.html
Normal file
20
src/test/html/background.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
.test { background: url(rust-0.png) gray; }
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div class="test" style="width:200px; height:200px; color:red;">
|
||||||
|
background: url(rust-0.png) gray; width:200px; height:200px;
|
||||||
|
</div>
|
||||||
|
<div class="test" style="background-image: url(rust-45.png); width:200px; height:200px; color:red;">
|
||||||
|
background-image: url(rust-45.png); width:200px; height:200px;
|
||||||
|
</div>
|
||||||
|
<div style="background: url(rust-90.png) yellow; width:200px; height:200px; border: 5px solid #000; color:blue;">
|
||||||
|
background: url(rust-90.png) yellow; width:200px; height:200px; border: 5px solid #000;
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
9
src/test/ref/background_a.html
Normal file
9
src/test/ref/background_a.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="test" style="background: url(rust-0.png); width:200px; height:200px;"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
9
src/test/ref/background_b.html
Normal file
9
src/test/ref/background_b.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<img class="test" src="rust-0.png" style="width:200px; height:200px;" />
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -29,3 +29,4 @@
|
||||||
== position_relative_a.html position_relative_b.html
|
== position_relative_a.html position_relative_b.html
|
||||||
== attr_exists_selector.html attr_exists_selector_ref.html
|
== attr_exists_selector.html attr_exists_selector_ref.html
|
||||||
== data_img_a.html data_img_b.html
|
== data_img_a.html data_img_b.html
|
||||||
|
== background_a.html background_b.html
|
||||||
|
|
BIN
src/test/ref/rust-0.png
Normal file
BIN
src/test/ref/rust-0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
Loading…
Add table
Add a link
Reference in a new issue