aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/table_wrapper.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/table_wrapper.rs')
-rw-r--r--components/layout/table_wrapper.rs1013
1 files changed, 0 insertions, 1013 deletions
diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs
deleted file mode 100644
index 72a30969b63..00000000000
--- a/components/layout/table_wrapper.rs
+++ /dev/null
@@ -1,1013 +0,0 @@
-/* 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 https://mozilla.org/MPL/2.0/. */
-
-//! CSS tables.
-//!
-//! This follows the "More Precise Definitions of Inline Layout and Table Layout" proposal written
-//! by L. David Baron (Mozilla) here:
-//!
-//! <http://dbaron.org/css/intrinsic/>
-//!
-//! Hereafter this document is referred to as INTRINSIC.
-
-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::CSSFloat;
-use style::values::computed::Size;
-
-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 {}
-
-/// A table wrapper flow based on a block formatting context.
-#[derive(Serialize)]
-#[repr(C)]
-pub struct TableWrapperFlow {
- pub block_flow: BlockFlow,
-
- /// Intrinsic column inline sizes according to INTRINSIC § 4.1
- pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>,
-
- /// Table-layout property
- 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)
- }
-
- // Instructs our first child, which is the table itself, to compute its border and padding.
- //
- // This is a little weird because we're computing border/padding/margins for our child,
- // when normally the child computes it itself. But it has to be this way because the
- // padding will affect where we place the child. This is an odd artifact of the way that
- // tables are separated into table flows and table wrapper flows.
- 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;
- }
- }
-
- /// Calculates table column sizes for automatic layout per INTRINSIC § 4.3.
- fn calculate_table_column_sizes_for_automatic_layout(
- &mut self,
- intermediate_column_inline_sizes: &mut [IntermediateColumnInlineSize],
- ) {
- let available_inline_size = self.available_inline_size();
-
- // Compute all the guesses for the column sizes, and sum them.
- 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();
-
- // Assign inline sizes.
- 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);
- // intermediate_column_inline_size.percentage = 0.0;
- total_used_inline_size += intermediate_column_inline_size.size
- }
-
- // Distribute excess inline-size if necessary per INTRINSIC § 4.4.
- //
- // FIXME(pcwalton, spec): How do I deal with fractional excess?
- 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();
-
- // FIXME(pcwalton, spec): INTRINSIC § 8 does not properly define how to compute this, but
- // says "the basic idea is the same as the shrink-to-fit width that CSS2.1 defines". So we
- // just use the shrink-to-fit inline size.
- 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
- },
- // FIXME(mttr): This fixes #4421 without breaking our current reftests, but I'm not
- // completely sure this is "correct".
- //
- // That said, `available_inline_size` is, as far as I can tell, equal to the table's
- // computed width property (W) and is used from this point forward in a way that seems
- // to correspond with CSS 2.1 § 17.5.2.2 under "Column and caption widths influence the
- // final table width as follows: …"
- _ => 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() {
- // If our "start" direction is different from our parent flow, then `border_box.start.i`
- // depends on `border_box.size.inline`.
- 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
- },
- );
-
- // Delegate to the appropriate inline size computer to find the constraint inputs and write
- // the constraint solutions in.
- 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) {
- // Get the intrinsic column inline-sizes info from the table flow.
- 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,
- // percentage: column_intrinsic_inline_size.percentage,
- },
- )
- .collect::<Vec<_>>();
-
- // Our inline-size was set to the inline-size of the containing block by the flow's parent.
- // Now compute the real value.
- 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;
- }
-
- // This has to be done before computing our inline size because `compute_used_inline_size`
- // internally consults the border and padding of the table.
- 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;
-
- // In case of fixed layout, column inline-sizes are calculated in table flow.
- 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)
- }
- }
-}
-
-/// The layout "guesses" defined in INTRINSIC § 4.3.
-struct AutoLayoutCandidateGuess {
- /// The column inline-size assignment where each column is assigned its intrinsic minimum
- /// inline-size.
- minimum_guess: Au,
-
- /// The column inline-size assignment where:
- /// * A column with an intrinsic percentage inline-size greater than 0% is assigned the
- /// larger of:
- /// - Its intrinsic percentage inline-size times the assignable inline-size;
- /// - Its intrinsic minimum inline-size;
- /// * Other columns receive their intrinsic minimum inline-size.
- minimum_percentage_guess: Au,
-
- /// The column inline-size assignment where:
- /// * Each column with an intrinsic percentage inline-size greater than 0% is assigned the
- /// larger of:
- /// - Its intrinsic percentage inline-size times the assignable inline-size;
- /// - Its intrinsic minimum inline-size;
- /// * Any other column that is constrained is assigned its intrinsic preferred inline-size;
- /// * Other columns are assigned their intrinsic minimum inline-size.
- minimum_specified_guess: Au,
-
- /// The column inline-size assignment where:
- /// * Each column with an intrinsic percentage inline-size greater than 0% is assigned the
- /// larger of:
- /// - Its intrinsic percentage inline-size times the assignable inline-size;
- /// - Its intrinsic minimum inline-size;
- /// * Other columns are assigned their intrinsic preferred inline-size.
- preferred_guess: Au,
-}
-
-impl AutoLayoutCandidateGuess {
- /// Creates a guess with all elements initialized to zero.
- fn new() -> AutoLayoutCandidateGuess {
- AutoLayoutCandidateGuess {
- minimum_guess: Au(0),
- minimum_percentage_guess: Au(0),
- minimum_specified_guess: Au(0),
- preferred_guess: Au(0),
- }
- }
-
- /// Fills in the inline-size guesses for this column per INTRINSIC § 4.3.
- 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,
- // FIXME(pcwalton): We need the notion of *constrainedness* per INTRINSIC § 4 to
- // implement this one correctly.
- 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
- },
- }
- }
-
- /// Calculates the inline-size, interpolating appropriately based on the value of `selection`.
- ///
- /// This does *not* distribute excess inline-size. That must be done later if necessary.
- 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 Add for &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,
- }
- }
-}
-
-/// The `CSSFloat` member specifies the weight of the smaller of the two guesses, on a scale from
-/// 0.0 to 1.0.
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum SelectedAutoLayoutCandidateGuess {
- UseMinimumGuess,
- InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(CSSFloat),
- InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(CSSFloat),
- InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(CSSFloat),
- UsePreferredGuessAndDistributeExcessInlineSize,
-}
-
-impl SelectedAutoLayoutCandidateGuess {
- /// See INTRINSIC § 4.3.
- ///
- /// FIXME(pcwalton, INTRINSIC spec): INTRINSIC doesn't specify whether these are exclusive or
- /// inclusive ranges.
- 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
- }
- }
-}
-
-/// Computes the weight needed to linearly interpolate `middle` between two guesses `low` and
-/// `high` as specified by INTRINSIC § 4.3.
-fn weight(low: Au, middle: Au, high: Au) -> CSSFloat {
- (middle - low).to_f32_px() / (high - low).to_f32_px()
-}
-
-/// Linearly interpolates between two guesses, as specified by INTRINSIC § 4.3.
-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
- }
-
- /// Based on the information here, distributes excess inline-size to the given column per
- /// INTRINSIC § 4.4.
- ///
- /// `#[inline]` so the compiler will hoist out the branch, which is loop-invariant.
- #[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) {
- // FIXME(spec, pcwalton): Gecko and WebKit do *something* here when there are
- // nonconstrained columns with no percentage *and* no preferred width. What do they
- // do?
- 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)
- };
-
- // The `min` here has the effect of throwing away fractional excess at the end of the
- // table.
- 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
- }
-}
-
-/// An intermediate column size assignment.
-struct IntermediateColumnInlineSize {
- size: Au,
- // This used to be stored here but nothing used it,
- // which started emitting a compiler warning: https://github.com/servo/servo/pull/28202
- // percentage: f32,
-}
-
-/// Returns the computed inline size of the table wrapper represented by `block`.
-///
-/// `table_border_padding` is the sum of the sizes of all border and padding in the inline
-/// direction of the table contained within this table wrapper.
-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);
- }
-}