From 1807fd3cc5741e410b7eae4eb4c2f389c594b144 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 15 Apr 2016 15:57:24 -0700 Subject: [PATCH] Generate a fragment for an empty elements with borders or padding --- components/layout/construct.rs | 43 ++++++++++++++++++++++++++++++-- components/layout/incremental.rs | 14 +++++++++-- components/style/values.rs | 13 ++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 8bf1a416484..dd8b7ec0756 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -13,6 +13,7 @@ #![deny(unsafe_code)] +use app_units::Au; use block::BlockFlow; use context::LayoutContext; use data::{HAS_NEWLY_CONSTRUCTED_FLOW, PrivateLayoutData}; @@ -808,7 +809,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let mut abs_descendants = AbsoluteDescendants::new(); // Concatenate all the fragments of our kids, creating {ib} splits as necessary. + let mut is_empty = true; for kid in node.children() { + is_empty = false; if kid.get_pseudo_element_type() != PseudoElementType::Normal { self.process(&kid); } @@ -889,6 +892,22 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> } } + if is_empty && node.style().has_padding_or_border() { + // An empty inline box needs at least one fragment to draw its background and borders. + let info = SpecificFragmentInfo::UnscannedText( + box UnscannedTextFragmentInfo::new(String::new(), None)); + let mut modified_style = node.style().clone(); + properties::modify_style_for_replaced_content(&mut modified_style); + properties::modify_style_for_text(&mut modified_style); + let fragment = Fragment::from_opaque_node_and_style(node.opaque(), + node.get_pseudo_element_type().strip(), + modified_style, + node.selected_style().clone(), + node.restyle_damage(), + info); + fragment_accumulator.fragments.fragments.push_back(fragment) + } + // Finally, make a new construction result. if opt_inline_block_splits.len() > 0 || !fragment_accumulator.fragments.is_empty() || abs_descendants.len() > 0 { @@ -923,8 +942,6 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> } // If this node is ignorable whitespace, bail out now. - // - // FIXME(#2001, pcwalton): Don't do this if there's padding or borders. if node.is_ignorable_whitespace() { return ConstructionResult::ConstructionItem(ConstructionItem::Whitespace( node.opaque(), @@ -1852,3 +1869,25 @@ fn control_chars_to_fragment(node: &InlineFragmentNodeInfo, restyle_damage, info) } + +/// Convenience methods for computed CSS values +trait ComputedValueUtils { + /// Returns true if this node has non-zero padding or border. + fn has_padding_or_border(&self) -> bool; +} + +impl ComputedValueUtils for ServoComputedValues { + fn has_padding_or_border(&self) -> bool { + let padding = self.get_padding(); + let border = self.get_border(); + + !padding.padding_top.is_definitely_zero() || + !padding.padding_right.is_definitely_zero() || + !padding.padding_bottom.is_definitely_zero() || + !padding.padding_left.is_definitely_zero() || + border.border_top_width != Au(0) || + border.border_right_width != Au(0) || + border.border_bottom_width != Au(0) || + border.border_left_width != Au(0) + } +} diff --git a/components/layout/incremental.rs b/components/layout/incremental.rs index cc34dc49bcd..affb4f42c70 100644 --- a/components/layout/incremental.rs +++ b/components/layout/incremental.rs @@ -5,7 +5,7 @@ use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, IS_ABSOLUTELY_POSITIONED}; use std::fmt; use std::sync::Arc; -use style::computed_values::float; +use style::computed_values::{display, float}; use style::dom::TRestyleDamage; use style::properties::{ComputedValues, ServoComputedValues}; @@ -193,7 +193,17 @@ pub fn compute_damage(old: Option<&Arc>, new: &ServoCompute get_text.text_decoration, get_text.unicode_bidi, get_inheritedtable.empty_cells, get_inheritedtable.caption_side, get_column.column_width, get_column.column_count - ]) || add_if_not_equal!(old, new, damage, + ]) || (new.get_box().display == display::T::inline && + add_if_not_equal!(old, new, damage, + [REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW, + RECONSTRUCT_FLOW], [ + // For inline boxes only, border/padding styles are used in flow construction (to decide + // whether to create fragments for empty flows). + get_border.border_top_width, get_border.border_right_width, + get_border.border_bottom_width, get_border.border_left_width, + get_padding.padding_top, get_padding.padding_right, + get_padding.padding_bottom, get_padding.padding_left + ])) || add_if_not_equal!(old, new, damage, [ REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW ], [get_border.border_top_width, get_border.border_right_width, get_border.border_bottom_width, get_border.border_left_width, diff --git a/components/style/values.rs b/components/style/values.rs index 754125bfc21..79239788704 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -1662,9 +1662,22 @@ pub mod computed { } impl LengthOrPercentage { + #[inline] pub fn zero() -> LengthOrPercentage { LengthOrPercentage::Length(Au(0)) } + + /// 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::LengthOrPercentage::*; + match *self { + Length(Au(0)) | Percentage(0.0) => true, + Length(_) | Percentage(_) | Calc(_) => false + } + } } impl fmt::Debug for LengthOrPercentage {