mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implement flexbox reordering
Add style property for order and implement reordering by this property in flex flow. Based on previous work by @zentner-kyle.
This commit is contained in:
parent
b214205ba9
commit
3580f91291
10 changed files with 96 additions and 69 deletions
|
@ -13,9 +13,9 @@ use display_list_builder::{DisplayListBuildState, FlexFlowDisplayListBuilding};
|
|||
use euclid::Point2D;
|
||||
use floats::FloatKind;
|
||||
use flow;
|
||||
use flow::INLINE_POSITION_IS_STATIC;
|
||||
use flow::IS_ABSOLUTELY_POSITIONED;
|
||||
use flow::{Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
|
||||
use flow::{INLINE_POSITION_IS_STATIC, IS_ABSOLUTELY_POSITIONED};
|
||||
use flow_ref::{self, FlowRef};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
||||
use gfx::display_list::{StackingContext, StackingContextId};
|
||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||
|
@ -73,6 +73,19 @@ enum Mode {
|
|||
Block
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FlexItem {
|
||||
pub flow: FlowRef,
|
||||
}
|
||||
|
||||
impl FlexItem {
|
||||
fn new(flow: FlowRef) -> FlexItem {
|
||||
FlexItem {
|
||||
flow: flow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A block with the CSS `display` property equal to `flex`.
|
||||
#[derive(Debug)]
|
||||
pub struct FlexFlow {
|
||||
|
@ -84,23 +97,9 @@ pub struct FlexFlow {
|
|||
/// The available main axis size
|
||||
available_main_size: AxisSize,
|
||||
/// The available cross axis size
|
||||
available_cross_size: AxisSize
|
||||
}
|
||||
|
||||
// TODO(zentner): This function should use flex-basis.
|
||||
fn flex_item_inline_sizes(flow: &mut Flow) -> IntrinsicISizes {
|
||||
let _scope = layout_debug_scope!("flex::flex_item_inline_sizes");
|
||||
debug!("flex_item_inline_sizes");
|
||||
let base = flow::mut_base(flow);
|
||||
|
||||
debug!("FlexItem intrinsic inline sizes: {:?}, {:?}",
|
||||
base.intrinsic_inline_sizes.minimum_inline_size,
|
||||
base.intrinsic_inline_sizes.preferred_inline_size);
|
||||
|
||||
IntrinsicISizes {
|
||||
minimum_inline_size: base.intrinsic_inline_sizes.minimum_inline_size,
|
||||
preferred_inline_size: base.intrinsic_inline_sizes.preferred_inline_size,
|
||||
}
|
||||
available_cross_size: AxisSize,
|
||||
/// List of flex-items that belong to this flex-container
|
||||
items: Vec<FlexItem>
|
||||
}
|
||||
|
||||
impl FlexFlow {
|
||||
|
@ -117,7 +116,8 @@ impl FlexFlow {
|
|||
block_flow: BlockFlow::from_fragment(fragment, flotation),
|
||||
main_mode: main_mode,
|
||||
available_main_size: AxisSize::Infinite,
|
||||
available_cross_size: AxisSize::Infinite
|
||||
available_cross_size: AxisSize::Infinite,
|
||||
items: Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,11 +132,15 @@ impl FlexFlow {
|
|||
|
||||
let mut computation = self.block_flow.fragment.compute_intrinsic_inline_sizes();
|
||||
if !fixed_width {
|
||||
for kid in self.block_flow.base.child_iter_mut() {
|
||||
let is_absolutely_positioned =
|
||||
flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED);
|
||||
for kid in &mut self.items {
|
||||
let base = flow::mut_base(flow_ref::deref_mut(&mut kid.flow));
|
||||
let is_absolutely_positioned = base.flags.contains(IS_ABSOLUTELY_POSITIONED);
|
||||
if !is_absolutely_positioned {
|
||||
computation.union_nonbreaking_inline(&flex_item_inline_sizes(kid));
|
||||
let flex_item_inline_sizes = IntrinsicISizes {
|
||||
minimum_inline_size: base.intrinsic_inline_sizes.minimum_inline_size,
|
||||
preferred_inline_size: base.intrinsic_inline_sizes.preferred_inline_size,
|
||||
};
|
||||
computation.union_nonbreaking_inline(&flex_item_inline_sizes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,18 +158,17 @@ impl FlexFlow {
|
|||
|
||||
let mut computation = self.block_flow.fragment.compute_intrinsic_inline_sizes();
|
||||
if !fixed_width {
|
||||
for kid in self.block_flow.base.child_iter_mut() {
|
||||
let is_absolutely_positioned =
|
||||
flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED);
|
||||
let child_base = flow::mut_base(kid);
|
||||
for kid in &mut self.items {
|
||||
let base = flow::mut_base(flow_ref::deref_mut(&mut kid.flow));
|
||||
let is_absolutely_positioned = base.flags.contains(IS_ABSOLUTELY_POSITIONED);
|
||||
if !is_absolutely_positioned {
|
||||
computation.content_intrinsic_sizes.minimum_inline_size =
|
||||
max(computation.content_intrinsic_sizes.minimum_inline_size,
|
||||
child_base.intrinsic_inline_sizes.minimum_inline_size);
|
||||
base.intrinsic_inline_sizes.minimum_inline_size);
|
||||
|
||||
computation.content_intrinsic_sizes.preferred_inline_size =
|
||||
max(computation.content_intrinsic_sizes.preferred_inline_size,
|
||||
child_base.intrinsic_inline_sizes.preferred_inline_size);
|
||||
base.intrinsic_inline_sizes.preferred_inline_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,21 +198,15 @@ impl FlexFlow {
|
|||
AxisSize::MinMax(ref constraint) => constraint.clamp(content_inline_size),
|
||||
AxisSize::Infinite => content_inline_size
|
||||
};
|
||||
let mut iterator = self.block_flow.base.child_iter_mut().enumerate().peekable();
|
||||
while let Some((_, kid)) = iterator.next() {
|
||||
for kid in &mut self.items {
|
||||
{
|
||||
let kid_base = flow::mut_base(kid);
|
||||
let kid_base = flow::mut_base(flow_ref::deref_mut(&mut kid.flow));
|
||||
kid_base.block_container_explicit_block_size = container_block_size;
|
||||
}
|
||||
|
||||
// The inline-start margin edge of the child flow is at our inline-start content edge,
|
||||
// and its inline-size is our content inline-size.
|
||||
let kid_mode = flow::base(kid).writing_mode;
|
||||
{
|
||||
let kid_base = flow::mut_base(kid);
|
||||
if kid_base.flags.contains(INLINE_POSITION_IS_STATIC) {
|
||||
// The inline-start margin edge of the child flow is at our inline-start content edge,
|
||||
// and its inline-size is our content inline-size.
|
||||
kid_base.position.start.i =
|
||||
if kid_mode.is_bidi_ltr() == containing_block_mode.is_bidi_ltr() {
|
||||
if kid_base.writing_mode.is_bidi_ltr() == containing_block_mode.is_bidi_ltr() {
|
||||
inline_start_content_edge
|
||||
} else {
|
||||
// The kid's inline 'start' is at the parent's 'end'
|
||||
|
@ -218,6 +215,7 @@ impl FlexFlow {
|
|||
}
|
||||
kid_base.block_container_inline_size = container_inline_size;
|
||||
kid_base.block_container_writing_mode = containing_block_mode;
|
||||
kid_base.position.start.i = inline_start_content_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,19 +252,25 @@ impl FlexFlow {
|
|||
|
||||
let block_container_explicit_block_size = self.block_flow.base.block_container_explicit_block_size;
|
||||
let mut inline_child_start = inline_start_content_edge;
|
||||
for kid in self.block_flow.base.child_iter_mut() {
|
||||
let kid_base = flow::mut_base(kid);
|
||||
for kid in &mut self.items {
|
||||
let base = flow::mut_base(flow_ref::deref_mut(&mut kid.flow));
|
||||
|
||||
kid_base.block_container_inline_size = even_content_inline_size;
|
||||
kid_base.block_container_writing_mode = container_mode;
|
||||
kid_base.block_container_explicit_block_size = block_container_explicit_block_size;
|
||||
kid_base.position.start.i = inline_child_start;
|
||||
base.block_container_inline_size = even_content_inline_size;
|
||||
base.block_container_writing_mode = container_mode;
|
||||
base.block_container_explicit_block_size = block_container_explicit_block_size;
|
||||
base.position.start.i = inline_child_start;
|
||||
inline_child_start = inline_child_start + even_content_inline_size;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(zentner): This function should actually flex elements!
|
||||
fn block_mode_assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||
let mut cur_b = self.block_flow.fragment.border_padding.block_start;
|
||||
for kid in &mut self.items {
|
||||
let base = flow::mut_base(flow_ref::deref_mut(&mut kid.flow));
|
||||
base.position.start.b = cur_b;
|
||||
cur_b = cur_b + base.position.size.block;
|
||||
}
|
||||
self.block_flow.assign_block_size(layout_context)
|
||||
}
|
||||
|
||||
|
@ -335,6 +339,10 @@ impl Flow for FlexFlow {
|
|||
FlowClass::Flex
|
||||
}
|
||||
|
||||
fn as_block(&self) -> &BlockFlow {
|
||||
&self.block_flow
|
||||
}
|
||||
|
||||
fn as_mut_block(&mut self) -> &mut BlockFlow {
|
||||
&mut self.block_flow
|
||||
}
|
||||
|
@ -352,8 +360,18 @@ impl Flow for FlexFlow {
|
|||
|
||||
// Flexbox Section 9.1: Re-order the flex items (and any absolutely positioned flex
|
||||
// container children) according to their order.
|
||||
// TODO(zentner): We need to re-order the items at some point. However, all the operations
|
||||
// here ignore order, so we can afford to do it later, if necessary.
|
||||
|
||||
let mut items = self.block_flow.base.children.iter_flow_ref_mut().map(|flow| {
|
||||
FlexItem::new(flow.clone())
|
||||
}).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
|
||||
)
|
||||
});
|
||||
|
||||
self.items = items;
|
||||
|
||||
match self.main_mode {
|
||||
Mode::Inline => self.inline_mode_bubble_inline_sizes(),
|
||||
|
|
|
@ -64,6 +64,12 @@ impl FlowList {
|
|||
}
|
||||
}
|
||||
|
||||
/// Provide a forward iterator with FlowRef items
|
||||
#[inline]
|
||||
pub fn iter_flow_ref_mut<'a>(&'a mut self) -> linked_list::IterMut<'a, FlowRef> {
|
||||
self.flows.iter_mut()
|
||||
}
|
||||
|
||||
/// O(1)
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
|
|
@ -310,4 +310,5 @@ partial interface CSSStyleDeclaration {
|
|||
|
||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString flexDirection;
|
||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString flex-direction;
|
||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString order;
|
||||
};
|
||||
|
|
|
@ -4906,6 +4906,28 @@ pub mod longhands {
|
|||
|
||||
// Flex container properties
|
||||
${single_keyword("flex-direction", "row row-reverse column column-reverse", experimental=True)}
|
||||
|
||||
// https://drafts.csswg.org/css-flexbox/#propdef-order
|
||||
<%self:longhand name="order">
|
||||
use values::computed::ComputedValueAsSpecified;
|
||||
|
||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
||||
|
||||
pub type SpecifiedValue = computed_value::T;
|
||||
|
||||
pub mod computed_value {
|
||||
pub type T = i32;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
0
|
||||
}
|
||||
|
||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||
specified::parse_integer(input)
|
||||
}
|
||||
</%self:longhand>
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[flexbox_computedstyle_order-inherit.htm]
|
||||
type: reftest
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[flexbox_computedstyle_order-integer.htm]
|
||||
type: reftest
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[flexbox_computedstyle_order-invalid.htm]
|
||||
type: reftest
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[flexbox_computedstyle_order-negative.htm]
|
||||
type: reftest
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[flexbox_computedstyle_order.htm]
|
||||
type: reftest
|
||||
expected: FAIL
|
|
@ -1,5 +0,0 @@
|
|||
[order_value.htm]
|
||||
type: testharness
|
||||
[CSS Flexible Box Test: order_check]
|
||||
expected: FAIL
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue