mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
layout: Port the flow tree over to the new generic tree functions
This commit is contained in:
parent
6a6cad1e39
commit
fe36f1dccb
7 changed files with 116 additions and 129 deletions
|
@ -16,6 +16,7 @@ use geom::point::Point2D;
|
|||
use geom::rect::Rect;
|
||||
use gfx::display_list::DisplayList;
|
||||
use gfx::geometry::Au;
|
||||
use servo_util::tree::TreeUtils;
|
||||
|
||||
pub struct BlockFlowData {
|
||||
/// Data common to all flows.
|
||||
|
|
|
@ -19,6 +19,7 @@ use gfx::image::holder::ImageHolder;
|
|||
use newcss::values::{CSSDisplay, CSSDisplayBlock, CSSDisplayInline, CSSDisplayInlineBlock};
|
||||
use newcss::values::{CSSDisplayNone};
|
||||
use servo_util::range::Range;
|
||||
use servo_util::tree::TreeUtils;
|
||||
|
||||
pub struct LayoutTreeBuilder {
|
||||
root_flow: Option<FlowContext>,
|
||||
|
@ -121,7 +122,6 @@ impl BoxGenerator {
|
|||
// depending on flow, make a box for this node.
|
||||
match self.flow {
|
||||
InlineFlow(inline) => {
|
||||
use servo_util::tree::TreeUtils; // For `is_leaf()`.
|
||||
|
||||
let mut inline = &mut *inline;
|
||||
let node_range_start = inline.boxes.len();
|
||||
|
@ -338,12 +338,8 @@ pub impl LayoutTreeBuilder {
|
|||
debug!("point b: %s", cur_node.debug_str());
|
||||
|
||||
// recurse on child nodes.
|
||||
{
|
||||
use servo_util::tree::TreeUtils; // For `each_child()`.
|
||||
|
||||
for cur_node.each_child |child_node| {
|
||||
self.construct_recursively(layout_ctx, child_node, &mut this_ctx);
|
||||
}
|
||||
for cur_node.each_child |child_node| {
|
||||
self.construct_recursively(layout_ctx, child_node, &mut this_ctx);
|
||||
}
|
||||
|
||||
this_ctx.default_collector.pop_node(layout_ctx, self, cur_node);
|
||||
|
@ -354,6 +350,7 @@ pub impl LayoutTreeBuilder {
|
|||
// eventually be elided or split, but the mapping between
|
||||
// nodes and FlowContexts should not change during layout.
|
||||
let flow = &mut this_ctx.default_collector.flow;
|
||||
let flow: &FlowContext = flow;
|
||||
for flow.each_child |child_flow| {
|
||||
do child_flow.with_common_info |child_flow_info| {
|
||||
let node = child_flow_info.node;
|
||||
|
@ -379,6 +376,7 @@ pub impl LayoutTreeBuilder {
|
|||
let mut found_child_block = false;
|
||||
|
||||
let flow = &mut parent_ctx.default_collector.flow;
|
||||
let flow: &FlowContext = flow;
|
||||
for flow.each_child |child_ctx| {
|
||||
match child_ctx {
|
||||
InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true,
|
||||
|
|
|
@ -41,6 +41,7 @@ use geom::point::Point2D;
|
|||
use geom::rect::Rect;
|
||||
use gfx::display_list::DisplayList;
|
||||
use gfx::geometry::Au;
|
||||
use servo_util::tree::{TreeNode, TreeNodeRef, TreeUtils};
|
||||
|
||||
/// The type of the formatting context and data specific to each context, such as line box
|
||||
/// structures or float lists.
|
||||
|
@ -64,6 +65,21 @@ pub enum FlowContextType {
|
|||
Flow_Table
|
||||
}
|
||||
|
||||
impl Clone for FlowContext {
|
||||
fn clone(&self) -> FlowContext {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeNodeRef<FlowData> for FlowContext {
|
||||
fn with_immutable_node<R>(&self, callback: &fn(&FlowData) -> R) -> R {
|
||||
self.with_common_imm_info(callback)
|
||||
}
|
||||
fn with_mutable_node<R>(&self, callback: &fn(&mut FlowData) -> R) -> R {
|
||||
self.with_common_info(callback)
|
||||
}
|
||||
}
|
||||
|
||||
/// Data common to all flows.
|
||||
///
|
||||
/// FIXME: We need a naming convention for pseudo-inheritance like this. How about
|
||||
|
@ -88,6 +104,48 @@ pub struct FlowData {
|
|||
position: Rect<Au>,
|
||||
}
|
||||
|
||||
impl TreeNode<FlowContext> for FlowData {
|
||||
fn parent_node(&self) -> Option<FlowContext> {
|
||||
self.parent
|
||||
}
|
||||
|
||||
fn first_child(&self) -> Option<FlowContext> {
|
||||
self.first_child
|
||||
}
|
||||
|
||||
fn last_child(&self) -> Option<FlowContext> {
|
||||
self.last_child
|
||||
}
|
||||
|
||||
fn prev_sibling(&self) -> Option<FlowContext> {
|
||||
self.prev_sibling
|
||||
}
|
||||
|
||||
fn next_sibling(&self) -> Option<FlowContext> {
|
||||
self.next_sibling
|
||||
}
|
||||
|
||||
fn set_parent_node(&mut self, new_parent_node: Option<FlowContext>) {
|
||||
self.parent = new_parent_node
|
||||
}
|
||||
|
||||
fn set_first_child(&mut self, new_first_child: Option<FlowContext>) {
|
||||
self.first_child = new_first_child
|
||||
}
|
||||
|
||||
fn set_last_child(&mut self, new_last_child: Option<FlowContext>) {
|
||||
self.last_child = new_last_child
|
||||
}
|
||||
|
||||
fn set_prev_sibling(&mut self, new_prev_sibling: Option<FlowContext>) {
|
||||
self.prev_sibling = new_prev_sibling
|
||||
}
|
||||
|
||||
fn set_next_sibling(&mut self, new_next_sibling: Option<FlowContext>) {
|
||||
self.next_sibling = new_next_sibling
|
||||
}
|
||||
}
|
||||
|
||||
impl FlowData {
|
||||
pub fn new(id: int, node: AbstractNode) -> FlowData {
|
||||
FlowData {
|
||||
|
@ -109,6 +167,30 @@ impl FlowData {
|
|||
}
|
||||
|
||||
impl<'self> FlowContext {
|
||||
// FIXME: This method is a duplicate of `with_immutable_node`; fix this.
|
||||
#[inline(always)]
|
||||
pub fn with_common_imm_info<R>(&self, block: &fn(&FlowData) -> R) -> R {
|
||||
match *self {
|
||||
AbsoluteFlow(info) => block(info),
|
||||
BlockFlow(info) => {
|
||||
let info = &*info; // FIXME: Borrow check workaround.
|
||||
block(&info.common)
|
||||
}
|
||||
FloatFlow(info) => block(info),
|
||||
InlineBlockFlow(info) => block(info),
|
||||
InlineFlow(info) => {
|
||||
let info = &*info; // FIXME: Borrow check workaround.
|
||||
block(&info.common)
|
||||
}
|
||||
RootFlow(info) => {
|
||||
let info = &*info; // FIXME: Borrow check workaround.
|
||||
block(&info.common)
|
||||
}
|
||||
TableFlow(info) => block(info),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This method is a duplicate of `with_mutable_node`; fix this.
|
||||
#[inline(always)]
|
||||
pub fn with_common_info<R>(&self, block: &fn(&mut FlowData) -> R) -> R {
|
||||
match *self {
|
||||
|
@ -145,87 +227,6 @@ impl<'self> FlowContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// Iterates over the immediate children of this flow.
|
||||
///
|
||||
/// TODO: Fold me into `util::tree`.
|
||||
pub fn each_child(&self, f: &fn(FlowContext) -> bool) {
|
||||
let mut current_opt = self.with_common_info(|info| info.first_child);
|
||||
while !current_opt.is_none() {
|
||||
let current = current_opt.get();
|
||||
if !f(current) {
|
||||
break;
|
||||
}
|
||||
current_opt = current.with_common_info(|info| info.next_sibling);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the given flow to the end of the list of this flow's children. The new child must be
|
||||
/// detached from the tree before calling this method.
|
||||
///
|
||||
/// TODO: Fold me into `util::tree`.
|
||||
pub fn add_child(&self, child: FlowContext) {
|
||||
do self.with_common_info |self_info| {
|
||||
do child.with_common_info |child_info| {
|
||||
assert!(child_info.parent.is_none());
|
||||
assert!(child_info.prev_sibling.is_none());
|
||||
assert!(child_info.next_sibling.is_none());
|
||||
|
||||
match self_info.last_child {
|
||||
None => {
|
||||
self_info.first_child = Some(child);
|
||||
}
|
||||
Some(last_child) => {
|
||||
do last_child.with_common_info |last_child_info| {
|
||||
assert!(last_child_info.next_sibling.is_none());
|
||||
last_child_info.next_sibling = Some(child);
|
||||
child_info.prev_sibling = Some(last_child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self_info.last_child = Some(child);
|
||||
child_info.parent = Some(*self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the given flow from the tree.
|
||||
///
|
||||
/// TODO: Fold me into `util::tree`.
|
||||
pub fn remove_child(&self, child: FlowContext) {
|
||||
do self.with_common_info |self_info| {
|
||||
do child.with_common_info |child_info| {
|
||||
assert!(child_info.parent.is_some());
|
||||
|
||||
match child_info.prev_sibling {
|
||||
None => self_info.first_child = child_info.next_sibling,
|
||||
Some(prev_sibling) => {
|
||||
do prev_sibling.with_common_info |prev_sibling_info| {
|
||||
prev_sibling_info.next_sibling = child_info.next_sibling;
|
||||
child_info.prev_sibling = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match child_info.next_sibling {
|
||||
None => {
|
||||
do child.with_common_info |child_info| {
|
||||
self_info.last_child = child_info.prev_sibling;
|
||||
}
|
||||
}
|
||||
Some(next_sibling) => {
|
||||
do next_sibling.with_common_info |next_sibling_info| {
|
||||
next_sibling_info.prev_sibling = Some(next_sibling);
|
||||
child_info.next_sibling = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
child_info.parent = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inline(&self) -> @mut InlineFlowData {
|
||||
match *self {
|
||||
InlineFlow(info) => info,
|
||||
|
|
|
@ -15,7 +15,6 @@ use layout::context::LayoutContext;
|
|||
use layout::debug::{BoxedMutDebugMethods, DebugMethods};
|
||||
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
|
||||
use layout::flow::FlowContext;
|
||||
use layout::traverse::*;
|
||||
use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg};
|
||||
use resource::local_image_cache::LocalImageCache;
|
||||
use util::task::spawn_listener;
|
||||
|
@ -35,6 +34,7 @@ use gfx::render_task::{RenderMsg, RenderTask};
|
|||
use newcss::select::SelectCtx;
|
||||
use newcss::stylesheet::Stylesheet;
|
||||
use newcss::types::OriginAuthor;
|
||||
use servo_util::tree::TreeUtils;
|
||||
use std::net::url::Url;
|
||||
|
||||
pub type LayoutTask = SharedChan<Msg>;
|
||||
|
@ -165,11 +165,12 @@ impl Layout {
|
|||
self.css_select_ctx.append_sheet(sheet.take(), OriginAuthor);
|
||||
}
|
||||
|
||||
/// The high-level routine that performs layout tasks.
|
||||
fn handle_build(&mut self, data: &BuildData) {
|
||||
let node = &data.node;
|
||||
// FIXME: Bad copy
|
||||
// FIXME: Bad copy!
|
||||
let doc_url = copy data.url;
|
||||
// FIXME: Bad clone
|
||||
// FIXME: Bad clone!
|
||||
let dom_event_chan = data.dom_event_chan.clone();
|
||||
|
||||
debug!("layout: received layout request for: %s", doc_url.to_str());
|
||||
|
@ -177,12 +178,13 @@ impl Layout {
|
|||
debug!("layout: parsed Node tree");
|
||||
debug!("%?", node.dump());
|
||||
|
||||
// Reset the image cache
|
||||
// Reset the image cache.
|
||||
self.local_image_cache.next_round(self.make_on_image_available_cb(dom_event_chan));
|
||||
|
||||
let screen_size = Size2D(Au::from_px(data.window_size.width as int),
|
||||
Au::from_px(data.window_size.height as int));
|
||||
|
||||
// Create a layout context for use throughout the following passes.
|
||||
let mut layout_ctx = LayoutContext {
|
||||
image_cache: self.local_image_cache,
|
||||
font_ctx: self.font_ctx,
|
||||
|
@ -190,8 +192,10 @@ impl Layout {
|
|||
screen_size: Rect(Point2D(Au(0), Au(0)), screen_size)
|
||||
};
|
||||
|
||||
// Initialize layout data for each node.
|
||||
//
|
||||
// FIXME: This is inefficient. We don't need an entire traversal to do this!
|
||||
do time("layout: aux initialization") {
|
||||
// TODO: this is dumb. we don't need an entire traversal to do this
|
||||
node.initialize_style_for_subtree(&mut self.layout_refs);
|
||||
}
|
||||
|
||||
|
@ -205,6 +209,7 @@ impl Layout {
|
|||
}
|
||||
}
|
||||
|
||||
// Construct the flow tree.
|
||||
let layout_root: FlowContext = do time("layout: tree construction") {
|
||||
let mut builder = LayoutTreeBuilder::new();
|
||||
let layout_root: FlowContext = match builder.construct_trees(&layout_ctx, *node) {
|
||||
|
@ -218,13 +223,21 @@ impl Layout {
|
|||
layout_root
|
||||
};
|
||||
|
||||
// Perform the primary layout passes over the flow tree to compute the locations of all
|
||||
// the boxes.
|
||||
do time("layout: main layout") {
|
||||
/* perform layout passes over the flow tree */
|
||||
do layout_root.traverse_postorder |f| { f.bubble_widths(&mut layout_ctx) }
|
||||
do layout_root.traverse_preorder |f| { f.assign_widths(&mut layout_ctx) }
|
||||
do layout_root.traverse_postorder |f| { f.assign_height(&mut layout_ctx) }
|
||||
for layout_root.traverse_postorder |flow| {
|
||||
flow.bubble_widths(&mut layout_ctx);
|
||||
};
|
||||
for layout_root.traverse_preorder |flow| {
|
||||
flow.assign_widths(&mut layout_ctx);
|
||||
};
|
||||
for layout_root.traverse_postorder |flow| {
|
||||
flow.assign_height(&mut layout_ctx);
|
||||
};
|
||||
}
|
||||
|
||||
// Build the display list, and send it to the renderer.
|
||||
do time("layout: display list building") {
|
||||
let builder = DisplayListBuilder {
|
||||
ctx: &layout_ctx,
|
||||
|
@ -249,13 +262,13 @@ impl Layout {
|
|||
self.render_task.send(RenderMsg(render_layer));
|
||||
} // time(layout: display list building)
|
||||
|
||||
// Tell content we're done
|
||||
// Tell content that we're done.
|
||||
data.content_join_chan.send(());
|
||||
}
|
||||
|
||||
|
||||
fn handle_query(&self, query: LayoutQuery,
|
||||
reply_chan: Chan<LayoutQueryResponse>) {
|
||||
/// Handles a query from the script task. This is the main routine that DOM functions like
|
||||
/// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
|
||||
fn handle_query(&self, query: LayoutQuery, reply_chan: Chan<LayoutQueryResponse>) {
|
||||
match query {
|
||||
ContentBox(node) => {
|
||||
let response = match node.layout_data().flow {
|
||||
|
|
|
@ -13,6 +13,8 @@ use layout::context::LayoutContext;
|
|||
use layout::flow::{FlowContext, FlowData, RootFlow};
|
||||
use layout::display_list_builder::DisplayListBuilder;
|
||||
|
||||
use servo_util::tree::TreeUtils;
|
||||
|
||||
pub struct RootFlowData {
|
||||
/// Data common to all flows.
|
||||
common: FlowData,
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use layout::flow::FlowContext;
|
||||
|
||||
/// A trait for running tree-based traversals over flows contexts.
|
||||
pub trait FlowContextTraversals {
|
||||
fn traverse_preorder(&self, preorder_cb: &fn(FlowContext));
|
||||
fn traverse_postorder(&self, postorder_cb: &fn(FlowContext));
|
||||
}
|
||||
|
||||
impl FlowContextTraversals for FlowContext {
|
||||
fn traverse_preorder(&self, preorder_cb: &fn(FlowContext)) {
|
||||
preorder_cb(*self);
|
||||
for self.each_child |child| {
|
||||
child.traverse_preorder(preorder_cb);
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse_postorder(&self, postorder_cb: &fn(FlowContext)) {
|
||||
for self.each_child |child| {
|
||||
child.traverse_postorder(postorder_cb);
|
||||
}
|
||||
postorder_cb(*self);
|
||||
}
|
||||
}
|
|
@ -104,7 +104,6 @@ pub mod layout {
|
|||
pub mod inline;
|
||||
pub mod root;
|
||||
pub mod text;
|
||||
pub mod traverse;
|
||||
mod aux;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue