Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extra display list data #482

Closed
wants to merge 11 commits into from

Reduce coupling between layout and the DOM by separating out the layo…

…ut interface.

Eventually, the layout interface will be moved along with the DOM into a
separate crate.
  • Loading branch information
pcwalton committed May 25, 2013
commit 2100f62ef5abd8411418b7bcdde10e40775bb5e3
@@ -8,7 +8,7 @@ use dom::bindings::utils::{domstring_to_jsval, WrapNewBindingObject};
use dom::bindings::utils::{str, CacheableWrapper, DOM_OBJECT_SLOT, DOMString};
use dom::element::*;
use dom::node::{AbstractNode, Element, ElementNodeTypeId, ScriptView};
use layout::layout_task;
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
use scripting::script_task::task_from_context;
use super::utils;

@@ -216,10 +216,10 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa
let width = match node.type_id() {
ElementNodeTypeId(HTMLImageElementTypeId) => {
let script_context = task_from_context(cx);
match (*script_context).query_layout(layout_task::ContentBox(node)) {
match (*script_context).query_layout(ContentBoxQuery(node)) {
Ok(rect) => {
match rect {
layout_task::ContentRect(rect) => rect.size.width.to_px(),
ContentBoxResponse(rect) => rect.size.width.to_px(),
_ => fail!(~"unexpected layout reply")
}
}
@@ -2,19 +2,17 @@
* 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/. */

//
// Element nodes.
//
//! Element nodes.

use dom::node::{ElementNodeTypeId, Node, ScriptView};
use dom::bindings::utils::DOMString;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::bindings::utils::DOMString;

use layout::layout_task;
use dom::node::{ElementNodeTypeId, Node, ScriptView};
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse};

use core::str::eq_slice;
use core::cell::Cell;
use core::str::eq_slice;
use std::net::url::Url;

pub struct Element {
@@ -169,9 +167,9 @@ pub impl<'self> Element {
let script_context = unsafe {
&mut *win.script_context
};
match script_context.query_layout(layout_task::ContentBoxes(node)) {
match script_context.query_layout(ContentBoxesQuery(node)) {
Ok(rects) => match rects {
layout_task::ContentRects(rects) =>
ContentBoxesResponse(rects) =>
do rects.map |r| {
ClientRect::new(
r.origin.y.to_f32(),
@@ -209,9 +207,9 @@ pub impl<'self> Element {
let node = self.parent.abstract.get();
assert!(node.is_element());
let script_context = unsafe { &mut *win.script_context };
match script_context.query_layout(layout_task::ContentBox(node)) {
match script_context.query_layout(ContentBoxQuery(node)) {
Ok(rect) => match rect {
layout_task::ContentRect(rect) =>
ContentBoxResponse(rect) =>
Some(ClientRect::new(
rect.origin.y.to_f32(),
(rect.origin.y + rect.size.height).to_f32(),
@@ -4,8 +4,8 @@

use dom::bindings::utils::WrapperCache;
use dom::bindings::window;
use layout_interface::MatchSelectorsDamage;
use scripting::script_task::{ExitMsg, FireTimerMsg, ScriptMsg, ScriptContext};
use layout::layout_task::MatchSelectorsDamage;
use util::task::spawn_listener;

use core::comm::{Port, Chan, SharedChan};
@@ -3,8 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use compositing::CompositorTask;
use layout::layout_task::LayoutTask;
use layout::layout_task;
use layout_interface::LayoutTask;
use layout_interface;
use scripting::script_task::{ExecuteMsg, LoadMsg, ScriptMsg, ScriptTask};
use scripting::script_task;
use util::task::spawn_listener;
@@ -61,10 +62,10 @@ impl Engine {
profiler_chan.clone());

let opts = opts.take();
let layout_task = LayoutTask(render_task.clone(),
image_cache_task.clone(),
opts,
profiler_task.chan.clone());
let layout_task = layout_task::create_layout_task(render_task.clone(),
image_cache_task.clone(),
opts,
profiler_task.chan.clone());

let script_task = ScriptTask::new(script_port.take(),
script_chan.take(),
@@ -105,7 +106,7 @@ impl Engine {

ExitMsg(sender) => {
self.script_task.chan.send(script_task::ExitMsg);
self.layout_task.send(layout_task::ExitMsg);
self.layout_task.chan.send(layout_interface::ExitMsg);

let (response_port, response_chan) = comm::stream();

@@ -2,19 +2,23 @@
* 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/. */

/// The layout task. Performs layout on the DOM, builds display lists and sends them to be
//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
/// rendered.

use css::matching::MatchMethods;
use css::select::new_css_select_ctx;
use dom::event::ReflowEvent;
use dom::node::{AbstractNode, LayoutView, ScriptView};
use dom::node::{AbstractNode, LayoutView};
use layout::aux::{LayoutData, LayoutAuxMethods};
use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use layout::debug::{BoxedMutDebugMethods, DebugMethods};
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
use layout::flow::FlowContext;
use layout_interface::{AddStylesheetMsg, BuildData, BuildMsg, ContentBoxQuery, ContentBoxResponse};
use layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
use layout_interface::{LayoutResponse, LayoutTask, MatchSelectorsDamage, Msg, NoDamage, QueryMsg};
use layout_interface::{ReflowDamage};
use scripting::script_task::{ScriptMsg, SendEventMsg};
use util::task::spawn_listener;
use servo_util::time;
@@ -40,124 +44,76 @@ use newcss::types::OriginAuthor;
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::TreeUtils;
use std::net::url::Url;

pub type LayoutTask = SharedChan<Msg>;

pub enum LayoutQuery {
ContentBox(AbstractNode<ScriptView>),
ContentBoxes(AbstractNode<ScriptView>),
}

pub type LayoutQueryResponse = Result<LayoutQueryResponse_, ()>;

pub enum LayoutQueryResponse_ {
ContentRect(Rect<Au>),
ContentRects(~[Rect<Au>])
}

pub enum Msg {
AddStylesheet(Stylesheet),
BuildMsg(~BuildData),
QueryMsg(LayoutQuery, Chan<LayoutQueryResponse>),
ExitMsg
}

// Dirty bits for layout.
pub enum Damage {
NoDamage, // Document is clean; do nothing.
ReflowDamage, // Reflow; don't perform CSS selector matching.
MatchSelectorsDamage, // Perform CSS selector matching and reflow.
}
pub fn create_layout_task(render_task: RenderTask, img_cache_task: ImageCacheTask, opts: Opts)
-> LayoutTask {
let chan = do spawn_listener::<Msg> |from_script| {
let mut layout = Layout::new(render_task.clone(),
img_cache_task.clone(),
from_script,
&opts);
layout.start();
};

impl Damage {
fn add(&mut self, new_damage: Damage) {
match (*self, new_damage) {
(NoDamage, _) => *self = new_damage,
(ReflowDamage, NoDamage) => *self = ReflowDamage,
(ReflowDamage, new_damage) => *self = new_damage,
(MatchSelectorsDamage, _) => *self = MatchSelectorsDamage
}
LayoutTask {
chan: SharedChan::new(chan),
}
}

pub struct BuildData {
node: AbstractNode<ScriptView>,
url: Url,
script_chan: SharedChan<ScriptMsg>,
window_size: Size2D<uint>,
script_join_chan: Chan<()>,
damage: Damage,
}

pub fn LayoutTask(render_task: RenderTask,
img_cache_task: ImageCacheTask,
opts: Opts,
prof_chan: ProfilerChan)
-> LayoutTask {
SharedChan::new(do spawn_listener::<Msg> |from_script| {
let mut layout = Layout(render_task.clone(),
img_cache_task.clone(),
from_script,
&opts,
prof_chan.clone());
layout.start();
})
}

struct Layout {
render_task: RenderTask,
image_cache_task: ImageCacheTask,
local_image_cache: @mut LocalImageCache,
from_script: Port<Msg>,
font_ctx: @mut FontContext,
// This is used to root reader data

/// This is used to root reader data.
layout_refs: ~[@mut LayoutData],

css_select_ctx: @mut SelectCtx,
prof_chan: ProfilerChan,
}

fn Layout(render_task: RenderTask,
image_cache_task: ImageCacheTask,
from_script: Port<Msg>,
opts: &Opts,
prof_chan: ProfilerChan)
-> Layout {
let fctx = @mut FontContext::new(opts.render_backend, true, prof_chan.clone());

Layout {
render_task: render_task,
image_cache_task: image_cache_task.clone(),
local_image_cache: @mut LocalImageCache(image_cache_task),
from_script: from_script,
font_ctx: fctx,
layout_refs: ~[],
css_select_ctx: @mut new_css_select_ctx(),
prof_chan: prof_chan.clone()
}
/// The channel on which to send profiling data.
profiler_chan: ProfilerChan,
}

impl Layout {
fn new(render_task: RenderTask,
image_cache_task: ImageCacheTask,
from_script: Port<Msg>,
opts: &Opts,
profiler_chan: ProfilerChan)
-> Layout {
let fctx = @mut FontContext::new(opts.render_backend, true);

Layout {
render_task: render_task,
image_cache_task: image_cache_task.clone(),
local_image_cache: @mut LocalImageCache(image_cache_task),
from_script: from_script,
font_ctx: fctx,

layout_refs: ~[],

css_select_ctx: @mut new_css_select_ctx(),
profiler_chan: profiler_chan
}
}

fn start(&mut self) {
while self.handle_request() {
// loop indefinitely
// Loop indefinitely.
}
}

fn handle_request(&mut self) -> bool {

match self.from_script.recv() {
AddStylesheet(sheet) => {
self.handle_add_stylesheet(sheet);
}
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
BuildMsg(data) => {
let data = Cell(data);

do profile(time::LayoutPerformCategory, self.prof_chan.clone()) {
self.handle_build(data.take());
}

}
QueryMsg(query, chan) => {
let chan = Cell(chan);
@@ -281,9 +237,9 @@ impl Layout {

/// 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>) {
fn handle_query(&self, query: LayoutQuery, reply_chan: Chan<Result<LayoutResponse,()>>) {
match query {
ContentBox(node) => {
ContentBoxQuery(node) => {
// FIXME: Isolate this transmutation into a single "bridge" module.
let node: AbstractNode<LayoutView> = unsafe {
transmute(node)
@@ -308,14 +264,14 @@ impl Layout {
error!("no boxes for node");
Err(())
}
Some(rect) => Ok(ContentRect(rect))
Some(rect) => Ok(ContentBoxResponse(rect))
}
}
};

reply_chan.send(response)
}
ContentBoxes(node) => {
ContentBoxesQuery(node) => {
// FIXME: Isolate this transmutation into a single "bridge" module.
let node: AbstractNode<LayoutView> = unsafe {
transmute(node)
@@ -329,7 +285,7 @@ impl Layout {
boxes.push(box.content_box());
}

Ok(ContentRects(boxes))
Ok(ContentBoxesResponse(boxes))
}
};

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.