diff options
author | Lars Bergstrom <lbergstrom@mozilla.com> | 2014-08-27 10:24:49 -0500 |
---|---|---|
committer | Lars Bergstrom <lbergstrom@mozilla.com> | 2014-08-27 10:24:49 -0500 |
commit | 370192451f46ab81dd07dae754280c88fc617c97 (patch) | |
tree | 5127807da3564f65bb16858ff1b9726ddceaf91b | |
parent | 1cea7223ec8c661c4737aedfbbe22f9a2bb8c811 (diff) | |
parent | fa6b59901a4281b591d612480b5db22574363139 (diff) | |
download | servo-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.rs | 19 | ||||
-rw-r--r-- | src/components/layout/construct.rs | 38 | ||||
-rw-r--r-- | src/components/layout/fragment.rs | 113 | ||||
-rw-r--r-- | src/components/layout/inline.rs | 325 | ||||
-rw-r--r-- | src/components/layout/text.rs | 2 | ||||
-rw-r--r-- | src/test/ref/basic.list | 2 | ||||
-rw-r--r-- | src/test/ref/inline_background_a.html | 17 | ||||
-rw-r--r-- | src/test/ref/inline_background_ref.html | 14 |
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> |