servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
//! CSS table formatting contexts.
|
|
|
|
|
2015-03-21 14:12:45 +03:00
|
|
|
#![deny(unsafe_code)]
|
2014-06-04 09:25:28 +04:00
|
|
|
|
2015-10-01 00:19:33 +03:00
|
|
|
use app_units::Au;
|
2015-11-05 04:34:11 +03:00
|
|
|
use block::{BlockFlow, CandidateBSizeIterator, ISizeAndMarginsComputer};
|
2014-07-19 00:27:23 +04:00
|
|
|
use block::{ISizeConstraintInput, ISizeConstraintSolution};
|
2017-02-08 04:16:05 +03:00
|
|
|
use context::LayoutContext;
|
2018-01-07 17:53:18 +03:00
|
|
|
use display_list::{BlockFlowDisplayListBuilding, BorderPaintingMode};
|
|
|
|
use display_list::{DisplayListBuildState, StackingContextCollectionFlags, StackingContextCollectionState};
|
2016-02-05 08:28:50 +03:00
|
|
|
use euclid::Point2D;
|
2017-12-15 21:44:50 +03:00
|
|
|
use flow::{BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, GetBaseFlow, OpaqueFlow};
|
2018-02-21 20:00:03 +03:00
|
|
|
use flow_list::{FlowListIterator, MutFlowListIterator};
|
2016-02-05 08:28:50 +03:00
|
|
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
2016-07-04 22:57:00 +03:00
|
|
|
use gfx_traits::print_tree::PrintTree;
|
2014-09-20 06:50:47 +04:00
|
|
|
use layout_debug;
|
2015-03-12 22:03:49 +03:00
|
|
|
use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
|
2018-02-21 20:00:03 +03:00
|
|
|
use std::{cmp, fmt};
|
2015-03-12 22:03:49 +03:00
|
|
|
use style::computed_values::{border_collapse, border_spacing, table_layout};
|
servo: Merge #12515 - Make the style crate more concrete (from servo:concrete-style); r=bholley
Background:
The changes to Servo code to support Stylo began in the `selectors` crate with making pseudo-elements generic, defined be the user, so that different users (such as Servo and Gecko/Stylo) could have a different set of pseudo-elements supported and parsed. Adding a trait makes sense there since `selectors` is in its own repository and has others users (or at least [one](https://github.com/SimonSapin/kuchiki)).
Then we kind of kept going with the same pattern and added a bunch of traits in the `style` crate to make everything generic, allowing Servo and Gecko/Stylo to do things differently. But we’ve also added a `gecko` Cargo feature to do conditional compilation, at first to enable or disable some CSS properties and values in the Mako templates. Since we’re doing conditional compilation anyway, it’s often easier and simpler to do it more (with `#[cfg(feature = "gecko")]` and `#[cfg(feature = "servo")]`) that to keep adding traits and making everything generic. When a type is generic, any method that we want to call on it needs to be part of some trait.
----
The first several commits move some code around, mostly from `geckolib` to `style` (with `#[cfg(feature = "gecko")]`) but otherwise don’t change much.
The following commits remove some traits and many type parameters through the `style` crate, replacing them with pairs of conditionally-compiled API-compatible items (types, methods, …).
Simplifying code is nice to make it more maintainable, but this is motivated by another change described in https://github.com/servo/servo/pull/12391#issuecomment-232183942. (Porting Servo for that change proved difficult because some code in the `style` crate was becoming generic over `String` vs `Atom`, and this PR will help make that concrete. That change, in turn, is motivated by removing geckolib’s `[replace]` override for string-cache, in order to enable using a single Cargo "workspace" in this repository.)
r? @bholley
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #__ (github issue number if applicable).
<!-- Either: -->
- [ ] There are tests for these changes OR
- [x] These changes do not require new tests because refactoring
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Source-Repo: https://github.com/servo/servo
Source-Revision: 2d01d41a506bcbc7f26a2284b9f42390d6ef96ab
--HG--
rename : servo/ports/geckolib/selector_impl.rs => servo/components/style/gecko_selector_impl.rs
rename : servo/ports/geckolib/values.rs => servo/components/style/gecko_values.rs
rename : servo/ports/geckolib/properties.mako.rs => servo/components/style/properties/gecko.mako.rs
2016-07-20 10:58:34 +03:00
|
|
|
use style::context::SharedStyleContext;
|
2016-02-18 12:21:29 +03:00
|
|
|
use style::logical_geometry::LogicalSize;
|
2017-07-18 05:44:25 +03:00
|
|
|
use style::properties::ComputedValues;
|
2018-02-21 20:00:03 +03:00
|
|
|
use style::properties::style_structs::Background;
|
2017-10-31 02:25:45 +03:00
|
|
|
use style::servo::restyle_damage::ServoRestyleDamage;
|
2015-01-31 01:27:53 +03:00
|
|
|
use style::values::CSSFloat;
|
2017-09-17 23:12:46 +03:00
|
|
|
use style::values::computed::LengthOrPercentageOrAuto;
|
2018-02-21 20:00:03 +03:00
|
|
|
use table_cell::TableCellFlow;
|
2015-09-19 22:34:51 +03:00
|
|
|
use table_row::{self, CellIntrinsicInlineSize, CollapsedBorder, CollapsedBorderProvenance};
|
2018-03-01 21:36:43 +03:00
|
|
|
use table_row::{TableRowFlow, TableRowSizeData};
|
2015-09-19 22:34:51 +03:00
|
|
|
use table_wrapper::TableLayout;
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
|
2017-10-14 05:43:09 +03:00
|
|
|
#[allow(unsafe_code)]
|
|
|
|
unsafe impl ::flow::HasBaseFlow for TableFlow {}
|
|
|
|
|
2014-05-29 04:34:06 +04:00
|
|
|
/// A table flow corresponded to the table's internal table fragment under a table wrapper flow.
|
|
|
|
/// The properties `position`, `float`, and `margin-*` are used on the table wrapper fragment,
|
|
|
|
/// not table fragment per CSS 2.1 § 10.5.
|
2016-11-07 11:15:03 +03:00
|
|
|
#[derive(Serialize)]
|
2017-10-14 05:43:09 +03:00
|
|
|
#[repr(C)]
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
pub struct TableFlow {
|
2014-04-28 02:52:39 +04:00
|
|
|
pub block_flow: BlockFlow,
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
|
2014-12-12 04:06:53 +03:00
|
|
|
/// Information about the intrinsic inline-sizes of each column, computed bottom-up during
|
|
|
|
/// intrinsic inline-size bubbling.
|
|
|
|
pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>,
|
|
|
|
|
2015-04-27 20:29:15 +03:00
|
|
|
/// Information about the actual inline sizes of each column, computed top-down during actual
|
2014-12-12 04:06:53 +03:00
|
|
|
/// inline-size bubbling.
|
|
|
|
pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,
|
2014-04-04 05:01:48 +04:00
|
|
|
|
2015-04-27 20:29:15 +03:00
|
|
|
/// The final width of the borders in the inline direction for each cell, computed by the
|
|
|
|
/// entire table and pushed down into each row during inline size computation.
|
|
|
|
pub collapsed_inline_direction_border_widths_for_table: Vec<Au>,
|
|
|
|
|
|
|
|
/// The final width of the borders in the block direction for each cell, computed by the
|
|
|
|
/// entire table and pushed down into each row during inline size computation.
|
|
|
|
pub collapsed_block_direction_border_widths_for_table: Vec<Au>,
|
|
|
|
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
/// Table-layout property
|
2014-04-28 02:52:39 +04:00
|
|
|
pub table_layout: TableLayout,
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TableFlow {
|
2015-08-07 07:11:04 +03:00
|
|
|
pub fn from_fragment(fragment: Fragment) -> TableFlow {
|
2016-10-27 04:14:04 +03:00
|
|
|
let mut block_flow = BlockFlow::from_fragment(fragment);
|
2015-03-10 08:24:47 +03:00
|
|
|
let table_layout =
|
2017-12-06 04:35:25 +03:00
|
|
|
if block_flow.fragment().style().get_table().table_layout == table_layout::T::Fixed {
|
2015-03-10 08:24:47 +03:00
|
|
|
TableLayout::Fixed
|
|
|
|
} else {
|
|
|
|
TableLayout::Auto
|
|
|
|
};
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
TableFlow {
|
|
|
|
block_flow: block_flow,
|
2014-12-12 04:06:53 +03:00
|
|
|
column_intrinsic_inline_sizes: Vec::new(),
|
|
|
|
column_computed_inline_sizes: Vec::new(),
|
2015-04-27 20:29:15 +03:00
|
|
|
collapsed_inline_direction_border_widths_for_table: Vec::new(),
|
|
|
|
collapsed_block_direction_border_widths_for_table: Vec::new(),
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
table_layout: table_layout
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-15 01:42:32 +04:00
|
|
|
/// 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.
|
2014-12-16 05:33:46 +03:00
|
|
|
fn update_automatic_column_inline_sizes(
|
|
|
|
parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
|
2016-10-27 04:14:04 +03:00
|
|
|
child_cell_inline_sizes: &[CellIntrinsicInlineSize],
|
|
|
|
surrounding_size: Au)
|
2014-12-16 05:33:46 +03:00
|
|
|
-> IntrinsicISizes {
|
2016-10-27 04:14:04 +03:00
|
|
|
let mut total_inline_sizes = IntrinsicISizes {
|
|
|
|
minimum_inline_size: surrounding_size,
|
|
|
|
preferred_inline_size: surrounding_size,
|
|
|
|
};
|
2014-12-16 05:33:46 +03:00
|
|
|
let mut column_index = 0;
|
2016-12-26 21:09:09 +03:00
|
|
|
let mut incoming_rowspan = vec![];
|
|
|
|
|
2015-08-15 12:03:21 +03:00
|
|
|
for child_cell_inline_size in child_cell_inline_sizes {
|
2016-12-26 21:09:09 +03:00
|
|
|
// Skip any column occupied by a cell from a previous row.
|
|
|
|
while column_index < incoming_rowspan.len() && incoming_rowspan[column_index] != 1 {
|
|
|
|
if incoming_rowspan[column_index] > 1 {
|
|
|
|
incoming_rowspan[column_index] -= 1;
|
|
|
|
}
|
|
|
|
column_index += 1;
|
|
|
|
}
|
2015-04-23 02:24:21 +03:00
|
|
|
for _ in 0..child_cell_inline_size.column_span {
|
2014-12-16 05:33:46 +03:00
|
|
|
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 = ColumnIntrinsicInlineSize {
|
2015-04-27 20:29:15 +03:00
|
|
|
minimum_length: cmp::max(parent_sizes.minimum_length,
|
|
|
|
column_size.minimum_length),
|
2014-12-16 05:33:46 +03:00
|
|
|
percentage: parent_sizes.greatest_percentage(column_size),
|
2015-04-27 20:29:15 +03:00
|
|
|
preferred: cmp::max(parent_sizes.preferred, column_size.preferred),
|
2014-12-16 05:33:46 +03:00
|
|
|
constrained: parent_sizes.constrained || column_size.constrained,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We discovered a new column. Initialize its data.
|
2018-02-07 14:20:36 +03:00
|
|
|
debug_assert_eq!(column_index, parent_inline_sizes.len());
|
2014-12-16 05:33:46 +03:00
|
|
|
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(ColumnIntrinsicInlineSize::new())
|
|
|
|
} else {
|
|
|
|
parent_inline_sizes.push(child_cell_inline_size.column_size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-27 04:14:04 +03:00
|
|
|
total_inline_sizes.minimum_inline_size +=
|
2014-12-16 05:33:46 +03:00
|
|
|
parent_inline_sizes[column_index].minimum_length;
|
2016-10-27 04:14:04 +03:00
|
|
|
total_inline_sizes.preferred_inline_size +=
|
2014-12-16 05:33:46 +03:00
|
|
|
parent_inline_sizes[column_index].preferred;
|
|
|
|
|
2016-12-26 21:09:09 +03:00
|
|
|
// If this cell spans later rows, record its rowspan.
|
|
|
|
if child_cell_inline_size.row_span > 1 {
|
|
|
|
if incoming_rowspan.len() < column_index + 1 {
|
|
|
|
incoming_rowspan.resize(column_index + 1, 0);
|
|
|
|
}
|
|
|
|
incoming_rowspan[column_index] = child_cell_inline_size.row_span;
|
|
|
|
}
|
|
|
|
|
2014-12-16 05:33:46 +03:00
|
|
|
column_index += 1
|
|
|
|
}
|
2014-04-04 05:01:48 +04:00
|
|
|
}
|
2014-12-16 05:33:46 +03:00
|
|
|
|
2014-10-15 01:42:32 +04:00
|
|
|
total_inline_sizes
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
|
2014-12-16 05:33:46 +03:00
|
|
|
/// 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.
|
2016-06-22 01:51:26 +03:00
|
|
|
fn update_column_inline_sizes_for_row(row: &TableRowFlow,
|
2014-12-16 05:33:46 +03:00
|
|
|
column_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
|
|
|
|
computation: &mut IntrinsicISizesContribution,
|
2015-04-27 20:29:15 +03:00
|
|
|
first_row: bool,
|
2016-10-27 04:14:04 +03:00
|
|
|
table_layout: TableLayout,
|
|
|
|
surrounding_inline_size: Au) {
|
2014-12-16 05:33:46 +03:00
|
|
|
// 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.
|
|
|
|
match table_layout {
|
2014-12-18 04:45:49 +03:00
|
|
|
TableLayout::Fixed => {
|
2014-12-16 05:33:46 +03:00
|
|
|
// Fixed table layout only looks at the first row.
|
|
|
|
//
|
|
|
|
// FIXME(pcwalton): This is really inefficient. We should stop after the first row!
|
2015-04-27 20:29:15 +03:00
|
|
|
if first_row {
|
2015-08-15 12:03:21 +03:00
|
|
|
for cell_inline_size in &row.cell_intrinsic_inline_sizes {
|
2014-12-16 05:33:46 +03:00
|
|
|
column_inline_sizes.push(cell_inline_size.column_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-18 04:45:49 +03:00
|
|
|
TableLayout::Auto => {
|
2014-12-16 05:33:46 +03:00
|
|
|
computation.union_block(&TableFlow::update_automatic_column_inline_sizes(
|
|
|
|
column_inline_sizes,
|
2016-10-27 04:14:04 +03:00
|
|
|
&row.cell_intrinsic_inline_sizes,
|
|
|
|
surrounding_inline_size))
|
2014-12-16 05:33:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-12 22:03:49 +03:00
|
|
|
|
|
|
|
/// Returns the effective spacing per cell, taking the value of `border-collapse` into account.
|
2015-04-27 20:29:15 +03:00
|
|
|
pub fn spacing(&self) -> border_spacing::T {
|
2015-03-12 22:03:49 +03:00
|
|
|
let style = self.block_flow.fragment.style();
|
|
|
|
match style.get_inheritedtable().border_collapse {
|
2017-12-06 04:35:25 +03:00
|
|
|
border_collapse::T::Separate => style.get_inheritedtable().border_spacing,
|
|
|
|
border_collapse::T::Collapse => border_spacing::T::zero(),
|
2015-03-12 22:03:49 +03:00
|
|
|
}
|
|
|
|
}
|
2015-04-28 21:53:59 +03:00
|
|
|
|
|
|
|
pub fn total_horizontal_spacing(&self) -> Au {
|
|
|
|
let num_columns = self.column_intrinsic_inline_sizes.len();
|
|
|
|
if num_columns == 0 {
|
|
|
|
return Au(0);
|
|
|
|
}
|
2017-09-17 23:12:46 +03:00
|
|
|
self.spacing().horizontal() * (num_columns as i32 + 1)
|
2015-04-28 21:53:59 +03:00
|
|
|
}
|
2018-02-21 20:00:03 +03:00
|
|
|
|
|
|
|
fn column_styles(&self) -> Vec<ColumnStyle> {
|
|
|
|
let mut styles = vec![];
|
|
|
|
for group in self.block_flow.base.child_iter()
|
|
|
|
.filter(|kid| kid.is_table_colgroup()) {
|
|
|
|
// XXXManishearth these as_foo methods should return options
|
|
|
|
// so that we can filter_map
|
|
|
|
let group = group.as_table_colgroup();
|
|
|
|
let colgroup_style = group.fragment.as_ref()
|
|
|
|
.map(|f| f.style());
|
|
|
|
|
|
|
|
// The colgroup's span attribute is only relevant when
|
|
|
|
// it has no children
|
|
|
|
// https://html.spec.whatwg.org/multipage/#forming-a-table
|
|
|
|
if group.cols.is_empty() {
|
|
|
|
let span = group.fragment.as_ref()
|
|
|
|
.map(|f| f.column_span()).unwrap_or(1);
|
|
|
|
styles.push(ColumnStyle { span, colgroup_style, col_style: None });
|
|
|
|
} else {
|
|
|
|
for col in &group.cols {
|
|
|
|
// XXXManishearth Arc-cloning colgroup_style is suboptimal
|
|
|
|
styles.push(ColumnStyle {
|
|
|
|
span: col.column_span(),
|
|
|
|
colgroup_style: colgroup_style,
|
|
|
|
col_style: Some(col.style()),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
styles
|
|
|
|
}
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Flow for TableFlow {
|
|
|
|
fn class(&self) -> FlowClass {
|
2014-12-18 04:45:49 +03:00
|
|
|
FlowClass::Table
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
|
2015-09-04 16:59:04 +03:00
|
|
|
fn as_mut_table(&mut self) -> &mut TableFlow {
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2015-09-04 16:59:04 +03:00
|
|
|
fn as_table(&self) -> &TableFlow {
|
2014-09-20 06:50:47 +04:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2015-09-04 16:59:04 +03:00
|
|
|
fn as_mut_block(&mut self) -> &mut BlockFlow {
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
&mut self.block_flow
|
|
|
|
}
|
|
|
|
|
2015-08-18 16:31:57 +03:00
|
|
|
fn as_block(&self) -> &BlockFlow {
|
2015-04-27 20:29:15 +03:00
|
|
|
&self.block_flow
|
|
|
|
}
|
|
|
|
|
2015-07-31 11:10:40 +03:00
|
|
|
fn mark_as_root(&mut self) {
|
|
|
|
self.block_flow.mark_as_root();
|
|
|
|
}
|
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
/// The specified column inline-sizes are set from column group and the first row for the fixed
|
2014-04-04 05:01:48 +04:00
|
|
|
/// table layout calculation.
|
2014-07-19 00:27:23 +04:00
|
|
|
/// The maximum min/pref inline-sizes of each column are set from the rows for the automatic
|
2014-04-04 05:01:48 +04:00
|
|
|
/// table layout calculation.
|
2014-10-15 00:06:36 +04:00
|
|
|
fn bubble_inline_sizes(&mut self) {
|
2014-10-17 22:15:23 +04:00
|
|
|
let _scope = layout_debug_scope!("table::bubble_inline_sizes {:x}",
|
2014-10-15 00:06:36 +04:00
|
|
|
self.block_flow.base.debug_id());
|
2014-09-20 06:50:47 +04:00
|
|
|
|
2016-03-02 01:08:12 +03:00
|
|
|
// Get column inline sizes from colgroups
|
2016-04-09 01:24:40 +03:00
|
|
|
for kid in self.block_flow.base.child_iter_mut().filter(|kid| kid.is_table_colgroup()) {
|
2016-03-02 01:08:12 +03:00
|
|
|
for specified_inline_size in &kid.as_mut_table_colgroup().inline_sizes {
|
|
|
|
self.column_intrinsic_inline_sizes.push(ColumnIntrinsicInlineSize {
|
|
|
|
minimum_length: match *specified_inline_size {
|
|
|
|
LengthOrPercentageOrAuto::Auto |
|
|
|
|
LengthOrPercentageOrAuto::Calc(_) |
|
|
|
|
LengthOrPercentageOrAuto::Percentage(_) => Au(0),
|
2017-09-13 13:20:20 +03:00
|
|
|
LengthOrPercentageOrAuto::Length(length) => Au::from(length),
|
2016-03-02 01:08:12 +03:00
|
|
|
},
|
|
|
|
percentage: match *specified_inline_size {
|
|
|
|
LengthOrPercentageOrAuto::Auto |
|
|
|
|
LengthOrPercentageOrAuto::Calc(_) |
|
|
|
|
LengthOrPercentageOrAuto::Length(_) => 0.0,
|
2017-06-15 23:37:04 +03:00
|
|
|
LengthOrPercentageOrAuto::Percentage(percentage) => percentage.0,
|
2016-03-02 01:08:12 +03:00
|
|
|
},
|
|
|
|
preferred: Au(0),
|
|
|
|
constrained: false,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-27 20:29:15 +03:00
|
|
|
self.collapsed_inline_direction_border_widths_for_table = Vec::new();
|
|
|
|
self.collapsed_block_direction_border_widths_for_table = vec![Au(0)];
|
|
|
|
|
|
|
|
let collapsing_borders = self.block_flow
|
|
|
|
.fragment
|
|
|
|
.style
|
|
|
|
.get_inheritedtable()
|
2017-12-06 04:35:25 +03:00
|
|
|
.border_collapse == border_collapse::T::Collapse;
|
2015-04-27 20:29:15 +03:00
|
|
|
let table_inline_collapsed_borders = if collapsing_borders {
|
|
|
|
Some(TableInlineCollapsedBorders {
|
|
|
|
start: CollapsedBorder::inline_start(&*self.block_flow.fragment.style,
|
|
|
|
CollapsedBorderProvenance::FromTable),
|
|
|
|
end: CollapsedBorder::inline_end(&*self.block_flow.fragment.style,
|
|
|
|
CollapsedBorderProvenance::FromTable),
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2014-10-15 01:42:32 +04:00
|
|
|
let mut computation = IntrinsicISizesContribution::new();
|
2016-03-02 01:08:12 +03:00
|
|
|
let mut previous_collapsed_block_end_borders =
|
2015-04-27 20:29:15 +03:00
|
|
|
PreviousBlockCollapsedBorders::FromTable(CollapsedBorder::block_start(
|
|
|
|
&*self.block_flow.fragment.style,
|
2016-03-02 01:08:12 +03:00
|
|
|
CollapsedBorderProvenance::FromTable));
|
2015-04-27 20:29:15 +03:00
|
|
|
let mut first_row = true;
|
2016-10-27 04:14:04 +03:00
|
|
|
let (border_padding, _) = self.block_flow.fragment.surrounding_intrinsic_inline_size();
|
2015-04-27 20:29:15 +03:00
|
|
|
|
|
|
|
{
|
2016-03-02 01:08:12 +03:00
|
|
|
let mut iterator = TableRowIterator::new(&mut self.block_flow.base).peekable();
|
|
|
|
while let Some(row) = iterator.next() {
|
2016-10-27 04:14:04 +03:00
|
|
|
TableFlow::update_column_inline_sizes_for_row(
|
|
|
|
row,
|
2016-03-02 01:08:12 +03:00
|
|
|
&mut self.column_intrinsic_inline_sizes,
|
|
|
|
&mut computation,
|
|
|
|
first_row,
|
2016-10-27 04:14:04 +03:00
|
|
|
self.table_layout,
|
|
|
|
border_padding);
|
2016-03-02 01:08:12 +03:00
|
|
|
if collapsing_borders {
|
|
|
|
let next_index_and_sibling = iterator.peek();
|
|
|
|
let next_collapsed_borders_in_block_direction =
|
|
|
|
match next_index_and_sibling {
|
|
|
|
Some(next_sibling) => {
|
|
|
|
NextBlockCollapsedBorders::FromNextRow(
|
|
|
|
&next_sibling.as_table_row()
|
|
|
|
.preliminary_collapsed_borders
|
|
|
|
.block_start)
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
NextBlockCollapsedBorders::FromTable(
|
|
|
|
CollapsedBorder::block_end(&*self.block_flow.fragment.style,
|
|
|
|
CollapsedBorderProvenance::FromTable))
|
2015-04-27 20:29:15 +03:00
|
|
|
}
|
|
|
|
};
|
2016-03-02 01:08:12 +03:00
|
|
|
perform_border_collapse_for_row(row,
|
|
|
|
table_inline_collapsed_borders.as_ref().unwrap(),
|
|
|
|
previous_collapsed_block_end_borders,
|
|
|
|
next_collapsed_borders_in_block_direction,
|
|
|
|
&mut self.collapsed_inline_direction_border_widths_for_table,
|
|
|
|
&mut self.collapsed_block_direction_border_widths_for_table);
|
|
|
|
previous_collapsed_block_end_borders =
|
|
|
|
PreviousBlockCollapsedBorders::FromPreviousRow(
|
2016-08-31 19:28:18 +03:00
|
|
|
row.final_collapsed_borders.block_end.clone());
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
2016-03-02 01:08:12 +03:00
|
|
|
first_row = false
|
2016-08-31 19:28:18 +03:00
|
|
|
};
|
2014-04-04 05:01:48 +04:00
|
|
|
}
|
2014-09-19 11:50:50 +04:00
|
|
|
|
2016-10-27 04:14:04 +03:00
|
|
|
let total_horizontal_spacing = self.total_horizontal_spacing();
|
|
|
|
let mut style_specified_intrinsic_inline_size =
|
|
|
|
self.block_flow
|
|
|
|
.fragment
|
|
|
|
.style_specified_intrinsic_inline_size()
|
|
|
|
.finish();
|
|
|
|
style_specified_intrinsic_inline_size.minimum_inline_size -= total_horizontal_spacing;
|
|
|
|
style_specified_intrinsic_inline_size.preferred_inline_size -= total_horizontal_spacing;
|
|
|
|
computation.union_block(&style_specified_intrinsic_inline_size);
|
|
|
|
computation.surrounding_size += total_horizontal_spacing;
|
2015-03-12 22:03:49 +03:00
|
|
|
|
2014-10-15 01:42:32 +04:00
|
|
|
self.block_flow.base.intrinsic_inline_sizes = computation.finish()
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
|
2014-10-15 01:42:32 +04:00
|
|
|
/// 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.
|
2017-02-08 04:16:05 +03:00
|
|
|
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
|
2014-10-17 22:15:23 +04:00
|
|
|
let _scope = layout_debug_scope!("table::assign_inline_sizes {:x}",
|
2014-09-20 06:50:47 +04:00
|
|
|
self.block_flow.base.debug_id());
|
2014-07-19 00:27:23 +04:00
|
|
|
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table");
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
|
2017-02-08 04:16:05 +03:00
|
|
|
let shared_context = layout_context.shared_context();
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
// The position was set to the containing block by the flow's parent.
|
2017-04-28 20:56:06 +03:00
|
|
|
// FIXME: The code for distributing column widths should really be placed under table_wrapper.rs.
|
2014-10-14 04:03:40 +04:00
|
|
|
let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
|
2017-04-28 20:56:06 +03:00
|
|
|
let mut constrained_column_inline_sizes_indices = vec![];
|
|
|
|
let mut unspecified_inline_sizes_indices = vec![];
|
|
|
|
for (idx, column_inline_size) in self.column_intrinsic_inline_sizes.iter().enumerate() {
|
|
|
|
if column_inline_size.constrained {
|
|
|
|
constrained_column_inline_sizes_indices.push(idx);
|
|
|
|
} else if column_inline_size.percentage == 0.0 {
|
|
|
|
unspecified_inline_sizes_indices.push(idx);
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-09 01:02:09 +03:00
|
|
|
let inline_size_computer = InternalTable;
|
2014-10-15 01:42:32 +04:00
|
|
|
inline_size_computer.compute_used_inline_size(&mut self.block_flow,
|
2016-06-23 11:03:02 +03:00
|
|
|
shared_context,
|
2015-04-28 19:44:39 +03:00
|
|
|
containing_block_inline_size);
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
let inline_start_content_edge = self.block_flow.fragment.border_padding.inline_start;
|
2015-03-17 21:33:53 +03:00
|
|
|
let inline_end_content_edge = self.block_flow.fragment.border_padding.inline_end;
|
2014-07-19 00:27:23 +04:00
|
|
|
let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
|
2015-03-12 22:03:49 +03:00
|
|
|
let spacing_per_cell = self.spacing();
|
2016-10-27 04:14:04 +03:00
|
|
|
let total_horizontal_spacing = self.total_horizontal_spacing();
|
|
|
|
let content_inline_size = self.block_flow.fragment.border_box.size.inline -
|
|
|
|
padding_and_borders - total_horizontal_spacing;
|
2017-04-28 20:56:06 +03:00
|
|
|
let mut remaining_inline_size = content_inline_size;
|
2014-10-20 22:54:34 +04:00
|
|
|
|
2014-04-04 05:01:48 +04:00
|
|
|
match self.table_layout {
|
2014-12-18 04:45:49 +03:00
|
|
|
TableLayout::Fixed => {
|
2014-12-12 04:06:53 +03:00
|
|
|
self.column_computed_inline_sizes.clear();
|
2017-04-28 20:56:06 +03:00
|
|
|
|
|
|
|
// https://drafts.csswg.org/css2/tables.html#fixed-table-layout
|
|
|
|
for column_inline_size in &self.column_intrinsic_inline_sizes {
|
|
|
|
if column_inline_size.constrained {
|
2016-09-09 07:17:06 +03:00
|
|
|
self.column_computed_inline_sizes.push(ColumnComputedInlineSize {
|
2017-04-28 20:56:06 +03:00
|
|
|
size: column_inline_size.minimum_length,
|
2016-09-09 07:17:06 +03:00
|
|
|
});
|
2017-04-28 20:56:06 +03:00
|
|
|
remaining_inline_size -= column_inline_size.minimum_length;
|
|
|
|
} else if column_inline_size.percentage != 0.0 {
|
|
|
|
let size = remaining_inline_size.scale_by(column_inline_size.percentage);
|
|
|
|
self.column_computed_inline_sizes.push(ColumnComputedInlineSize {
|
|
|
|
size: size,
|
|
|
|
});
|
|
|
|
remaining_inline_size -= size;
|
|
|
|
} else {
|
|
|
|
// Set the size to 0 now, distribute the remaining widths later
|
2016-09-09 07:17:06 +03:00
|
|
|
self.column_computed_inline_sizes.push(ColumnComputedInlineSize {
|
2017-04-28 20:56:06 +03:00
|
|
|
size: Au(0),
|
2016-09-09 07:17:06 +03:00
|
|
|
});
|
|
|
|
}
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
2017-04-28 20:56:06 +03:00
|
|
|
|
|
|
|
// Distribute remaining content inline size
|
|
|
|
if unspecified_inline_sizes_indices.len() > 0 {
|
|
|
|
for &index in &unspecified_inline_sizes_indices {
|
|
|
|
self.column_computed_inline_sizes[index].size =
|
|
|
|
remaining_inline_size.scale_by(1.0 / unspecified_inline_sizes_indices.len() as f32);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let total_minimum_size = self.column_intrinsic_inline_sizes
|
|
|
|
.iter()
|
|
|
|
.filter(|size| size.constrained)
|
|
|
|
.map(|size| size.minimum_length.0 as f32)
|
|
|
|
.sum::<f32>();
|
|
|
|
|
|
|
|
for &index in &constrained_column_inline_sizes_indices {
|
|
|
|
self.column_computed_inline_sizes[index].size +=
|
|
|
|
remaining_inline_size.scale_by(
|
|
|
|
self.column_computed_inline_sizes[index].size.0 as f32 / total_minimum_size);
|
|
|
|
}
|
|
|
|
}
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
2014-12-12 04:06:53 +03:00
|
|
|
_ => {
|
|
|
|
// The table wrapper already computed the inline-sizes and propagated them down
|
|
|
|
// to us.
|
|
|
|
}
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
|
2015-04-27 20:29:15 +03:00
|
|
|
let column_computed_inline_sizes = &self.column_computed_inline_sizes;
|
|
|
|
let collapsed_inline_direction_border_widths_for_table =
|
|
|
|
&self.collapsed_inline_direction_border_widths_for_table;
|
|
|
|
let mut collapsed_block_direction_border_widths_for_table =
|
|
|
|
self.collapsed_block_direction_border_widths_for_table.iter().peekable();
|
2016-12-26 21:09:09 +03:00
|
|
|
let mut incoming_rowspan = vec![];
|
2016-06-23 11:03:02 +03:00
|
|
|
self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
|
2015-03-12 22:03:49 +03:00
|
|
|
inline_start_content_edge,
|
2015-03-17 21:33:53 +03:00
|
|
|
inline_end_content_edge,
|
2015-03-12 22:03:49 +03:00
|
|
|
content_inline_size,
|
2015-04-27 20:29:15 +03:00
|
|
|
|child_flow,
|
2015-05-11 15:50:09 +03:00
|
|
|
_child_index,
|
|
|
|
_content_inline_size,
|
2015-04-27 20:29:15 +03:00
|
|
|
writing_mode,
|
2015-05-11 15:50:09 +03:00
|
|
|
_inline_start_margin_edge,
|
|
|
|
_inline_end_margin_edge| {
|
2015-04-27 20:29:15 +03:00
|
|
|
table_row::propagate_column_inline_sizes_to_child(
|
|
|
|
child_flow,
|
|
|
|
writing_mode,
|
|
|
|
column_computed_inline_sizes,
|
2016-12-26 21:09:09 +03:00
|
|
|
&spacing_per_cell,
|
|
|
|
&mut incoming_rowspan);
|
2015-04-27 20:29:15 +03:00
|
|
|
if child_flow.is_table_row() {
|
2015-08-18 16:31:57 +03:00
|
|
|
let child_table_row = child_flow.as_mut_table_row();
|
2015-04-27 20:29:15 +03:00
|
|
|
child_table_row.populate_collapsed_border_spacing(
|
|
|
|
collapsed_inline_direction_border_widths_for_table,
|
|
|
|
&mut collapsed_block_direction_border_widths_for_table);
|
|
|
|
} else if child_flow.is_table_rowgroup() {
|
2015-08-18 16:31:57 +03:00
|
|
|
let child_table_rowgroup = child_flow.as_mut_table_rowgroup();
|
2015-04-27 20:29:15 +03:00
|
|
|
child_table_rowgroup.populate_collapsed_border_spacing(
|
|
|
|
collapsed_inline_direction_border_widths_for_table,
|
|
|
|
&mut collapsed_block_direction_border_widths_for_table);
|
|
|
|
}
|
2016-08-31 19:28:18 +03:00
|
|
|
});
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
|
2018-03-01 02:40:39 +03:00
|
|
|
fn assign_block_size(&mut self, lc: &LayoutContext) {
|
2014-07-19 00:27:23 +04:00
|
|
|
debug!("assign_block_size: assigning block_size for table");
|
2017-09-17 23:12:46 +03:00
|
|
|
let vertical_spacing = self.spacing().vertical();
|
2018-03-01 02:40:39 +03:00
|
|
|
self.block_flow.assign_block_size_for_table_like_flow(vertical_spacing, lc)
|
2014-05-03 03:10:20 +04:00
|
|
|
}
|
|
|
|
|
2017-08-08 22:04:23 +03:00
|
|
|
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
|
|
|
|
self.block_flow.compute_stacking_relative_position(layout_context)
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
2014-09-15 20:29:39 +04:00
|
|
|
|
2015-05-13 22:27:21 +03:00
|
|
|
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
|
|
|
self.block_flow.generated_containing_block_size(flow)
|
2014-09-15 20:29:39 +04:00
|
|
|
}
|
2014-10-02 05:36:25 +04:00
|
|
|
|
|
|
|
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
|
|
|
|
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
|
|
|
|
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
|
|
|
|
}
|
2014-10-22 20:54:35 +04:00
|
|
|
|
2016-03-02 03:51:08 +03:00
|
|
|
fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
|
2015-04-27 20:29:15 +03:00
|
|
|
let border_painting_mode = match self.block_flow
|
|
|
|
.fragment
|
|
|
|
.style
|
|
|
|
.get_inheritedtable()
|
|
|
|
.border_collapse {
|
2017-12-06 04:35:25 +03:00
|
|
|
border_collapse::T::Separate => BorderPaintingMode::Separate,
|
|
|
|
border_collapse::T::Collapse => BorderPaintingMode::Hidden,
|
2015-04-27 20:29:15 +03:00
|
|
|
};
|
|
|
|
|
2016-03-02 03:51:08 +03:00
|
|
|
self.block_flow.build_display_list_for_block(state, border_painting_mode);
|
2018-02-21 20:00:03 +03:00
|
|
|
|
|
|
|
let iter = TableCellStyleIterator::new(&self);
|
|
|
|
for mut style in iter {
|
|
|
|
style.build_display_list(state)
|
|
|
|
}
|
2016-03-02 03:51:08 +03:00
|
|
|
}
|
|
|
|
|
2017-09-15 22:43:40 +03:00
|
|
|
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
|
2017-10-19 05:34:23 +03:00
|
|
|
// Stacking contexts are collected by the table wrapper.
|
2017-10-31 02:25:45 +03:00
|
|
|
self.block_flow.collect_stacking_contexts_for_block(state,
|
|
|
|
StackingContextCollectionFlags::NEVER_CREATES_STACKING_CONTEXT);
|
2014-10-22 20:54:35 +04:00
|
|
|
}
|
2014-10-31 23:39:34 +03:00
|
|
|
|
2017-07-19 16:03:17 +03:00
|
|
|
fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
|
2014-10-31 23:39:34 +03:00
|
|
|
self.block_flow.repair_style(new_style)
|
|
|
|
}
|
2014-11-03 22:03:37 +03:00
|
|
|
|
2016-02-05 08:28:50 +03:00
|
|
|
fn compute_overflow(&self) -> Overflow {
|
2015-01-05 04:51:48 +03:00
|
|
|
self.block_flow.compute_overflow()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn iterate_through_fragment_border_boxes(&self,
|
|
|
|
iterator: &mut FragmentBorderBoxIterator,
|
2015-08-04 03:39:43 +03:00
|
|
|
level: i32,
|
2015-01-05 04:51:48 +03:00
|
|
|
stacking_context_position: &Point2D<Au>) {
|
2015-08-04 03:39:43 +03:00
|
|
|
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
|
2014-11-03 22:03:37 +03:00
|
|
|
}
|
2015-03-10 08:24:47 +03:00
|
|
|
|
|
|
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
|
|
|
self.block_flow.mutate_fragments(mutator)
|
|
|
|
}
|
2015-11-24 05:19:07 +03:00
|
|
|
|
|
|
|
fn print_extra_flow_children(&self, print_tree: &mut PrintTree) {
|
|
|
|
self.block_flow.print_extra_flow_children(print_tree);
|
|
|
|
}
|
2014-05-07 07:37:35 +04:00
|
|
|
}
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
|
2018-02-21 20:00:03 +03:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct ColumnStyle<'table> {
|
|
|
|
span: u32,
|
|
|
|
colgroup_style: Option<&'table ComputedValues>,
|
|
|
|
col_style: Option<&'table ComputedValues>,
|
|
|
|
}
|
|
|
|
|
2015-02-12 03:24:45 +03:00
|
|
|
impl fmt::Debug for TableFlow {
|
2014-05-07 07:37:35 +04:00
|
|
|
/// Outputs a debugging string describing this table flow.
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2015-01-28 04:15:50 +03:00
|
|
|
write!(f, "TableFlow: {:?}", self.block_flow)
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Table, TableRowGroup, TableRow, TableCell types.
|
2014-07-19 00:27:23 +04:00
|
|
|
/// Their inline-sizes are calculated in the same way and do not have margins.
|
2017-12-09 01:02:09 +03:00
|
|
|
pub struct InternalTable;
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
impl ISizeAndMarginsComputer for InternalTable {
|
|
|
|
/// Compute the used value of inline-size, taking care of min-inline-size and max-inline-size.
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
///
|
2014-07-19 00:27:23 +04:00
|
|
|
/// CSS Section 10.4: Minimum and Maximum inline-sizes
|
2017-12-09 01:02:09 +03:00
|
|
|
fn compute_used_inline_size(
|
|
|
|
&self,
|
|
|
|
block: &mut BlockFlow,
|
|
|
|
shared_context: &SharedStyleContext,
|
|
|
|
parent_flow_inline_size: Au
|
|
|
|
) {
|
2015-08-19 12:20:37 +03:00
|
|
|
let mut input = self.compute_inline_size_constraint_inputs(block,
|
|
|
|
parent_flow_inline_size,
|
2016-06-23 11:03:02 +03:00
|
|
|
shared_context);
|
2015-08-19 12:20:37 +03:00
|
|
|
|
|
|
|
// Tables are always at least as wide as their minimum inline size.
|
|
|
|
let minimum_inline_size =
|
|
|
|
block.base.intrinsic_inline_sizes.minimum_inline_size -
|
|
|
|
block.fragment.border_padding.inline_start_end();
|
|
|
|
input.available_inline_size = cmp::max(input.available_inline_size, minimum_inline_size);
|
2014-10-20 22:54:34 +04:00
|
|
|
|
2015-08-19 12:20:37 +03:00
|
|
|
let solution = self.solve_inline_size_constraints(block, &input);
|
2014-07-19 00:27:23 +04:00
|
|
|
self.set_inline_size_constraint_solutions(block, solution);
|
servo: Merge #1973 - Support fixed-layout table and a part of anonymous table object (from june0cho:table_rebase); r=larsbergstrom,metajack
This is a rebase of #1548 on recent master.
There have been many changes since #1548 is first uploaded, so I'm creating new PR.
This PR includes:
- construction of table-* flows (table-wrapper, table-caption, table, table-rowgroup, table-row, table-cell)
- fixed-layout table calculation
- a part of anonymous table object implementation
[CSS 2.1, 17.2.1](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) (Step 1-1, 1-2, Step 2)
Source-Repo: https://github.com/servo/servo
Source-Revision: fd5e5cd18b41f0ce2b33fb97fb4e3d75ddbbbceb
2014-03-25 21:40:47 +04:00
|
|
|
}
|
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
/// Solve the inline-size and margins constraints for this block flow.
|
|
|
|
fn solve_inline_size_constraints(&self, _: &mut BlockFlow, input: &ISizeConstraintInput)
|
2015-04-28 19:44:39 +03:00
|
|
|
-> ISizeConstraintSolution {
|
2014-10-15 01:42:32 +04:00
|
|
|
ISizeConstraintSolution::new(input.available_inline_size, Au(0), Au(0))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-27 20:29:15 +03:00
|
|
|
/// Information about the intrinsic inline sizes of columns within a table.
|
|
|
|
///
|
|
|
|
/// During table inline-size bubbling, we might need to store both a percentage constraint and a
|
|
|
|
/// specific width constraint. For instance, one cell might say that it wants to be 100 pixels wide
|
|
|
|
/// in the inline direction and another cell might say that it wants to take up 20% of the inline-
|
|
|
|
/// size of the table. Now because we bubble up these constraints during the bubble-inline-sizes
|
|
|
|
/// phase of layout, we don't know yet how wide the table is ultimately going to be in the inline
|
|
|
|
/// direction. As we need to pick the maximum width of all cells for a column (in this case, the
|
|
|
|
/// maximum of 100 pixels and 20% of the table), the preceding constraint means that we must
|
|
|
|
/// potentially store both a specified width *and* a specified percentage, so that the inline-size
|
|
|
|
/// assignment phase of layout will know which one to pick.
|
2017-08-24 01:18:31 +03:00
|
|
|
#[derive(Clone, Copy, Debug, Serialize)]
|
2015-04-27 20:29:15 +03:00
|
|
|
pub struct ColumnIntrinsicInlineSize {
|
|
|
|
/// The preferred intrinsic inline size.
|
|
|
|
pub preferred: Au,
|
|
|
|
/// The largest specified size of this column as a length.
|
|
|
|
pub minimum_length: Au,
|
|
|
|
/// The largest specified size of this column as a percentage (`width` property).
|
|
|
|
pub percentage: CSSFloat,
|
|
|
|
/// Whether the column inline size is *constrained* per INTRINSIC § 4.1.
|
|
|
|
pub constrained: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ColumnIntrinsicInlineSize {
|
|
|
|
/// Returns a newly-initialized `ColumnIntrinsicInlineSize` with all fields blank.
|
|
|
|
pub fn new() -> ColumnIntrinsicInlineSize {
|
|
|
|
ColumnIntrinsicInlineSize {
|
|
|
|
preferred: Au(0),
|
|
|
|
minimum_length: Au(0),
|
|
|
|
percentage: 0.0,
|
|
|
|
constrained: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the higher of the two percentages specified in `self` and `other`.
|
|
|
|
pub fn greatest_percentage(&self, other: &ColumnIntrinsicInlineSize) -> CSSFloat {
|
|
|
|
if self.percentage > other.percentage {
|
|
|
|
self.percentage
|
|
|
|
} else {
|
|
|
|
other.percentage
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The actual inline size for each column.
|
|
|
|
///
|
|
|
|
/// TODO(pcwalton): There will probably be some `border-collapse`-related info in here too
|
|
|
|
/// eventually.
|
2017-08-24 01:18:31 +03:00
|
|
|
#[derive(Clone, Copy, Debug, Serialize)]
|
2015-04-27 20:29:15 +03:00
|
|
|
pub struct ColumnComputedInlineSize {
|
|
|
|
/// The computed size of this inline column.
|
|
|
|
pub size: Au,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait VecExt<T> {
|
2016-03-02 01:08:12 +03:00
|
|
|
fn push_or_set(&mut self, index: usize, value: T) -> &mut T;
|
|
|
|
fn get_mut_or_push(&mut self, index: usize, zero: T) -> &mut T;
|
2015-04-27 20:29:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> VecExt<T> for Vec<T> {
|
2016-03-02 01:08:12 +03:00
|
|
|
fn push_or_set(&mut self, index: usize, value: T) -> &mut T {
|
2015-04-27 20:29:15 +03:00
|
|
|
if index < self.len() {
|
|
|
|
self[index] = value
|
|
|
|
} else {
|
2018-02-07 14:20:36 +03:00
|
|
|
debug_assert_eq!(index, self.len());
|
2015-04-27 20:29:15 +03:00
|
|
|
self.push(value)
|
|
|
|
}
|
2016-03-02 01:08:12 +03:00
|
|
|
&mut self[index]
|
2015-04-27 20:29:15 +03:00
|
|
|
}
|
|
|
|
|
2016-03-02 01:08:12 +03:00
|
|
|
fn get_mut_or_push(&mut self, index: usize, zero: T) -> &mut T {
|
2015-04-27 20:29:15 +03:00
|
|
|
if index >= self.len() {
|
2018-02-07 14:20:36 +03:00
|
|
|
debug_assert_eq!(index, self.len());
|
2015-04-27 20:29:15 +03:00
|
|
|
self.push(zero)
|
|
|
|
}
|
|
|
|
&mut self[index]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Updates the border styles in the block direction for a single row. This function should
|
|
|
|
/// only be called if border collapsing is on. It is factored out into a separate function
|
|
|
|
/// because we process children of rowgroups too.
|
|
|
|
fn perform_border_collapse_for_row(child_table_row: &mut TableRowFlow,
|
|
|
|
table_inline_borders: &TableInlineCollapsedBorders,
|
|
|
|
previous_block_borders: PreviousBlockCollapsedBorders,
|
|
|
|
next_block_borders: NextBlockCollapsedBorders,
|
|
|
|
inline_spacing: &mut Vec<Au>,
|
|
|
|
block_spacing: &mut Vec<Au>) {
|
2016-12-26 21:09:09 +03:00
|
|
|
// TODO mbrubeck: Take rowspan and colspan into account.
|
2016-08-31 19:28:18 +03:00
|
|
|
let number_of_borders_inline_direction = child_table_row.preliminary_collapsed_borders.inline.len();
|
2015-04-27 20:29:15 +03:00
|
|
|
// Compute interior inline borders.
|
|
|
|
for (i, this_inline_border) in child_table_row.preliminary_collapsed_borders
|
|
|
|
.inline
|
2016-08-31 19:28:18 +03:00
|
|
|
.iter_mut()
|
2015-04-27 20:29:15 +03:00
|
|
|
.enumerate() {
|
|
|
|
child_table_row.final_collapsed_borders.inline.push_or_set(i, *this_inline_border);
|
2016-08-31 19:28:18 +03:00
|
|
|
if i == 0 {
|
|
|
|
child_table_row.final_collapsed_borders.inline[i].combine(&table_inline_borders.start);
|
|
|
|
} else if i + 1 == number_of_borders_inline_direction {
|
|
|
|
child_table_row.final_collapsed_borders.inline[i].combine(&table_inline_borders.end);
|
|
|
|
}
|
2015-04-27 20:29:15 +03:00
|
|
|
|
2016-03-02 01:08:12 +03:00
|
|
|
let inline_spacing = inline_spacing.get_mut_or_push(i, Au(0));
|
2016-08-31 19:28:18 +03:00
|
|
|
*inline_spacing = cmp::max(*inline_spacing, child_table_row.final_collapsed_borders.inline[i].width)
|
2015-04-27 20:29:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compute block-start borders.
|
2017-01-25 07:06:18 +03:00
|
|
|
let block_start_borders = &mut child_table_row.final_collapsed_borders.block_start;
|
|
|
|
*block_start_borders = child_table_row.preliminary_collapsed_borders.block_start.clone();
|
|
|
|
for (i, this_border) in block_start_borders.iter_mut().enumerate() {
|
|
|
|
match previous_block_borders {
|
|
|
|
PreviousBlockCollapsedBorders::FromPreviousRow(ref previous_block_borders) => {
|
|
|
|
if previous_block_borders.len() > i {
|
|
|
|
this_border.combine(&previous_block_borders[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PreviousBlockCollapsedBorders::FromTable(table_border) => {
|
|
|
|
this_border.combine(&table_border);
|
|
|
|
}
|
2015-04-27 20:29:15 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute block-end borders.
|
|
|
|
let next_block = &mut child_table_row.final_collapsed_borders.block_end;
|
|
|
|
block_spacing.push(Au(0));
|
|
|
|
let block_spacing = block_spacing.last_mut().unwrap();
|
|
|
|
for (i, this_block_border) in child_table_row.preliminary_collapsed_borders
|
|
|
|
.block_end
|
|
|
|
.iter()
|
|
|
|
.enumerate() {
|
2016-03-02 01:08:12 +03:00
|
|
|
let next_block = next_block.push_or_set(i, *this_block_border);
|
2015-04-27 20:29:15 +03:00
|
|
|
match next_block_borders {
|
|
|
|
NextBlockCollapsedBorders::FromNextRow(next_block_borders) => {
|
2015-04-28 23:32:31 +03:00
|
|
|
if next_block_borders.len() > i {
|
|
|
|
next_block.combine(&next_block_borders[i])
|
|
|
|
}
|
2015-04-27 20:29:15 +03:00
|
|
|
}
|
|
|
|
NextBlockCollapsedBorders::FromTable(ref next_block_borders) => {
|
|
|
|
next_block.combine(next_block_borders);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*block_spacing = cmp::max(*block_spacing, next_block.width)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-12 22:03:49 +03:00
|
|
|
/// Encapsulates functionality shared among all table-like flows: for now, tables and table
|
|
|
|
/// rowgroups.
|
|
|
|
pub trait TableLikeFlow {
|
|
|
|
/// Lays out the rows of a table.
|
2018-03-01 02:40:39 +03:00
|
|
|
fn assign_block_size_for_table_like_flow(&mut self, block_direction_spacing: Au,
|
|
|
|
layout_context: &LayoutContext);
|
2015-03-12 22:03:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TableLikeFlow for BlockFlow {
|
2018-03-01 02:40:39 +03:00
|
|
|
fn assign_block_size_for_table_like_flow(&mut self, block_direction_spacing: Au,
|
|
|
|
layout_context: &LayoutContext) {
|
2015-04-27 20:29:15 +03:00
|
|
|
debug_assert!(self.fragment.style.get_inheritedtable().border_collapse ==
|
2017-12-06 04:35:25 +03:00
|
|
|
border_collapse::T::Separate || block_direction_spacing == Au(0));
|
2015-04-27 20:29:15 +03:00
|
|
|
|
2018-03-01 02:40:39 +03:00
|
|
|
fn border_spacing_for_row(fragment: &Fragment, row: &TableRowFlow,
|
|
|
|
block_direction_spacing: Au) -> Au {
|
|
|
|
match fragment.style.get_inheritedtable().border_collapse {
|
|
|
|
border_collapse::T::Separate => block_direction_spacing,
|
|
|
|
border_collapse::T::Collapse => {
|
|
|
|
row.collapsed_border_spacing.block_start
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-31 02:25:45 +03:00
|
|
|
if self.base.restyle_damage.contains(ServoRestyleDamage::REFLOW) {
|
2018-03-01 21:36:43 +03:00
|
|
|
let mut sizes = vec![Default::default()];
|
2018-03-01 02:40:39 +03:00
|
|
|
// The amount of border spacing up to and including this row,
|
|
|
|
// but not including the spacing beneath it
|
2018-03-01 21:36:43 +03:00
|
|
|
let mut cumulative_border_spacing = Au(0);
|
2018-03-01 02:40:39 +03:00
|
|
|
let mut incoming_rowspan_data = vec![];
|
2018-03-01 21:36:43 +03:00
|
|
|
let mut rowgroup_id = 0;
|
|
|
|
let mut first = true;
|
2018-03-01 02:40:39 +03:00
|
|
|
|
|
|
|
// First pass: Compute block-direction border spacings
|
|
|
|
// XXXManishearth this can be done in tandem with the second pass,
|
|
|
|
// provided we never hit any rowspan cases
|
2018-03-01 21:36:43 +03:00
|
|
|
for kid in self.base.child_iter_mut() {
|
|
|
|
if kid.is_table_row() {
|
|
|
|
// skip the first row, it is accounted for
|
|
|
|
if first {
|
|
|
|
first = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
cumulative_border_spacing +=
|
|
|
|
border_spacing_for_row(&self.fragment, kid.as_table_row(),
|
|
|
|
block_direction_spacing);
|
|
|
|
sizes.push(TableRowSizeData {
|
|
|
|
// we haven't calculated sizes yet
|
|
|
|
size: Au(0),
|
|
|
|
cumulative_border_spacing,
|
|
|
|
rowgroup_id
|
|
|
|
});
|
|
|
|
} else if kid.is_table_rowgroup() && !first {
|
|
|
|
rowgroup_id += 1;
|
|
|
|
}
|
2018-03-01 02:40:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Second pass: Compute row block sizes
|
|
|
|
// [expensive: iterates over cells]
|
|
|
|
let mut i = 0;
|
|
|
|
for kid in self.base.child_iter_mut() {
|
|
|
|
if kid.is_table_row() {
|
2018-03-01 21:36:43 +03:00
|
|
|
let size = kid.as_mut_table_row()
|
2018-03-01 02:40:39 +03:00
|
|
|
.compute_block_size_table_row_base(layout_context,
|
|
|
|
&mut incoming_rowspan_data,
|
|
|
|
&sizes,
|
|
|
|
i);
|
2018-03-01 21:36:43 +03:00
|
|
|
sizes[i].size = size;
|
2018-03-01 02:40:39 +03:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-12 22:03:49 +03:00
|
|
|
// Our current border-box position.
|
|
|
|
let block_start_border_padding = self.fragment.border_padding.block_start;
|
|
|
|
let mut current_block_offset = block_start_border_padding;
|
2015-04-28 21:53:59 +03:00
|
|
|
let mut has_rows = false;
|
2015-03-12 22:03:49 +03:00
|
|
|
|
2018-03-01 02:40:39 +03:00
|
|
|
// Third pass: Assign block sizes and positions to rows, cells, and other children
|
|
|
|
// [expensive: iterates over cells]
|
2015-03-12 22:03:49 +03:00
|
|
|
// At this point, `current_block_offset` is at the content edge of our box. Now iterate
|
|
|
|
// over children.
|
2018-03-01 02:40:39 +03:00
|
|
|
let mut i = 0;
|
2016-04-09 01:24:40 +03:00
|
|
|
for kid in self.base.child_iter_mut() {
|
2015-03-12 22:03:49 +03:00
|
|
|
if kid.is_table_row() {
|
2015-04-28 21:53:59 +03:00
|
|
|
has_rows = true;
|
2018-03-01 02:40:39 +03:00
|
|
|
let row = kid.as_mut_table_row();
|
|
|
|
row.assign_block_size_to_self_and_children(&sizes, i);
|
|
|
|
row.mut_base().restyle_damage
|
|
|
|
.remove(ServoRestyleDamage::REFLOW_OUT_OF_FLOW |
|
|
|
|
ServoRestyleDamage::REFLOW);
|
2015-04-27 20:29:15 +03:00
|
|
|
current_block_offset = current_block_offset +
|
2018-03-01 02:40:39 +03:00
|
|
|
border_spacing_for_row(&self.fragment, row,
|
|
|
|
block_direction_spacing);
|
|
|
|
i += 1;
|
2015-03-12 22:03:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// At this point, `current_block_offset` is at the border edge of the child.
|
2017-12-15 21:44:50 +03:00
|
|
|
kid.mut_base().position.start.b = current_block_offset;
|
2015-03-12 22:03:49 +03:00
|
|
|
|
|
|
|
// Move past the child's border box. Do not use the `translate_including_floats`
|
|
|
|
// function here because the child has already translated floats past its border
|
|
|
|
// box.
|
2017-12-15 21:44:50 +03:00
|
|
|
let kid_base = kid.mut_base();
|
2015-03-12 22:03:49 +03:00
|
|
|
current_block_offset = current_block_offset + kid_base.position.size.block;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute any explicitly-specified block size.
|
2015-04-27 20:29:15 +03:00
|
|
|
// Can't use `for` because we assign to
|
|
|
|
// `candidate_block_size_iterator.candidate_value`.
|
2015-03-12 22:03:49 +03:00
|
|
|
let mut block_size = current_block_offset - block_start_border_padding;
|
|
|
|
let mut candidate_block_size_iterator = CandidateBSizeIterator::new(
|
|
|
|
&self.fragment,
|
|
|
|
self.base.block_container_explicit_block_size);
|
2015-10-12 13:37:42 +03:00
|
|
|
while let Some(candidate_block_size) = candidate_block_size_iterator.next() {
|
|
|
|
candidate_block_size_iterator.candidate_value =
|
|
|
|
match candidate_block_size {
|
|
|
|
MaybeAuto::Auto => block_size,
|
|
|
|
MaybeAuto::Specified(value) => value
|
|
|
|
};
|
2015-03-12 22:03:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust `current_block_offset` as necessary to account for the explicitly-specified
|
|
|
|
// block-size.
|
|
|
|
block_size = candidate_block_size_iterator.candidate_value;
|
|
|
|
let delta = block_size - (current_block_offset - block_start_border_padding);
|
|
|
|
current_block_offset = current_block_offset + delta;
|
|
|
|
|
|
|
|
// Take border, padding, and spacing into account.
|
|
|
|
let block_end_offset = self.fragment.border_padding.block_end +
|
2015-04-28 21:53:59 +03:00
|
|
|
if has_rows { block_direction_spacing } else { Au(0) };
|
2015-03-12 22:03:49 +03:00
|
|
|
current_block_offset = current_block_offset + block_end_offset;
|
|
|
|
|
|
|
|
// Now that `current_block_offset` is at the block-end of the border box, compute the
|
|
|
|
// final border box position.
|
|
|
|
self.fragment.border_box.size.block = current_block_offset;
|
|
|
|
self.fragment.border_box.start.b = Au(0);
|
|
|
|
self.base.position.size.block = current_block_offset;
|
2015-09-01 21:33:07 +03:00
|
|
|
|
2018-03-01 02:40:39 +03:00
|
|
|
// Fourth pass: Assign absolute position info
|
2015-09-01 21:33:07 +03:00
|
|
|
// Write in the size of the relative containing block for children. (This information
|
|
|
|
// is also needed to handle RTL.)
|
2016-04-09 01:24:40 +03:00
|
|
|
for kid in self.base.child_iter_mut() {
|
2017-12-15 21:44:50 +03:00
|
|
|
kid.mut_base().early_absolute_position_info = EarlyAbsolutePositionInfo {
|
2015-09-01 21:33:07 +03:00
|
|
|
relative_containing_block_size: self.fragment.content_box().size,
|
|
|
|
relative_containing_block_mode: self.fragment.style().writing_mode,
|
|
|
|
};
|
|
|
|
}
|
2015-03-12 22:03:49 +03:00
|
|
|
}
|
|
|
|
|
2017-10-31 02:25:45 +03:00
|
|
|
self.base.restyle_damage.remove(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW);
|
2015-03-12 22:03:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-27 20:29:15 +03:00
|
|
|
/// Inline collapsed borders for the table itself.
|
2016-08-31 19:28:18 +03:00
|
|
|
#[derive(Debug)]
|
2015-04-27 20:29:15 +03:00
|
|
|
struct TableInlineCollapsedBorders {
|
|
|
|
/// The table border at the start of the inline direction.
|
|
|
|
start: CollapsedBorder,
|
|
|
|
/// The table border at the end of the inline direction.
|
|
|
|
end: CollapsedBorder,
|
2014-12-12 04:06:53 +03:00
|
|
|
}
|
2015-03-12 22:03:49 +03:00
|
|
|
|
2015-04-27 20:29:15 +03:00
|
|
|
enum PreviousBlockCollapsedBorders {
|
|
|
|
FromPreviousRow(Vec<CollapsedBorder>),
|
|
|
|
FromTable(CollapsedBorder),
|
2015-03-12 22:03:49 +03:00
|
|
|
}
|
|
|
|
|
2015-04-27 20:29:15 +03:00
|
|
|
enum NextBlockCollapsedBorders<'a> {
|
|
|
|
FromNextRow(&'a [CollapsedBorder]),
|
|
|
|
FromTable(CollapsedBorder),
|
2016-03-02 01:08:12 +03:00
|
|
|
}
|
|
|
|
|
2018-02-21 20:00:03 +03:00
|
|
|
/// Iterator over all the rows of a table, which also
|
|
|
|
/// provides the Fragment for rowgroups if any
|
|
|
|
struct TableRowAndGroupIterator<'a> {
|
|
|
|
kids: FlowListIterator<'a>,
|
|
|
|
group: Option<(&'a Fragment, FlowListIterator<'a>)>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TableRowAndGroupIterator<'a> {
|
|
|
|
fn new(base: &'a BaseFlow) -> Self {
|
|
|
|
TableRowAndGroupIterator {
|
|
|
|
kids: base.child_iter(),
|
|
|
|
group: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for TableRowAndGroupIterator<'a> {
|
|
|
|
type Item = (Option<&'a Fragment>, &'a TableRowFlow);
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
// If we're inside a rowgroup, iterate through the rowgroup's children.
|
|
|
|
if let Some(ref mut group) = self.group {
|
|
|
|
if let Some(grandkid) = group.1.next() {
|
|
|
|
return Some((Some(group.0), grandkid.as_table_row()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Otherwise, iterate through the table's children.
|
|
|
|
self.group = None;
|
|
|
|
match self.kids.next() {
|
|
|
|
Some(kid) => {
|
|
|
|
if kid.is_table_rowgroup() {
|
|
|
|
let mut rowgroup = kid.as_table_rowgroup();
|
|
|
|
let iter = rowgroup.block_flow.base.child_iter();
|
|
|
|
self.group = Some((&rowgroup.block_flow.fragment, iter));
|
|
|
|
self.next()
|
|
|
|
} else if kid.is_table_row() {
|
|
|
|
Some((None, kid.as_table_row()))
|
|
|
|
} else {
|
|
|
|
self.next() // Skip children that are not rows or rowgroups
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Iterator over all the rows of a table, which also
|
|
|
|
/// provides the Fragment for rowgroups if any
|
|
|
|
struct MutTableRowAndGroupIterator<'a> {
|
2016-03-02 01:08:12 +03:00
|
|
|
kids: MutFlowListIterator<'a>,
|
2018-02-21 20:00:03 +03:00
|
|
|
group: Option<(&'a Fragment, MutFlowListIterator<'a>)>
|
2016-03-02 01:08:12 +03:00
|
|
|
}
|
|
|
|
|
2018-02-21 20:00:03 +03:00
|
|
|
impl<'a> MutTableRowAndGroupIterator<'a> {
|
2016-03-02 01:08:12 +03:00
|
|
|
fn new(base: &'a mut BaseFlow) -> Self {
|
2018-02-21 20:00:03 +03:00
|
|
|
MutTableRowAndGroupIterator {
|
2016-04-09 01:24:40 +03:00
|
|
|
kids: base.child_iter_mut(),
|
2018-02-21 20:00:03 +03:00
|
|
|
group: None,
|
2016-03-02 01:08:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-21 20:00:03 +03:00
|
|
|
impl<'a> Iterator for MutTableRowAndGroupIterator<'a> {
|
|
|
|
type Item = (Option<&'a Fragment>, &'a mut TableRowFlow);
|
2016-03-02 01:08:12 +03:00
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
// If we're inside a rowgroup, iterate through the rowgroup's children.
|
2018-02-21 20:00:03 +03:00
|
|
|
if let Some(ref mut group) = self.group {
|
|
|
|
if let Some(grandkid) = group.1.next() {
|
|
|
|
return Some((Some(group.0), grandkid.as_mut_table_row()))
|
2016-03-02 01:08:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Otherwise, iterate through the table's children.
|
2018-02-21 20:00:03 +03:00
|
|
|
self.group = None;
|
2016-03-02 01:08:12 +03:00
|
|
|
match self.kids.next() {
|
|
|
|
Some(kid) => {
|
|
|
|
if kid.is_table_rowgroup() {
|
2018-02-21 20:00:03 +03:00
|
|
|
let mut rowgroup = kid.as_mut_table_rowgroup();
|
|
|
|
let iter = rowgroup.block_flow.base.child_iter_mut();
|
|
|
|
self.group = Some((&rowgroup.block_flow.fragment, iter));
|
2016-03-02 01:08:12 +03:00
|
|
|
self.next()
|
|
|
|
} else if kid.is_table_row() {
|
2018-02-21 20:00:03 +03:00
|
|
|
Some((None, kid.as_mut_table_row()))
|
2016-03-02 01:08:12 +03:00
|
|
|
} else {
|
|
|
|
self.next() // Skip children that are not rows or rowgroups
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => None
|
|
|
|
}
|
|
|
|
}
|
2015-03-12 22:03:49 +03:00
|
|
|
}
|
2018-02-21 20:00:03 +03:00
|
|
|
|
|
|
|
/// Iterator over all the rows of a table
|
|
|
|
struct TableRowIterator<'a>(MutTableRowAndGroupIterator<'a>);
|
|
|
|
|
|
|
|
impl<'a> TableRowIterator<'a> {
|
|
|
|
fn new(base: &'a mut BaseFlow) -> Self {
|
|
|
|
TableRowIterator(MutTableRowAndGroupIterator::new(base))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for TableRowIterator<'a> {
|
|
|
|
type Item = &'a mut TableRowFlow;
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
self.0.next().map(|n| n.1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An iterator over table cells, yielding all relevant style objects
|
|
|
|
/// for each cell
|
|
|
|
///
|
|
|
|
/// Used for correctly handling table layers from
|
|
|
|
/// https://drafts.csswg.org/css2/tables.html#table-layers
|
|
|
|
struct TableCellStyleIterator<'table> {
|
|
|
|
column_styles: Vec<ColumnStyle<'table>>,
|
|
|
|
row_iterator: TableRowAndGroupIterator<'table>,
|
|
|
|
row_info: Option<TableCellStyleIteratorRowInfo<'table>>,
|
|
|
|
column_index: TableCellColumnIndexData,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
struct TableCellStyleIteratorRowInfo<'table> {
|
|
|
|
row: &'table TableRowFlow,
|
|
|
|
rowgroup: Option<&'table Fragment>,
|
|
|
|
cell_iterator: FlowListIterator<'table>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'table> TableCellStyleIterator<'table> {
|
|
|
|
fn new(table: &'table TableFlow) -> Self {
|
|
|
|
let column_styles = table.column_styles();
|
|
|
|
let mut row_iterator = TableRowAndGroupIterator::new(&table.block_flow.base);
|
|
|
|
let row_info = if let Some((group, row)) = row_iterator.next() {
|
|
|
|
Some(TableCellStyleIteratorRowInfo {
|
|
|
|
row: &row,
|
|
|
|
rowgroup: group,
|
|
|
|
cell_iterator: row.block_flow.base.child_iter()
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
TableCellStyleIterator {
|
|
|
|
column_styles, row_iterator, row_info,
|
|
|
|
column_index: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct TableCellStyleInfo<'table> {
|
|
|
|
cell: &'table TableCellFlow,
|
|
|
|
colgroup_style: Option<&'table ComputedValues>,
|
|
|
|
col_style: Option<&'table ComputedValues>,
|
|
|
|
rowgroup_style: Option<&'table ComputedValues>,
|
|
|
|
row_style: &'table ComputedValues,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct TableCellColumnIndexData {
|
|
|
|
/// Which column this is in the table
|
|
|
|
pub absolute: u32,
|
|
|
|
/// The index of the current column in column_styles
|
|
|
|
/// (i.e. which <col> element it is)
|
|
|
|
pub relative: u32,
|
|
|
|
/// In case of multispan <col>s, where we are in the
|
|
|
|
/// span of the current <col> element
|
|
|
|
pub relative_offset: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for TableCellColumnIndexData {
|
|
|
|
fn default() -> Self {
|
|
|
|
TableCellColumnIndexData {
|
|
|
|
absolute: 0,
|
|
|
|
relative: 0,
|
|
|
|
relative_offset: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TableCellColumnIndexData {
|
|
|
|
/// Moves forward by `amount` columns, updating the various indices used
|
|
|
|
///
|
|
|
|
/// This totally ignores rowspan -- if colspan and rowspan clash,
|
|
|
|
/// they just overlap, so we ignore it.
|
|
|
|
fn advance(&mut self, amount: u32, column_styles: &[ColumnStyle]) {
|
|
|
|
self.absolute += amount;
|
|
|
|
self.relative_offset += amount;
|
|
|
|
if let Some(mut current_col) =
|
|
|
|
column_styles.get(self.relative as usize) {
|
|
|
|
while self.relative_offset >= current_col.span {
|
|
|
|
// move to the next column
|
|
|
|
self.relative += 1;
|
|
|
|
self.relative_offset -= current_col.span;
|
|
|
|
if let Some(column_style) =
|
|
|
|
column_styles.get(self.relative as usize) {
|
|
|
|
current_col = column_style;
|
|
|
|
} else {
|
|
|
|
// we ran out of column_styles,
|
|
|
|
// so we don't need to update the indices
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'table> Iterator for TableCellStyleIterator<'table> {
|
|
|
|
type Item = TableCellStyleInfo<'table>;
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
// FIXME We do this awkward .take() followed by shoving it back in
|
|
|
|
// because without NLL the row_info borrow lasts too long
|
|
|
|
if let Some(mut row_info) = self.row_info.take() {
|
|
|
|
if let Some(rowspan) = row_info.row.incoming_rowspan.get(self.column_index.absolute as usize) {
|
|
|
|
// we are not allowed to use this column as a starting point. Try the next one.
|
|
|
|
if *rowspan > 1 {
|
|
|
|
self.column_index.advance(1, &self.column_styles);
|
|
|
|
// put row_info back in
|
|
|
|
self.row_info = Some(row_info);
|
|
|
|
// try again
|
|
|
|
return self.next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(cell) = row_info.cell_iterator.next() {
|
|
|
|
let rowgroup_style = row_info.rowgroup.map(|r| r.style());
|
|
|
|
let row_style = row_info.row.block_flow.fragment.style();
|
|
|
|
let cell = cell.as_table_cell();
|
|
|
|
let (col_style, colgroup_style) = if let Some(column_style) =
|
|
|
|
self.column_styles.get(self.column_index.relative as usize) {
|
|
|
|
let styles = (column_style.col_style.clone(), column_style.colgroup_style.clone());
|
|
|
|
self.column_index.advance(cell.column_span, &self.column_styles);
|
|
|
|
|
|
|
|
styles
|
|
|
|
} else {
|
|
|
|
(None, None)
|
|
|
|
};
|
|
|
|
// put row_info back in
|
|
|
|
self.row_info = Some(row_info);
|
|
|
|
return Some(TableCellStyleInfo {
|
|
|
|
cell,
|
|
|
|
colgroup_style,
|
|
|
|
col_style,
|
|
|
|
rowgroup_style,
|
|
|
|
row_style,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
// next row
|
|
|
|
if let Some((group, row)) = self.row_iterator.next() {
|
|
|
|
self.row_info = Some(TableCellStyleIteratorRowInfo {
|
|
|
|
row: &row,
|
|
|
|
rowgroup: group,
|
|
|
|
cell_iterator: row.block_flow.base.child_iter()
|
|
|
|
});
|
|
|
|
self.column_index = Default::default();
|
|
|
|
self.next()
|
|
|
|
} else {
|
|
|
|
// out of rows
|
|
|
|
// row_info stays None
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// empty table
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'table> TableCellStyleInfo<'table> {
|
|
|
|
fn build_display_list(&self, mut state: &mut DisplayListBuildState) {
|
|
|
|
use style::computed_values::visibility::T as Visibility;
|
|
|
|
|
|
|
|
if !self.cell.visible || self.cell.block_flow.fragment.style()
|
|
|
|
.get_inheritedbox().visibility != Visibility::Visible {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
let border_painting_mode = match self.cell.block_flow
|
|
|
|
.fragment
|
|
|
|
.style
|
|
|
|
.get_inheritedtable()
|
|
|
|
.border_collapse {
|
|
|
|
border_collapse::T::Separate => BorderPaintingMode::Separate,
|
|
|
|
border_collapse::T::Collapse => BorderPaintingMode::Collapse(&self.cell.collapsed_borders),
|
|
|
|
};
|
|
|
|
{
|
|
|
|
let cell_flow = &self.cell.block_flow;
|
|
|
|
let initial = ComputedValues::initial_values();
|
|
|
|
|
|
|
|
let build_dl = |sty: &ComputedValues, state: &mut &mut DisplayListBuildState| {
|
|
|
|
let background = sty.get_background();
|
|
|
|
// Don't redraw backgrounds that we've already drawn
|
|
|
|
if background as *const Background == initial.get_background() as *const _ {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let background_color = sty.resolve_color(background.background_color);
|
|
|
|
cell_flow.build_display_list_for_background_if_applicable_with_background(
|
|
|
|
state, background, background_color
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(ref sty) = self.colgroup_style {
|
|
|
|
build_dl(&sty, &mut state);
|
|
|
|
}
|
|
|
|
if let Some(ref sty) = self.col_style {
|
|
|
|
build_dl(&sty, &mut state);
|
|
|
|
}
|
|
|
|
if let Some(ref sty) = self.rowgroup_style {
|
|
|
|
build_dl(sty, &mut state);
|
|
|
|
}
|
|
|
|
build_dl(self.row_style, &mut state);
|
|
|
|
}
|
|
|
|
// the restyle damage will be set in TableCellFlow::build_display_list()
|
|
|
|
self.cell.block_flow.build_display_list_for_block_no_damage(state, border_painting_mode)
|
|
|
|
}
|
|
|
|
}
|