mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
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:
commit
c5e81f8361
32 changed files with 806 additions and 440 deletions
|
@ -60,6 +60,10 @@ use table_cell::CollapsedBordersForCell;
|
|||
use url::Url;
|
||||
use util::opts;
|
||||
|
||||
fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
|
||||
&arr[index % arr.len()]
|
||||
}
|
||||
|
||||
pub struct DisplayListBuildState<'a> {
|
||||
pub layout_context: &'a LayoutContext<'a>,
|
||||
pub items: Vec<DisplayItem>,
|
||||
|
@ -146,7 +150,7 @@ pub trait FragmentDisplayListBuilding {
|
|||
fn compute_background_image_size(&self,
|
||||
style: &ServoComputedValues,
|
||||
bounds: &Rect<Au>,
|
||||
image: &WebRenderImageInfo)
|
||||
image: &WebRenderImageInfo, index: usize)
|
||||
-> Size2D<Au>;
|
||||
|
||||
/// 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,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
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
|
||||
/// to the appropriate section of the display list.
|
||||
|
@ -344,27 +349,32 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
if !border_radii.is_square() {
|
||||
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
|
||||
// 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
|
||||
// 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.
|
||||
// http://dev.w3.org/csswg/css-backgrounds-3/#the-background-clip
|
||||
let mut bounds = *absolute_bounds;
|
||||
|
||||
match style.get_background().background_clip {
|
||||
background_clip::T::border_box => {}
|
||||
background_clip::T::padding_box => {
|
||||
// This is the clip for the color (which is the last element in the bg array)
|
||||
let color_clip = get_cyclic(&background.background_clip.0,
|
||||
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);
|
||||
bounds.origin.x = bounds.origin.x + border.left;
|
||||
bounds.origin.y = bounds.origin.y + border.top;
|
||||
bounds.size.width = bounds.size.width - border.horizontal();
|
||||
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);
|
||||
bounds.origin.x = bounds.origin.x + border_padding.left;
|
||||
bounds.origin.y = bounds.origin.y + border_padding.top;
|
||||
|
@ -388,23 +398,26 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
// Implements background image, per spec:
|
||||
// http://www.w3.org/TR/CSS21/colors.html#background
|
||||
let background = style.get_background();
|
||||
match background.background_image.0 {
|
||||
None => {}
|
||||
Some(computed::Image::LinearGradient(ref gradient)) => {
|
||||
self.build_display_list_for_background_linear_gradient(state,
|
||||
display_list_section,
|
||||
&bounds,
|
||||
&clip,
|
||||
gradient,
|
||||
style);
|
||||
}
|
||||
Some(computed::Image::Url(ref image_url, ref _extra_data)) => {
|
||||
self.build_display_list_for_background_image(state,
|
||||
style,
|
||||
display_list_section,
|
||||
&bounds,
|
||||
&clip,
|
||||
image_url);
|
||||
for (i, background_image) in background.background_image.0.iter().enumerate().rev() {
|
||||
match background_image.0 {
|
||||
None => {}
|
||||
Some(computed::Image::LinearGradient(ref gradient)) => {
|
||||
self.build_display_list_for_background_linear_gradient(state,
|
||||
display_list_section,
|
||||
&bounds,
|
||||
&clip,
|
||||
gradient,
|
||||
style);
|
||||
}
|
||||
Some(computed::Image::Url(ref image_url, ref _extra_data)) => {
|
||||
self.build_display_list_for_background_image(state,
|
||||
style,
|
||||
display_list_section,
|
||||
&bounds,
|
||||
&clip,
|
||||
image_url,
|
||||
i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +425,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
fn compute_background_image_size(&self,
|
||||
style: &ServoComputedValues,
|
||||
bounds: &Rect<Au>,
|
||||
image: &WebRenderImageInfo)
|
||||
image: &WebRenderImageInfo,
|
||||
index: usize)
|
||||
-> Size2D<Au> {
|
||||
// If `image_aspect_ratio` < `bounds_aspect_ratio`, the image is tall; otherwise, it is
|
||||
// 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 intrinsic_size = Size2D::new(Au::from_px(image.width as i32),
|
||||
Au::from_px(image.height as i32));
|
||||
match (style.get_background().background_size.clone(),
|
||||
image_aspect_ratio < bounds_aspect_ratio) {
|
||||
(background_size::T::Contain, false) | (background_size::T::Cover, true) => {
|
||||
let background_size = get_cyclic(&style.get_background().background_size.0, index).clone();
|
||||
match (background_size, image_aspect_ratio < bounds_aspect_ratio) {
|
||||
(background_size::single_value::T::Contain, false) |
|
||||
(background_size::single_value::T::Cover, true) => {
|
||||
Size2D::new(bounds.size.width,
|
||||
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),
|
||||
bounds.size.height)
|
||||
}
|
||||
|
||||
(background_size::T::Explicit(background_size::ExplicitSize {
|
||||
(background_size::single_value::T::Explicit(background_size::single_value
|
||||
::ExplicitSize {
|
||||
width,
|
||||
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))
|
||||
}
|
||||
|
||||
(background_size::T::Explicit(background_size::ExplicitSize {
|
||||
(background_size::single_value::T::Explicit(background_size::single_value
|
||||
::ExplicitSize {
|
||||
width: LengthOrPercentageOrAuto::Auto,
|
||||
height
|
||||
}), _) => {
|
||||
|
@ -450,7 +468,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
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,
|
||||
height
|
||||
}), _) => {
|
||||
|
@ -468,19 +487,22 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
display_list_section: DisplayListSection,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
clip: &ClippingRegion,
|
||||
image_url: &Url) {
|
||||
image_url: &Url,
|
||||
index: usize) {
|
||||
let background = style.get_background();
|
||||
let fetch_image_data_as_well = !opts::get().use_webrender;
|
||||
let webrender_image =
|
||||
state.layout_context.get_webrender_image_for_url(image_url,
|
||||
UsePlaceholder::No,
|
||||
fetch_image_data_as_well);
|
||||
|
||||
if let Some((webrender_image, image_data)) = webrender_image {
|
||||
debug!("(building display list) building background image");
|
||||
|
||||
// Use `background-size` to get the size.
|
||||
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.
|
||||
//
|
||||
|
@ -492,25 +514,27 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
let border = style.logical_border_width().to_physical(style.writing_mode);
|
||||
|
||||
// Use 'background-origin' to get the origin value.
|
||||
let (mut origin_x, mut origin_y) = match background.background_origin {
|
||||
background_origin::T::padding_box => {
|
||||
let origin = get_cyclic(&background.background_origin.0, index);
|
||||
let (mut origin_x, mut origin_y) = match *origin {
|
||||
background_origin::single_value::T::padding_box => {
|
||||
(Au(0), Au(0))
|
||||
}
|
||||
background_origin::T::border_box => {
|
||||
background_origin::single_value::T::border_box => {
|
||||
(-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);
|
||||
(border_padding.left - border.left, border_padding.top - border.top)
|
||||
}
|
||||
};
|
||||
|
||||
// Use `background-attachment` to get the initial virtual origin
|
||||
let (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
|
||||
background_attachment::T::scroll => {
|
||||
let attachment = get_cyclic(&background.background_attachment.0, index);
|
||||
let (virtual_origin_x, virtual_origin_y) = match *attachment {
|
||||
background_attachment::single_value::T::scroll => {
|
||||
(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
|
||||
// 'background-origin' has no effect.
|
||||
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.
|
||||
let horizontal_position = model::specified(background.background_position.horizontal,
|
||||
bounds.size.width - image_size.width);
|
||||
let vertical_position = model::specified(background.background_position.vertical,
|
||||
bounds.size.height - image_size.height);
|
||||
let horizontal_position = model::specified(position.horizontal,
|
||||
bounds.size.width - image_size.width);
|
||||
let vertical_position = model::specified(position.vertical,
|
||||
bounds.size.height - image_size.height);
|
||||
|
||||
let abs_x = border.left + virtual_origin_x + horizontal_position + origin_x;
|
||||
let abs_y = border.top + virtual_origin_y + vertical_position + origin_y;
|
||||
|
||||
// Adjust origin and size based on background-repeat
|
||||
match background.background_repeat {
|
||||
background_repeat::T::no_repeat => {
|
||||
match *get_cyclic(&background.background_repeat.0, index) {
|
||||
background_repeat::single_value::T::no_repeat => {
|
||||
bounds.origin.x = abs_x;
|
||||
bounds.origin.y = abs_y;
|
||||
bounds.size.width = image_size.width;
|
||||
bounds.size.height = image_size.height;
|
||||
}
|
||||
background_repeat::T::repeat_x => {
|
||||
background_repeat::single_value::T::repeat_x => {
|
||||
bounds.origin.y = abs_y;
|
||||
bounds.size.height = image_size.height;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
|
||||
|
@ -544,7 +569,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
abs_x,
|
||||
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.size.width = image_size.width;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
|
||||
|
@ -552,31 +577,32 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
abs_y,
|
||||
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,
|
||||
&mut bounds.size.width,
|
||||
abs_x,
|
||||
image_size.width.to_nearest_px() as u32);
|
||||
&mut bounds.size.width,
|
||||
abs_x,
|
||||
image_size.width.to_nearest_px() as u32);
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
|
||||
&mut bounds.size.height,
|
||||
abs_y,
|
||||
image_size.height.to_nearest_px() as u32);
|
||||
&mut bounds.size.height,
|
||||
abs_y,
|
||||
image_size.height.to_nearest_px() as u32);
|
||||
}
|
||||
};
|
||||
|
||||
// Create the image display item.
|
||||
let base = state.create_base_display_item(&bounds,
|
||||
&clip,
|
||||
self.node,
|
||||
style.get_cursor(Cursor::Default),
|
||||
display_list_section);
|
||||
&clip,
|
||||
self.node,
|
||||
style.get_cursor(Cursor::Default),
|
||||
display_list_section);
|
||||
state.add_display_item(DisplayItem::ImageClass(box ImageDisplayItem {
|
||||
base: base,
|
||||
webrender_image: webrender_image,
|
||||
image_data: image_data.map(Arc::new),
|
||||
stretch_size: Size2D::new(image_size.width, image_size.height),
|
||||
image_rendering: style.get_inheritedbox().image_rendering.clone(),
|
||||
base: base,
|
||||
webrender_image: webrender_image,
|
||||
image_data: image_data.map(Arc::new),
|
||||
stretch_size: Size2D::new(image_size.width, image_size.height),
|
||||
image_rendering: style.get_inheritedbox().image_rendering.clone(),
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -362,8 +362,11 @@ impl LayoutElementHelpers for LayoutJS<Element> {
|
|||
if let Some(url) = background {
|
||||
hints.push(from_declaration(
|
||||
PropertyDeclaration::BackgroundImage(DeclaredValue::Value(
|
||||
background_image::SpecifiedValue(Some(
|
||||
specified::Image::Url(url, specified::UrlExtraData { })))))));
|
||||
background_image::SpecifiedValue(vec![
|
||||
background_image::single_value::SpecifiedValue(Some(
|
||||
specified::Image::Url(url, specified::UrlExtraData { })
|
||||
))
|
||||
])))));
|
||||
}
|
||||
|
||||
let color = if let Some(this) = self.downcast::<HTMLFontElement>() {
|
||||
|
|
1
components/servo/Cargo.lock
generated
1
components/servo/Cargo.lock
generated
|
@ -2236,6 +2236,7 @@ dependencies = [
|
|||
"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)",
|
||||
"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)",
|
||||
"ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plugins 0.0.1",
|
||||
|
|
|
@ -34,6 +34,7 @@ heapsize_plugin = {version = "0.1.2", optional = true}
|
|||
lazy_static = "0.2"
|
||||
log = "0.3.5"
|
||||
matches = "0.1"
|
||||
num-integer = "0.1.32"
|
||||
num-traits = "0.1.32"
|
||||
ordered-float = "0.2.2"
|
||||
quickersort = "2.0.0"
|
||||
|
|
|
@ -56,6 +56,7 @@ extern crate log;
|
|||
#[allow(unused_extern_crates)]
|
||||
#[macro_use]
|
||||
extern crate matches;
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
extern crate ordered_float;
|
||||
extern crate quickersort;
|
||||
|
|
|
@ -937,6 +937,32 @@ fn static_assert() {
|
|||
|
||||
</%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
|
||||
// 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.
|
||||
|
@ -950,109 +976,105 @@ fn static_assert() {
|
|||
|
||||
<% impl_color("background_color", "mBackgroundColor", need_clone=True) %>
|
||||
|
||||
pub fn copy_background_repeat_from(&mut self, other: &Self) {
|
||||
self.gecko.mImage.mRepeatCount = cmp::min(1, other.gecko.mImage.mRepeatCount);
|
||||
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};
|
||||
<%self:simple_background_array_property name="repeat" field_name="mRepeat">
|
||||
use properties::longhands::background_repeat::single_value::computed_value::T;
|
||||
use gecko_bindings::structs::nsStyleImageLayers_Repeat;
|
||||
let (repeat_x, repeat_y) = match v {
|
||||
T::repeat_x => (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),
|
||||
T::repeat => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT,
|
||||
use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
|
||||
use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT;
|
||||
|
||||
let (repeat_x, repeat_y) = match servo {
|
||||
T::repeat_x => (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),
|
||||
T::no_repeat => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT,
|
||||
NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT),
|
||||
T::repeat => (NS_STYLE_IMAGELAYER_REPEAT_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.gecko.mImage.mLayers.mFirstElement.mRepeat = nsStyleImageLayers_Repeat {
|
||||
mXRepeat: repeat_x as u8,
|
||||
mYRepeat: repeat_y as u8,
|
||||
};
|
||||
}
|
||||
<%self:simple_background_array_property name="clip" field_name="mClip">
|
||||
use properties::longhands::background_clip::single_value::computed_value::T;
|
||||
|
||||
pub fn copy_background_clip_from(&mut self, other: &Self) {
|
||||
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 {
|
||||
match servo {
|
||||
T::border_box => structs::NS_STYLE_IMAGELAYER_CLIP_BORDER as u8,
|
||||
T::padding_box => structs::NS_STYLE_IMAGELAYER_CLIP_PADDING 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.gecko.mImage.mOriginCount = cmp::min(1, other.gecko.mImage.mOriginCount);
|
||||
self.gecko.mImage.mLayers.mFirstElement.mOrigin =
|
||||
other.gecko.mImage.mLayers.mFirstElement.mOrigin;
|
||||
}
|
||||
<%self:simple_background_array_property name="origin" field_name="mOrigin">
|
||||
use properties::longhands::background_origin::single_value::computed_value::T;
|
||||
|
||||
pub fn set_background_origin(&mut self, v: longhands::background_origin::computed_value::T) {
|
||||
use properties::longhands::background_origin::computed_value::T;
|
||||
|
||||
self.gecko.mImage.mOriginCount = 1;
|
||||
self.gecko.mImage.mLayers.mFirstElement.mOrigin = match v {
|
||||
match servo {
|
||||
T::border_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_BORDER as u8,
|
||||
T::padding_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_PADDING 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.gecko.mImage.mAttachmentCount = cmp::min(1, other.gecko.mImage.mAttachmentCount);
|
||||
self.gecko.mImage.mLayers.mFirstElement.mAttachment =
|
||||
other.gecko.mImage.mLayers.mFirstElement.mAttachment;
|
||||
}
|
||||
<%self:simple_background_array_property name="attachment" field_name="mAttachment">
|
||||
use properties::longhands::background_attachment::single_value::computed_value::T;
|
||||
|
||||
pub fn set_background_attachment(&mut self, v: longhands::background_attachment::computed_value::T) {
|
||||
use properties::longhands::background_attachment::computed_value::T;
|
||||
|
||||
self.gecko.mImage.mAttachmentCount = 1;
|
||||
self.gecko.mImage.mLayers.mFirstElement.mAttachment = match v {
|
||||
match servo {
|
||||
T::scroll => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL as u8,
|
||||
T::fixed => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED 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) {
|
||||
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.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 {
|
||||
use values::computed::position::Position;
|
||||
let position = &self.gecko.mImage.mLayers.mFirstElement.mPosition;
|
||||
Position {
|
||||
horizontal: position.mXPosition.into(),
|
||||
vertical: position.mYPosition.into(),
|
||||
}
|
||||
longhands::background_position::computed_value::T(
|
||||
self.gecko.mImage.mLayers.iter()
|
||||
.take(self.gecko.mImage.mPositionXCount as usize)
|
||||
.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) {
|
||||
let position = &mut self.gecko.mImage.mLayers.mFirstElement.mPosition;
|
||||
position.mXPosition = v.horizontal.into();
|
||||
position.mYPosition = v.vertical.into();
|
||||
self.gecko.mImage.mPositionXCount = 1;
|
||||
self.gecko.mImage.mPositionYCount = 1;
|
||||
unsafe {
|
||||
Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, v.0.len());
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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 style_struct_name="List" skip_longhands="list-style-type" skip_additionals="*">
|
||||
|
|
|
@ -69,10 +69,10 @@
|
|||
${caller.body()}
|
||||
}
|
||||
pub mod computed_value {
|
||||
use super::single_value;
|
||||
pub use super::single_value::computed_value as single_value;
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[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 {
|
||||
|
@ -285,8 +285,8 @@
|
|||
}
|
||||
</%def>
|
||||
|
||||
<%def name="single_keyword(name, values, **kwargs)">
|
||||
<%call expr="single_keyword_computed(name, values, **kwargs)">
|
||||
<%def name="single_keyword(name, values, vector=False, **kwargs)">
|
||||
<%call expr="single_keyword_computed(name, values, vector, **kwargs)">
|
||||
use values::computed::ComputedValueAsSpecified;
|
||||
use values::NoViewportPercentage;
|
||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
||||
|
@ -294,16 +294,16 @@
|
|||
</%call>
|
||||
</%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 [
|
||||
'gecko_constant_prefix', 'gecko_enum_prefix',
|
||||
'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;
|
||||
${caller.body()}
|
||||
pub mod computed_value {
|
||||
define_css_keyword_enum! { T:
|
||||
% 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])}
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
||||
get_initial_value()
|
||||
}
|
||||
#[inline]
|
||||
pub fn parse(_context: &ParserContext, input: &mut Parser)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
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 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,
|
||||
declarations: &mut Vec<PropertyDeclaration>)
|
||||
|
@ -526,8 +571,8 @@
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
super::serialize_four_sides(
|
||||
dest,
|
||||
self.${to_rust_ident(sub_property_pattern % 'top')},
|
||||
|
|
|
@ -155,6 +155,18 @@ pub trait Interpolate: Sized {
|
|||
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
|
||||
impl Interpolate for Au {
|
||||
#[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
|
||||
impl Interpolate for RGBA {
|
||||
#[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, ()> {
|
||||
use properties::longhands::background_size::computed_value::ExplicitSize;
|
||||
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(()),
|
||||
}
|
||||
Ok(BackgroundPosition(try!(self.0.interpolate(&other.0, time))))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
|||
"::cssparser::Color::RGBA(::cssparser::RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */",
|
||||
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 std::fmt;
|
||||
use values::specified::Image;
|
||||
|
@ -54,6 +54,10 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
|||
pub fn get_initial_value() -> computed_value::T {
|
||||
computed_value::T(None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
||||
SpecifiedValue(None)
|
||||
}
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||
Ok(SpecifiedValue(None))
|
||||
|
@ -75,7 +79,7 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
|||
}
|
||||
</%helpers:vector_longhand>
|
||||
|
||||
<%helpers:longhand name="background-position" animatable="True">
|
||||
<%helpers:vector_longhand name="background-position" animatable="True">
|
||||
use cssparser::ToCss;
|
||||
use std::fmt;
|
||||
use values::LocalToCss;
|
||||
|
@ -84,6 +88,7 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
|||
|
||||
pub mod computed_value {
|
||||
use values::computed::position::Position;
|
||||
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
|
||||
|
||||
pub type T = Position;
|
||||
}
|
||||
|
@ -98,30 +103,42 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
|||
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)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
Ok(try!(Position::parse(input)))
|
||||
}
|
||||
</%helpers:longhand>
|
||||
</%helpers:vector_longhand>
|
||||
|
||||
${helpers.single_keyword("background-repeat",
|
||||
"repeat repeat-x repeat-y no-repeat",
|
||||
vector=True,
|
||||
animatable=False)}
|
||||
|
||||
${helpers.single_keyword("background-attachment",
|
||||
"scroll fixed" + (" local" if product == "gecko" else ""),
|
||||
vector=True,
|
||||
animatable=False)}
|
||||
|
||||
${helpers.single_keyword("background-clip",
|
||||
"border-box padding-box content-box",
|
||||
vector=True,
|
||||
animatable=False)}
|
||||
|
||||
${helpers.single_keyword("background-origin",
|
||||
"padding-box border-box content-box",
|
||||
vector=True,
|
||||
animatable=False)}
|
||||
|
||||
<%helpers:longhand name="background-size" animatable="True">
|
||||
<%helpers:vector_longhand name="background-size" animatable="True">
|
||||
use cssparser::{ToCss, Token};
|
||||
use std::ascii::AsciiExt;
|
||||
use std::fmt;
|
||||
|
@ -129,6 +146,7 @@ ${helpers.single_keyword("background-origin",
|
|||
|
||||
pub mod computed_value {
|
||||
use values::computed::LengthOrPercentageOrAuto;
|
||||
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
|
@ -144,6 +162,23 @@ ${helpers.single_keyword("background-origin",
|
|||
Cover,
|
||||
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 {
|
||||
|
@ -237,6 +272,13 @@ ${helpers.single_keyword("background-origin",
|
|||
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,()> {
|
||||
let width;
|
||||
|
@ -274,4 +316,4 @@ ${helpers.single_keyword("background-origin",
|
|||
height: height,
|
||||
}))
|
||||
}
|
||||
</%helpers:longhand>
|
||||
</%helpers:vector_longhand>
|
||||
|
|
|
@ -2034,6 +2034,10 @@ pub fn cascade(viewport_size: Size2D<Au>,
|
|||
}
|
||||
% endfor
|
||||
|
||||
% if product == "gecko":
|
||||
style.mutate_background().fill_arrays();
|
||||
% endif
|
||||
|
||||
// The initial value of outline width may be changed at computed value time.
|
||||
if style.get_outline().clone_outline_style().none_or_hidden() &&
|
||||
style.get_outline().outline_has_nonzero_width() {
|
||||
|
|
|
@ -12,172 +12,204 @@
|
|||
use properties::longhands::{background_image, background_size, background_origin, background_clip};
|
||||
|
||||
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
||||
let mut 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;
|
||||
let mut background_color = None;
|
||||
|
||||
loop {
|
||||
if position.is_none() {
|
||||
if let Ok(value) = input.try(|input| background_position::parse(context, input)) {
|
||||
position = Some(value);
|
||||
any = true;
|
||||
|
||||
// Parse background size, if applicable.
|
||||
size = input.try(|input| {
|
||||
try!(input.expect_delim('/'));
|
||||
background_size::parse(context, input)
|
||||
}).ok();
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
if color.is_none() {
|
||||
% for name in "image position repeat size attachment origin clip".split():
|
||||
let mut background_${name} = background_${name}::SpecifiedValue(Vec::new());
|
||||
% endfor
|
||||
try!(input.parse_comma_separated(|input| {
|
||||
% for name in "image position repeat size attachment origin clip".split():
|
||||
let mut ${name} = None;
|
||||
% endfor
|
||||
loop {
|
||||
if let Ok(value) = input.try(|input| background_color::parse(context, input)) {
|
||||
color = Some(value);
|
||||
any = true;
|
||||
continue
|
||||
if background_color.is_none() {
|
||||
background_color = Some(value);
|
||||
continue
|
||||
} else {
|
||||
// color can only be the last element
|
||||
return Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
if image.is_none() {
|
||||
if let Ok(value) = input.try(|input| background_image::parse(context, input)) {
|
||||
image = Some(value);
|
||||
any = true;
|
||||
continue
|
||||
if position.is_none() {
|
||||
if let Ok(value) = input.try(|input| background_position::single_value
|
||||
::parse(context, input)) {
|
||||
position = Some(value);
|
||||
|
||||
// Parse background size, if applicable.
|
||||
size = input.try(|input| {
|
||||
try!(input.expect_delim('/'));
|
||||
background_size::single_value::parse(context, input)
|
||||
}).ok();
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
if repeat.is_none() {
|
||||
if let Ok(value) = input.try(|input| background_repeat::parse(context, input)) {
|
||||
repeat = Some(value);
|
||||
any = true;
|
||||
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));
|
||||
% for name in "image repeat attachment origin clip".split():
|
||||
if ${name}.is_none() {
|
||||
if let Ok(value) = input.try(|input| background_${name}::single_value
|
||||
::parse(context, input)) {
|
||||
${name} = Some(value);
|
||||
continue
|
||||
}
|
||||
}
|
||||
},
|
||||
(&DeclaredValue::Value(ref origin), _) => {
|
||||
try!(write!(dest, " "));
|
||||
try!(origin.to_css(dest));
|
||||
},
|
||||
(_, &DeclaredValue::Value(ref clip)) => {
|
||||
try!(write!(dest, " "));
|
||||
try!(clip.to_css(dest));
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
% endfor
|
||||
break
|
||||
}
|
||||
let mut any = false;
|
||||
% for name in "image position repeat size attachment origin clip".split():
|
||||
any = any || ${name}.is_some();
|
||||
% endfor
|
||||
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(())
|
||||
|
|
|
@ -25,8 +25,8 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style",
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
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
|
||||
// can be compared via partial eq
|
||||
% 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> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
super::serialize_directional_border(
|
||||
dest,
|
||||
self.border_${side}_width,
|
||||
|
@ -134,8 +134,8 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
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,
|
||||
// so we can just one set of color/style/width
|
||||
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 /,
|
||||
// so putting a default generic impl for now
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
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!(write!(dest, " "));
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
// 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".
|
||||
// Other shorthands do not include their name in the to_css method
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
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) {
|
||||
(&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => {
|
||||
*x_value == y_container.0
|
||||
|
@ -132,8 +132,8 @@ macro_rules! try_parse_one {
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
try!(self.transition_property.to_css(dest));
|
||||
try!(write!(dest, " "));
|
||||
|
||||
|
@ -268,8 +268,8 @@ macro_rules! try_parse_one {
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
try!(self.animation_duration.to_css(dest));
|
||||
try!(write!(dest, " "));
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
try!(self.column_width.to_css(dest));
|
||||
try!(write!(dest, " "));
|
||||
|
||||
|
|
|
@ -68,8 +68,8 @@
|
|||
}
|
||||
|
||||
// This may be a bit off, unsure, possibly needs changes
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
if let DeclaredValue::Value(ref style) = *self.font_style {
|
||||
try!(style.to_css(dest));
|
||||
try!(write!(dest, " "));
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
self.overflow_wrap.to_css(dest)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,8 +92,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match *self.list_style_position {
|
||||
DeclaredValue::Initial => try!(write!(dest, "outside")),
|
||||
_ => try!(self.list_style_position.to_css(dest))
|
||||
|
|
|
@ -49,8 +49,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
try!(self.outline_width.to_css(dest));
|
||||
try!(write!(dest, " "));
|
||||
|
||||
|
@ -89,8 +89,8 @@
|
|||
}
|
||||
|
||||
// TODO: Border radius for the radius shorthand is not implemented correctly yet
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
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!(write!(dest, " "));
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
}
|
||||
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match *self.flex_direction {
|
||||
DeclaredValue::Initial => try!(write!(dest, "row")),
|
||||
_ => try!(self.flex_direction.to_css(dest))
|
||||
|
@ -107,8 +107,8 @@
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
try!(self.flex_grow.to_css(dest));
|
||||
try!(write!(dest, " "));
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
impl<'a> LonghandsToSerialize<'a> {
|
||||
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match *self.text_decoration_line {
|
||||
DeclaredValue::Value(ref line) => {
|
||||
try!(line.to_css(dest));
|
||||
|
|
1
ports/cef/Cargo.lock
generated
1
ports/cef/Cargo.lock
generated
|
@ -2119,6 +2119,7 @@ dependencies = [
|
|||
"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)",
|
||||
"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)",
|
||||
"ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plugins 0.0.1",
|
||||
|
|
9
ports/geckolib/Cargo.lock
generated
9
ports/geckolib/Cargo.lock
generated
|
@ -234,6 +234,14 @@ dependencies = [
|
|||
"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]]
|
||||
name = "num-traits"
|
||||
version = "0.1.35"
|
||||
|
@ -363,6 +371,7 @@ dependencies = [
|
|||
"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)",
|
||||
"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)",
|
||||
"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)",
|
||||
|
|
|
@ -335,6 +335,8 @@ extern "C" {
|
|||
pub fn Gecko_DestroyClipPath(clip: *mut StyleClipPath);
|
||||
pub fn Gecko_NewBasicShape(type_: StyleBasicShapeType)
|
||||
-> *mut StyleBasicShape;
|
||||
pub fn Gecko_FillAllBackgroundLists(layers: *mut nsStyleImageLayers,
|
||||
maxLen: u32);
|
||||
pub fn Gecko_AddRefCalcArbitraryThread(aPtr: *mut Calc);
|
||||
pub fn Gecko_ReleaseCalcArbitraryThread(aPtr: *mut Calc);
|
||||
pub fn Gecko_Construct_nsStyleFont(ptr: *mut nsStyleFont);
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::iter::{once, Chain, Once, IntoIterator};
|
||||
use std::slice::IterMut;
|
||||
use std::slice::{Iter, IterMut};
|
||||
use structs::nsStyleAutoArray;
|
||||
|
||||
impl<T> nsStyleAutoArray<T> {
|
||||
pub fn iter_mut(&mut self) -> Chain<Once<&mut T>, IterMut<T>> {
|
||||
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
|
||||
// additional member fields that contain the length, which must be kept
|
||||
|
|
|
@ -679,18 +679,44 @@ mod shorthand_serialization {
|
|||
*/
|
||||
|
||||
mod background {
|
||||
use style::properties::longhands::background_attachment::computed_value::T as Attachment;
|
||||
use style::properties::longhands::background_clip::computed_value::T as Clip;
|
||||
use style::properties::longhands::background_image::SpecifiedValue as ImageContainer;
|
||||
use style::properties::longhands::background_origin::computed_value::T as Origin;
|
||||
use style::properties::longhands::background_position::SpecifiedValue as PositionContainer;
|
||||
use style::properties::longhands::background_repeat::computed_value::T as Repeat;
|
||||
use style::properties::longhands::background_size::SpecifiedExplicitSize;
|
||||
use style::properties::longhands::background_size::SpecifiedValue as Size;
|
||||
use style::properties::longhands::background_attachment as attachment;
|
||||
use style::properties::longhands::background_clip as clip;
|
||||
use style::properties::longhands::background_image as image;
|
||||
use style::properties::longhands::background_origin as origin;
|
||||
use style::properties::longhands::background_position as position;
|
||||
use style::properties::longhands::background_repeat as repeat;
|
||||
use style::properties::longhands::background_size as size;
|
||||
use style::values::specified::Image;
|
||||
use style::values::specified::position::Position;
|
||||
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]
|
||||
fn background_should_serialize_all_available_properties_when_specified() {
|
||||
let mut properties = Vec::new();
|
||||
|
@ -700,29 +726,31 @@ mod shorthand_serialization {
|
|||
authored: None
|
||||
});
|
||||
|
||||
let position = DeclaredValue::Value(
|
||||
let position = single_vec_value_typedef!(position,
|
||||
Position {
|
||||
horizontal: LengthOrPercentage::Length(Length::from_px(7f32)),
|
||||
vertical: LengthOrPercentage::Length(Length::from_px(4f32))
|
||||
}
|
||||
);
|
||||
|
||||
let repeat = DeclaredValue::Value(Repeat::repeat_x);
|
||||
let attachment = DeclaredValue::Value(Attachment::scroll);
|
||||
let repeat = single_vec_keyword_value!(repeat, repeat_x);
|
||||
let attachment = single_vec_keyword_value!(attachment, scroll);
|
||||
|
||||
let image = DeclaredValue::Value(ImageContainer(
|
||||
Some(Image::Url(Url::parse("http://servo/test.png").unwrap(), UrlExtraData {}))
|
||||
));
|
||||
let image = single_vec_value!(image,
|
||||
Some(Image::Url(Url::parse("http://servo/test.png").unwrap(),
|
||||
UrlExtraData {})));
|
||||
|
||||
let size = DeclaredValue::Value(
|
||||
Size::Explicit(SpecifiedExplicitSize {
|
||||
width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)),
|
||||
height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32))
|
||||
}
|
||||
));
|
||||
let size = single_vec_variant_value!(size,
|
||||
size::single_value::SpecifiedValue::Explicit(
|
||||
size::single_value::SpecifiedExplicitSize {
|
||||
width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)),
|
||||
height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32))
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
let origin = DeclaredValue::Value(Origin::border_box);
|
||||
let clip = DeclaredValue::Value(Clip::padding_box);
|
||||
let origin = single_vec_keyword_value!(origin, border_box);
|
||||
let clip = single_vec_keyword_value!(clip, padding_box);
|
||||
|
||||
properties.push(PropertyDeclaration::BackgroundColor(color));
|
||||
properties.push(PropertyDeclaration::BackgroundPosition(position));
|
||||
|
@ -751,29 +779,31 @@ mod shorthand_serialization {
|
|||
authored: None
|
||||
});
|
||||
|
||||
let position = DeclaredValue::Value(
|
||||
let position = single_vec_value_typedef!(position,
|
||||
Position {
|
||||
horizontal: LengthOrPercentage::Length(Length::from_px(7f32)),
|
||||
vertical: LengthOrPercentage::Length(Length::from_px(4f32))
|
||||
}
|
||||
);
|
||||
|
||||
let repeat = DeclaredValue::Value(Repeat::repeat_x);
|
||||
let attachment = DeclaredValue::Value(Attachment::scroll);
|
||||
let repeat = single_vec_keyword_value!(repeat, repeat_x);
|
||||
let attachment = single_vec_keyword_value!(attachment, scroll);
|
||||
|
||||
let image = DeclaredValue::Value(ImageContainer(
|
||||
Some(Image::Url(Url::parse("http://servo/test.png").unwrap(), UrlExtraData {}))
|
||||
));
|
||||
let image = single_vec_value!(image,
|
||||
Some(Image::Url(Url::parse("http://servo/test.png").unwrap(),
|
||||
UrlExtraData {})));
|
||||
|
||||
let size = DeclaredValue::Value(
|
||||
Size::Explicit(SpecifiedExplicitSize {
|
||||
width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)),
|
||||
height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32))
|
||||
})
|
||||
let size = single_vec_variant_value!(size,
|
||||
size::single_value::SpecifiedValue::Explicit(
|
||||
size::single_value::SpecifiedExplicitSize {
|
||||
width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)),
|
||||
height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32))
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
let origin = DeclaredValue::Value(Origin::padding_box);
|
||||
let clip = DeclaredValue::Value(Clip::padding_box);
|
||||
let origin = single_vec_keyword_value!(origin, padding_box);
|
||||
let clip = single_vec_keyword_value!(clip, padding_box);
|
||||
|
||||
properties.push(PropertyDeclaration::BackgroundColor(color));
|
||||
properties.push(PropertyDeclaration::BackgroundPosition(position));
|
||||
|
@ -801,17 +831,17 @@ mod shorthand_serialization {
|
|||
authored: None
|
||||
});
|
||||
|
||||
let position = DeclaredValue::Value(
|
||||
let position = single_vec_value_typedef!(position,
|
||||
Position {
|
||||
horizontal: LengthOrPercentage::Length(Length::from_px(0f32)),
|
||||
vertical: LengthOrPercentage::Length(Length::from_px(0f32))
|
||||
}
|
||||
);
|
||||
|
||||
let repeat = DeclaredValue::Value(Repeat::repeat_x);
|
||||
let attachment = DeclaredValue::Value(Attachment::scroll);
|
||||
let repeat = single_vec_keyword_value!(repeat, repeat_x);
|
||||
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;
|
||||
|
||||
|
|
|
@ -191,19 +191,40 @@ fn test_parse_stylesheet() {
|
|||
}
|
||||
)),
|
||||
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),
|
||||
(PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
|
||||
(PropertyDeclaration::BackgroundRepeat(DeclaredValue::Value(
|
||||
longhands::background_repeat::SpecifiedValue(
|
||||
vec![longhands::background_repeat::single_value
|
||||
::get_initial_specified_value()]))),
|
||||
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),
|
||||
(PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
|
||||
(PropertyDeclaration::BackgroundImage(DeclaredValue::Value(
|
||||
longhands::background_image::SpecifiedValue(
|
||||
vec![longhands::background_image::single_value
|
||||
::get_initial_specified_value()]))),
|
||||
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),
|
||||
(PropertyDeclaration::BackgroundOrigin(DeclaredValue::Initial),
|
||||
(PropertyDeclaration::BackgroundOrigin(DeclaredValue::Value(
|
||||
longhands::background_origin::SpecifiedValue(
|
||||
vec![longhands::background_origin::single_value
|
||||
::get_initial_specified_value()]))),
|
||||
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),
|
||||
]),
|
||||
important_count: 0,
|
||||
|
|
|
@ -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
|
||||
|
|
@ -3564,6 +3564,30 @@
|
|||
"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": [
|
||||
{
|
||||
"path": "css/multiple_css_class_a.html",
|
||||
|
@ -12832,6 +12856,30 @@
|
|||
"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": [
|
||||
{
|
||||
"path": "css/multiple_css_class_a.html",
|
||||
|
|
BIN
tests/wpt/mozilla/tests/css/bubbles.png
Normal file
BIN
tests/wpt/mozilla/tests/css/bubbles.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
31
tests/wpt/mozilla/tests/css/multiple_backgrounds.html
Normal file
31
tests/wpt/mozilla/tests/css/multiple_backgrounds.html
Normal 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>
|
47
tests/wpt/mozilla/tests/css/multiple_backgrounds_ref.html
Normal file
47
tests/wpt/mozilla/tests/css/multiple_backgrounds_ref.html
Normal 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>
|
BIN
tests/wpt/mozilla/tests/css/rust-logo-256x256.png
Normal file
BIN
tests/wpt/mozilla/tests/css/rust-logo-256x256.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
Loading…
Add table
Add a link
Reference in a new issue