aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Bergstrom <lbergstrom@mozilla.com>2014-08-27 10:24:49 -0500
committerLars Bergstrom <lbergstrom@mozilla.com>2014-08-27 10:24:49 -0500
commit370192451f46ab81dd07dae754280c88fc617c97 (patch)
tree5127807da3564f65bb16858ff1b9726ddceaf91b
parent1cea7223ec8c661c4737aedfbbe22f9a2bb8c811 (diff)
parentfa6b59901a4281b591d612480b5db22574363139 (diff)
downloadservo-370192451f46ab81dd07dae754280c88fc617c97.tar.gz
servo-370192451f46ab81dd07dae754280c88fc617c97.zip
Merge pull request #3134 from glennw/inline-background
Add support for backgrounds on inline elements. Fix fixup() by removing it.
-rw-r--r--src/components/layout/block.rs19
-rw-r--r--src/components/layout/construct.rs38
-rw-r--r--src/components/layout/fragment.rs113
-rw-r--r--src/components/layout/inline.rs325
-rw-r--r--src/components/layout/text.rs2
-rw-r--r--src/test/ref/basic.list2
-rw-r--r--src/test/ref/inline_background_a.html17
-rw-r--r--src/test/ref/inline_background_ref.html14
8 files changed, 155 insertions, 375 deletions
diff --git a/src/components/layout/block.rs b/src/components/layout/block.rs
index 4c17cebc97f..5b433e44636 100644
--- a/src/components/layout/block.rs
+++ b/src/components/layout/block.rs
@@ -1107,8 +1107,7 @@ impl BlockFlow {
let rel_offset =
self.fragment.relative_position(&self.base
.absolute_position_info
- .relative_containing_block_size,
- None);
+ .relative_containing_block_size);
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
@@ -1120,8 +1119,7 @@ impl BlockFlow {
layout_context,
self.base.abs_position + (offset + rel_offset).to_physical(
self.base.writing_mode, container_size),
- background_border_level,
- None);
+ background_border_level);
let mut child_layers = DList::new();
for kid in self.base.child_iter() {
@@ -1470,7 +1468,7 @@ impl Flow for BlockFlow {
flags.union_floated_descendants_flags(child_base.flags);
}
- let fragment_intrinsic_inline_sizes = self.fragment.intrinsic_inline_sizes(None);
+ let fragment_intrinsic_inline_sizes = self.fragment.intrinsic_inline_sizes();
intrinsic_inline_sizes.minimum_inline_size = geometry::max(intrinsic_inline_sizes.minimum_inline_size,
fragment_intrinsic_inline_sizes.minimum_inline_size);
intrinsic_inline_sizes.preferred_inline_size = geometry::max(intrinsic_inline_sizes.preferred_inline_size,
@@ -1624,8 +1622,7 @@ impl Flow for BlockFlow {
let relative_offset =
self.fragment.relative_position(&self.base
.absolute_position_info
- .relative_containing_block_size,
- None);
+ .relative_containing_block_size);
if self.is_positioned() {
self.base.absolute_position_info.absolute_containing_block_position =
self.base.abs_position
@@ -1811,7 +1808,7 @@ pub trait ISizeAndMarginsComputer {
let containing_block_inline_size = self.containing_block_inline_size(block, parent_flow_inline_size, ctx);
let computed_inline_size = self.initial_computed_inline_size(block, parent_flow_inline_size, ctx);
- block.fragment.compute_border_padding_margins(containing_block_inline_size, None);
+ block.fragment.compute_border_padding_margins(containing_block_inline_size);
let style = block.fragment.style();
@@ -2257,7 +2254,7 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
-> MaybeAuto {
let containing_block_inline_size = block.containing_block_size(ctx.shared.screen_size).inline;
let fragment = block.fragment();
- fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size, None);
+ fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size);
// For replaced absolute flow, the rest of the constraint solving will
// take inline-size to be specified as the value computed here.
Specified(fragment.content_inline_size())
@@ -2306,7 +2303,7 @@ impl ISizeAndMarginsComputer for BlockReplaced {
_: &LayoutContext)
-> MaybeAuto {
let fragment = block.fragment();
- fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size, None);
+ fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size);
// For replaced block flow, the rest of the constraint solving will
// take inline-size to be specified as the value computed here.
Specified(fragment.content_inline_size())
@@ -2362,7 +2359,7 @@ impl ISizeAndMarginsComputer for FloatReplaced {
_: &LayoutContext)
-> MaybeAuto {
let fragment = block.fragment();
- fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size, None);
+ fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size);
// For replaced block flow, the rest of the constraint solving will
// take inline-size to be specified as the value computed here.
Specified(fragment.content_inline_size())
diff --git a/src/components/layout/construct.rs b/src/components/layout/construct.rs
index db6084a1c02..0f832bacfb8 100644
--- a/src/components/layout/construct.rs
+++ b/src/components/layout/construct.rs
@@ -32,7 +32,7 @@ use fragment::{ImageFragment, ImageFragmentInfo, SpecificFragmentInfo, TableFrag
use fragment::{TableCellFragment, TableColumnFragment, TableColumnFragmentInfo};
use fragment::{TableRowFragment, TableWrapperFragment, UnscannedTextFragment};
use fragment::{UnscannedTextFragmentInfo};
-use inline::{FragmentIndex, InlineFragments, InlineFlow};
+use inline::{InlineFragments, InlineFlow};
use parallel;
use table_wrapper::TableWrapperFlow;
use table::TableFlow;
@@ -57,7 +57,6 @@ use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstruc
use script::dom::node::{TextNodeTypeId};
use script::dom::htmlobjectelement::is_image_data;
use servo_util::namespace;
-use servo_util::range::Range;
use std::mem;
use std::sync::atomics::Relaxed;
use style::ComputedValues;
@@ -140,37 +139,40 @@ struct InlineFragmentsAccumulator {
/// The list of fragments.
fragments: InlineFragments,
- /// Whether we've created a range to enclose all the fragments. This will be true if the outer node
- /// is an inline and false otherwise.
- has_enclosing_range: bool,
+ /// Whether we've created a range to enclose all the fragments. This will be Some() if the outer node
+ /// is an inline and None otherwise.
+ enclosing_style: Option<Arc<ComputedValues>>,
}
impl InlineFragmentsAccumulator {
fn new() -> InlineFragmentsAccumulator {
InlineFragmentsAccumulator {
fragments: InlineFragments::new(),
- has_enclosing_range: false,
+ enclosing_style: None,
}
}
fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
- let mut fragments = InlineFragments::new();
- fragments.push_range(node.style().clone(), Range::empty());
+ let fragments = InlineFragments::new();
InlineFragmentsAccumulator {
fragments: fragments,
- has_enclosing_range: true,
+ enclosing_style: Some(node.style().clone()),
}
}
fn finish(self) -> InlineFragments {
let InlineFragmentsAccumulator {
fragments: mut fragments,
- has_enclosing_range
+ enclosing_style
} = self;
- if has_enclosing_range {
- let len = FragmentIndex(fragments.len() as int);
- fragments.get_mut_range(FragmentIndex(0)).range.extend_to(len);
+ match enclosing_style {
+ Some(enclosing_style) => {
+ for frag in fragments.fragments.mut_iter() {
+ frag.add_inline_context_style(enclosing_style.clone());
+ }
+ }
+ None => {}
}
fragments
}
@@ -374,10 +376,10 @@ impl<'a, 'b> FlowConstructor<'a, 'b> {
// Add whitespace results. They will be stripped out later on when
// between block elements, and retained when between inline elements.
let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::from_text(" ".to_string()));
- let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
+ let mut fragment = Fragment::from_opaque_node_and_style(whitespace_node,
whitespace_style.clone(),
fragment_info);
- inline_fragment_accumulator.fragments.push(fragment, whitespace_style);
+ inline_fragment_accumulator.fragments.push(&mut fragment, whitespace_style);
}
ConstructionItemConstructionResult(TableColumnFragmentConstructionItem(_)) => {
// TODO: Implement anonymous table objects for missing parents
@@ -525,10 +527,10 @@ impl<'a, 'b> FlowConstructor<'a, 'b> {
=> {
// Instantiate the whitespace fragment.
let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::from_text(" ".to_string()));
- let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
+ let mut fragment = Fragment::from_opaque_node_and_style(whitespace_node,
whitespace_style.clone(),
fragment_info);
- fragment_accumulator.fragments.push(fragment, whitespace_style)
+ fragment_accumulator.fragments.push(&mut fragment, whitespace_style)
}
ConstructionItemConstructionResult(TableColumnFragmentConstructionItem(_)) => {
// TODO: Implement anonymous table objects for missing parents
@@ -570,7 +572,7 @@ impl<'a, 'b> FlowConstructor<'a, 'b> {
}
let mut fragments = InlineFragments::new();
- fragments.push(Fragment::new(self, node), node.style().clone());
+ fragments.push(&mut Fragment::new(self, node), node.style().clone());
let construction_item = InlineFragmentsConstructionItem(InlineFragmentsConstructionResult {
splits: Vec::new(),
diff --git a/src/components/layout/fragment.rs b/src/components/layout/fragment.rs
index 316f29c0d23..19015b94f89 100644
--- a/src/components/layout/fragment.rs
+++ b/src/components/layout/fragment.rs
@@ -99,6 +99,10 @@ pub struct Fragment {
///
/// FIXME(#2260, pcwalton): This is very inefficient; remove.
pub new_line_pos: Vec<CharIndex>,
+
+ /// Holds the style context information for fragments
+ /// that are part of an inline formatting context.
+ pub inline_context: Option<InlineFragmentContext>,
}
/// Info specific to the kind of fragment. Keep this enum small.
@@ -330,6 +334,7 @@ impl Fragment {
margin: LogicalMargin::zero(writing_mode),
specific: constructor.build_specific_fragment_info_for_node(node),
new_line_pos: vec!(),
+ inline_context: None,
}
}
@@ -345,6 +350,7 @@ impl Fragment {
margin: LogicalMargin::zero(writing_mode),
specific: specific,
new_line_pos: vec!(),
+ inline_context: None,
}
}
@@ -369,6 +375,7 @@ impl Fragment {
margin: LogicalMargin::zero(writing_mode),
specific: specific,
new_line_pos: vec!(),
+ inline_context: None,
}
}
@@ -386,6 +393,7 @@ impl Fragment {
margin: LogicalMargin::zero(writing_mode),
specific: specific,
new_line_pos: vec!(),
+ inline_context: None,
}
}
@@ -407,9 +415,19 @@ impl Fragment {
margin: self.margin,
specific: specific,
new_line_pos: self.new_line_pos.clone(),
+ inline_context: self.inline_context.clone(),
}
}
+ /// Adds a style to the inline context for this fragment. If the inline
+ /// context doesn't exist yet, it will be created.
+ pub fn add_inline_context_style(&mut self, style: Arc<ComputedValues>) {
+ if self.inline_context.is_none() {
+ self.inline_context = Some(InlineFragmentContext::new());
+ }
+ self.inline_context.get_mut_ref().styles.push(style.clone());
+ }
+
/// Uses the style only to estimate the intrinsic inline-sizes. These may be modified for text or
/// replaced elements.
fn style_specified_intrinsic_inline_size(&self) -> IntrinsicISizes {
@@ -444,7 +462,7 @@ impl Fragment {
};
// FIXME(#2261, pcwalton): This won't work well for inlines: is this OK?
- let border = self.border_width(None);
+ let border = self.border_width();
let surround_inline_size = margin_inline_start + margin_inline_end + padding_inline_start + padding_inline_end +
border.inline_start_end();
@@ -465,13 +483,12 @@ impl Fragment {
/// it should only be called during intrinsic inline-size computation or computation of
/// `border_padding`. Other consumers of this information should simply consult that field.
#[inline]
- fn border_width(&self, inline_fragment_context: Option<InlineFragmentContext>)
- -> LogicalMargin<Au> {
- match inline_fragment_context {
+ fn border_width(&self) -> LogicalMargin<Au> {
+ match self.inline_context {
None => self.style().logical_border_width(),
- Some(inline_fragment_context) => {
+ Some(ref inline_fragment_context) => {
let zero = LogicalMargin::zero(self.style.writing_mode);
- inline_fragment_context.ranges().fold(zero, |acc, range| acc + range.border())
+ inline_fragment_context.styles.iter().fold(zero, |acc, style| acc + style.logical_border_width())
}
}
}
@@ -480,8 +497,7 @@ impl Fragment {
/// style. After this call, the `border_padding` and the vertical direction of the `margin`
/// field will be correct.
pub fn compute_border_padding_margins(&mut self,
- containing_block_inline_size: Au,
- inline_fragment_context: Option<InlineFragmentContext>) {
+ containing_block_inline_size: Au) {
// Compute vertical margins. Note that this value will be ignored by layout if the style
// specifies `auto`.
match self.specific {
@@ -500,19 +516,19 @@ impl Fragment {
}
// Compute border.
- let border = self.border_width(inline_fragment_context);
+ let border = self.border_width();
// Compute padding.
let padding = match self.specific {
TableColumnFragment(_) | TableRowFragment |
TableWrapperFragment => LogicalMargin::zero(self.style.writing_mode),
_ => {
- match inline_fragment_context {
+ match self.inline_context {
None => model::padding_from_style(self.style(), containing_block_inline_size),
- Some(inline_fragment_context) => {
+ Some(ref inline_fragment_context) => {
let zero = LogicalMargin::zero(self.style.writing_mode);
- inline_fragment_context.ranges()
- .fold(zero, |acc, range| acc + range.padding())
+ inline_fragment_context.styles.iter()
+ .fold(zero, |acc, style| acc + model::padding_from_style(&**style, Au(0)))
}
}
}
@@ -523,8 +539,7 @@ impl Fragment {
// Return offset from original position because of `position: relative`.
pub fn relative_position(&self,
- containing_block_size: &LogicalSize<Au>,
- inline_fragment_context: Option<InlineFragmentContext>)
+ containing_block_size: &LogicalSize<Au>)
-> LogicalSize<Au> {
fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>)
-> LogicalSize<Au> {
@@ -544,16 +559,16 @@ impl Fragment {
// Go over the ancestor fragments and add all relative offsets (if any).
let mut rel_pos = LogicalSize::zero(self.style.writing_mode);
- match inline_fragment_context {
+ match self.inline_context {
None => {
if self.style().get_box().position == position::relative {
rel_pos = rel_pos + from_style(self.style(), containing_block_size);
}
}
- Some(inline_fragment_context) => {
- for range in inline_fragment_context.ranges() {
- if range.style.get_box().position == position::relative {
- rel_pos = rel_pos + from_style(&*range.style, containing_block_size);
+ Some(ref inline_fragment_context) => {
+ for style in inline_fragment_context.styles.iter() {
+ if style.get_box().position == position::relative {
+ rel_pos = rel_pos + from_style(&**style, containing_block_size);
}
}
},
@@ -634,6 +649,7 @@ impl Fragment {
/// Adds the display items necessary to paint the background of this fragment to the display
/// list if necessary.
pub fn build_display_list_for_background_if_applicable(&self,
+ style: &ComputedValues,
list: &mut DisplayList,
layout_context: &LayoutContext,
level: StackingLevel,
@@ -642,7 +658,6 @@ impl Fragment {
// needed. We could use display list optimization to clean this up, but it still seems
// inefficient. What we really want is something like "nearest ancestor element that
// doesn't have a fragment".
- let style = self.style();
let background_color = style.resolve_color(style.get_background().background_color);
if !background_color.alpha.approx_eq(&0.0) {
let display_item = box SolidColorDisplayItem {
@@ -742,11 +757,9 @@ impl Fragment {
pub fn build_display_list_for_borders_if_applicable(&self,
list: &mut DisplayList,
abs_bounds: &Rect<Au>,
- level: StackingLevel,
- inline_fragment_context:
- Option<InlineFragmentContext>) {
+ level: StackingLevel) {
// Fast path.
- let border = self.border_width(inline_fragment_context);
+ let border = self.border_width();
if border.is_zero() {
return
}
@@ -844,8 +857,7 @@ impl Fragment {
display_list: &mut DisplayList,
layout_context: &LayoutContext,
flow_origin: Point2D<Au>,
- background_and_border_level: BackgroundAndBorderLevel,
- inline_fragment_context: Option<InlineFragmentContext>)
+ background_and_border_level: BackgroundAndBorderLevel)
-> ChildDisplayListAccumulator {
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
@@ -886,18 +898,31 @@ impl Fragment {
display_list.push(PseudoDisplayItemClass(base_display_item));
// Add the background to the list, if applicable.
- self.build_display_list_for_background_if_applicable(display_list,
- layout_context,
- level,
- &absolute_fragment_bounds);
+ match self.inline_context {
+ Some(ref inline_context) => {
+ for style in inline_context.styles.iter().rev() {
+ self.build_display_list_for_background_if_applicable(&**style,
+ display_list,
+ layout_context,
+ level,
+ &absolute_fragment_bounds);
+ }
+ }
+ None => {
+ self.build_display_list_for_background_if_applicable(&*self.style,
+ display_list,
+ layout_context,
+ level,
+ &absolute_fragment_bounds);
+ }
+ }
// Add a border, if applicable.
//
// TODO: Outlines.
self.build_display_list_for_borders_if_applicable(display_list,
&absolute_fragment_bounds,
- level,
- inline_fragment_context);
+ level);
}
// Add a clip, if applicable.
@@ -944,8 +969,8 @@ impl Fragment {
// FIXME(#2263, pcwalton): This is a bit of an abuse of the logging infrastructure.
// We should have a real `SERVO_DEBUG` system.
debug!("{:?}", self.build_debug_borders_around_text_fragments(display_list,
- flow_origin,
- text_fragment))
+ flow_origin,
+ text_fragment))
},
GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment | TableRowFragment |
TableWrapperFragment => {
@@ -1017,7 +1042,7 @@ impl Fragment {
}
/// Returns the intrinsic inline-sizes of this fragment.
- pub fn intrinsic_inline_sizes(&mut self, inline_fragment_context: Option<InlineFragmentContext>)
+ pub fn intrinsic_inline_sizes(&mut self)
-> IntrinsicISizes {
let mut result = self.style_specified_intrinsic_inline_size();
@@ -1046,12 +1071,12 @@ impl Fragment {
}
// Take borders and padding for parent inline fragments into account, if necessary.
- match inline_fragment_context {
+ match self.inline_context {
None => {}
- Some(context) => {
- for range in context.ranges() {
- let border_width = range.border().inline_start_end();
- let padding_inline_size = range.padding().inline_start_end();
+ Some(ref context) => {
+ for style in context.styles.iter() {
+ let border_width = style.logical_border_width().inline_start_end();
+ let padding_inline_size = model::padding_from_style(&**style, Au(0)).inline_start_end();
result.minimum_inline_size = result.minimum_inline_size + border_width + padding_inline_size;
result.preferred_inline_size = result.preferred_inline_size + border_width + padding_inline_size;
}
@@ -1265,9 +1290,7 @@ impl Fragment {
/// Assigns replaced inline-size, padding, and margins for this fragment only if it is replaced
/// content per CSS 2.1 § 10.3.2.
pub fn assign_replaced_inline_size_if_necessary(&mut self,
- container_inline_size: Au,
- inline_fragment_context:
- Option<InlineFragmentContext>) {
+ container_inline_size: Au) {
match self.specific {
GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment |
TableWrapperFragment => return,
@@ -1276,7 +1299,7 @@ impl Fragment {
ImageFragment(_) | ScannedTextFragment(_) => {}
};
- self.compute_border_padding_margins(container_inline_size, inline_fragment_context);
+ self.compute_border_padding_margins(container_inline_size);
let style_inline_size = self.style().content_inline_size();
let style_block_size = self.style().content_block_size();
diff --git a/src/components/layout/inline.rs b/src/components/layout/inline.rs
index 9b6b0af28d7..bdbabe31f5e 100644
--- a/src/components/layout/inline.rs
+++ b/src/components/layout/inline.rs
@@ -11,7 +11,6 @@ use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass};
use flow;
use fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
use model::IntrinsicISizes;
-use model;
use text;
use wrapper::ThreadSafeLayoutNode;
@@ -23,14 +22,12 @@ use gfx::font_context::FontContext;
use gfx::text::glyph::CharIndex;
use servo_util::geometry::Au;
use servo_util::geometry;
-use servo_util::logical_geometry::{LogicalRect, LogicalMargin, LogicalSize};
+use servo_util::logical_geometry::{LogicalRect, LogicalSize};
use servo_util::range;
use servo_util::range::{EachIndex, Range, RangeIndex, IntRangeIndex};
-use std::iter::Enumerate;
use std::fmt;
use std::mem;
use std::num;
-use std::slice::{Items, MutItems};
use std::u16;
use style::computed_values::{text_align, vertical_align, white_space};
use style::ComputedValues;
@@ -342,7 +339,7 @@ impl LineBreaker {
}
}
- old_fragments.fixup(mem::replace(&mut self.new_fragments, vec![]));
+ old_fragments.fragments = mem::replace(&mut self.new_fragments, vec![]);
flow.fragments = old_fragments;
flow.lines = mem::replace(&mut self.lines, Vec::new());
}
@@ -627,43 +624,10 @@ impl LineBreaker {
}
}
-/// Iterator over fragments.
-pub struct FragmentIterator<'a> {
- iter: Enumerate<Items<'a,Fragment>>,
- ranges: &'a Vec<InlineFragmentRange>,
-}
-
-impl<'a> Iterator<(&'a Fragment, InlineFragmentContext<'a>)> for FragmentIterator<'a> {
- #[inline]
- fn next(&mut self) -> Option<(&'a Fragment, InlineFragmentContext<'a>)> {
- self.iter.next().map(|(i, fragment)| {
- (fragment, InlineFragmentContext::new(self.ranges, FragmentIndex(i as int)))
- })
- }
-}
-
-/// Mutable iterator over fragments.
-pub struct MutFragmentIterator<'a> {
- iter: Enumerate<MutItems<'a,Fragment>>,
- ranges: &'a Vec<InlineFragmentRange>,
-}
-
-impl<'a> Iterator<(&'a mut Fragment, InlineFragmentContext<'a>)> for MutFragmentIterator<'a> {
- #[inline]
- fn next(&mut self) -> Option<(&'a mut Fragment, InlineFragmentContext<'a>)> {
- self.iter.next().map(|(i, fragment)| {
- (fragment, InlineFragmentContext::new(self.ranges, FragmentIndex(i as int)))
- })
- }
-}
-
/// Represents a list of inline fragments, including element ranges.
pub struct InlineFragments {
/// The fragments themselves.
pub fragments: Vec<Fragment>,
- /// Tracks the elements that made up the fragments above. This is used to
- /// recover the DOM structure from the `fragments` when it's needed.
- pub ranges: Vec<InlineFragmentRange>,
}
impl InlineFragments {
@@ -671,7 +635,6 @@ impl InlineFragments {
pub fn new() -> InlineFragments {
InlineFragments {
fragments: vec![],
- ranges: vec![],
}
}
@@ -686,35 +649,14 @@ impl InlineFragments {
}
/// Pushes a new inline fragment.
- pub fn push(&mut self, fragment: Fragment, style: Arc<ComputedValues>) {
- self.ranges.push(InlineFragmentRange::new(
- style, Range::new(FragmentIndex(self.fragments.len() as int), FragmentIndex(1)),
- ));
- self.fragments.push(fragment)
+ pub fn push(&mut self, fragment: &mut Fragment, style: Arc<ComputedValues>) {
+ fragment.add_inline_context_style(style);
+ self.fragments.push(fragment.clone());
}
/// Merges another set of inline fragments with this one.
- pub fn push_all(&mut self, InlineFragments { fragments, ranges }: InlineFragments) {
- let adjustment = FragmentIndex(self.fragments.len() as int);
- self.push_all_ranges(ranges, adjustment);
- self.fragments.push_all_move(fragments);
- }
-
- /// Returns an iterator that iterates over all fragments along with the appropriate context.
- pub fn iter<'a>(&'a self) -> FragmentIterator<'a> {
- FragmentIterator {
- iter: self.fragments.as_slice().iter().enumerate(),
- ranges: &self.ranges,
- }
- }
-
- /// Returns an iterator that iterates over all fragments along with the appropriate context and
- /// allows those fragments to be mutated.
- pub fn mut_iter<'a>(&'a mut self) -> MutFragmentIterator<'a> {
- MutFragmentIterator {
- iter: self.fragments.as_mut_slice().mut_iter().enumerate(),
- ranges: &self.ranges,
- }
+ pub fn push_all(&mut self, fragments: InlineFragments) {
+ self.fragments.push_all_move(fragments.fragments);
}
/// A convenience function to return the fragment at a given index.
@@ -727,134 +669,6 @@ impl InlineFragments {
self.fragments.get_mut(index)
}
- /// Adds the given node to the fragment map.
- pub fn push_range(&mut self, style: Arc<ComputedValues>, range: Range<FragmentIndex>) {
- self.ranges.push(InlineFragmentRange::new(style, range))
- }
-
- /// Pushes the ranges in a fragment map, adjusting indices as necessary.
- fn push_all_ranges(&mut self, ranges: Vec<InlineFragmentRange>, adjustment: FragmentIndex) {
- for other_range in ranges.move_iter() {
- let InlineFragmentRange {
- style: other_style,
- range: mut other_range
- } = other_range;
-
- other_range.shift_by(adjustment);
- self.push_range(other_style, other_range)
- }
- }
-
- /// Returns the range with the given index.
- pub fn get_mut_range<'a>(&'a mut self, index: FragmentIndex) -> &'a mut InlineFragmentRange {
- self.ranges.get_mut(index.to_uint())
- }
-
- /// Rebuilds the list after the fragments have been split or deleted (for example, for line
- /// breaking). This assumes that the overall structure of the DOM has not changed; if the
- /// DOM has changed, then the flow constructor will need to do more complicated surgery than
- /// this function can provide.
- ///
- /// FIXME(#2267, pcwalton): It would be more efficient to not have to clone fragments all the time;
- /// i.e. if `self.fragments` contained less info than the entire range of fragments. See
- /// `layout::construct::strip_ignorable_whitespace_from_start` for an example of some code that
- /// needlessly has to clone fragments.
- pub fn fixup(&mut self, new_fragments: Vec<Fragment>) {
- // TODO(pcwalton): Post Rust upgrade, use `with_capacity` here.
- let old_list = mem::replace(&mut self.ranges, vec![]);
- let mut worklist = vec![]; // FIXME(#2269, pcwalton): was smallvec4
- let mut old_list_iter = old_list.move_iter().peekable();
-
- { // Enter a new scope so that new_fragments_iter's borrow is released
- let mut new_fragments_iter = new_fragments.iter().enumerate().peekable();
- // FIXME(#2270, pcwalton): I don't think this will work if multiple old fragments
- // correspond to the same node.
- for (i, old_fragment) in self.fragments.iter().enumerate() {
- let old_fragment_index = FragmentIndex(i as int);
- // Find the start of the corresponding new fragment.
- let new_fragment_start = match new_fragments_iter.peek() {
- Some(&(index, new_fragment)) if new_fragment.node == old_fragment.node => {
- // We found the start of the corresponding new fragment.
- FragmentIndex(index as int)
- }
- Some(_) | None => {
- // The old fragment got deleted entirely.
- continue
- }
- };
- drop(new_fragments_iter.next());
-
- // Eat any additional fragments that the old fragment got split into.
- loop {
- match new_fragments_iter.peek() {
- Some(&(_, new_fragment)) if new_fragment.node == old_fragment.node => {}
- Some(_) | None => break,
- }
- drop(new_fragments_iter.next());
- }
-
- // Find all ranges that started at this old fragment and add them onto the worklist.
- loop {
- match old_list_iter.peek() {
- None => break,
- Some(fragment_range) => {
- if fragment_range.range.begin() > old_fragment_index {
- // We haven't gotten to the appropriate old fragment yet, so stop.
- break
- }
- // Note that it can be the case that `fragment_range.range.begin() < i`.
- // This is OK, as it corresponds to the case in which a fragment got
- // deleted entirely (e.g. ignorable whitespace got nuked). In that case we
- // want to keep the range, but shorten it.
- }
- };
-
- let InlineFragmentRange {
- style: style,
- range: old_range,
- } = old_list_iter.next().unwrap();
- worklist.push(InlineFragmentFixupWorkItem {
- style: style,
- new_start_index: new_fragment_start,
- old_end_index: old_range.end(),
- });
- }
-
- // Pop off any ranges that ended at this fragment.
- loop {
- match worklist.as_slice().last() {
- None => break,
- Some(last_work_item) => {
- if last_work_item.old_end_index > old_fragment_index + FragmentIndex(1) {
- // Haven't gotten to it yet.
- break
- }
- }
- }
-
- let new_last_index = match new_fragments_iter.peek() {
- None => {
- // At the end.
- FragmentIndex(new_fragments.len() as int)
- }
- Some(&(index, _)) => {
- FragmentIndex(index as int)
- },
- };
-
- let InlineFragmentFixupWorkItem {
- style,
- new_start_index,
- ..
- } = worklist.pop().unwrap();
- let range = Range::new(new_start_index, new_last_index - new_start_index);
- self.ranges.push(InlineFragmentRange::new(style, range))
- }
- }
- }
- self.fragments = new_fragments;
- }
-
/// Strips ignorable whitespace from the start of a list of fragments.
pub fn strip_ignorable_whitespace_from_start(&mut self) {
if self.is_empty() { return }; // Fast path
@@ -874,7 +688,7 @@ impl InlineFragments {
new_fragments.push(fragment);
}
- self.fixup(new_fragments);
+ self.fragments = new_fragments;
}
/// Strips ignorable whitespace from the end of a list of fragments.
@@ -889,7 +703,8 @@ impl InlineFragments {
drop(new_fragments.pop());
}
- self.fixup(new_fragments);
+
+ self.fragments = new_fragments;
}
}
@@ -936,17 +751,15 @@ impl InlineFlow {
// not recurse on a line if nothing in it can intersect the dirty region.
debug!("Flow: building display list for {:u} inline fragments", self.fragments.len());
- for (fragment, context) in self.fragments.mut_iter() {
+ for fragment in self.fragments.fragments.mut_iter() {
let rel_offset = fragment.relative_position(&self.base
.absolute_position_info
- .relative_containing_block_size,
- Some(context));
+ .relative_containing_block_size);
drop(fragment.build_display_list(&mut self.base.display_list,
layout_context,
self.base.abs_position.add_size(
&rel_offset.to_physical(self.base.writing_mode)),
- ContentLevel,
- Some(context)));
+ ContentLevel));
}
// TODO(#225): Should `inline-block` elements have flows as children of the inline flow or
@@ -1095,11 +908,11 @@ impl Flow for InlineFlow {
}
let mut intrinsic_inline_sizes = IntrinsicISizes::new();
- for (fragment, context) in self.fragments.mut_iter() {
+ for fragment in self.fragments.fragments.mut_iter() {
debug!("Flow: measuring {}", *fragment);
let fragment_intrinsic_inline_sizes =
- fragment.intrinsic_inline_sizes(Some(context));
+ fragment.intrinsic_inline_sizes();
intrinsic_inline_sizes.minimum_inline_size = geometry::max(
intrinsic_inline_sizes.minimum_inline_size,
fragment_intrinsic_inline_sizes.minimum_inline_size);
@@ -1123,9 +936,8 @@ impl Flow for InlineFlow {
{
let inline_size = self.base.position.size.inline;
let this = &mut *self;
- for (fragment, context) in this.fragments.mut_iter() {
- fragment.assign_replaced_inline_size_if_necessary(inline_size,
- Some(context))
+ for fragment in this.fragments.fragments.mut_iter() {
+ fragment.assign_replaced_inline_size_if_necessary(inline_size);
}
}
@@ -1157,7 +969,7 @@ impl Flow for InlineFlow {
debug!("assign_block_size_inline: floats in: {:?}", self.base.floats);
// assign block-size for inline fragments
- for (fragment, _) in self.fragments.mut_iter() {
+ for fragment in self.fragments.fragments.mut_iter() {
fragment.assign_replaced_block_size_if_necessary();
}
@@ -1305,7 +1117,7 @@ impl Flow for InlineFlow {
impl fmt::Show for InlineFlow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "InlineFlow"));
- for (i, (fragment, _)) in self.fragments.iter().enumerate() {
+ for (i, fragment) in self.fragments.fragments.iter().enumerate() {
if i == 0 {
try!(write!(f, ": {}", fragment))
} else {
@@ -1316,102 +1128,15 @@ impl fmt::Show for InlineFlow {
}
}
-/// Information that inline flows keep about a single nested element. This is used to recover the
-/// DOM structure from the flat fragment list when it's needed.
-pub struct InlineFragmentRange {
- /// The style of the DOM node that this range refers to.
- pub style: Arc<ComputedValues>,
- /// The range, in indices into the fragment list.
- pub range: Range<FragmentIndex>,
-}
-
-impl InlineFragmentRange {
- /// Creates a new fragment range from the given values.
- fn new(style: Arc<ComputedValues>, range: Range<FragmentIndex>) -> InlineFragmentRange {
- InlineFragmentRange {
- style: style,
- range: range,
- }
- }
-
- /// Returns the dimensions of the border in this fragment range.
- #[inline]
- pub fn border(&self) -> LogicalMargin<Au> {
- self.style.logical_border_width()
- }
-
- /// Returns the dimensions of the padding in this fragment range.
- #[inline]
- pub fn padding(&self) -> LogicalMargin<Au> {
- // FIXME(#2266, pcwalton): Is Au(0) right here for the containing block?
- model::padding_from_style(&*self.style, Au(0))
- }
-}
-
-struct InlineFragmentFixupWorkItem {
- style: Arc<ComputedValues>,
- new_start_index: FragmentIndex,
- old_end_index: FragmentIndex,
-}
-
-/// The type of an iterator over fragment ranges in the fragment map.
-pub struct RangeIterator<'a> {
- iter: Items<'a,InlineFragmentRange>,
- index: FragmentIndex,
- is_first: bool,
+#[deriving(Clone)]
+pub struct InlineFragmentContext {
+ pub styles: Vec<Arc<ComputedValues>>,
}
-impl<'a> Iterator<&'a InlineFragmentRange> for RangeIterator<'a> {
- fn next(&mut self) -> Option<&'a InlineFragmentRange> {
- if !self.is_first {
- // Yield the next fragment range if it contains the index
- self.iter.next().and_then(|frag_range| {
- if frag_range.range.contains(self.index) { Some(frag_range) } else { None }
- })
- } else {
- // Find the first fragment range that contains the index if it exists
- let index = self.index;
- let first = self.iter.by_ref().find(|frag_range| {
- frag_range.range.contains(index)
- });
- self.is_first = false; // We have made our first iteration
- first
- }
- }
-}
-
-/// The context that an inline fragment appears in. This allows the fragment map to be passed in
-/// conveniently to various fragment functions.
-pub struct InlineFragmentContext<'a> {
- ranges: &'a Vec<InlineFragmentRange>,
- index: FragmentIndex,
-}
-
-impl<'a> InlineFragmentContext<'a> {
- pub fn new<'a>(ranges: &'a Vec<InlineFragmentRange>, index: FragmentIndex) -> InlineFragmentContext<'a> {
+impl InlineFragmentContext {
+ pub fn new() -> InlineFragmentContext {
InlineFragmentContext {
- ranges: ranges,
- index: index,
- }
- }
-
- /// Iterates over all ranges that contain the fragment at context's index, outermost first.
- #[inline(always)]
- pub fn ranges(&self) -> RangeIterator<'a> {
- // TODO: It would be more straightforward to return an existing iterator
- // rather defining our own `RangeIterator`, but this requires unboxed
- // closures in order to satisfy the borrow checker:
- //
- // ~~~rust
- // let index = self.index;
- // self.ranges.iter()
- // .skip_while(|fr| fr.range.contains(index))
- // .take_while(|fr| fr.range.contains(index))
- // ~~~
- RangeIterator {
- iter: self.ranges.iter(),
- index: self.index,
- is_first: true,
+ styles: vec!()
}
}
}
diff --git a/src/components/layout/text.rs b/src/components/layout/text.rs
index 4aad9d187b0..569580995c8 100644
--- a/src/components/layout/text.rs
+++ b/src/components/layout/text.rs
@@ -75,7 +75,7 @@ impl TextRunScanner {
debug!("TextRunScanner: swapping out fragments.");
- fragments.fixup(new_fragments);
+ fragments.fragments = new_fragments;
}
/// A "clump" is a range of inline flow leaves that can be merged together into a single
diff --git a/src/test/ref/basic.list b/src/test/ref/basic.list
index 9884fe140b4..5ba2816f037 100644
--- a/src/test/ref/basic.list
+++ b/src/test/ref/basic.list
@@ -103,3 +103,5 @@ experimental == vertical-lr-blocks.html vertical-lr-blocks_ref.html
# FIXME: use the real test when pixel-snapping for scrolling is fixed.
#== ../html/acid2.html#top acid2_ref_broken.html
flaky_gpu,flaky_linux == acid2_noscroll.html acid2_ref_broken.html
+
+!= inline_background_a.html inline_background_ref.html
diff --git a/src/test/ref/inline_background_a.html b/src/test/ref/inline_background_a.html
new file mode 100644
index 00000000000..58a34046d5d
--- /dev/null
+++ b/src/test/ref/inline_background_a.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <style type="text/css">
+ .white {
+ color: white;
+ }
+ .bggreen {
+ background-color: green;
+ }
+ body {
+ margin: 0;
+ }
+ </style>
+ </head>
+ <body><span class="bggreen white">White text on a green background</span></body>
+</html>
diff --git a/src/test/ref/inline_background_ref.html b/src/test/ref/inline_background_ref.html
new file mode 100644
index 00000000000..e2ecc75beba
--- /dev/null
+++ b/src/test/ref/inline_background_ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <style type="text/css">
+ .white {
+ color: white;
+ }
+ body {
+ margin: 0;
+ }
+ </style>
+ </head>
+ <body><span class="white">White text on a green background</span></body>
+</html>