mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
style: Implement basic column spans.
This patch provides some of the groundwork for column spans greater than 1. It implements the column-span CSS property (prefixed so as not to be exposed to content) as well as the corresponding colspan attribute; although the former is not well-specified outside of CSS multi-column layout, INTRINSIC refers to it. Although width is distributed to spanning columns, they do not yet contribute minimum and preferred widths; this will be implemented in a follow-up. Additionally, this patch cleans up some miscellaneous formatting issues and improves the handling of table rowgroups.
This commit is contained in:
parent
14bafb11be
commit
56b78de5bc
13 changed files with 269 additions and 129 deletions
|
@ -11,11 +11,12 @@ use block::{ISizeConstraintInput, ISizeConstraintSolution};
|
|||
use construct::FlowConstructor;
|
||||
use context::LayoutContext;
|
||||
use floats::FloatKind;
|
||||
use flow::{Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, ImmutableFlowUtils};
|
||||
use flow::{TableFlowClass};
|
||||
use flow::{mod, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
|
||||
use flow::{ImmutableFlowUtils, TableFlowClass};
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use layout_debug;
|
||||
use model::{IntrinsicISizes, IntrinsicISizesContribution};
|
||||
use table_row::CellIntrinsicInlineSize;
|
||||
use table_wrapper::{TableLayout, FixedLayout, AutoLayout};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
|
@ -105,24 +106,52 @@ impl TableFlow {
|
|||
/// Update the corresponding value of `self_inline_sizes` if a value of `kid_inline_sizes` has
|
||||
/// a larger value than one of `self_inline_sizes`. Returns the minimum and preferred inline
|
||||
/// sizes.
|
||||
pub fn update_column_inline_sizes(parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
|
||||
child_inline_sizes: &Vec<ColumnIntrinsicInlineSize>)
|
||||
fn update_automatic_column_inline_sizes(parent_inline_sizes: &mut Vec<ColumnInlineSize>,
|
||||
child_cell_inline_sizes: &[CellIntrinsicInlineSize])
|
||||
-> IntrinsicISizes {
|
||||
let mut total_inline_sizes = IntrinsicISizes::new();
|
||||
for (parent_sizes, child_sizes) in parent_inline_sizes.iter_mut()
|
||||
.zip(child_inline_sizes.iter()) {
|
||||
*parent_sizes = ColumnIntrinsicInlineSize {
|
||||
minimum_length: max(parent_sizes.minimum_length, child_sizes.minimum_length),
|
||||
percentage: parent_sizes.greatest_percentage(child_sizes),
|
||||
preferred: max(parent_sizes.preferred, child_sizes.preferred),
|
||||
constrained: parent_sizes.constrained || child_sizes.constrained
|
||||
};
|
||||
let mut column_index = 0;
|
||||
for child_cell_inline_size in child_cell_inline_sizes.iter() {
|
||||
for _ in range(0, child_cell_inline_size.column_span) {
|
||||
if column_index < parent_inline_sizes.len() {
|
||||
// We already have some intrinsic size information for this column. Merge it in
|
||||
// according to the rules specified in INTRINSIC § 4.
|
||||
let parent_sizes = &mut parent_inline_sizes[column_index];
|
||||
if child_cell_inline_size.column_span > 1 {
|
||||
// TODO(pcwalton): Perform the recursive algorithm specified in INTRINSIC §
|
||||
// 4. For now we make this column contribute no width.
|
||||
} else {
|
||||
let column_size = &child_cell_inline_size.column_size;
|
||||
*parent_sizes = ColumnInlineSize {
|
||||
minimum_length: max(parent_sizes.minimum_length,
|
||||
column_size.minimum_length),
|
||||
percentage: parent_sizes.greatest_percentage(column_size),
|
||||
preferred: max(parent_sizes.preferred, column_size.preferred),
|
||||
constrained: parent_sizes.constrained || column_size.constrained,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We discovered a new column. Initialize its data.
|
||||
debug_assert!(column_index == parent_inline_sizes.len());
|
||||
if child_cell_inline_size.column_span > 1 {
|
||||
// TODO(pcwalton): Perform the recursive algorithm specified in INTRINSIC §
|
||||
// 4. For now we make this column contribute no width.
|
||||
parent_inline_sizes.push(ColumnInlineSize::new())
|
||||
} else {
|
||||
parent_inline_sizes.push(child_cell_inline_size.column_size)
|
||||
}
|
||||
}
|
||||
|
||||
total_inline_sizes.minimum_inline_size = total_inline_sizes.minimum_inline_size +
|
||||
parent_sizes.minimum_length;
|
||||
total_inline_sizes.preferred_inline_size = total_inline_sizes.preferred_inline_size +
|
||||
parent_sizes.preferred;
|
||||
parent_inline_sizes[column_index].minimum_length;
|
||||
total_inline_sizes.preferred_inline_size =
|
||||
total_inline_sizes.preferred_inline_size +
|
||||
parent_inline_sizes[column_index].preferred;
|
||||
|
||||
column_index += 1
|
||||
}
|
||||
}
|
||||
|
||||
total_inline_sizes
|
||||
}
|
||||
|
||||
|
@ -136,6 +165,39 @@ impl TableFlow {
|
|||
fn assign_block_size_table_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||
self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse);
|
||||
}
|
||||
|
||||
/// Updates the minimum and preferred inline-size calculation for a single row. This is
|
||||
/// factored out into a separate function because we process children of rowgroups too.
|
||||
fn update_column_inline_sizes_for_row(child: &mut Flow,
|
||||
column_inline_sizes: &mut Vec<ColumnInlineSize>,
|
||||
computation: &mut IntrinsicISizesContribution,
|
||||
did_first_row: &mut bool,
|
||||
table_layout: TableLayout) {
|
||||
// Read column inline-sizes from the table-row, and assign inline-size=0 for the columns
|
||||
// not defined in the column group.
|
||||
//
|
||||
// FIXME: Need to read inline-sizes from either table-header-group OR the first table-row.
|
||||
debug_assert!(child.is_table_row());
|
||||
let row = child.as_table_row();
|
||||
match table_layout {
|
||||
FixedLayout => {
|
||||
// Fixed table layout only looks at the first row.
|
||||
//
|
||||
// FIXME(pcwalton): This is really inefficient. We should stop after the first row!
|
||||
if !*did_first_row {
|
||||
*did_first_row = true;
|
||||
for cell_inline_size in row.cell_intrinsic_inline_sizes.iter() {
|
||||
column_inline_sizes.push(cell_inline_size.column_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
AutoLayout => {
|
||||
computation.union_block(&TableFlow::update_automatic_column_inline_sizes(
|
||||
column_inline_sizes,
|
||||
row.cell_intrinsic_inline_sizes.as_slice()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Flow for TableFlow {
|
||||
|
@ -190,50 +252,20 @@ impl Flow for TableFlow {
|
|||
constrained: false,
|
||||
})
|
||||
}
|
||||
} else if kid.is_table_rowgroup() || kid.is_table_row() {
|
||||
// Read column inline-sizes from the table-row-group/table-row, and assign
|
||||
// inline-size=0 for the columns not defined in the column group.
|
||||
// FIXME: Need to read inline-sizes from either table-header-group OR the first
|
||||
// table-row.
|
||||
match self.table_layout {
|
||||
FixedLayout => {
|
||||
// Fixed table layout only looks at the first row.
|
||||
if !did_first_row {
|
||||
did_first_row = true;
|
||||
for child_column_inline_size in kid.column_intrinsic_inline_sizes()
|
||||
.iter() {
|
||||
self.column_intrinsic_inline_sizes.push(*child_column_inline_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
AutoLayout => {
|
||||
let child_column_inline_sizes = kid.column_intrinsic_inline_sizes();
|
||||
let mut child_intrinsic_sizes = TableFlow::update_column_inline_sizes(
|
||||
&mut self.column_intrinsic_inline_sizes,
|
||||
child_column_inline_sizes);
|
||||
|
||||
// Add new columns if processing this row caused us to discover them.
|
||||
let child_column_count = child_column_inline_sizes.len();
|
||||
let parent_column_count = self.column_intrinsic_inline_sizes.len();
|
||||
debug!("table until the previous row has {} column(s) and this row has {} \
|
||||
column(s)",
|
||||
parent_column_count,
|
||||
child_column_count);
|
||||
self.column_intrinsic_inline_sizes.reserve(child_column_count);
|
||||
for i in range(parent_column_count, child_column_count) {
|
||||
let inline_size_for_new_column = (*child_column_inline_sizes)[i];
|
||||
child_intrinsic_sizes.minimum_inline_size =
|
||||
child_intrinsic_sizes.minimum_inline_size +
|
||||
inline_size_for_new_column.minimum_length;
|
||||
child_intrinsic_sizes.preferred_inline_size =
|
||||
child_intrinsic_sizes.preferred_inline_size +
|
||||
inline_size_for_new_column.preferred;
|
||||
self.column_intrinsic_inline_sizes.push(inline_size_for_new_column);
|
||||
}
|
||||
|
||||
computation.union_block(&child_intrinsic_sizes)
|
||||
}
|
||||
} else if kid.is_table_rowgroup() {
|
||||
for grandkid in flow::mut_base(kid).child_iter() {
|
||||
TableFlow::update_column_inline_sizes_for_row(grandkid,
|
||||
&mut self.column_inline_sizes,
|
||||
&mut computation,
|
||||
&mut did_first_row,
|
||||
self.table_layout)
|
||||
}
|
||||
} else if kid.is_table_row() {
|
||||
TableFlow::update_column_inline_sizes_for_row(kid,
|
||||
&mut self.column_inline_sizes,
|
||||
&mut computation,
|
||||
&mut did_first_row,
|
||||
self.table_layout)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,20 +30,29 @@ use sync::Arc;
|
|||
pub struct TableRowFlow {
|
||||
pub block_flow: BlockFlow,
|
||||
|
||||
/// Information about the intrinsic inline-sizes of each column.
|
||||
pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>,
|
||||
/// Information about the intrinsic inline-sizes of each cell.
|
||||
pub cell_intrinsic_inline_sizes: Vec<CellIntrinsicInlineSize>,
|
||||
|
||||
/// Information about the computed inline-sizes of each column.
|
||||
pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,
|
||||
}
|
||||
|
||||
/// Information about the column inline size and span for each cell.
|
||||
#[deriving(Encodable)]
|
||||
pub struct CellIntrinsicInlineSize {
|
||||
/// Inline sizes that this cell contributes to the column.
|
||||
pub column_size: ColumnInlineSize,
|
||||
/// The column span of this cell.
|
||||
pub column_span: u32,
|
||||
}
|
||||
|
||||
impl TableRowFlow {
|
||||
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
||||
fragment: Fragment)
|
||||
-> TableRowFlow {
|
||||
TableRowFlow {
|
||||
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
|
||||
column_intrinsic_inline_sizes: Vec::new(),
|
||||
cell_intrinsic_inline_sizes: Vec::new(),
|
||||
column_computed_inline_sizes: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +62,8 @@ impl TableRowFlow {
|
|||
-> TableRowFlow {
|
||||
TableRowFlow {
|
||||
block_flow: BlockFlow::from_node(constructor, node),
|
||||
column_intrinsic_inline_sizes: Vec::new(),
|
||||
column_computed_inline_sizes: Vec::new(),
|
||||
cell_intrinsic_inline_sizes: Vec::new(),
|
||||
column_computed_inline_sizes: Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,10 +190,13 @@ impl Flow for TableRowFlow {
|
|||
|
||||
// Collect the specified column inline-size of the cell. This is used in both fixed and
|
||||
// automatic table layout calculation.
|
||||
let child_specified_inline_size = kid.as_table_cell()
|
||||
.fragment()
|
||||
.style()
|
||||
.content_inline_size();
|
||||
let child_specified_inline_size;
|
||||
let child_column_span;
|
||||
{
|
||||
let child_style = kid.as_table_cell().fragment().style();
|
||||
child_specified_inline_size = child_style.content_inline_size();
|
||||
child_column_span = child_style.get_table()._servo_column_span
|
||||
}
|
||||
|
||||
// Collect minimum and preferred inline-sizes of the cell for automatic table layout
|
||||
// calculation.
|
||||
|
@ -208,15 +220,16 @@ impl Flow for TableRowFlow {
|
|||
};
|
||||
min_inline_size = min_inline_size + child_column_inline_size.minimum_length;
|
||||
pref_inline_size = pref_inline_size + child_column_inline_size.preferred;
|
||||
self.column_intrinsic_inline_sizes.push(child_column_inline_size);
|
||||
self.cell_intrinsic_inline_sizes.push(CellIntrinsicInlineSize {
|
||||
column_size: child_column_inline_size,
|
||||
column_span: child_column_span,
|
||||
});
|
||||
}
|
||||
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size;
|
||||
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = max(min_inline_size,
|
||||
pref_inline_size);
|
||||
}
|
||||
|
||||
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
|
||||
/// When called on this context, the context has had its inline-size set by the parent context.
|
||||
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
|
||||
let _scope = layout_debug_scope!("table_row::assign_inline_sizes {:x}",
|
||||
self.block_flow.base.debug_id());
|
||||
|
@ -233,11 +246,41 @@ impl Flow for TableRowFlow {
|
|||
layout_context,
|
||||
containing_block_inline_size);
|
||||
|
||||
// Spread out the completed inline sizes among columns with spans > 1.
|
||||
let mut computed_inline_size_for_cells = Vec::new();
|
||||
let mut column_inline_size_iterator = self.column_inline_sizes.iter();
|
||||
for cell_intrinsic_inline_size in self.cell_intrinsic_inline_sizes.iter() {
|
||||
//(intrinsic_inline_size_for_column, computed_inline_size_for_column) in
|
||||
// Start with the computed inline size for the first column in the span.
|
||||
let mut column_inline_size = match column_inline_size_iterator.next() {
|
||||
Some(column_inline_size) => *column_inline_size,
|
||||
None => {
|
||||
// This could happen if there are too few cells in this row. Don't crash.
|
||||
break
|
||||
}
|
||||
};
|
||||
|
||||
// Add in computed inline sizes for any extra columns in the span.
|
||||
for _ in range(1, cell_intrinsic_inline_size.column_span) {
|
||||
let extra_column_inline_size = match column_inline_size_iterator.next() {
|
||||
Some(column_inline_size) => column_inline_size,
|
||||
None => break,
|
||||
};
|
||||
column_inline_size.minimum_length = column_inline_size.minimum_length +
|
||||
extra_column_inline_size.minimum_length;
|
||||
column_inline_size.preferred = column_inline_size.preferred +
|
||||
extra_column_inline_size.preferred;
|
||||
}
|
||||
|
||||
computed_inline_size_for_cells.push(column_inline_size)
|
||||
}
|
||||
|
||||
// Push those inline sizes down to the cells.
|
||||
self.block_flow.propagate_assigned_inline_size_to_children(
|
||||
layout_context,
|
||||
inline_start_content_edge,
|
||||
containing_block_inline_size,
|
||||
Some(self.column_computed_inline_sizes.as_slice()));
|
||||
Some(computed_inline_size_for_cells.as_slice()));
|
||||
}
|
||||
|
||||
fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
|
||||
#![deny(unsafe_blocks)]
|
||||
|
||||
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayNotCollapse};
|
||||
use block::{BlockFlow, ISizeAndMarginsComputer};
|
||||
use construct::FlowConstructor;
|
||||
use context::LayoutContext;
|
||||
use flow::{TableRowGroupFlowClass, FlowClass, Flow, ImmutableFlowUtils};
|
||||
use flow::{mod, Flow, FlowClass, TableRowGroupFlowClass};
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use layout_debug;
|
||||
use model::IntrinsicISizesContribution;
|
||||
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, TableFlow};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
|
@ -24,6 +23,7 @@ use sync::Arc;
|
|||
/// A table formatting context.
|
||||
#[deriving(Encodable)]
|
||||
pub struct TableRowGroupFlow {
|
||||
/// Fields common to all block flows.
|
||||
pub block_flow: BlockFlow,
|
||||
|
||||
/// Information about the intrinsic inline-sizes of each column.
|
||||
|
@ -91,54 +91,11 @@ impl Flow for TableRowGroupFlow {
|
|||
&mut self.column_computed_inline_sizes
|
||||
}
|
||||
|
||||
|
||||
/// Recursively (bottom-up) determines the context's preferred and minimum inline-sizes. When
|
||||
/// called on this context, all child contexts have had their min/pref inline-sizes set. This
|
||||
/// function must decide min/pref inline-sizes based on child context inline-sizes and
|
||||
/// dimensions of any fragments it is responsible for flowing.
|
||||
///
|
||||
/// Min/pref inline-sizes set by this function are used in automatic table layout calculation.
|
||||
///
|
||||
/// Also, this function finds the specified column inline-sizes from the first row. These are
|
||||
/// used in fixed table layout calculation.
|
||||
fn bubble_inline_sizes(&mut self) {
|
||||
let _scope = layout_debug_scope!("table_rowgroup::bubble_inline_sizes {:x}",
|
||||
self.block_flow.base.debug_id());
|
||||
|
||||
let mut computation = IntrinsicISizesContribution::new();
|
||||
for kid in self.block_flow.base.child_iter() {
|
||||
assert!(kid.is_table_row());
|
||||
|
||||
// Calculate minimum and preferred inline sizes for automatic table layout.
|
||||
if self.column_intrinsic_inline_sizes.is_empty() {
|
||||
// We're the first row.
|
||||
self.column_intrinsic_inline_sizes = kid.column_intrinsic_inline_sizes().clone();
|
||||
} else {
|
||||
let mut child_intrinsic_sizes =
|
||||
TableFlow::update_column_inline_sizes(&mut self.column_intrinsic_inline_sizes,
|
||||
kid.column_intrinsic_inline_sizes());
|
||||
|
||||
// update the number of column inline-sizes from table-rows.
|
||||
let column_count = self.column_intrinsic_inline_sizes.len();
|
||||
let child_column_count = kid.column_intrinsic_inline_sizes().len();
|
||||
for i in range(column_count, child_column_count) {
|
||||
let this_column_inline_size = (*kid.column_intrinsic_inline_sizes())[i];
|
||||
|
||||
// FIXME(pcwalton): Ignoring the percentage here seems dubious.
|
||||
child_intrinsic_sizes.minimum_inline_size =
|
||||
child_intrinsic_sizes.minimum_inline_size +
|
||||
this_column_inline_size.minimum_length;
|
||||
child_intrinsic_sizes.preferred_inline_size =
|
||||
child_intrinsic_sizes.preferred_inline_size +
|
||||
this_column_inline_size.preferred;
|
||||
self.column_intrinsic_inline_sizes.push(this_column_inline_size);
|
||||
}
|
||||
|
||||
computation.union_block(&child_intrinsic_sizes)
|
||||
}
|
||||
}
|
||||
|
||||
self.block_flow.base.intrinsic_inline_sizes = computation.finish()
|
||||
// Proper calculation of intrinsic sizes in table layout requires access to the entire
|
||||
// table, which we don't have yet. Defer to our parent.
|
||||
}
|
||||
|
||||
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
|
||||
|
|
|
@ -44,8 +44,9 @@ use dom::node::{window_from_node};
|
|||
use dom::nodelist::NodeList;
|
||||
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
||||
use devtools_traits::AttrInfo;
|
||||
use style::{mod, BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute, IntegerAttribute};
|
||||
use style::{LengthAttribute, SimpleColorAttribute, SizeIntegerAttribute, UnsignedIntegerAttribute};
|
||||
use style::{mod, BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute};
|
||||
use style::{ColSpanUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute};
|
||||
use style::{SimpleColorAttribute, SizeIntegerAttribute, UnsignedIntegerAttribute};
|
||||
use style::{WidthLengthAttribute, matches, parse_selector_list_from_str};
|
||||
use servo_util::namespace;
|
||||
use servo_util::str::{DOMString, LengthOrPercentageOrAuto, SimpleColor};
|
||||
|
@ -349,6 +350,14 @@ impl RawLayoutElementHelpers for Element {
|
|||
None
|
||||
}
|
||||
}
|
||||
ColSpanUnsignedIntegerAttribute => {
|
||||
if self.is_htmltablecellelement() {
|
||||
let this: &HTMLTableCellElement = mem::transmute(self);
|
||||
this.get_colspan()
|
||||
} else {
|
||||
panic!("I'm not a table cell!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ pub struct HTMLTableCellElement {
|
|||
htmlelement: HTMLElement,
|
||||
background_color: Cell<Option<SimpleColor>>,
|
||||
border: Cell<Option<u32>>,
|
||||
colspan: Cell<Option<u32>>,
|
||||
width: Cell<LengthOrPercentageOrAuto>,
|
||||
}
|
||||
|
||||
|
@ -45,6 +46,7 @@ impl HTMLTableCellElement {
|
|||
htmlelement: HTMLElement::new_inherited(type_id, tag_name, prefix, document),
|
||||
background_color: Cell::new(None),
|
||||
border: Cell::new(None),
|
||||
colspan: Cell::new(None),
|
||||
width: Cell::new(AutoLpa),
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +60,7 @@ impl HTMLTableCellElement {
|
|||
pub trait HTMLTableCellElementHelpers {
|
||||
fn get_background_color(&self) -> Option<SimpleColor>;
|
||||
fn get_border(&self) -> Option<u32>;
|
||||
fn get_colspan(&self) -> Option<u32>;
|
||||
fn get_width(&self) -> LengthOrPercentageOrAuto;
|
||||
}
|
||||
|
||||
|
@ -70,6 +73,10 @@ impl HTMLTableCellElementHelpers for HTMLTableCellElement {
|
|||
self.border.get()
|
||||
}
|
||||
|
||||
fn get_colspan(&self) -> Option<u32> {
|
||||
self.colspan.get()
|
||||
}
|
||||
|
||||
fn get_width(&self) -> LengthOrPercentageOrAuto {
|
||||
self.width.get()
|
||||
}
|
||||
|
@ -97,6 +104,9 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> {
|
|||
.as_slice()
|
||||
.chars()).unwrap_or(1)))
|
||||
}
|
||||
&atom!("colspan") => {
|
||||
self.colspan.set(str::parse_unsigned_integer(attr.value().as_slice().chars()));
|
||||
}
|
||||
&atom!("width") => self.width.set(str::parse_length(attr.value().as_slice())),
|
||||
_ => ()
|
||||
}
|
||||
|
@ -111,6 +121,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> {
|
|||
match attr.local_name() {
|
||||
&atom!("bgcolor") => self.background_color.set(None),
|
||||
&atom!("border") => self.border.set(None),
|
||||
&atom!("colspan") => self.colspan.set(None),
|
||||
&atom!("width") => self.width.set(AutoLpa),
|
||||
_ => ()
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@ impl HTMLTableElementHelpers for HTMLTableElement {
|
|||
fn get_border(&self) -> Option<u32> {
|
||||
self.border.get()
|
||||
}
|
||||
|
||||
fn get_width(&self) -> LengthOrPercentageOrAuto {
|
||||
self.width.get()
|
||||
}
|
||||
|
@ -135,6 +136,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableElement> {
|
|||
.as_slice()
|
||||
.chars()).unwrap_or(1)))
|
||||
}
|
||||
&atom!("width") => self.width.set(str::parse_length(attr.value().as_slice())),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +150,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableElement> {
|
|||
match attr.local_name() {
|
||||
&atom!("bgcolor") => self.background_color.set(None),
|
||||
&atom!("border") => self.border.set(None),
|
||||
&atom!("width") => self.width.set(AutoLpa),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
use node::{TElement, TElementAttributes, TNode};
|
||||
use properties::{BackgroundColorDeclaration, BorderBottomWidthDeclaration};
|
||||
use properties::{BorderLeftWidthDeclaration, BorderRightWidthDeclaration};
|
||||
use properties::{BorderTopWidthDeclaration, SpecifiedValue, WidthDeclaration, specified};
|
||||
use properties::{BorderTopWidthDeclaration, ServoColumnSpanDeclaration, SpecifiedValue};
|
||||
use properties::{WidthDeclaration, specified};
|
||||
use selector_matching::{DeclarationBlock, Stylist};
|
||||
|
||||
use cssparser::{RGBA, RGBAColor};
|
||||
|
@ -32,6 +33,8 @@ pub enum IntegerAttribute {
|
|||
pub enum UnsignedIntegerAttribute {
|
||||
/// `<td border>`
|
||||
BorderUnsignedIntegerAttribute,
|
||||
/// `<td colspan>`
|
||||
ColSpanUnsignedIntegerAttribute,
|
||||
}
|
||||
|
||||
/// Legacy presentational attributes that take a simple color as defined in HTML5 § 2.4.6.
|
||||
|
@ -111,6 +114,14 @@ impl PresentationalHintSynthesis for Stylist {
|
|||
*shareable = false
|
||||
}
|
||||
}
|
||||
match element.get_unsigned_integer_attribute(ColSpanUnsignedIntegerAttribute) {
|
||||
None => {}
|
||||
Some(value) => {
|
||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||
ServoColumnSpanDeclaration(SpecifiedValue(value))));
|
||||
*shareable = false
|
||||
}
|
||||
}
|
||||
self.synthesize_presentational_hint_for_legacy_background_color_attribute(
|
||||
element,
|
||||
matching_rules_list,
|
||||
|
|
|
@ -54,9 +54,10 @@ pub use selectors::{PseudoElement, Before, After, SelectorList, parse_selector_l
|
|||
pub use selectors::{AttrSelector, NamespaceConstraint, SpecificNamespace, AnyNamespace};
|
||||
pub use selectors::{SimpleSelector, LocalNameSelector};
|
||||
pub use cssparser::{Color, RGBA};
|
||||
pub use legacy::{BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute, IntegerAttribute};
|
||||
pub use legacy::{LengthAttribute, SimpleColorAttribute, SizeIntegerAttribute};
|
||||
pub use legacy::{UnsignedIntegerAttribute, WidthLengthAttribute};
|
||||
pub use legacy::{BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute};
|
||||
pub use legacy::{ColSpanUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute};
|
||||
pub use legacy::{SimpleColorAttribute, SizeIntegerAttribute, UnsignedIntegerAttribute};
|
||||
pub use legacy::{WidthLengthAttribute};
|
||||
pub use font_face::{Source, LocalSource, UrlSource_};
|
||||
|
||||
mod stylesheets;
|
||||
|
|
|
@ -1316,6 +1316,34 @@ pub mod longhands {
|
|||
|
||||
${single_keyword("table-layout", "auto fixed")}
|
||||
|
||||
<%self:single_component_value name="-servo-column-span">
|
||||
// The handling of this property is not well-specified by INTRINSIC, but its presence is
|
||||
// assumed. HTML5 14.3.9 specifies that the `colspan` attribute is to be a nonnegative
|
||||
// integer.
|
||||
pub use super::computed_as_specified as to_computed_value;
|
||||
pub mod computed_value {
|
||||
pub type T = u32;
|
||||
}
|
||||
pub type SpecifiedValue = computed_value::T;
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
1
|
||||
}
|
||||
|
||||
pub fn from_component_value(input: &ComponentValue, _: &Url) -> Result<SpecifiedValue,()> {
|
||||
match input {
|
||||
&Number(ref value) => {
|
||||
match value.int_value {
|
||||
None => Err(()),
|
||||
Some(n) => Ok(n as SpecifiedValue),
|
||||
}
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
</%self:single_component_value>
|
||||
|
||||
// CSS 2.1, Section 18 - User interface
|
||||
|
||||
|
||||
|
|
|
@ -802,8 +802,8 @@ pub fn common_style_affecting_attributes() -> [CommonStyleAffectingAttributeInfo
|
|||
/// Attributes that, if present, disable style sharing. All legacy HTML attributes must be in
|
||||
/// either this list or `common_style_affecting_attributes`. See the comment in
|
||||
/// `synthesize_presentational_hints_for_legacy_attributes`.
|
||||
pub fn rare_style_affecting_attributes() -> [Atom, ..2] {
|
||||
[ atom!("bgcolor"), atom!("border") ]
|
||||
pub fn rare_style_affecting_attributes() -> [Atom, ..3] {
|
||||
[ atom!("bgcolor"), atom!("border"), atom!("colspan") ]
|
||||
}
|
||||
|
||||
/// Determines whether the given element matches the given single selector.
|
||||
|
|
|
@ -209,5 +209,6 @@ fragment=top != ../html/acid2.html acid2_ref.html
|
|||
== box_shadow_inset_parsing_a.html box_shadow_inset_parsing_ref.html
|
||||
!= list_style_type_a.html list_style_type_ref.html
|
||||
== list_style_position_a.html list_style_position_ref.html
|
||||
== table_colspan_simple_a.html table_colspan_simple_ref.html
|
||||
== legacy_td_bgcolor_attribute_a.html legacy_td_bgcolor_attribute_ref.html
|
||||
== legacy_table_border_attribute_a.html legacy_table_border_attribute_ref.html
|
||||
|
|
22
tests/ref/table_colspan_simple_a.html
Normal file
22
tests/ref/table_colspan_simple_a.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
td[colspan="2"] {
|
||||
background-color: blue;
|
||||
color: white;
|
||||
}
|
||||
td[colspan="3"] {
|
||||
background-color: green;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<table border=0 cellspacing=0 cellpadding=0>
|
||||
<tr><td width=100> </td><td width=100> </td><td width=100> </td></tr>
|
||||
<tr><td colspan=2> </td><td> </td></tr>
|
||||
<tr><td> <td colspan=2> </td></tr>
|
||||
<tr><td colspan=3> </td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
22
tests/ref/table_colspan_simple_ref.html
Normal file
22
tests/ref/table_colspan_simple_ref.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
td.two {
|
||||
background-color: blue;
|
||||
color: white;
|
||||
}
|
||||
td.three {
|
||||
background-color: green;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<table border=0 cellspacing=0 cellpadding=0>
|
||||
<tr><td width=100> </td><td width=100> </td><td width=100> </td></tr>
|
||||
<tr><td class=two> </td><td class=two></td><td> </td></tr>
|
||||
<tr><td> <td class=two> </td><td class=two></td></tr>
|
||||
<tr><td class=three> </td><td class=three></td><td class=three></td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue