зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #5133 - layout: Implement `image-rendering` per CSS-IMAGES-3 § 5.3 and (from servo:background-size); r=SimonSapin
`background-size` per CSS-BACKGROUNDS § 3.9. Nearest neighbor interpolation is used for `crisp-edges`, like Firefox. A note has been added that we could do better if we wanted to. Multiple backgrounds are not yet supported. Rebase of #4368. Fixes #4368. Source-Repo: https://github.com/servo/servo Source-Revision: e1a50c771973fe3223cf98feea5d570375d68fa9
This commit is contained in:
Родитель
73082d1626
Коммит
4578a773a4
|
@ -42,8 +42,9 @@ use util::smallvec::{SmallVec, SmallVec8};
|
|||
use std::fmt;
|
||||
use std::slice::Iter;
|
||||
use std::sync::Arc;
|
||||
use style::computed_values::{border_style, cursor, filter, image_rendering, mix_blend_mode};
|
||||
use style::computed_values::{pointer_events};
|
||||
use style::properties::ComputedValues;
|
||||
use style::computed_values::{border_style, cursor, filter, mix_blend_mode, pointer_events};
|
||||
|
||||
// It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for
|
||||
// layout to use.
|
||||
|
@ -763,6 +764,10 @@ pub struct ImageDisplayItem {
|
|||
/// the bounds of this display item, then the image will be repeated in the appropriate
|
||||
/// direction to tile the entire bounds.
|
||||
pub stretch_size: Size2D<Au>,
|
||||
|
||||
/// The algorithm we should use to stretch the image. See `image_rendering` in CSS-IMAGES-3 §
|
||||
/// 5.3.
|
||||
pub image_rendering: image_rendering::T,
|
||||
}
|
||||
|
||||
/// Paints a gradient.
|
||||
|
@ -937,7 +942,9 @@ impl DisplayItem {
|
|||
bounds.origin.y = bounds.origin.y + y_offset;
|
||||
bounds.size = image_item.stretch_size;
|
||||
|
||||
paint_context.draw_image(&bounds, image_item.image.clone());
|
||||
paint_context.draw_image(&bounds,
|
||||
image_item.image.clone(),
|
||||
image_item.image_rendering.clone());
|
||||
|
||||
x_offset = x_offset + image_item.stretch_size.width;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ use std::mem;
|
|||
use std::num::Float;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use style::computed_values::{border_style, filter, mix_blend_mode};
|
||||
use style::computed_values::{border_style, filter, image_rendering, mix_blend_mode};
|
||||
use util::geometry::{self, Au, MAX_RECT, ZERO_RECT};
|
||||
use util::opts;
|
||||
use util::range::Range;
|
||||
|
@ -127,7 +127,10 @@ impl<'a> PaintContext<'a> {
|
|||
self.draw_target.pop_clip();
|
||||
}
|
||||
|
||||
pub fn draw_image(&self, bounds: &Rect<Au>, image: Arc<Box<Image>>) {
|
||||
pub fn draw_image(&self,
|
||||
bounds: &Rect<Au>,
|
||||
image: Arc<Box<Image>>,
|
||||
image_rendering: image_rendering::T) {
|
||||
let size = Size2D(image.width as i32, image.height as i32);
|
||||
let (pixel_width, pixels, source_format) = match image.pixels {
|
||||
PixelsByColorType::RGBA8(ref pixels) => (4, pixels.as_slice(), SurfaceFormat::B8G8R8A8),
|
||||
|
@ -146,7 +149,17 @@ impl<'a> PaintContext<'a> {
|
|||
let source_rect = Rect(Point2D(0.0, 0.0),
|
||||
Size2D(image.width as AzFloat, image.height as AzFloat));
|
||||
let dest_rect = bounds.to_azure_rect();
|
||||
let draw_surface_options = DrawSurfaceOptions::new(Filter::Linear, true);
|
||||
|
||||
// TODO(pcwalton): According to CSS-IMAGES-3 § 5.3, nearest-neighbor interpolation is a
|
||||
// conforming implementation of `crisp-edges`, but it is not the best we could do.
|
||||
// Something like Scale2x would be ideal.
|
||||
let draw_surface_options = match image_rendering {
|
||||
image_rendering::T::Auto => DrawSurfaceOptions::new(Filter::Linear, true),
|
||||
image_rendering::T::CrispEdges | image_rendering::T::Pixelated => {
|
||||
DrawSurfaceOptions::new(Filter::Point, true)
|
||||
}
|
||||
};
|
||||
|
||||
let draw_options = DrawOptions::new(1.0, 0);
|
||||
draw_target_ref.draw_surface(azure_surface,
|
||||
dest_rect,
|
||||
|
|
|
@ -18,7 +18,7 @@ use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo
|
|||
use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo};
|
||||
use inline::InlineFlow;
|
||||
use list_item::ListItemFlow;
|
||||
use model;
|
||||
use model::{self, MaybeAuto};
|
||||
use util::{OpaqueNodeMethods, ToGfxColor};
|
||||
|
||||
use geom::{Point2D, Rect, Size2D, SideOffsets2D};
|
||||
|
@ -31,8 +31,7 @@ use gfx::display_list::{GradientStop, ImageDisplayItem, LineDisplayItem};
|
|||
use gfx::display_list::{OpaqueNode, SolidColorDisplayItem};
|
||||
use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation};
|
||||
use gfx::paint_task::{PaintLayer, THREAD_TINT_COLORS};
|
||||
use png;
|
||||
use png::PixelsByColorType;
|
||||
use png::{self, PixelsByColorType};
|
||||
use msg::compositor_msg::ScrollPolicy;
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
|
@ -46,11 +45,11 @@ use std::default::Default;
|
|||
use std::iter::repeat;
|
||||
use std::num::Float;
|
||||
use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
|
||||
use style::values::computed::{Image, LinearGradient, LengthOrPercentage};
|
||||
use style::values::computed::{Image, LinearGradient, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
use style::values::RGBA;
|
||||
use style::computed_values::filter::Filter;
|
||||
use style::computed_values::{background_attachment, background_repeat, border_style, overflow_x};
|
||||
use style::computed_values::{position, visibility};
|
||||
use style::computed_values::{background_attachment, background_repeat, background_size};
|
||||
use style::computed_values::{border_style, image_rendering, overflow_x, position, visibility};
|
||||
use style::properties::style_structs::Border;
|
||||
use style::properties::ComputedValues;
|
||||
use std::num::ToPrimitive;
|
||||
|
@ -93,6 +92,14 @@ pub trait FragmentDisplayListBuilding {
|
|||
absolute_bounds: &Rect<Au>,
|
||||
clip: &ClippingRegion);
|
||||
|
||||
/// Computes the background size for an image with the given background area according to the
|
||||
/// rules in CSS-BACKGROUNDS § 3.9.
|
||||
fn compute_background_image_size(&self,
|
||||
style: &ComputedValues,
|
||||
bounds: &Rect<Au>,
|
||||
image: &png::Image)
|
||||
-> Size2D<Au>;
|
||||
|
||||
/// Adds the display items necessary to paint the background image of this fragment to the
|
||||
/// display list at the appropriate stacking level.
|
||||
fn build_display_list_for_background_image(&self,
|
||||
|
@ -326,6 +333,59 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_background_image_size(&self,
|
||||
style: &ComputedValues,
|
||||
bounds: &Rect<Au>,
|
||||
image: &png::Image)
|
||||
-> Size2D<Au> {
|
||||
// If `image_aspect_ratio` < `bounds_aspect_ratio`, the image is tall; otherwise, it is
|
||||
// wide.
|
||||
let image_aspect_ratio = (image.width as f64) / (image.height as f64);
|
||||
let bounds_aspect_ratio = bounds.size.width.to_subpx() / bounds.size.height.to_subpx();
|
||||
let intrinsic_size = Size2D(Au::from_px(image.width as int),
|
||||
Au::from_px(image.height as int));
|
||||
match (style.get_background().background_size.clone(),
|
||||
image_aspect_ratio < bounds_aspect_ratio) {
|
||||
(background_size::T::Contain, false) | (background_size::T::Cover, true) => {
|
||||
Size2D(bounds.size.width,
|
||||
Au::from_frac_px(bounds.size.width.to_subpx() / image_aspect_ratio))
|
||||
}
|
||||
|
||||
(background_size::T::Contain, true) | (background_size::T::Cover, false) => {
|
||||
Size2D(Au::from_frac_px(bounds.size.height.to_subpx() * image_aspect_ratio),
|
||||
bounds.size.height)
|
||||
}
|
||||
|
||||
(background_size::T::Explicit(background_size::ExplicitSize {
|
||||
width,
|
||||
height: LengthOrPercentageOrAuto::Auto,
|
||||
}), _) => {
|
||||
let width = MaybeAuto::from_style(width, bounds.size.width)
|
||||
.specified_or_default(intrinsic_size.width);
|
||||
Size2D(width, Au::from_frac_px(width.to_subpx() / image_aspect_ratio))
|
||||
}
|
||||
|
||||
(background_size::T::Explicit(background_size::ExplicitSize {
|
||||
width: LengthOrPercentageOrAuto::Auto,
|
||||
height
|
||||
}), _) => {
|
||||
let height = MaybeAuto::from_style(height, bounds.size.height)
|
||||
.specified_or_default(intrinsic_size.height);
|
||||
Size2D(Au::from_frac_px(height.to_subpx() * image_aspect_ratio), height)
|
||||
}
|
||||
|
||||
(background_size::T::Explicit(background_size::ExplicitSize {
|
||||
width,
|
||||
height
|
||||
}), _) => {
|
||||
Size2D(MaybeAuto::from_style(width, bounds.size.width)
|
||||
.specified_or_default(intrinsic_size.width),
|
||||
MaybeAuto::from_style(height, bounds.size.height)
|
||||
.specified_or_default(intrinsic_size.height))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_display_list_for_background_image(&self,
|
||||
style: &ComputedValues,
|
||||
display_list: &mut DisplayList,
|
||||
|
@ -349,16 +409,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
};
|
||||
debug!("(building display list) building background image");
|
||||
|
||||
let image_width = Au::from_px(image.width as int);
|
||||
let image_height = Au::from_px(image.height as int);
|
||||
// Use `background-size` to get the size.
|
||||
let mut bounds = *absolute_bounds;
|
||||
let image_size = self.compute_background_image_size(style, &bounds, &**image);
|
||||
|
||||
// Clip.
|
||||
//
|
||||
// TODO: Check the bounds to see if a clip item is actually required.
|
||||
let clip = clip.clone().intersect_rect(&bounds);
|
||||
|
||||
// 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 {
|
||||
background_attachment::T::scroll => {
|
||||
(absolute_bounds.origin.x, absolute_bounds.origin.y)
|
||||
|
@ -368,11 +428,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
};
|
||||
|
||||
// Use background-position to get the offset
|
||||
// Use `background-position` to get the offset.
|
||||
let horizontal_position = model::specified(background.background_position.horizontal,
|
||||
bounds.size.width - image_width);
|
||||
bounds.size.width - image_size.width);
|
||||
let vertical_position = model::specified(background.background_position.vertical,
|
||||
bounds.size.height - image_height);
|
||||
bounds.size.height - image_size.height);
|
||||
|
||||
let abs_x = virtual_origin_x + horizontal_position;
|
||||
let abs_y = virtual_origin_y + vertical_position;
|
||||
|
@ -382,26 +442,34 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
background_repeat::T::no_repeat => {
|
||||
bounds.origin.x = abs_x;
|
||||
bounds.origin.y = abs_y;
|
||||
bounds.size.width = image_width;
|
||||
bounds.size.height = image_height;
|
||||
bounds.size.width = image_size.width;
|
||||
bounds.size.height = image_size.height;
|
||||
}
|
||||
background_repeat::T::repeat_x => {
|
||||
bounds.origin.y = abs_y;
|
||||
bounds.size.height = image_height;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x, &mut bounds.size.width,
|
||||
abs_x, image.width);
|
||||
bounds.size.height = image_size.height;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
|
||||
&mut bounds.size.width,
|
||||
abs_x,
|
||||
image_size.width.to_nearest_px() as u32);
|
||||
}
|
||||
background_repeat::T::repeat_y => {
|
||||
bounds.origin.x = abs_x;
|
||||
bounds.size.width = image_width;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y, &mut bounds.size.height,
|
||||
abs_y, image.height);
|
||||
bounds.size.width = image_size.width;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
|
||||
&mut bounds.size.height,
|
||||
abs_y,
|
||||
image_size.height.to_nearest_px() as u32);
|
||||
}
|
||||
background_repeat::T::repeat => {
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x, &mut bounds.size.width,
|
||||
abs_x, image.width);
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y, &mut bounds.size.height,
|
||||
abs_y, image.height);
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
|
||||
&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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -413,8 +481,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
Cursor::DefaultCursor),
|
||||
clip),
|
||||
image: image.clone(),
|
||||
stretch_size: Size2D(Au::from_px(image.width as int),
|
||||
Au::from_px(image.height as int)),
|
||||
stretch_size: Size2D(image_size.width, image_size.height),
|
||||
image_rendering: style.get_effects().image_rendering.clone(),
|
||||
}), level);
|
||||
}
|
||||
|
||||
|
@ -913,6 +981,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
(*clip).clone()),
|
||||
image: image.clone(),
|
||||
stretch_size: stacking_relative_content_box.size,
|
||||
image_rendering: self.style.get_effects().image_rendering.clone(),
|
||||
}));
|
||||
} else {
|
||||
// No image data at all? Do nothing.
|
||||
|
@ -948,6 +1017,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
pixels: PixelsByColorType::RGBA8(canvas_data),
|
||||
}),
|
||||
stretch_size: stacking_relative_content_box.size,
|
||||
image_rendering: image_rendering::T::Auto,
|
||||
};
|
||||
|
||||
display_list.content.push_back(DisplayItem::ImageClass(canvas_display_item));
|
||||
|
|
|
@ -38,6 +38,7 @@ partial interface CSSStyleDeclaration {
|
|||
[TreatNullAs=EmptyString] attribute DOMString backgroundRepeat;
|
||||
[TreatNullAs=EmptyString] attribute DOMString backgroundImage;
|
||||
[TreatNullAs=EmptyString] attribute DOMString backgroundAttachment;
|
||||
[TreatNullAs=EmptyString] attribute DOMString backgroundSize;
|
||||
|
||||
[TreatNullAs=EmptyString] attribute DOMString border;
|
||||
[TreatNullAs=EmptyString] attribute DOMString borderColor;
|
||||
|
@ -178,4 +179,6 @@ partial interface CSSStyleDeclaration {
|
|||
[TreatNullAs=EmptyString] attribute DOMString maxWidth;
|
||||
|
||||
[TreatNullAs=EmptyString] attribute DOMString zIndex;
|
||||
|
||||
[TreatNullAs=EmptyString] attribute DOMString imageRendering;
|
||||
};
|
||||
|
|
|
@ -1286,6 +1286,126 @@ pub mod longhands {
|
|||
|
||||
${single_keyword("background-attachment", "scroll fixed")}
|
||||
|
||||
<%self:longhand name="background-size">
|
||||
use cssparser::{ToCss, Token};
|
||||
use std::ascii::AsciiExt;
|
||||
use text_writer::{self, TextWriter};
|
||||
use values::computed::{Context, ToComputedValue};
|
||||
|
||||
pub mod computed_value {
|
||||
use values::computed::LengthOrPercentageOrAuto;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub struct ExplicitSize {
|
||||
pub width: LengthOrPercentageOrAuto,
|
||||
pub height: LengthOrPercentageOrAuto,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum T {
|
||||
Explicit(ExplicitSize),
|
||||
Cover,
|
||||
Contain,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct SpecifiedExplicitSize {
|
||||
pub width: specified::LengthOrPercentageOrAuto,
|
||||
pub height: specified::LengthOrPercentageOrAuto,
|
||||
}
|
||||
|
||||
impl ToCss for SpecifiedExplicitSize {
|
||||
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||
try!(self.width.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
self.height.to_css(dest)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum SpecifiedValue {
|
||||
Explicit(SpecifiedExplicitSize),
|
||||
Cover,
|
||||
Contain,
|
||||
}
|
||||
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||
match *self {
|
||||
SpecifiedValue::Explicit(ref size) => size.to_css(dest),
|
||||
SpecifiedValue::Cover => dest.write_str("cover"),
|
||||
SpecifiedValue::Contain => dest.write_str("contain"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
type ComputedValue = computed_value::T;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &computed::Context) -> computed_value::T {
|
||||
match *self {
|
||||
SpecifiedValue::Explicit(ref size) => {
|
||||
computed_value::T::Explicit(computed_value::ExplicitSize {
|
||||
width: size.width.to_computed_value(context),
|
||||
height: size.height.to_computed_value(context),
|
||||
})
|
||||
}
|
||||
SpecifiedValue::Cover => computed_value::T::Cover,
|
||||
SpecifiedValue::Contain => computed_value::T::Contain,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
computed_value::T::Explicit(computed_value::ExplicitSize {
|
||||
width: computed::LengthOrPercentageOrAuto::Auto,
|
||||
height: computed::LengthOrPercentageOrAuto::Auto,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||
let width;
|
||||
if let Ok(value) = input.try(|input| {
|
||||
match input.next() {
|
||||
Err(_) => Err(()),
|
||||
Ok(Token::Ident(ref ident)) if ident.as_slice()
|
||||
.eq_ignore_ascii_case("cover") => {
|
||||
Ok(SpecifiedValue::Cover)
|
||||
}
|
||||
Ok(Token::Ident(ref ident)) if ident.as_slice()
|
||||
.eq_ignore_ascii_case("contain") => {
|
||||
Ok(SpecifiedValue::Contain)
|
||||
}
|
||||
Ok(_) => Err(()),
|
||||
}
|
||||
}) {
|
||||
return Ok(value)
|
||||
} else {
|
||||
width = try!(specified::LengthOrPercentageOrAuto::parse(input))
|
||||
}
|
||||
|
||||
let height;
|
||||
if let Ok(value) = input.try(|input| {
|
||||
match input.next() {
|
||||
Err(_) => Ok(specified::LengthOrPercentageOrAuto::Auto),
|
||||
Ok(_) => Err(()),
|
||||
}
|
||||
}) {
|
||||
height = value
|
||||
} else {
|
||||
height = try!(specified::LengthOrPercentageOrAuto::parse(input));
|
||||
}
|
||||
|
||||
Ok(SpecifiedValue::Explicit(SpecifiedExplicitSize {
|
||||
width: width,
|
||||
height: height,
|
||||
}))
|
||||
}
|
||||
</%self:longhand>
|
||||
|
||||
${new_style_struct("Color", is_inherited=True)}
|
||||
|
||||
<%self:raw_longhand name="color">
|
||||
|
@ -2628,6 +2748,62 @@ pub mod longhands {
|
|||
"""normal multiply screen overlay darken lighten color-dodge
|
||||
color-burn hard-light soft-light difference exclusion hue
|
||||
saturation color luminosity""")}
|
||||
|
||||
<%self:longhand name="image-rendering">
|
||||
use values::computed::{Context, ToComputedValue};
|
||||
|
||||
pub mod computed_value {
|
||||
use cssparser::ToCss;
|
||||
use text_writer::{self, TextWriter};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum T {
|
||||
Auto,
|
||||
CrispEdges,
|
||||
Pixelated,
|
||||
}
|
||||
|
||||
impl ToCss for T {
|
||||
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||
match *self {
|
||||
T::Auto => dest.write_str("auto"),
|
||||
T::CrispEdges => dest.write_str("crisp-edges"),
|
||||
T::Pixelated => dest.write_str("pixelated"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type SpecifiedValue = computed_value::T;
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
computed_value::T::Auto
|
||||
}
|
||||
|
||||
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||
// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for
|
||||
// `auto`.
|
||||
match_ignore_ascii_case! {
|
||||
try!(input.expect_ident()),
|
||||
"auto" => Ok(computed_value::T::Auto),
|
||||
"optimizespeed" => Ok(computed_value::T::Auto),
|
||||
"optimizequality" => Ok(computed_value::T::Auto),
|
||||
"crisp-edges" => Ok(computed_value::T::CrispEdges),
|
||||
"pixelated" => Ok(computed_value::T::Pixelated)
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
type ComputedValue = computed_value::T;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, _: &Context) -> computed_value::T {
|
||||
*self
|
||||
}
|
||||
}
|
||||
</%self:longhand>
|
||||
}
|
||||
|
||||
|
||||
|
@ -2720,14 +2896,17 @@ pub mod shorthands {
|
|||
|
||||
// TODO: other background-* properties
|
||||
<%self:shorthand name="background"
|
||||
sub_properties="background-color background-position background-repeat background-attachment background-image">
|
||||
use properties::longhands::{background_color, background_position, background_repeat,
|
||||
background_attachment, background_image};
|
||||
sub_properties="background-color background-position background-repeat background-attachment background-image background-size">
|
||||
use properties::longhands::{background_color, background_position, background_repeat};
|
||||
use properties::longhands::{background_attachment, background_image, background_size};
|
||||
|
||||
use cssparser::Token;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -2736,6 +2915,13 @@ pub mod shorthands {
|
|||
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
|
||||
}
|
||||
}
|
||||
|
@ -2777,6 +2963,7 @@ pub mod shorthands {
|
|||
background_position: position,
|
||||
background_repeat: repeat,
|
||||
background_attachment: attachment,
|
||||
background_size: size,
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
|
|
|
@ -435,6 +435,7 @@ fn test_parse_stylesheet() {
|
|||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![
|
||||
PropertyDeclaration::BackgroundSize(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
|
||||
|
|
Загрузка…
Ссылка в новой задаче