зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
e3b513b969
Коммит
fe9ce360f4
|
@ -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 {
|
||||
|
|
Загрузка…
Ссылка в новой задаче