Auto merge of #10691 - pcwalton:float-fixes, r=mbrubeck

layout: Fix float speculation with percentage inline sizes, rewrite vertical alignment, fix inline block ascent/descent computation, and fix absolute inline-block hypothetical boxes.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10691)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-05-04 13:49:23 -07:00
commit 35ba29355f
32 changed files with 540 additions and 405 deletions

View file

@ -272,7 +272,14 @@ impl<'a> TextRun {
})
}
/// Returns the index of the first glyph run containing the given byte index.
pub fn minimum_splittable_inline_size(&self, range: &Range<ByteIndex>) -> Au {
match self.natural_word_slices_in_range(range).next() {
None => Au(0),
Some(slice) => self.advance_for_range(&slice.range),
}
}
/// Returns the index of the first glyph run containing the given character index.
fn index_of_first_glyph_run_containing(&self, index: ByteIndex) -> Option<usize> {
let self_ptr = self as *const TextRun;
INDEX_OF_FIRST_GLYPH_RUN_CACHE.with(|index_of_first_glyph_run_cache| {

View file

@ -33,7 +33,8 @@ use display_list_builder::BlockFlowDisplayListBuilding;
use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
use euclid::{Point2D, Rect, Size2D};
use floats::{ClearType, FloatKind, Floats, PlacementInfo};
use flow::{BLOCK_POSITION_IS_STATIC, CLEARS_LEFT, CLEARS_RIGHT, INLINE_POSITION_IS_STATIC};
use flow::{BLOCK_POSITION_IS_STATIC, CLEARS_LEFT, CLEARS_RIGHT};
use flow::{CONTAINS_TEXT_OR_REPLACED_FRAGMENTS, INLINE_POSITION_IS_STATIC};
use flow::{IS_ABSOLUTELY_POSITIONED};
use flow::{ImmutableFlowUtils, LateAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
use flow::{NEEDS_LAYER, PostorderFlowTraversal, PreorderFlowTraversal, FragmentationContext};
@ -1473,61 +1474,89 @@ impl BlockFlow {
}
}
/// Computes intrinsic widths for a block.
/// Computes intrinsic inline sizes for a block.
pub fn bubble_inline_sizes_for_block(&mut self, consult_children: bool) {
let _scope = layout_debug_scope!("block::bubble_inline_sizes {:x}", self.base.debug_id());
let flags = self.base.flags;
// Find the maximum inline-size from children.
let mut computation = self.fragment.compute_intrinsic_inline_sizes();
let (mut left_float_width, mut right_float_width) = (Au(0), Au(0));
let (mut left_float_width_accumulator, mut right_float_width_accumulator) = (Au(0), Au(0));
for kid in self.base.child_iter_mut() {
let is_absolutely_positioned =
flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED);
let child_base = flow::mut_base(kid);
let float_kind = child_base.flags.float_kind();
if !is_absolutely_positioned && consult_children {
computation.content_intrinsic_sizes.minimum_inline_size =
max(computation.content_intrinsic_sizes.minimum_inline_size,
child_base.intrinsic_inline_sizes.minimum_inline_size);
if child_base.flags.contains(CLEARS_LEFT) {
left_float_width = max(left_float_width, left_float_width_accumulator);
left_float_width_accumulator = Au(0)
}
if child_base.flags.contains(CLEARS_RIGHT) {
right_float_width = max(right_float_width, right_float_width_accumulator);
right_float_width_accumulator = Au(0)
}
match float_kind {
float::T::none => {
computation.content_intrinsic_sizes.preferred_inline_size =
max(computation.content_intrinsic_sizes.preferred_inline_size,
child_base.intrinsic_inline_sizes.preferred_inline_size);
}
float::T::left => {
left_float_width_accumulator = left_float_width_accumulator +
child_base.intrinsic_inline_sizes.preferred_inline_size;
}
float::T::right => {
right_float_width_accumulator = right_float_width_accumulator +
child_base.intrinsic_inline_sizes.preferred_inline_size;
}
let mut flags = self.base.flags;
if self.definitely_has_zero_block_size() {
// This is kind of a hack for Acid2. But it's a harmless one, because (a) this behavior
// is unspecified; (b) it matches the behavior one would intuitively expect, since
// floats don't flow around blocks that take up no space in the block direction.
flags.remove(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
} else if self.fragment.is_text_or_replaced() {
flags.insert(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
} else {
flags.remove(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
for kid in self.base.children.iter() {
if flow::base(kid).flags.contains(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS) {
flags.insert(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
break
}
}
}
// Find the maximum inline-size from children.
//
// See: https://lists.w3.org/Archives/Public/www-style/2014Nov/0085.html
//
// FIXME(pcwalton): This doesn't exactly follow that algorithm at the moment.
// FIXME(pcwalton): This should consider all float descendants, not just children.
// FIXME(pcwalton): This is not well-spec'd; INTRINSIC specifies to do this, but CSS-SIZING
// says not to. In practice, Gecko and WebKit both do this.
let mut computation = self.fragment.compute_intrinsic_inline_sizes();
let (mut left_float_width, mut right_float_width) = (Au(0), Au(0));
let (mut left_float_width_accumulator, mut right_float_width_accumulator) = (Au(0), Au(0));
let mut preferred_inline_size_of_children_without_text_or_replaced_fragments = Au(0);
for kid in self.base.child_iter_mut() {
if flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) || !consult_children {
continue
}
let child_base = flow::mut_base(kid);
let float_kind = child_base.flags.float_kind();
computation.content_intrinsic_sizes.minimum_inline_size =
max(computation.content_intrinsic_sizes.minimum_inline_size,
child_base.intrinsic_inline_sizes.minimum_inline_size);
if child_base.flags.contains(CLEARS_LEFT) {
left_float_width = max(left_float_width, left_float_width_accumulator);
left_float_width_accumulator = Au(0)
}
if child_base.flags.contains(CLEARS_RIGHT) {
right_float_width = max(right_float_width, right_float_width_accumulator);
right_float_width_accumulator = Au(0)
}
match (float_kind, child_base.flags.contains(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS)) {
(float::T::none, true) => {
computation.content_intrinsic_sizes.preferred_inline_size =
max(computation.content_intrinsic_sizes.preferred_inline_size,
child_base.intrinsic_inline_sizes.preferred_inline_size);
}
(float::T::none, false) => {
preferred_inline_size_of_children_without_text_or_replaced_fragments = max(
preferred_inline_size_of_children_without_text_or_replaced_fragments,
child_base.intrinsic_inline_sizes.preferred_inline_size)
}
(float::T::left, _) => {
left_float_width_accumulator = left_float_width_accumulator +
child_base.intrinsic_inline_sizes.preferred_inline_size;
}
(float::T::right, _) => {
right_float_width_accumulator = right_float_width_accumulator +
child_base.intrinsic_inline_sizes.preferred_inline_size;
}
}
}
left_float_width = max(left_float_width, left_float_width_accumulator);
right_float_width = max(right_float_width, right_float_width_accumulator);
computation.content_intrinsic_sizes.preferred_inline_size =
computation.content_intrinsic_sizes.preferred_inline_size + left_float_width +
right_float_width;
computation.content_intrinsic_sizes.preferred_inline_size =
max(computation.content_intrinsic_sizes.preferred_inline_size,
left_float_width + right_float_width);
preferred_inline_size_of_children_without_text_or_replaced_fragments);
self.base.intrinsic_inline_sizes = computation.finish();
self.base.flags = flags
@ -1630,6 +1659,18 @@ impl BlockFlow {
FormattingContextType::None | FormattingContextType::Other => {}
}
}
fn definitely_has_zero_block_size(&self) -> bool {
if !self.fragment.style.content_block_size().is_definitely_zero() {
return false
}
let border_width = self.fragment.border_width();
if border_width.block_start != Au(0) || border_width.block_end != Au(0) {
return false
}
let padding = self.fragment.style.logical_padding();
padding.block_start.is_definitely_zero() && padding.block_end.is_definitely_zero()
}
}
impl Flow for BlockFlow {

View file

@ -686,7 +686,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
/// FIXME(pcwalton): It is not clear to me that there isn't a cleaner way to handle
/// `<textarea>`.
fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ConcreteThreadSafeLayoutNode)
-> ConstructionResult {
-> ConstructionResult {
let mut initial_fragments = IntermediateInlineFragments::new();
let node_is_input_or_text_area =
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
@ -1023,7 +1023,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
/// This is an annoying case, because the computed `display` value is `block`, but the
/// hypothetical box is inline.
fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ConcreteThreadSafeLayoutNode)
fn build_fragment_for_absolutely_positioned_inline(&mut self,
node: &ConcreteThreadSafeLayoutNode)
-> ConstructionResult {
let block_flow_result = self.build_flow_for_block(node, None);
let (block_flow, abs_descendants) = match block_flow_result {
@ -1519,11 +1520,10 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<ConcreteThreadS
}
Some(NodeTypeId::Element(_)) => {
let style = node.style(self.style_context());
let munged_display = if style.get_box()._servo_display_for_hypothetical_box ==
display::T::inline {
display::T::inline
} else {
style.get_box().display
let original_display = style.get_box()._servo_display_for_hypothetical_box;
let munged_display = match original_display {
display::T::inline | display::T::inline_block => original_display,
_ => style.get_box().display,
};
(munged_display, style.get_box().float, style.get_box().position)
}
@ -1577,7 +1577,8 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<ConcreteThreadS
// Inline items that are absolutely-positioned contribute inline fragment construction
// results with a hypothetical fragment.
(display::T::inline, _, position::T::absolute) => {
(display::T::inline, _, position::T::absolute) |
(display::T::inline_block, _, position::T::absolute) => {
let construction_result =
self.build_fragment_for_absolutely_positioned_inline(node);
self.set_flow_construction_result(node, construction_result)

View file

@ -11,6 +11,7 @@ use std::fmt;
use std::i32;
use style::computed_values::float;
use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
use style::values::computed::LengthOrPercentageOrAuto;
/// The kind of float: left or right.
#[derive(Clone, RustcEncodable, Debug, Copy)]
@ -78,7 +79,11 @@ impl FloatList {
impl fmt::Debug for FloatList {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "max_block_start={:?} floats={}", self.max_block_start, self.floats.len())
try!(write!(f, "max_block_start={:?} floats={}", self.max_block_start, self.floats.len()));
for float in self.floats.iter() {
try!(write!(f, " {:?}", float));
}
Ok(())
}
}
@ -490,14 +495,30 @@ impl SpeculatedFloatPlacement {
}
let base_flow = flow::base(flow);
if !base_flow.flags.is_float() {
return
}
let mut float_inline_size = base_flow.intrinsic_inline_sizes.preferred_inline_size;
if float_inline_size == Au(0) {
if flow.is_block_like() {
// Hack: If the size of the float is a percentage, then there's no way we can guess
// at its size now. So just pick an arbitrary nonzero value (in this case, 1px) so
// that the layout traversal logic will know that objects later in the document
// might flow around this float.
if let LengthOrPercentageOrAuto::Percentage(percentage) =
flow.as_block().fragment.style.content_inline_size() {
if percentage > 0.0 {
float_inline_size = Au::from_px(1)
}
}
}
}
match base_flow.flags.float_kind() {
float::T::none => {}
float::T::left => {
self.left = self.left + base_flow.intrinsic_inline_sizes.preferred_inline_size
}
float::T::right => {
self.right = self.right + base_flow.intrinsic_inline_sizes.preferred_inline_size
}
float::T::left => self.left = self.left + float_inline_size,
float::T::right => self.right = self.right + float_inline_size,
}
}

View file

@ -512,6 +512,8 @@ pub trait ImmutableFlowUtils {
/// Returns true if floats might flow through this flow, as determined by the float placement
/// speculation pass.
fn floats_might_flow_through(self) -> bool;
fn baseline_offset_of_last_line_box_in_flow(self) -> Option<Au>;
}
pub trait MutableFlowUtils {
@ -634,45 +636,48 @@ bitflags! {
#[doc = "Whether this flow must have its own layer. Even if this flag is not set, it might"]
#[doc = "get its own layer if it's deemed to be likely to overlap flows with their own"]
#[doc = "layer."]
const NEEDS_LAYER = 0b0000_0000_0000_0010_0000,
const NEEDS_LAYER = 0b0000_0000_0000_0000_0010_0000,
#[doc = "Whether this flow is absolutely positioned. This is checked all over layout, so a"]
#[doc = "virtual call is too expensive."]
const IS_ABSOLUTELY_POSITIONED = 0b0000_0000_0000_0100_0000,
const IS_ABSOLUTELY_POSITIONED = 0b0000_0000_0000_0000_0100_0000,
#[doc = "Whether this flow clears to the left. This is checked all over layout, so a"]
#[doc = "virtual call is too expensive."]
const CLEARS_LEFT = 0b0000_0000_0000_1000_0000,
const CLEARS_LEFT = 0b0000_0000_0000_0000_1000_0000,
#[doc = "Whether this flow clears to the right. This is checked all over layout, so a"]
#[doc = "virtual call is too expensive."]
const CLEARS_RIGHT = 0b0000_0000_0001_0000_0000,
const CLEARS_RIGHT = 0b0000_0000_0000_0001_0000_0000,
#[doc = "Whether this flow is left-floated. This is checked all over layout, so a"]
#[doc = "virtual call is too expensive."]
const FLOATS_LEFT = 0b0000_0000_0010_0000_0000,
const FLOATS_LEFT = 0b0000_0000_0000_0010_0000_0000,
#[doc = "Whether this flow is right-floated. This is checked all over layout, so a"]
#[doc = "virtual call is too expensive."]
const FLOATS_RIGHT = 0b0000_0000_0100_0000_0000,
const FLOATS_RIGHT = 0b0000_0000_0000_0100_0000_0000,
#[doc = "Text alignment. \
NB: If you update this, update `TEXT_ALIGN_SHIFT` below."]
const TEXT_ALIGN = 0b0000_0111_1000_0000_0000,
const TEXT_ALIGN = 0b0000_0000_0111_1000_0000_0000,
#[doc = "Whether this flow has a fragment with `counter-reset` or `counter-increment` \
styles."]
const AFFECTS_COUNTERS = 0b0000_1000_0000_0000_0000,
const AFFECTS_COUNTERS = 0b0000_0000_1000_0000_0000_0000,
#[doc = "Whether this flow's descendants have fragments that affect `counter-reset` or \
`counter-increment` styles."]
const HAS_COUNTER_AFFECTING_CHILDREN = 0b0001_0000_0000_0000_0000,
const HAS_COUNTER_AFFECTING_CHILDREN = 0b0000_0001_0000_0000_0000_0000,
#[doc = "Whether this flow behaves as though it had `position: static` for the purposes \
of positioning in the inline direction. This is set for flows with `position: \
static` and `position: relative` as well as absolutely-positioned flows with \
unconstrained positions in the inline direction."]
const INLINE_POSITION_IS_STATIC = 0b0010_0000_0000_0000_0000,
const INLINE_POSITION_IS_STATIC = 0b0000_0010_0000_0000_0000_0000,
#[doc = "Whether this flow behaves as though it had `position: static` for the purposes \
of positioning in the block direction. This is set for flows with `position: \
static` and `position: relative` as well as absolutely-positioned flows with \
unconstrained positions in the block direction."]
const BLOCK_POSITION_IS_STATIC = 0b0100_0000_0000_0000_0000,
const BLOCK_POSITION_IS_STATIC = 0b0000_0100_0000_0000_0000_0000,
/// Whether any ancestor is a fragmentation container
const CAN_BE_FRAGMENTED = 0b1000_0000_0000_0000_0000,
const CAN_BE_FRAGMENTED = 0b0000_1000_0000_0000_0000_0000,
/// Whether this flow contains any text and/or replaced fragments.
const CONTAINS_TEXT_OR_REPLACED_FRAGMENTS = 0b0001_0000_0000_0000_0000_0000,
}
}
@ -975,9 +980,11 @@ impl fmt::Debug for BaseFlow {
};
write!(f,
"sc={:?} pos={:?}, floatspec-in={:?}, floatspec-out={:?}, overflow={:?}{}{}{}",
"sc={:?} pos={:?}, {}{} floatspec-in={:?}, floatspec-out={:?}, overflow={:?}{}{}{}",
self.stacking_context_id,
self.position,
if self.flags.contains(FLOATS_LEFT) { "FL" } else { "" },
if self.flags.contains(FLOATS_RIGHT) { "FR" } else { "" },
self.speculated_float_placement_in,
self.speculated_float_placement_out,
self.overflow,
@ -1387,6 +1394,21 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
}
self.as_block().formatting_context_type() == FormattingContextType::None
}
fn baseline_offset_of_last_line_box_in_flow(self) -> Option<Au> {
for kid in base(self).children.iter().rev() {
if kid.is_inline_flow() {
return kid.as_inline().baseline_offset_of_last_line()
}
if kid.is_block_like() &&
kid.as_block().formatting_context_type() == FormattingContextType::None {
if let Some(baseline_offset) = kid.baseline_offset_of_last_line_box_in_flow() {
return Some(base(kid).position.start.b + baseline_offset)
}
}
}
None
}
}
impl<'a> MutableFlowUtils for &'a mut Flow {

View file

@ -111,6 +111,12 @@ impl<'a> Iterator for FlowListIterator<'a> {
}
}
impl<'a> DoubleEndedIterator for FlowListIterator<'a> {
fn next_back(&mut self) -> Option<&'a Flow> {
self.it.next_back().map(|x| &**x)
}
}
impl<'a> Iterator for MutFlowListIterator<'a> {
type Item = &'a mut Flow;
#[inline]

View file

@ -11,7 +11,7 @@ use canvas_traits::CanvasMsg;
use context::LayoutContext;
use euclid::{Point2D, Rect, Size2D};
use floats::ClearType;
use flow::{self, Flow};
use flow::{self, Flow, ImmutableFlowUtils};
use flow_ref::{self, FlowRef};
use gfx;
use gfx::display_list::{BLUR_INFLATION_FACTOR, FragmentType, OpaqueNode, StackingContextId};
@ -38,7 +38,7 @@ use std::sync::{Arc, Mutex};
use style::computed_values::content::ContentItem;
use style::computed_values::{border_collapse, clear, display, mix_blend_mode, overflow_wrap};
use style::computed_values::{overflow_x, position, text_decoration, transform_style};
use style::computed_values::{white_space, word_break, z_index};
use style::computed_values::{vertical_align, white_space, word_break, z_index};
use style::dom::TRestyleDamage;
use style::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
use style::properties::{ComputedValues, ServoComputedValues};
@ -1031,7 +1031,8 @@ impl Fragment {
let mut specified = Au(0);
if flags.contains(INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED) {
specified = MaybeAuto::from_style(style.content_inline_size(), Au(0)).specified_or_zero();
specified = MaybeAuto::from_style(style.content_inline_size(),
Au(0)).specified_or_zero();
specified = max(model::specified(style.min_inline_size(), Au(0)), specified);
if let Some(max) = model::specified_or_none(style.max_inline_size(), Au(0)) {
specified = min(specified, max)
@ -1070,14 +1071,15 @@ impl Fragment {
pub fn calculate_line_height(&self, layout_context: &LayoutContext) -> Au {
let font_style = self.style.get_font_arc();
let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(), font_style);
let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(),
font_style);
text::line_height_from_style(&*self.style, &font_metrics)
}
/// Returns the sum of the inline-sizes of all the borders of this fragment. Note that this
/// can be expensive to compute, so if possible use the `border_padding` field instead.
#[inline]
fn border_width(&self) -> LogicalMargin<Au> {
pub fn border_width(&self) -> LogicalMargin<Au> {
let style_border_width = match self.specific {
SpecificFragmentInfo::ScannedText(_) |
SpecificFragmentInfo::InlineBlock(_) => LogicalMargin::zero(self.style.writing_mode),
@ -1471,6 +1473,17 @@ impl Fragment {
result
}
/// Returns the narrowest inline-size that the first splittable part of this fragment could
/// possibly be split to. (In most cases, this returns the inline-size of the first word in
/// this fragment.)
pub fn minimum_splittable_inline_size(&self) -> Au {
match self.specific {
SpecificFragmentInfo::ScannedText(ref text) => {
text.run.minimum_splittable_inline_size(&text.range)
}
_ => Au(0),
}
}
/// TODO: What exactly does this function return? Why is it Au(0) for
/// `SpecificFragmentInfo::Generic`?
@ -1972,14 +1985,19 @@ impl Fragment {
}
SpecificFragmentInfo::InlineBlock(ref info) => {
// See CSS 2.1 § 10.8.1.
let block_flow = info.flow_ref.as_block();
let font_style = self.style.get_font_arc();
let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(),
font_style);
InlineMetrics::from_block_height(&font_metrics,
block_flow.base.position.size.block,
block_flow.fragment.margin.block_start,
block_flow.fragment.margin.block_end)
let flow = &info.flow_ref;
let block_flow = flow.as_block();
let baseline_offset = match flow.baseline_offset_of_last_line_box_in_flow() {
Some(baseline_offset) => baseline_offset,
None => block_flow.fragment.border_box.size.block,
};
let start_margin = block_flow.fragment.margin.block_start;
let end_margin = block_flow.fragment.margin.block_end;
let depth_below_baseline = flow::base(&**flow).position.size.block -
baseline_offset + end_margin;
InlineMetrics::new(baseline_offset + start_margin,
depth_below_baseline,
baseline_offset)
}
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) => {
@ -2541,6 +2559,46 @@ impl Fragment {
pub fn layer_id_for_overflow_scroll(&self) -> LayerId {
LayerId::new_of_type(LayerType::OverflowScroll, self.node.id() as usize)
}
/// Returns true if any of the inline styles associated with this fragment have
/// `vertical-align` set to `top` or `bottom`.
pub fn is_vertically_aligned_to_top_or_bottom(&self) -> bool {
match self.style.get_box().vertical_align {
vertical_align::T::top | vertical_align::T::bottom => return true,
_ => {}
}
if let Some(ref inline_context) = self.inline_context {
for node in &inline_context.nodes {
match node.style.get_box().vertical_align {
vertical_align::T::top | vertical_align::T::bottom => return true,
_ => {}
}
}
}
false
}
pub fn is_text_or_replaced(&self) -> bool {
match self.specific {
SpecificFragmentInfo::Generic |
SpecificFragmentInfo::InlineAbsolute(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::Multicol |
SpecificFragmentInfo::MulticolColumn |
SpecificFragmentInfo::Table |
SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableColumn(_) |
SpecificFragmentInfo::TableRow |
SpecificFragmentInfo::TableWrapper => false,
SpecificFragmentInfo::Canvas(_) |
SpecificFragmentInfo::GeneratedContent(_) |
SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::ScannedText(_) |
SpecificFragmentInfo::UnscannedText(_) => true
}
}
}
impl fmt::Debug for Fragment {

View file

@ -11,7 +11,8 @@ use display_list_builder::DisplayListBuildState;
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
use euclid::{Point2D, Size2D};
use floats::{FloatKind, Floats, PlacementInfo};
use flow::{EarlyAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
use flow::{CONTAINS_TEXT_OR_REPLACED_FRAGMENTS, EarlyAbsolutePositionInfo, MutableFlowUtils};
use flow::{OpaqueFlow};
use flow::{self, BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, IS_ABSOLUTELY_POSITIONED};
use flow_ref;
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
@ -26,7 +27,7 @@ use range::{Range, RangeIndex};
use std::cmp::max;
use std::collections::VecDeque;
use std::sync::Arc;
use std::{fmt, isize, mem};
use std::{fmt, i32, isize, mem};
use style::computed_values::{display, overflow_x, position, text_align, text_justify};
use style::computed_values::{text_overflow, vertical_align, white_space};
use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
@ -418,13 +419,23 @@ impl LineBreaker {
// block-size. This might not be the case with some weird text fonts.
fn new_inline_metrics_for_line(&self, new_fragment: &Fragment, layout_context: &LayoutContext)
-> InlineMetrics {
self.pending_line.inline_metrics.max(&new_fragment.inline_metrics(layout_context))
if !new_fragment.is_vertically_aligned_to_top_or_bottom() {
let fragment_inline_metrics = new_fragment.inline_metrics(layout_context);
self.pending_line.inline_metrics.max(&fragment_inline_metrics)
} else {
self.pending_line.inline_metrics
}
}
fn new_block_size_for_line(&self, new_fragment: &Fragment, layout_context: &LayoutContext)
-> Au {
max(self.pending_line.bounds.size.block,
self.new_inline_metrics_for_line(new_fragment, layout_context).block_size())
let new_block_size = if new_fragment.is_vertically_aligned_to_top_or_bottom() {
max(new_fragment.inline_metrics(layout_context).block_size(),
self.minimum_block_size_above_baseline + self.minimum_depth_below_baseline)
} else {
self.new_inline_metrics_for_line(new_fragment, layout_context).block_size()
};
max(self.pending_line.bounds.size.block, new_block_size)
}
/// Computes the position of a line that has only the provided fragment. Returns the bounding
@ -444,7 +455,7 @@ impl LineBreaker {
// Initially, pretend a splittable fragment has zero inline-size. We will move it later if
// it has nonzero inline-size and that causes problems.
let placement_inline_size = if first_fragment.can_split() {
Au(0)
first_fragment.minimum_splittable_inline_size()
} else {
first_fragment.margin_box_inline_size() + self.indentation_for_pending_fragment()
};
@ -855,105 +866,6 @@ impl InlineFlow {
flow
}
/// Returns the distance from the baseline for the logical block-start inline-start corner of
/// this fragment, taking into account the value of the CSS `vertical-align` property.
/// Negative values mean "toward the logical block-start" and positive values mean "toward the
/// logical block-end".
///
/// The extra boolean is set if and only if `largest_block_size_for_top_fragments` and/or
/// `largest_block_size_for_bottom_fragments` were updated. That is, if the box has a `top` or
/// `bottom` value for `vertical-align`, true is returned.
fn distance_from_baseline(fragment: &Fragment,
ascent: Au,
parent_text_block_start: Au,
parent_text_block_end: Au,
block_size_above_baseline: &mut Au,
depth_below_baseline: &mut Au,
largest_block_size_for_top_fragments: &mut Au,
largest_block_size_for_bottom_fragments: &mut Au,
layout_context: &LayoutContext)
-> (Au, bool) {
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();
match box_style.display {
display::T::inline | display::T::block | display::T::inline_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::LengthOrPercentage(LengthOrPercentage::Length(length)) => {
offset_from_baseline = offset_from_baseline - length
}
vertical_align::T::LengthOrPercentage(LengthOrPercentage::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
}
vertical_align::T::LengthOrPercentage(LengthOrPercentage::Calc(calc)) => {
let line_height = fragment.calculate_line_height(layout_context);
let percent_offset = line_height.scale_by(calc.percentage());
offset_from_baseline = offset_from_baseline - percent_offset - calc.length()
}
}
}
(offset_from_baseline - ascent, largest_size_updated)
}
/// Sets fragment positions in the inline direction based on alignment for one line. This
/// performs text justification if mandated by the style.
fn set_inline_fragment_positions(fragments: &mut InlineFragments,
@ -1119,13 +1031,12 @@ impl InlineFlow {
}
}
/// Sets final fragment positions in the block direction for one line. Assumes that the
/// fragment positions were initially set to the distance from the baseline first.
/// Sets final fragment positions in the block direction for one line.
fn set_block_fragment_positions(fragments: &mut InlineFragments,
line: &Line,
line_distance_from_flow_block_start: Au,
baseline_distance_from_block_start: Au,
largest_depth_below_baseline: Au) {
minimum_block_size_above_baseline: Au,
minimum_depth_below_baseline: Au,
layout_context: &LayoutContext) {
for fragment_index in line.range.each_index() {
// If any of the inline styles say `top` or `bottom`, adjust the vertical align
// appropriately.
@ -1133,42 +1044,63 @@ impl InlineFlow {
// 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());
let mut vertical_align = vertical_align::T::baseline;
let fragment_inline_metrics = fragment.inline_metrics(layout_context);
let mut block_start = line.bounds.start.b +
line.inline_metrics.block_size_above_baseline -
fragment_inline_metrics.ascent;
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) |
(display::T::inline_block, vertical_align::T::top) => {
vertical_align = vertical_align::T::top;
break
match style.get_box().vertical_align {
vertical_align::T::baseline => {}
vertical_align::T::middle => {}
vertical_align::T::sub => {
let sub_offset =
(minimum_block_size_above_baseline +
minimum_depth_below_baseline).scale_by(FONT_SUBSCRIPT_OFFSET_RATIO);
block_start = block_start + sub_offset
}
(display::T::inline, vertical_align::T::bottom) |
(display::T::block, vertical_align::T::bottom) |
(display::T::inline_block, vertical_align::T::bottom) => {
vertical_align = vertical_align::T::bottom;
break
vertical_align::T::super_ => {
let super_offset =
(minimum_block_size_above_baseline +
minimum_depth_below_baseline).scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO);
block_start = block_start - super_offset
}
vertical_align::T::text_top => {
block_start = line.bounds.start.b +
line.inline_metrics.block_size_above_baseline -
minimum_block_size_above_baseline
}
vertical_align::T::text_bottom => {
block_start = line.bounds.start.b +
line.inline_metrics.block_size_above_baseline +
minimum_depth_below_baseline -
fragment.border_box.size.block
}
vertical_align::T::top => {
block_start = line.bounds.start.b
}
vertical_align::T::bottom => {
block_start = line.bounds.start.b + line.bounds.size.block -
fragment.border_box.size.block
}
vertical_align::T::LengthOrPercentage(LengthOrPercentage::Length(length)) => {
block_start = block_start - length
}
vertical_align::T::LengthOrPercentage(LengthOrPercentage::Percentage(
percentage)) => {
let line_height = fragment.calculate_line_height(layout_context);
let length = line_height.scale_by(percentage);
block_start = block_start - length
}
vertical_align::T::LengthOrPercentage(LengthOrPercentage::Calc(calc)) => {
let line_height = fragment.calculate_line_height(layout_context);
let percentage_length = line_height.scale_by(calc.percentage());
block_start = block_start - percentage_length - calc.length()
}
_ => {}
}
}
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;
}
_ => {
fragment.border_box.start.b = fragment.border_box.start.b +
line_distance_from_flow_block_start + baseline_distance_from_block_start
}
}
fragment.border_box.start.b = block_start;
fragment.update_late_computed_block_position_if_necessary();
}
}
@ -1192,31 +1124,88 @@ impl InlineFlow {
let line_height = text::line_height_from_style(style, &font_metrics);
let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics, line_height);
let mut block_size_above_baseline = inline_metrics.block_size_above_baseline;
let mut depth_below_baseline = inline_metrics.depth_below_baseline;
let mut block_size_above_baseline = Au(0);
let mut depth_below_baseline = Au(i32::MIN);
let mut largest_block_size_for_top_fragments = Au(0);
let mut largest_block_size_for_bottom_fragments = Au(0);
// We use `vertical_align::T::baseline` here because `vertical-align` must not apply to
// the inside of inline blocks.
update_inline_metrics(&inline_metrics,
style.get_box().display,
vertical_align::T::baseline,
&mut block_size_above_baseline,
&mut depth_below_baseline,
&mut largest_block_size_for_top_fragments,
&mut largest_block_size_for_bottom_fragments);
// According to CSS 2.1 § 10.8, `line-height` of any inline element specifies the minimal
// height of line boxes within the element.
for frag in &self.fragments.fragments {
match frag.inline_context {
Some(ref inline_context) => {
for node in &inline_context.nodes {
let font_style = node.style.get_font_arc();
let font_metrics = text::font_metrics_for_style(font_context, font_style);
let line_height = text::line_height_from_style(&*node.style, &font_metrics);
let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics,
line_height);
block_size_above_baseline = max(block_size_above_baseline,
inline_metrics.block_size_above_baseline);
depth_below_baseline = max(depth_below_baseline,
inline_metrics.depth_below_baseline);
}
if let Some(ref inline_context) = frag.inline_context {
for node in &inline_context.nodes {
let font_style = node.style.get_font_arc();
let font_metrics = text::font_metrics_for_style(font_context, font_style);
let line_height = text::line_height_from_style(&*node.style, &font_metrics);
let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics,
line_height);
update_inline_metrics(&inline_metrics,
node.style.get_box().display,
node.style.get_box().vertical_align,
&mut block_size_above_baseline,
&mut depth_below_baseline,
&mut largest_block_size_for_top_fragments,
&mut largest_block_size_for_bottom_fragments);
}
None => {}
}
}
(block_size_above_baseline, depth_below_baseline)
block_size_above_baseline =
max(block_size_above_baseline,
largest_block_size_for_bottom_fragments - max(depth_below_baseline, Au(0)));
depth_below_baseline =
max(depth_below_baseline,
largest_block_size_for_top_fragments - block_size_above_baseline);
return (block_size_above_baseline, depth_below_baseline);
fn update_inline_metrics(inline_metrics: &InlineMetrics,
display_value: display::T,
vertical_align_value: vertical_align::T,
block_size_above_baseline: &mut Au,
depth_below_baseline: &mut Au,
largest_block_size_for_top_fragments: &mut Au,
largest_block_size_for_bottom_fragments: &mut Au) {
match (display_value, vertical_align_value) {
(display::T::inline, vertical_align::T::top) |
(display::T::block, vertical_align::T::top) |
(display::T::inline_block, vertical_align::T::top) if
inline_metrics.block_size_above_baseline >= Au(0) => {
*largest_block_size_for_top_fragments =
max(*largest_block_size_for_top_fragments,
inline_metrics.block_size_above_baseline +
inline_metrics.depth_below_baseline)
}
(display::T::inline, vertical_align::T::bottom) |
(display::T::block, vertical_align::T::bottom) |
(display::T::inline_block, vertical_align::T::bottom) if
inline_metrics.depth_below_baseline >= Au(0) => {
*largest_block_size_for_bottom_fragments =
max(*largest_block_size_for_bottom_fragments,
inline_metrics.block_size_above_baseline +
inline_metrics.depth_below_baseline)
}
_ => {
*block_size_above_baseline =
max(*block_size_above_baseline,
inline_metrics.block_size_above_baseline);
*depth_below_baseline = max(*depth_below_baseline,
inline_metrics.depth_below_baseline);
}
}
}
}
fn update_restyle_damage(&mut self) {
@ -1275,6 +1264,16 @@ impl InlineFlow {
}
}
}
pub fn baseline_offset_of_last_line(&self) -> Option<Au> {
match self.lines.last() {
None => None,
Some(ref last_line) => {
Some(last_line.bounds.start.b + last_line.bounds.size.block -
last_line.inline_metrics.depth_below_baseline)
}
}
}
}
impl Flow for InlineFlow {
@ -1300,6 +1299,8 @@ impl Flow for InlineFlow {
flow::mut_base(kid).floats = Floats::new(writing_mode);
}
self.base.flags.remove(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
let mut intrinsic_sizes_for_flow = IntrinsicISizesContribution::new();
let mut intrinsic_sizes_for_inline_run = IntrinsicISizesContribution::new();
let mut intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
@ -1358,6 +1359,10 @@ impl Flow for InlineFlow {
}
fragment.restyle_damage.remove(BUBBLE_ISIZES);
if fragment.is_text_or_replaced() {
self.base.flags.insert(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
}
}
// Flush any remaining nonbroken-run and inline-run intrinsic sizes.
@ -1451,11 +1456,8 @@ impl Flow for InlineFlow {
// Now, go through each line and lay out the fragments inside.
let mut line_distance_from_flow_block_start = Au(0);
let line_count = self.lines.len();
for line_index in 0..line_count {
let line = &mut self.lines[line_index];
for (line_index, line) in self.lines.iter_mut().enumerate() {
// Lay out fragments in the inline direction, and justify them if necessary.
InlineFlow::set_inline_fragment_positions(&mut self.fragments,
line,
@ -1463,108 +1465,17 @@ impl Flow for InlineFlow {
indentation,
line_index + 1 == line_count);
// Set the block-start position of the current line.
// `line_height_offset` is updated at the end of the previous loop.
line.bounds.start.b = line_distance_from_flow_block_start;
// Calculate the distance from the baseline to the block-start and block-end of the
// line.
let mut largest_block_size_above_baseline = self.minimum_block_size_above_baseline;
let mut largest_depth_below_baseline = self.minimum_depth_below_baseline;
// Calculate the largest block-size among fragments with 'top' and 'bottom' values
// respectively.
let (mut largest_block_size_for_top_fragments,
mut largest_block_size_for_bottom_fragments) = (Au(0), Au(0));
for fragment_index in line.range.each_index() {
let fragment = &mut self.fragments.fragments[fragment_index.to_usize()];
let InlineMetrics {
mut block_size_above_baseline,
mut depth_below_baseline,
ascent
} = fragment.inline_metrics(layout_context);
// To calculate text-top and text-bottom value when `vertical-align` is involved,
// we should find the top and bottom of the content area of the parent fragment.
// "Content area" is defined in CSS 2.1 § 10.6.1.
//
// TODO: We should extract em-box info from the font size of the parent and
// calculate the distances from the baseline to the block-start and the block-end
// of the parent's content area.
// We should calculate the distance from baseline to the top of parent's content
// area. But for now we assume it's the font size.
//
// CSS 2.1 does not state which font to use. This version of the code uses
// the parent's font.
// Calculate the final block-size above the baseline for this fragment.
//
// The no-update flag decides whether `largest_block_size_for_top_fragments` and
// `largest_block_size_for_bottom_fragments` are to be updated or not. This will be
// set if and only if the fragment has `vertical-align` set to `top` or `bottom`.
let (distance_from_baseline, no_update_flag) =
InlineFlow::distance_from_baseline(
fragment,
ascent,
self.minimum_block_size_above_baseline,
self.minimum_depth_below_baseline,
&mut block_size_above_baseline,
&mut depth_below_baseline,
&mut largest_block_size_for_top_fragments,
&mut largest_block_size_for_bottom_fragments,
layout_context);
// Unless the current fragment has `vertical-align` set to `top` or `bottom`,
// `largest_block_size_above_baseline` and `largest_depth_below_baseline` are
// updated.
if !no_update_flag {
largest_block_size_above_baseline = max(block_size_above_baseline,
largest_block_size_above_baseline);
largest_depth_below_baseline = max(depth_below_baseline,
largest_depth_below_baseline);
}
// Temporarily use `fragment.border_box.start.b` to mean "the distance from the
// baseline". We will assign the real value later.
fragment.border_box.start.b = distance_from_baseline
}
// Calculate the distance from the baseline to the top of the largest fragment with a
// value for `bottom`. Then, if necessary, update `largest_block-size_above_baseline`.
largest_block_size_above_baseline =
max(largest_block_size_above_baseline,
largest_block_size_for_bottom_fragments - largest_depth_below_baseline);
// Calculate the distance from baseline to the bottom of the largest fragment with a
// value for `top`. Then, if necessary, update `largest_depth_below_baseline`.
largest_depth_below_baseline =
max(largest_depth_below_baseline,
largest_block_size_for_top_fragments - largest_block_size_above_baseline);
// Now, the distance from the logical block-start of the line to the baseline can be
// computed as `largest_block-size_above_baseline`.
let baseline_distance_from_block_start = largest_block_size_above_baseline;
// Compute the final positions in the block direction of each fragment. Recall that
// `fragment.border_box.start.b` was set to the distance from the baseline above.
// Compute the final positions in the block direction of each fragment.
InlineFlow::set_block_fragment_positions(&mut self.fragments,
line,
line_distance_from_flow_block_start,
baseline_distance_from_block_start,
largest_depth_below_baseline);
self.minimum_block_size_above_baseline,
self.minimum_depth_below_baseline,
layout_context);
// This is used to set the block-start position of the next line in the next loop.
line.bounds.size.block = largest_block_size_above_baseline +
largest_depth_below_baseline;
line_distance_from_flow_block_start = line_distance_from_flow_block_start +
line.bounds.size.block;
// We're no longer on the first line, so set indentation to zero.
// This is used to set the block-start position of the next line in the next iteration
// of the loop. We're no longer on the first line, so set indentation to zero.
indentation = Au(0)
} // End of `lines.iter_mut()` loop.
}
// Assign block sizes for any inline-block descendants.
let thread_id = self.base.thread_id;
@ -1951,22 +1862,6 @@ impl InlineMetrics {
}
}
/// Calculates inline metrics from font metrics and line block-size per CSS 2.1 § 10.8.1.
#[inline]
pub fn from_block_height(font_metrics: &FontMetrics,
block_height: Au,
block_start_margin: Au,
block_end_margin: Au)
-> InlineMetrics {
let leading = block_height + block_start_margin + block_end_margin -
(font_metrics.ascent + font_metrics.descent);
InlineMetrics {
block_size_above_baseline: font_metrics.ascent + leading.scale_by(0.5),
depth_below_baseline: font_metrics.descent + leading.scale_by(0.5),
ascent: font_metrics.ascent + leading.scale_by(0.5) - block_start_margin,
}
}
pub fn block_size(&self) -> Au {
self.block_size_above_baseline + self.depth_below_baseline
}

View file

@ -1837,6 +1837,21 @@ pub mod computed {
Auto,
Calc(CalcLengthOrPercentage),
}
impl LengthOrPercentageOrAuto {
/// Returns true if the computed value is absolute 0 or 0%.
///
/// (Returns false for calc() values, even if ones that may resolve to zero.)
#[inline]
pub fn is_definitely_zero(&self) -> bool {
use self::LengthOrPercentageOrAuto::*;
match *self {
Length(Au(0)) | Percentage(0.0) => true,
Length(_) | Percentage(_) | Calc(_) | Auto => false
}
}
}
impl fmt::Debug for LengthOrPercentageOrAuto {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {

View file

@ -0,0 +1,3 @@
[flexbox_align-items-stretch-2.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +1,3 @@
[c414-flt-fit-001.htm]
[ttwf-reftest-flex-inline.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[c414-flt-wrap-001.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[c5525-fltmrgn-000.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[c5525-fltwidth-001.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[first-line-pseudo-014.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[first-line-pseudo-015.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[floats-132.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[floats-wrap-top-below-inline-002l.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[floats-wrap-top-below-inline-002r.htm]
type: reftest
expected: FAIL

View file

@ -1,4 +0,0 @@
[inline-block-zorder-003.htm]
type: reftest
expected:
if os == "mac": FAIL

View file

@ -1,3 +0,0 @@
[inline-replaced-width-012.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[inline-replaced-width-013.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[inline-replaced-width-015.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[left-applies-to-012.htm]
type: reftest
expected: FAIL

View file

@ -1,3 +0,0 @@
[right-applies-to-012.htm]
type: reftest
expected: FAIL

View file

@ -1644,6 +1644,18 @@
"url": "/_mozilla/css/floats_margin_collapse_with_clearance_a.html"
}
],
"css/floats_percentage_width_a.html": [
{
"path": "css/floats_percentage_width_a.html",
"references": [
[
"/_mozilla/css/floats_percentage_width_ref.html",
"=="
]
],
"url": "/_mozilla/css/floats_percentage_width_a.html"
}
],
"css/focus_selector.html": [
{
"path": "css/focus_selector.html",
@ -2280,6 +2292,18 @@
"url": "/_mozilla/css/inline_background_a.html"
}
],
"css/inline_block_absolute_hypothetical_a.html": [
{
"path": "css/inline_block_absolute_hypothetical_a.html",
"references": [
[
"/_mozilla/css/inline_block_absolute_hypothetical_ref.html",
"=="
]
],
"url": "/_mozilla/css/inline_block_absolute_hypothetical_a.html"
}
],
"css/inline_block_baseline_a.html": [
{
"path": "css/inline_block_baseline_a.html",
@ -8408,6 +8432,18 @@
"url": "/_mozilla/css/floats_margin_collapse_with_clearance_a.html"
}
],
"css/floats_percentage_width_a.html": [
{
"path": "css/floats_percentage_width_a.html",
"references": [
[
"/_mozilla/css/floats_percentage_width_ref.html",
"=="
]
],
"url": "/_mozilla/css/floats_percentage_width_a.html"
}
],
"css/focus_selector.html": [
{
"path": "css/focus_selector.html",
@ -9044,6 +9080,18 @@
"url": "/_mozilla/css/inline_background_a.html"
}
],
"css/inline_block_absolute_hypothetical_a.html": [
{
"path": "css/inline_block_absolute_hypothetical_a.html",
"references": [
[
"/_mozilla/css/inline_block_absolute_hypothetical_ref.html",
"=="
]
],
"url": "/_mozilla/css/inline_block_absolute_hypothetical_a.html"
}
],
"css/inline_block_baseline_a.html": [
{
"path": "css/inline_block_baseline_a.html",

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title></title>
<style>
* {
margin: 0;
padding: none;
}
div {
float: left;
width: 100%;
height: 100px;
background: gold;
}
</style>
<link rel="match" href="floats_percentage_width_ref.html">
<div></div>X

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title></title>
<style>
* {
margin: 0;
padding: none;
}
div {
width: 100%;
height: 100px;
background: gold;
}
</style>
<div></div>X

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="match" href="inline_block_absolute_hypothetical_ref.html">
<style>
span {
display: inline-block;
position: absolute;
top: 32px;
}
</style>
Hello <span>world</span>!

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<meta charset="utf-8">
<style>
span {
display: inline;
position: absolute;
top: 32px;
}
</style>
Hello <span>world</span>!

View file

@ -7,6 +7,8 @@ body, html {
input {
margin-left: 64px;
border: none;
background: lightblue;
color: transparent;
vertical-align: top;
}
</style>

View file

@ -7,6 +7,8 @@ input {
position: absolute;
left: 64px;
border: none;
background: lightblue;
color: transparent;
}
</style>
<input type=button value=Hello>