зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #3296 - Support CSS2 background-position keyword and percent values. r=SimonSapin (from mbrubeck:background-position)
Source-Repo: https://github.com/servo/servo Source-Revision: 8e2ac7a5c54326f47cbb23394142beee0c17cff2
This commit is contained in:
Родитель
2a3015f090
Коммит
88a04bafa4
|
@ -728,12 +728,15 @@ impl 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);
|
||||
|
||||
// Adjust bounds for `background-position` and `background-attachment`.
|
||||
let mut bounds = *absolute_bounds;
|
||||
let horizontal_position = model::specified(background.background_position.horizontal,
|
||||
bounds.size.width);
|
||||
bounds.size.width - image_width);
|
||||
let vertical_position = model::specified(background.background_position.vertical,
|
||||
bounds.size.height);
|
||||
bounds.size.height - image_height);
|
||||
|
||||
// TODO: These are some situations below where it is possible
|
||||
// to determine that clipping is not necessary - this is an
|
||||
|
@ -743,9 +746,6 @@ impl Fragment {
|
|||
children: DisplayList::new(),
|
||||
});
|
||||
|
||||
let image_width = Au::from_px(image.width as int);
|
||||
let image_height = Au::from_px(image.height as int);
|
||||
|
||||
match background.background_attachment {
|
||||
background_attachment::scroll => {
|
||||
bounds.origin.x = bounds.origin.x + horizontal_position;
|
||||
|
@ -759,25 +759,21 @@ impl Fragment {
|
|||
}
|
||||
background_repeat::repeat_x => {
|
||||
bounds.size.height = Au::min(bounds.size.height - vertical_position, image_height);
|
||||
if horizontal_position > Au(0) {
|
||||
bounds.origin.x = bounds.origin.x - image_width;
|
||||
if horizontal_position != Au(0) {
|
||||
bounds.size.width = bounds.size.width + image_width;
|
||||
}
|
||||
}
|
||||
background_repeat::repeat_y => {
|
||||
bounds.size.width = Au::min(bounds.size.width - horizontal_position, image_width);
|
||||
if vertical_position > Au(0) {
|
||||
bounds.origin.y = bounds.origin.y - image_height;
|
||||
if vertical_position != Au(0) {
|
||||
bounds.size.height = bounds.size.height + image_height;
|
||||
}
|
||||
}
|
||||
background_repeat::repeat => {
|
||||
if horizontal_position > Au(0) {
|
||||
bounds.origin.x = bounds.origin.x - image_width;
|
||||
if horizontal_position != Au(0) {
|
||||
bounds.size.width = bounds.size.width + image_width;
|
||||
}
|
||||
if vertical_position > Au(0) {
|
||||
bounds.origin.y = bounds.origin.y - image_height;
|
||||
if vertical_position != Au(0) {
|
||||
bounds.size.height = bounds.size.height + image_height;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,6 +160,47 @@ pub mod specified {
|
|||
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ false)
|
||||
}
|
||||
}
|
||||
|
||||
// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position
|
||||
#[deriving(Clone)]
|
||||
pub enum PositionComponent {
|
||||
Pos_Length(Length),
|
||||
Pos_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
|
||||
Pos_Center,
|
||||
Pos_Left,
|
||||
Pos_Right,
|
||||
Pos_Top,
|
||||
Pos_Bottom,
|
||||
}
|
||||
impl PositionComponent {
|
||||
pub fn parse(input: &ComponentValue) -> Result<PositionComponent, ()> {
|
||||
match input {
|
||||
&Dimension(ref value, ref unit) =>
|
||||
Length::parse_dimension(value.value, unit.as_slice()).map(Pos_Length),
|
||||
&ast::Percentage(ref value) => Ok(Pos_Percentage(value.value / 100.)),
|
||||
&Number(ref value) if value.value == 0. => Ok(Pos_Length(Au_(Au(0)))),
|
||||
&Ident(ref value) => {
|
||||
if value.as_slice().eq_ignore_ascii_case("center") { Ok(Pos_Center) }
|
||||
else if value.as_slice().eq_ignore_ascii_case("left") { Ok(Pos_Left) }
|
||||
else if value.as_slice().eq_ignore_ascii_case("right") { Ok(Pos_Right) }
|
||||
else if value.as_slice().eq_ignore_ascii_case("top") { Ok(Pos_Top) }
|
||||
else if value.as_slice().eq_ignore_ascii_case("bottom") { Ok(Pos_Bottom) }
|
||||
else { Err(()) }
|
||||
}
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
|
||||
match self {
|
||||
Pos_Length(x) => LP_Length(x),
|
||||
Pos_Percentage(x) => LP_Percentage(x),
|
||||
Pos_Center => LP_Percentage(0.5),
|
||||
Pos_Left | Pos_Top => LP_Percentage(0.0),
|
||||
Pos_Right | Pos_Bottom => LP_Percentage(1.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod computed {
|
||||
|
|
|
@ -627,6 +627,46 @@ pub mod longhands {
|
|||
pub vertical: specified::LengthOrPercentage,
|
||||
}
|
||||
|
||||
impl SpecifiedValue {
|
||||
fn new(first: specified::PositionComponent, second: specified::PositionComponent)
|
||||
-> Result<SpecifiedValue,()> {
|
||||
let (horiz, vert) = match (category(first), category(second)) {
|
||||
// Don't allow two vertical keywords or two horizontal keywords.
|
||||
(HorizontalKeyword, HorizontalKeyword) |
|
||||
(VerticalKeyword, VerticalKeyword) => return Err(()),
|
||||
|
||||
// Swap if both are keywords and vertical precedes horizontal.
|
||||
(VerticalKeyword, HorizontalKeyword) |
|
||||
(VerticalKeyword, OtherKeyword) |
|
||||
(OtherKeyword, HorizontalKeyword) => (second, first),
|
||||
|
||||
// By default, horizontal is first.
|
||||
_ => (first, second),
|
||||
};
|
||||
Ok(SpecifiedValue {
|
||||
horizontal: horiz.to_length_or_percentage(),
|
||||
vertical: vert.to_length_or_percentage(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Collapse `Position` into a few categories to simplify the above `match` expression.
|
||||
enum PositionCategory {
|
||||
HorizontalKeyword,
|
||||
VerticalKeyword,
|
||||
OtherKeyword,
|
||||
LengthOrPercentage,
|
||||
}
|
||||
fn category(p: specified::PositionComponent) -> PositionCategory {
|
||||
match p {
|
||||
specified::Pos_Left | specified::Pos_Right => HorizontalKeyword,
|
||||
specified::Pos_Top | specified::Pos_Bottom => VerticalKeyword,
|
||||
specified::Pos_Center => OtherKeyword,
|
||||
specified::Pos_Length(_) |
|
||||
specified::Pos_Percentage(_) => LengthOrPercentage,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
|
||||
-> computed_value::T {
|
||||
|
@ -644,29 +684,32 @@ pub mod longhands {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(#1997, pcwalton): Support complete CSS2 syntax.
|
||||
pub fn parse_horizontal_and_vertical(horiz: &ComponentValue, vert: &ComponentValue)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
let horiz = try!(specified::LengthOrPercentage::parse_non_negative(horiz));
|
||||
let vert = try!(specified::LengthOrPercentage::parse_non_negative(vert));
|
||||
pub fn parse_one(first: &ComponentValue) -> Result<SpecifiedValue, ()> {
|
||||
let first = try!(specified::PositionComponent::parse(first));
|
||||
// If only one value is provided, use `center` for the second.
|
||||
SpecifiedValue::new(first, specified::Pos_Center)
|
||||
}
|
||||
|
||||
Ok(SpecifiedValue {
|
||||
horizontal: horiz,
|
||||
vertical: vert,
|
||||
})
|
||||
pub fn parse_two(first: &ComponentValue, second: &ComponentValue)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
let first = try!(specified::PositionComponent::parse(first));
|
||||
let second = try!(specified::PositionComponent::parse(second));
|
||||
SpecifiedValue::new(first, second)
|
||||
}
|
||||
|
||||
pub fn parse(input: &[ComponentValue], _: &Url) -> Result<SpecifiedValue, ()> {
|
||||
let mut input_iter = input.skip_whitespace();
|
||||
let horizontal = input_iter.next();
|
||||
let vertical = input_iter.next();
|
||||
let first = input_iter.next();
|
||||
let second = input_iter.next();
|
||||
if input_iter.next().is_some() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
match (horizontal, vertical) {
|
||||
(Some(horizontal), Some(vertical)) => {
|
||||
parse_horizontal_and_vertical(horizontal, vertical)
|
||||
match (first, second) {
|
||||
(Some(first), Some(second)) => {
|
||||
parse_two(first, second)
|
||||
}
|
||||
(Some(first), None) => {
|
||||
parse_one(first)
|
||||
}
|
||||
_ => Err(())
|
||||
}
|
||||
|
@ -1097,10 +1140,40 @@ pub mod shorthands {
|
|||
|
||||
let (mut color, mut image, mut position, mut repeat, mut attachment) =
|
||||
(None, None, None, None, None);
|
||||
let mut last_component_value = None;
|
||||
let mut unused_component_value = None;
|
||||
let mut any = false;
|
||||
|
||||
for component_value in input.skip_whitespace() {
|
||||
// Try `background-position` first because it might not use the value.
|
||||
if position.is_none() {
|
||||
match mem::replace(&mut unused_component_value, None) {
|
||||
Some(saved_component_value) => {
|
||||
// First try parsing a pair of values, then a single value.
|
||||
match background_position::parse_two(saved_component_value,
|
||||
component_value) {
|
||||
Ok(v) => {
|
||||
position = Some(v);
|
||||
any = true;
|
||||
continue
|
||||
},
|
||||
Err(()) => {
|
||||
match background_position::parse_one(saved_component_value) {
|
||||
Ok(v) => {
|
||||
position = Some(v);
|
||||
any = true;
|
||||
// We haven't used the current `component_value`;
|
||||
// keep attempting to parse it below.
|
||||
},
|
||||
// If we get here, parsing failed.
|
||||
Err(()) => return Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => () // Wait until we have a pair of potential values.
|
||||
}
|
||||
}
|
||||
|
||||
if color.is_none() {
|
||||
match background_color::from_component_value(component_value, base_url) {
|
||||
Ok(v) => {
|
||||
|
@ -1146,32 +1219,27 @@ pub mod shorthands {
|
|||
}
|
||||
}
|
||||
|
||||
match mem::replace(&mut last_component_value, None) {
|
||||
Some(saved_component_value) => {
|
||||
if position.is_none() {
|
||||
match background_position::parse_horizontal_and_vertical(
|
||||
saved_component_value,
|
||||
component_value) {
|
||||
Ok(v) => {
|
||||
position = Some(v);
|
||||
any = true;
|
||||
continue
|
||||
},
|
||||
Err(()) => (),
|
||||
}
|
||||
}
|
||||
// Save the component value. It may the first of a background-position pair.
|
||||
unused_component_value = Some(component_value);
|
||||
}
|
||||
|
||||
// If we get here, parsing failed.
|
||||
return Err(())
|
||||
}
|
||||
None => {
|
||||
// Save the component value.
|
||||
last_component_value = Some(component_value)
|
||||
if position.is_none() {
|
||||
// Check for a lone trailing background-position value.
|
||||
match mem::replace(&mut unused_component_value, None) {
|
||||
Some(saved_component_value) => {
|
||||
match background_position::parse_one(saved_component_value) {
|
||||
Ok(v) => {
|
||||
position = Some(v);
|
||||
any = true;
|
||||
},
|
||||
Err(()) => return Err(())
|
||||
}
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
|
||||
if any && last_component_value.is_none() {
|
||||
if any && unused_component_value.is_none() {
|
||||
Ok(Longhands {
|
||||
background_color: color,
|
||||
background_image: image,
|
||||
|
|
Загрузка…
Ссылка в новой задаче