mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
layout: Implement border-spacing
per CSS 2.1 § 17.6.1 and the legacy
`cellspacing` attribute per HTML5 § 14.3.9. Table layout code has been refactored to push the spacing down to rowgroups and rows; this will aid the implementation of `border-collapse` as well. This commit also fixes two nasty issues in table layout: * In fixed layout, extra space would not be divided among columns that had auto width but had nonzero minimum width. * In automatic layout, extra space would be distributed to constrained columns as well even if unconstrained columns with percentage equal to zero were present.
This commit is contained in:
parent
e8f1a046c6
commit
586c12ccc4
26 changed files with 690 additions and 208 deletions
|
@ -36,6 +36,7 @@ git = "https://github.com/servo/string-cache"
|
|||
[dependencies]
|
||||
text_writer = "0.1.1"
|
||||
encoding = "0.2"
|
||||
rustc-serialize = "0.2"
|
||||
matches = "0.1"
|
||||
url = "0.2.16"
|
||||
mod_path = "0.1"
|
||||
|
|
|
@ -14,7 +14,7 @@ use values::specified::CSSColor;
|
|||
use values::{CSSFloat, specified};
|
||||
use properties::DeclaredValue::SpecifiedValue;
|
||||
use properties::PropertyDeclaration;
|
||||
use properties::longhands;
|
||||
use properties::longhands::{self, border_spacing};
|
||||
use selector_matching::Stylist;
|
||||
|
||||
use cssparser::Color;
|
||||
|
@ -43,6 +43,8 @@ pub enum IntegerAttribute {
|
|||
pub enum UnsignedIntegerAttribute {
|
||||
/// `<td border>`
|
||||
Border,
|
||||
/// `<table cellspacing>`
|
||||
CellSpacing,
|
||||
/// `<td colspan>`
|
||||
ColSpan,
|
||||
}
|
||||
|
@ -143,6 +145,21 @@ impl PresentationalHintSynthesis for Stylist {
|
|||
element,
|
||||
matching_rules_list,
|
||||
shareable);
|
||||
match element.get_unsigned_integer_attribute(
|
||||
UnsignedIntegerAttribute::CellSpacing) {
|
||||
None => {}
|
||||
Some(length) => {
|
||||
let width_value = specified::Length::Absolute(Au::from_px(length as int));
|
||||
matching_rules_list.vec_push(from_declaration(
|
||||
PropertyDeclaration::BorderSpacing(
|
||||
SpecifiedValue(
|
||||
border_spacing::SpecifiedValue {
|
||||
horizontal: width_value,
|
||||
vertical: width_value,
|
||||
}))));
|
||||
*shareable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
name if *name == atom!("body") || *name == atom!("tr") || *name == atom!("thead") ||
|
||||
*name == atom!("tbody") || *name == atom!("tfoot") => {
|
||||
|
|
|
@ -28,6 +28,7 @@ extern crate cssparser;
|
|||
extern crate matches;
|
||||
|
||||
extern crate encoding;
|
||||
extern crate "rustc-serialize" as rustc_serialize;
|
||||
extern crate string_cache;
|
||||
extern crate selectors;
|
||||
|
||||
|
|
|
@ -2020,6 +2020,89 @@ pub mod longhands {
|
|||
|
||||
${single_keyword("caption-side", "top bottom")}
|
||||
|
||||
${single_keyword("border-collapse", "separate collapse", experimental=True)}
|
||||
|
||||
<%self:longhand name="border-spacing">
|
||||
use values::computed::{Context, ToComputedValue};
|
||||
|
||||
use cssparser::ToCss;
|
||||
use text_writer::{self, TextWriter};
|
||||
use util::geometry::Au;
|
||||
|
||||
pub mod computed_value {
|
||||
use util::geometry::Au;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable)]
|
||||
pub struct T {
|
||||
pub horizontal: Au,
|
||||
pub vertical: Au,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SpecifiedValue {
|
||||
pub horizontal: specified::Length,
|
||||
pub vertical: specified::Length,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
computed_value::T {
|
||||
horizontal: Au(0),
|
||||
vertical: Au(0),
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||
try!(self.horizontal.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
self.vertical.to_css(dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
type ComputedValue = computed_value::T;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||
computed_value::T {
|
||||
horizontal: self.horizontal.to_computed_value(context),
|
||||
vertical: self.vertical.to_computed_value(context),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||
let mut lengths = [ None, None ];
|
||||
for i in range(0, 2) {
|
||||
match specified::Length::parse_non_negative(input) {
|
||||
Err(()) => break,
|
||||
Ok(length) => lengths[i] = Some(length),
|
||||
}
|
||||
}
|
||||
if input.next().is_ok() {
|
||||
return Err(())
|
||||
}
|
||||
match (lengths[0], lengths[1]) {
|
||||
(None, None) => Err(()),
|
||||
(Some(length), None) => {
|
||||
Ok(SpecifiedValue {
|
||||
horizontal: length,
|
||||
vertical: length,
|
||||
})
|
||||
}
|
||||
(Some(horizontal), Some(vertical)) => {
|
||||
Ok(SpecifiedValue {
|
||||
horizontal: horizontal,
|
||||
vertical: vertical,
|
||||
})
|
||||
}
|
||||
(None, Some(_)) => panic!("shouldn't happen"),
|
||||
}
|
||||
}
|
||||
</%self:longhand>
|
||||
|
||||
// CSS 2.1, Section 18 - User interface
|
||||
|
||||
|
||||
|
|
|
@ -193,16 +193,19 @@ impl Stylist {
|
|||
|
||||
let mut shareable = true;
|
||||
|
||||
// Step 1: Virtual rules that are synthesized from legacy HTML attributes.
|
||||
self.synthesize_presentational_hints_for_legacy_attributes(element,
|
||||
applicable_declarations,
|
||||
&mut shareable);
|
||||
|
||||
// Step 2: Normal rules.
|
||||
// Step 1: Normal user-agent rules.
|
||||
map.user_agent.normal.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
applicable_declarations,
|
||||
&mut shareable);
|
||||
|
||||
// Step 2: Presentational hints.
|
||||
self.synthesize_presentational_hints_for_legacy_attributes(element,
|
||||
applicable_declarations,
|
||||
&mut shareable);
|
||||
|
||||
// Step 3: User and author normal rules.
|
||||
map.user.normal.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
applicable_declarations,
|
||||
|
@ -212,27 +215,27 @@ impl Stylist {
|
|||
applicable_declarations,
|
||||
&mut shareable);
|
||||
|
||||
// Step 3: Normal style attributes.
|
||||
// Step 4: Normal style attributes.
|
||||
style_attribute.map(|sa| {
|
||||
shareable = false;
|
||||
applicable_declarations.vec_push(
|
||||
GenericDeclarationBlock::from_declarations(sa.normal.clone()))
|
||||
});
|
||||
|
||||
// Step 4: Author-supplied `!important` rules.
|
||||
// Step 5: Author-supplied `!important` rules.
|
||||
map.author.important.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
applicable_declarations,
|
||||
&mut shareable);
|
||||
|
||||
// Step 5: `!important` style attributes.
|
||||
// Step 6: `!important` style attributes.
|
||||
style_attribute.map(|sa| {
|
||||
shareable = false;
|
||||
applicable_declarations.vec_push(
|
||||
GenericDeclarationBlock::from_declarations(sa.important.clone()))
|
||||
});
|
||||
|
||||
// Step 6: User and UA `!important` rules.
|
||||
// Step 7: User and UA `!important` rules.
|
||||
map.user.important.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
applicable_declarations,
|
||||
|
@ -277,3 +280,4 @@ impl PerPseudoElementSelectorMap {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue