mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Merge pull request #3134 from glennw/inline-background
Add support for backgrounds on inline elements. Fix fixup() by removing it.
This commit is contained in:
commit
370192451f
8 changed files with 155 additions and 375 deletions
|
@ -1107,8 +1107,7 @@ impl BlockFlow {
|
||||||
let rel_offset =
|
let rel_offset =
|
||||||
self.fragment.relative_position(&self.base
|
self.fragment.relative_position(&self.base
|
||||||
.absolute_position_info
|
.absolute_position_info
|
||||||
.relative_containing_block_size,
|
.relative_containing_block_size);
|
||||||
None);
|
|
||||||
|
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
|
@ -1120,8 +1119,7 @@ impl BlockFlow {
|
||||||
layout_context,
|
layout_context,
|
||||||
self.base.abs_position + (offset + rel_offset).to_physical(
|
self.base.abs_position + (offset + rel_offset).to_physical(
|
||||||
self.base.writing_mode, container_size),
|
self.base.writing_mode, container_size),
|
||||||
background_border_level,
|
background_border_level);
|
||||||
None);
|
|
||||||
|
|
||||||
let mut child_layers = DList::new();
|
let mut child_layers = DList::new();
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
|
@ -1470,7 +1468,7 @@ impl Flow for BlockFlow {
|
||||||
flags.union_floated_descendants_flags(child_base.flags);
|
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,
|
intrinsic_inline_sizes.minimum_inline_size = geometry::max(intrinsic_inline_sizes.minimum_inline_size,
|
||||||
fragment_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,
|
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 =
|
let relative_offset =
|
||||||
self.fragment.relative_position(&self.base
|
self.fragment.relative_position(&self.base
|
||||||
.absolute_position_info
|
.absolute_position_info
|
||||||
.relative_containing_block_size,
|
.relative_containing_block_size);
|
||||||
None);
|
|
||||||
if self.is_positioned() {
|
if self.is_positioned() {
|
||||||
self.base.absolute_position_info.absolute_containing_block_position =
|
self.base.absolute_position_info.absolute_containing_block_position =
|
||||||
self.base.abs_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 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);
|
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();
|
let style = block.fragment.style();
|
||||||
|
|
||||||
|
@ -2257,7 +2254,7 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
|
||||||
-> MaybeAuto {
|
-> MaybeAuto {
|
||||||
let containing_block_inline_size = block.containing_block_size(ctx.shared.screen_size).inline;
|
let containing_block_inline_size = block.containing_block_size(ctx.shared.screen_size).inline;
|
||||||
let fragment = block.fragment();
|
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
|
// For replaced absolute flow, the rest of the constraint solving will
|
||||||
// take inline-size to be specified as the value computed here.
|
// take inline-size to be specified as the value computed here.
|
||||||
Specified(fragment.content_inline_size())
|
Specified(fragment.content_inline_size())
|
||||||
|
@ -2306,7 +2303,7 @@ impl ISizeAndMarginsComputer for BlockReplaced {
|
||||||
_: &LayoutContext)
|
_: &LayoutContext)
|
||||||
-> MaybeAuto {
|
-> MaybeAuto {
|
||||||
let fragment = block.fragment();
|
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
|
// For replaced block flow, the rest of the constraint solving will
|
||||||
// take inline-size to be specified as the value computed here.
|
// take inline-size to be specified as the value computed here.
|
||||||
Specified(fragment.content_inline_size())
|
Specified(fragment.content_inline_size())
|
||||||
|
@ -2362,7 +2359,7 @@ impl ISizeAndMarginsComputer for FloatReplaced {
|
||||||
_: &LayoutContext)
|
_: &LayoutContext)
|
||||||
-> MaybeAuto {
|
-> MaybeAuto {
|
||||||
let fragment = block.fragment();
|
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
|
// For replaced block flow, the rest of the constraint solving will
|
||||||
// take inline-size to be specified as the value computed here.
|
// take inline-size to be specified as the value computed here.
|
||||||
Specified(fragment.content_inline_size())
|
Specified(fragment.content_inline_size())
|
||||||
|
|
|
@ -32,7 +32,7 @@ use fragment::{ImageFragment, ImageFragmentInfo, SpecificFragmentInfo, TableFrag
|
||||||
use fragment::{TableCellFragment, TableColumnFragment, TableColumnFragmentInfo};
|
use fragment::{TableCellFragment, TableColumnFragment, TableColumnFragmentInfo};
|
||||||
use fragment::{TableRowFragment, TableWrapperFragment, UnscannedTextFragment};
|
use fragment::{TableRowFragment, TableWrapperFragment, UnscannedTextFragment};
|
||||||
use fragment::{UnscannedTextFragmentInfo};
|
use fragment::{UnscannedTextFragmentInfo};
|
||||||
use inline::{FragmentIndex, InlineFragments, InlineFlow};
|
use inline::{InlineFragments, InlineFlow};
|
||||||
use parallel;
|
use parallel;
|
||||||
use table_wrapper::TableWrapperFlow;
|
use table_wrapper::TableWrapperFlow;
|
||||||
use table::TableFlow;
|
use table::TableFlow;
|
||||||
|
@ -57,7 +57,6 @@ use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstruc
|
||||||
use script::dom::node::{TextNodeTypeId};
|
use script::dom::node::{TextNodeTypeId};
|
||||||
use script::dom::htmlobjectelement::is_image_data;
|
use script::dom::htmlobjectelement::is_image_data;
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
use servo_util::range::Range;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::atomics::Relaxed;
|
use std::sync::atomics::Relaxed;
|
||||||
use style::ComputedValues;
|
use style::ComputedValues;
|
||||||
|
@ -140,37 +139,40 @@ struct InlineFragmentsAccumulator {
|
||||||
/// The list of fragments.
|
/// The list of fragments.
|
||||||
fragments: InlineFragments,
|
fragments: InlineFragments,
|
||||||
|
|
||||||
/// Whether we've created a range to enclose all the fragments. This will be true if the outer node
|
/// Whether we've created a range to enclose all the fragments. This will be Some() if the outer node
|
||||||
/// is an inline and false otherwise.
|
/// is an inline and None otherwise.
|
||||||
has_enclosing_range: bool,
|
enclosing_style: Option<Arc<ComputedValues>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineFragmentsAccumulator {
|
impl InlineFragmentsAccumulator {
|
||||||
fn new() -> InlineFragmentsAccumulator {
|
fn new() -> InlineFragmentsAccumulator {
|
||||||
InlineFragmentsAccumulator {
|
InlineFragmentsAccumulator {
|
||||||
fragments: InlineFragments::new(),
|
fragments: InlineFragments::new(),
|
||||||
has_enclosing_range: false,
|
enclosing_style: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
|
fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
|
||||||
let mut fragments = InlineFragments::new();
|
let fragments = InlineFragments::new();
|
||||||
fragments.push_range(node.style().clone(), Range::empty());
|
|
||||||
InlineFragmentsAccumulator {
|
InlineFragmentsAccumulator {
|
||||||
fragments: fragments,
|
fragments: fragments,
|
||||||
has_enclosing_range: true,
|
enclosing_style: Some(node.style().clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self) -> InlineFragments {
|
fn finish(self) -> InlineFragments {
|
||||||
let InlineFragmentsAccumulator {
|
let InlineFragmentsAccumulator {
|
||||||
fragments: mut fragments,
|
fragments: mut fragments,
|
||||||
has_enclosing_range
|
enclosing_style
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
if has_enclosing_range {
|
match enclosing_style {
|
||||||
let len = FragmentIndex(fragments.len() as int);
|
Some(enclosing_style) => {
|
||||||
fragments.get_mut_range(FragmentIndex(0)).range.extend_to(len);
|
for frag in fragments.fragments.mut_iter() {
|
||||||
|
frag.add_inline_context_style(enclosing_style.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
fragments
|
fragments
|
||||||
}
|
}
|
||||||
|
@ -374,10 +376,10 @@ impl<'a, 'b> FlowConstructor<'a, 'b> {
|
||||||
// Add whitespace results. They will be stripped out later on when
|
// Add whitespace results. They will be stripped out later on when
|
||||||
// between block elements, and retained when between inline elements.
|
// between block elements, and retained when between inline elements.
|
||||||
let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::from_text(" ".to_string()));
|
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(),
|
whitespace_style.clone(),
|
||||||
fragment_info);
|
fragment_info);
|
||||||
inline_fragment_accumulator.fragments.push(fragment, whitespace_style);
|
inline_fragment_accumulator.fragments.push(&mut fragment, whitespace_style);
|
||||||
}
|
}
|
||||||
ConstructionItemConstructionResult(TableColumnFragmentConstructionItem(_)) => {
|
ConstructionItemConstructionResult(TableColumnFragmentConstructionItem(_)) => {
|
||||||
// TODO: Implement anonymous table objects for missing parents
|
// TODO: Implement anonymous table objects for missing parents
|
||||||
|
@ -525,10 +527,10 @@ impl<'a, 'b> FlowConstructor<'a, 'b> {
|
||||||
=> {
|
=> {
|
||||||
// Instantiate the whitespace fragment.
|
// Instantiate the whitespace fragment.
|
||||||
let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::from_text(" ".to_string()));
|
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(),
|
whitespace_style.clone(),
|
||||||
fragment_info);
|
fragment_info);
|
||||||
fragment_accumulator.fragments.push(fragment, whitespace_style)
|
fragment_accumulator.fragments.push(&mut fragment, whitespace_style)
|
||||||
}
|
}
|
||||||
ConstructionItemConstructionResult(TableColumnFragmentConstructionItem(_)) => {
|
ConstructionItemConstructionResult(TableColumnFragmentConstructionItem(_)) => {
|
||||||
// TODO: Implement anonymous table objects for missing parents
|
// TODO: Implement anonymous table objects for missing parents
|
||||||
|
@ -570,7 +572,7 @@ impl<'a, 'b> FlowConstructor<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut fragments = InlineFragments::new();
|
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 {
|
let construction_item = InlineFragmentsConstructionItem(InlineFragmentsConstructionResult {
|
||||||
splits: Vec::new(),
|
splits: Vec::new(),
|
||||||
|
|
|
@ -99,6 +99,10 @@ pub struct Fragment {
|
||||||
///
|
///
|
||||||
/// FIXME(#2260, pcwalton): This is very inefficient; remove.
|
/// FIXME(#2260, pcwalton): This is very inefficient; remove.
|
||||||
pub new_line_pos: Vec<CharIndex>,
|
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.
|
/// Info specific to the kind of fragment. Keep this enum small.
|
||||||
|
@ -330,6 +334,7 @@ impl Fragment {
|
||||||
margin: LogicalMargin::zero(writing_mode),
|
margin: LogicalMargin::zero(writing_mode),
|
||||||
specific: constructor.build_specific_fragment_info_for_node(node),
|
specific: constructor.build_specific_fragment_info_for_node(node),
|
||||||
new_line_pos: vec!(),
|
new_line_pos: vec!(),
|
||||||
|
inline_context: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,6 +350,7 @@ impl Fragment {
|
||||||
margin: LogicalMargin::zero(writing_mode),
|
margin: LogicalMargin::zero(writing_mode),
|
||||||
specific: specific,
|
specific: specific,
|
||||||
new_line_pos: vec!(),
|
new_line_pos: vec!(),
|
||||||
|
inline_context: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,6 +375,7 @@ impl Fragment {
|
||||||
margin: LogicalMargin::zero(writing_mode),
|
margin: LogicalMargin::zero(writing_mode),
|
||||||
specific: specific,
|
specific: specific,
|
||||||
new_line_pos: vec!(),
|
new_line_pos: vec!(),
|
||||||
|
inline_context: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,6 +393,7 @@ impl Fragment {
|
||||||
margin: LogicalMargin::zero(writing_mode),
|
margin: LogicalMargin::zero(writing_mode),
|
||||||
specific: specific,
|
specific: specific,
|
||||||
new_line_pos: vec!(),
|
new_line_pos: vec!(),
|
||||||
|
inline_context: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,9 +415,19 @@ impl Fragment {
|
||||||
margin: self.margin,
|
margin: self.margin,
|
||||||
specific: specific,
|
specific: specific,
|
||||||
new_line_pos: self.new_line_pos.clone(),
|
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
|
/// Uses the style only to estimate the intrinsic inline-sizes. These may be modified for text or
|
||||||
/// replaced elements.
|
/// replaced elements.
|
||||||
fn style_specified_intrinsic_inline_size(&self) -> IntrinsicISizes {
|
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?
|
// 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 +
|
let surround_inline_size = margin_inline_start + margin_inline_end + padding_inline_start + padding_inline_end +
|
||||||
border.inline_start_end();
|
border.inline_start_end();
|
||||||
|
|
||||||
|
@ -465,13 +483,12 @@ impl Fragment {
|
||||||
/// it should only be called during intrinsic inline-size computation or computation of
|
/// 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.
|
/// `border_padding`. Other consumers of this information should simply consult that field.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn border_width(&self, inline_fragment_context: Option<InlineFragmentContext>)
|
fn border_width(&self) -> LogicalMargin<Au> {
|
||||||
-> LogicalMargin<Au> {
|
match self.inline_context {
|
||||||
match inline_fragment_context {
|
|
||||||
None => self.style().logical_border_width(),
|
None => self.style().logical_border_width(),
|
||||||
Some(inline_fragment_context) => {
|
Some(ref inline_fragment_context) => {
|
||||||
let zero = LogicalMargin::zero(self.style.writing_mode);
|
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`
|
/// style. After this call, the `border_padding` and the vertical direction of the `margin`
|
||||||
/// field will be correct.
|
/// field will be correct.
|
||||||
pub fn compute_border_padding_margins(&mut self,
|
pub fn compute_border_padding_margins(&mut self,
|
||||||
containing_block_inline_size: Au,
|
containing_block_inline_size: Au) {
|
||||||
inline_fragment_context: Option<InlineFragmentContext>) {
|
|
||||||
// Compute vertical margins. Note that this value will be ignored by layout if the style
|
// Compute vertical margins. Note that this value will be ignored by layout if the style
|
||||||
// specifies `auto`.
|
// specifies `auto`.
|
||||||
match self.specific {
|
match self.specific {
|
||||||
|
@ -500,19 +516,19 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute border.
|
// Compute border.
|
||||||
let border = self.border_width(inline_fragment_context);
|
let border = self.border_width();
|
||||||
|
|
||||||
// Compute padding.
|
// Compute padding.
|
||||||
let padding = match self.specific {
|
let padding = match self.specific {
|
||||||
TableColumnFragment(_) | TableRowFragment |
|
TableColumnFragment(_) | TableRowFragment |
|
||||||
TableWrapperFragment => LogicalMargin::zero(self.style.writing_mode),
|
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),
|
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);
|
let zero = LogicalMargin::zero(self.style.writing_mode);
|
||||||
inline_fragment_context.ranges()
|
inline_fragment_context.styles.iter()
|
||||||
.fold(zero, |acc, range| acc + range.padding())
|
.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`.
|
// Return offset from original position because of `position: relative`.
|
||||||
pub fn relative_position(&self,
|
pub fn relative_position(&self,
|
||||||
containing_block_size: &LogicalSize<Au>,
|
containing_block_size: &LogicalSize<Au>)
|
||||||
inline_fragment_context: Option<InlineFragmentContext>)
|
|
||||||
-> LogicalSize<Au> {
|
-> LogicalSize<Au> {
|
||||||
fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>)
|
fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>)
|
||||||
-> LogicalSize<Au> {
|
-> LogicalSize<Au> {
|
||||||
|
@ -544,16 +559,16 @@ impl Fragment {
|
||||||
|
|
||||||
// Go over the ancestor fragments and add all relative offsets (if any).
|
// Go over the ancestor fragments and add all relative offsets (if any).
|
||||||
let mut rel_pos = LogicalSize::zero(self.style.writing_mode);
|
let mut rel_pos = LogicalSize::zero(self.style.writing_mode);
|
||||||
match inline_fragment_context {
|
match self.inline_context {
|
||||||
None => {
|
None => {
|
||||||
if self.style().get_box().position == position::relative {
|
if self.style().get_box().position == position::relative {
|
||||||
rel_pos = rel_pos + from_style(self.style(), containing_block_size);
|
rel_pos = rel_pos + from_style(self.style(), containing_block_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(inline_fragment_context) => {
|
Some(ref inline_fragment_context) => {
|
||||||
for range in inline_fragment_context.ranges() {
|
for style in inline_fragment_context.styles.iter() {
|
||||||
if range.style.get_box().position == position::relative {
|
if style.get_box().position == position::relative {
|
||||||
rel_pos = rel_pos + from_style(&*range.style, containing_block_size);
|
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
|
/// Adds the display items necessary to paint the background of this fragment to the display
|
||||||
/// list if necessary.
|
/// list if necessary.
|
||||||
pub fn build_display_list_for_background_if_applicable(&self,
|
pub fn build_display_list_for_background_if_applicable(&self,
|
||||||
|
style: &ComputedValues,
|
||||||
list: &mut DisplayList,
|
list: &mut DisplayList,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
level: StackingLevel,
|
level: StackingLevel,
|
||||||
|
@ -642,7 +658,6 @@ impl Fragment {
|
||||||
// needed. We could use display list optimization to clean this up, but it still seems
|
// 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
|
// inefficient. What we really want is something like "nearest ancestor element that
|
||||||
// doesn't have a fragment".
|
// doesn't have a fragment".
|
||||||
let style = self.style();
|
|
||||||
let background_color = style.resolve_color(style.get_background().background_color);
|
let background_color = style.resolve_color(style.get_background().background_color);
|
||||||
if !background_color.alpha.approx_eq(&0.0) {
|
if !background_color.alpha.approx_eq(&0.0) {
|
||||||
let display_item = box SolidColorDisplayItem {
|
let display_item = box SolidColorDisplayItem {
|
||||||
|
@ -742,11 +757,9 @@ impl Fragment {
|
||||||
pub fn build_display_list_for_borders_if_applicable(&self,
|
pub fn build_display_list_for_borders_if_applicable(&self,
|
||||||
list: &mut DisplayList,
|
list: &mut DisplayList,
|
||||||
abs_bounds: &Rect<Au>,
|
abs_bounds: &Rect<Au>,
|
||||||
level: StackingLevel,
|
level: StackingLevel) {
|
||||||
inline_fragment_context:
|
|
||||||
Option<InlineFragmentContext>) {
|
|
||||||
// Fast path.
|
// Fast path.
|
||||||
let border = self.border_width(inline_fragment_context);
|
let border = self.border_width();
|
||||||
if border.is_zero() {
|
if border.is_zero() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -844,8 +857,7 @@ impl Fragment {
|
||||||
display_list: &mut DisplayList,
|
display_list: &mut DisplayList,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
flow_origin: Point2D<Au>,
|
flow_origin: Point2D<Au>,
|
||||||
background_and_border_level: BackgroundAndBorderLevel,
|
background_and_border_level: BackgroundAndBorderLevel)
|
||||||
inline_fragment_context: Option<InlineFragmentContext>)
|
|
||||||
-> ChildDisplayListAccumulator {
|
-> ChildDisplayListAccumulator {
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
|
@ -886,18 +898,31 @@ impl Fragment {
|
||||||
display_list.push(PseudoDisplayItemClass(base_display_item));
|
display_list.push(PseudoDisplayItemClass(base_display_item));
|
||||||
|
|
||||||
// Add the background to the list, if applicable.
|
// Add the background to the list, if applicable.
|
||||||
self.build_display_list_for_background_if_applicable(display_list,
|
match self.inline_context {
|
||||||
layout_context,
|
Some(ref inline_context) => {
|
||||||
level,
|
for style in inline_context.styles.iter().rev() {
|
||||||
&absolute_fragment_bounds);
|
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.
|
// Add a border, if applicable.
|
||||||
//
|
//
|
||||||
// TODO: Outlines.
|
// TODO: Outlines.
|
||||||
self.build_display_list_for_borders_if_applicable(display_list,
|
self.build_display_list_for_borders_if_applicable(display_list,
|
||||||
&absolute_fragment_bounds,
|
&absolute_fragment_bounds,
|
||||||
level,
|
level);
|
||||||
inline_fragment_context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a clip, if applicable.
|
// 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.
|
// FIXME(#2263, pcwalton): This is a bit of an abuse of the logging infrastructure.
|
||||||
// We should have a real `SERVO_DEBUG` system.
|
// We should have a real `SERVO_DEBUG` system.
|
||||||
debug!("{:?}", self.build_debug_borders_around_text_fragments(display_list,
|
debug!("{:?}", self.build_debug_borders_around_text_fragments(display_list,
|
||||||
flow_origin,
|
flow_origin,
|
||||||
text_fragment))
|
text_fragment))
|
||||||
},
|
},
|
||||||
GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment | TableRowFragment |
|
GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment | TableRowFragment |
|
||||||
TableWrapperFragment => {
|
TableWrapperFragment => {
|
||||||
|
@ -1017,7 +1042,7 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the intrinsic inline-sizes of this 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 {
|
-> IntrinsicISizes {
|
||||||
let mut result = self.style_specified_intrinsic_inline_size();
|
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.
|
// Take borders and padding for parent inline fragments into account, if necessary.
|
||||||
match inline_fragment_context {
|
match self.inline_context {
|
||||||
None => {}
|
None => {}
|
||||||
Some(context) => {
|
Some(ref context) => {
|
||||||
for range in context.ranges() {
|
for style in context.styles.iter() {
|
||||||
let border_width = range.border().inline_start_end();
|
let border_width = style.logical_border_width().inline_start_end();
|
||||||
let padding_inline_size = range.padding().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.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;
|
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
|
/// Assigns replaced inline-size, padding, and margins for this fragment only if it is replaced
|
||||||
/// content per CSS 2.1 § 10.3.2.
|
/// content per CSS 2.1 § 10.3.2.
|
||||||
pub fn assign_replaced_inline_size_if_necessary(&mut self,
|
pub fn assign_replaced_inline_size_if_necessary(&mut self,
|
||||||
container_inline_size: Au,
|
container_inline_size: Au) {
|
||||||
inline_fragment_context:
|
|
||||||
Option<InlineFragmentContext>) {
|
|
||||||
match self.specific {
|
match self.specific {
|
||||||
GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment |
|
GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment |
|
||||||
TableWrapperFragment => return,
|
TableWrapperFragment => return,
|
||||||
|
@ -1276,7 +1299,7 @@ impl Fragment {
|
||||||
ImageFragment(_) | ScannedTextFragment(_) => {}
|
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_inline_size = self.style().content_inline_size();
|
||||||
let style_block_size = self.style().content_block_size();
|
let style_block_size = self.style().content_block_size();
|
||||||
|
|
|
@ -11,7 +11,6 @@ use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass};
|
||||||
use flow;
|
use flow;
|
||||||
use fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
|
use fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
|
||||||
use model::IntrinsicISizes;
|
use model::IntrinsicISizes;
|
||||||
use model;
|
|
||||||
use text;
|
use text;
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
|
@ -23,14 +22,12 @@ use gfx::font_context::FontContext;
|
||||||
use gfx::text::glyph::CharIndex;
|
use gfx::text::glyph::CharIndex;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::geometry;
|
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;
|
||||||
use servo_util::range::{EachIndex, Range, RangeIndex, IntRangeIndex};
|
use servo_util::range::{EachIndex, Range, RangeIndex, IntRangeIndex};
|
||||||
use std::iter::Enumerate;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::num;
|
use std::num;
|
||||||
use std::slice::{Items, MutItems};
|
|
||||||
use std::u16;
|
use std::u16;
|
||||||
use style::computed_values::{text_align, vertical_align, white_space};
|
use style::computed_values::{text_align, vertical_align, white_space};
|
||||||
use style::ComputedValues;
|
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.fragments = old_fragments;
|
||||||
flow.lines = mem::replace(&mut self.lines, Vec::new());
|
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.
|
/// Represents a list of inline fragments, including element ranges.
|
||||||
pub struct InlineFragments {
|
pub struct InlineFragments {
|
||||||
/// The fragments themselves.
|
/// The fragments themselves.
|
||||||
pub fragments: Vec<Fragment>,
|
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 {
|
impl InlineFragments {
|
||||||
|
@ -671,7 +635,6 @@ impl InlineFragments {
|
||||||
pub fn new() -> InlineFragments {
|
pub fn new() -> InlineFragments {
|
||||||
InlineFragments {
|
InlineFragments {
|
||||||
fragments: vec![],
|
fragments: vec![],
|
||||||
ranges: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,35 +649,14 @@ impl InlineFragments {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes a new inline fragment.
|
/// Pushes a new inline fragment.
|
||||||
pub fn push(&mut self, fragment: Fragment, style: Arc<ComputedValues>) {
|
pub fn push(&mut self, fragment: &mut Fragment, style: Arc<ComputedValues>) {
|
||||||
self.ranges.push(InlineFragmentRange::new(
|
fragment.add_inline_context_style(style);
|
||||||
style, Range::new(FragmentIndex(self.fragments.len() as int), FragmentIndex(1)),
|
self.fragments.push(fragment.clone());
|
||||||
));
|
|
||||||
self.fragments.push(fragment)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merges another set of inline fragments with this one.
|
/// Merges another set of inline fragments with this one.
|
||||||
pub fn push_all(&mut self, InlineFragments { fragments, ranges }: InlineFragments) {
|
pub fn push_all(&mut self, fragments: InlineFragments) {
|
||||||
let adjustment = FragmentIndex(self.fragments.len() as int);
|
self.fragments.push_all_move(fragments.fragments);
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience function to return the fragment at a given index.
|
/// A convenience function to return the fragment at a given index.
|
||||||
|
@ -727,134 +669,6 @@ impl InlineFragments {
|
||||||
self.fragments.get_mut(index)
|
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.
|
/// Strips ignorable whitespace from the start of a list of fragments.
|
||||||
pub fn strip_ignorable_whitespace_from_start(&mut self) {
|
pub fn strip_ignorable_whitespace_from_start(&mut self) {
|
||||||
if self.is_empty() { return }; // Fast path
|
if self.is_empty() { return }; // Fast path
|
||||||
|
@ -874,7 +688,7 @@ impl InlineFragments {
|
||||||
new_fragments.push(fragment);
|
new_fragments.push(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fixup(new_fragments);
|
self.fragments = new_fragments;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Strips ignorable whitespace from the end of a list of fragments.
|
/// Strips ignorable whitespace from the end of a list of fragments.
|
||||||
|
@ -889,7 +703,8 @@ impl InlineFragments {
|
||||||
drop(new_fragments.pop());
|
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.
|
// 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());
|
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
|
let rel_offset = fragment.relative_position(&self.base
|
||||||
.absolute_position_info
|
.absolute_position_info
|
||||||
.relative_containing_block_size,
|
.relative_containing_block_size);
|
||||||
Some(context));
|
|
||||||
drop(fragment.build_display_list(&mut self.base.display_list,
|
drop(fragment.build_display_list(&mut self.base.display_list,
|
||||||
layout_context,
|
layout_context,
|
||||||
self.base.abs_position.add_size(
|
self.base.abs_position.add_size(
|
||||||
&rel_offset.to_physical(self.base.writing_mode)),
|
&rel_offset.to_physical(self.base.writing_mode)),
|
||||||
ContentLevel,
|
ContentLevel));
|
||||||
Some(context)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(#225): Should `inline-block` elements have flows as children of the inline flow or
|
// 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();
|
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);
|
debug!("Flow: measuring {}", *fragment);
|
||||||
|
|
||||||
let fragment_intrinsic_inline_sizes =
|
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 = geometry::max(
|
||||||
intrinsic_inline_sizes.minimum_inline_size,
|
intrinsic_inline_sizes.minimum_inline_size,
|
||||||
fragment_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 inline_size = self.base.position.size.inline;
|
||||||
let this = &mut *self;
|
let this = &mut *self;
|
||||||
for (fragment, context) in this.fragments.mut_iter() {
|
for fragment in this.fragments.fragments.mut_iter() {
|
||||||
fragment.assign_replaced_inline_size_if_necessary(inline_size,
|
fragment.assign_replaced_inline_size_if_necessary(inline_size);
|
||||||
Some(context))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1157,7 +969,7 @@ impl Flow for InlineFlow {
|
||||||
debug!("assign_block_size_inline: floats in: {:?}", self.base.floats);
|
debug!("assign_block_size_inline: floats in: {:?}", self.base.floats);
|
||||||
|
|
||||||
// assign block-size for inline fragments
|
// 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();
|
fragment.assign_replaced_block_size_if_necessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1305,7 +1117,7 @@ impl Flow for InlineFlow {
|
||||||
impl fmt::Show for InlineFlow {
|
impl fmt::Show for InlineFlow {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
try!(write!(f, "InlineFlow"));
|
try!(write!(f, "InlineFlow"));
|
||||||
for (i, (fragment, _)) in self.fragments.iter().enumerate() {
|
for (i, fragment) in self.fragments.fragments.iter().enumerate() {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
try!(write!(f, ": {}", fragment))
|
try!(write!(f, ": {}", fragment))
|
||||||
} else {
|
} 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
|
#[deriving(Clone)]
|
||||||
/// DOM structure from the flat fragment list when it's needed.
|
pub struct InlineFragmentContext {
|
||||||
pub struct InlineFragmentRange {
|
pub styles: Vec<Arc<ComputedValues>>,
|
||||||
/// 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 {
|
impl InlineFragmentContext {
|
||||||
/// Creates a new fragment range from the given values.
|
pub fn new() -> InlineFragmentContext {
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
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> {
|
|
||||||
InlineFragmentContext {
|
InlineFragmentContext {
|
||||||
ranges: ranges,
|
styles: vec!()
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ impl TextRunScanner {
|
||||||
|
|
||||||
debug!("TextRunScanner: swapping out fragments.");
|
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
|
/// A "clump" is a range of inline flow leaves that can be merged together into a single
|
||||||
|
|
|
@ -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.
|
# FIXME: use the real test when pixel-snapping for scrolling is fixed.
|
||||||
#== ../html/acid2.html#top acid2_ref_broken.html
|
#== ../html/acid2.html#top acid2_ref_broken.html
|
||||||
flaky_gpu,flaky_linux == acid2_noscroll.html acid2_ref_broken.html
|
flaky_gpu,flaky_linux == acid2_noscroll.html acid2_ref_broken.html
|
||||||
|
|
||||||
|
!= inline_background_a.html inline_background_ref.html
|
||||||
|
|
17
src/test/ref/inline_background_a.html
Normal file
17
src/test/ref/inline_background_a.html
Normal file
|
@ -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>
|
14
src/test/ref/inline_background_ref.html
Normal file
14
src/test/ref/inline_background_ref.html
Normal file
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue