Auto merge of #12945 - Manishearth:bgarray, r=SimonSapin

Support multiple backgrounds in both servo and stylo

(Commits do not build individually, but split up for review)

These patches make all of the background- properties accept multiple values, and add the layout code to display them.

Still needs some cleanup, and some testing, but it seems to work.

r? @SimonSapin

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12945)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-08-22 22:09:23 -05:00 committed by GitHub
commit c5e81f8361
32 changed files with 806 additions and 440 deletions

View file

@ -60,6 +60,10 @@ use table_cell::CollapsedBordersForCell;
use url::Url; use url::Url;
use util::opts; use util::opts;
fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
&arr[index % arr.len()]
}
pub struct DisplayListBuildState<'a> { pub struct DisplayListBuildState<'a> {
pub layout_context: &'a LayoutContext<'a>, pub layout_context: &'a LayoutContext<'a>,
pub items: Vec<DisplayItem>, pub items: Vec<DisplayItem>,
@ -146,7 +150,7 @@ pub trait FragmentDisplayListBuilding {
fn compute_background_image_size(&self, fn compute_background_image_size(&self,
style: &ServoComputedValues, style: &ServoComputedValues,
bounds: &Rect<Au>, bounds: &Rect<Au>,
image: &WebRenderImageInfo) image: &WebRenderImageInfo, index: usize)
-> Size2D<Au>; -> Size2D<Au>;
/// Adds the display items necessary to paint the background image of this fragment to the /// Adds the display items necessary to paint the background image of this fragment to the
@ -157,7 +161,8 @@ pub trait FragmentDisplayListBuilding {
display_list_section: DisplayListSection, display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>, absolute_bounds: &Rect<Au>,
clip: &ClippingRegion, clip: &ClippingRegion,
image_url: &Url); image_url: &Url,
background_index: usize);
/// Adds the display items necessary to paint the background linear gradient of this fragment /// Adds the display items necessary to paint the background linear gradient of this fragment
/// to the appropriate section of the display list. /// to the appropriate section of the display list.
@ -344,27 +349,32 @@ impl FragmentDisplayListBuilding for Fragment {
if !border_radii.is_square() { if !border_radii.is_square() {
clip.intersect_with_rounded_rect(absolute_bounds, &border_radii) clip.intersect_with_rounded_rect(absolute_bounds, &border_radii)
} }
let background = style.get_background();
// FIXME: This causes a lot of background colors to be displayed when they are clearly not // FIXME: This causes a lot of background colors to be displayed when they are clearly not
// needed. We could use display list optimization to clean this up, but it still seems // needed. We could use display list optimization to clean this up, but it still seems
// inefficient. What we really want is something like "nearest ancestor element that // inefficient. What we really want is something like "nearest ancestor element that
// doesn't have a fragment". // doesn't have a fragment".
let background_color = style.resolve_color(style.get_background().background_color); let background_color = style.resolve_color(background.background_color);
// 'background-clip' determines the area within which the background is painted. // 'background-clip' determines the area within which the background is painted.
// http://dev.w3.org/csswg/css-backgrounds-3/#the-background-clip // http://dev.w3.org/csswg/css-backgrounds-3/#the-background-clip
let mut bounds = *absolute_bounds; let mut bounds = *absolute_bounds;
match style.get_background().background_clip { // This is the clip for the color (which is the last element in the bg array)
background_clip::T::border_box => {} let color_clip = get_cyclic(&background.background_clip.0,
background_clip::T::padding_box => { background.background_image.0.len() - 1);
match *color_clip {
background_clip::single_value::T::border_box => {}
background_clip::single_value::T::padding_box => {
let border = style.logical_border_width().to_physical(style.writing_mode); let border = style.logical_border_width().to_physical(style.writing_mode);
bounds.origin.x = bounds.origin.x + border.left; bounds.origin.x = bounds.origin.x + border.left;
bounds.origin.y = bounds.origin.y + border.top; bounds.origin.y = bounds.origin.y + border.top;
bounds.size.width = bounds.size.width - border.horizontal(); bounds.size.width = bounds.size.width - border.horizontal();
bounds.size.height = bounds.size.height - border.vertical(); bounds.size.height = bounds.size.height - border.vertical();
} }
background_clip::T::content_box => { background_clip::single_value::T::content_box => {
let border_padding = self.border_padding.to_physical(style.writing_mode); let border_padding = self.border_padding.to_physical(style.writing_mode);
bounds.origin.x = bounds.origin.x + border_padding.left; bounds.origin.x = bounds.origin.x + border_padding.left;
bounds.origin.y = bounds.origin.y + border_padding.top; bounds.origin.y = bounds.origin.y + border_padding.top;
@ -388,23 +398,26 @@ impl FragmentDisplayListBuilding for Fragment {
// Implements background image, per spec: // Implements background image, per spec:
// http://www.w3.org/TR/CSS21/colors.html#background // http://www.w3.org/TR/CSS21/colors.html#background
let background = style.get_background(); let background = style.get_background();
match background.background_image.0 { for (i, background_image) in background.background_image.0.iter().enumerate().rev() {
None => {} match background_image.0 {
Some(computed::Image::LinearGradient(ref gradient)) => { None => {}
self.build_display_list_for_background_linear_gradient(state, Some(computed::Image::LinearGradient(ref gradient)) => {
display_list_section, self.build_display_list_for_background_linear_gradient(state,
&bounds, display_list_section,
&clip, &bounds,
gradient, &clip,
style); gradient,
} style);
Some(computed::Image::Url(ref image_url, ref _extra_data)) => { }
self.build_display_list_for_background_image(state, Some(computed::Image::Url(ref image_url, ref _extra_data)) => {
style, self.build_display_list_for_background_image(state,
display_list_section, style,
&bounds, display_list_section,
&clip, &bounds,
image_url); &clip,
image_url,
i);
}
} }
} }
} }
@ -412,7 +425,8 @@ impl FragmentDisplayListBuilding for Fragment {
fn compute_background_image_size(&self, fn compute_background_image_size(&self,
style: &ServoComputedValues, style: &ServoComputedValues,
bounds: &Rect<Au>, bounds: &Rect<Au>,
image: &WebRenderImageInfo) image: &WebRenderImageInfo,
index: usize)
-> Size2D<Au> { -> Size2D<Au> {
// If `image_aspect_ratio` < `bounds_aspect_ratio`, the image is tall; otherwise, it is // If `image_aspect_ratio` < `bounds_aspect_ratio`, the image is tall; otherwise, it is
// wide. // wide.
@ -420,19 +434,22 @@ impl FragmentDisplayListBuilding for Fragment {
let bounds_aspect_ratio = bounds.size.width.to_f64_px() / bounds.size.height.to_f64_px(); let bounds_aspect_ratio = bounds.size.width.to_f64_px() / bounds.size.height.to_f64_px();
let intrinsic_size = Size2D::new(Au::from_px(image.width as i32), let intrinsic_size = Size2D::new(Au::from_px(image.width as i32),
Au::from_px(image.height as i32)); Au::from_px(image.height as i32));
match (style.get_background().background_size.clone(), let background_size = get_cyclic(&style.get_background().background_size.0, index).clone();
image_aspect_ratio < bounds_aspect_ratio) { match (background_size, image_aspect_ratio < bounds_aspect_ratio) {
(background_size::T::Contain, false) | (background_size::T::Cover, true) => { (background_size::single_value::T::Contain, false) |
(background_size::single_value::T::Cover, true) => {
Size2D::new(bounds.size.width, Size2D::new(bounds.size.width,
Au::from_f64_px(bounds.size.width.to_f64_px() / image_aspect_ratio)) Au::from_f64_px(bounds.size.width.to_f64_px() / image_aspect_ratio))
} }
(background_size::T::Contain, true) | (background_size::T::Cover, false) => { (background_size::single_value::T::Contain, true) |
(background_size::single_value::T::Cover, false) => {
Size2D::new(Au::from_f64_px(bounds.size.height.to_f64_px() * image_aspect_ratio), Size2D::new(Au::from_f64_px(bounds.size.height.to_f64_px() * image_aspect_ratio),
bounds.size.height) bounds.size.height)
} }
(background_size::T::Explicit(background_size::ExplicitSize { (background_size::single_value::T::Explicit(background_size::single_value
::ExplicitSize {
width, width,
height: LengthOrPercentageOrAuto::Auto, height: LengthOrPercentageOrAuto::Auto,
}), _) => { }), _) => {
@ -441,7 +458,8 @@ impl FragmentDisplayListBuilding for Fragment {
Size2D::new(width, Au::from_f64_px(width.to_f64_px() / image_aspect_ratio)) Size2D::new(width, Au::from_f64_px(width.to_f64_px() / image_aspect_ratio))
} }
(background_size::T::Explicit(background_size::ExplicitSize { (background_size::single_value::T::Explicit(background_size::single_value
::ExplicitSize {
width: LengthOrPercentageOrAuto::Auto, width: LengthOrPercentageOrAuto::Auto,
height height
}), _) => { }), _) => {
@ -450,7 +468,8 @@ impl FragmentDisplayListBuilding for Fragment {
Size2D::new(Au::from_f64_px(height.to_f64_px() * image_aspect_ratio), height) Size2D::new(Au::from_f64_px(height.to_f64_px() * image_aspect_ratio), height)
} }
(background_size::T::Explicit(background_size::ExplicitSize { (background_size::single_value::T::Explicit(background_size::single_value
::ExplicitSize {
width, width,
height height
}), _) => { }), _) => {
@ -468,19 +487,22 @@ impl FragmentDisplayListBuilding for Fragment {
display_list_section: DisplayListSection, display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>, absolute_bounds: &Rect<Au>,
clip: &ClippingRegion, clip: &ClippingRegion,
image_url: &Url) { image_url: &Url,
index: usize) {
let background = style.get_background(); let background = style.get_background();
let fetch_image_data_as_well = !opts::get().use_webrender; let fetch_image_data_as_well = !opts::get().use_webrender;
let webrender_image = let webrender_image =
state.layout_context.get_webrender_image_for_url(image_url, state.layout_context.get_webrender_image_for_url(image_url,
UsePlaceholder::No, UsePlaceholder::No,
fetch_image_data_as_well); fetch_image_data_as_well);
if let Some((webrender_image, image_data)) = webrender_image { if let Some((webrender_image, image_data)) = webrender_image {
debug!("(building display list) building background image"); debug!("(building display list) building background image");
// Use `background-size` to get the size. // Use `background-size` to get the size.
let mut bounds = *absolute_bounds; let mut bounds = *absolute_bounds;
let image_size = self.compute_background_image_size(style, &bounds, &webrender_image); let image_size = self.compute_background_image_size(style, &bounds,
&webrender_image, index);
// Clip. // Clip.
// //
@ -492,25 +514,27 @@ impl FragmentDisplayListBuilding for Fragment {
let border = style.logical_border_width().to_physical(style.writing_mode); let border = style.logical_border_width().to_physical(style.writing_mode);
// Use 'background-origin' to get the origin value. // Use 'background-origin' to get the origin value.
let (mut origin_x, mut origin_y) = match background.background_origin { let origin = get_cyclic(&background.background_origin.0, index);
background_origin::T::padding_box => { let (mut origin_x, mut origin_y) = match *origin {
background_origin::single_value::T::padding_box => {
(Au(0), Au(0)) (Au(0), Au(0))
} }
background_origin::T::border_box => { background_origin::single_value::T::border_box => {
(-border.left, -border.top) (-border.left, -border.top)
} }
background_origin::T::content_box => { background_origin::single_value::T::content_box => {
let border_padding = self.border_padding.to_physical(self.style.writing_mode); let border_padding = self.border_padding.to_physical(self.style.writing_mode);
(border_padding.left - border.left, border_padding.top - border.top) (border_padding.left - border.left, border_padding.top - border.top)
} }
}; };
// Use `background-attachment` to get the initial virtual origin // Use `background-attachment` to get the initial virtual origin
let (virtual_origin_x, virtual_origin_y) = match background.background_attachment { let attachment = get_cyclic(&background.background_attachment.0, index);
background_attachment::T::scroll => { let (virtual_origin_x, virtual_origin_y) = match *attachment {
background_attachment::single_value::T::scroll => {
(absolute_bounds.origin.x, absolute_bounds.origin.y) (absolute_bounds.origin.x, absolute_bounds.origin.y)
} }
background_attachment::T::fixed => { background_attachment::single_value::T::fixed => {
// If the background-attachment value for this image is fixed, then // If the background-attachment value for this image is fixed, then
// 'background-origin' has no effect. // 'background-origin' has no effect.
origin_x = Au(0); origin_x = Au(0);
@ -519,24 +543,25 @@ impl FragmentDisplayListBuilding for Fragment {
} }
}; };
let position = *get_cyclic(&background.background_position.0, index);
// Use `background-position` to get the offset. // Use `background-position` to get the offset.
let horizontal_position = model::specified(background.background_position.horizontal, let horizontal_position = model::specified(position.horizontal,
bounds.size.width - image_size.width); bounds.size.width - image_size.width);
let vertical_position = model::specified(background.background_position.vertical, let vertical_position = model::specified(position.vertical,
bounds.size.height - image_size.height); bounds.size.height - image_size.height);
let abs_x = border.left + virtual_origin_x + horizontal_position + origin_x; let abs_x = border.left + virtual_origin_x + horizontal_position + origin_x;
let abs_y = border.top + virtual_origin_y + vertical_position + origin_y; let abs_y = border.top + virtual_origin_y + vertical_position + origin_y;
// Adjust origin and size based on background-repeat // Adjust origin and size based on background-repeat
match background.background_repeat { match *get_cyclic(&background.background_repeat.0, index) {
background_repeat::T::no_repeat => { background_repeat::single_value::T::no_repeat => {
bounds.origin.x = abs_x; bounds.origin.x = abs_x;
bounds.origin.y = abs_y; bounds.origin.y = abs_y;
bounds.size.width = image_size.width; bounds.size.width = image_size.width;
bounds.size.height = image_size.height; bounds.size.height = image_size.height;
} }
background_repeat::T::repeat_x => { background_repeat::single_value::T::repeat_x => {
bounds.origin.y = abs_y; bounds.origin.y = abs_y;
bounds.size.height = image_size.height; bounds.size.height = image_size.height;
ImageFragmentInfo::tile_image(&mut bounds.origin.x, ImageFragmentInfo::tile_image(&mut bounds.origin.x,
@ -544,7 +569,7 @@ impl FragmentDisplayListBuilding for Fragment {
abs_x, abs_x,
image_size.width.to_nearest_px() as u32); image_size.width.to_nearest_px() as u32);
} }
background_repeat::T::repeat_y => { background_repeat::single_value::T::repeat_y => {
bounds.origin.x = abs_x; bounds.origin.x = abs_x;
bounds.size.width = image_size.width; bounds.size.width = image_size.width;
ImageFragmentInfo::tile_image(&mut bounds.origin.y, ImageFragmentInfo::tile_image(&mut bounds.origin.y,
@ -552,31 +577,32 @@ impl FragmentDisplayListBuilding for Fragment {
abs_y, abs_y,
image_size.height.to_nearest_px() as u32); image_size.height.to_nearest_px() as u32);
} }
background_repeat::T::repeat => { background_repeat::single_value::T::repeat => {
ImageFragmentInfo::tile_image(&mut bounds.origin.x, ImageFragmentInfo::tile_image(&mut bounds.origin.x,
&mut bounds.size.width, &mut bounds.size.width,
abs_x, abs_x,
image_size.width.to_nearest_px() as u32); image_size.width.to_nearest_px() as u32);
ImageFragmentInfo::tile_image(&mut bounds.origin.y, ImageFragmentInfo::tile_image(&mut bounds.origin.y,
&mut bounds.size.height, &mut bounds.size.height,
abs_y, abs_y,
image_size.height.to_nearest_px() as u32); image_size.height.to_nearest_px() as u32);
} }
}; };
// Create the image display item. // Create the image display item.
let base = state.create_base_display_item(&bounds, let base = state.create_base_display_item(&bounds,
&clip, &clip,
self.node, self.node,
style.get_cursor(Cursor::Default), style.get_cursor(Cursor::Default),
display_list_section); display_list_section);
state.add_display_item(DisplayItem::ImageClass(box ImageDisplayItem { state.add_display_item(DisplayItem::ImageClass(box ImageDisplayItem {
base: base, base: base,
webrender_image: webrender_image, webrender_image: webrender_image,
image_data: image_data.map(Arc::new), image_data: image_data.map(Arc::new),
stretch_size: Size2D::new(image_size.width, image_size.height), stretch_size: Size2D::new(image_size.width, image_size.height),
image_rendering: style.get_inheritedbox().image_rendering.clone(), image_rendering: style.get_inheritedbox().image_rendering.clone(),
})); }));
} }
} }

View file

@ -362,8 +362,11 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(url) = background { if let Some(url) = background {
hints.push(from_declaration( hints.push(from_declaration(
PropertyDeclaration::BackgroundImage(DeclaredValue::Value( PropertyDeclaration::BackgroundImage(DeclaredValue::Value(
background_image::SpecifiedValue(Some( background_image::SpecifiedValue(vec![
specified::Image::Url(url, specified::UrlExtraData { }))))))); background_image::single_value::SpecifiedValue(Some(
specified::Image::Url(url, specified::UrlExtraData { })
))
])))));
} }
let color = if let Some(this) = self.downcast::<HTMLFontElement>() { let color = if let Some(this) = self.downcast::<HTMLFontElement>() {

View file

@ -2236,6 +2236,7 @@ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1", "plugins 0.0.1",

View file

@ -34,6 +34,7 @@ heapsize_plugin = {version = "0.1.2", optional = true}
lazy_static = "0.2" lazy_static = "0.2"
log = "0.3.5" log = "0.3.5"
matches = "0.1" matches = "0.1"
num-integer = "0.1.32"
num-traits = "0.1.32" num-traits = "0.1.32"
ordered-float = "0.2.2" ordered-float = "0.2.2"
quickersort = "2.0.0" quickersort = "2.0.0"

View file

@ -56,6 +56,7 @@ extern crate log;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
#[macro_use] #[macro_use]
extern crate matches; extern crate matches;
extern crate num_integer;
extern crate num_traits; extern crate num_traits;
extern crate ordered_float; extern crate ordered_float;
extern crate quickersort; extern crate quickersort;

View file

@ -937,6 +937,32 @@ fn static_assert() {
</%self:impl_trait> </%self:impl_trait>
<%def name="simple_background_array_property(name, field_name)">
pub fn copy_background_${name}_from(&mut self, other: &Self) {
unsafe {
Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, other.gecko.mImage.mLayers.len());
}
for (layer, other) in self.gecko.mImage.mLayers.iter_mut()
.zip(other.gecko.mImage.mLayers.iter())
.take(other.gecko.mImage.${field_name}Count as usize) {
layer.${field_name} = other.${field_name};
}
self.gecko.mImage.${field_name}Count = other.gecko.mImage.${field_name}Count;
}
pub fn set_background_${name}(&mut self, v: longhands::background_${name}::computed_value::T) {
unsafe {
Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, v.0.len());
}
self.gecko.mImage.${field_name}Count = v.0.len() as u32;
for (servo, geckolayer) in v.0.into_iter().zip(self.gecko.mImage.mLayers.iter_mut()) {
geckolayer.${field_name} = {
${caller.body()}
};
}
}
</%def>
// TODO: Gecko accepts lists in most background-related properties. We just use // TODO: Gecko accepts lists in most background-related properties. We just use
// the first element (which is the common case), but at some point we want to // the first element (which is the common case), but at some point we want to
// add support for parsing these lists in servo and pushing to nsTArray's. // add support for parsing these lists in servo and pushing to nsTArray's.
@ -950,109 +976,105 @@ fn static_assert() {
<% impl_color("background_color", "mBackgroundColor", need_clone=True) %> <% impl_color("background_color", "mBackgroundColor", need_clone=True) %>
pub fn copy_background_repeat_from(&mut self, other: &Self) { <%self:simple_background_array_property name="repeat" field_name="mRepeat">
self.gecko.mImage.mRepeatCount = cmp::min(1, other.gecko.mImage.mRepeatCount); use properties::longhands::background_repeat::single_value::computed_value::T;
self.gecko.mImage.mLayers.mFirstElement.mRepeat =
other.gecko.mImage.mLayers.mFirstElement.mRepeat;
}
pub fn set_background_repeat(&mut self, v: longhands::background_repeat::computed_value::T) {
use properties::longhands::background_repeat::computed_value::T;
use gecko_bindings::structs::{NS_STYLE_IMAGELAYER_REPEAT_REPEAT, NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT};
use gecko_bindings::structs::nsStyleImageLayers_Repeat; use gecko_bindings::structs::nsStyleImageLayers_Repeat;
let (repeat_x, repeat_y) = match v { use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
T::repeat_x => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT, use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT;
NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT),
T::repeat_y => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT, let (repeat_x, repeat_y) = match servo {
NS_STYLE_IMAGELAYER_REPEAT_REPEAT), T::repeat_x => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT,
T::repeat => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT, NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT),
T::repeat_y => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT,
NS_STYLE_IMAGELAYER_REPEAT_REPEAT), NS_STYLE_IMAGELAYER_REPEAT_REPEAT),
T::no_repeat => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT, T::repeat => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT,
NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT), NS_STYLE_IMAGELAYER_REPEAT_REPEAT),
T::no_repeat => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT,
NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT),
}; };
nsStyleImageLayers_Repeat {
mXRepeat: repeat_x as u8,
mYRepeat: repeat_y as u8,
}
</%self:simple_background_array_property>
self.gecko.mImage.mRepeatCount = 1; <%self:simple_background_array_property name="clip" field_name="mClip">
self.gecko.mImage.mLayers.mFirstElement.mRepeat = nsStyleImageLayers_Repeat { use properties::longhands::background_clip::single_value::computed_value::T;
mXRepeat: repeat_x as u8,
mYRepeat: repeat_y as u8,
};
}
pub fn copy_background_clip_from(&mut self, other: &Self) { match servo {
self.gecko.mImage.mClipCount = cmp::min(1, other.gecko.mImage.mClipCount);
self.gecko.mImage.mLayers.mFirstElement.mClip =
other.gecko.mImage.mLayers.mFirstElement.mClip;
}
pub fn set_background_clip(&mut self, v: longhands::background_clip::computed_value::T) {
use properties::longhands::background_clip::computed_value::T;
self.gecko.mImage.mClipCount = 1;
// TODO: Gecko supports background-clip: text, but just on -webkit-
// prefixed properties.
self.gecko.mImage.mLayers.mFirstElement.mClip = match v {
T::border_box => structs::NS_STYLE_IMAGELAYER_CLIP_BORDER as u8, T::border_box => structs::NS_STYLE_IMAGELAYER_CLIP_BORDER as u8,
T::padding_box => structs::NS_STYLE_IMAGELAYER_CLIP_PADDING as u8, T::padding_box => structs::NS_STYLE_IMAGELAYER_CLIP_PADDING as u8,
T::content_box => structs::NS_STYLE_IMAGELAYER_CLIP_CONTENT as u8, T::content_box => structs::NS_STYLE_IMAGELAYER_CLIP_CONTENT as u8,
}; }
} </%self:simple_background_array_property>
pub fn copy_background_origin_from(&mut self, other: &Self) { <%self:simple_background_array_property name="origin" field_name="mOrigin">
self.gecko.mImage.mOriginCount = cmp::min(1, other.gecko.mImage.mOriginCount); use properties::longhands::background_origin::single_value::computed_value::T;
self.gecko.mImage.mLayers.mFirstElement.mOrigin =
other.gecko.mImage.mLayers.mFirstElement.mOrigin;
}
pub fn set_background_origin(&mut self, v: longhands::background_origin::computed_value::T) { match servo {
use properties::longhands::background_origin::computed_value::T;
self.gecko.mImage.mOriginCount = 1;
self.gecko.mImage.mLayers.mFirstElement.mOrigin = match v {
T::border_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_BORDER as u8, T::border_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_BORDER as u8,
T::padding_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_PADDING as u8, T::padding_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_PADDING as u8,
T::content_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_CONTENT as u8, T::content_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_CONTENT as u8,
}; }
} </%self:simple_background_array_property>
pub fn copy_background_attachment_from(&mut self, other: &Self) { <%self:simple_background_array_property name="attachment" field_name="mAttachment">
self.gecko.mImage.mAttachmentCount = cmp::min(1, other.gecko.mImage.mAttachmentCount); use properties::longhands::background_attachment::single_value::computed_value::T;
self.gecko.mImage.mLayers.mFirstElement.mAttachment =
other.gecko.mImage.mLayers.mFirstElement.mAttachment;
}
pub fn set_background_attachment(&mut self, v: longhands::background_attachment::computed_value::T) { match servo {
use properties::longhands::background_attachment::computed_value::T;
self.gecko.mImage.mAttachmentCount = 1;
self.gecko.mImage.mLayers.mFirstElement.mAttachment = match v {
T::scroll => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL as u8, T::scroll => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL as u8,
T::fixed => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED as u8, T::fixed => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED as u8,
T::local => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL as u8, T::local => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL as u8,
}; }
} </%self:simple_background_array_property>
pub fn copy_background_position_from(&mut self, other: &Self) { pub fn copy_background_position_from(&mut self, other: &Self) {
self.gecko.mImage.mPositionXCount = cmp::min(1, other.gecko.mImage.mPositionXCount); self.gecko.mImage.mPositionXCount = cmp::min(1, other.gecko.mImage.mPositionXCount);
self.gecko.mImage.mPositionYCount = cmp::min(1, other.gecko.mImage.mPositionYCount); self.gecko.mImage.mPositionYCount = cmp::min(1, other.gecko.mImage.mPositionYCount);
self.gecko.mImage.mLayers.mFirstElement.mPosition = self.gecko.mImage.mLayers.mFirstElement.mPosition =
other.gecko.mImage.mLayers.mFirstElement.mPosition; other.gecko.mImage.mLayers.mFirstElement.mPosition;
unsafe {
Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, other.gecko.mImage.mLayers.len());
}
for (layer, other) in self.gecko.mImage.mLayers.iter_mut()
.zip(other.gecko.mImage.mLayers.iter())
.take(other.gecko.mImage.mPositionXCount as usize) {
layer.mPosition.mXPosition = other.mPosition.mXPosition;
}
for (layer, other) in self.gecko.mImage.mLayers.iter_mut()
.zip(other.gecko.mImage.mLayers.iter())
.take(other.gecko.mImage.mPositionYCount as usize) {
layer.mPosition.mYPosition = other.mPosition.mYPosition;
}
self.gecko.mImage.mPositionXCount = other.gecko.mImage.mPositionXCount;
self.gecko.mImage.mPositionYCount = other.gecko.mImage.mPositionYCount;
} }
pub fn clone_background_position(&self) -> longhands::background_position::computed_value::T { pub fn clone_background_position(&self) -> longhands::background_position::computed_value::T {
use values::computed::position::Position; use values::computed::position::Position;
let position = &self.gecko.mImage.mLayers.mFirstElement.mPosition; longhands::background_position::computed_value::T(
Position { self.gecko.mImage.mLayers.iter()
horizontal: position.mXPosition.into(), .take(self.gecko.mImage.mPositionXCount as usize)
vertical: position.mYPosition.into(), .take(self.gecko.mImage.mPositionYCount as usize)
} .map(|position| Position {
horizontal: position.mPosition.mXPosition.into(),
vertical: position.mPosition.mYPosition.into(),
})
.collect()
)
} }
pub fn set_background_position(&mut self, v: longhands::background_position::computed_value::T) { pub fn set_background_position(&mut self, v: longhands::background_position::computed_value::T) {
let position = &mut self.gecko.mImage.mLayers.mFirstElement.mPosition; unsafe {
position.mXPosition = v.horizontal.into(); Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, v.0.len());
position.mYPosition = v.vertical.into(); }
self.gecko.mImage.mPositionXCount = 1;
self.gecko.mImage.mPositionYCount = 1; self.gecko.mImage.mPositionXCount = v.0.len() as u32;
self.gecko.mImage.mPositionYCount = v.0.len() as u32;
for (servo, geckolayer) in v.0.into_iter().zip(self.gecko.mImage.mLayers.iter_mut()) {
geckolayer.mPosition.mXPosition = servo.horizontal.into();
geckolayer.mPosition.mYPosition = servo.vertical.into();
}
} }
pub fn copy_background_image_from(&mut self, other: &Self) { pub fn copy_background_image_from(&mut self, other: &Self) {
@ -1156,6 +1178,24 @@ fn static_assert() {
} }
} }
pub fn fill_arrays(&mut self) {
use gecko_bindings::bindings::Gecko_FillAllBackgroundLists;
use std::cmp;
let mut max_len = 1;
% for member in "mRepeat mClip mOrigin mAttachment mPositionX mPositionY mImage".split():
max_len = cmp::max(max_len, self.gecko.mImage.${member}Count);
% endfor
// XXXManishearth Gecko does an optimization here where it only
// fills things in if any of the properties have been set
unsafe {
// While we could do this manually, we'd need to also manually
// run all the copy constructors, so we just delegate to gecko
Gecko_FillAllBackgroundLists(&mut self.gecko.mImage, max_len);
}
}
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="List" skip_longhands="list-style-type" skip_additionals="*"> <%self:impl_trait style_struct_name="List" skip_longhands="list-style-type" skip_additionals="*">

View file

@ -69,10 +69,10 @@
${caller.body()} ${caller.body()}
} }
pub mod computed_value { pub mod computed_value {
use super::single_value; pub use super::single_value::computed_value as single_value;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Vec<single_value::computed_value::T>); pub struct T(pub Vec<single_value::T>);
} }
impl ToCss for computed_value::T { impl ToCss for computed_value::T {
@ -285,8 +285,8 @@
} }
</%def> </%def>
<%def name="single_keyword(name, values, **kwargs)"> <%def name="single_keyword(name, values, vector=False, **kwargs)">
<%call expr="single_keyword_computed(name, values, **kwargs)"> <%call expr="single_keyword_computed(name, values, vector, **kwargs)">
use values::computed::ComputedValueAsSpecified; use values::computed::ComputedValueAsSpecified;
use values::NoViewportPercentage; use values::NoViewportPercentage;
impl ComputedValueAsSpecified for SpecifiedValue {} impl ComputedValueAsSpecified for SpecifiedValue {}
@ -294,16 +294,16 @@
</%call> </%call>
</%def> </%def>
<%def name="single_keyword_computed(name, values, **kwargs)"> <%def name="single_keyword_computed(name, values, vector=False, **kwargs)">
<% <%
keyword_kwargs = {a: kwargs.pop(a, None) for a in [ keyword_kwargs = {a: kwargs.pop(a, None) for a in [
'gecko_constant_prefix', 'gecko_enum_prefix', 'gecko_constant_prefix', 'gecko_enum_prefix',
'extra_gecko_values', 'extra_servo_values', 'extra_gecko_values', 'extra_servo_values',
]} ]}
%> %>
<%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
<%def name="inner_body()">
pub use self::computed_value::T as SpecifiedValue; pub use self::computed_value::T as SpecifiedValue;
${caller.body()}
pub mod computed_value { pub mod computed_value {
define_css_keyword_enum! { T: define_css_keyword_enum! { T:
% for value in data.longhands_by_name[name].keyword.values_for(product): % for value in data.longhands_by_name[name].keyword.values_for(product):
@ -316,11 +316,26 @@
computed_value::T::${to_rust_ident(values.split()[0])} computed_value::T::${to_rust_ident(values.split()[0])}
} }
#[inline] #[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
get_initial_value()
}
#[inline]
pub fn parse(_context: &ParserContext, input: &mut Parser) pub fn parse(_context: &ParserContext, input: &mut Parser)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ()> {
computed_value::T::parse(input) computed_value::T::parse(input)
} }
</%call> </%def>
% if vector:
<%call expr="vector_longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
${inner_body()}
${caller.body()}
</%call>
% else:
<%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
${inner_body()}
${caller.body()}
</%call>
% endif
</%def> </%def>
<%def name="keyword_list(name, values, **kwargs)"> <%def name="keyword_list(name, values, **kwargs)">
@ -464,6 +479,36 @@
} }
} }
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let mut all_inherit = true;
let mut all_initial = true;
let mut with_variables = false;
% for sub_property in shorthand.sub_properties:
match *self.${sub_property.ident} {
DeclaredValue::Initial => all_inherit = false,
DeclaredValue::Inherit => all_initial = false,
DeclaredValue::WithVariables {..} => with_variables = true,
DeclaredValue::Value(..) => {
all_initial = false;
all_inherit = false;
}
}
% endfor
if with_variables {
// We don't serialize shorthands with variables
dest.write_str("")
} else if all_inherit {
dest.write_str("inherit")
} else if all_initial {
dest.write_str("initial")
} else {
self.to_css_declared(dest)
}
}
}
pub fn parse(context: &ParserContext, input: &mut Parser, pub fn parse(context: &ParserContext, input: &mut Parser,
declarations: &mut Vec<PropertyDeclaration>) declarations: &mut Vec<PropertyDeclaration>)
@ -526,8 +571,8 @@
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
super::serialize_four_sides( super::serialize_four_sides(
dest, dest,
self.${to_rust_ident(sub_property_pattern % 'top')}, self.${to_rust_ident(sub_property_pattern % 'top')},

View file

@ -155,6 +155,18 @@ pub trait Interpolate: Sized {
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()>; fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()>;
} }
/// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list
pub trait RepeatableListInterpolate: Interpolate {}
impl<T: RepeatableListInterpolate> Interpolate for Vec<T> {
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
use num_integer::lcm;
let len = lcm(self.len(), other.len());
self.iter().cycle().zip(other.iter().cycle()).take(len).map(|(me, you)| {
me.interpolate(you, time)
}).collect()
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-number /// https://drafts.csswg.org/css-transitions/#animtype-number
impl Interpolate for Au { impl Interpolate for Au {
#[inline] #[inline]
@ -296,6 +308,14 @@ impl Interpolate for BorderSpacing {
} }
} }
impl Interpolate for BackgroundSize {
#[inline]
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
self.0.interpolate(&other.0, time).map(BackgroundSize)
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-color /// https://drafts.csswg.org/css-transitions/#animtype-color
impl Interpolate for RGBA { impl Interpolate for RGBA {
#[inline] #[inline]
@ -496,18 +516,12 @@ impl Interpolate for Position {
} }
} }
impl Interpolate for BackgroundSize { impl RepeatableListInterpolate for Position {}
impl Interpolate for BackgroundPosition {
#[inline]
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> { fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
use properties::longhands::background_size::computed_value::ExplicitSize; Ok(BackgroundPosition(try!(self.0.interpolate(&other.0, time))))
match (self, other) {
(&BackgroundSize::Explicit(ref me), &BackgroundSize::Explicit(ref other)) => {
Ok(BackgroundSize::Explicit(ExplicitSize {
width: try!(me.width.interpolate(&other.width, time)),
height: try!(me.height.interpolate(&other.height, time)),
}))
}
_ => Err(()),
}
} }
} }

View file

@ -10,7 +10,7 @@ ${helpers.predefined_type("background-color", "CSSColor",
"::cssparser::Color::RGBA(::cssparser::RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */", "::cssparser::Color::RGBA(::cssparser::RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */",
animatable=True)} animatable=True)}
<%helpers:vector_longhand gecko_only="True" name="background-image" animatable="False"> <%helpers:vector_longhand name="background-image" animatable="False">
use cssparser::ToCss; use cssparser::ToCss;
use std::fmt; use std::fmt;
use values::specified::Image; use values::specified::Image;
@ -54,6 +54,10 @@ ${helpers.predefined_type("background-color", "CSSColor",
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
computed_value::T(None) computed_value::T(None)
} }
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(None)
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
Ok(SpecifiedValue(None)) Ok(SpecifiedValue(None))
@ -75,7 +79,7 @@ ${helpers.predefined_type("background-color", "CSSColor",
} }
</%helpers:vector_longhand> </%helpers:vector_longhand>
<%helpers:longhand name="background-position" animatable="True"> <%helpers:vector_longhand name="background-position" animatable="True">
use cssparser::ToCss; use cssparser::ToCss;
use std::fmt; use std::fmt;
use values::LocalToCss; use values::LocalToCss;
@ -84,6 +88,7 @@ ${helpers.predefined_type("background-color", "CSSColor",
pub mod computed_value { pub mod computed_value {
use values::computed::position::Position; use values::computed::position::Position;
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
pub type T = Position; pub type T = Position;
} }
@ -98,30 +103,42 @@ ${helpers.predefined_type("background-color", "CSSColor",
vertical: computed::LengthOrPercentage::Percentage(0.0), vertical: computed::LengthOrPercentage::Percentage(0.0),
} }
} }
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
use values::specified::Percentage;
Position {
horizontal: specified::LengthOrPercentage::Percentage(Percentage(0.0)),
vertical: specified::LengthOrPercentage::Percentage(Percentage(0.0)),
}
}
pub fn parse(_context: &ParserContext, input: &mut Parser) pub fn parse(_context: &ParserContext, input: &mut Parser)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ()> {
Ok(try!(Position::parse(input))) Ok(try!(Position::parse(input)))
} }
</%helpers:longhand> </%helpers:vector_longhand>
${helpers.single_keyword("background-repeat", ${helpers.single_keyword("background-repeat",
"repeat repeat-x repeat-y no-repeat", "repeat repeat-x repeat-y no-repeat",
vector=True,
animatable=False)} animatable=False)}
${helpers.single_keyword("background-attachment", ${helpers.single_keyword("background-attachment",
"scroll fixed" + (" local" if product == "gecko" else ""), "scroll fixed" + (" local" if product == "gecko" else ""),
vector=True,
animatable=False)} animatable=False)}
${helpers.single_keyword("background-clip", ${helpers.single_keyword("background-clip",
"border-box padding-box content-box", "border-box padding-box content-box",
vector=True,
animatable=False)} animatable=False)}
${helpers.single_keyword("background-origin", ${helpers.single_keyword("background-origin",
"padding-box border-box content-box", "padding-box border-box content-box",
vector=True,
animatable=False)} animatable=False)}
<%helpers:longhand name="background-size" animatable="True"> <%helpers:vector_longhand name="background-size" animatable="True">
use cssparser::{ToCss, Token}; use cssparser::{ToCss, Token};
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::fmt; use std::fmt;
@ -129,6 +146,7 @@ ${helpers.single_keyword("background-origin",
pub mod computed_value { pub mod computed_value {
use values::computed::LengthOrPercentageOrAuto; use values::computed::LengthOrPercentageOrAuto;
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -144,6 +162,23 @@ ${helpers.single_keyword("background-origin",
Cover, Cover,
Contain, Contain,
} }
impl RepeatableListInterpolate for T {}
impl Interpolate for T {
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
use properties::longhands::background_size::single_value::computed_value::ExplicitSize;
match (self, other) {
(&T::Explicit(ref me), &T::Explicit(ref other)) => {
Ok(T::Explicit(ExplicitSize {
width: try!(me.width.interpolate(&other.width, time)),
height: try!(me.height.interpolate(&other.height, time)),
}))
}
_ => Err(()),
}
}
}
} }
impl ToCss for computed_value::T { impl ToCss for computed_value::T {
@ -237,6 +272,13 @@ ${helpers.single_keyword("background-origin",
height: computed::LengthOrPercentageOrAuto::Auto, height: computed::LengthOrPercentageOrAuto::Auto,
}) })
} }
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue::Explicit(SpecifiedExplicitSize {
width: specified::LengthOrPercentageOrAuto::Auto,
height: specified::LengthOrPercentageOrAuto::Auto,
})
}
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
let width; let width;
@ -274,4 +316,4 @@ ${helpers.single_keyword("background-origin",
height: height, height: height,
})) }))
} }
</%helpers:longhand> </%helpers:vector_longhand>

View file

@ -2034,6 +2034,10 @@ pub fn cascade(viewport_size: Size2D<Au>,
} }
% endfor % endfor
% if product == "gecko":
style.mutate_background().fill_arrays();
% endif
// The initial value of outline width may be changed at computed value time. // The initial value of outline width may be changed at computed value time.
if style.get_outline().clone_outline_style().none_or_hidden() && if style.get_outline().clone_outline_style().none_or_hidden() &&
style.get_outline().outline_has_nonzero_width() { style.get_outline().outline_has_nonzero_width() {

View file

@ -12,172 +12,204 @@
use properties::longhands::{background_image, background_size, background_origin, background_clip}; use properties::longhands::{background_image, background_size, background_origin, background_clip};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
let mut color = None; let mut background_color = None;
let mut image = None;
let mut position = None;
let mut repeat = None;
let mut size = None;
let mut attachment = None;
let mut any = false;
let mut origin = None;
let mut clip = None;
loop { % for name in "image position repeat size attachment origin clip".split():
if position.is_none() { let mut background_${name} = background_${name}::SpecifiedValue(Vec::new());
if let Ok(value) = input.try(|input| background_position::parse(context, input)) { % endfor
position = Some(value); try!(input.parse_comma_separated(|input| {
any = true; % for name in "image position repeat size attachment origin clip".split():
let mut ${name} = None;
// Parse background size, if applicable. % endfor
size = input.try(|input| { loop {
try!(input.expect_delim('/'));
background_size::parse(context, input)
}).ok();
continue
}
}
if color.is_none() {
if let Ok(value) = input.try(|input| background_color::parse(context, input)) { if let Ok(value) = input.try(|input| background_color::parse(context, input)) {
color = Some(value); if background_color.is_none() {
any = true; background_color = Some(value);
continue continue
} else {
// color can only be the last element
return Err(())
}
} }
} if position.is_none() {
if image.is_none() { if let Ok(value) = input.try(|input| background_position::single_value
if let Ok(value) = input.try(|input| background_image::parse(context, input)) { ::parse(context, input)) {
image = Some(value); position = Some(value);
any = true;
continue // Parse background size, if applicable.
size = input.try(|input| {
try!(input.expect_delim('/'));
background_size::single_value::parse(context, input)
}).ok();
continue
}
} }
} % for name in "image repeat attachment origin clip".split():
if repeat.is_none() { if ${name}.is_none() {
if let Ok(value) = input.try(|input| background_repeat::parse(context, input)) { if let Ok(value) = input.try(|input| background_${name}::single_value
repeat = Some(value); ::parse(context, input)) {
any = true; ${name} = Some(value);
continue continue
}
}
if attachment.is_none() {
if let Ok(value) = input.try(|input| background_attachment::parse(context, input)) {
attachment = Some(value);
any = true;
continue
}
}
if origin.is_none() {
if let Ok(value) = input.try(|input| background_origin::parse(context, input)) {
origin = Some(value);
any = true;
continue
}
}
if clip.is_none() {
if let Ok(value) = input.try(|input| background_clip::parse(context, input)) {
clip = Some(value);
any = true;
continue
}
}
break
}
if any {
Ok(Longhands {
background_color: color,
background_image: image,
background_position: position,
background_repeat: repeat,
background_attachment: attachment,
background_size: size,
background_origin: origin,
background_clip: clip,
})
} else {
Err(())
}
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self.background_color {
DeclaredValue::Value(ref color) => {
try!(color.to_css(dest));
},
_ => {
try!(write!(dest, "transparent"));
}
};
try!(write!(dest, " "));
match *self.background_image {
DeclaredValue::Value(ref image) => {
try!(image.to_css(dest));
},
_ => {
try!(write!(dest, "none"));
}
};
try!(write!(dest, " "));
try!(self.background_repeat.to_css(dest));
try!(write!(dest, " "));
match *self.background_attachment {
DeclaredValue::Value(ref attachment) => {
try!(attachment.to_css(dest));
},
_ => {
try!(write!(dest, "scroll"));
}
};
try!(write!(dest, " "));
try!(self.background_position.to_css(dest));
if let DeclaredValue::Value(ref size) = *self.background_size {
try!(write!(dest, " / "));
try!(size.to_css(dest));
}
match (self.background_origin, self.background_clip) {
(&DeclaredValue::Value(ref origin), &DeclaredValue::Value(ref clip)) => {
use properties::longhands::background_origin::computed_value::T as Origin;
use properties::longhands::background_clip::computed_value::T as Clip;
try!(write!(dest, " "));
match (origin, clip) {
(&Origin::padding_box, &Clip::padding_box) => {
try!(origin.to_css(dest));
},
(&Origin::border_box, &Clip::border_box) => {
try!(origin.to_css(dest));
},
(&Origin::content_box, &Clip::content_box) => {
try!(origin.to_css(dest));
},
_ => {
try!(origin.to_css(dest));
try!(write!(dest, " "));
try!(clip.to_css(dest));
} }
} }
}, % endfor
(&DeclaredValue::Value(ref origin), _) => { break
try!(write!(dest, " ")); }
try!(origin.to_css(dest)); let mut any = false;
}, % for name in "image position repeat size attachment origin clip".split():
(_, &DeclaredValue::Value(ref clip)) => { any = any || ${name}.is_some();
try!(write!(dest, " ")); % endfor
try!(clip.to_css(dest)); any = any || background_color.is_some();
}, if any {
_ => {} % for name in "image position repeat size attachment origin clip".split():
}; if let Some(bg_${name}) = ${name} {
background_${name}.0.push(bg_${name});
} else {
background_${name}.0.push(background_${name}::single_value
::get_initial_specified_value());
}
% endfor
Ok(())
} else {
Err(())
}
}));
Ok(Longhands {
background_color: background_color,
background_image: Some(background_image),
background_position: Some(background_position),
background_repeat: Some(background_repeat),
background_attachment: Some(background_attachment),
background_size: Some(background_size),
background_origin: Some(background_origin),
background_clip: Some(background_clip),
})
}
impl<'a> LonghandsToSerialize<'a> {
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
// mako doesn't like ampersands following `<`
fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
match *x {
DeclaredValue::Value(ref val) => Some(val),
_ => None,
}
}
use std::cmp;
let mut len = 0;
% for name in "image position repeat size attachment origin clip".split():
len = cmp::max(len, extract_value(self.background_${name}).map(|i| i.0.len())
.unwrap_or(0));
% endfor
// There should be at least one declared value
if len == 0 {
return dest.write_str("")
}
let mut first = true;
for i in 0..len {
% for name in "image position repeat size attachment origin clip".split():
let ${name} = if let DeclaredValue::Value(ref arr) = *self.background_${name} {
arr.0.get(i % arr.0.len())
} else {
None
};
% endfor
let color = if i == len - 1 {
Some(self.background_color)
} else {
None
};
if first {
first = false;
} else {
try!(write!(dest, ", "));
}
match color {
Some(&DeclaredValue::Value(ref color)) => {
try!(color.to_css(dest));
try!(write!(dest, " "));
},
Some(_) => {
try!(write!(dest, "transparent "));
}
// Not yet the last one
None => ()
};
if let Some(image) = image {
try!(image.to_css(dest));
} else {
try!(write!(dest, "none"));
}
try!(write!(dest, " "));
if let Some(repeat) = repeat {
try!(repeat.to_css(dest));
} else {
try!(write!(dest, "repeat"));
}
try!(write!(dest, " "));
if let Some(attachment) = attachment {
try!(attachment.to_css(dest));
} else {
try!(write!(dest, "scroll"));
}
try!(write!(dest, " "));
try!(position.unwrap_or(&background_position::single_value
::get_initial_specified_value())
.to_css(dest));
if let Some(size) = size {
try!(write!(dest, " / "));
try!(size.to_css(dest));
}
match (origin, clip) {
(Some(origin), Some(clip)) => {
use properties::longhands::background_origin::single_value::computed_value::T as Origin;
use properties::longhands::background_clip::single_value::computed_value::T as Clip;
try!(write!(dest, " "));
match (origin, clip) {
(&Origin::padding_box, &Clip::padding_box) => {
try!(origin.to_css(dest));
},
(&Origin::border_box, &Clip::border_box) => {
try!(origin.to_css(dest));
},
(&Origin::content_box, &Clip::content_box) => {
try!(origin.to_css(dest));
},
_ => {
try!(origin.to_css(dest));
try!(write!(dest, " "));
try!(clip.to_css(dest));
}
}
},
(Some(origin), _) => {
try!(write!(dest, " "));
try!(origin.to_css(dest));
},
(_, Some(clip)) => {
try!(write!(dest, " "));
try!(clip.to_css(dest));
},
_ => {}
};
}
Ok(()) Ok(())

View file

@ -25,8 +25,8 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style",
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
// extract tuple container values so that the different border widths // extract tuple container values so that the different border widths
// can be compared via partial eq // can be compared via partial eq
% for side in ["top", "right", "bottom", "left"]: % for side in ["top", "right", "bottom", "left"]:
@ -102,8 +102,8 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
super::serialize_directional_border( super::serialize_directional_border(
dest, dest,
self.border_${side}_width, self.border_${side}_width,
@ -134,8 +134,8 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
// If all longhands are all present, then all sides should be the same, // If all longhands are all present, then all sides should be the same,
// so we can just one set of color/style/width // so we can just one set of color/style/width
super::serialize_directional_border( super::serialize_directional_border(
@ -170,8 +170,8 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
// TODO: I do not understand how border radius works with respect to the slashes /, // TODO: I do not understand how border radius works with respect to the slashes /,
// so putting a default generic impl for now // so putting a default generic impl for now
// https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius // https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.border_top_left_radius.to_css(dest)); try!(self.border_top_left_radius.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));

View file

@ -19,8 +19,8 @@
// Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal // Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
// values, they no longer use the shared property name "overflow". // values, they no longer use the shared property name "overflow".
// Other shorthands do not include their name in the to_css method // Other shorthands do not include their name in the to_css method
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let x_and_y_equal = match (self.overflow_x, self.overflow_y) { let x_and_y_equal = match (self.overflow_x, self.overflow_y) {
(&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => { (&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => {
*x_value == y_container.0 *x_value == y_container.0
@ -132,8 +132,8 @@ macro_rules! try_parse_one {
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.transition_property.to_css(dest)); try!(self.transition_property.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));
@ -268,8 +268,8 @@ macro_rules! try_parse_one {
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.animation_duration.to_css(dest)); try!(self.animation_duration.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));

View file

@ -48,8 +48,8 @@
} }
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.column_width.to_css(dest)); try!(self.column_width.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));

View file

@ -68,8 +68,8 @@
} }
// This may be a bit off, unsure, possibly needs changes // This may be a bit off, unsure, possibly needs changes
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
if let DeclaredValue::Value(ref style) = *self.font_style { if let DeclaredValue::Value(ref style) = *self.font_style {
try!(style.to_css(dest)); try!(style.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));

View file

@ -15,8 +15,8 @@
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.overflow_wrap.to_css(dest) self.overflow_wrap.to_css(dest)
} }
} }

View file

@ -92,8 +92,8 @@
} }
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self.list_style_position { match *self.list_style_position {
DeclaredValue::Initial => try!(write!(dest, "outside")), DeclaredValue::Initial => try!(write!(dest, "outside")),
_ => try!(self.list_style_position.to_css(dest)) _ => try!(self.list_style_position.to_css(dest))

View file

@ -49,8 +49,8 @@
} }
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.outline_width.to_css(dest)); try!(self.outline_width.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));
@ -89,8 +89,8 @@
} }
// TODO: Border radius for the radius shorthand is not implemented correctly yet // TODO: Border radius for the radius shorthand is not implemented correctly yet
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self._moz_outline_radius_topleft.to_css(dest)); try!(self._moz_outline_radius_topleft.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));

View file

@ -38,8 +38,8 @@
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self.flex_direction { match *self.flex_direction {
DeclaredValue::Initial => try!(write!(dest, "row")), DeclaredValue::Initial => try!(write!(dest, "row")),
_ => try!(self.flex_direction.to_css(dest)) _ => try!(self.flex_direction.to_css(dest))
@ -107,8 +107,8 @@
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.flex_grow.to_css(dest)); try!(self.flex_grow.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));

View file

@ -46,8 +46,8 @@
}) })
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self.text_decoration_line { match *self.text_decoration_line {
DeclaredValue::Value(ref line) => { DeclaredValue::Value(ref line) => {
try!(line.to_css(dest)); try!(line.to_css(dest));

1
ports/cef/Cargo.lock generated
View file

@ -2119,6 +2119,7 @@ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1", "plugins 0.0.1",

View file

@ -234,6 +234,14 @@ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "num-integer"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.1.35" version = "0.1.35"
@ -363,6 +371,7 @@ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -335,6 +335,8 @@ extern "C" {
pub fn Gecko_DestroyClipPath(clip: *mut StyleClipPath); pub fn Gecko_DestroyClipPath(clip: *mut StyleClipPath);
pub fn Gecko_NewBasicShape(type_: StyleBasicShapeType) pub fn Gecko_NewBasicShape(type_: StyleBasicShapeType)
-> *mut StyleBasicShape; -> *mut StyleBasicShape;
pub fn Gecko_FillAllBackgroundLists(layers: *mut nsStyleImageLayers,
maxLen: u32);
pub fn Gecko_AddRefCalcArbitraryThread(aPtr: *mut Calc); pub fn Gecko_AddRefCalcArbitraryThread(aPtr: *mut Calc);
pub fn Gecko_ReleaseCalcArbitraryThread(aPtr: *mut Calc); pub fn Gecko_ReleaseCalcArbitraryThread(aPtr: *mut Calc);
pub fn Gecko_Construct_nsStyleFont(ptr: *mut nsStyleFont); pub fn Gecko_Construct_nsStyleFont(ptr: *mut nsStyleFont);

View file

@ -3,13 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::iter::{once, Chain, Once, IntoIterator}; use std::iter::{once, Chain, Once, IntoIterator};
use std::slice::IterMut; use std::slice::{Iter, IterMut};
use structs::nsStyleAutoArray; use structs::nsStyleAutoArray;
impl<T> nsStyleAutoArray<T> { impl<T> nsStyleAutoArray<T> {
pub fn iter_mut(&mut self) -> Chain<Once<&mut T>, IterMut<T>> { pub fn iter_mut(&mut self) -> Chain<Once<&mut T>, IterMut<T>> {
once(&mut self.mFirstElement).chain(self.mOtherElements.iter_mut()) once(&mut self.mFirstElement).chain(self.mOtherElements.iter_mut())
} }
pub fn iter(&self) -> Chain<Once<&T>, Iter<T>> {
once(&self.mFirstElement).chain(self.mOtherElements.iter())
}
// Note that often structs containing autoarrays will have // Note that often structs containing autoarrays will have
// additional member fields that contain the length, which must be kept // additional member fields that contain the length, which must be kept

View file

@ -679,18 +679,44 @@ mod shorthand_serialization {
*/ */
mod background { mod background {
use style::properties::longhands::background_attachment::computed_value::T as Attachment; use style::properties::longhands::background_attachment as attachment;
use style::properties::longhands::background_clip::computed_value::T as Clip; use style::properties::longhands::background_clip as clip;
use style::properties::longhands::background_image::SpecifiedValue as ImageContainer; use style::properties::longhands::background_image as image;
use style::properties::longhands::background_origin::computed_value::T as Origin; use style::properties::longhands::background_origin as origin;
use style::properties::longhands::background_position::SpecifiedValue as PositionContainer; use style::properties::longhands::background_position as position;
use style::properties::longhands::background_repeat::computed_value::T as Repeat; use style::properties::longhands::background_repeat as repeat;
use style::properties::longhands::background_size::SpecifiedExplicitSize; use style::properties::longhands::background_size as size;
use style::properties::longhands::background_size::SpecifiedValue as Size;
use style::values::specified::Image; use style::values::specified::Image;
use style::values::specified::position::Position; use style::values::specified::position::Position;
use super::*; use super::*;
macro_rules! single_vec_value_typedef {
($name:ident, $path:expr) => {
DeclaredValue::Value($name::SpecifiedValue(
vec![$path]
))
};
}
macro_rules! single_vec_value {
($name:ident, $path:expr) => {
DeclaredValue::Value($name::SpecifiedValue(
vec![$name::single_value::SpecifiedValue($path)]
))
};
}
macro_rules! single_vec_keyword_value {
($name:ident, $kw:ident) => {
DeclaredValue::Value($name::SpecifiedValue(
vec![$name::single_value::SpecifiedValue::$kw]
))
};
}
macro_rules! single_vec_variant_value {
($name:ident, $variant:expr) => {
DeclaredValue::Value($name::SpecifiedValue(
vec![$variant]
))
};
}
#[test] #[test]
fn background_should_serialize_all_available_properties_when_specified() { fn background_should_serialize_all_available_properties_when_specified() {
let mut properties = Vec::new(); let mut properties = Vec::new();
@ -700,29 +726,31 @@ mod shorthand_serialization {
authored: None authored: None
}); });
let position = DeclaredValue::Value( let position = single_vec_value_typedef!(position,
Position { Position {
horizontal: LengthOrPercentage::Length(Length::from_px(7f32)), horizontal: LengthOrPercentage::Length(Length::from_px(7f32)),
vertical: LengthOrPercentage::Length(Length::from_px(4f32)) vertical: LengthOrPercentage::Length(Length::from_px(4f32))
} }
); );
let repeat = DeclaredValue::Value(Repeat::repeat_x); let repeat = single_vec_keyword_value!(repeat, repeat_x);
let attachment = DeclaredValue::Value(Attachment::scroll); let attachment = single_vec_keyword_value!(attachment, scroll);
let image = DeclaredValue::Value(ImageContainer( let image = single_vec_value!(image,
Some(Image::Url(Url::parse("http://servo/test.png").unwrap(), UrlExtraData {})) Some(Image::Url(Url::parse("http://servo/test.png").unwrap(),
)); UrlExtraData {})));
let size = DeclaredValue::Value( let size = single_vec_variant_value!(size,
Size::Explicit(SpecifiedExplicitSize { size::single_value::SpecifiedValue::Explicit(
width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)), size::single_value::SpecifiedExplicitSize {
height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32)) width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)),
} height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32))
)); }
)
);
let origin = DeclaredValue::Value(Origin::border_box); let origin = single_vec_keyword_value!(origin, border_box);
let clip = DeclaredValue::Value(Clip::padding_box); let clip = single_vec_keyword_value!(clip, padding_box);
properties.push(PropertyDeclaration::BackgroundColor(color)); properties.push(PropertyDeclaration::BackgroundColor(color));
properties.push(PropertyDeclaration::BackgroundPosition(position)); properties.push(PropertyDeclaration::BackgroundPosition(position));
@ -751,29 +779,31 @@ mod shorthand_serialization {
authored: None authored: None
}); });
let position = DeclaredValue::Value( let position = single_vec_value_typedef!(position,
Position { Position {
horizontal: LengthOrPercentage::Length(Length::from_px(7f32)), horizontal: LengthOrPercentage::Length(Length::from_px(7f32)),
vertical: LengthOrPercentage::Length(Length::from_px(4f32)) vertical: LengthOrPercentage::Length(Length::from_px(4f32))
} }
); );
let repeat = DeclaredValue::Value(Repeat::repeat_x); let repeat = single_vec_keyword_value!(repeat, repeat_x);
let attachment = DeclaredValue::Value(Attachment::scroll); let attachment = single_vec_keyword_value!(attachment, scroll);
let image = DeclaredValue::Value(ImageContainer( let image = single_vec_value!(image,
Some(Image::Url(Url::parse("http://servo/test.png").unwrap(), UrlExtraData {})) Some(Image::Url(Url::parse("http://servo/test.png").unwrap(),
)); UrlExtraData {})));
let size = DeclaredValue::Value( let size = single_vec_variant_value!(size,
Size::Explicit(SpecifiedExplicitSize { size::single_value::SpecifiedValue::Explicit(
width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)), size::single_value::SpecifiedExplicitSize {
height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32)) width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)),
}) height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32))
}
)
); );
let origin = DeclaredValue::Value(Origin::padding_box); let origin = single_vec_keyword_value!(origin, padding_box);
let clip = DeclaredValue::Value(Clip::padding_box); let clip = single_vec_keyword_value!(clip, padding_box);
properties.push(PropertyDeclaration::BackgroundColor(color)); properties.push(PropertyDeclaration::BackgroundColor(color));
properties.push(PropertyDeclaration::BackgroundPosition(position)); properties.push(PropertyDeclaration::BackgroundPosition(position));
@ -801,17 +831,17 @@ mod shorthand_serialization {
authored: None authored: None
}); });
let position = DeclaredValue::Value( let position = single_vec_value_typedef!(position,
Position { Position {
horizontal: LengthOrPercentage::Length(Length::from_px(0f32)), horizontal: LengthOrPercentage::Length(Length::from_px(0f32)),
vertical: LengthOrPercentage::Length(Length::from_px(0f32)) vertical: LengthOrPercentage::Length(Length::from_px(0f32))
} }
); );
let repeat = DeclaredValue::Value(Repeat::repeat_x); let repeat = single_vec_keyword_value!(repeat, repeat_x);
let attachment = DeclaredValue::Value(Attachment::scroll); let attachment = single_vec_keyword_value!(attachment, scroll);
let image = DeclaredValue::Value(ImageContainer(None)); let image = single_vec_value!(image, None);
let size = DeclaredValue::Initial; let size = DeclaredValue::Initial;

