layout: Implement <table width> and <center>.

Improves Hacker News.
This commit is contained in:
Patrick Walton 2015-05-07 18:09:57 -07:00
parent 263b69cf7f
commit 4b9cd4e65d
13 changed files with 160 additions and 36 deletions

View file

@ -55,7 +55,7 @@ use std::cmp::{max, min};
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use style::computed_values::{border_collapse, box_sizing, display, float, overflow_x, overflow_y}; use style::computed_values::{border_collapse, box_sizing, display, float, overflow_x, overflow_y};
use style::computed_values::{position}; use style::computed_values::{position, text_align};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::computed::{LengthOrPercentageOrNone}; use style::values::computed::{LengthOrPercentageOrNone};
@ -1954,6 +1954,7 @@ pub struct ISizeConstraintInput {
pub inline_end_margin: MaybeAuto, pub inline_end_margin: MaybeAuto,
pub inline_start: MaybeAuto, pub inline_start: MaybeAuto,
pub inline_end: MaybeAuto, pub inline_end: MaybeAuto,
pub text_align: text_align::T,
pub available_inline_size: Au, pub available_inline_size: Au,
} }
@ -1963,6 +1964,7 @@ impl ISizeConstraintInput {
inline_end_margin: MaybeAuto, inline_end_margin: MaybeAuto,
inline_start: MaybeAuto, inline_start: MaybeAuto,
inline_end: MaybeAuto, inline_end: MaybeAuto,
text_align: text_align::T,
available_inline_size: Au) available_inline_size: Au)
-> ISizeConstraintInput { -> ISizeConstraintInput {
ISizeConstraintInput { ISizeConstraintInput {
@ -1971,6 +1973,7 @@ impl ISizeConstraintInput {
inline_end_margin: inline_end_margin, inline_end_margin: inline_end_margin,
inline_start: inline_start, inline_start: inline_start,
inline_end: inline_end, inline_end: inline_end,
text_align: text_align,
available_inline_size: available_inline_size, available_inline_size: available_inline_size,
} }
} }
@ -2066,6 +2069,7 @@ pub trait ISizeAndMarginsComputer {
containing_block_inline_size), containing_block_inline_size),
MaybeAuto::from_style(position.inline_end, MaybeAuto::from_style(position.inline_end,
containing_block_inline_size), containing_block_inline_size),
style.get_inheritedtext().text_align,
available_inline_size) available_inline_size)
} }
@ -2241,18 +2245,28 @@ pub trait ISizeAndMarginsComputer {
// available_inline-size // available_inline-size
let (inline_start_margin, mut inline_size, inline_end_margin) = let (inline_start_margin, mut inline_size, inline_end_margin) =
match (inline_start_margin, computed_inline_size, inline_end_margin) { match (inline_start_margin, computed_inline_size, inline_end_margin) {
// If all have a computed value other than 'auto', the system is // If all have a computed value other than 'auto', the system is over-constrained.
// over-constrained so we discard the end margin.
(MaybeAuto::Specified(margin_start), (MaybeAuto::Specified(margin_start),
MaybeAuto::Specified(inline_size), MaybeAuto::Specified(inline_size),
MaybeAuto::Specified(margin_end)) => { MaybeAuto::Specified(margin_end)) => {
if parent_has_same_direction { match (input.text_align, parent_has_same_direction) {
(margin_start, inline_size, available_inline_size - (text_align::T::servo_center, _) => {
(margin_start + inline_size)) // This is used for `<center>` and friends per HTML5 § 14.3.3. Make the
} else { // inline-start and inline-end margins equal per HTML5 § 14.2.
(available_inline_size - (margin_end + inline_size), let margin = (available_inline_size - inline_size).scale_by(0.5);
inline_size, (margin, inline_size, margin)
margin_end) }
(_, true) => {
// Ignore the end margin.
(margin_start, inline_size, available_inline_size -
(margin_start + inline_size))
}
(_, false) => {
// Ignore the start margin.
(available_inline_size - (margin_end + inline_size),
inline_size,
margin_end)
}
} }
} }
// If exactly one value is 'auto', solve for it // If exactly one value is 'auto', solve for it

View file

@ -917,7 +917,7 @@ impl InlineFlow {
InlineFlow::justify_inline_fragments(fragments, line, slack_inline_size) InlineFlow::justify_inline_fragments(fragments, line, slack_inline_size)
} }
text_align::T::justify | text_align::T::start => {} text_align::T::justify | text_align::T::start => {}
text_align::T::center => { text_align::T::center | text_align::T::servo_center => {
inline_start_position_for_fragment = inline_start_position_for_fragment + inline_start_position_for_fragment = inline_start_position_for_fragment +
slack_inline_size.scale_by(0.5) slack_inline_size.scale_by(0.5)
} }

View file

@ -75,6 +75,14 @@ pub trait PresentationalHintSynthesis {
E: TElement<'a> + E: TElement<'a> +
TElementAttributes<'a>, TElementAttributes<'a>,
V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>; V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
/// Synthesizes rules for the legacy `width` attribute.
fn synthesize_presentational_hint_for_legacy_width_attribute<'a,E,V>(
&self,
element: E,
matching_rules_list: &mut V,
shareable: &mut bool)
where E: TElement<'a> + TElementAttributes<'a>,
V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
} }
impl PresentationalHintSynthesis for Stylist { impl PresentationalHintSynthesis for Stylist {
@ -97,27 +105,20 @@ impl PresentationalHintSynthesis for Stylist {
match element.get_local_name() { match element.get_local_name() {
name if *name == atom!("td") => { name if *name == atom!("td") => {
match element.get_length_attribute(LengthAttribute::Width) { self.synthesize_presentational_hint_for_legacy_width_attribute(
LengthOrPercentageOrAuto::Auto => {} element,
LengthOrPercentageOrAuto::Percentage(percentage) => { matching_rules_list,
let width_value = specified::LengthOrPercentageOrAuto::Percentage(percentage); shareable);
matching_rules_list.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
*shareable = false
}
LengthOrPercentageOrAuto::Length(length) => {
let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Absolute(length));
matching_rules_list.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
*shareable = false
}
}
self.synthesize_presentational_hint_for_legacy_border_attribute( self.synthesize_presentational_hint_for_legacy_border_attribute(
element, element,
matching_rules_list, matching_rules_list,
shareable); shareable);
} }
name if *name == atom!("table") => { name if *name == atom!("table") => {
self.synthesize_presentational_hint_for_legacy_width_attribute(
element,
matching_rules_list,
shareable);
self.synthesize_presentational_hint_for_legacy_border_attribute( self.synthesize_presentational_hint_for_legacy_border_attribute(
element, element,
matching_rules_list, matching_rules_list,
@ -221,6 +222,31 @@ impl PresentationalHintSynthesis for Stylist {
} }
} }
} }
fn synthesize_presentational_hint_for_legacy_width_attribute<'a,E,V>(
&self,
element: E,
matching_rules_list: &mut V,
shareable: &mut bool)
where E: TElement<'a> + TElementAttributes<'a>,
V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> {
match element.get_length_attribute(LengthAttribute::Width) {
LengthOrPercentageOrAuto::Auto => {}
LengthOrPercentageOrAuto::Percentage(percentage) => {
let width_value = specified::LengthOrPercentageOrAuto::Percentage(percentage);
matching_rules_list.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
*shareable = false
}
LengthOrPercentageOrAuto::Length(length) => {
let width_value = specified::LengthOrPercentageOrAuto::Length(
specified::Length::Absolute(length));
matching_rules_list.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
*shareable = false
}
}
}
} }

View file

@ -1735,10 +1735,10 @@ pub mod longhands {
impl ComputedValueAsSpecified for SpecifiedValue {} impl ComputedValueAsSpecified for SpecifiedValue {}
pub mod computed_value { pub mod computed_value {
macro_rules! define_text_align { macro_rules! define_text_align {
( $( $name: ident => $discriminant: expr, )+ ) => { ( $( $name: ident ( $string: expr ) => $discriminant: expr, )+ ) => {
define_css_keyword_enum! { T: define_css_keyword_enum! { T:
$( $(
stringify!($name) => $name, $string => $name,
)+ )+
} }
impl T { impl T {
@ -1761,12 +1761,13 @@ pub mod longhands {
} }
} }
define_text_align! { define_text_align! {
start => 0, start("start") => 0,
end => 1, end("end") => 1,
left => 2, left("left") => 2,
right => 3, right("right") => 3,
center => 4, center("center") => 4,
justify => 5, justify("justify") => 5,
servo_center("-servo-center") => 6,
} }
} }
#[inline] pub fn get_initial_value() -> computed_value::T { #[inline] pub fn get_initial_value() -> computed_value::T {

View file

@ -11,7 +11,6 @@ pre[wrap] { white-space: pre-wrap; }
FIXME: also "align descendants" FIXME: also "align descendants"
https://html.spec.whatwg.org/multipage/#align-descendants https://html.spec.whatwg.org/multipage/#align-descendants
*/ */
center, div[align=center i], div[align=middle i] { text-align: center; }
div[align=left i] { text-align: left; } div[align=left i] { text-align: left; }
div[align=right i] { text-align: right; } div[align=right i] { text-align: right; }
div[align=justify i] { text-align: justify; } div[align=justify i] { text-align: justify; }

View file

@ -19,6 +19,17 @@ table {
font-size: initial; font-size: initial;
line-height: initial; line-height: initial;
white-space: initial; white-space: initial;
/* text-align: initial; -- see FIXME below */
}
/*
* FIXME(pcwalton): Actually saying `text-align: initial` above breaks `<table>` inside `<center>`
* in quirks mode. This is because we (following Gecko, WebKit, and Blink) implement the HTML5
* align-descendants rules with a special `text-align: -servo-center`. `text-align: initial`, if
* placed on the `<table>` element per the spec, would break this behavior. So we place it on
* `<tbody>` instead.
*/
tbody {
text-align: initial; text-align: initial;
} }

View file

@ -19,3 +19,5 @@ td[align="left"] { text-align: left; }
td[align="center"] { text-align: center; } td[align="center"] { text-align: center; }
td[align="right"] { text-align: right; } td[align="right"] { text-align: right; }
center, div[align=center i], div[align=middle i] { text-align: -servo-center; }

View file

@ -261,6 +261,7 @@ experimental != overconstrained_block.html overconstrained_block_ref.html
== root_pseudo_a.html root_pseudo_b.html == root_pseudo_a.html root_pseudo_b.html
experimental == rtl_body.html rtl_body_ref.html experimental == rtl_body.html rtl_body_ref.html
experimental == rtl_simple.html rtl_simple_ref.html experimental == rtl_simple.html rtl_simple_ref.html
== servo_center_a.html servo_center_ref.html
== setattribute_id_restyle_a.html setattribute_id_restyle_b.html == setattribute_id_restyle_a.html setattribute_id_restyle_b.html
== stacking_context_overflow_a.html stacking_context_overflow_ref.html == stacking_context_overflow_a.html stacking_context_overflow_ref.html
== stacking_context_overflow_relative_outline_a.html stacking_context_overflow_relative_outline_ref.html == stacking_context_overflow_relative_outline_a.html stacking_context_overflow_relative_outline_ref.html
@ -279,6 +280,7 @@ experimental == rtl_simple.html rtl_simple_ref.html
== table_percentage_capping_a.html table_percentage_capping_ref.html == table_percentage_capping_a.html table_percentage_capping_ref.html
== table_percentage_width_a.html table_percentage_width_ref.html == table_percentage_width_a.html table_percentage_width_ref.html
experimental == table_row_direction_a.html table_row_direction_ref.html experimental == table_row_direction_a.html table_row_direction_ref.html
== table_width_attribute_a.html table_width_attribute_ref.html
== text_align_complex_a.html text_align_complex_ref.html == text_align_complex_a.html text_align_complex_ref.html
== text_align_justify_a.html text_align_justify_ref.html == text_align_justify_a.html text_align_justify_ref.html
experimental == text_align_rtl.html text_align_rtl_ref.html experimental == text_align_rtl.html text_align_rtl_ref.html

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<style>
table {
width: 85%;
background: gold;
}
tbody {
text-align: left;
}
</style>
</head>
<body>
<center>
<table><tr><td>a</td></tr></table>
</center>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<style>
table {
width: 85%;
margin-left: auto;
margin-right: auto;
background: gold;
}
</style>
</head>
<body>
<table><tr><td>a</td></tr></table>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<style>
table {
background: gold;
}
</style>
</head>
<body>
<table width=85%><tr><td>a</td></tr></table>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<style>
table {
width: 85%;
background: gold;
}
</style>
</head>
<body>
<table><tr><td>a</td></tr></table>
</body>
</html>

View file

@ -2,4 +2,4 @@
type: reftest type: reftest
reftype: == reftype: ==
refurl: /html/rendering/non-replaced-elements/tables/table-width-150percent-ref.html refurl: /html/rendering/non-replaced-elements/tables/table-width-150percent-ref.html
expected: FAIL expected: PASS