servo: Merge #3399 - Handle generated content with `display: block` correctly during flow (from pcwalton:fix-generated-content-iteration)

Source-Repo: https://github.com/servo/servo
Source-Revision: b8f34bbc5170f78e4939b1d647f8d8498e3c2fb6
This commit is contained in:
Patrick Walton 2014-09-19 12:27:32 -07:00
Родитель e3b513b969
Коммит fe9ce360f4
3 изменённых файлов: 55 добавлений и 19 удалений

Просмотреть файл

@ -212,14 +212,24 @@ impl<'a> FlowConstructor<'a> {
Some(url) => {
// FIXME(pcwalton): The fact that image fragments store the cache within them makes
// little sense to me.
ImageFragment(ImageFragmentInfo::new(node, url, self.layout_context.shared.image_cache.clone()))
ImageFragment(ImageFragmentInfo::new(node,
url,
self.layout_context
.shared
.image_cache
.clone()))
}
}
}
/// Builds specific `Fragment` info for the given node.
///
/// This does *not* construct the text for generated content (but, for generated content with
/// `display: block`, it does construct the generic fragment corresponding to the block).
/// Construction of the text fragment is done specially by `build_flow_using_children()` and
/// `build_fragments_for_replaced_inline_content()`.
pub fn build_specific_fragment_info_for_node(&mut self, node: &ThreadSafeLayoutNode)
-> SpecificFragmentInfo {
-> SpecificFragmentInfo {
match node.type_id() {
Some(ElementNodeTypeId(HTMLImageElementTypeId)) => {
self.build_fragment_info_for_image(node, node.image_url())
@ -239,8 +249,11 @@ impl<'a> FlowConstructor<'a> {
Some(ElementNodeTypeId(HTMLTableHeaderCellElementTypeId)) => TableCellFragment,
Some(ElementNodeTypeId(HTMLTableRowElementTypeId)) |
Some(ElementNodeTypeId(HTMLTableSectionElementTypeId)) => TableRowFragment,
None | Some(TextNodeTypeId) => UnscannedTextFragment(UnscannedTextFragmentInfo::new(node)),
_ => GenericFragment,
Some(TextNodeTypeId) => UnscannedTextFragment(UnscannedTextFragmentInfo::new(node)),
_ => {
// This includes pseudo-elements.
GenericFragment
}
}
}
@ -431,6 +444,15 @@ impl<'a> FlowConstructor<'a> {
let mut consecutive_siblings = vec!();
let mut first_fragment = true;
// Special case: If this is generated content, then we need to initialize the accumulator
// with the fragment corresponding to that content.
if node.get_pseudo_element_type() != Normal {
let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::new(node));
let mut fragment = Fragment::new_from_specific_info(node, fragment_info);
inline_fragment_accumulator.fragments.push(&mut fragment, node.style().clone());
first_fragment = false;
}
// List of absolute descendants, in tree order.
let mut abs_descendants = Descendants::new();
for kid in node.children() {
@ -587,8 +609,9 @@ impl<'a> FlowConstructor<'a> {
}
}
/// Creates an `InlineFragmentsConstructionResult` for replaced content. Replaced content doesn't
/// render its children, so this just nukes a child's fragments and creates a `Fragment`.
/// Creates an `InlineFragmentsConstructionResult` for replaced content. Replaced content
/// doesn't render its children, so this just nukes a child's fragments and creates a
/// `Fragment`.
fn build_fragments_for_replaced_inline_content(&mut self, node: &ThreadSafeLayoutNode)
-> ConstructionResult {
for kid in node.children() {
@ -605,8 +628,18 @@ impl<'a> FlowConstructor<'a> {
node.style().clone()))
}
// If this is generated content, then we need to initialize the accumulator with the
// fragment corresponding to that content. Otherwise, just initialize with the ordinary
// fragment that needs to be generated for this inline node.
let mut fragment = if node.get_pseudo_element_type() != Normal {
let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::new(node));
Fragment::new_from_specific_info(node, fragment_info)
} else {
Fragment::new(self, node)
};
let mut fragments = InlineFragments::new();
fragments.push(&mut Fragment::new(self, node), node.style().clone());
fragments.push(&mut fragment, node.style().clone());
let construction_item = InlineFragmentsConstructionItem(InlineFragmentsConstructionResult {
splits: Vec::new(),
@ -853,17 +886,17 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
//
// TODO: This should actually consult the table in that section to get the
// final computed value for 'display'.
//
// `#[inline(always)]` because this is always called from the traversal function and for some
// reason LLVM's inlining heuristics go awry here.
#[inline(always)]
fn process(&mut self, node: &ThreadSafeLayoutNode) -> bool {
// Get the `display` property for this node, and determine whether this node is floated.
let (display, float, positioning) = match node.type_id() {
None => {
// Pseudo-element.
let style = node.style();
(display::inline, style.get_box().float, style.get_box().position)
let display = match node.get_pseudo_element_type() {
Normal | Before | After => display::inline,
BeforeBlock | AfterBlock => display::block,
};
(display, style.get_box().float, style.get_box().position)
}
Some(ElementNodeTypeId(_)) => {
let style = node.style();

Просмотреть файл

@ -351,10 +351,12 @@ impl TableColumnFragmentInfo {
impl Fragment {
/// Constructs a new `Fragment` instance for the given node.
///
/// This does *not* construct the text for generated content. See comments in
/// `FlowConstructor::build_specific_fragment_info_for_node()` for more details.
///
/// Arguments:
///
/// * `constructor`: The flow constructor.
///
/// * `node`: The node to create a fragment for.
pub fn new(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) -> Fragment {
let style = node.style().clone();
@ -373,7 +375,8 @@ impl Fragment {
}
/// Constructs a new `Fragment` instance from a specific info.
pub fn new_from_specific_info(node: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment {
pub fn new_from_specific_info(node: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo)
-> Fragment {
let style = node.style().clone();
let writing_mode = style.writing_mode;
Fragment {

Просмотреть файл

@ -495,7 +495,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> {
/// Returns `None` if this is a pseudo-element.
fn type_id(&self) -> Option<NodeTypeId> {
if self.pseudo == Before || self.pseudo == After {
if self.pseudo != Normal {
return None
}
@ -511,7 +511,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> {
}
fn first_child(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
if self.pseudo == Before || self.pseudo == After {
if self.pseudo != Normal {
return None
}
@ -531,11 +531,11 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> {
}
fn text(&self) -> String {
if self.pseudo == Before || self.pseudo == After {
if self.pseudo != Normal {
let layout_data_ref = self.borrow_layout_data();
let node_layout_data_wrapper = layout_data_ref.get_ref();
if self.pseudo == Before {
if self.pseudo == Before || self.pseudo == BeforeBlock {
let before_style = node_layout_data_wrapper.data.before_style.get_ref();
return get_content(&before_style.get_box().content)
} else {
@ -748,7 +748,7 @@ impl<'a> Iterator<ThreadSafeLayoutNode<'a>> for ThreadSafeLayoutNodeChildrenIter
let pseudo_after_node = if parent_node.is_block(After) && parent_node.pseudo == Normal {
let pseudo_after_node = parent_node.with_pseudo(AfterBlock);
Some(pseudo_after_node)
} else if parent_node.pseudo == Normal || parent_node.pseudo == AfterBlock {
} else if parent_node.pseudo == Normal {
let pseudo_after_node = parent_node.with_pseudo(After);
Some(pseudo_after_node)
} else {