diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/main/dom/bindings/element.rs | 6 | ||||
-rw-r--r-- | src/components/main/dom/element.rs | 22 | ||||
-rw-r--r-- | src/components/main/dom/window.rs | 2 | ||||
-rw-r--r-- | src/components/main/engine.rs | 14 | ||||
-rw-r--r-- | src/components/main/layout/layout_task.rs | 160 | ||||
-rw-r--r-- | src/components/main/layout_interface.rs | 103 | ||||
-rw-r--r-- | src/components/main/scripting/script_task.rs | 19 | ||||
-rwxr-xr-x | src/components/main/servo.rc | 1 |
8 files changed, 193 insertions, 134 deletions
diff --git a/src/components/main/dom/bindings/element.rs b/src/components/main/dom/bindings/element.rs index 66d47931f73..11930321136 100644 --- a/src/components/main/dom/bindings/element.rs +++ b/src/components/main/dom/bindings/element.rs @@ -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") } } diff --git a/src/components/main/dom/element.rs b/src/components/main/dom/element.rs index e3a5e59dae3..742fdb46682 100644 --- a/src/components/main/dom/element.rs +++ b/src/components/main/dom/element.rs @@ -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(), diff --git a/src/components/main/dom/window.rs b/src/components/main/dom/window.rs index c7eaacd7f31..439dca0fd79 100644 --- a/src/components/main/dom/window.rs +++ b/src/components/main/dom/window.rs @@ -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}; diff --git a/src/components/main/engine.rs b/src/components/main/engine.rs index 575fbc57bbf..c26686262d4 100644 --- a/src/components/main/engine.rs +++ b/src/components/main/engine.rs @@ -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; @@ -18,7 +19,6 @@ use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; use servo_net::resource_task::ResourceTask; use servo_net::resource_task; use servo_util::time::{ProfilerChan, ProfilerPort, ProfilerTask}; -use servo_util::time; use std::net::url::Url; pub type EngineTask = Chan<Msg>; @@ -61,10 +61,10 @@ impl Engine { let profiler_task = ProfilerTask::new(profiler_port.take(), 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 +105,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(); diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 5da211854bf..d23d377e244 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -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,128 +44,80 @@ 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, + profiler_chan: ProfilerChan) + -> LayoutTask { + let chan = do spawn_listener::<Msg> |from_script| { + let mut layout = Layout::new(render_task.clone(), + img_cache_task.clone(), + from_script, + &opts, + profiler_chan.clone()); + 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() - } + css_select_ctx: @mut SelectCtx, + 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, profiler_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(), + 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()) { + do profile(time::LayoutPerformCategory, self.profiler_chan.clone()) { self.handle_build(data.take()); } - } QueryMsg(query, chan) => { let chan = Cell(chan); - do profile(time::LayoutQueryCategory, self.prof_chan.clone()) { + do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) { self.handle_query(query, chan.take()) } } @@ -212,7 +168,7 @@ impl Layout { // Initialize layout data for each node. // // FIXME: This is inefficient. We don't need an entire traversal to do this! - do profile(time::LayoutAuxInitCategory, self.prof_chan.clone()) { + do profile(time::LayoutAuxInitCategory, self.profiler_chan.clone()) { node.initialize_style_for_subtree(&mut self.layout_refs); } @@ -220,7 +176,7 @@ impl Layout { match data.damage { NoDamage | ReflowDamage => {} MatchSelectorsDamage => { - do profile(time::LayoutSelectorMatchCategory, self.prof_chan.clone()) { + do profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone()) { node.restyle_subtree(self.css_select_ctx); } } @@ -228,7 +184,7 @@ impl Layout { // Construct the flow tree. let layout_root: FlowContext = do profile(time::LayoutTreeBuilderCategory, - self.prof_chan.clone()) { + self.profiler_chan.clone()) { let mut builder = LayoutTreeBuilder::new(); let layout_root: FlowContext = match builder.construct_trees(&layout_ctx, *node) { Ok(root) => root, @@ -243,7 +199,7 @@ impl Layout { // Perform the primary layout passes over the flow tree to compute the locations of all // the boxes. - do profile(time::LayoutMainCategory, self.prof_chan.clone()) { + do profile(time::LayoutMainCategory, self.profiler_chan.clone()) { for layout_root.traverse_postorder |flow| { flow.bubble_widths(&mut layout_ctx); }; @@ -256,7 +212,7 @@ impl Layout { } // Build the display list, and send it to the renderer. - do profile(time::LayoutDispListBuildCategory, self.prof_chan.clone()) { + do profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone()) { let builder = DisplayListBuilder { ctx: &layout_ctx, }; @@ -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)) } }; diff --git a/src/components/main/layout_interface.rs b/src/components/main/layout_interface.rs new file mode 100644 index 00000000000..fc99bb3dcab --- /dev/null +++ b/src/components/main/layout_interface.rs @@ -0,0 +1,103 @@ +/* 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/. */ + +//! The high-level interface from script to layout. Using this abstract interface helps reduce +/// coupling between these two components, and enables the DOM to be placed in a separate crate +/// from layout. + +use dom::node::{AbstractNode, ScriptView}; +use scripting::script_task::ScriptMsg; + +use core::comm::{Chan, SharedChan}; +use geom::rect::Rect; +use geom::size::Size2D; +use gfx::geometry::Au; +use newcss::stylesheet::Stylesheet; +use std::net::url::Url; + +/// Asynchronous messages that script can send to layout. +/// +/// FIXME(pcwalton): I think this should probably be merged with `LayoutQuery` below. +pub enum Msg { + /// Adds the given stylesheet to the document. + AddStylesheetMsg(Stylesheet), + + /// Requests a reflow. + /// + /// FIXME(pcwalton): Call this `reflow` instead? + BuildMsg(~BuildData), + + /// Performs a synchronous layout request. + /// + /// FIXME(pcwalton): As noted below, this isn't very type safe. + QueryMsg(LayoutQuery, Chan<Result<LayoutResponse,()>>), + + /// Requests that the layout task shut down and exit. + ExitMsg, +} + +/// Synchronous messages that script can send to layout. +pub enum LayoutQuery { + /// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call. + ContentBoxQuery(AbstractNode<ScriptView>), + /// Requests the dimensions of all the content boxes, as in the `getClientRects()` call. + ContentBoxesQuery(AbstractNode<ScriptView>), +} + +/// The reply of a synchronous message from script to layout. +/// +/// FIXME(pcwalton): This isn't very type safe. Maybe `LayoutQuery` objects should include +/// response channels? +pub enum LayoutResponse { + /// A response to the `ContentBoxQuery` message. + ContentBoxResponse(Rect<Au>), + /// A response to the `ContentBoxesQuery` message. + ContentBoxesResponse(~[Rect<Au>]), +} + +/// Dirty bits for layout. +pub enum Damage { + /// The document is clean; nothing needs to be done. + NoDamage, + /// Reflow, but do not perform CSS selector matching. + ReflowDamage, + /// Perform CSS selector matching and reflow. + MatchSelectorsDamage, +} + +impl Damage { + /// Sets this damage to the maximum of this damage and the given damage. + /// + /// FIXME(pcwalton): This could be refactored to use `max` and the `Ord` trait, and this + /// function removed. + 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 + } + } +} + +/// Information needed for a reflow. +pub struct BuildData { + node: AbstractNode<ScriptView>, + /// What reflow needs to be done. + damage: Damage, + /// The URL of the page. + url: Url, + /// The channel through which messages can be sent back to the script task. + script_chan: SharedChan<ScriptMsg>, + /// The current window size. + window_size: Size2D<uint>, + script_join_chan: Chan<()>, +} + +/// Encapsulates a channel to the layout task. +#[deriving(Clone)] +pub struct LayoutTask { + chan: SharedChan<Msg>, +} + diff --git a/src/components/main/scripting/script_task.rs b/src/components/main/scripting/script_task.rs index fb01adef9b7..cf99428c677 100644 --- a/src/components/main/scripting/script_task.rs +++ b/src/components/main/scripting/script_task.rs @@ -10,10 +10,10 @@ use dom::document::Document; use dom::event::{Event, ResizeEvent, ReflowEvent}; use dom::node::define_bindings; use dom::window::Window; -use layout::layout_task::{AddStylesheet, BuildData, BuildMsg, Damage, LayoutQuery}; -use layout::layout_task::{LayoutQueryResponse, LayoutTask, MatchSelectorsDamage, NoDamage}; -use layout::layout_task::{QueryMsg, ReflowDamage}; -use layout::layout_task; +use layout_interface::{AddStylesheetMsg, BuildData, BuildMsg, Damage, LayoutQuery}; +use layout_interface::{LayoutResponse, LayoutTask, MatchSelectorsDamage, NoDamage}; +use layout_interface::{QueryMsg, ReflowDamage}; +use layout_interface; use core::cast::transmute; use core::cell::Cell; @@ -292,7 +292,8 @@ impl ScriptContext { for self.root_frame.each |frame| { frame.document.teardown(); } - self.layout_task.send(layout_task::ExitMsg) + + self.layout_task.chan.send(layout_interface::ExitMsg) } /// The entry point to document loading. Defines bindings, sets up the window and document @@ -321,7 +322,7 @@ impl ScriptContext { // in the script task. loop { match html_parsing_result.style_port.recv() { - Some(sheet) => self.layout_task.send(AddStylesheet(sheet)), + Some(sheet) => self.layout_task.chan.send(AddStylesheetMsg(sheet)), None => break, } } @@ -416,7 +417,7 @@ impl ScriptContext { damage: replace(&mut self.damage, NoDamage), }; - self.layout_task.send(BuildMsg(data)) + self.layout_task.chan.send(BuildMsg(data)) } } @@ -424,11 +425,11 @@ impl ScriptContext { } /// Sends the given query to layout. - pub fn query_layout(&mut self, query: LayoutQuery) -> LayoutQueryResponse { + pub fn query_layout(&mut self, query: LayoutQuery) -> Result<LayoutResponse,()> { self.join_layout(); let (response_port, response_chan) = comm::stream(); - self.layout_task.send(QueryMsg(query, response_chan)); + self.layout_task.chan.send(QueryMsg(query, response_chan)); response_port.recv() } diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc index e4526bacf23..94692bfddfc 100755 --- a/src/components/main/servo.rc +++ b/src/components/main/servo.rc @@ -121,6 +121,7 @@ pub mod html { pub mod hubbub_html_parser; } +pub mod layout_interface; pub mod windowing; #[path="platform/mod.rs"] |