Skip to content

Commit

Permalink
Implement flexbox reordering
Browse files Browse the repository at this point in the history
Add style property for order and implement reordering by this property
in flex flow. Based on previous work by @zentner-kyle.
  • Loading branch information
dlrobertson committed Apr 11, 2016
1 parent b214205 commit 3580f91
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 69 deletions.
116 changes: 67 additions & 49 deletions components/layout/flex.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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()
}
}

Expand All @@ -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);
}
}
}
Expand All @@ -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);
}
}
}
Expand Down Expand Up @@ -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'
Expand All @@ -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;
}
}
}
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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
}
Expand All @@ -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(),
Expand Down
6 changes: 6 additions & 0 deletions components/layout/flow_list.rs
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions components/script/dom/webidls/CSSStyleDeclaration.webidl
Expand Up @@ -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;
};
22 changes: 22 additions & 0 deletions components/style/properties.mako.rs
Expand Up @@ -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>
}


Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

0 comments on commit 3580f91

Please sign in to comment.