mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Generalize the rest of layout to operate on generic Layout*.
There wasn't a good way to split this up, unfortunately. With this change, the only remaining usage of the Servo-specific structures is in layout_task, where the root node is received from the script task. \o/
This commit is contained in:
parent
77a8091996
commit
cf33f00018
10 changed files with 198 additions and 156 deletions
|
@ -38,6 +38,7 @@ use script::dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId};
|
||||||
use script::dom::htmlobjectelement::is_image_data;
|
use script::dom::htmlobjectelement::is_image_data;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
@ -57,7 +58,7 @@ use traversal::PostorderNodeMutTraversal;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::linked_list;
|
use util::linked_list;
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// The results of flow construction for a DOM node.
|
/// The results of flow construction for a DOM node.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -208,7 +209,8 @@ impl InlineFragmentsAccumulator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_inline_node(node: &ServoThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
|
fn from_inline_node<'ln, N>(node: &N) -> InlineFragmentsAccumulator
|
||||||
|
where N: ThreadSafeLayoutNode<'ln> {
|
||||||
InlineFragmentsAccumulator {
|
InlineFragmentsAccumulator {
|
||||||
fragments: IntermediateInlineFragments::new(),
|
fragments: IntermediateInlineFragments::new(),
|
||||||
enclosing_node: Some(InlineFragmentNodeInfo {
|
enclosing_node: Some(InlineFragmentNodeInfo {
|
||||||
|
@ -265,29 +267,35 @@ impl InlineFragmentsAccumulator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An object that knows how to create flows.
|
/// An object that knows how to create flows.
|
||||||
pub struct FlowConstructor<'a> {
|
pub struct FlowConstructor<'a, 'ln, N: ThreadSafeLayoutNode<'ln>> {
|
||||||
/// The layout context.
|
/// The layout context.
|
||||||
pub layout_context: &'a LayoutContext<'a>,
|
pub layout_context: &'a LayoutContext<'a>,
|
||||||
|
/// Satisfy the compiler about the unused parameters, which we use to improve the ergonomics of
|
||||||
|
/// the ensuing impl {} by removing the need to parameterize all the methods individually.
|
||||||
|
phantom1: PhantomData<&'ln ()>,
|
||||||
|
phantom2: PhantomData<N>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FlowConstructor<'a> {
|
impl<'a, 'ln, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>>
|
||||||
|
FlowConstructor<'a, 'ln, ConcreteThreadSafeLayoutNode> {
|
||||||
/// Creates a new flow constructor.
|
/// Creates a new flow constructor.
|
||||||
pub fn new<'b>(layout_context: &'b LayoutContext<'b>)
|
pub fn new(layout_context: &'a LayoutContext<'a>) -> Self {
|
||||||
-> FlowConstructor<'b> {
|
|
||||||
FlowConstructor {
|
FlowConstructor {
|
||||||
layout_context: layout_context,
|
layout_context: layout_context,
|
||||||
|
phantom1: PhantomData,
|
||||||
|
phantom2: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_flow_construction_result(&self,
|
fn set_flow_construction_result(&self,
|
||||||
node: &ServoThreadSafeLayoutNode,
|
node: &ConcreteThreadSafeLayoutNode,
|
||||||
result: ConstructionResult) {
|
result: ConstructionResult) {
|
||||||
node.set_flow_construction_result(result);
|
node.set_flow_construction_result(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds the fragment for the given block or subclass thereof.
|
/// Builds the fragment for the given block or subclass thereof.
|
||||||
fn build_fragment_for_block(&mut self, node: &ServoThreadSafeLayoutNode) -> Fragment {
|
fn build_fragment_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode) -> Fragment {
|
||||||
let specific_fragment_info = match node.type_id() {
|
let specific_fragment_info = match node.type_id() {
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
HTMLElementTypeId::HTMLIFrameElement))) => {
|
HTMLElementTypeId::HTMLIFrameElement))) => {
|
||||||
|
@ -343,7 +351,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
fn generate_anonymous_table_flows_if_necessary(&mut self,
|
fn generate_anonymous_table_flows_if_necessary(&mut self,
|
||||||
flow: &mut FlowRef,
|
flow: &mut FlowRef,
|
||||||
child: &mut FlowRef,
|
child: &mut FlowRef,
|
||||||
child_node: &ServoThreadSafeLayoutNode) {
|
child_node: &ConcreteThreadSafeLayoutNode) {
|
||||||
if !flow.is_block_flow() {
|
if !flow.is_block_flow() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -401,7 +409,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
flow: &mut FlowRef,
|
flow: &mut FlowRef,
|
||||||
flow_list: &mut Vec<FlowRef>,
|
flow_list: &mut Vec<FlowRef>,
|
||||||
absolute_descendants: &mut AbsoluteDescendants,
|
absolute_descendants: &mut AbsoluteDescendants,
|
||||||
node: &ServoThreadSafeLayoutNode) {
|
node: &ConcreteThreadSafeLayoutNode) {
|
||||||
let mut fragments = fragment_accumulator.to_intermediate_inline_fragments();
|
let mut fragments = fragment_accumulator.to_intermediate_inline_fragments();
|
||||||
if fragments.is_empty() {
|
if fragments.is_empty() {
|
||||||
return
|
return
|
||||||
|
@ -486,8 +494,8 @@ impl<'a> FlowConstructor<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
flow: &mut FlowRef,
|
flow: &mut FlowRef,
|
||||||
consecutive_siblings: &mut Vec<FlowRef>,
|
consecutive_siblings: &mut Vec<FlowRef>,
|
||||||
node: &ServoThreadSafeLayoutNode,
|
node: &ConcreteThreadSafeLayoutNode,
|
||||||
kid: ServoThreadSafeLayoutNode,
|
kid: ConcreteThreadSafeLayoutNode,
|
||||||
inline_fragment_accumulator: &mut InlineFragmentsAccumulator,
|
inline_fragment_accumulator: &mut InlineFragmentsAccumulator,
|
||||||
abs_descendants: &mut AbsoluteDescendants) {
|
abs_descendants: &mut AbsoluteDescendants) {
|
||||||
match kid.swap_out_construction_result() {
|
match kid.swap_out_construction_result() {
|
||||||
|
@ -595,7 +603,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
fn build_flow_for_block_starting_with_fragments(
|
fn build_flow_for_block_starting_with_fragments(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut flow: FlowRef,
|
mut flow: FlowRef,
|
||||||
node: &ServoThreadSafeLayoutNode,
|
node: &ConcreteThreadSafeLayoutNode,
|
||||||
initial_fragments: IntermediateInlineFragments)
|
initial_fragments: IntermediateInlineFragments)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
// Gather up fragments for the inline flows we might need to create.
|
// Gather up fragments for the inline flows we might need to create.
|
||||||
|
@ -662,7 +670,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): It is not clear to me that there isn't a cleaner way to handle
|
/// FIXME(pcwalton): It is not clear to me that there isn't a cleaner way to handle
|
||||||
/// `<textarea>`.
|
/// `<textarea>`.
|
||||||
fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ServoThreadSafeLayoutNode)
|
fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ConcreteThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let mut initial_fragments = IntermediateInlineFragments::new();
|
let mut initial_fragments = IntermediateInlineFragments::new();
|
||||||
let node_is_input_or_text_area =
|
let node_is_input_or_text_area =
|
||||||
|
@ -695,7 +703,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// Pushes fragments appropriate for the content of the given node onto the given list.
|
/// Pushes fragments appropriate for the content of the given node onto the given list.
|
||||||
fn create_fragments_for_node_text_content(&self,
|
fn create_fragments_for_node_text_content(&self,
|
||||||
fragments: &mut IntermediateInlineFragments,
|
fragments: &mut IntermediateInlineFragments,
|
||||||
node: &ServoThreadSafeLayoutNode,
|
node: &ConcreteThreadSafeLayoutNode,
|
||||||
style: &Arc<ComputedValues>) {
|
style: &Arc<ComputedValues>) {
|
||||||
// Fast path: If there is no text content, return immediately.
|
// Fast path: If there is no text content, return immediately.
|
||||||
let text_content = node.text_content();
|
let text_content = node.text_content();
|
||||||
|
@ -744,7 +752,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
|
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
|
||||||
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
|
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
|
||||||
/// to happen.
|
/// to happen.
|
||||||
fn build_flow_for_block(&mut self, node: &ServoThreadSafeLayoutNode, float_kind: Option<FloatKind>)
|
fn build_flow_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode, float_kind: Option<FloatKind>)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let fragment = self.build_fragment_for_block(node);
|
let fragment = self.build_fragment_for_block(node);
|
||||||
let flow: FlowRef = if node.style().is_multicol() {
|
let flow: FlowRef = if node.style().is_multicol() {
|
||||||
|
@ -758,7 +766,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// Bubbles up {ib} splits.
|
/// Bubbles up {ib} splits.
|
||||||
fn accumulate_inline_block_splits(&mut self,
|
fn accumulate_inline_block_splits(&mut self,
|
||||||
splits: LinkedList<InlineBlockSplit>,
|
splits: LinkedList<InlineBlockSplit>,
|
||||||
node: &ServoThreadSafeLayoutNode,
|
node: &ConcreteThreadSafeLayoutNode,
|
||||||
fragment_accumulator: &mut InlineFragmentsAccumulator,
|
fragment_accumulator: &mut InlineFragmentsAccumulator,
|
||||||
opt_inline_block_splits: &mut LinkedList<InlineBlockSplit>) {
|
opt_inline_block_splits: &mut LinkedList<InlineBlockSplit>) {
|
||||||
for split in splits {
|
for split in splits {
|
||||||
|
@ -783,7 +791,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// Returns the `InlineFragmentsConstructionResult`, if any. There will be no
|
/// Returns the `InlineFragmentsConstructionResult`, if any. There will be no
|
||||||
/// `InlineFragmentsConstructionResult` if this node consisted entirely of ignorable
|
/// `InlineFragmentsConstructionResult` if this node consisted entirely of ignorable
|
||||||
/// whitespace.
|
/// whitespace.
|
||||||
fn build_fragments_for_nonreplaced_inline_content(&mut self, node: &ServoThreadSafeLayoutNode)
|
fn build_fragments_for_nonreplaced_inline_content(&mut self, node: &ConcreteThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let mut opt_inline_block_splits: LinkedList<InlineBlockSplit> = LinkedList::new();
|
let mut opt_inline_block_splits: LinkedList<InlineBlockSplit> = LinkedList::new();
|
||||||
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
||||||
|
@ -897,7 +905,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// Creates an `InlineFragmentsConstructionResult` for replaced content. Replaced content
|
/// Creates an `InlineFragmentsConstructionResult` for replaced content. Replaced content
|
||||||
/// doesn't render its children, so this just nukes a child's fragments and creates a
|
/// doesn't render its children, so this just nukes a child's fragments and creates a
|
||||||
/// `Fragment`.
|
/// `Fragment`.
|
||||||
fn build_fragments_for_replaced_inline_content(&mut self, node: &ServoThreadSafeLayoutNode)
|
fn build_fragments_for_replaced_inline_content(&mut self, node: &ConcreteThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
self.set_flow_construction_result(&kid, ConstructionResult::None)
|
self.set_flow_construction_result(&kid, ConstructionResult::None)
|
||||||
|
@ -941,7 +949,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
ConstructionResult::ConstructionItem(construction_item)
|
ConstructionResult::ConstructionItem(construction_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_fragment_for_inline_block(&mut self, node: &ServoThreadSafeLayoutNode)
|
fn build_fragment_for_inline_block(&mut self, node: &ConcreteThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let block_flow_result = self.build_flow_for_block(node, None);
|
let block_flow_result = self.build_flow_for_block(node, None);
|
||||||
let (block_flow, abs_descendants) = match block_flow_result {
|
let (block_flow, abs_descendants) = match block_flow_result {
|
||||||
|
@ -973,7 +981,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// This is an annoying case, because the computed `display` value is `block`, but the
|
/// This is an annoying case, because the computed `display` value is `block`, but the
|
||||||
/// hypothetical box is inline.
|
/// hypothetical box is inline.
|
||||||
fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ServoThreadSafeLayoutNode)
|
fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ConcreteThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let block_flow_result = self.build_flow_for_block(node, None);
|
let block_flow_result = self.build_flow_for_block(node, None);
|
||||||
let (block_flow, abs_descendants) = match block_flow_result {
|
let (block_flow, abs_descendants) = match block_flow_result {
|
||||||
|
@ -1005,7 +1013,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Builds one or more fragments for a node with `display: inline`. This yields an
|
/// Builds one or more fragments for a node with `display: inline`. This yields an
|
||||||
/// `InlineFragmentsConstructionResult`.
|
/// `InlineFragmentsConstructionResult`.
|
||||||
fn build_fragments_for_inline(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult {
|
fn build_fragments_for_inline(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult {
|
||||||
// Is this node replaced content?
|
// Is this node replaced content?
|
||||||
if !node.is_replaced_content() {
|
if !node.is_replaced_content() {
|
||||||
// Go to a path that concatenates our kids' fragments.
|
// Go to a path that concatenates our kids' fragments.
|
||||||
|
@ -1021,7 +1029,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// `caption-side` property is equal to the given `side`.
|
/// `caption-side` property is equal to the given `side`.
|
||||||
fn place_table_caption_under_table_wrapper_on_side(&mut self,
|
fn place_table_caption_under_table_wrapper_on_side(&mut self,
|
||||||
table_wrapper_flow: &mut FlowRef,
|
table_wrapper_flow: &mut FlowRef,
|
||||||
node: &ServoThreadSafeLayoutNode,
|
node: &ConcreteThreadSafeLayoutNode,
|
||||||
side: caption_side::T) {
|
side: caption_side::T) {
|
||||||
// Only flows that are table captions are matched here.
|
// Only flows that are table captions are matched here.
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
|
@ -1046,7 +1054,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
fn generate_anonymous_missing_child(&mut self,
|
fn generate_anonymous_missing_child(&mut self,
|
||||||
child_flows: Vec<FlowRef>,
|
child_flows: Vec<FlowRef>,
|
||||||
flow: &mut FlowRef,
|
flow: &mut FlowRef,
|
||||||
node: &ServoThreadSafeLayoutNode) {
|
node: &ConcreteThreadSafeLayoutNode) {
|
||||||
let mut anonymous_flow = flow.generate_missing_child_flow(node);
|
let mut anonymous_flow = flow.generate_missing_child_flow(node);
|
||||||
let mut consecutive_siblings = vec!();
|
let mut consecutive_siblings = vec!();
|
||||||
for kid_flow in child_flows {
|
for kid_flow in child_flows {
|
||||||
|
@ -1072,7 +1080,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Builds a flow for a node with `display: table`. This yields a `TableWrapperFlow` with
|
/// Builds a flow for a node with `display: table`. This yields a `TableWrapperFlow` with
|
||||||
/// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
|
/// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
|
||||||
fn build_flow_for_table_wrapper(&mut self, node: &ServoThreadSafeLayoutNode, float_value: float::T)
|
fn build_flow_for_table_wrapper(&mut self, node: &ConcreteThreadSafeLayoutNode, float_value: float::T)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper);
|
let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper);
|
||||||
let mut wrapper_flow: FlowRef = Arc::new(
|
let mut wrapper_flow: FlowRef = Arc::new(
|
||||||
|
@ -1134,7 +1142,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Builds a flow for a node with `display: table-caption`. This yields a `TableCaptionFlow`
|
/// Builds a flow for a node with `display: table-caption`. This yields a `TableCaptionFlow`
|
||||||
/// with possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
/// with possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
||||||
fn build_flow_for_table_caption(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult {
|
fn build_flow_for_table_caption(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult {
|
||||||
let fragment = self.build_fragment_for_block(node);
|
let fragment = self.build_fragment_for_block(node);
|
||||||
let flow = Arc::new(TableCaptionFlow::from_fragment(fragment));
|
let flow = Arc::new(TableCaptionFlow::from_fragment(fragment));
|
||||||
self.build_flow_for_block_like(flow, node)
|
self.build_flow_for_block_like(flow, node)
|
||||||
|
@ -1142,7 +1150,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Builds a flow for a node with `display: table-row-group`. This yields a `TableRowGroupFlow`
|
/// Builds a flow for a node with `display: table-row-group`. This yields a `TableRowGroupFlow`
|
||||||
/// with possibly other `TableRowFlow`s underneath it.
|
/// with possibly other `TableRowFlow`s underneath it.
|
||||||
fn build_flow_for_table_rowgroup(&mut self, node: &ServoThreadSafeLayoutNode)
|
fn build_flow_for_table_rowgroup(&mut self, node: &ConcreteThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
|
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
|
||||||
let flow = Arc::new(TableRowGroupFlow::from_fragment(fragment));
|
let flow = Arc::new(TableRowGroupFlow::from_fragment(fragment));
|
||||||
|
@ -1151,7 +1159,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with
|
/// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with
|
||||||
/// possibly other `TableCellFlow`s underneath it.
|
/// possibly other `TableCellFlow`s underneath it.
|
||||||
fn build_flow_for_table_row(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult {
|
fn build_flow_for_table_row(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult {
|
||||||
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
|
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
|
||||||
let flow = Arc::new(TableRowFlow::from_fragment(fragment));
|
let flow = Arc::new(TableRowFlow::from_fragment(fragment));
|
||||||
self.build_flow_for_block_like(flow, node)
|
self.build_flow_for_block_like(flow, node)
|
||||||
|
@ -1159,7 +1167,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with
|
/// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with
|
||||||
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
||||||
fn build_flow_for_table_cell(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult {
|
fn build_flow_for_table_cell(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult {
|
||||||
let fragment = Fragment::new(node, SpecificFragmentInfo::TableCell);
|
let fragment = Fragment::new(node, SpecificFragmentInfo::TableCell);
|
||||||
|
|
||||||
// Determine if the table cell should be hidden. Per CSS 2.1 § 17.6.1.1, this will be true
|
// Determine if the table cell should be hidden. Per CSS 2.1 § 17.6.1.1, this will be true
|
||||||
|
@ -1180,7 +1188,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Builds a flow for a node with `display: list-item`. This yields a `ListItemFlow` with
|
/// Builds a flow for a node with `display: list-item`. This yields a `ListItemFlow` with
|
||||||
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
||||||
fn build_flow_for_list_item(&mut self, node: &ServoThreadSafeLayoutNode, flotation: float::T)
|
fn build_flow_for_list_item(&mut self, node: &ConcreteThreadSafeLayoutNode, flotation: float::T)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let flotation = FloatKind::from_property(flotation);
|
let flotation = FloatKind::from_property(flotation);
|
||||||
let marker_fragments = match node.style().get_list().list_style_image.0 {
|
let marker_fragments = match node.style().get_list().list_style_image.0 {
|
||||||
|
@ -1239,7 +1247,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a fragment for a node with `display: table-column`.
|
/// Creates a fragment for a node with `display: table-column`.
|
||||||
fn build_fragments_for_table_column(&mut self, node: &ServoThreadSafeLayoutNode)
|
fn build_fragments_for_table_column(&mut self, node: &ConcreteThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
// CSS 2.1 § 17.2.1. Treat all child fragments of a `table-column` as `display: none`.
|
// CSS 2.1 § 17.2.1. Treat all child fragments of a `table-column` as `display: none`.
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
|
@ -1254,7 +1262,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Builds a flow for a node with `display: table-column-group`.
|
/// Builds a flow for a node with `display: table-column-group`.
|
||||||
/// This yields a `TableColGroupFlow`.
|
/// This yields a `TableColGroupFlow`.
|
||||||
fn build_flow_for_table_colgroup(&mut self, node: &ServoThreadSafeLayoutNode)
|
fn build_flow_for_table_colgroup(&mut self, node: &ConcreteThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let fragment =
|
let fragment =
|
||||||
Fragment::new(node,
|
Fragment::new(node,
|
||||||
|
@ -1283,7 +1291,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a flow for a node with 'display: flex'.
|
/// Builds a flow for a node with 'display: flex'.
|
||||||
fn build_flow_for_flex(&mut self, node: &ServoThreadSafeLayoutNode, float_kind: Option<FloatKind>)
|
fn build_flow_for_flex(&mut self, node: &ConcreteThreadSafeLayoutNode, float_kind: Option<FloatKind>)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let fragment = self.build_fragment_for_block(node);
|
let fragment = self.build_fragment_for_block(node);
|
||||||
let flow = Arc::new(FlexFlow::from_fragment(fragment, float_kind));
|
let flow = Arc::new(FlexFlow::from_fragment(fragment, float_kind));
|
||||||
|
@ -1295,7 +1303,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
///
|
///
|
||||||
/// TODO(pcwalton): Add some more fast paths, like toggling `display: none`, adding block kids
|
/// TODO(pcwalton): Add some more fast paths, like toggling `display: none`, adding block kids
|
||||||
/// to block parents with no {ib} splits, adding out-of-flow kids, etc.
|
/// to block parents with no {ib} splits, adding out-of-flow kids, etc.
|
||||||
pub fn repair_if_possible(&mut self, node: &ServoThreadSafeLayoutNode) -> bool {
|
pub fn repair_if_possible(&mut self, node: &ConcreteThreadSafeLayoutNode) -> bool {
|
||||||
// We can skip reconstructing the flow if we don't have to reconstruct and none of our kids
|
// We can skip reconstructing the flow if we don't have to reconstruct and none of our kids
|
||||||
// did either.
|
// did either.
|
||||||
//
|
//
|
||||||
|
@ -1403,14 +1411,16 @@ impl<'a> FlowConstructor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
impl<'a, 'ln, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<'ln, ConcreteThreadSafeLayoutNode>
|
||||||
|
for FlowConstructor<'a, 'ln, ConcreteThreadSafeLayoutNode>
|
||||||
|
where ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln> {
|
||||||
// Construct Flow based on 'display', 'position', and 'float' values.
|
// Construct Flow based on 'display', 'position', and 'float' values.
|
||||||
//
|
//
|
||||||
// CSS 2.1 Section 9.7
|
// CSS 2.1 Section 9.7
|
||||||
//
|
//
|
||||||
// TODO: This should actually consult the table in that section to get the
|
// TODO: This should actually consult the table in that section to get the
|
||||||
// final computed value for 'display'.
|
// final computed value for 'display'.
|
||||||
fn process(&mut self, node: &ServoThreadSafeLayoutNode) -> bool {
|
fn process(&mut self, node: &ConcreteThreadSafeLayoutNode) -> bool {
|
||||||
// Get the `display` property for this node, and determine whether this node is floated.
|
// Get the `display` property for this node, and determine whether this node is floated.
|
||||||
let (display, float, positioning) = match node.type_id() {
|
let (display, float, positioning) = match node.type_id() {
|
||||||
None => {
|
None => {
|
||||||
|
@ -1580,7 +1590,8 @@ trait NodeUtils {
|
||||||
fn swap_out_construction_result(self) -> ConstructionResult;
|
fn swap_out_construction_result(self) -> ConstructionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> NodeUtils for ServoThreadSafeLayoutNode<'ln> {
|
impl<'ln, ConcreteThreadSafeLayoutNode> NodeUtils for ConcreteThreadSafeLayoutNode
|
||||||
|
where ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln> {
|
||||||
fn is_replaced_content(&self) -> bool {
|
fn is_replaced_content(&self) -> bool {
|
||||||
match self.type_id() {
|
match self.type_id() {
|
||||||
None |
|
None |
|
||||||
|
@ -1639,7 +1650,7 @@ trait ObjectElement<'a> {
|
||||||
fn object_data(&self) -> Option<Url>;
|
fn object_data(&self) -> Option<Url>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> ObjectElement<'ln> for ServoThreadSafeLayoutNode<'ln> {
|
impl<'ln, N> ObjectElement<'ln> for N where N: ThreadSafeLayoutNode<'ln> {
|
||||||
fn get_type_and_data(&self) -> (Option<&'ln str>, Option<&'ln str>) {
|
fn get_type_and_data(&self) -> (Option<&'ln str>, Option<&'ln str>) {
|
||||||
let elem = self.as_element();
|
let elem = self.as_element();
|
||||||
(elem.get_attr(&ns!(), &atom!("type")), elem.get_attr(&ns!(), &atom!("data")))
|
(elem.get_attr(&ns!(), &atom!("type")), elem.get_attr(&ns!(), &atom!("data")))
|
||||||
|
|
|
@ -59,7 +59,7 @@ use table_wrapper::TableWrapperFlow;
|
||||||
use util::geometry::ZERO_RECT;
|
use util::geometry::ZERO_RECT;
|
||||||
use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
|
||||||
use util::print_tree::PrintTree;
|
use util::print_tree::PrintTree;
|
||||||
use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, ThreadSafeLayoutNode};
|
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// Virtual methods that make up a float context.
|
/// Virtual methods that make up a float context.
|
||||||
///
|
///
|
||||||
|
@ -435,7 +435,7 @@ pub trait ImmutableFlowUtils {
|
||||||
fn need_anonymous_flow(self, child: &Flow) -> bool;
|
fn need_anonymous_flow(self, child: &Flow) -> bool;
|
||||||
|
|
||||||
/// Generates missing child flow of this flow.
|
/// Generates missing child flow of this flow.
|
||||||
fn generate_missing_child_flow(self, node: &ServoThreadSafeLayoutNode) -> FlowRef;
|
fn generate_missing_child_flow<'ln, N: ThreadSafeLayoutNode<'ln>>(self, node: &N) -> FlowRef;
|
||||||
|
|
||||||
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
|
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
|
||||||
fn contains_roots_of_absolute_flow_tree(&self) -> bool;
|
fn contains_roots_of_absolute_flow_tree(&self) -> bool;
|
||||||
|
@ -1212,7 +1212,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
|
||||||
/// FIXME(pcwalton): This duplicates some logic in
|
/// FIXME(pcwalton): This duplicates some logic in
|
||||||
/// `generate_anonymous_table_flows_if_necessary()`. We should remove this function eventually,
|
/// `generate_anonymous_table_flows_if_necessary()`. We should remove this function eventually,
|
||||||
/// as it's harder to understand.
|
/// as it's harder to understand.
|
||||||
fn generate_missing_child_flow(self, node: &ServoThreadSafeLayoutNode) -> FlowRef {
|
fn generate_missing_child_flow<'ln, N: ThreadSafeLayoutNode<'ln>>(self, node: &N) -> FlowRef {
|
||||||
let mut style = node.style().clone();
|
let mut style = node.style().clone();
|
||||||
match self.class() {
|
match self.class() {
|
||||||
FlowClass::Table | FlowClass::TableRowGroup => {
|
FlowClass::Table | FlowClass::TableRowGroup => {
|
||||||
|
|
|
@ -50,7 +50,7 @@ use util::geometry::ZERO_POINT;
|
||||||
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
||||||
use util::range::*;
|
use util::range::*;
|
||||||
use util::str::slice_chars;
|
use util::str::slice_chars;
|
||||||
use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
use wrapper::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
|
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
|
||||||
/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
|
/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
|
||||||
|
@ -309,7 +309,7 @@ pub struct CanvasFragmentInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanvasFragmentInfo {
|
impl CanvasFragmentInfo {
|
||||||
pub fn new(node: &ServoThreadSafeLayoutNode, data: HTMLCanvasData) -> CanvasFragmentInfo {
|
pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N, data: HTMLCanvasData) -> CanvasFragmentInfo {
|
||||||
CanvasFragmentInfo {
|
CanvasFragmentInfo {
|
||||||
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node,
|
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node,
|
||||||
Some(Au::from_px(data.width as i32)),
|
Some(Au::from_px(data.width as i32)),
|
||||||
|
@ -345,11 +345,10 @@ impl ImageFragmentInfo {
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little
|
/// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little
|
||||||
/// sense to me.
|
/// sense to me.
|
||||||
pub fn new(node: &ServoThreadSafeLayoutNode,
|
pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N, url: Option<Url>,
|
||||||
url: Option<Url>,
|
layout_context: &LayoutContext) -> ImageFragmentInfo {
|
||||||
layout_context: &LayoutContext)
|
fn convert_length<'ln, N>(node: &N, name: &Atom) -> Option<Au>
|
||||||
-> ImageFragmentInfo {
|
where N: ThreadSafeLayoutNode<'ln> {
|
||||||
fn convert_length(node: &ServoThreadSafeLayoutNode, name: &Atom) -> Option<Au> {
|
|
||||||
let element = node.as_element();
|
let element = node.as_element();
|
||||||
element.get_attr(&ns!(), name)
|
element.get_attr(&ns!(), name)
|
||||||
.and_then(|string| string.parse().ok())
|
.and_then(|string| string.parse().ok())
|
||||||
|
@ -423,9 +422,10 @@ pub struct ReplacedImageFragmentInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReplacedImageFragmentInfo {
|
impl ReplacedImageFragmentInfo {
|
||||||
pub fn new(node: &ServoThreadSafeLayoutNode,
|
pub fn new<'ln, N>(node: &N,
|
||||||
dom_width: Option<Au>,
|
dom_width: Option<Au>,
|
||||||
dom_height: Option<Au>) -> ReplacedImageFragmentInfo {
|
dom_height: Option<Au>) -> ReplacedImageFragmentInfo
|
||||||
|
where N: ThreadSafeLayoutNode<'ln> {
|
||||||
let is_vertical = node.style().writing_mode.is_vertical();
|
let is_vertical = node.style().writing_mode.is_vertical();
|
||||||
ReplacedImageFragmentInfo {
|
ReplacedImageFragmentInfo {
|
||||||
computed_inline_size: None,
|
computed_inline_size: None,
|
||||||
|
@ -583,7 +583,7 @@ pub struct IframeFragmentInfo {
|
||||||
|
|
||||||
impl IframeFragmentInfo {
|
impl IframeFragmentInfo {
|
||||||
/// Creates the information specific to an iframe fragment.
|
/// Creates the information specific to an iframe fragment.
|
||||||
pub fn new(node: &ServoThreadSafeLayoutNode) -> IframeFragmentInfo {
|
pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N) -> IframeFragmentInfo {
|
||||||
let pipeline_id = node.iframe_pipeline_id();
|
let pipeline_id = node.iframe_pipeline_id();
|
||||||
IframeFragmentInfo {
|
IframeFragmentInfo {
|
||||||
pipeline_id: pipeline_id,
|
pipeline_id: pipeline_id,
|
||||||
|
@ -758,7 +758,7 @@ pub struct TableColumnFragmentInfo {
|
||||||
|
|
||||||
impl TableColumnFragmentInfo {
|
impl TableColumnFragmentInfo {
|
||||||
/// Create the information specific to an table column fragment.
|
/// Create the information specific to an table column fragment.
|
||||||
pub fn new(node: &ServoThreadSafeLayoutNode) -> TableColumnFragmentInfo {
|
pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N) -> TableColumnFragmentInfo {
|
||||||
let element = node.as_element();
|
let element = node.as_element();
|
||||||
let span = element.get_attr(&ns!(), &atom!("span"))
|
let span = element.get_attr(&ns!(), &atom!("span"))
|
||||||
.and_then(|string| string.parse().ok())
|
.and_then(|string| string.parse().ok())
|
||||||
|
@ -771,7 +771,7 @@ impl TableColumnFragmentInfo {
|
||||||
|
|
||||||
impl Fragment {
|
impl Fragment {
|
||||||
/// Constructs a new `Fragment` instance.
|
/// Constructs a new `Fragment` instance.
|
||||||
pub fn new(node: &ServoThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment {
|
pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N, specific: SpecificFragmentInfo) -> Fragment {
|
||||||
let style = node.style().clone();
|
let style = node.style().clone();
|
||||||
let writing_mode = style.writing_mode;
|
let writing_mode = style.writing_mode;
|
||||||
|
|
||||||
|
|
|
@ -758,7 +758,7 @@ impl LayoutTask {
|
||||||
possibly_locked_rw_data.block(rw_data);
|
possibly_locked_rw_data.block(rw_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_layout_root(&self, node: ServoLayoutNode) -> Option<FlowRef> {
|
fn try_get_layout_root<'ln, N: LayoutNode<'ln>>(&self, node: N) -> Option<FlowRef> {
|
||||||
let mut layout_data_ref = node.mutate_layout_data();
|
let mut layout_data_ref = node.mutate_layout_data();
|
||||||
let layout_data =
|
let layout_data =
|
||||||
match layout_data_ref.as_mut() {
|
match layout_data_ref.as_mut() {
|
||||||
|
@ -1271,7 +1271,7 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dirty_all_nodes(node: ServoLayoutNode) {
|
unsafe fn dirty_all_nodes<'ln, N: LayoutNode<'ln>>(node: N) {
|
||||||
for node in node.traverse_preorder() {
|
for node in node.traverse_preorder() {
|
||||||
// TODO(cgaebel): mark nodes which are sensitive to media queries as
|
// TODO(cgaebel): mark nodes which are sensitive to media queries as
|
||||||
// "changed":
|
// "changed":
|
||||||
|
|
|
@ -22,8 +22,7 @@ use traversal::{ConstructFlows, RecalcStyleForNode};
|
||||||
use traversal::{PostorderDomTraversal, PreorderDomTraversal};
|
use traversal::{PostorderDomTraversal, PreorderDomTraversal};
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
|
use util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
|
||||||
use wrapper::UnsafeLayoutNode;
|
use wrapper::{LayoutNode, UnsafeLayoutNode};
|
||||||
use wrapper::{LayoutNode, ServoLayoutNode, layout_node_from_unsafe_layout_node, layout_node_to_unsafe_layout_node};
|
|
||||||
|
|
||||||
const CHUNK_SIZE: usize = 64;
|
const CHUNK_SIZE: usize = 64;
|
||||||
|
|
||||||
|
@ -88,7 +87,9 @@ pub type ChunkedFlowTraversalFunction =
|
||||||
pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &SharedLayoutContext);
|
pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &SharedLayoutContext);
|
||||||
|
|
||||||
/// A parallel top-down DOM traversal.
|
/// A parallel top-down DOM traversal.
|
||||||
pub trait ParallelPreorderDomTraversal : PreorderDomTraversal {
|
pub trait ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||||
|
: PreorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||||
|
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||||
fn run_parallel(&self,
|
fn run_parallel(&self,
|
||||||
nodes: UnsafeLayoutNodeList,
|
nodes: UnsafeLayoutNodeList,
|
||||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>);
|
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>);
|
||||||
|
@ -103,9 +104,7 @@ pub trait ParallelPreorderDomTraversal : PreorderDomTraversal {
|
||||||
let mut discovered_child_nodes = Vec::new();
|
let mut discovered_child_nodes = Vec::new();
|
||||||
for unsafe_node in *unsafe_nodes.0 {
|
for unsafe_node in *unsafe_nodes.0 {
|
||||||
// Get a real layout node.
|
// Get a real layout node.
|
||||||
let node: ServoLayoutNode = unsafe {
|
let node = unsafe { ConcreteLayoutNode::from_unsafe(&unsafe_node) };
|
||||||
layout_node_from_unsafe_layout_node(&unsafe_node)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Perform the appropriate traversal.
|
// Perform the appropriate traversal.
|
||||||
self.process(node);
|
self.process(node);
|
||||||
|
@ -123,7 +122,7 @@ pub trait ParallelPreorderDomTraversal : PreorderDomTraversal {
|
||||||
// Possibly enqueue the children.
|
// Possibly enqueue the children.
|
||||||
if child_count != 0 {
|
if child_count != 0 {
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
discovered_child_nodes.push(layout_node_to_unsafe_layout_node(&kid))
|
discovered_child_nodes.push(kid.to_unsafe())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If there were no more children, start walking back up.
|
// If there were no more children, start walking back up.
|
||||||
|
@ -141,7 +140,9 @@ pub trait ParallelPreorderDomTraversal : PreorderDomTraversal {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A parallel bottom-up DOM traversal.
|
/// A parallel bottom-up DOM traversal.
|
||||||
trait ParallelPostorderDomTraversal : PostorderDomTraversal {
|
trait ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||||
|
: PostorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||||
|
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||||
fn root(&self) -> OpaqueNode;
|
fn root(&self) -> OpaqueNode;
|
||||||
|
|
||||||
/// Process current node and potentially traverse its ancestors.
|
/// Process current node and potentially traverse its ancestors.
|
||||||
|
@ -157,9 +158,7 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal {
|
||||||
/// fetch-and-subtract the parent's children count.
|
/// fetch-and-subtract the parent's children count.
|
||||||
fn run_parallel(&self, unsafe_node: UnsafeLayoutNode) {
|
fn run_parallel(&self, unsafe_node: UnsafeLayoutNode) {
|
||||||
// Get a real layout node.
|
// Get a real layout node.
|
||||||
let mut node: ServoLayoutNode = unsafe {
|
let mut node = unsafe { ConcreteLayoutNode::from_unsafe(&unsafe_node) };
|
||||||
layout_node_from_unsafe_layout_node(&unsafe_node)
|
|
||||||
};
|
|
||||||
loop {
|
loop {
|
||||||
// Perform the appropriate operation.
|
// Perform the appropriate operation.
|
||||||
self.process(node);
|
self.process(node);
|
||||||
|
@ -349,41 +348,59 @@ impl<'a> ParallelPreorderFlowTraversal for ComputeAbsolutePositions<'a> {
|
||||||
|
|
||||||
impl<'a> ParallelPostorderFlowTraversal for BuildDisplayList<'a> {}
|
impl<'a> ParallelPostorderFlowTraversal for BuildDisplayList<'a> {}
|
||||||
|
|
||||||
impl<'a> ParallelPostorderDomTraversal for ConstructFlows<'a> {
|
impl<'a, 'ln, ConcreteLayoutNode> ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||||
|
for ConstructFlows<'a>
|
||||||
|
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||||
fn root(&self) -> OpaqueNode {
|
fn root(&self) -> OpaqueNode {
|
||||||
self.root
|
self.root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> ParallelPreorderDomTraversal for RecalcStyleForNode<'a> {
|
impl<'a, 'ln, ConcreteLayoutNode> ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||||
|
for RecalcStyleForNode<'a>
|
||||||
|
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||||
fn run_parallel(&self,
|
fn run_parallel(&self,
|
||||||
unsafe_nodes: UnsafeLayoutNodeList,
|
unsafe_nodes: UnsafeLayoutNodeList,
|
||||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
|
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
|
||||||
self.run_parallel_helper(unsafe_nodes, proxy, recalc_style, construct_flows)
|
// Not exactly sure why we need UFCS here, but we seem to.
|
||||||
|
<RecalcStyleForNode<'a> as ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>>
|
||||||
|
::run_parallel_helper(self, unsafe_nodes, proxy,
|
||||||
|
recalc_style::<'ln, ConcreteLayoutNode>,
|
||||||
|
construct_flows::<'ln, ConcreteLayoutNode>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recalc_style(unsafe_nodes: UnsafeLayoutNodeList,
|
fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeLayoutNodeList,
|
||||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
|
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>)
|
||||||
|
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||||
let shared_layout_context = proxy.user_data();
|
let shared_layout_context = proxy.user_data();
|
||||||
let layout_context = LayoutContext::new(shared_layout_context);
|
let layout_context = LayoutContext::new(shared_layout_context);
|
||||||
let recalc_style_for_node_traversal = RecalcStyleForNode {
|
let recalc_style_for_node_traversal = RecalcStyleForNode {
|
||||||
layout_context: &layout_context,
|
layout_context: &layout_context,
|
||||||
root: unsafe_nodes.1,
|
root: unsafe_nodes.1,
|
||||||
};
|
};
|
||||||
recalc_style_for_node_traversal.run_parallel(unsafe_nodes, proxy)
|
|
||||||
|
// The UFCS is necessary here to select the proper set of generic routines which
|
||||||
|
// will eventually cast the UnsafeNode to a concrete LayoutNode implementation.
|
||||||
|
<RecalcStyleForNode as ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>>
|
||||||
|
::run_parallel(&recalc_style_for_node_traversal, unsafe_nodes, proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_flows(root: OpaqueNode,
|
fn construct_flows<'ln, ConcreteLayoutNode: LayoutNode<'ln>>(
|
||||||
unsafe_node: UnsafeLayoutNode,
|
root: OpaqueNode,
|
||||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
|
unsafe_node: UnsafeLayoutNode,
|
||||||
|
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
|
||||||
let shared_layout_context = proxy.user_data();
|
let shared_layout_context = proxy.user_data();
|
||||||
let layout_context = LayoutContext::new(shared_layout_context);
|
let layout_context = LayoutContext::new(shared_layout_context);
|
||||||
let construct_flows_traversal = ConstructFlows {
|
let construct_flows_traversal = ConstructFlows {
|
||||||
layout_context: &layout_context,
|
layout_context: &layout_context,
|
||||||
root: root,
|
root: root,
|
||||||
};
|
};
|
||||||
construct_flows_traversal.run_parallel(unsafe_node)
|
|
||||||
|
// The UFCS is necessary here to select the proper set of generic routines which
|
||||||
|
// will eventually cast the UnsafeNode to a concrete LayoutNode implementation.
|
||||||
|
<ConstructFlows as ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>>
|
||||||
|
::run_parallel(&construct_flows_traversal, unsafe_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_inline_sizes(unsafe_flows: UnsafeFlowList,
|
fn assign_inline_sizes(unsafe_flows: UnsafeFlowList,
|
||||||
|
@ -440,13 +457,13 @@ fn run_queue_with_custom_work_data_type<To, F>(
|
||||||
queue.run(shared_layout_context);
|
queue.run(shared_layout_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn traverse_dom_preorder(root: ServoLayoutNode,
|
pub fn traverse_dom_preorder<'ln, ConcreteLayoutNode: LayoutNode<'ln>>(root: ConcreteLayoutNode,
|
||||||
shared_layout_context: &SharedLayoutContext,
|
shared_layout_context: &SharedLayoutContext,
|
||||||
queue: &mut WorkQueue<SharedLayoutContext, WorkQueueData>) {
|
queue: &mut WorkQueue<SharedLayoutContext, WorkQueueData>) {
|
||||||
run_queue_with_custom_work_data_type(queue, |queue| {
|
run_queue_with_custom_work_data_type(queue, |queue| {
|
||||||
queue.push(WorkUnit {
|
queue.push(WorkUnit {
|
||||||
fun: recalc_style,
|
fun: recalc_style::<'ln, ConcreteLayoutNode>,
|
||||||
data: (box vec![layout_node_to_unsafe_layout_node(&root)], root.opaque()),
|
data: (box vec![root.to_unsafe()], root.opaque()),
|
||||||
});
|
});
|
||||||
}, shared_layout_context);
|
}, shared_layout_context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ use style::values::AuExtensionMethods;
|
||||||
use util::cursor::Cursor;
|
use util::cursor::Cursor;
|
||||||
use util::geometry::ZERO_POINT;
|
use util::geometry::ZERO_POINT;
|
||||||
use util::logical_geometry::WritingMode;
|
use util::logical_geometry::WritingMode;
|
||||||
use wrapper::{LayoutNode, ServoLayoutNode, ServoThreadSafeLayoutNode, ThreadSafeLayoutNode};
|
use wrapper::{LayoutNode, ThreadSafeLayoutNode};
|
||||||
|
|
||||||
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutTaskData>>);
|
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutTaskData>>);
|
||||||
|
|
||||||
|
@ -292,9 +292,8 @@ impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_content_box_request(requested_node: ServoLayoutNode,
|
pub fn process_content_box_request<'ln, N: LayoutNode<'ln>>(
|
||||||
layout_root: &mut FlowRef)
|
requested_node: N, layout_root: &mut FlowRef) -> Rect<Au> {
|
||||||
-> Rect<Au> {
|
|
||||||
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
||||||
// stuff. So the position is wrong in most cases.
|
// stuff. So the position is wrong in most cases.
|
||||||
let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node.opaque());
|
let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node.opaque());
|
||||||
|
@ -305,9 +304,8 @@ pub fn process_content_box_request(requested_node: ServoLayoutNode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_content_boxes_request(requested_node: ServoLayoutNode,
|
pub fn process_content_boxes_request<'ln, N: LayoutNode<'ln>>(requested_node: N, layout_root: &mut FlowRef)
|
||||||
layout_root: &mut FlowRef)
|
-> Vec<Rect<Au>> {
|
||||||
-> Vec<Rect<Au>> {
|
|
||||||
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
||||||
// stuff. So the position is wrong in most cases.
|
// stuff. So the position is wrong in most cases.
|
||||||
let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node.opaque());
|
let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node.opaque());
|
||||||
|
@ -431,9 +429,8 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_node_geometry_request(requested_node: ServoLayoutNode,
|
pub fn process_node_geometry_request<'ln, N: LayoutNode<'ln>>(requested_node: N, layout_root: &mut FlowRef)
|
||||||
layout_root: &mut FlowRef)
|
-> Rect<i32> {
|
||||||
-> Rect<i32> {
|
|
||||||
let mut iterator = FragmentLocatingFragmentIterator::new(requested_node.opaque());
|
let mut iterator = FragmentLocatingFragmentIterator::new(requested_node.opaque());
|
||||||
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
||||||
iterator.client_rect
|
iterator.client_rect
|
||||||
|
@ -441,12 +438,10 @@ pub fn process_node_geometry_request(requested_node: ServoLayoutNode,
|
||||||
|
|
||||||
/// Return the resolved value of property for a given (pseudo)element.
|
/// Return the resolved value of property for a given (pseudo)element.
|
||||||
/// https://drafts.csswg.org/cssom/#resolved-value
|
/// https://drafts.csswg.org/cssom/#resolved-value
|
||||||
pub fn process_resolved_style_request(requested_node: ServoLayoutNode,
|
pub fn process_resolved_style_request<'ln, N: LayoutNode<'ln>>(
|
||||||
pseudo: &Option<PseudoElement>,
|
requested_node: N, pseudo: &Option<PseudoElement>,
|
||||||
property: &Atom,
|
property: &Atom, layout_root: &mut FlowRef) -> Option<String> {
|
||||||
layout_root: &mut FlowRef)
|
let layout_node = requested_node.to_threadsafe();
|
||||||
-> Option<String> {
|
|
||||||
let layout_node = ServoThreadSafeLayoutNode::new(&requested_node);
|
|
||||||
let layout_node = match pseudo {
|
let layout_node = match pseudo {
|
||||||
&Some(PseudoElement::Before) => layout_node.get_before_pseudo(),
|
&Some(PseudoElement::Before) => layout_node.get_before_pseudo(),
|
||||||
&Some(PseudoElement::After) => layout_node.get_after_pseudo(),
|
&Some(PseudoElement::After) => layout_node.get_after_pseudo(),
|
||||||
|
@ -480,10 +475,11 @@ pub fn process_resolved_style_request(requested_node: ServoLayoutNode,
|
||||||
// There are probably other quirks.
|
// There are probably other quirks.
|
||||||
let applies = true;
|
let applies = true;
|
||||||
|
|
||||||
fn used_value_for_position_property(layout_node: ServoThreadSafeLayoutNode,
|
fn used_value_for_position_property<'ln, N: LayoutNode<'ln>>(
|
||||||
layout_root: &mut FlowRef,
|
layout_node: N::ConcreteThreadSafeLayoutNode,
|
||||||
requested_node: ServoLayoutNode,
|
layout_root: &mut FlowRef,
|
||||||
property: &Atom) -> Option<String> {
|
requested_node: N,
|
||||||
|
property: &Atom) -> Option<String> {
|
||||||
let layout_data = layout_node.borrow_layout_data();
|
let layout_data = layout_node.borrow_layout_data();
|
||||||
let position = layout_data.as_ref().map(|layout_data| {
|
let position = layout_data.as_ref().map(|layout_data| {
|
||||||
match layout_data.data.flow_construction_result {
|
match layout_data.data.flow_construction_result {
|
||||||
|
@ -560,9 +556,8 @@ pub fn process_resolved_style_request(requested_node: ServoLayoutNode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_offset_parent_query(requested_node: ServoLayoutNode,
|
pub fn process_offset_parent_query<'ln, N: LayoutNode<'ln>>(requested_node: N, layout_root: &mut FlowRef)
|
||||||
layout_root: &mut FlowRef)
|
-> OffsetParentResponse {
|
||||||
-> OffsetParentResponse {
|
|
||||||
let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node.opaque());
|
let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node.opaque());
|
||||||
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
||||||
let parent_info_index = iterator.parent_nodes.iter().rposition(|info| info.is_some());
|
let parent_info_index = iterator.parent_nodes.iter().rposition(|info| info.is_some());
|
||||||
|
|
|
@ -19,11 +19,15 @@ use traversal::{BuildDisplayList, ComputeAbsolutePositions};
|
||||||
use traversal::{PostorderDomTraversal, PreorderDomTraversal};
|
use traversal::{PostorderDomTraversal, PreorderDomTraversal};
|
||||||
use util::geometry::ZERO_POINT;
|
use util::geometry::ZERO_POINT;
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use wrapper::{LayoutNode, ServoLayoutNode};
|
use wrapper::LayoutNode;
|
||||||
|
|
||||||
pub fn traverse_dom_preorder(root: ServoLayoutNode,
|
pub fn traverse_dom_preorder<'le, N>(root: N,
|
||||||
shared_layout_context: &SharedLayoutContext) {
|
shared_layout_context: &SharedLayoutContext)
|
||||||
fn doit(node: ServoLayoutNode, recalc_style: RecalcStyleForNode, construct_flows: ConstructFlows) {
|
where N: LayoutNode<'le> {
|
||||||
|
fn doit<'le, N>(node: N,
|
||||||
|
recalc_style: RecalcStyleForNode,
|
||||||
|
construct_flows: ConstructFlows)
|
||||||
|
where N: LayoutNode<'le> {
|
||||||
recalc_style.process(node);
|
recalc_style.process(node);
|
||||||
|
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
|
@ -43,7 +47,7 @@ pub fn traverse_dom_preorder(root: ServoLayoutNode,
|
||||||
root: root.opaque(),
|
root: root.opaque(),
|
||||||
};
|
};
|
||||||
|
|
||||||
doit(root, recalc_style, construct_flows);
|
doit::<'le, N>(root, recalc_style, construct_flows);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_generated_content(root: &mut FlowRef, shared_layout_context: &SharedLayoutContext) {
|
pub fn resolve_generated_content(root: &mut FlowRef, shared_layout_context: &SharedLayoutContext) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ use table::InternalTable;
|
||||||
use table_row::{CollapsedBorder, CollapsedBorderProvenance};
|
use table_row::{CollapsedBorder, CollapsedBorderProvenance};
|
||||||
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
||||||
use util::print_tree::PrintTree;
|
use util::print_tree::PrintTree;
|
||||||
use wrapper::{ServoThreadSafeLayoutNode, ThreadSafeLayoutNode};
|
use wrapper::{ThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// A table formatting context.
|
/// A table formatting context.
|
||||||
#[derive(RustcEncodable)]
|
#[derive(RustcEncodable)]
|
||||||
|
@ -45,10 +45,8 @@ pub struct TableCellFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableCellFlow {
|
impl TableCellFlow {
|
||||||
pub fn from_node_fragment_and_visibility_flag(node: &ServoThreadSafeLayoutNode,
|
pub fn from_node_fragment_and_visibility_flag<'ln, N: ThreadSafeLayoutNode<'ln>>(
|
||||||
fragment: Fragment,
|
node: &N, fragment: Fragment, visible: bool) -> TableCellFlow {
|
||||||
visible: bool)
|
|
||||||
-> TableCellFlow {
|
|
||||||
TableCellFlow {
|
TableCellFlow {
|
||||||
block_flow: BlockFlow::from_fragment(fragment, None),
|
block_flow: BlockFlow::from_fragment(fragment, None),
|
||||||
collapsed_borders: CollapsedBordersForCell::new(),
|
collapsed_borders: CollapsedBordersForCell::new(),
|
||||||
|
|
|
@ -17,8 +17,8 @@ use std::cell::RefCell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use util::tid::tid;
|
use util::tid::tid;
|
||||||
use wrapper::{LayoutNode, ServoLayoutNode, layout_node_to_unsafe_layout_node};
|
use wrapper::{LayoutNode, UnsafeLayoutNode};
|
||||||
use wrapper::{ServoThreadSafeLayoutNode, ThreadSafeLayoutNode, UnsafeLayoutNode};
|
use wrapper::{ThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// Every time we do another layout, the old bloom filters are invalid. This is
|
/// Every time we do another layout, the old bloom filters are invalid. This is
|
||||||
/// detected by ticking a generation number every layout.
|
/// detected by ticking a generation number every layout.
|
||||||
|
@ -51,10 +51,11 @@ thread_local!(
|
||||||
///
|
///
|
||||||
/// If one does not exist, a new one will be made for you. If it is out of date,
|
/// If one does not exist, a new one will be made for you. If it is out of date,
|
||||||
/// it will be cleared and reused.
|
/// it will be cleared and reused.
|
||||||
fn take_task_local_bloom_filter(parent_node: Option<ServoLayoutNode>,
|
fn take_task_local_bloom_filter<'ln, N>(parent_node: Option<N>,
|
||||||
root: OpaqueNode,
|
root: OpaqueNode,
|
||||||
layout_context: &LayoutContext)
|
layout_context: &LayoutContext)
|
||||||
-> Box<BloomFilter> {
|
-> Box<BloomFilter>
|
||||||
|
where N: LayoutNode<'ln> {
|
||||||
STYLE_BLOOM.with(|style_bloom| {
|
STYLE_BLOOM.with(|style_bloom| {
|
||||||
match (parent_node, style_bloom.borrow_mut().take()) {
|
match (parent_node, style_bloom.borrow_mut().take()) {
|
||||||
// Root node. Needs new bloom filter.
|
// Root node. Needs new bloom filter.
|
||||||
|
@ -70,7 +71,7 @@ fn take_task_local_bloom_filter(parent_node: Option<ServoLayoutNode>,
|
||||||
}
|
}
|
||||||
// Found cached bloom filter.
|
// Found cached bloom filter.
|
||||||
(Some(parent), Some((mut bloom_filter, old_node, old_generation))) => {
|
(Some(parent), Some((mut bloom_filter, old_node, old_generation))) => {
|
||||||
if old_node == layout_node_to_unsafe_layout_node(&parent) &&
|
if old_node == parent.to_unsafe() &&
|
||||||
old_generation == layout_context.shared.generation {
|
old_generation == layout_context.shared.generation {
|
||||||
// Hey, the cached parent is our parent! We can reuse the bloom filter.
|
// Hey, the cached parent is our parent! We can reuse the bloom filter.
|
||||||
debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.0);
|
debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.0);
|
||||||
|
@ -97,9 +98,10 @@ fn put_task_local_bloom_filter(bf: Box<BloomFilter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "Ancestors" in this context is inclusive of ourselves.
|
/// "Ancestors" in this context is inclusive of ourselves.
|
||||||
fn insert_ancestors_into_bloom_filter(bf: &mut Box<BloomFilter>,
|
fn insert_ancestors_into_bloom_filter<'ln, N>(bf: &mut Box<BloomFilter>,
|
||||||
mut n: ServoLayoutNode,
|
mut n: N,
|
||||||
root: OpaqueNode) {
|
root: OpaqueNode)
|
||||||
|
where N: LayoutNode<'ln> {
|
||||||
debug!("[{}] Inserting ancestors.", tid());
|
debug!("[{}] Inserting ancestors.", tid());
|
||||||
let mut ancestors = 0;
|
let mut ancestors = 0;
|
||||||
loop {
|
loop {
|
||||||
|
@ -116,21 +118,21 @@ fn insert_ancestors_into_bloom_filter(bf: &mut Box<BloomFilter>,
|
||||||
|
|
||||||
|
|
||||||
/// A top-down traversal.
|
/// A top-down traversal.
|
||||||
pub trait PreorderDomTraversal {
|
pub trait PreorderDomTraversal<'ln, ConcreteLayoutNode: LayoutNode<'ln>> {
|
||||||
/// The operation to perform. Return true to continue or false to stop.
|
/// The operation to perform. Return true to continue or false to stop.
|
||||||
fn process(&self, node: ServoLayoutNode);
|
fn process(&self, node: ConcreteLayoutNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bottom-up traversal, with a optional in-order pass.
|
/// A bottom-up traversal, with a optional in-order pass.
|
||||||
pub trait PostorderDomTraversal {
|
pub trait PostorderDomTraversal<'ln, ConcreteLayoutNode: LayoutNode<'ln>> {
|
||||||
/// The operation to perform. Return true to continue or false to stop.
|
/// The operation to perform. Return true to continue or false to stop.
|
||||||
fn process(&self, node: ServoLayoutNode);
|
fn process(&self, node: ConcreteLayoutNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bottom-up, parallelizable traversal.
|
/// A bottom-up, parallelizable traversal.
|
||||||
pub trait PostorderNodeMutTraversal {
|
pub trait PostorderNodeMutTraversal<'ln, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>> {
|
||||||
/// The operation to perform. Return true to continue or false to stop.
|
/// The operation to perform. Return true to continue or false to stop.
|
||||||
fn process<'a>(&'a mut self, node: &ServoThreadSafeLayoutNode<'a>) -> bool;
|
fn process(&mut self, node: &ConcreteThreadSafeLayoutNode) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The recalc-style-for-node traversal, which styles each node and must run before
|
/// The recalc-style-for-node traversal, which styles each node and must run before
|
||||||
|
@ -141,10 +143,12 @@ pub struct RecalcStyleForNode<'a> {
|
||||||
pub root: OpaqueNode,
|
pub root: OpaqueNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
|
impl<'a, 'ln, ConcreteLayoutNode> PreorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||||
|
for RecalcStyleForNode<'a>
|
||||||
|
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn process(&self, node: ServoLayoutNode) {
|
fn process(&self, node: ConcreteLayoutNode) {
|
||||||
// Initialize layout data.
|
// Initialize layout data.
|
||||||
//
|
//
|
||||||
// FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
|
// FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
|
||||||
|
@ -162,7 +166,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
|
||||||
// Remove existing CSS styles from nodes whose content has changed (e.g. text changed),
|
// Remove existing CSS styles from nodes whose content has changed (e.g. text changed),
|
||||||
// to force non-incremental reflow.
|
// to force non-incremental reflow.
|
||||||
if node.has_changed() {
|
if node.has_changed() {
|
||||||
let node = ServoThreadSafeLayoutNode::new(&node);
|
let node = node.to_threadsafe();
|
||||||
node.unstyle();
|
node.unstyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +203,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
if node.has_changed() {
|
if node.has_changed() {
|
||||||
ServoThreadSafeLayoutNode::new(&node).set_restyle_damage(
|
node.to_threadsafe().set_restyle_damage(
|
||||||
incremental::rebuild_and_reflow())
|
incremental::rebuild_and_reflow())
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -222,12 +226,12 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
|
||||||
}
|
}
|
||||||
StyleSharingResult::StyleWasShared(index, damage) => {
|
StyleSharingResult::StyleWasShared(index, damage) => {
|
||||||
style_sharing_candidate_cache.touch(index);
|
style_sharing_candidate_cache.touch(index);
|
||||||
ServoThreadSafeLayoutNode::new(&node).set_restyle_damage(damage);
|
node.to_threadsafe().set_restyle_damage(damage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let unsafe_layout_node = layout_node_to_unsafe_layout_node(&node);
|
let unsafe_layout_node = node.to_unsafe();
|
||||||
|
|
||||||
// Before running the children, we need to insert our nodes into the bloom
|
// Before running the children, we need to insert our nodes into the bloom
|
||||||
// filter.
|
// filter.
|
||||||
|
@ -246,13 +250,15 @@ pub struct ConstructFlows<'a> {
|
||||||
pub root: OpaqueNode,
|
pub root: OpaqueNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PostorderDomTraversal for ConstructFlows<'a> {
|
impl<'a, 'ln, ConcreteLayoutNode> PostorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||||
|
for ConstructFlows<'a>
|
||||||
|
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn process(&self, node: ServoLayoutNode) {
|
fn process(&self, node: ConcreteLayoutNode) {
|
||||||
// Construct flows for this node.
|
// Construct flows for this node.
|
||||||
{
|
{
|
||||||
let tnode = ServoThreadSafeLayoutNode::new(&node);
|
let tnode = node.to_threadsafe();
|
||||||
|
|
||||||
// Always reconstruct if incremental layout is turned off.
|
// Always reconstruct if incremental layout is turned off.
|
||||||
let nonincremental_layout = opts::get().nonincremental_layout;
|
let nonincremental_layout = opts::get().nonincremental_layout;
|
||||||
|
@ -277,7 +283,7 @@ impl<'a> PostorderDomTraversal for ConstructFlows<'a> {
|
||||||
node.set_dirty_descendants(false);
|
node.set_dirty_descendants(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let unsafe_layout_node = layout_node_to_unsafe_layout_node(&node);
|
let unsafe_layout_node = node.to_unsafe();
|
||||||
|
|
||||||
let (mut bf, old_node, old_generation) =
|
let (mut bf, old_node, old_generation) =
|
||||||
STYLE_BLOOM.with(|style_bloom| {
|
STYLE_BLOOM.with(|style_bloom| {
|
||||||
|
@ -296,7 +302,7 @@ impl<'a> PostorderDomTraversal for ConstructFlows<'a> {
|
||||||
Some(parent) => {
|
Some(parent) => {
|
||||||
// Otherwise, put it back, but remove this node.
|
// Otherwise, put it back, but remove this node.
|
||||||
node.remove_from_bloom_filter(&mut *bf);
|
node.remove_from_bloom_filter(&mut *bf);
|
||||||
let unsafe_parent = layout_node_to_unsafe_layout_node(&parent);
|
let unsafe_parent = parent.to_unsafe();
|
||||||
put_task_local_bloom_filter(bf, &unsafe_parent, self.layout_context);
|
put_task_local_bloom_filter(bf, &unsafe_parent, self.layout_context);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,15 +71,25 @@ use style::restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_S
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::str::{is_whitespace, search_index};
|
use util::str::{is_whitespace, search_index};
|
||||||
|
|
||||||
|
/// Opaque type stored in type-unsafe work queues for parallel layout.
|
||||||
|
/// Must be transmutable to and from LayoutNode.
|
||||||
|
pub type UnsafeLayoutNode = (usize, usize);
|
||||||
|
|
||||||
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
||||||
/// only ever see these and must never see instances of `LayoutJS`.
|
/// only ever see these and must never see instances of `LayoutJS`.
|
||||||
|
|
||||||
pub trait LayoutNode<'ln> : Sized + Copy + Clone {
|
pub trait LayoutNode<'ln> : Sized + Copy + Clone {
|
||||||
|
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>;
|
||||||
type ConcreteLayoutElement: LayoutElement<'ln, ConcreteLayoutNode = Self,
|
type ConcreteLayoutElement: LayoutElement<'ln, ConcreteLayoutNode = Self,
|
||||||
ConcreteLayoutDocument = Self::ConcreteLayoutDocument>;
|
ConcreteLayoutDocument = Self::ConcreteLayoutDocument>;
|
||||||
type ConcreteLayoutDocument: LayoutDocument<'ln, ConcreteLayoutNode = Self,
|
type ConcreteLayoutDocument: LayoutDocument<'ln, ConcreteLayoutNode = Self,
|
||||||
ConcreteLayoutElement = Self::ConcreteLayoutElement>;
|
ConcreteLayoutElement = Self::ConcreteLayoutElement>;
|
||||||
|
|
||||||
|
fn to_unsafe(&self) -> UnsafeLayoutNode;
|
||||||
|
unsafe fn from_unsafe(&UnsafeLayoutNode) -> Self;
|
||||||
|
|
||||||
|
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode;
|
||||||
|
|
||||||
/// Returns the type ID of this node.
|
/// Returns the type ID of this node.
|
||||||
fn type_id(&self) -> NodeTypeId;
|
fn type_id(&self) -> NodeTypeId;
|
||||||
|
|
||||||
|
@ -268,9 +278,26 @@ impl<'ln> ServoLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
|
impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
|
||||||
|
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
|
||||||
type ConcreteLayoutElement = ServoLayoutElement<'ln>;
|
type ConcreteLayoutElement = ServoLayoutElement<'ln>;
|
||||||
type ConcreteLayoutDocument = ServoLayoutDocument<'ln>;
|
type ConcreteLayoutDocument = ServoLayoutDocument<'ln>;
|
||||||
|
|
||||||
|
fn to_unsafe(&self) -> UnsafeLayoutNode {
|
||||||
|
unsafe {
|
||||||
|
let ptr: usize = mem::transmute_copy(self);
|
||||||
|
(ptr, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_unsafe(n: &UnsafeLayoutNode) -> Self {
|
||||||
|
let (node, _) = *n;
|
||||||
|
mem::transmute(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
|
||||||
|
ServoThreadSafeLayoutNode::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
fn type_id(&self) -> NodeTypeId {
|
fn type_id(&self) -> NodeTypeId {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.node.type_id_for_layout()
|
self.node.type_id_for_layout()
|
||||||
|
@ -1281,22 +1308,6 @@ impl<'le> ThreadSafeLayoutElement<'le> for ServoThreadSafeLayoutElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opaque type stored in type-unsafe work queues for parallel layout.
|
|
||||||
/// Must be transmutable to and from LayoutNode.
|
|
||||||
pub type UnsafeLayoutNode = (usize, usize);
|
|
||||||
|
|
||||||
pub fn layout_node_to_unsafe_layout_node(node: &ServoLayoutNode) -> UnsafeLayoutNode {
|
|
||||||
unsafe {
|
|
||||||
let ptr: usize = mem::transmute_copy(node);
|
|
||||||
(ptr, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn layout_node_from_unsafe_layout_node(node: &UnsafeLayoutNode) -> ServoLayoutNode {
|
|
||||||
let (node, _) = *node;
|
|
||||||
mem::transmute(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TextContent {
|
pub enum TextContent {
|
||||||
Text(String),
|
Text(String),
|
||||||
GeneratedContent(Vec<ContentItem>),
|
GeneratedContent(Vec<ContentItem>),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue