Skip to content

Commit

Permalink
Implement 'background-origin' property in CSS3 Background
Browse files Browse the repository at this point in the history
This property determines the background positioning area, that is the position of
the origin of an image specified using the 'background-image' CSS property.

'background-origin' is ignored when background-attachment is fixed.

Spec: http://dev.w3.org/csswg/css-backgrounds-3/#background-origin

Fixes #6045.
  • Loading branch information
Jinwoo-Song committed May 15, 2015
1 parent b05c3fc commit b1b22c0
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 8 deletions.
29 changes: 23 additions & 6 deletions components/layout/display_list_builder.rs
Expand Up @@ -43,7 +43,7 @@ use std::sync::Arc;
use std::sync::mpsc::channel;
use style::computed_values::filter::Filter;
use style::computed_values::transform::ComputedMatrix;
use style::computed_values::{background_attachment, background_repeat, background_size};
use style::computed_values::{background_attachment, background_origin, background_repeat, background_size};
use style::computed_values::{border_style, image_rendering, overflow_x, position, visibility};
use style::properties::ComputedValues;
use style::properties::style_structs::Border;
Expand Down Expand Up @@ -419,12 +419,32 @@ impl FragmentDisplayListBuilding for Fragment {
// TODO: Check the bounds to see if a clip item is actually required.
let clip = clip.clone().intersect_rect(&bounds);

// Background image should be positioned on the padding box basis.
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 => {
(Au(0), Au(0))
}
background_origin::T::border_box => {
(-border.left, -border.top)
}
background_origin::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 => {
(absolute_bounds.origin.x, absolute_bounds.origin.y)
}
background_attachment::T::fixed => {
// If the ‘background-attachment’ value for this image is ‘fixed’, then 'background-origin' has no effect.
origin_x = Au(0);
origin_y = Au(0);
(Au(0), Au(0))
}
};
Expand All @@ -435,11 +455,8 @@ impl FragmentDisplayListBuilding for Fragment {
let vertical_position = model::specified(background.background_position.vertical,
bounds.size.height - image_size.height);

// Background image should be positioned on the padding box basis.
let border = style.logical_border_width().to_physical(style.writing_mode);

let abs_x = border.left + virtual_origin_x + horizontal_position;
let abs_y = border.top + virtual_origin_y + vertical_position;
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 {
Expand Down
1 change: 1 addition & 0 deletions components/script/dom/webidls/CSSStyleDeclaration.webidl
Expand Up @@ -39,6 +39,7 @@ partial interface CSSStyleDeclaration {
[TreatNullAs=EmptyString] attribute DOMString backgroundImage;
[TreatNullAs=EmptyString] attribute DOMString backgroundAttachment;
[TreatNullAs=EmptyString] attribute DOMString backgroundSize;
[TreatNullAs=EmptyString] attribute DOMString backgroundOrigin;

[TreatNullAs=EmptyString] attribute DOMString border;
[TreatNullAs=EmptyString] attribute DOMString borderColor;
Expand Down
16 changes: 14 additions & 2 deletions components/style/properties.mako.rs
Expand Up @@ -1295,6 +1295,8 @@ pub mod longhands {

${single_keyword("background-attachment", "scroll fixed")}

${single_keyword("background-origin", "padding-box border-box content-box")}

<%self:longhand name="background-size">
use cssparser::{ToCss, Token};
use std::ascii::AsciiExt;
Expand Down Expand Up @@ -4244,9 +4246,10 @@ pub mod shorthands {

// TODO: other background-* properties
<%self:shorthand name="background"
sub_properties="background-color background-position background-repeat background-attachment background-image background-size">
sub_properties="background-color background-position background-repeat background-attachment
background-image background-size background-origin">
use properties::longhands::{background_color, background_position, background_repeat};
use properties::longhands::{background_attachment, background_image, background_size};
use properties::longhands::{background_attachment, background_image, background_size, background_origin};

let mut color = None;
let mut image = None;
Expand All @@ -4255,6 +4258,7 @@ pub mod shorthands {
let mut size = None;
let mut attachment = None;
let mut any = false;
let mut origin = None;

loop {
if position.is_none() {
Expand Down Expand Up @@ -4299,6 +4303,13 @@ pub mod shorthands {
continue
}
}
if origin.is_none() {
if let Ok(value) = input.try(|input| background_origin::parse(context, input)) {
origin = Some(value);
any = true;
continue
}
}
break
}

Expand All @@ -4310,6 +4321,7 @@ pub mod shorthands {
background_repeat: repeat,
background_attachment: attachment,
background_size: size,
background_origin: origin,
})
} else {
Err(())
Expand Down
40 changes: 40 additions & 0 deletions tests/ref/background_origin_a.html
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<style>
#foo1 {
background: url(400x400_green.png);
background-origin: padding-box;
background-repeat: no-repeat;
width: 400px;
height: 400px;
padding: 20px;
border: 20px dotted red;
}
#foo2 {
background: url(400x400_green.png);
background-origin: border-box;
background-repeat: no-repeat;
width: 400px;
height: 400px;
padding: 20px;
border: 20px dotted red;
}
#foo3 {
background: url(400x400_green.png);
background-origin: content-box;
background-repeat: no-repeat;
width: 400px;
height: 400px;
padding: 20px;
border: 20px dotted red;
}
</style>
</head>
<body>
<div id=foo1></div>
<div id=foo2></div>
<div id=foo3></div>
</body>
</html>

39 changes: 39 additions & 0 deletions tests/ref/background_origin_ref.html
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<style>
#foo1 {
background: url(400x400_green.png);
background-repeat: no-repeat;
width: 400px;
height: 400px;
padding: 20px;
border: 20px dotted red;
}
#foo2 {
background: url(400x400_green.png);
background-position: -20px -20px;
background-repeat: no-repeat;
width: 400px;
height: 400px;
padding: 20px;
border: 20px dotted red;
}
#foo3 {
background: url(400x400_green.png);
background-position: 20px 20px;
background-repeat: no-repeat;
width: 400px;
height: 400px;
padding: 20px;
border: 20px dotted red;
}
</style>
</head>
<body>
<div id=foo1></div>
<div id=foo2></div>
<div id=foo3></div>
</body>
</html>

1 change: 1 addition & 0 deletions tests/ref/basic.list
Expand Up @@ -25,6 +25,7 @@ flaky_cpu == append_style_a.html append_style_b.html
== background_external_stylesheet.html background_ref.html
== background_image_position_a.html background_image_position_ref.html
== background_none_a.html background_none_b.html
== background_origin_a.html background_origin_ref.html
== background_position_a.html background_position_b.html
== background_position_keyword.html background_position_b.html
== background_position_percent.html background_position_b.html
Expand Down
1 change: 1 addition & 0 deletions tests/unit/style/stylesheets.rs
Expand Up @@ -116,6 +116,7 @@ fn test_parse_stylesheet() {
],
declarations: PropertyDeclarationBlock {
normal: Arc::new(vec![
PropertyDeclaration::BackgroundOrigin(DeclaredValue::Initial),
PropertyDeclaration::BackgroundSize(DeclaredValue::Initial),
PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
Expand Down

0 comments on commit b1b22c0

Please sign in to comment.