View file

@ -191,19 +191,40 @@ fn test_parse_stylesheet() {
} }
)), )),
Importance::Normal), Importance::Normal),
(PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial), (PropertyDeclaration::BackgroundPosition(DeclaredValue::Value(
longhands::background_position::SpecifiedValue(
vec![longhands::background_position::single_value
::get_initial_specified_value()]))),
Importance::Normal), Importance::Normal),
(PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial), (PropertyDeclaration::BackgroundRepeat(DeclaredValue::Value(
longhands::background_repeat::SpecifiedValue(
vec![longhands::background_repeat::single_value
::get_initial_specified_value()]))),
Importance::Normal), Importance::Normal),
(PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial), (PropertyDeclaration::BackgroundAttachment(DeclaredValue::Value(
longhands::background_attachment::SpecifiedValue(
vec![longhands::background_attachment::single_value
::get_initial_specified_value()]))),
Importance::Normal), Importance::Normal),
(PropertyDeclaration::BackgroundImage(DeclaredValue::Initial), (PropertyDeclaration::BackgroundImage(DeclaredValue::Value(
longhands::background_image::SpecifiedValue(
vec![longhands::background_image::single_value
::get_initial_specified_value()]))),
Importance::Normal), Importance::Normal),
(PropertyDeclaration::BackgroundSize(DeclaredValue::Initial), (PropertyDeclaration::BackgroundSize(DeclaredValue::Value(
longhands::background_size::SpecifiedValue(
vec![longhands::background_size::single_value
::get_initial_specified_value()]))),
Importance::Normal), Importance::Normal),
(PropertyDeclaration::BackgroundOrigin(DeclaredValue::Initial), (PropertyDeclaration::BackgroundOrigin(DeclaredValue::Value(
longhands::background_origin::SpecifiedValue(
vec![longhands::background_origin::single_value
::get_initial_specified_value()]))),
Importance::Normal), Importance::Normal),
(PropertyDeclaration::BackgroundClip(DeclaredValue::Initial), (PropertyDeclaration::BackgroundClip(DeclaredValue::Value(
longhands::background_clip::SpecifiedValue(
vec![longhands::background_clip::single_value
::get_initial_specified_value()]))),
Importance::Normal), Importance::Normal),
]), ]),
important_count: 0, important_count: 0,

View file

@ -1,35 +0,0 @@
[cssom-setProperty-shorthand.htm]
type: testharness
[shorthand font can be set with setProperty]
expected: FAIL
[shorthand border-top can be set with setProperty]
expected: FAIL
[shorthand border-right can be set with setProperty]
expected: FAIL
[shorthand border-bottom can be set with setProperty]
expected: FAIL
[shorthand border-left can be set with setProperty]
expected: FAIL
[shorthand border can be set with setProperty]
expected: FAIL
[shorthand list-style can be set with setProperty]
expected: FAIL
[shorthand outline can be set with setProperty]
expected: FAIL
[shorthand background can be set with setProperty]
expected: FAIL
[shorthand overflow can be set with setProperty]
expected: FAIL
[shorthand border-radius can be set with setProperty]
expected: FAIL

View file

@ -3564,6 +3564,30 @@
"url": "/_mozilla/css/mix_blend_mode_a.html" "url": "/_mozilla/css/mix_blend_mode_a.html"
} }
], ],
"css/multiple_backgrounds.html": [
{
"path": "css/multiple_backgrounds.html",
"references": [
[
"/_mozilla/css/multiple_backgrounds_ref.html",
"=="
]
],
"url": "/_mozilla/css/multiple_backgrounds.html"
}
],
"css/multiple_backgrounds_ref.html": [
{
"path": "css/multiple_backgrounds_ref.html",
"references": [
[
"/_mozilla/css/multiple_backgrounds_ref.html",
"=="
]
],
"url": "/_mozilla/css/multiple_backgrounds_ref.html"
}
],
"css/multiple_css_class_a.html": [ "css/multiple_css_class_a.html": [
{ {
"path": "css/multiple_css_class_a.html", "path": "css/multiple_css_class_a.html",
@ -12832,6 +12856,30 @@
"url": "/_mozilla/css/mix_blend_mode_a.html" "url": "/_mozilla/css/mix_blend_mode_a.html"
} }
], ],
"css/multiple_backgrounds.html": [
{
"path": "css/multiple_backgrounds.html",
"references": [
[
"/_mozilla/css/multiple_backgrounds_ref.html",
"=="
]
],
"url": "/_mozilla/css/multiple_backgrounds.html"
}
],
"css/multiple_backgrounds_ref.html": [
{
"path": "css/multiple_backgrounds_ref.html",
"references": [
[
"/_mozilla/css/multiple_backgrounds_ref.html",
"=="
]
],
"url": "/_mozilla/css/multiple_backgrounds_ref.html"
}
],
"css/multiple_css_class_a.html": [ "css/multiple_css_class_a.html": [
{ {
"path": "css/multiple_css_class_a.html", "path": "css/multiple_css_class_a.html",

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

View file

@ -0,0 +1,31 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="match" href="multiple_backgrounds_ref.html">
<style type="text/css">
/* Example from
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Background_and_Borders/Using_CSS_multiple_backgrounds
(Public domain)
bubbles.png is from the above MDN page, by Mozilla contributors,
licensed under CC-BY-SA 2.5
Rust logo from https://www.rust-lang.org/logos/rust-logo-256x256.png,
licensed as CC-BY-SA 4.0, owned by Mozilla
*/
#multibg {
width: 700px;
height: 400px;
background: url(rust-logo-256x256.png) no-repeat bottom right / 256px 256px,
url(bubbles.png) no-repeat left / 700px 100%,
linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0)) no-repeat;
}
</style>
</head>
<body>
<div id="multibg">
</div>
</body>
</html>

View file

@ -0,0 +1,47 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="match" href="multiple_backgrounds_ref.html">
<style type="text/css">
/* Example from
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Background_and_Borders/Using_CSS_multiple_backgrounds
(Public domain)
bubbles.png is from the above MDN page, by Mozilla contributors,
licensed under CC-BY-SA 2.5
Rust logo from https://www.rust-lang.org/logos/rust-logo-256x256.png,
licensed as CC-BY-SA 4.0, owned by Mozilla
*/
#gradientbg {
width: 700px;
height: 400px;
background: linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0)) no-repeat;
}
#bubblesbg {
width: 100%;
height: 100%;
background: url(bubbles.png) no-repeat left / 700px 100%;
position: relative;
}
#rustbg {
width: 256px;
height: 256px;
background: url(rust-logo-256x256.png) no-repeat left / 256px 256px;
position: absolute;
bottom: 0;
right: 0;
}
</style>
</head>
<body>
<div id="gradientbg">
<div id="bubblesbg">
<div id="rustbg">
</div>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB