use std::cmp::{max, min};
use std::fmt;
use std::ops::Add;
use app_units::Au;
use base::print_tree::PrintTree;
use euclid::default::Point2D;
use log::{debug, trace};
use serde::Serialize;
use style::computed_values::{position, table_layout};
use style::context::SharedStyleContext;
use style::logical_geometry::{LogicalRect, LogicalSize};
use style::properties::ComputedValues;
use style::values::computed::Size;
use style::values::CSSFloat;
use crate::block::{
AbsoluteNonReplaced, BlockFlow, FloatNonReplaced, ISizeAndMarginsComputer,
ISizeConstraintInput, ISizeConstraintSolution, MarginsMayCollapseFlag,
};
use crate::context::LayoutContext;
use crate::display_list::{
DisplayListBuildState, StackingContextCollectionFlags, StackingContextCollectionState,
};
use crate::floats::FloatKind;
use crate::flow::{Flow, FlowClass, FlowFlags, ImmutableFlowUtils, OpaqueFlow};
use crate::fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use crate::model::MaybeAuto;
use crate::table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
#[derive(Clone, Copy, Debug, Serialize)]
pub enum TableLayout {
Fixed,
Auto,
}
#[allow(unsafe_code)]
unsafe impl crate::flow::HasBaseFlow for TableWrapperFlow {}
#[derive(Serialize)]
#[repr(C)]
pub struct TableWrapperFlow {
pub block_flow: BlockFlow,
pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>,
pub table_layout: TableLayout,
}
impl TableWrapperFlow {
pub fn from_fragment(fragment: Fragment) -> TableWrapperFlow {
TableWrapperFlow::from_fragment_and_float_kind(fragment, None)
}
pub fn from_fragment_and_float_kind(
fragment: Fragment,
float_kind: Option<FloatKind>,
) -> TableWrapperFlow {
let mut block_flow = BlockFlow::from_fragment_and_float_kind(fragment, float_kind);
let table_layout =
if block_flow.fragment().style().get_table().table_layout == table_layout::T::Fixed {
TableLayout::Fixed
} else {
TableLayout::Auto
};
TableWrapperFlow {
block_flow,
column_intrinsic_inline_sizes: vec![],
table_layout,
}
}
fn border_padding_and_spacing(&mut self) -> (Au, Au) {
let (mut table_border_padding, mut spacing) = (Au(0), Au(0));
for kid in self.block_flow.base.child_iter_mut() {
if kid.is_table() {
let kid_table = kid.as_table();
spacing = kid_table.total_horizontal_spacing();
table_border_padding = kid_table
.block_flow
.fragment
.border_padding
.inline_start_end();
break;
}
}
(table_border_padding, spacing)
}
fn compute_border_and_padding_of_table(&mut self) {
let available_inline_size = self.block_flow.base.block_container_inline_size;
for kid in self.block_flow.base.child_iter_mut() {
if !kid.is_table() {
continue;
}
let kid_table = kid.as_mut_table();
let kid_block_flow = &mut kid_table.block_flow;
kid_block_flow
.fragment
.compute_border_and_padding(available_inline_size);
kid_block_flow
.fragment
.compute_block_direction_margins(available_inline_size);
kid_block_flow
.fragment
.compute_inline_direction_margins(available_inline_size);
return;
}
}
fn calculate_table_column_sizes_for_automatic_layout(
&mut self,
intermediate_column_inline_sizes: &mut [IntermediateColumnInlineSize],
) {
let available_inline_size = self.available_inline_size();
let mut total_guess = AutoLayoutCandidateGuess::new();
let guesses: Vec<AutoLayoutCandidateGuess> = self
.column_intrinsic_inline_sizes
.iter()
.map(|column_intrinsic_inline_size| {
let guess = AutoLayoutCandidateGuess::from_column_intrinsic_inline_size(
column_intrinsic_inline_size,
available_inline_size,
);
total_guess = &total_guess + &guess;
guess
})
.collect();
let selection =
SelectedAutoLayoutCandidateGuess::select(&total_guess, available_inline_size);
let mut total_used_inline_size = Au(0);
for (intermediate_column_inline_size, guess) in intermediate_column_inline_sizes
.iter_mut()
.zip(guesses.iter())
{
intermediate_column_inline_size.size = guess.calculate(selection);
total_used_inline_size += intermediate_column_inline_size.size
}
let excess_inline_size = available_inline_size - total_used_inline_size;
if excess_inline_size > Au(0) &&
selection ==
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize
{
let mut info = ExcessInlineSizeDistributionInfo::new();
for column_intrinsic_inline_size in &self.column_intrinsic_inline_sizes {
info.update(column_intrinsic_inline_size)
}
let mut total_distributed_excess_size = Au(0);
for (intermediate_column_inline_size, column_intrinsic_inline_size) in
intermediate_column_inline_sizes
.iter_mut()
.zip(self.column_intrinsic_inline_sizes.iter())
{
info.distribute_excess_inline_size_to_column(
intermediate_column_inline_size,
column_intrinsic_inline_size,
excess_inline_size,
&mut total_distributed_excess_size,
)
}
total_used_inline_size = available_inline_size
}
self.set_inline_size(total_used_inline_size)
}
fn available_inline_size(&mut self) -> Au {
let available_inline_size = self.block_flow.fragment.border_box.size.inline;
let (table_border_padding, spacing) = self.border_padding_and_spacing();
let available_inline_size = match self.block_flow.fragment.style().content_inline_size() {
Size::Auto => {
self.block_flow
.get_shrink_to_fit_inline_size(available_inline_size) -
table_border_padding
},
_ => available_inline_size,
};
available_inline_size - spacing
}
fn set_inline_size(&mut self, total_used_inline_size: Au) {
let (table_border_padding, spacing) = self.border_padding_and_spacing();
self.block_flow.fragment.border_box.size.inline =
total_used_inline_size + table_border_padding + spacing;
self.block_flow.base.position.size.inline = total_used_inline_size +
table_border_padding +
spacing +
self.block_flow.fragment.margin.inline_start_end();
let writing_mode = self.block_flow.base.writing_mode;
let container_mode = self.block_flow.base.block_container_writing_mode;
if writing_mode.is_bidi_ltr() != container_mode.is_bidi_ltr() {
self.block_flow.fragment.border_box.start.i =
self.block_flow.base.block_container_inline_size -
self.block_flow.fragment.margin.inline_end -
self.block_flow.fragment.border_box.size.inline;
}
}
fn compute_used_inline_size(
&mut self,
shared_context: &SharedStyleContext,
parent_flow_inline_size: Au,
intermediate_column_inline_sizes: &[IntermediateColumnInlineSize],
) {
let (border_padding, spacing) = self.border_padding_and_spacing();
let minimum_width_of_all_columns = intermediate_column_inline_sizes.iter().fold(
border_padding + spacing,
|accumulator, intermediate_column_inline_sizes| {
accumulator + intermediate_column_inline_sizes.size
},
);
let preferred_width_of_all_columns = self.column_intrinsic_inline_sizes.iter().fold(
border_padding + spacing,
|accumulator, column_intrinsic_inline_sizes| {
accumulator + column_intrinsic_inline_sizes.preferred
},
);
if self.block_flow.base.flags.is_float() {
let inline_size_computer = FloatedTable {
minimum_width_of_all_columns,
preferred_width_of_all_columns,
table_border_padding: border_padding,
};
let input = inline_size_computer.compute_inline_size_constraint_inputs(
&mut self.block_flow,
parent_flow_inline_size,
shared_context,
);
let solution =
inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, &input);
inline_size_computer
.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
inline_size_computer
.set_inline_position_of_flow_if_necessary(&mut self.block_flow, solution);
return;
}
if !self
.block_flow
.base
.flags
.contains(FlowFlags::INLINE_POSITION_IS_STATIC)
{
let inline_size_computer = AbsoluteTable {
minimum_width_of_all_columns,
preferred_width_of_all_columns,
table_border_padding: border_padding,
};
let input = inline_size_computer.compute_inline_size_constraint_inputs(
&mut self.block_flow,
parent_flow_inline_size,
shared_context,
);
let solution =
inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, &input);
inline_size_computer
.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
inline_size_computer
.set_inline_position_of_flow_if_necessary(&mut self.block_flow, solution);
return;
}
let inline_size_computer = Table {
minimum_width_of_all_columns,
preferred_width_of_all_columns,
table_border_padding: border_padding,
};
let input = inline_size_computer.compute_inline_size_constraint_inputs(
&mut self.block_flow,
parent_flow_inline_size,
shared_context,
);
let solution =
inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, &input);
inline_size_computer.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
inline_size_computer
.set_inline_position_of_flow_if_necessary(&mut self.block_flow, solution);
}
}
impl Flow for TableWrapperFlow {
fn class(&self) -> FlowClass {
FlowClass::TableWrapper
}
fn as_table_wrapper(&self) -> &TableWrapperFlow {
self
}
fn as_mut_block(&mut self) -> &mut BlockFlow {
&mut self.block_flow
}
fn as_block(&self) -> &BlockFlow {
&self.block_flow
}
fn mark_as_root(&mut self) {
self.block_flow.mark_as_root();
}
fn bubble_inline_sizes(&mut self) {
for kid in self.block_flow.base.child_iter_mut() {
debug_assert!(kid.is_table_caption() || kid.is_table());
if kid.is_table() {
let table = kid.as_table();
self.column_intrinsic_inline_sizes
.clone_from(&table.column_intrinsic_inline_sizes)
}
}
self.block_flow.bubble_inline_sizes();
}
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
if self.block_flow.base.flags.is_float() {
"floated table_wrapper"
} else {
"table_wrapper"
}
);
trace!("TableWrapperFlow before assigning: {:?}", &self);
let shared_context = layout_context.shared_context();
self.block_flow
.initialize_container_size_for_root(shared_context);
let mut intermediate_column_inline_sizes = self
.column_intrinsic_inline_sizes
.iter()
.map(
|column_intrinsic_inline_size| IntermediateColumnInlineSize {
size: column_intrinsic_inline_size.minimum_length,
},
)
.collect::<Vec<_>>();
let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
if self.block_flow.base.flags.is_float() {
self.block_flow
.float
.as_mut()
.unwrap()
.containing_inline_size = containing_block_inline_size;
}
self.compute_border_and_padding_of_table();
self.compute_used_inline_size(
shared_context,
containing_block_inline_size,
&intermediate_column_inline_sizes,
);
match self.table_layout {
TableLayout::Auto => self.calculate_table_column_sizes_for_automatic_layout(
&mut intermediate_column_inline_sizes,
),
TableLayout::Fixed => {},
}
let inline_start_content_edge = self.block_flow.fragment.border_box.start.i;
let content_inline_size = self.block_flow.fragment.border_box.size.inline;
let inline_end_content_edge = self.block_flow.fragment.border_padding.inline_end +
self.block_flow.fragment.margin.inline_end;
let assigned_column_inline_sizes = match self.table_layout {
TableLayout::Fixed => None,
TableLayout::Auto => Some(
intermediate_column_inline_sizes
.iter()
.map(|sizes| ColumnComputedInlineSize { size: sizes.size })
.collect::<Vec<_>>(),
),
};
match assigned_column_inline_sizes {
None => self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|_, _, _, _, _, _| {},
),
Some(ref assigned_column_inline_sizes) => {
self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|child_flow, _, _, _, _, _| {
if child_flow.class() == FlowClass::Table {
child_flow.as_mut_table().column_computed_inline_sizes =
assigned_column_inline_sizes.to_vec();
}
},
)
},
}
trace!("TableWrapperFlow after assigning: {:?}", &self);
}
fn assign_block_size(&mut self, layout_context: &LayoutContext) {
debug!("assign_block_size: assigning block_size for table_wrapper");
trace!("TableWrapperFlow before assigning: {:?}", &self);
let remaining = self.block_flow.assign_block_size_block_base(
layout_context,
None,
MarginsMayCollapseFlag::MarginsMayNotCollapse,
);
debug_assert!(remaining.is_none());
trace!("TableWrapperFlow after assigning: {:?}", &self);
}
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow
.compute_stacking_relative_position(layout_context)
}
fn place_float_if_applicable<'a>(&mut self) {
self.block_flow.place_float_if_applicable()
}
fn assign_block_size_for_inorder_child_if_necessary(
&mut self,
layout_context: &LayoutContext,
parent_thread_id: u8,
content_box: LogicalRect<Au>,
) -> bool {
self.block_flow
.assign_block_size_for_inorder_child_if_necessary(
layout_context,
parent_thread_id,
content_box,
)
}
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)
}
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_size(flow)
}
fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
self.block_flow.build_display_list(state);
}
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
self.block_flow.collect_stacking_contexts_for_block(
state,
StackingContextCollectionFlags::POSITION_NEVER_CREATES_CONTAINING_BLOCK |
StackingContextCollectionFlags::NEVER_CREATES_CLIP_SCROLL_NODE,
);
}
fn repair_style(&mut self, new_style: &crate::ServoArc<ComputedValues>) {
self.block_flow.repair_style(new_style)
}
fn compute_overflow(&self) -> Overflow {
self.block_flow.compute_overflow()
}
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut dyn FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
}
fn mutate_fragments(&mut self, mutator: &mut dyn FnMut(&mut Fragment)) {
self.block_flow.mutate_fragments(mutator)
}
fn print_extra_flow_children(&self, print_tree: &mut PrintTree) {
self.block_flow.print_extra_flow_children(print_tree);
}
fn positioning(&self) -> position::T {
self.block_flow.positioning()
}
}
impl fmt::Debug for TableWrapperFlow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.block_flow.base.flags.is_float() {
write!(f, "TableWrapperFlow(Float): {:?}", self.block_flow)
} else {
write!(f, "TableWrapperFlow: {:?}", self.block_flow)
}
}
}
struct AutoLayoutCandidateGuess {
minimum_guess: Au,
minimum_percentage_guess: Au,
minimum_specified_guess: Au,
preferred_guess: Au,
}
impl AutoLayoutCandidateGuess {
fn new() -> AutoLayoutCandidateGuess {
AutoLayoutCandidateGuess {
minimum_guess: Au(0),
minimum_percentage_guess: Au(0),
minimum_specified_guess: Au(0),
preferred_guess: Au(0),
}
}
fn from_column_intrinsic_inline_size(
column_intrinsic_inline_size: &ColumnIntrinsicInlineSize,
assignable_inline_size: Au,
) -> AutoLayoutCandidateGuess {
let minimum_percentage_guess = max(
assignable_inline_size.scale_by(column_intrinsic_inline_size.percentage),
column_intrinsic_inline_size.minimum_length,
);
AutoLayoutCandidateGuess {
minimum_guess: column_intrinsic_inline_size.minimum_length,
minimum_percentage_guess,
minimum_specified_guess: if column_intrinsic_inline_size.percentage > 0.0 {
minimum_percentage_guess
} else if column_intrinsic_inline_size.constrained {
column_intrinsic_inline_size.preferred
} else {
column_intrinsic_inline_size.minimum_length
},
preferred_guess: if column_intrinsic_inline_size.percentage > 0.0 {
minimum_percentage_guess
} else {
column_intrinsic_inline_size.preferred
},
}
}
fn calculate(&self, selection: SelectedAutoLayoutCandidateGuess) -> Au {
match selection {
SelectedAutoLayoutCandidateGuess::UseMinimumGuess => self.minimum_guess,
SelectedAutoLayoutCandidateGuess::
InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight) => {
interp(self.minimum_guess, self.minimum_percentage_guess, weight)
}
SelectedAutoLayoutCandidateGuess::
InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight) => {
interp(self.minimum_percentage_guess, self.minimum_specified_guess, weight)
}
SelectedAutoLayoutCandidateGuess::
InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight) => {
interp(self.minimum_specified_guess, self.preferred_guess, weight)
}
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize => {
self.preferred_guess
}
}
}
}
impl<'a> Add for &'a AutoLayoutCandidateGuess {
type Output = AutoLayoutCandidateGuess;
#[inline]
fn add(self, other: &AutoLayoutCandidateGuess) -> AutoLayoutCandidateGuess {
AutoLayoutCandidateGuess {
minimum_guess: self.minimum_guess + other.minimum_guess,
minimum_percentage_guess: self.minimum_percentage_guess +
other.minimum_percentage_guess,
minimum_specified_guess: self.minimum_specified_guess + other.minimum_specified_guess,
preferred_guess: self.preferred_guess + other.preferred_guess,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum SelectedAutoLayoutCandidateGuess {
UseMinimumGuess,
InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(CSSFloat),
InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(CSSFloat),
InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(CSSFloat),
UsePreferredGuessAndDistributeExcessInlineSize,
}
impl SelectedAutoLayoutCandidateGuess {
fn select(
guess: &AutoLayoutCandidateGuess,
assignable_inline_size: Au,
) -> SelectedAutoLayoutCandidateGuess {
if assignable_inline_size < guess.minimum_guess {
SelectedAutoLayoutCandidateGuess::UseMinimumGuess
} else if assignable_inline_size < guess.minimum_percentage_guess {
let weight = weight(
guess.minimum_guess,
assignable_inline_size,
guess.minimum_percentage_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight)
} else if assignable_inline_size < guess.minimum_specified_guess {
let weight = weight(
guess.minimum_percentage_guess,
assignable_inline_size,
guess.minimum_specified_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight)
} else if assignable_inline_size < guess.preferred_guess {
let weight = weight(
guess.minimum_specified_guess,
assignable_inline_size,
guess.preferred_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight)
} else {
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize
}
}
}
fn weight(low: Au, middle: Au, high: Au) -> CSSFloat {
(middle - low).to_f32_px() / (high - low).to_f32_px()
}
fn interp(low: Au, high: Au, weight: CSSFloat) -> Au {
low + (high - low).scale_by(weight)
}
struct ExcessInlineSizeDistributionInfo {
preferred_inline_size_of_nonconstrained_columns_with_no_percentage: Au,
count_of_nonconstrained_columns_with_no_percentage: u32,
preferred_inline_size_of_constrained_columns_with_no_percentage: Au,
total_percentage: CSSFloat,
column_count: u32,
}
impl ExcessInlineSizeDistributionInfo {
fn new() -> ExcessInlineSizeDistributionInfo {
ExcessInlineSizeDistributionInfo {
preferred_inline_size_of_nonconstrained_columns_with_no_percentage: Au(0),
count_of_nonconstrained_columns_with_no_percentage: 0,
preferred_inline_size_of_constrained_columns_with_no_percentage: Au(0),
total_percentage: 0.0,
column_count: 0,
}
}
fn update(&mut self, column_intrinsic_inline_size: &ColumnIntrinsicInlineSize) {
if !column_intrinsic_inline_size.constrained &&
column_intrinsic_inline_size.percentage == 0.0
{
self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage +=
column_intrinsic_inline_size.preferred;
self.count_of_nonconstrained_columns_with_no_percentage += 1
}
if column_intrinsic_inline_size.constrained &&
column_intrinsic_inline_size.percentage == 0.0
{
self.preferred_inline_size_of_constrained_columns_with_no_percentage +=
column_intrinsic_inline_size.preferred
}
self.total_percentage += column_intrinsic_inline_size.percentage;
self.column_count += 1
}
#[inline]
fn distribute_excess_inline_size_to_column(
&self,
intermediate_column_inline_size: &mut IntermediateColumnInlineSize,
column_intrinsic_inline_size: &ColumnIntrinsicInlineSize,
excess_inline_size: Au,
total_distributed_excess_size: &mut Au,
) {
let proportion =
if self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage > Au(0) {
if !column_intrinsic_inline_size.constrained &&
column_intrinsic_inline_size.percentage == 0.0
{
column_intrinsic_inline_size.preferred.to_f32_px() /
self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage
.to_f32_px()
} else {
0.0
}
} else if self.count_of_nonconstrained_columns_with_no_percentage > 0 {
1.0 / (self.count_of_nonconstrained_columns_with_no_percentage as CSSFloat)
} else if self.preferred_inline_size_of_constrained_columns_with_no_percentage > Au(0) {
column_intrinsic_inline_size.preferred.to_f32_px() /
self.preferred_inline_size_of_constrained_columns_with_no_percentage
.to_f32_px()
} else if self.total_percentage > 0.0 {
column_intrinsic_inline_size.percentage / self.total_percentage
} else {
1.0 / (self.column_count as CSSFloat)
};
let amount_to_distribute = min(
excess_inline_size.scale_by(proportion),
excess_inline_size - *total_distributed_excess_size,
);
*total_distributed_excess_size += amount_to_distribute;
intermediate_column_inline_size.size += amount_to_distribute
}
}
struct IntermediateColumnInlineSize {
size: Au,
}
fn initial_computed_inline_size(
block: &mut BlockFlow,
containing_block_inline_size: Au,
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
table_border_padding: Au,
) -> MaybeAuto {
block
.fragment
.style
.content_inline_size()
.to_used_value(containing_block_inline_size)
.map_or_else(
|| {
if preferred_width_of_all_columns + table_border_padding <=
containing_block_inline_size
{
MaybeAuto::Specified(preferred_width_of_all_columns + table_border_padding)
} else if minimum_width_of_all_columns > containing_block_inline_size {
MaybeAuto::Specified(minimum_width_of_all_columns)
} else {
MaybeAuto::Auto
}
},
|used| {
MaybeAuto::Specified(max(
used - table_border_padding,
minimum_width_of_all_columns,
))
},
)
}
struct Table {
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
table_border_padding: Au,
}
impl ISizeAndMarginsComputer for Table {
fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) {
block
.fragment
.compute_border_and_padding(containing_block_inline_size)
}
fn initial_computed_inline_size(
&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> MaybeAuto {
let containing_block_inline_size =
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
initial_computed_inline_size(
block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding,
)
}
fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput,
) -> ISizeConstraintSolution {
self.solve_block_inline_size_constraints(block, input)
}
}
struct FloatedTable {
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
table_border_padding: Au,
}
impl ISizeAndMarginsComputer for FloatedTable {
fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) {
block
.fragment
.compute_border_and_padding(containing_block_inline_size)
}
fn initial_computed_inline_size(
&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> MaybeAuto {
let containing_block_inline_size =
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
initial_computed_inline_size(
block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding,
)
}
fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput,
) -> ISizeConstraintSolution {
FloatNonReplaced.solve_inline_size_constraints(block, input)
}
}
struct AbsoluteTable {
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
table_border_padding: Au,
}
impl ISizeAndMarginsComputer for AbsoluteTable {
fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) {
block
.fragment
.compute_border_and_padding(containing_block_inline_size)
}
fn initial_computed_inline_size(
&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> MaybeAuto {
let containing_block_inline_size =
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
initial_computed_inline_size(
block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding,
)
}
fn containing_block_inline_size(
&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> Au {
AbsoluteNonReplaced.containing_block_inline_size(
block,
parent_flow_inline_size,
shared_context,
)
}
fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput,
) -> ISizeConstraintSolution {
AbsoluteNonReplaced.solve_inline_size_constraints(block, input)
}
fn set_inline_position_of_flow_if_necessary(
&self,
block: &mut BlockFlow,
solution: ISizeConstraintSolution,
) {
AbsoluteNonReplaced.set_inline_position_of_flow_if_necessary(block, solution);
}
}