mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
layout: Check flow descendants of inline block fragments to find their
baselines when aligning inline fragments per CSS 2.1 § 10.8.1.
This commit is contained in:
parent
8823f87276
commit
04f05349b1
6 changed files with 191 additions and 65 deletions
|
@ -33,7 +33,8 @@ use display_list_builder::BlockFlowDisplayListBuilding;
|
||||||
use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
|
use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use floats::{ClearType, FloatKind, Floats, PlacementInfo};
|
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::{IS_ABSOLUTELY_POSITIONED};
|
||||||
use flow::{ImmutableFlowUtils, LateAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
|
use flow::{ImmutableFlowUtils, LateAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
|
||||||
use flow::{NEEDS_LAYER, PostorderFlowTraversal, PreorderFlowTraversal, FragmentationContext};
|
use flow::{NEEDS_LAYER, PostorderFlowTraversal, PreorderFlowTraversal, FragmentationContext};
|
||||||
|
@ -1477,57 +1478,85 @@ impl BlockFlow {
|
||||||
pub fn bubble_inline_sizes_for_block(&mut self, consult_children: bool) {
|
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 _scope = layout_debug_scope!("block::bubble_inline_sizes {:x}", self.base.debug_id());
|
||||||
|
|
||||||
let flags = self.base.flags;
|
let mut flags = self.base.flags;
|
||||||
|
if self.definitely_has_zero_block_size() {
|
||||||
// Find the maximum inline-size from children.
|
// This is kind of a hack for Acid2. But it's a harmless one, because (a) this behavior
|
||||||
let mut computation = self.fragment.compute_intrinsic_inline_sizes();
|
// is unspecified; (b) it matches the behavior one would intuitively expect, since
|
||||||
let (mut left_float_width, mut right_float_width) = (Au(0), Au(0));
|
// floats don't flow around blocks that take up no space in the block direction.
|
||||||
let (mut left_float_width_accumulator, mut right_float_width_accumulator) = (Au(0), Au(0));
|
flags.remove(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
|
||||||
for kid in self.base.child_iter_mut() {
|
} else if self.fragment.is_text_or_replaced() {
|
||||||
let is_absolutely_positioned =
|
flags.insert(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
|
||||||
flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED);
|
} else {
|
||||||
let child_base = flow::mut_base(kid);
|
flags.remove(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
|
||||||
let float_kind = child_base.flags.float_kind();
|
for kid in self.base.children.iter() {
|
||||||
if !is_absolutely_positioned && consult_children {
|
if flow::base(kid).flags.contains(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS) {
|
||||||
computation.content_intrinsic_sizes.minimum_inline_size =
|
flags.insert(CONTAINS_TEXT_OR_REPLACED_FRAGMENTS);
|
||||||
max(computation.content_intrinsic_sizes.minimum_inline_size,
|
break
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 should consider all float descendants, not just children.
|
||||||
// FIXME(pcwalton): This is not well-spec'd; INTRINSIC specifies to do this, but CSS-SIZING
|
let mut computation = self.fragment.compute_intrinsic_inline_sizes();
|
||||||
// says not to. In practice, Gecko and WebKit both do this.
|
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);
|
left_float_width = max(left_float_width, left_float_width_accumulator);
|
||||||
right_float_width = max(right_float_width, right_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 =
|
computation.content_intrinsic_sizes.preferred_inline_size =
|
||||||
max(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.intrinsic_inline_sizes = computation.finish();
|
||||||
self.base.flags = flags
|
self.base.flags = flags
|
||||||
|
@ -1630,6 +1659,18 @@ impl BlockFlow {
|
||||||
FormattingContextType::None | FormattingContextType::Other => {}
|
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 {
|
impl Flow for BlockFlow {
|
||||||
|
|
|
@ -512,6 +512,8 @@ pub trait ImmutableFlowUtils {
|
||||||
/// Returns true if floats might flow through this flow, as determined by the float placement
|
/// Returns true if floats might flow through this flow, as determined by the float placement
|
||||||
/// speculation pass.
|
/// speculation pass.
|
||||||
fn floats_might_flow_through(self) -> bool;
|
fn floats_might_flow_through(self) -> bool;
|
||||||
|
|
||||||
|
fn baseline_offset_of_last_line_box_in_flow(self) -> Option<Au>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MutableFlowUtils {
|
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 = "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 = "get its own layer if it's deemed to be likely to overlap flows with their own"]
|
||||||
#[doc = "layer."]
|
#[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 = "Whether this flow is absolutely positioned. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[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 = "Whether this flow clears to the left. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[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 = "Whether this flow clears to the right. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[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 = "Whether this flow is left-floated. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[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 = "Whether this flow is right-floated. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[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. \
|
#[doc = "Text alignment. \
|
||||||
|
|
||||||
NB: If you update this, update `TEXT_ALIGN_SHIFT` below."]
|
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` \
|
#[doc = "Whether this flow has a fragment with `counter-reset` or `counter-increment` \
|
||||||
styles."]
|
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 \
|
#[doc = "Whether this flow's descendants have fragments that affect `counter-reset` or \
|
||||||
`counter-increment` styles."]
|
`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 \
|
#[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: \
|
of positioning in the inline direction. This is set for flows with `position: \
|
||||||
static` and `position: relative` as well as absolutely-positioned flows with \
|
static` and `position: relative` as well as absolutely-positioned flows with \
|
||||||
unconstrained positions in the inline direction."]
|
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 \
|
#[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: \
|
of positioning in the block direction. This is set for flows with `position: \
|
||||||
static` and `position: relative` as well as absolutely-positioned flows with \
|
static` and `position: relative` as well as absolutely-positioned flows with \
|
||||||
unconstrained positions in the block direction."]
|
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
|
/// 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1387,6 +1392,21 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
|
||||||
}
|
}
|
||||||
self.as_block().formatting_context_type() == FormattingContextType::None
|
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 {
|
impl<'a> MutableFlowUtils for &'a mut Flow {
|
||||||
|
|
|
@ -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> {
|
impl<'a> Iterator for MutFlowListIterator<'a> {
|
||||||
type Item = &'a mut Flow;
|
type Item = &'a mut Flow;
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1077,7 +1077,7 @@ impl Fragment {
|
||||||
/// Returns the sum of the inline-sizes of all the borders of this fragment. Note that this
|
/// 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.
|
/// can be expensive to compute, so if possible use the `border_padding` field instead.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn border_width(&self) -> LogicalMargin<Au> {
|
pub fn border_width(&self) -> LogicalMargin<Au> {
|
||||||
let style_border_width = match self.specific {
|
let style_border_width = match self.specific {
|
||||||
SpecificFragmentInfo::ScannedText(_) |
|
SpecificFragmentInfo::ScannedText(_) |
|
||||||
SpecificFragmentInfo::InlineBlock(_) => LogicalMargin::zero(self.style.writing_mode),
|
SpecificFragmentInfo::InlineBlock(_) => LogicalMargin::zero(self.style.writing_mode),
|
||||||
|
@ -1983,14 +1983,19 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::InlineBlock(ref info) => {
|
SpecificFragmentInfo::InlineBlock(ref info) => {
|
||||||
// See CSS 2.1 § 10.8.1.
|
// See CSS 2.1 § 10.8.1.
|
||||||
let block_flow = info.flow_ref.as_block();
|
let flow = &info.flow_ref;
|
||||||
let font_style = self.style.get_font_arc();
|
let block_flow = flow.as_block();
|
||||||
let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(),
|
let baseline_offset = match flow.baseline_offset_of_last_line_box_in_flow() {
|
||||||
font_style);
|
Some(baseline_offset) => baseline_offset,
|
||||||
InlineMetrics::from_block_height(&font_metrics,
|
None => block_flow.fragment.border_box.size.block,
|
||||||
block_flow.base.position.size.block,
|
};
|
||||||
block_flow.fragment.margin.block_start,
|
let start_margin = block_flow.fragment.margin.block_start;
|
||||||
block_flow.fragment.margin.block_end)
|
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::InlineAbsoluteHypothetical(_) |
|
||||||
SpecificFragmentInfo::InlineAbsolute(_) => {
|
SpecificFragmentInfo::InlineAbsolute(_) => {
|
||||||
|
@ -2552,6 +2557,28 @@ impl Fragment {
|
||||||
pub fn layer_id_for_overflow_scroll(&self) -> LayerId {
|
pub fn layer_id_for_overflow_scroll(&self) -> LayerId {
|
||||||
LayerId::new_of_type(LayerType::OverflowScroll, self.node.id() as usize)
|
LayerId::new_of_type(LayerType::OverflowScroll, self.node.id() as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl fmt::Debug for Fragment {
|
||||||
|
|
|
@ -11,7 +11,8 @@ use display_list_builder::DisplayListBuildState;
|
||||||
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
|
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
|
||||||
use euclid::{Point2D, Size2D};
|
use euclid::{Point2D, Size2D};
|
||||||
use floats::{FloatKind, Floats, PlacementInfo};
|
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::{self, BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, IS_ABSOLUTELY_POSITIONED};
|
||||||
use flow_ref;
|
use flow_ref;
|
||||||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
|
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
|
||||||
|
@ -1275,6 +1276,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 {
|
impl Flow for InlineFlow {
|
||||||
|
@ -1300,6 +1311,8 @@ impl Flow for InlineFlow {
|
||||||
flow::mut_base(kid).floats = Floats::new(writing_mode);
|
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_flow = IntrinsicISizesContribution::new();
|
||||||
let mut intrinsic_sizes_for_inline_run = IntrinsicISizesContribution::new();
|
let mut intrinsic_sizes_for_inline_run = IntrinsicISizesContribution::new();
|
||||||
let mut intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
|
let mut intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
|
||||||
|
@ -1358,6 +1371,10 @@ impl Flow for InlineFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment.restyle_damage.remove(BUBBLE_ISIZES);
|
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.
|
// Flush any remaining nonbroken-run and inline-run intrinsic sizes.
|
||||||
|
|
|
@ -1837,6 +1837,21 @@ pub mod computed {
|
||||||
Auto,
|
Auto,
|
||||||
Calc(CalcLengthOrPercentage),
|
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 {
|
impl fmt::Debug for LengthOrPercentageOrAuto {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue