mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #12330 - stshine:flexitem, r=pcwalton
Implement flexible box layout for row container <!-- Please describe your changes on the following line: --> This pull requests implements basic flexible box layout for row container. It has implemented most basic flexbox features, including grow, shrink, multi-line, *reverse properties, and alignment under `justify-content`, `align-items`, `align-self`, `align-content`. --- <!-- 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] There are tests for these changes <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> r? @pcwalton <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12330) <!-- Reviewable:end -->
This commit is contained in:
commit
15947f8f73
200 changed files with 623 additions and 700 deletions
|
@ -487,6 +487,7 @@ pub enum BlockType {
|
||||||
FloatNonReplaced,
|
FloatNonReplaced,
|
||||||
InlineBlockReplaced,
|
InlineBlockReplaced,
|
||||||
InlineBlockNonReplaced,
|
InlineBlockNonReplaced,
|
||||||
|
FlexItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
|
@ -521,7 +522,9 @@ pub struct BlockFlow {
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags BlockFlowFlags: u8 {
|
flags BlockFlowFlags: u8 {
|
||||||
#[doc = "If this is set, then this block flow is the root flow."]
|
#[doc = "If this is set, then this block flow is the root flow."]
|
||||||
const IS_ROOT = 0x01,
|
const IS_ROOT = 0b0000_0001,
|
||||||
|
#[doc = "Whether this block flow is a child of a flex container."]
|
||||||
|
const IS_FLEX = 0b0001_0000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,6 +559,8 @@ impl BlockFlow {
|
||||||
} else {
|
} else {
|
||||||
BlockType::AbsoluteNonReplaced
|
BlockType::AbsoluteNonReplaced
|
||||||
}
|
}
|
||||||
|
} else if self.is_flex() {
|
||||||
|
BlockType::FlexItem
|
||||||
} else if self.base.flags.is_float() {
|
} else if self.base.flags.is_float() {
|
||||||
if self.is_replaced_content() {
|
if self.is_replaced_content() {
|
||||||
BlockType::FloatReplaced
|
BlockType::FloatReplaced
|
||||||
|
@ -631,6 +636,12 @@ impl BlockFlow {
|
||||||
shared_context,
|
shared_context,
|
||||||
containing_block_inline_size);
|
containing_block_inline_size);
|
||||||
}
|
}
|
||||||
|
BlockType::FlexItem => {
|
||||||
|
let inline_size_computer = FlexItem;
|
||||||
|
inline_size_computer.compute_used_inline_size(self,
|
||||||
|
shared_context,
|
||||||
|
containing_block_inline_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1138,7 +1149,7 @@ impl BlockFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn explicit_block_size(&self, containing_block_size: Option<Au>) -> Option<Au> {
|
pub fn explicit_block_size(&self, containing_block_size: Option<Au>) -> Option<Au> {
|
||||||
let content_block_size = self.fragment.style().content_block_size();
|
let content_block_size = self.fragment.style().content_block_size();
|
||||||
|
|
||||||
match (content_block_size, containing_block_size) {
|
match (content_block_size, containing_block_size) {
|
||||||
|
@ -1671,6 +1682,14 @@ impl BlockFlow {
|
||||||
let padding = self.fragment.style.logical_padding();
|
let padding = self.fragment.style.logical_padding();
|
||||||
padding.block_start.is_definitely_zero() && padding.block_end.is_definitely_zero()
|
padding.block_start.is_definitely_zero() && padding.block_end.is_definitely_zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mark_as_flex(&mut self) {
|
||||||
|
self.flags.insert(IS_FLEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_flex(&self) -> bool {
|
||||||
|
self.flags.contains(IS_FLEX)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Flow for BlockFlow {
|
impl Flow for BlockFlow {
|
||||||
|
@ -2557,6 +2576,7 @@ pub struct FloatNonReplaced;
|
||||||
pub struct FloatReplaced;
|
pub struct FloatReplaced;
|
||||||
pub struct InlineBlockNonReplaced;
|
pub struct InlineBlockNonReplaced;
|
||||||
pub struct InlineBlockReplaced;
|
pub struct InlineBlockReplaced;
|
||||||
|
pub struct FlexItem;
|
||||||
|
|
||||||
impl ISizeAndMarginsComputer for AbsoluteNonReplaced {
|
impl ISizeAndMarginsComputer for AbsoluteNonReplaced {
|
||||||
/// Solve the horizontal constraint equation for absolute non-replaced elements.
|
/// Solve the horizontal constraint equation for absolute non-replaced elements.
|
||||||
|
@ -3047,6 +3067,30 @@ impl ISizeAndMarginsComputer for InlineBlockReplaced {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ISizeAndMarginsComputer for FlexItem {
|
||||||
|
// Replace the default method directly to prevent recalculating and setting margins again
|
||||||
|
// which has already been set by its parent.
|
||||||
|
fn compute_used_inline_size(&self,
|
||||||
|
block: &mut BlockFlow,
|
||||||
|
shared_context: &SharedStyleContext,
|
||||||
|
parent_flow_inline_size: Au) {
|
||||||
|
let container_block_size = block.explicit_block_containing_size(shared_context);
|
||||||
|
block.fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size,
|
||||||
|
container_block_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The used inline size and margins are set by parent flex flow, do nothing here.
|
||||||
|
fn solve_inline_size_constraints(&self,
|
||||||
|
block: &mut BlockFlow,
|
||||||
|
_: &ISizeConstraintInput)
|
||||||
|
-> ISizeConstraintSolution {
|
||||||
|
let fragment = block.fragment();
|
||||||
|
ISizeConstraintSolution::new(fragment.border_box.size.inline,
|
||||||
|
fragment.margin.inline_start,
|
||||||
|
fragment.margin.inline_end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A stacking context, a pseudo-stacking context, or a non-stacking context.
|
/// A stacking context, a pseudo-stacking context, or a non-stacking context.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum BlockStackingContextType {
|
pub enum BlockStackingContextType {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::{Au, MAX_AU};
|
||||||
use block::BlockFlow;
|
use block::BlockFlow;
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list_builder::{DisplayListBuildState, FlexFlowDisplayListBuilding};
|
use display_list_builder::{DisplayListBuildState, FlexFlowDisplayListBuilding};
|
||||||
|
@ -20,15 +20,19 @@ use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
||||||
use gfx::display_list::StackingContext;
|
use gfx::display_list::StackingContext;
|
||||||
use gfx_traits::StackingContextId;
|
use gfx_traits::StackingContextId;
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint};
|
use model::{Direction, IntrinsicISizes, MaybeAuto, MinMaxConstraint};
|
||||||
|
use model::{specified, specified_or_none};
|
||||||
use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
|
use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||||
use std::cmp::max;
|
use std::cmp::{max, min};
|
||||||
|
use std::ops::Range;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::computed_values::flex_direction;
|
use style::computed_values::border_collapse;
|
||||||
use style::context::SharedStyleContext;
|
use style::computed_values::{align_content, align_self, flex_direction, flex_wrap, justify_content};
|
||||||
|
use style::context::{SharedStyleContext, StyleContext};
|
||||||
use style::logical_geometry::LogicalSize;
|
use style::logical_geometry::LogicalSize;
|
||||||
use style::properties::ServoComputedValues;
|
use style::properties::ServoComputedValues;
|
||||||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
|
use style::values::computed::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone};
|
||||||
|
|
||||||
/// The size of an axis. May be a specified size, a min/max
|
/// The size of an axis. May be a specified size, a min/max
|
||||||
/// constraint, or an unlimited size
|
/// constraint, or an unlimited size
|
||||||
|
@ -51,13 +55,13 @@ impl AxisSize {
|
||||||
Some(size) => AxisSize::Definite(size.scale_by(percent)),
|
Some(size) => AxisSize::Definite(size.scale_by(percent)),
|
||||||
None => AxisSize::Infinite
|
None => AxisSize::Infinite
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
LengthOrPercentageOrAuto::Calc(calc) => {
|
LengthOrPercentageOrAuto::Calc(calc) => {
|
||||||
match content_size {
|
match content_size {
|
||||||
Some(size) => AxisSize::Definite(size.scale_by(calc.percentage())),
|
Some(size) => AxisSize::Definite(size.scale_by(calc.percentage())),
|
||||||
None => AxisSize::Infinite
|
None => AxisSize::Infinite
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
LengthOrPercentageOrAuto::Auto => {
|
LengthOrPercentageOrAuto::Auto => {
|
||||||
AxisSize::MinMax(MinMaxConstraint::new(content_size, min, max))
|
AxisSize::MinMax(MinMaxConstraint::new(content_size, min, max))
|
||||||
}
|
}
|
||||||
|
@ -65,25 +69,263 @@ impl AxisSize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A mode describes which logical axis a flex axis is parallel with.
|
/// This function accepts the flex-basis and the size property in main direction from style,
|
||||||
// The logical axises are inline and block, the flex axises are main and cross.
|
/// and the container size, then return the used value of flex basis. it can be used to help
|
||||||
// When the flex container has flex-direction: column or flex-direction: column-reverse, the main axis
|
/// determining the flex base size and to indicate whether the main size of the item
|
||||||
// should be block. Otherwise, it should be inline.
|
/// is definite after flex size resolving.
|
||||||
#[derive(Debug)]
|
fn from_flex_basis(flex_basis: LengthOrPercentageOrAutoOrContent,
|
||||||
enum Mode {
|
main_length: LengthOrPercentageOrAuto,
|
||||||
Inline,
|
containing_length: Option<Au>) -> MaybeAuto {
|
||||||
Block
|
match (flex_basis, containing_length) {
|
||||||
|
(LengthOrPercentageOrAutoOrContent::Length(length), _) =>
|
||||||
|
MaybeAuto::Specified(length),
|
||||||
|
(LengthOrPercentageOrAutoOrContent::Percentage(percent), Some(size)) =>
|
||||||
|
MaybeAuto::Specified(size.scale_by(percent)),
|
||||||
|
(LengthOrPercentageOrAutoOrContent::Percentage(_), None) =>
|
||||||
|
MaybeAuto::Auto,
|
||||||
|
(LengthOrPercentageOrAutoOrContent::Calc(calc), Some(size)) =>
|
||||||
|
MaybeAuto::Specified(calc.length() + size.scale_by(calc.percentage())),
|
||||||
|
(LengthOrPercentageOrAutoOrContent::Calc(_), None) =>
|
||||||
|
MaybeAuto::Auto,
|
||||||
|
(LengthOrPercentageOrAutoOrContent::Content, _) =>
|
||||||
|
MaybeAuto::Auto,
|
||||||
|
(LengthOrPercentageOrAutoOrContent::Auto, Some(size)) =>
|
||||||
|
MaybeAuto::from_style(main_length, size),
|
||||||
|
(LengthOrPercentageOrAutoOrContent::Auto, None) => {
|
||||||
|
if let LengthOrPercentageOrAuto::Length(length) = main_length {
|
||||||
|
MaybeAuto::Specified(length)
|
||||||
|
} else {
|
||||||
|
MaybeAuto::Auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a child in a flex container. Most fields here are used in
|
||||||
|
/// flex size resolving, and items are sorted by the 'order' property.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FlexItem {
|
struct FlexItem {
|
||||||
|
/// Main size of a flex item, used to store results of flexible length calcuation.
|
||||||
|
pub main_size: Au,
|
||||||
|
/// Used flex base size.
|
||||||
|
pub base_size: Au,
|
||||||
|
/// The minimal size in main direction.
|
||||||
|
pub min_size: Au,
|
||||||
|
/// The maximal main size. If this property is not actually set by style
|
||||||
|
/// It will be the largest size available for code reuse.
|
||||||
|
pub max_size: Au,
|
||||||
|
/// Reference to the actual flow.
|
||||||
pub flow: FlowRef,
|
pub flow: FlowRef,
|
||||||
|
/// Style of the child flow, stored here to reduce overhead.
|
||||||
|
pub style: Arc<ServoComputedValues>,
|
||||||
|
/// The 'flex-grow' property of this item.
|
||||||
|
pub flex_grow: f32,
|
||||||
|
/// The 'flex-shrink' property of this item.
|
||||||
|
pub flex_shrink: f32,
|
||||||
|
/// The 'order' property of this item.
|
||||||
|
pub order: i32,
|
||||||
|
/// Whether the main size has met its constraint.
|
||||||
|
pub is_frozen: bool,
|
||||||
|
/// True if this flow has property 'visibility::collapse'.
|
||||||
|
pub is_strut: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlexItem {
|
impl FlexItem {
|
||||||
fn new(flow: FlowRef) -> FlexItem {
|
pub fn new(flow: FlowRef) -> FlexItem {
|
||||||
|
let style = flow.as_block().fragment.style.clone();
|
||||||
|
let flex_grow = style.get_position().flex_grow;
|
||||||
|
let flex_shrink = style.get_position().flex_shrink;
|
||||||
|
let order = style.get_position().order;
|
||||||
|
// TODO(stshine): for item with 'visibility:collapse', set is_strut to true.
|
||||||
|
|
||||||
FlexItem {
|
FlexItem {
|
||||||
flow: flow
|
main_size: Au(0),
|
||||||
|
base_size: Au(0),
|
||||||
|
min_size: Au(0),
|
||||||
|
max_size: MAX_AU,
|
||||||
|
flow: flow,
|
||||||
|
style: style,
|
||||||
|
flex_grow: flex_grow,
|
||||||
|
flex_shrink: flex_shrink,
|
||||||
|
order: order,
|
||||||
|
is_frozen: false,
|
||||||
|
is_strut: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the used flex base size, minimal main size and maximal main size.
|
||||||
|
/// For block mode container this method should be called in assign_block_size()
|
||||||
|
/// pass so that the item has already been layouted.
|
||||||
|
pub fn init_sizes(&mut self, containing_length: Au, direction: Direction) {
|
||||||
|
let block = flow_ref::deref_mut(&mut self.flow).as_mut_block();
|
||||||
|
match direction {
|
||||||
|
// TODO(stshine): the definition of min-{width, height} in style component
|
||||||
|
// should change to LengthOrPercentageOrAuto for automatic implied minimal size.
|
||||||
|
// https://drafts.csswg.org/css-flexbox-1/#min-size-auto
|
||||||
|
Direction::Inline => {
|
||||||
|
let basis = from_flex_basis(self.style.get_position().flex_basis,
|
||||||
|
self.style.content_inline_size(),
|
||||||
|
Some(containing_length));
|
||||||
|
|
||||||
|
// These methods compute auto margins to zero length, which is exactly what we want.
|
||||||
|
block.fragment.compute_border_and_padding(containing_length,
|
||||||
|
border_collapse::T::separate);
|
||||||
|
block.fragment.compute_inline_direction_margins(containing_length);
|
||||||
|
block.fragment.compute_block_direction_margins(containing_length);
|
||||||
|
|
||||||
|
let content_size = block.base.intrinsic_inline_sizes.preferred_inline_size
|
||||||
|
- block.fragment.surrounding_intrinsic_inline_size()
|
||||||
|
+ block.fragment.box_sizing_boundary(direction);
|
||||||
|
self.base_size = basis.specified_or_default(content_size);
|
||||||
|
self.max_size = specified_or_none(self.style.max_inline_size(), containing_length)
|
||||||
|
.unwrap_or(MAX_AU);
|
||||||
|
self.min_size = specified(self.style.min_inline_size(), containing_length);
|
||||||
|
}
|
||||||
|
Direction::Block => {
|
||||||
|
let basis = from_flex_basis(self.style.get_position().flex_basis,
|
||||||
|
self.style.content_block_size(),
|
||||||
|
Some(containing_length));
|
||||||
|
let content_size = block.fragment.border_box.size.block
|
||||||
|
- block.fragment.border_padding.block_start_end()
|
||||||
|
+ block.fragment.box_sizing_boundary(direction);
|
||||||
|
self.base_size = basis.specified_or_default(content_size);
|
||||||
|
self.max_size = specified_or_none(self.style.max_block_size(), containing_length)
|
||||||
|
.unwrap_or(MAX_AU);
|
||||||
|
self.min_size = specified(self.style.min_block_size(), containing_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the outer main size of the item, including paddings and margins,
|
||||||
|
/// clamped by max and min size.
|
||||||
|
pub fn outer_main_size(&self, direction: Direction) -> Au {
|
||||||
|
let ref fragment = self.flow.as_block().fragment;
|
||||||
|
let outer_width = match direction {
|
||||||
|
Direction::Inline => {
|
||||||
|
fragment.border_padding.inline_start_end() + fragment.margin.inline_start_end()
|
||||||
|
}
|
||||||
|
Direction::Block => {
|
||||||
|
fragment.border_padding.block_start_end() + fragment.margin.block_start_end()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
max(self.min_size, min(self.base_size, self.max_size))
|
||||||
|
- fragment.box_sizing_boundary(direction) + outer_width
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of auto margins in given direction.
|
||||||
|
pub fn auto_margin_count(&self, direction: Direction) -> i32 {
|
||||||
|
let margin = self.style.logical_margin();
|
||||||
|
let mut margin_count = 0;
|
||||||
|
match direction {
|
||||||
|
Direction::Inline => {
|
||||||
|
if margin.inline_start == LengthOrPercentageOrAuto::Auto {
|
||||||
|
margin_count += 1;
|
||||||
|
}
|
||||||
|
if margin.inline_end == LengthOrPercentageOrAuto::Auto {
|
||||||
|
margin_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::Block => {
|
||||||
|
if margin.block_start == LengthOrPercentageOrAuto::Auto {
|
||||||
|
margin_count += 1;
|
||||||
|
}
|
||||||
|
if margin.block_end == LengthOrPercentageOrAuto::Auto {
|
||||||
|
margin_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
margin_count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A line in a flex container.
|
||||||
|
// TODO(stshine): More fields are required to handle collapsed items and baseline alignment.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct FlexLine {
|
||||||
|
/// Range of items belong to this line in 'self.items'.
|
||||||
|
pub range: Range<usize>,
|
||||||
|
/// Remaining free space of this line, items will grow or shrink based on it being positive or negative.
|
||||||
|
pub free_space: Au,
|
||||||
|
/// The number of auto margins of items.
|
||||||
|
pub auto_margin_count: i32,
|
||||||
|
/// Line size in the block direction.
|
||||||
|
pub cross_size: Au,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlexLine {
|
||||||
|
pub fn new(range: Range<usize>, free_space: Au, auto_margin_count: i32) -> FlexLine {
|
||||||
|
FlexLine {
|
||||||
|
range: range,
|
||||||
|
auto_margin_count: auto_margin_count,
|
||||||
|
free_space: free_space,
|
||||||
|
cross_size: Au(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method implements the flexible lengths resolving algorithm.
|
||||||
|
/// The 'collapse' parameter is used to indicate whether items with 'visibility: collapse'
|
||||||
|
/// is included in length resolving. The result main size is stored in 'item.main_size'.
|
||||||
|
/// https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths
|
||||||
|
pub fn flex_resolve(&mut self, items: &mut [FlexItem], collapse: bool) {
|
||||||
|
let mut total_grow = 0.0;
|
||||||
|
let mut total_shrink = 0.0;
|
||||||
|
let mut total_scaled = 0.0;
|
||||||
|
let mut active_count = 0;
|
||||||
|
// Iterate through items, collect total factors and freeze those that have already met
|
||||||
|
// their constraints or won't grow/shrink in corresponding scenario.
|
||||||
|
// https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths
|
||||||
|
for item in items.iter_mut().filter(|i| !(i.is_strut && collapse)) {
|
||||||
|
item.main_size = max(item.min_size, min(item.base_size, item.max_size));
|
||||||
|
if item.main_size != item.base_size
|
||||||
|
|| (self.free_space > Au(0) && item.flex_grow == 0.0)
|
||||||
|
|| (self.free_space < Au(0) && item.flex_shrink == 0.0) {
|
||||||
|
item.is_frozen = true;
|
||||||
|
} else {
|
||||||
|
item.is_frozen = false;
|
||||||
|
total_grow += item.flex_grow;
|
||||||
|
total_shrink += item.flex_shrink;
|
||||||
|
// The scaled factor is used to calculate flex shrink
|
||||||
|
total_scaled += item.flex_shrink * item.base_size.0 as f32;
|
||||||
|
active_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let initial_free_space = self.free_space;
|
||||||
|
let mut total_variation = Au(1);
|
||||||
|
// If there is no remaining free space or all items are frozen, stop loop.
|
||||||
|
while total_variation != Au(0) && self.free_space != Au(0) && active_count > 0 {
|
||||||
|
self.free_space =
|
||||||
|
// https://drafts.csswg.org/css-flexbox/#remaining-free-space
|
||||||
|
if self.free_space > Au(0) {
|
||||||
|
min(initial_free_space.scale_by(total_grow), self.free_space)
|
||||||
|
} else {
|
||||||
|
max(initial_free_space.scale_by(total_shrink), self.free_space)
|
||||||
|
};
|
||||||
|
|
||||||
|
total_variation = Au(0);
|
||||||
|
for item in items.iter_mut().filter(|i| !i.is_frozen).filter(|i| !(i.is_strut && collapse)) {
|
||||||
|
// Use this and the 'abs()' below to make the code work in both grow and shrink scenarios.
|
||||||
|
let (factor, end_size) = if self.free_space > Au(0) {
|
||||||
|
(item.flex_grow / total_grow, item.max_size)
|
||||||
|
} else {
|
||||||
|
(item.flex_shrink * item.base_size.0 as f32 / total_scaled, item.min_size)
|
||||||
|
};
|
||||||
|
let variation = self.free_space.scale_by(factor);
|
||||||
|
if variation.0.abs() > (end_size - item.main_size).0.abs() {
|
||||||
|
// Use constraint as the target main size, and freeze item.
|
||||||
|
total_variation += end_size - item.main_size;
|
||||||
|
item.main_size = end_size;
|
||||||
|
item.is_frozen = true;
|
||||||
|
active_count -= 1;
|
||||||
|
total_shrink -= item.flex_shrink;
|
||||||
|
total_grow -= item.flex_grow;
|
||||||
|
total_scaled -= item.flex_shrink * item.base_size.0 as f32;
|
||||||
|
} else {
|
||||||
|
total_variation += variation;
|
||||||
|
item.main_size += variation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.free_space -= total_variation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,38 +337,97 @@ pub struct FlexFlow {
|
||||||
block_flow: BlockFlow,
|
block_flow: BlockFlow,
|
||||||
/// The logical axis which the main axis will be parallel with.
|
/// The logical axis which the main axis will be parallel with.
|
||||||
/// The cross axis will be parallel with the opposite logical axis.
|
/// The cross axis will be parallel with the opposite logical axis.
|
||||||
main_mode: Mode,
|
main_mode: Direction,
|
||||||
/// The available main axis size
|
/// The available main axis size
|
||||||
available_main_size: AxisSize,
|
available_main_size: AxisSize,
|
||||||
/// The available cross axis size
|
/// The available cross axis size
|
||||||
available_cross_size: AxisSize,
|
available_cross_size: AxisSize,
|
||||||
|
/// List of flex lines in the container.
|
||||||
|
lines: Vec<FlexLine>,
|
||||||
/// List of flex-items that belong to this flex-container
|
/// List of flex-items that belong to this flex-container
|
||||||
items: Vec<FlexItem>,
|
items: Vec<FlexItem>,
|
||||||
/// True if the flex-direction is *-reversed
|
/// True if the flex-direction is *-reversed
|
||||||
is_reverse: bool
|
main_reverse: bool,
|
||||||
|
/// True if this flex container can be multiline.
|
||||||
|
is_wrappable: bool,
|
||||||
|
/// True if the cross direction is reversed.
|
||||||
|
cross_reverse: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlexFlow {
|
impl FlexFlow {
|
||||||
pub fn from_fragment(fragment: Fragment,
|
pub fn from_fragment(fragment: Fragment,
|
||||||
flotation: Option<FloatKind>)
|
flotation: Option<FloatKind>)
|
||||||
-> FlexFlow {
|
-> FlexFlow {
|
||||||
let (main_mode, is_reverse) = match fragment.style.get_position().flex_direction {
|
let main_mode;
|
||||||
flex_direction::T::row => (Mode::Inline, false),
|
let main_reverse;
|
||||||
flex_direction::T::row_reverse => (Mode::Inline, true),
|
let is_wrappable;
|
||||||
flex_direction::T::column => (Mode::Block, false),
|
let cross_reverse;
|
||||||
flex_direction::T::column_reverse => (Mode::Block, true),
|
{
|
||||||
};
|
let style = fragment.style();
|
||||||
|
let (mode, reverse) = match style.get_position().flex_direction {
|
||||||
|
flex_direction::T::row => (Direction::Inline, false),
|
||||||
|
flex_direction::T::row_reverse => (Direction::Inline, true),
|
||||||
|
flex_direction::T::column => (Direction::Block, false),
|
||||||
|
flex_direction::T::column_reverse => (Direction::Block, true),
|
||||||
|
};
|
||||||
|
main_mode = mode;
|
||||||
|
main_reverse =
|
||||||
|
reverse == style.writing_mode.is_bidi_ltr();
|
||||||
|
let (wrappable, reverse) = match fragment.style.get_position().flex_wrap {
|
||||||
|
flex_wrap::T::nowrap => (false, false),
|
||||||
|
flex_wrap::T::wrap => (true, false),
|
||||||
|
flex_wrap::T::wrap_reverse => (true, true),
|
||||||
|
};
|
||||||
|
is_wrappable = wrappable;
|
||||||
|
// TODO(stshine): Handle vertical writing mode.
|
||||||
|
cross_reverse = reverse;
|
||||||
|
}
|
||||||
|
|
||||||
FlexFlow {
|
FlexFlow {
|
||||||
block_flow: BlockFlow::from_fragment(fragment, flotation),
|
block_flow: BlockFlow::from_fragment(fragment, flotation),
|
||||||
main_mode: main_mode,
|
main_mode: main_mode,
|
||||||
available_main_size: AxisSize::Infinite,
|
available_main_size: AxisSize::Infinite,
|
||||||
available_cross_size: AxisSize::Infinite,
|
available_cross_size: AxisSize::Infinite,
|
||||||
|
lines: Vec::new(),
|
||||||
items: Vec::new(),
|
items: Vec::new(),
|
||||||
is_reverse: is_reverse
|
main_reverse: main_reverse,
|
||||||
|
is_wrappable: is_wrappable,
|
||||||
|
cross_reverse: cross_reverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a line start after the last item that is already in a line.
|
||||||
|
/// Note that when the container main size is infinite(i.e. A column flexbox with auto height),
|
||||||
|
/// we do not need to do flex resolving and this can be considered as a fast-path, so the
|
||||||
|
/// 'container_size' param does not need to be 'None'. A line has to contain at least one item;
|
||||||
|
/// (except this) if the container can be multi-line the sum of outer main size of items should
|
||||||
|
/// be less than the container size; a line should be filled by items as much as possible.
|
||||||
|
/// After been collected in a line a item should have its main sizes initialized.
|
||||||
|
fn get_flex_line(&mut self, container_size: Au) -> Option<FlexLine> {
|
||||||
|
let start = self.lines.last().map(|line| line.range.end).unwrap_or(0);
|
||||||
|
if start == self.items.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut end = start;
|
||||||
|
let mut total_line_size = Au(0);
|
||||||
|
let mut margin_count = 0;
|
||||||
|
|
||||||
|
let items = &mut self.items[start..];
|
||||||
|
for mut item in items {
|
||||||
|
item.init_sizes(container_size, self.main_mode);
|
||||||
|
let outer_main_size = item.outer_main_size(self.main_mode);
|
||||||
|
if total_line_size + outer_main_size > container_size && end != start && self.is_wrappable {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
margin_count += item.auto_margin_count(self.main_mode);
|
||||||
|
total_line_size += outer_main_size;
|
||||||
|
end += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let line = FlexLine::new(start..end, container_size - total_line_size, margin_count);
|
||||||
|
Some(line)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(zentner): This function should use flex-basis.
|
// TODO(zentner): This function should use flex-basis.
|
||||||
// Currently, this is the core of BlockFlow::bubble_inline_sizes() with all float logic
|
// Currently, this is the core of BlockFlow::bubble_inline_sizes() with all float logic
|
||||||
// stripped out, and max replaced with union_nonbreaking_inline.
|
// stripped out, and max replaced with union_nonbreaking_inline.
|
||||||
|
@ -226,9 +527,6 @@ impl FlexFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(zentner): This function should actually flex elements!
|
|
||||||
// Currently, this is the core of InlineFlow::propagate_assigned_inline_size_to_children() with
|
|
||||||
// fragment logic stripped out.
|
|
||||||
fn inline_mode_assign_inline_sizes(&mut self,
|
fn inline_mode_assign_inline_sizes(&mut self,
|
||||||
_shared_context: &SharedStyleContext,
|
_shared_context: &SharedStyleContext,
|
||||||
inline_start_content_edge: Au,
|
inline_start_content_edge: Au,
|
||||||
|
@ -251,43 +549,113 @@ impl FlexFlow {
|
||||||
AxisSize::Infinite => content_inline_size,
|
AxisSize::Infinite => content_inline_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
let even_content_inline_size = inline_size / child_count;
|
|
||||||
|
|
||||||
let container_mode = self.block_flow.base.block_container_writing_mode;
|
let container_mode = self.block_flow.base.block_container_writing_mode;
|
||||||
self.block_flow.base.position.size.inline = inline_size;
|
self.block_flow.base.position.size.inline = inline_size;
|
||||||
|
|
||||||
let block_container_explicit_block_size = self.block_flow.base.block_container_explicit_block_size;
|
// Calculate non-auto block size to pass to children.
|
||||||
let mut inline_child_start = if !self.is_reverse {
|
let box_border = self.block_flow.fragment.box_sizing_boundary(Direction::Block);
|
||||||
inline_start_content_edge
|
|
||||||
} else {
|
|
||||||
self.block_flow.fragment.border_box.size.inline
|
|
||||||
};
|
|
||||||
for kid in &mut self.items {
|
|
||||||
let base = flow::mut_base(flow_ref::deref_mut(&mut kid.flow));
|
|
||||||
|
|
||||||
base.block_container_inline_size = even_content_inline_size;
|
let parent_container_size = self.block_flow.explicit_block_containing_size(_shared_context);
|
||||||
base.block_container_writing_mode = container_mode;
|
// https://drafts.csswg.org/css-ui-3/#box-sizing
|
||||||
base.block_container_explicit_block_size = block_container_explicit_block_size;
|
let explicit_content_size = self
|
||||||
if !self.is_reverse {
|
.block_flow
|
||||||
base.position.start.i = inline_child_start;
|
.explicit_block_size(parent_container_size)
|
||||||
inline_child_start = inline_child_start + even_content_inline_size;
|
.map(|x| max(x - box_border, Au(0)));
|
||||||
|
let containing_block_text_align =
|
||||||
|
self.block_flow.fragment.style().get_inheritedtext().text_align;
|
||||||
|
|
||||||
|
while let Some(mut line) = self.get_flex_line(inline_size) {
|
||||||
|
let items = &mut self.items[line.range.clone()];
|
||||||
|
line.flex_resolve(items, false);
|
||||||
|
// TODO(stshine): if this flex line contain children that have
|
||||||
|
// property visibility:collapse, exclude them and resolve again.
|
||||||
|
|
||||||
|
let item_count = items.len() as i32;
|
||||||
|
let mut cur_i = inline_start_content_edge;
|
||||||
|
let item_interval = if line.free_space >= Au(0) && line.auto_margin_count == 0 {
|
||||||
|
match self.block_flow.fragment.style().get_position().justify_content {
|
||||||
|
justify_content::T::space_between => {
|
||||||
|
if item_count == 1 {
|
||||||
|
Au(0)
|
||||||
|
} else {
|
||||||
|
line.free_space / (item_count - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
justify_content::T::space_around => {
|
||||||
|
line.free_space / item_count
|
||||||
|
}
|
||||||
|
_ => Au(0),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
base.position.start.i = inline_child_start - base.intrinsic_inline_sizes.preferred_inline_size;
|
Au(0)
|
||||||
inline_child_start = inline_child_start - even_content_inline_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
match self.block_flow.fragment.style().get_position().justify_content {
|
||||||
|
// Overflow equally in both ends of line.
|
||||||
|
justify_content::T::center | justify_content::T::space_around => {
|
||||||
|
cur_i += (line.free_space - item_interval * (item_count - 1)) / 2;
|
||||||
|
}
|
||||||
|
justify_content::T::flex_end => {
|
||||||
|
cur_i += line.free_space;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for item in items.iter_mut() {
|
||||||
|
let mut block = flow_ref::deref_mut(&mut item.flow).as_mut_block();
|
||||||
|
|
||||||
|
block.base.block_container_writing_mode = container_mode;
|
||||||
|
block.base.block_container_inline_size = inline_size;
|
||||||
|
block.base.block_container_explicit_block_size = explicit_content_size;
|
||||||
|
// Per CSS 2.1 § 16.3.1, text alignment propagates to all children in flow.
|
||||||
|
//
|
||||||
|
// TODO(#2265, pcwalton): Do this in the cascade instead.
|
||||||
|
block.base.flags.set_text_align(containing_block_text_align);
|
||||||
|
// FIXME(stshine): should this be done during construction?
|
||||||
|
block.mark_as_flex();
|
||||||
|
|
||||||
|
let margin = block.fragment.style().logical_margin();
|
||||||
|
let auto_len =
|
||||||
|
if line.auto_margin_count == 0 || line.free_space <= Au(0) {
|
||||||
|
Au(0)
|
||||||
|
} else {
|
||||||
|
line.free_space / line.auto_margin_count
|
||||||
|
};
|
||||||
|
let margin_inline_start = MaybeAuto::from_style(margin.inline_start, inline_size)
|
||||||
|
.specified_or_default(auto_len);
|
||||||
|
let margin_inline_end = MaybeAuto::from_style(margin.inline_end, inline_size)
|
||||||
|
.specified_or_default(auto_len);
|
||||||
|
let item_inline_size = item.main_size
|
||||||
|
- block.fragment.box_sizing_boundary(self.main_mode)
|
||||||
|
+ block.fragment.border_padding.inline_start_end();
|
||||||
|
let item_outer_size = item_inline_size + block.fragment.margin.inline_start_end();
|
||||||
|
|
||||||
|
block.fragment.margin.inline_start = margin_inline_start;
|
||||||
|
block.fragment.margin.inline_end = margin_inline_end;
|
||||||
|
block.fragment.border_box.start.i = margin_inline_start;
|
||||||
|
block.fragment.border_box.size.inline = item_inline_size;
|
||||||
|
block.base.position.start.i = if !self.main_reverse {
|
||||||
|
cur_i
|
||||||
|
} else {
|
||||||
|
inline_start_content_edge * 2 + content_inline_size - cur_i - item_outer_size
|
||||||
|
};
|
||||||
|
block.base.position.size.inline = item_outer_size;
|
||||||
|
cur_i += item_outer_size + item_interval;
|
||||||
|
}
|
||||||
|
self.lines.push(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(zentner): This function should actually flex elements!
|
// TODO(zentner): This function should actually flex elements!
|
||||||
fn block_mode_assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
fn block_mode_assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||||
let mut cur_b = if !self.is_reverse {
|
let mut cur_b = if !self.main_reverse {
|
||||||
self.block_flow.fragment.border_padding.block_start
|
self.block_flow.fragment.border_padding.block_start
|
||||||
} else {
|
} else {
|
||||||
self.block_flow.fragment.border_box.size.block
|
self.block_flow.fragment.border_box.size.block
|
||||||
};
|
};
|
||||||
for kid in &mut self.items {
|
for kid in &mut self.items {
|
||||||
let base = flow::mut_base(flow_ref::deref_mut(&mut kid.flow));
|
let base = flow::mut_base(flow_ref::deref_mut(&mut kid.flow));
|
||||||
if !self.is_reverse {
|
if !self.main_reverse {
|
||||||
base.position.start.b = cur_b;
|
base.position.start.b = cur_b;
|
||||||
cur_b = cur_b + base.position.size.block;
|
cur_b = cur_b + base.position.size.block;
|
||||||
} else {
|
} else {
|
||||||
|
@ -298,63 +666,134 @@ impl FlexFlow {
|
||||||
self.block_flow.assign_block_size(layout_context)
|
self.block_flow.assign_block_size(layout_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(zentner): This function should actually flex elements!
|
|
||||||
// Currently, this is the core of TableRowFlow::assign_block_size() with
|
|
||||||
// float related logic stripped out.
|
|
||||||
fn inline_mode_assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
fn inline_mode_assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||||
let _scope = layout_debug_scope!("flex::inline_mode_assign_block_size");
|
let _scope = layout_debug_scope!("flex::inline_mode_assign_block_size");
|
||||||
|
|
||||||
let mut max_block_size = Au(0);
|
let line_count = self.lines.len() as i32;
|
||||||
let thread_id = self.block_flow.base.thread_id;
|
let line_align = self.block_flow.fragment.style().get_position().align_content;
|
||||||
for kid in self.block_flow.base.child_iter_mut() {
|
let mut cur_b = self.block_flow.fragment.border_padding.block_start;
|
||||||
kid.assign_block_size_for_inorder_child_if_necessary(layout_context, thread_id);
|
let mut total_cross_size = Au(0);
|
||||||
|
let mut line_interval = Au(0);
|
||||||
|
|
||||||
{
|
for line in self.lines.iter_mut() {
|
||||||
let child_fragment = &mut kid.as_mut_block().fragment;
|
for item in &self.items[line.range.clone()] {
|
||||||
// TODO: Percentage block-size
|
let ref fragment = item.flow.as_block().fragment;
|
||||||
let child_specified_block_size =
|
line.cross_size = max(line.cross_size,
|
||||||
MaybeAuto::from_style(child_fragment.style().content_block_size(),
|
fragment.border_box.size.block + fragment.margin.block_start_end());
|
||||||
Au(0)).specified_or_zero();
|
|
||||||
max_block_size =
|
|
||||||
max(max_block_size,
|
|
||||||
child_specified_block_size +
|
|
||||||
child_fragment.border_padding.block_start_end());
|
|
||||||
}
|
}
|
||||||
let child_node = flow::mut_base(kid);
|
total_cross_size += line.cross_size;
|
||||||
child_node.position.start.b = Au(0);
|
|
||||||
max_block_size = max(max_block_size, child_node.position.size.block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut block_size = max_block_size;
|
let box_border = self.block_flow.fragment.box_sizing_boundary(Direction::Block);
|
||||||
// TODO: Percentage block-size
|
let parent_container_size =
|
||||||
|
self.block_flow.explicit_block_containing_size(layout_context.shared_context());
|
||||||
|
// https://drafts.csswg.org/css-ui-3/#box-sizing
|
||||||
|
let explicit_content_size = self
|
||||||
|
.block_flow
|
||||||
|
.explicit_block_size(parent_container_size)
|
||||||
|
.map(|x| max(x - box_border, Au(0)));
|
||||||
|
|
||||||
block_size = match MaybeAuto::from_style(self.block_flow
|
if let Some(container_block_size) = explicit_content_size {
|
||||||
.fragment
|
let free_space = container_block_size - total_cross_size;
|
||||||
.style()
|
total_cross_size = container_block_size;
|
||||||
.content_block_size(),
|
|
||||||
Au(0)) {
|
|
||||||
MaybeAuto::Auto => block_size,
|
|
||||||
MaybeAuto::Specified(value) => max(value, block_size),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assign the block-size of own fragment
|
if line_align == align_content::T::stretch && free_space > Au(0) {
|
||||||
let mut position = self.block_flow.fragment.border_box;
|
for line in self.lines.iter_mut() {
|
||||||
position.size.block = block_size;
|
line.cross_size += free_space / line_count;
|
||||||
self.block_flow.fragment.border_box = position;
|
}
|
||||||
self.block_flow.base.position.size.block = block_size;
|
|
||||||
|
|
||||||
// Assign the block-size of kid fragments, which is the same value as own block-size.
|
|
||||||
for kid in self.block_flow.base.child_iter_mut() {
|
|
||||||
{
|
|
||||||
let kid_fragment = &mut kid.as_mut_block().fragment;
|
|
||||||
let mut position = kid_fragment.border_box;
|
|
||||||
position.size.block = block_size;
|
|
||||||
kid_fragment.border_box = position;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign the child's block size.
|
line_interval = match line_align {
|
||||||
flow::mut_base(kid).position.size.block = block_size
|
align_content::T::space_between => {
|
||||||
|
if line_count == 1 {
|
||||||
|
Au(0)
|
||||||
|
} else {
|
||||||
|
free_space / (line_count - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
align_content::T::space_around => {
|
||||||
|
free_space / line_count
|
||||||
|
}
|
||||||
|
_ => Au(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
match line_align {
|
||||||
|
align_content::T::center | align_content::T::space_around => {
|
||||||
|
cur_b += (free_space - line_interval * (line_count - 1)) / 2;
|
||||||
|
}
|
||||||
|
align_content::T::flex_end => {
|
||||||
|
cur_b += free_space;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for line in &self.lines {
|
||||||
|
for mut item in self.items[line.range.clone()].iter_mut() {
|
||||||
|
let auto_margin_count = item.auto_margin_count(Direction::Block);
|
||||||
|
let mut block = flow_ref::deref_mut(&mut item.flow).as_mut_block();
|
||||||
|
let margin = block.fragment.style().logical_margin();
|
||||||
|
|
||||||
|
let mut margin_block_start = block.fragment.margin.block_start;
|
||||||
|
let mut margin_block_end = block.fragment.margin.block_end;
|
||||||
|
let mut free_space = line.cross_size - block.base.position.size.block
|
||||||
|
- block.fragment.margin.block_start_end();
|
||||||
|
|
||||||
|
// The spec is a little vague here, but if I understand it correctly, the outer
|
||||||
|
// cross size of item should equal to the line size if any auto margin exists.
|
||||||
|
// https://drafts.csswg.org/css-flexbox/#algo-cross-margins
|
||||||
|
if auto_margin_count > 0 {
|
||||||
|
if margin.block_start == LengthOrPercentageOrAuto::Auto {
|
||||||
|
margin_block_start = if free_space < Au(0) {
|
||||||
|
Au(0)
|
||||||
|
} else {
|
||||||
|
free_space / auto_margin_count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
margin_block_end = line.cross_size - margin_block_start - block.base.position.size.block;
|
||||||
|
free_space = Au(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let self_align = block.fragment.style().get_position().align_self;
|
||||||
|
if self_align == align_self::T::stretch &&
|
||||||
|
block.fragment.style().content_block_size() == LengthOrPercentageOrAuto::Auto {
|
||||||
|
free_space = Au(0);
|
||||||
|
block.base.block_container_explicit_block_size = Some(line.cross_size);
|
||||||
|
block.base.position.size.block =
|
||||||
|
line.cross_size - margin_block_start - margin_block_end;
|
||||||
|
block.fragment.border_box.size.block = block.base.position.size.block;
|
||||||
|
// FIXME(stshine): item with 'align-self: stretch' and auto cross size should act
|
||||||
|
// as if it has a fixed cross size, all child blocks should resolve against it.
|
||||||
|
// block.assign_block_size(layout_context);
|
||||||
|
}
|
||||||
|
block.base.position.start.b = margin_block_start +
|
||||||
|
if !self.cross_reverse {
|
||||||
|
cur_b
|
||||||
|
} else {
|
||||||
|
self.block_flow.fragment.border_padding.block_start * 2
|
||||||
|
+ total_cross_size - cur_b - line.cross_size
|
||||||
|
};
|
||||||
|
// TODO(stshine): support baseline alignment.
|
||||||
|
if free_space != Au(0) {
|
||||||
|
let flex_cross = match self_align {
|
||||||
|
align_self::T::flex_end => free_space,
|
||||||
|
align_self::T::center => free_space / 2,
|
||||||
|
_ => Au(0),
|
||||||
|
};
|
||||||
|
block.base.position.start.b +=
|
||||||
|
if !self.cross_reverse {
|
||||||
|
flex_cross
|
||||||
|
} else {
|
||||||
|
free_space - flex_cross
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur_b += line_interval + line.cross_size;
|
||||||
|
}
|
||||||
|
let total_block_size = total_cross_size + self.block_flow.fragment.border_padding.block_start_end();
|
||||||
|
self.block_flow.fragment.border_box.size.block = total_block_size;
|
||||||
|
self.block_flow.base.position.size.block = total_block_size;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,24 +821,19 @@ impl Flow for FlexFlow {
|
||||||
// Flexbox Section 9.0: Generate anonymous flex items:
|
// Flexbox Section 9.0: Generate anonymous flex items:
|
||||||
// This part was handled in the flow constructor.
|
// This part was handled in the flow constructor.
|
||||||
|
|
||||||
// Flexbox Section 9.1: Re-order the flex items (and any absolutely positioned flex
|
// Flexbox Section 9.1: Re-order flex items according to their order.
|
||||||
// container children) according to their order.
|
// FIXME(stshine): This should be done during flow construction.
|
||||||
|
let mut items = self.block_flow.base.children.iter_flow_ref_mut()
|
||||||
let mut items = self.block_flow.base.children.iter_flow_ref_mut().map(|flow| {
|
.filter(|flow| !flow.as_block().base.flags.contains(IS_ABSOLUTELY_POSITIONED))
|
||||||
FlexItem::new(flow.clone())
|
.map(|flow| FlexItem::new(flow.clone()))
|
||||||
}).collect::<Vec<FlexItem>>();
|
.collect::<Vec<FlexItem>>();
|
||||||
|
|
||||||
items.sort_by(|item1, item2| {
|
|
||||||
item1.flow.as_block().fragment.style.get_position().order.cmp(
|
|
||||||
&item2.flow.as_block().fragment.style.get_position().order
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
|
items.sort_by_key(|item| item.order);
|
||||||
self.items = items;
|
self.items = items;
|
||||||
|
|
||||||
match self.main_mode {
|
match self.main_mode {
|
||||||
Mode::Inline => self.inline_mode_bubble_inline_sizes(),
|
Direction::Inline => self.inline_mode_bubble_inline_sizes(),
|
||||||
Mode::Block => self.block_mode_bubble_inline_sizes()
|
Direction::Block => self.block_mode_bubble_inline_sizes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,15 +892,15 @@ impl Flow for FlexFlow {
|
||||||
let content_inline_size = self.block_flow.fragment.border_box.size.inline - padding_and_borders;
|
let content_inline_size = self.block_flow.fragment.border_box.size.inline - padding_and_borders;
|
||||||
|
|
||||||
match self.main_mode {
|
match self.main_mode {
|
||||||
Mode::Inline => {
|
Direction::Inline => {
|
||||||
self.available_main_size = available_inline_size;
|
self.available_main_size = available_inline_size;
|
||||||
self.available_cross_size = available_block_size;
|
self.available_cross_size = available_block_size;
|
||||||
self.inline_mode_assign_inline_sizes(shared_context,
|
self.inline_mode_assign_inline_sizes(shared_context,
|
||||||
inline_start_content_edge,
|
inline_start_content_edge,
|
||||||
inline_end_content_edge,
|
inline_end_content_edge,
|
||||||
content_inline_size)
|
content_inline_size)
|
||||||
},
|
}
|
||||||
Mode::Block => {
|
Direction::Block => {
|
||||||
self.available_main_size = available_block_size;
|
self.available_main_size = available_block_size;
|
||||||
self.available_cross_size = available_inline_size;
|
self.available_cross_size = available_inline_size;
|
||||||
self.block_mode_assign_inline_sizes(shared_context,
|
self.block_mode_assign_inline_sizes(shared_context,
|
||||||
|
@ -480,9 +914,9 @@ impl Flow for FlexFlow {
|
||||||
fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||||
self.block_flow.assign_block_size(layout_context);
|
self.block_flow.assign_block_size(layout_context);
|
||||||
match self.main_mode {
|
match self.main_mode {
|
||||||
Mode::Inline =>
|
Direction::Inline =>
|
||||||
self.inline_mode_assign_block_size(layout_context),
|
self.inline_mode_assign_block_size(layout_context),
|
||||||
Mode::Block =>
|
Direction::Block =>
|
||||||
self.block_mode_assign_block_size(layout_context)
|
self.block_mode_assign_block_size(layout_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT};
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
|
use model::{self, Direction, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::image::base::{Image, ImageMetadata};
|
use net_traits::image::base::{Image, ImageMetadata};
|
||||||
use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
|
use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
|
||||||
|
@ -39,7 +39,7 @@ use std::fmt;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use style::arc_ptr_eq;
|
use style::arc_ptr_eq;
|
||||||
use style::computed_values::content::ContentItem;
|
use style::computed_values::content::ContentItem;
|
||||||
use style::computed_values::{border_collapse, clear, color, display, mix_blend_mode};
|
use style::computed_values::{border_collapse, box_sizing, clear, color, display, mix_blend_mode};
|
||||||
use style::computed_values::{overflow_wrap, overflow_x, position, text_decoration};
|
use style::computed_values::{overflow_wrap, overflow_x, position, text_decoration};
|
||||||
use style::computed_values::{transform_style, vertical_align, white_space, word_break, z_index};
|
use style::computed_values::{transform_style, vertical_align, white_space, word_break, z_index};
|
||||||
use style::dom::TRestyleDamage;
|
use style::dom::TRestyleDamage;
|
||||||
|
@ -1109,6 +1109,20 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the border width in given direction if this fragment has property
|
||||||
|
/// 'box-sizing: border-box'. The `border_padding` field should have been initialized.
|
||||||
|
pub fn box_sizing_boundary(&self, direction: Direction) -> Au {
|
||||||
|
match (self.style().get_position().box_sizing, direction) {
|
||||||
|
(box_sizing::T::border_box, Direction::Inline) => {
|
||||||
|
self.border_padding.inline_start_end()
|
||||||
|
}
|
||||||
|
(box_sizing::T::border_box, Direction::Block) => {
|
||||||
|
self.border_padding.block_start_end()
|
||||||
|
}
|
||||||
|
_ => Au(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes the margins in the inline direction from the containing block inline-size and the
|
/// Computes the margins in the inline direction from the containing block inline-size and the
|
||||||
/// style. After this call, the inline direction of the `margin` field will be correct.
|
/// style. After this call, the inline direction of the `margin` field will be correct.
|
||||||
///
|
///
|
||||||
|
|
|
@ -502,6 +502,13 @@ impl ToGfxMatrix for ComputedMatrix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used to specify the logical direction.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Direction {
|
||||||
|
Inline,
|
||||||
|
Block
|
||||||
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
||||||
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
|
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
|
||||||
/// A min or max constraint
|
/// A min or max constraint
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[align-content-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[align-content-002.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[align-content-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[align-content-005.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[align-content-006.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[align-self-005.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[css-box-justify-content.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-002.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-004.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-align-items-center.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-basis-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-basis-002.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-basis-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-basis-004.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-basis-005.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-basis-006.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-basis-008.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-box-wrap.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-container-margin.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-direction-modify.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-flow-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-flow-002.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-flow-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-flow-004.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-flow-005.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-flow-006.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-grow-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-grow-002.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-grow-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-grow-005.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-items-flexibility.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-shrink-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-shrink-002.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-shrink-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-shrink-004.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-shrink-005.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-shrink-006.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flex-shrink-007.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-abspos-child-001a.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-anonymous-items-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-basic-block-horiz-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-flex-wrap-default.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-flex-wrap-horiz-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-flex-wrap-horiz-002.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-flex-wrap-nowrap.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-items-as-stacking-contexts-002.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-items-as-stacking-contexts-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-justify-content-horiz-001a.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-justify-content-horiz-001b.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-justify-content-horiz-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-mbp-horiz-001-reverse.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-mbp-horiz-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-mbp-horiz-002a.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-mbp-horiz-002b.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-mbp-horiz-003-reverse.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-mbp-horiz-003.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-whitespace-handling-001b.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox-writing-mode-007.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-content-center.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-content-flexend.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-content-flexstart.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-content-spacearound.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-content-spacebetween.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-content-stretch-2.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-content-stretch.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-items-center-2.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-items-center.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-items-flexend-2.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-items-flexend.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-items-flexstart-2.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-items-flexstart.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[flexbox_align-items-stretch-writing-modes.htm]
|
||||||
|
type: reftest
|
||||||
|
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-items-stretch.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-self-auto.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-self-baseline.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-self-center.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-self-flexend.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-self-flexstart.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_align-self-stretch.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,5 +1,4 @@
|
||||||
[flexbox_computedstyle_min-width-auto.htm]
|
[flexbox_computedstyle_min-width-auto.htm]
|
||||||
type: testharness
|
type: testharness
|
||||||
[flexbox | computed style | min-width: auto]
|
expected: TIMEOUT
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
[flexbox_direction-row-reverse.htm]
|
[flexbox_direction-row-reverse.htm]
|
||||||
type: reftest
|
type: reftest
|
||||||
expected: FAIL
|
expected:
|
||||||
|
if os == "mac": FAIL
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-0-1-unitless-basis.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-0-N-shrink.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-0-N-unitless-basis.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-0-N.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-0-Npercent-shrink.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-0-Npercent.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-0-auto-shrink.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-0-auto.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-1-1-unitless-basis.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-1-N-shrink.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-1-N-unitless-basis.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-1-N.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-1-Npercent-shrink.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[flexbox_flex-0-1-Npercent.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue