aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/block.rs
diff options
context:
space:
mode:
authorMatt Brubeck <mbrubeck@limpet.net>2015-02-24 16:43:43 -0800
committerMatt Brubeck <mbrubeck@limpet.net>2015-03-09 14:21:26 -0700
commit8221bfc3ef854d90ecb9a0df3aa490310cbe8469 (patch)
treedd17d192a5944fafad6875addbd21fc2941360d2 /components/layout/block.rs
parent7cd776b74f7996894965deb8700adb6ef46d705d (diff)
downloadservo-8221bfc3ef854d90ecb9a0df3aa490310cbe8469.tar.gz
servo-8221bfc3ef854d90ecb9a0df3aa490310cbe8469.zip
Layout fixes for RTL child flows in LTR parents
...and vice-versa. This is not a complete fix for all mixed-direction layout cases, but it fixes enough problems to make some simple test cases pass, like tha attached reftest. There are FIXME comments for many of the remaining issues. In particular, this does not yet handle RTL layout of fixed/absolute elements.
Diffstat (limited to 'components/layout/block.rs')
-rw-r--r--components/layout/block.rs104
1 files changed, 82 insertions, 22 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 81edba159b7..356232f90f8 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -54,7 +54,7 @@ use rustc_serialize::{Encoder, Encodable};
use msg::compositor_msg::LayerId;
use msg::constellation_msg::ConstellationChan;
use util::geometry::{Au, MAX_AU};
-use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
+use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
use util::opts;
use std::cmp::{max, min};
use std::fmt;
@@ -1329,6 +1329,8 @@ impl BlockFlow {
} else {
content_inline_size
};
+ // FIXME (mbrubeck): Get correct mode for absolute containing block
+ let containing_block_mode = self.base.writing_mode;
for (i, kid) in self.base.child_iter().enumerate() {
{
@@ -1352,16 +1354,30 @@ impl BlockFlow {
// 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(IS_ABSOLUTELY_POSITIONED) &&
!kid_base.flags.is_float() {
- kid_base.position.start.i = inline_start_content_edge
+ kid_base.position.start.i =
+ if kid_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'
+ inline_start_content_edge + content_inline_size
+ }
}
kid_base.block_container_inline_size = content_inline_size;
+ kid_base.block_container_writing_mode = containing_block_mode;
}
if kid.is_block_like() {
- kid.as_block().hypothetical_position.i = inline_start_content_edge
+ kid.as_block().hypothetical_position.i =
+ if kid_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'
+ inline_start_content_edge + content_inline_size
+ }
}
// Determine float impaction.
@@ -1398,6 +1414,7 @@ impl BlockFlow {
propagate_column_inline_sizes_to_child(kid,
i,
content_inline_size,
+ containing_block_mode,
*column_computed_inline_sizes,
&mut inline_start_margin_edge)
}
@@ -1610,6 +1627,7 @@ impl Flow for BlockFlow {
self.base.position.start = LogicalPoint::zero(self.base.writing_mode);
self.base.block_container_inline_size = LogicalSize::from_physical(
self.base.writing_mode, layout_context.shared.screen_size).inline;
+ self.base.block_container_writing_mode = self.base.writing_mode;
// The root element is never impacted by floats.
self.base.flags.remove(IMPACTED_BY_LEFT_FLOATS);
@@ -1717,8 +1735,9 @@ impl Flow for BlockFlow {
}
fn compute_absolute_position(&mut self) {
- // FIXME(#2795): Get the real container size
- let container_size = Size2D::zero();
+ // FIXME (mbrubeck): Get the real container size, taking the container writing mode into
+ // account. Must handle vertical writing modes.
+ let container_size = Size2D(self.base.block_container_inline_size, Au(0));
if self.is_root() {
self.base.clip = ClippingRegion::max()
@@ -1789,6 +1808,8 @@ impl Flow for BlockFlow {
.flags
.contains(LAYERS_NEEDED_FOR_DESCENDANTS),
};
+ let container_size_for_children =
+ self.fragment.content_box().size.to_physical(self.base.writing_mode);
// Compute the origin and clipping rectangle for children.
let relative_offset = relative_offset.to_physical(self.base.writing_mode);
@@ -1824,7 +1845,8 @@ impl Flow for BlockFlow {
if !flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) {
let kid_base = flow::mut_base(kid);
kid_base.stacking_relative_position = origin_for_children +
- kid_base.position.start.to_physical(kid_base.writing_mode, container_size);
+ kid_base.position.start.to_physical(kid_base.writing_mode,
+ container_size_for_children);
}
flow::mut_base(kid).absolute_position_info = absolute_position_info_for_children;
@@ -2074,17 +2096,30 @@ pub trait ISizeAndMarginsComputer {
let inline_size;
let extra_inline_size_from_margin;
{
+ let block_mode = block.base.writing_mode;
+
+ // FIXME (mbrubeck): Get correct containing block for positioned blocks?
+ let container_mode = block.base.block_container_writing_mode;
+ let container_size = block.base.block_container_inline_size;
+
let fragment = block.fragment();
fragment.margin.inline_start = solution.margin_inline_start;
fragment.margin.inline_end = solution.margin_inline_end;
- // Left border edge.
- fragment.border_box.start.i = fragment.margin.inline_start;
-
// The associated fragment has the border box of this flow.
inline_size = solution.inline_size + fragment.border_padding.inline_start_end();
fragment.border_box.size.inline = inline_size;
+ // Start border edge.
+ // FIXME (mbrubeck): Handle vertical writing modes.
+ fragment.border_box.start.i =
+ if container_mode.is_bidi_ltr() == block_mode.is_bidi_ltr() {
+ fragment.margin.inline_start
+ } else {
+ // The parent's "start" direction is the child's "end" direction.
+ container_size - inline_size - fragment.margin.inline_end
+ };
+
// To calculate the total size of this block, we also need to account for any additional
// size contribution from positive margins. Negative margins means the block isn't made
// larger at all by the margin.
@@ -2186,6 +2221,13 @@ pub trait ISizeAndMarginsComputer {
input.inline_end_margin,
input.available_inline_size);
+ // Check for direction of parent flow (NOT Containing Block)
+ let block_mode = block.base.writing_mode;
+ let container_mode = block.base.block_container_writing_mode;
+
+ // FIXME (mbrubeck): Handle vertical writing modes.
+ let parent_has_same_direction = container_mode.is_bidi_ltr() == block_mode.is_bidi_ltr();
+
// If inline-size is not 'auto', and inline-size + margins > available_inline-size, all
// 'auto' margins are treated as 0.
let (inline_start_margin, inline_end_margin) = match computed_inline_size {
@@ -2208,10 +2250,14 @@ pub trait ISizeAndMarginsComputer {
match (inline_start_margin, computed_inline_size, inline_end_margin) {
// If all have a computed value other than 'auto', the system is
// over-constrained so we discard the end margin.
- (MaybeAuto::Specified(margin_start), MaybeAuto::Specified(inline_size), MaybeAuto::Specified(_margin_end)) =>
- (margin_start, inline_size, available_inline_size -
- (margin_start + inline_size)),
-
+ (MaybeAuto::Specified(margin_start), MaybeAuto::Specified(inline_size), MaybeAuto::Specified(margin_end)) => {
+ if parent_has_same_direction {
+ (margin_start, inline_size, available_inline_size -
+ (margin_start + inline_size))
+ } else {
+ (available_inline_size - (margin_end + inline_size), inline_size, margin_end)
+ }
+ }
// If exactly one value is 'auto', solve for it
(MaybeAuto::Auto, MaybeAuto::Specified(inline_size), MaybeAuto::Specified(margin_end)) =>
(available_inline_size - (inline_size + margin_end), inline_size, margin_end),
@@ -2284,9 +2330,12 @@ impl ISizeAndMarginsComputer for AbsoluteNonReplaced {
..
} = input;
- // TODO: Check for direction of parent flow (NOT Containing Block)
- // when right-to-left is implemented.
- // Assume direction is 'ltr' for now
+ // Check for direction of parent flow (NOT Containing Block)
+ let block_mode = block.base.writing_mode;
+ let container_mode = block.base.block_container_writing_mode;
+
+ // FIXME (mbrubeck): Handle vertical writing modes.
+ let parent_has_same_direction = container_mode.is_bidi_ltr() == block_mode.is_bidi_ltr();
// Distance from the inline-start edge of the Absolute Containing Block to the
// inline-start margin edge of a hypothetical box that would have been the
@@ -2312,9 +2361,14 @@ impl ISizeAndMarginsComputer for AbsoluteNonReplaced {
(MaybeAuto::Auto, MaybeAuto::Auto) => {
let total_margin_val = available_inline_size - inline_start - inline_end - inline_size;
if total_margin_val < Au(0) {
- // margin-inline-start becomes 0 because direction is 'ltr'.
- // TODO: Handle 'rtl' when it is implemented.
- (inline_start, inline_end, inline_size, Au(0), total_margin_val)
+ if parent_has_same_direction {
+ // margin-inline-start becomes 0
+ (inline_start, inline_end, inline_size, Au(0), total_margin_val)
+ } else {
+ // margin-inline-end becomes 0, because it's toward the parent's
+ // inline-start edge.
+ (inline_start, inline_end, inline_size, total_margin_val, Au(0))
+ }
} else {
// Equal margins
(inline_start, inline_end, inline_size,
@@ -2332,10 +2386,14 @@ impl ISizeAndMarginsComputer for AbsoluteNonReplaced {
}
(MaybeAuto::Specified(margin_start), MaybeAuto::Specified(margin_end)) => {
// Values are over-constrained.
- // Ignore value for 'inline-end' cos direction is 'ltr'.
- // TODO: Handle 'rtl' when it is implemented.
let sum = inline_start + inline_size + margin_start + margin_end;
- (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end)
+ if parent_has_same_direction {
+ // Ignore value for 'inline-end'
+ (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end)
+ } else {
+ // Ignore value for 'inline-start'
+ (available_inline_size - sum, inline_end, inline_size, margin_start, margin_end)
+ }
}
}
}
@@ -2633,6 +2691,7 @@ fn propagate_column_inline_sizes_to_child(
kid: &mut Flow,
child_index: uint,
content_inline_size: Au,
+ writing_mode: WritingMode,
column_computed_inline_sizes: &[ColumnComputedInlineSize],
inline_start_margin_edge: &mut Au) {
// If kid is table_rowgroup or table_row, the column inline-sizes info should be copied from
@@ -2656,6 +2715,7 @@ fn propagate_column_inline_sizes_to_child(
let kid_base = flow::mut_base(kid);
kid_base.position.start.i = *inline_start_margin_edge;
kid_base.block_container_inline_size = inline_size;
+ kid_base.block_container_writing_mode = writing_mode;
}
if kid.is_table_cell() {