diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2015-04-09 10:36:18 -0700 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2015-04-09 14:55:05 -0700 |
commit | 18074bf908508c45df65a6eacfafc65028b8a24d (patch) | |
tree | e37d6ee61cfe6080c64e6e6878185167b9e8576e /components/layout/inline.rs | |
parent | 51dd6984f7cc292d77b2330d404ffcff34981214 (diff) | |
download | servo-18074bf908508c45df65a6eacfafc65028b8a24d.tar.gz servo-18074bf908508c45df65a6eacfafc65028b8a24d.zip |
layout: Lay out nested inline elements with different `vertical-align`
values properly in simple cases.
This allows things like `<sup><span>Foo</span></sup>` to work and
improves Wikipedia.
Diffstat (limited to 'components/layout/inline.rs')
-rw-r--r-- | components/layout/inline.rs | 158 |
1 files changed, 102 insertions, 56 deletions
diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 1f9e59dba2e..aa3d0d91bda 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -24,13 +24,14 @@ use gfx::text::glyph::CharIndex; use gfx::text::text_run::TextRun; use std::cmp::max; use std::fmt; +use std::iter; use std::mem; use std::num::ToPrimitive; use std::ops::{Add, Sub, Mul, Div, Rem, Neg, Shl, Shr, Not, BitOr, BitAnd, BitXor}; use std::sync::Arc; use std::u16; -use style::computed_values::{overflow_x, text_align, text_justify, text_overflow, vertical_align}; -use style::computed_values::{white_space}; +use style::computed_values::{display, overflow_x, text_align, text_justify, text_overflow}; +use style::computed_values::{vertical_align, white_space}; use style::properties::ComputedValues; use util::geometry::{Au, MAX_AU, ZERO_RECT}; use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; @@ -782,59 +783,80 @@ impl InlineFlow { largest_block_size_for_bottom_fragments: &mut Au, layout_context: &LayoutContext) -> (Au, bool) { - match fragment.vertical_align() { - vertical_align::T::baseline => (-ascent, false), - vertical_align::T::middle => { - // TODO: x-height value should be used from font info. - // TODO: The code below passes our current reftests but doesn't work in all - // situations. Add vertical align reftests and fix this. - (-ascent, false) - }, - vertical_align::T::sub => { - let sub_offset = (parent_text_block_start + parent_text_block_end) - .scale_by(FONT_SUBSCRIPT_OFFSET_RATIO); - (sub_offset - ascent, false) - }, - vertical_align::T::super_ => { - let super_offset = (parent_text_block_start + parent_text_block_end) - .scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO); - (-super_offset - ascent, false) - }, - vertical_align::T::text_top => { - let fragment_block_size = *block_size_above_baseline + *depth_below_baseline; - let prev_depth_below_baseline = *depth_below_baseline; - *block_size_above_baseline = parent_text_block_start; - *depth_below_baseline = fragment_block_size - *block_size_above_baseline; - (*depth_below_baseline - prev_depth_below_baseline - ascent, false) - }, - vertical_align::T::text_bottom => { - let fragment_block_size = *block_size_above_baseline + *depth_below_baseline; - let prev_depth_below_baseline = *depth_below_baseline; - *depth_below_baseline = parent_text_block_end; - *block_size_above_baseline = fragment_block_size - *depth_below_baseline; - (*depth_below_baseline - prev_depth_below_baseline - ascent, false) - }, - vertical_align::T::top => { - *largest_block_size_for_top_fragments = - max(*largest_block_size_for_top_fragments, - *block_size_above_baseline + *depth_below_baseline); - let offset_top = *block_size_above_baseline - ascent; - (offset_top, true) - }, - vertical_align::T::bottom => { - *largest_block_size_for_bottom_fragments = - max(*largest_block_size_for_bottom_fragments, - *block_size_above_baseline + *depth_below_baseline); - let offset_bottom = -(*depth_below_baseline + ascent); - (offset_bottom, true) - }, - vertical_align::T::Length(length) => (-(length + ascent), false), - vertical_align::T::Percentage(p) => { - let line_height = fragment.calculate_line_height(layout_context); - let percent_offset = line_height.scale_by(p); - (-(percent_offset + ascent), false) + let (mut offset_from_baseline, mut largest_size_updated) = (Au(0), false); + for style in fragment.inline_styles() { + // Ignore `vertical-align` values for table cells. + let box_style = style.get_box(); + if box_style.display != display::T::inline && + box_style.display != display::T::block { + continue + } + + match box_style.vertical_align { + vertical_align::T::baseline => {} + vertical_align::T::middle => { + // TODO: x-height value should be used from font info. + // TODO: Doing nothing here passes our current reftests but doesn't work in + // all situations. Add vertical align reftests and fix this. + }, + vertical_align::T::sub => { + let sub_offset = (parent_text_block_start + parent_text_block_end) + .scale_by(FONT_SUBSCRIPT_OFFSET_RATIO); + offset_from_baseline = offset_from_baseline + sub_offset + }, + vertical_align::T::super_ => { + let super_offset = (parent_text_block_start + parent_text_block_end) + .scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO); + offset_from_baseline = offset_from_baseline - super_offset + }, + vertical_align::T::text_top => { + let fragment_block_size = *block_size_above_baseline + + *depth_below_baseline; + let prev_depth_below_baseline = *depth_below_baseline; + *block_size_above_baseline = parent_text_block_start; + *depth_below_baseline = fragment_block_size - *block_size_above_baseline; + offset_from_baseline = offset_from_baseline + *depth_below_baseline - + prev_depth_below_baseline + }, + vertical_align::T::text_bottom => { + let fragment_block_size = *block_size_above_baseline + + *depth_below_baseline; + let prev_depth_below_baseline = *depth_below_baseline; + *depth_below_baseline = parent_text_block_end; + *block_size_above_baseline = fragment_block_size - *depth_below_baseline; + offset_from_baseline = offset_from_baseline + *depth_below_baseline - + prev_depth_below_baseline + }, + vertical_align::T::top => { + if !largest_size_updated { + largest_size_updated = true; + *largest_block_size_for_top_fragments = + max(*largest_block_size_for_top_fragments, + *block_size_above_baseline + *depth_below_baseline); + offset_from_baseline = offset_from_baseline + + *block_size_above_baseline + } + }, + vertical_align::T::bottom => { + if !largest_size_updated { + largest_size_updated = true; + *largest_block_size_for_bottom_fragments = + max(*largest_block_size_for_bottom_fragments, + *block_size_above_baseline + *depth_below_baseline); + offset_from_baseline = offset_from_baseline - *depth_below_baseline + } + }, + vertical_align::T::Length(length) => { + offset_from_baseline = offset_from_baseline - length + } + vertical_align::T::Percentage(p) => { + let line_height = fragment.calculate_line_height(layout_context); + let percent_offset = line_height.scale_by(p); + offset_from_baseline = offset_from_baseline - percent_offset + } } } + (offset_from_baseline - ascent, largest_size_updated) } /// Sets fragment positions in the inline direction based on alignment for one line. This @@ -962,22 +984,46 @@ impl InlineFlow { baseline_distance_from_block_start: Au, largest_depth_below_baseline: Au) { for fragment_index in range(line.range.begin(), line.range.end()) { + // If any of the inline styles say `top` or `bottom`, adjust the vertical align + // appropriately. + // + // FIXME(#5624, pcwalton): This passes our current reftests but isn't the right thing + // to do. let fragment = fragments.get_mut(fragment_index.to_usize()); - match fragment.vertical_align() { + let mut vertical_align = vertical_align::T::baseline; + for style in fragment.inline_styles() { + match (style.get_box().display, style.get_box().vertical_align) { + (display::T::inline, vertical_align::T::top) | + (display::T::block, vertical_align::T::top) => { + vertical_align = vertical_align::T::top; + break + } + (display::T::inline, vertical_align::T::bottom) | + (display::T::block, vertical_align::T::bottom) => { + vertical_align = vertical_align::T::bottom; + break + } + _ => {} + } + } + + match vertical_align { vertical_align::T::top => { fragment.border_box.start.b = fragment.border_box.start.b + line_distance_from_flow_block_start } vertical_align::T::bottom => { fragment.border_box.start.b = fragment.border_box.start.b + - line_distance_from_flow_block_start + baseline_distance_from_block_start + - largest_depth_below_baseline + line_distance_from_flow_block_start + + baseline_distance_from_block_start + + largest_depth_below_baseline; } _ => { fragment.border_box.start.b = fragment.border_box.start.b + line_distance_from_flow_block_start + baseline_distance_from_block_start } } + fragment.update_late_computed_block_position_if_necessary(); } } |