From fdde75eb47886601abd5c417d4ba316a2d88320c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 May 2013 15:30:28 -0700 Subject: [PATCH 1/7] Rename "osmain" to "compositing" --- .../resize_rate_limiter.rs | 0 src/servo/platform/base.rs | 5 - src/servo/platform/osmain.rs | 367 ------------------ src/servo/servo.rc | 13 +- 4 files changed, 5 insertions(+), 380 deletions(-) rename src/servo/{platform => compositing}/resize_rate_limiter.rs (100%) delete mode 100644 src/servo/platform/base.rs delete mode 100644 src/servo/platform/osmain.rs diff --git a/src/servo/platform/resize_rate_limiter.rs b/src/servo/compositing/resize_rate_limiter.rs similarity index 100% rename from src/servo/platform/resize_rate_limiter.rs rename to src/servo/compositing/resize_rate_limiter.rs diff --git a/src/servo/platform/base.rs b/src/servo/platform/base.rs deleted file mode 100644 index 2daeb35126c..00000000000 --- a/src/servo/platform/base.rs +++ /dev/null @@ -1,5 +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/. */ - - diff --git a/src/servo/platform/osmain.rs b/src/servo/platform/osmain.rs deleted file mode 100644 index 16485a8f0d0..00000000000 --- a/src/servo/platform/osmain.rs +++ /dev/null @@ -1,367 +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 ShareGlContext = sharegl::platform::Context; -use dom::event::Event; -use platform::resize_rate_limiter::ResizeRateLimiter; - -use azure::azure_hl::{BackendType, B8G8R8A8, DataSourceSurface, DrawTarget, SourceSurfaceMethods}; -use core::comm::{Chan, SharedChan, Port}; -use core::util; -use geom::matrix::identity; -use geom::point::Point2D; -use geom::rect::Rect; -use geom::size::Size2D; -use gfx::compositor::{Compositor, LayerBuffer, LayerBufferSet}; -use gfx::opts::Opts; -use servo_util::time; -use core::cell::Cell; -use glut::glut; -use layers; -use sharegl; -use sharegl::ShareGlContext; -use sharegl::base::ShareContext; - -pub struct OSMain { - chan: SharedChan -} - -impl Clone for OSMain { - fn clone(&self) -> OSMain { - OSMain { - chan: self.chan.clone() - } - } -} - -// FIXME: Move me over to opts.rs. -enum Mode { - GlutMode, - ShareMode -} - -enum Window { - GlutWindow(glut::Window), - ShareWindow(ShareGlContext) -} - -pub enum Msg { - BeginDrawing(comm::Chan), - Draw(comm::Chan, LayerBufferSet), - AddKeyHandler(comm::Chan<()>), - Exit -} - -pub fn OSMain(dom_event_chan: comm::SharedChan, opts: Opts) -> OSMain { - let dom_event_chan = Cell(dom_event_chan); - OSMain { - chan: SharedChan::new(on_osmain::(|po| { - let po = Cell(po); - do platform::runmain { - debug!("preparing to enter main loop"); - - // FIXME: Use the servo options. - let mode; - match os::getenv("SERVO_SHARE") { - Some(_) => mode = ShareMode, - None => mode = GlutMode - } - - mainloop(mode, po.take(), dom_event_chan.take(), &opts); - } - })) - } -} - -/// Azure surface wrapping to work with the layers infrastructure. -struct AzureDrawTargetImageData { - draw_target: DrawTarget, - data_source_surface: DataSourceSurface, - size: Size2D -} - -impl layers::layers::ImageData for AzureDrawTargetImageData { - fn size(&self) -> Size2D { self.size } - fn stride(&self) -> uint { self.data_source_surface.stride() as uint } - fn format(&self) -> layers::layers::Format { - // FIXME: This is not always correct. We should query the Azure draw target for the format. - layers::layers::ARGB32Format - } - fn with_data(&self, f: layers::layers::WithDataFn) { - do self.data_source_surface.with_data |data| { - f(data); - } - } -} - -fn mainloop(mode: Mode, - po: Port, - dom_event_chan: SharedChan, - opts: &Opts) { - let key_handlers: @mut ~[Chan<()>] = @mut ~[]; - - let window; - match mode { - GlutMode => { - glut::init(); - glut::init_display_mode(glut::DOUBLE); - let glut_window = glut::create_window(~"Servo"); - glut::reshape_window(glut_window, 800, 600); - window = GlutWindow(glut_window); - } - ShareMode => { - let size = Size2D(800, 600); - let share_context: ShareGlContext = sharegl::base::ShareContext::new(size); - io::println(fmt!("Sharing ID is %d", share_context.id())); - window = ShareWindow(share_context); - } - } - - let surfaces = @mut SurfaceSet(opts.render_backend); - - let context = layers::rendergl::init_render_context(); - - let root_layer = @mut layers::layers::ContainerLayer(); - let original_layer_transform; - { - let image_data = @layers::layers::BasicImageData::new(Size2D(0u, 0u), - 0, - layers::layers::RGB24Format, - ~[]); - let image = @mut layers::layers::Image::new(image_data as @layers::layers::ImageData); - let image_layer = @mut layers::layers::ImageLayer(image); - original_layer_transform = image_layer.common.transform; - image_layer.common.set_transform(original_layer_transform.scale(800.0, 600.0, 1.0)); - root_layer.add_child(layers::layers::ImageLayerKind(image_layer)); - } - - - let scene = @layers::scene::Scene(layers::layers::ContainerLayerKind(root_layer), - Size2D(800.0, 600.0), - identity()); - - let done = @mut false; - let resize_rate_limiter = @mut ResizeRateLimiter(dom_event_chan); - let check_for_messages: @fn() = || { - - // Periodically check if content responded to our last resize event - resize_rate_limiter.check_resize_response(); - - // Handle messages - //#debug("osmain: peeking"); - while po.peek() { - match po.recv() { - AddKeyHandler(key_ch) => key_handlers.push(key_ch), - BeginDrawing(sender) => lend_surface(surfaces, sender), - Draw(sender, draw_target) => { - debug!("osmain: received new frame"); - return_surface(surfaces, draw_target); - lend_surface(surfaces, sender); - - // Iterate over the children of the container layer. - let mut current_layer_child = root_layer.first_child; - - // Replace the image layer data with the buffer data. - let buffers = util::replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]); - for buffers.each |buffer| { - let width = buffer.rect.size.width as uint; - let height = buffer.rect.size.height as uint; - - debug!("osmain: compositing buffer rect %?", &buffer.rect); - - let image_data = @AzureDrawTargetImageData { - draw_target: buffer.draw_target.clone(), - data_source_surface: buffer.draw_target.snapshot().get_data_surface(), - size: Size2D(width, height) - }; - let image = @mut layers::layers::Image::new(image_data as @layers::layers::ImageData); - - // Find or create an image layer. - let image_layer; - current_layer_child = match current_layer_child { - None => { - debug!("osmain: adding new image layer"); - image_layer = @mut layers::layers::ImageLayer(image); - root_layer.add_child(layers::layers::ImageLayerKind(image_layer)); - None - } - Some(layers::layers::ImageLayerKind(existing_image_layer)) => { - image_layer = existing_image_layer; - image_layer.set_image(image); - - // Move on to the next sibling. - do current_layer_child.get().with_common |common| { - common.next_sibling - } - } - Some(_) => { - fail!(~"found unexpected layer kind") - } - }; - - // Set the layer's transform. - let x = buffer.rect.origin.x as f32; - let y = buffer.rect.origin.y as f32; - image_layer.common.set_transform( - original_layer_transform.translate(x, y, 0.0) - .scale(width as f32, height as f32, 1.0)); - } - surfaces.front.layer_buffer_set.buffers = buffers; - } - Exit => { - *done = true; - } - } - } - }; - - let adjust_for_window_resizing: @fn() = || { - let window_width = glut::get(glut::WindowWidth) as uint; - let window_height = glut::get(glut::WindowHeight) as uint; - - // FIXME: Cross-crate struct mutability is broken. - let size: &mut Size2D; - unsafe { size = cast::transmute(&scene.size); } - *size = Size2D(window_width as f32, window_height as f32); - }; - - let composite: @fn() = || { - //#debug("osmain: drawing to screen"); - - do time::time(~"compositing") { - adjust_for_window_resizing(); - layers::rendergl::render_scene(context, scene); - } - - glut::swap_buffers(); - glut::post_redisplay(); - }; - - match window { - GlutWindow(window) => { - do glut::reshape_func(window) |width, height| { - debug!("osmain: window resized to %d,%d", width as int, height as int); - check_for_messages(); - resize_rate_limiter.window_resized(width as uint, height as uint); - //composite(); - } - - do glut::display_func() { - //debug!("osmain: display func"); - check_for_messages(); - composite(); - } - - while !*done { - //#debug("osmain: running GLUT check loop"); - glut::check_loop(); - } - } - ShareWindow(share_context) => { - loop { - check_for_messages(); - do time::time(~"compositing") { - layers::rendergl::render_scene(context, scene); - } - - share_context.flush(); - } - } - } -} - -/** -Implementation to allow the osmain channel to be used as a graphics -compositor for the renderer -*/ -impl Compositor for OSMain { - fn begin_drawing(&self, next_dt: comm::Chan) { - self.chan.send(BeginDrawing(next_dt)) - } - fn draw(&self, next_dt: comm::Chan, draw_me: LayerBufferSet) { - self.chan.send(Draw(next_dt, draw_me)) - } -} - -struct SurfaceSet { - front: Surface, - back: Surface, -} - -fn lend_surface(surfaces: &mut SurfaceSet, receiver: comm::Chan) { - // We are in a position to lend out the surface? - assert!(surfaces.front.have); - // Ok then take it - let old_layer_buffers = util::replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]); - let new_layer_buffers = do old_layer_buffers.map |layer_buffer| { - let draw_target_ref = &layer_buffer.draw_target; - let layer_buffer = LayerBuffer { - draw_target: draw_target_ref.clone(), - rect: copy layer_buffer.rect, - stride: layer_buffer.stride - }; - debug!("osmain: lending surface %?", layer_buffer); - layer_buffer - }; - surfaces.front.layer_buffer_set.buffers = old_layer_buffers; - - let new_layer_buffer_set = LayerBufferSet { buffers: new_layer_buffers }; - receiver.send(new_layer_buffer_set); - // Now we don't have it - surfaces.front.have = false; - // But we (hopefully) have another! - surfaces.front <-> surfaces.back; - // Let's look - assert!(surfaces.front.have); -} - -fn return_surface(surfaces: &mut SurfaceSet, layer_buffer_set: LayerBufferSet) { - //#debug("osmain: returning surface %?", layer_buffer_set); - // We have room for a return - assert!(surfaces.front.have); - assert!(!surfaces.back.have); - - surfaces.back.layer_buffer_set = layer_buffer_set; - - // Now we have it again - surfaces.back.have = true; -} - -fn SurfaceSet(backend: BackendType) -> SurfaceSet { - SurfaceSet { front: Surface(backend), back: Surface(backend) } -} - -struct Surface { - layer_buffer_set: LayerBufferSet, - have: bool, -} - -fn Surface(backend: BackendType) -> Surface { - let layer_buffer = LayerBuffer { - draw_target: DrawTarget::new(backend, Size2D(800i32, 600i32), B8G8R8A8), - rect: Rect(Point2D(0u, 0u), Size2D(800u, 600u)), - stride: 800 * 4 - }; - let layer_buffer_set = LayerBufferSet { buffers: ~[ layer_buffer ] }; - Surface { layer_buffer_set: layer_buffer_set, have: true } -} - -/// A function for spawning into the platform's main thread -fn on_osmain(f: ~fn(po: Port)) -> Chan { - let (setup_po, setup_ch) = comm::stream(); - do task::task().sched_mode(task::PlatformThread).spawn { - let (po, ch) = comm::stream(); - setup_ch.send(ch); - f(po); - } - setup_po.recv() -} - -// #[cfg(target_os = "linux")] -mod platform { - pub fn runmain(f: &fn()) { - f() - } -} - diff --git a/src/servo/servo.rc b/src/servo/servo.rc index d2d749d8c70..b7ba8307b98 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -33,8 +33,8 @@ extern mod core_graphics; #[cfg(target_os="macos")] extern mod core_text; +use compositing::{AddKeyHandler, OSMain}; use engine::{Engine, LoadURLMsg}; -use platform::osmain::{AddKeyHandler, OSMain}; pub use gfx::opts::{Opts, Png, Screen}; // FIXME: Do we really want "Screen" and "Png" visible? pub use gfx::resource; @@ -43,6 +43,9 @@ pub use gfx::resource::resource_task::ResourceTask; pub use gfx::text; pub use servo_util::url::make_url; +#[path="compositing/mod.rs"] +pub mod compositing; + pub mod content { pub mod content_task; } @@ -112,12 +115,6 @@ pub mod html { pub mod hubbub_html_parser; } -pub mod platform { - pub mod base; - pub mod osmain; - priv mod resize_rate_limiter; -} - #[path = "util/mod.rs"] pub mod util; @@ -179,7 +176,7 @@ fn run_pipeline_screen(opts: &Opts) { engine_task.send(engine::ExitMsg(exit_chan)); exit_response_from_engine.recv(); - osmain.chan.send(platform::osmain::Exit); + osmain.chan.send(compositing::Exit); } fn run_pipeline_png(_opts: &Opts, _outfile: &str) { From 7e933b74641f48b6fd531e58f36519821406cd54 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 May 2013 17:55:10 -0700 Subject: [PATCH 2/7] Separate out windowing from compositing --- src/servo/platform/common/glut_windowing.rs | 92 +++++++++++++++++++ .../platform/common/shared_gl_windowing.rs | 59 ++++++++++++ src/servo/platform/mod.rs | 18 ++++ src/servo/servo.rc | 3 + 4 files changed, 172 insertions(+) create mode 100644 src/servo/platform/common/glut_windowing.rs create mode 100644 src/servo/platform/common/shared_gl_windowing.rs create mode 100644 src/servo/platform/mod.rs diff --git a/src/servo/platform/common/glut_windowing.rs b/src/servo/platform/common/glut_windowing.rs new file mode 100644 index 00000000000..4aa02260d6c --- /dev/null +++ b/src/servo/platform/common/glut_windowing.rs @@ -0,0 +1,92 @@ +/* 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/. */ + +//! A windowing implementation using GLUT. +/// +/// GLUT is a very old and bare-bones toolkit. However, it has good cross-platform support, at +/// least on desktops. It is designed for testing Servo without the need of a UI. + +use compositing::{CompositeCallback, ResizeCallback}; + +use geom::size::Size2D; +use glut::glut::{DOUBLE, WindowHeight, WindowWidth}; +use glut::glut; + +/// A structure responsible for setting up and tearing down the entire windowing system. +pub struct Application; + +impl Application { + pub fn new() -> Application { + glut::init(); + glut::init_display_mode(DOUBLE); + Application + } +} + +/// The type of a window. +pub struct Window { + glut_window: glut::Window, + composite_callback: Option, + resize_callback: Option, +} + +impl Window { + /// Creates a new window. + pub fn new(_: &Application) -> @mut Window { + // Create the GLUT window. + let glut_window = glut::create_window(~"Servo"); + glut::reshape_window(glut_window, 800, 600); + + // Create our window object. + let window = @mut Window { + glut_window: glut_window, + composite_callback: None, + resize_callback: None, + }; + + // Register event handlers. + do glut::reshape_func(window.glut_window) |width, height| { + match window.resize_callback { + None => {} + Some(callback) => callback(width as uint, height as uint), + } + }; + do glut::display_func { + // FIXME(pcwalton): This will not work with multiple windows. + match window.composite_callback { + None => {} + Some(callback) => callback(), + } + }; + + window + } + + /// Returns the size of the window. + pub fn size(&mut self) -> Size2D { + Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32) + } + + /// Presents the window to the screen (perhaps by page flipping). + pub fn present(&mut self) { + glut::swap_buffers(); + glut::post_redisplay(); + } + + /// Registers a callback to run when a composite event occurs. + pub fn set_composite_callback(&mut self, new_composite_callback: CompositeCallback) { + self.composite_callback = Some(new_composite_callback) + } + + /// Registers a callback to run when a resize event occurs. + pub fn set_resize_callback(&mut self, new_resize_callback: ResizeCallback) { + self.resize_callback = Some(new_resize_callback) + } + + /// Spins the event loop. + pub fn check_loop(@mut self) { + glut::check_loop() + } +} + diff --git a/src/servo/platform/common/shared_gl_windowing.rs b/src/servo/platform/common/shared_gl_windowing.rs new file mode 100644 index 00000000000..dda49e5c136 --- /dev/null +++ b/src/servo/platform/common/shared_gl_windowing.rs @@ -0,0 +1,59 @@ +/* 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/. */ + +//! A windowing implementation using shared OpenGL textures. +/// +/// In this setup, Servo renders to an OpenGL texture and uses IPC to share that texture with +/// another application. It also uses IPC to handle events. +/// +/// This is designed for sandboxing scenarios which the OpenGL graphics driver is either sandboxed +/// along with the Servo process or trusted. If the OpenGL driver itself is untrusted, then this +/// windowing implementation is not appropriate. + +use compositing::{CompositeCallback, ResizeCallback}; + +use geom::size::Size2D; +use sharegl::base::ShareContext; +use sharegl::platform::Context; + +/// A structure responsible for setting up and tearing down the entire windowing system. +pub struct Application; + +impl Application { + pub fn new() -> Application { + Application + } +} + +/// The type of a window. +pub struct Window(Context); + +impl Window { + /// Creates a new window. + pub fn new(_: &Application) -> @mut Window { + let share_context: Context = ShareContext::new(Size2D(800, 600)); + println(fmt!("Sharing ID is %d", share_context.id())); + @mut Window(share_context) + } + + /// Returns the size of the window. + pub fn size(&mut self) -> Size2D { + Size2D(800.0, 600.0) + } + + /// Presents the window to the screen (perhaps by page flipping). + pub fn present(&mut self) { + (*self).flush(); + } + + /// Registers a callback to run when a composite event occurs. + pub fn set_composite_callback(&mut self, _: CompositeCallback) {} + + /// Registers a callback to run when a resize event occurs. + pub fn set_resize_callback(&mut self, _: ResizeCallback) {} + + /// Returns the next event. + pub fn check_loop(@mut self) {} +} + diff --git a/src/servo/platform/mod.rs b/src/servo/platform/mod.rs new file mode 100644 index 00000000000..fdbd3bf42d9 --- /dev/null +++ b/src/servo/platform/mod.rs @@ -0,0 +1,18 @@ +/* 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/. */ + +//! Platform-specific functionality for Servo. + +#[cfg(not(shared_gl_windowing))] +pub use platform::common::glut_windowing::{Application, Window}; +#[cfg(shared_gl_windowing)] +pub use platform::common::shared_gl_windowing::{Application, Window}; + +pub mod common { + #[cfg(not(shared_gl_windowing))] + pub mod glut_windowing; + #[cfg(shared_gl_windowing)] + pub mod shared_gl_windowing; +} + diff --git a/src/servo/servo.rc b/src/servo/servo.rc index b7ba8307b98..6e466cb769f 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -115,6 +115,9 @@ pub mod html { pub mod hubbub_html_parser; } +#[path="platform/mod.rs"] +pub mod platform; + #[path = "util/mod.rs"] pub mod util; From 0a6b537c5fa92461ec9266f87b6082f0832ef6c4 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 9 May 2013 11:42:24 -0700 Subject: [PATCH 3/7] servo: Remove the type parameter from the compositor, rename OSMain, and refactor engine a bit --- src/servo-gfx/compositor.rs | 6 +- src/servo/engine.rs | 108 +++++++++++++++++++----------------- src/servo/servo.rc | 30 +++++----- 3 files changed, 73 insertions(+), 71 deletions(-) diff --git a/src/servo-gfx/compositor.rs b/src/servo-gfx/compositor.rs index 0527b30a6b7..e7fbdf74e7f 100644 --- a/src/servo-gfx/compositor.rs +++ b/src/servo-gfx/compositor.rs @@ -21,10 +21,8 @@ pub struct LayerBufferSet { buffers: ~[LayerBuffer] } -/** -The interface used to by the renderer to aquire draw targets for -each rendered frame and submit them to be drawn to the display -*/ +/// The interface used to by the renderer to acquire draw targets for each rendered frame and +/// submit them to be drawn to the display. pub trait Compositor { fn begin_drawing(&self, next_dt: comm::Chan); fn draw(&self, next_dt: comm::Chan, +draw_me: LayerBufferSet); diff --git a/src/servo/engine.rs b/src/servo/engine.rs index 5dd02f6d310..dc693e7e2a0 100644 --- a/src/servo/engine.rs +++ b/src/servo/engine.rs @@ -2,6 +2,7 @@ * 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 compositing::CompositorImpl; use content::content_task::{ContentTask, ExecuteMsg, ParseMsg}; use content::content_task; use dom::event::Event; @@ -13,7 +14,7 @@ use resource::resource_task; use util::task::spawn_listener; use core::cell::Cell; -use core::comm::{Port, Chan}; +use core::comm::{Chan, Port, SharedChan}; use gfx::compositor::Compositor; use gfx::opts::Opts; use gfx::render_task::RenderTask; @@ -23,13 +24,13 @@ use std::net::url::Url; pub type EngineTask = Chan; pub enum Msg { - LoadURLMsg(Url), + LoadUrlMsg(Url), ExitMsg(Chan<()>) } -pub struct Engine { +pub struct Engine { request_port: Port, - compositor: C, + compositor: CompositorImpl, render_task: RenderTask, resource_task: ResourceTask, image_cache_task: ImageCacheTask, @@ -37,39 +38,42 @@ pub struct Engine { content_task: ContentTask } -pub fn Engine(compositor: C, - opts: &Opts, - dom_event_port: comm::Port, - dom_event_chan: comm::SharedChan, - resource_task: ResourceTask, - image_cache_task: ImageCacheTask) - -> EngineTask { - let dom_event_port = Cell(dom_event_port); - let dom_event_chan = Cell(dom_event_chan); +impl Engine { + pub fn start(compositor: CompositorImpl, + opts: &Opts, + dom_event_port: Port, + dom_event_chan: SharedChan, + resource_task: ResourceTask, + image_cache_task: ImageCacheTask) + -> EngineTask { + let dom_event_port = Cell(dom_event_port); + let dom_event_chan = Cell(dom_event_chan); - let opts = Cell(copy *opts); - do spawn_listener:: |request| { - let render_task = RenderTask(compositor.clone(), opts.with_ref(|o| copy *o)); - let layout_task = LayoutTask(render_task.clone(), image_cache_task.clone(), opts.take()); - let content_task = ContentTask(layout_task.clone(), - dom_event_port.take(), - dom_event_chan.take(), - resource_task.clone(), - image_cache_task.clone()); + let opts = Cell(copy *opts); + do spawn_listener:: |request| { + let render_task = RenderTask(compositor.clone(), opts.with_ref(|o| copy *o)); - Engine { - request_port: request, - compositor: compositor.clone(), - render_task: render_task, - resource_task: resource_task.clone(), - image_cache_task: image_cache_task.clone(), - layout_task: layout_task, - content_task: content_task - }.run(); + let opts = opts.take(); + let layout_task = LayoutTask(render_task.clone(), image_cache_task.clone(), opts); + + let content_task = ContentTask(layout_task.clone(), + dom_event_port.take(), + dom_event_chan.take(), + resource_task.clone(), + image_cache_task.clone()); + + Engine { + request_port: request, + compositor: compositor.clone(), + render_task: render_task, + resource_task: resource_task.clone(), + image_cache_task: image_cache_task.clone(), + layout_task: layout_task, + content_task: content_task, + }.run() + } } -} -impl Engine { fn run(&self) { while self.handle_request(self.request_port.recv()) { // Go on... @@ -78,30 +82,30 @@ impl Engine { fn handle_request(&self, request: Msg) -> bool { match request { - LoadURLMsg(url) => { - if url.path.ends_with(".js") { - self.content_task.send(ExecuteMsg(url)) - } else { - self.content_task.send(ParseMsg(url)) + LoadUrlMsg(url) => { + if url.path.ends_with(".js") { + self.content_task.send(ExecuteMsg(url)) + } else { + self.content_task.send(ParseMsg(url)) + } + return true } - return true; - } - ExitMsg(sender) => { - self.content_task.send(content_task::ExitMsg); - self.layout_task.send(layout_task::ExitMsg); - - let (response_port, response_chan) = comm::stream(); + ExitMsg(sender) => { + self.content_task.send(content_task::ExitMsg); + self.layout_task.send(layout_task::ExitMsg); - self.render_task.send(render_task::ExitMsg(response_chan)); - response_port.recv(); + let (response_port, response_chan) = comm::stream(); - self.image_cache_task.exit(); - self.resource_task.send(resource_task::Exit); + self.render_task.send(render_task::ExitMsg(response_chan)); + response_port.recv(); - sender.send(()); - return false; - } + self.image_cache_task.exit(); + self.resource_task.send(resource_task::Exit); + + sender.send(()); + return false + } } } } diff --git a/src/servo/servo.rc b/src/servo/servo.rc index 6e466cb769f..e396341138c 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -33,8 +33,8 @@ extern mod core_graphics; #[cfg(target_os="macos")] extern mod core_text; -use compositing::{AddKeyHandler, OSMain}; -use engine::{Engine, LoadURLMsg}; +use compositing::{AddKeyHandler, CompositorImpl}; +use engine::{Engine, LoadUrlMsg}; pub use gfx::opts::{Opts, Png, Screen}; // FIXME: Do we really want "Screen" and "Png" visible? pub use gfx::resource; @@ -145,29 +145,29 @@ fn run_pipeline_screen(opts: &Opts) { let dom_event_chan = comm::SharedChan::new(dom_event_chan); // The platform event handler thread - let osmain = OSMain(dom_event_chan.clone(), copy *opts); + let compositor = CompositorImpl::new(dom_event_chan.clone(), copy *opts); // Send each file to render then wait for keypress - let (keypress_from_osmain, keypress_to_engine) = comm::stream(); - osmain.chan.send(AddKeyHandler(keypress_to_engine)); + let (keypress_from_compositor, keypress_to_engine) = comm::stream(); + compositor.chan.send(AddKeyHandler(keypress_to_engine)); // Create a servo instance let resource_task = ResourceTask(); let image_cache_task = ImageCacheTask(resource_task.clone()); - let engine_task = Engine(osmain.clone(), - opts, - dom_event_port, - dom_event_chan, - resource_task, - image_cache_task); + let engine_task = Engine::start(compositor.clone(), + opts, + dom_event_port, + dom_event_chan, + resource_task, + image_cache_task); for opts.urls.each |filename| { let url = make_url(copy *filename, None); debug!("master: Sending url `%s`", url.to_str()); - engine_task.send(LoadURLMsg(url)); + engine_task.send(LoadUrlMsg(url)); debug!("master: Waiting for keypress"); - match keypress_from_osmain.try_recv() { + match keypress_from_compositor.try_recv() { Some(*) => { } None => { error!("keypress stream closed unexpectedly") } }; @@ -179,7 +179,7 @@ fn run_pipeline_screen(opts: &Opts) { engine_task.send(engine::ExitMsg(exit_chan)); exit_response_from_engine.recv(); - osmain.chan.send(compositing::Exit); + compositor.chan.send(compositing::Exit); } fn run_pipeline_png(_opts: &Opts, _outfile: &str) { @@ -209,7 +209,7 @@ fn run_pipeline_png(url: ~str, outfile: &str) { dom_event_chan, resource_task, image_cache_task); - engine_task.send(LoadURLMsg(make_url(copy url, None))); + engine_task.send(LoadUrlMsg(make_url(copy url, None))); match buffered_file_writer(&Path(outfile)) { Ok(writer) => writer.write(pngdata_from_compositor.recv()), From 7267f806a7817e48b0ac0c9c4aa23a8a0d288b03 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 9 May 2013 11:47:31 -0700 Subject: [PATCH 4/7] servo: Warning police. --- src/servo/dom/bindings/element.rs | 8 ++++---- src/servo/dom/bindings/node.rs | 2 +- src/servo/engine.rs | 1 - src/servo/layout/block.rs | 3 +-- src/servo/layout/box.rs | 3 +-- src/servo/layout/box_builder.rs | 7 ++----- src/servo/layout/inline.rs | 3 +-- 7 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/servo/dom/bindings/element.rs b/src/servo/dom/bindings/element.rs index 0e171de0cd1..4f568f15b5a 100644 --- a/src/servo/dom/bindings/element.rs +++ b/src/servo/dom/bindings/element.rs @@ -174,7 +174,7 @@ extern fn getBoundingClientRect(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JS extern fn setAttribute(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool { unsafe { let obj = JS_THIS_OBJECT(cx, vp); - let mut node = unwrap(obj); + let node = unwrap(obj); if (argc < 2) { return 0; //XXXjdm throw exception @@ -212,7 +212,7 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa return 0; } - let mut node = unwrap(obj); + let node = unwrap(obj); let width = match node.type_id() { ElementNodeTypeId(HTMLImageElementTypeId) => { let content = task_from_context(cx); @@ -245,7 +245,7 @@ extern fn HTMLImageElement_setWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa return 0; } - let mut node = unwrap(obj); + let node = unwrap(obj); match node.type_id() { ElementNodeTypeId(HTMLImageElementTypeId) => { do node.as_mut_element |elem| { @@ -269,7 +269,7 @@ extern fn getTagName(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { return 0; } - let mut node = unwrap(obj); + let node = unwrap(obj); do node.with_imm_element |elem| { let s = str(copy elem.tag_name); *vp = domstring_to_jsval(cx, &s); diff --git a/src/servo/dom/bindings/node.rs b/src/servo/dom/bindings/node.rs index c1be3694aa8..1050a1e57e8 100644 --- a/src/servo/dom/bindings/node.rs +++ b/src/servo/dom/bindings/node.rs @@ -68,7 +68,7 @@ pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj { } pub unsafe fn unwrap(obj: *JSObject) -> AbstractNode { - let raw = unsafe { utils::unwrap::<*mut Node>(obj) }; + let raw = utils::unwrap::<*mut Node>(obj); AbstractNode::from_raw(raw) } diff --git a/src/servo/engine.rs b/src/servo/engine.rs index dc693e7e2a0..d194535e8ed 100644 --- a/src/servo/engine.rs +++ b/src/servo/engine.rs @@ -15,7 +15,6 @@ use util::task::spawn_listener; use core::cell::Cell; use core::comm::{Chan, Port, SharedChan}; -use gfx::compositor::Compositor; use gfx::opts::Opts; use gfx::render_task::RenderTask; use gfx::render_task; diff --git a/src/servo/layout/block.rs b/src/servo/layout/block.rs index 1c284c0c891..4a441f4cc38 100644 --- a/src/servo/layout/block.rs +++ b/src/servo/layout/block.rs @@ -127,8 +127,7 @@ impl BlockLayout for FlowContext { assert!(self.starts_block_flow()); let mut remaining_width = self.with_imm_node(|this| this.position.size.width); - let mut _right_used = Au(0); - let mut left_used = Au(0); + let left_used = Au(0); // Let the box consume some width. It will return the amount remaining for its children. do self.with_block_box |box| { diff --git a/src/servo/layout/box.rs b/src/servo/layout/box.rs index a0e8b9f0cad..288e4a6151a 100644 --- a/src/servo/layout/box.rs +++ b/src/servo/layout/box.rs @@ -21,8 +21,7 @@ use gfx::font::{FontStyle, FontWeight300}; use gfx::geometry::Au; use gfx::image::holder::ImageHolder; use gfx::resource::local_image_cache::LocalImageCache; -use gfx; -use newcss::color::{Color, rgb}; +use newcss::color::rgb; use newcss::complete::CompleteStyle; use newcss::units::{Cursive, Em, Fantasy, Length, Monospace, Pt, Px, SansSerif, Serif}; use newcss::values::{CSSBorderWidthLength, CSSBorderWidthMedium}; diff --git a/src/servo/layout/box_builder.rs b/src/servo/layout/box_builder.rs index b5e50a9f45f..9a04148ced8 100644 --- a/src/servo/layout/box_builder.rs +++ b/src/servo/layout/box_builder.rs @@ -10,8 +10,7 @@ use dom::node::{ElementNodeTypeId, TextNodeTypeId}; use layout::block::BlockFlowData; use layout::box::{GenericRenderBoxClass, ImageRenderBox, ImageRenderBoxClass, RenderBox}; use layout::box::{RenderBoxBase, RenderBoxType, RenderBox_Generic, RenderBox_Image}; -use layout::box::{RenderBox_Text, TextRenderBox, UnscannedTextRenderBox}; -use layout::box::{UnscannedTextRenderBoxClass}; +use layout::box::{RenderBox_Text, UnscannedTextRenderBox, UnscannedTextRenderBoxClass}; use layout::context::LayoutContext; use layout::debug::{BoxedMutDebugMethods, DebugMethods}; use layout::flow::{AbsoluteFlow, BlockFlow, FloatFlow, Flow_Absolute, Flow_Block, Flow_Float}; @@ -20,7 +19,6 @@ use layout::flow::{FlowContextType, FlowData, InlineBlockFlow, InlineFlow, RootF use layout::inline::{InlineFlowData, InlineLayout}; use layout::root::RootFlowData; -use gfx::image::holder::ImageHolder; use newcss::values::{CSSDisplay, CSSDisplayBlock, CSSDisplayInline, CSSDisplayInlineBlock}; use newcss::values::{CSSDisplayNone}; use servo_util::range::Range; @@ -461,7 +459,7 @@ pub impl LayoutTreeBuilder { let result = match ty { RenderBox_Generic => GenericRenderBoxClass(@mut base), RenderBox_Text => UnscannedTextRenderBoxClass(@mut UnscannedTextRenderBox::new(base)), - RenderBox_Image => self.make_image_box(layout_ctx, node, flow_context, base), + RenderBox_Image => self.make_image_box(layout_ctx, node, base), }; debug!("LayoutTreeBuilder: created box: %s", result.debug_str()); result @@ -470,7 +468,6 @@ pub impl LayoutTreeBuilder { fn make_image_box(&mut self, layout_ctx: &LayoutContext, node: AbstractNode, - flow_context: FlowContext, base: RenderBoxBase) -> RenderBox { assert!(node.is_image_element()); diff --git a/src/servo/layout/inline.rs b/src/servo/layout/inline.rs index 1e0f4ba2313..6a0cf73fa34 100644 --- a/src/servo/layout/inline.rs +++ b/src/servo/layout/inline.rs @@ -17,7 +17,6 @@ use core::util; use geom::{Point2D, Rect, Size2D}; use gfx::display_list::DisplayList; use gfx::geometry::Au; -use gfx::image::holder; use gfx::text::text_run::TextRun; use gfx::text::util::*; use newcss::values::{CSSTextAlignCenter, CSSTextAlignJustify, CSSTextAlignLeft}; @@ -674,7 +673,7 @@ impl InlineFlowData { let width = Au::from_px(size.get_or_default(Size2D(0, 0)).width); image_box.base.position.size.width = width; } - TextRenderBoxClass(text_box) => { + TextRenderBoxClass(_) => { // Text boxes are preinitialized. } GenericRenderBoxClass(generic_box) => { From 932070b9e7df841ee9206d065a3ecd2de123a627 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 9 May 2013 14:06:03 -0700 Subject: [PATCH 5/7] Split the network stuff out of servo-gfx into servo-net --- Makefile.in | 18 +++- configure | 1 + src/servo-gfx/display_list.rs | 4 +- src/servo-gfx/image/encode/tga.rs | 28 ------ src/servo-gfx/opts.rs | 12 --- src/servo-gfx/render_context.rs | 2 +- src/servo-gfx/render_task.rs | 4 +- src/servo-gfx/servo_gfx.rc | 16 +--- .../resource => servo-net}/file_loader.rs | 11 ++- .../resource => servo-net}/http_loader.rs | 9 +- src/{servo-gfx => servo-net}/image/base.rs | 1 - src/{servo-gfx => servo-net}/image/holder.rs | 30 +++--- src/{servo-gfx => servo-net}/image/test.jpeg | Bin .../image_cache_task.rs | 87 ++++++------------ .../local_image_cache.rs | 7 +- .../resource => servo-net}/resource_task.rs | 10 +- src/servo-net/servo_net.rc | 33 +++++++ src/{servo-gfx/resource => servo-net}/util.rs | 0 src/servo/content/content_task.rs | 6 +- src/servo/engine.rs | 6 +- src/servo/html/cssparse.rs | 7 +- src/servo/html/hubbub_html_parser.rs | 6 +- src/servo/layout/box.rs | 4 +- src/servo/layout/context.rs | 7 +- src/servo/layout/layout_task.rs | 4 +- src/servo/servo.rc | 85 ++++------------- 26 files changed, 149 insertions(+), 249 deletions(-) delete mode 100644 src/servo-gfx/image/encode/tga.rs rename src/{servo-gfx/resource => servo-net}/file_loader.rs (80%) rename src/{servo-gfx/resource => servo-net}/http_loader.rs (90%) rename src/{servo-gfx => servo-net}/image/base.rs (99%) rename src/{servo-gfx => servo-net}/image/holder.rs (77%) rename src/{servo-gfx => servo-net}/image/test.jpeg (100%) rename src/{servo-gfx/resource => servo-net}/image_cache_task.rs (95%) rename src/{servo-gfx/resource => servo-net}/local_image_cache.rs (96%) rename src/{servo-gfx/resource => servo-net}/resource_task.rs (96%) create mode 100644 src/servo-net/servo_net.rc rename src/{servo-gfx/resource => servo-net}/util.rs (100%) diff --git a/Makefile.in b/Makefile.in index d0c31bfd78d..c1b1ac83e38 100644 --- a/Makefile.in +++ b/Makefile.in @@ -168,21 +168,28 @@ DONE_servo_util = $(B)src/servo-util/libservoutil.dummy DEPS_servo_util = $(CRATE_servo_util) $(SRC_servo_util) $(DONE_SUBMODULES) -RFLAGS_servo_gfx = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-util +RFLAGS_servo_net = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-util +SRC_servo_net = $(call rwildcard,$(S)src/servo-net/,*.rs) +CRATE_servo_net = $(S)src/servo-net/servo_net.rc +DONE_servo_net = $(B)src/servo-net/libservonet.dummy + +DEPS_servo_net = $(CRATE_servo_net) $(SRC_servo_net) $(DONE_SUBMODULES) $(DONE_servo_util) + +RFLAGS_servo_gfx = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-util -L $(B)src/servo-net SRC_servo_gfx = $(call rwildcard,$(S)src/servo-gfx/,*.rs) CRATE_servo_gfx = $(S)src/servo-gfx/servo_gfx.rc DONE_servo_gfx = $(B)src/servo-gfx/libservogfx.dummy -DEPS_servo_gfx = $(CRATE_servo_gfx) $(SRC_servo_gfx) $(DONE_SUBMODULES) $(DONE_servo_util) +DEPS_servo_gfx = $(CRATE_servo_gfx) $(SRC_servo_gfx) $(DONE_SUBMODULES) $(DONE_servo_util) $(DONE_servo_net) -RFLAGS_servo = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-gfx -L $(B)src/servo-util +RFLAGS_servo = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-gfx -L $(B)src/servo-util -L $(B)src/servo-net WEBIDL_servo = $(call rwildcard,$(S)src/servo/,*.webidl) AUTOGEN_SRC_servo = $(patsubst %.webidl, %Binding.rs, $(WEBIDL_servo)) SRC_servo = $(call rwildcard,$(S)src/servo/,*.rs) $(AUTOGEN_SRC_servo) CRATE_servo = $(S)src/servo/servo.rc -DEPS_servo = $(CRATE_servo) $(SRC_servo) $(DONE_SUBMODULES) $(DONE_servo_util) $(DONE_servo_gfx) +DEPS_servo = $(CRATE_servo) $(SRC_servo) $(DONE_SUBMODULES) $(DONE_servo_util) $(DONE_servo_gfx) $(DONE_servo_net) # rules that depend on having correct meta-target vars (DEPS_CLEAN, DEPS_servo, etc) include $(S)mk/check.mk @@ -197,6 +204,9 @@ all: servo package $(DONE_servo_util): $(DEPS_servo_util) $(RUSTC) $(RFLAGS_servo_util) -o $@ $< && touch $@ +$(DONE_servo_net): $(DEPS_servo_net) + $(RUSTC) $(RFLAGS_servo_net) -o $@ $< && touch $@ + $(DONE_servo_gfx): $(DEPS_servo_gfx) $(RUSTC) $(RFLAGS_servo_gfx) -o $@ $< && touch $@ diff --git a/configure b/configure index 6dbd320d078..18918506d48 100755 --- a/configure +++ b/configure @@ -419,6 +419,7 @@ do done make_dir ${CFG_BUILD_DIR}src/servo-util +make_dir ${CFG_BUILD_DIR}src/servo-net make_dir ${CFG_BUILD_DIR}src/servo-gfx make_dir src/test/ref make_dir src/rust diff --git a/src/servo-gfx/display_list.rs b/src/servo-gfx/display_list.rs index 87fdb66d8ff..e79dccea6c2 100644 --- a/src/servo-gfx/display_list.rs +++ b/src/servo-gfx/display_list.rs @@ -4,15 +4,15 @@ use color::{Color, rgb}; use geometry::Au; -use image::base::Image; use render_context::RenderContext; use text::SendableTextRun; -use servo_util::range::Range; use clone_arc = std::arc::clone; use geom::Rect; use geom::Point2D; use std::arc::ARC; +use servo_net::image::base::Image; +use servo_util::range::Range; struct DisplayItemData { bounds : Rect, // TODO: whose coordinate system should this use? diff --git a/src/servo-gfx/image/encode/tga.rs b/src/servo-gfx/image/encode/tga.rs deleted file mode 100644 index 8c5b948d505..00000000000 --- a/src/servo-gfx/image/encode/tga.rs +++ /dev/null @@ -1,28 +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 core::io::WriterUtil; -use surface; - -fn encode(writer: @io::Writer, surface: &surface::ImageSurface) { - assert!(surface.format == surface::fo_rgba_8888); - - writer.write_u8(0u8); // identsize - writer.write_u8(0u8); // colourmaptype - writer.write_u8(2u8); // imagetype - - writer.write_le_u16(0u16); // colourmapstart - writer.write_le_u16(0u16); // colourmaplength - writer.write_u8(16u8); // colourmapbits - - writer.write_le_u16(0u16); // xstart - writer.write_le_u16(0u16); // ystart - writer.write_le_u16(surface.size.width as u16); // width - writer.write_le_u16(surface.size.height as u16); // height - writer.write_u8(32u8); // bits - writer.write_u8(0x30u8); // descriptor - - writer.write(surface.buffer); -} - diff --git a/src/servo-gfx/opts.rs b/src/servo-gfx/opts.rs index 8dd926857e3..d9c6ff1446c 100644 --- a/src/servo-gfx/opts.rs +++ b/src/servo-gfx/opts.rs @@ -10,17 +10,11 @@ use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBacke pub struct Opts { urls: ~[~str], - render_mode: RenderMode, render_backend: BackendType, n_render_threads: uint, tile_size: uint, } -pub enum RenderMode { - Screen, - Png(~str) -} - #[allow(non_implicitly_copyable_typarams)] pub fn from_cmdline_args(args: &[~str]) -> Opts { use std::getopts; @@ -45,11 +39,6 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts { copy opt_match.free }; - let render_mode = match getopts::opt_maybe_str(&opt_match, ~"o") { - Some(output_file) => Png(output_file), - None => Screen, - }; - let render_backend = match getopts::opt_maybe_str(&opt_match, ~"r") { Some(backend_str) => { if backend_str == ~"direct2d" { @@ -81,7 +70,6 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts { Opts { urls: urls, - render_mode: render_mode, render_backend: render_backend, n_render_threads: n_render_threads, tile_size: tile_size, diff --git a/src/servo-gfx/render_context.rs b/src/servo-gfx/render_context.rs index d7d815c2252..17fb40d825c 100644 --- a/src/servo-gfx/render_context.rs +++ b/src/servo-gfx/render_context.rs @@ -5,7 +5,6 @@ use compositor::LayerBuffer; use font_context::FontContext; use geometry::Au; -use image::base::Image; use opts::Opts; use azure::azure_hl::{B8G8R8A8, Color, ColorPattern, DrawOptions}; @@ -15,6 +14,7 @@ use core::libc::types::common::c99::uint16_t; use geom::point::Point2D; use geom::rect::Rect; use geom::size::Size2D; +use servo_net::image::base::Image; use std::arc; use std::arc::ARC; diff --git a/src/servo-gfx/render_task.rs b/src/servo-gfx/render_task.rs index 4064972782f..970a39cff75 100644 --- a/src/servo-gfx/render_task.rs +++ b/src/servo-gfx/render_task.rs @@ -11,13 +11,13 @@ use geom::matrix2d::Matrix2D; use opts::Opts; use render_context::RenderContext; use render_layers::{RenderLayer, render_layers}; -use resource::util::spawn_listener; -use servo_util::time::time; use core::cell::Cell; use core::comm::{Port, SharedChan}; use core::task::SingleThreaded; use std::task_pool::TaskPool; +use servo_net::util::spawn_listener; +use servo_util::time::time; pub enum Msg { RenderMsg(RenderLayer), diff --git a/src/servo-gfx/servo_gfx.rc b/src/servo-gfx/servo_gfx.rc index d3aadde8c0f..f785e0fc877 100644 --- a/src/servo-gfx/servo_gfx.rc +++ b/src/servo-gfx/servo_gfx.rc @@ -13,6 +13,7 @@ extern mod geom; extern mod http_client; extern mod stb_image; extern mod std; +extern mod servo_net; extern mod servo_util (name = "servo_util"); // Eventually we would like the shaper to be pluggable, as many operating systems have their own @@ -57,22 +58,7 @@ pub mod opts; #[path="platform/mod.rs"] pub mod platform; -// Images -pub mod image { - pub mod base; - pub mod holder; -} - // Text #[path = "text/mod.rs"] pub mod text; -// FIXME: Blech. This does not belong in the GFX module. -pub mod resource { - pub mod file_loader; - pub mod http_loader; - pub mod image_cache_task; - pub mod local_image_cache; - pub mod resource_task; - pub mod util; -} diff --git a/src/servo-gfx/resource/file_loader.rs b/src/servo-net/file_loader.rs similarity index 80% rename from src/servo-gfx/resource/file_loader.rs rename to src/servo-net/file_loader.rs index fc7816d5f49..e7d03c091eb 100644 --- a/src/servo-gfx/resource/file_loader.rs +++ b/src/servo-net/file_loader.rs @@ -2,16 +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/. */ -use core::task::spawn; -use resource::resource_task::{Payload, Done, LoaderTask}; -use core::io::{file_reader, ReaderUtil}; +use resource_task::{Done, LoaderTask, Payload}; + +use core::io::{ReaderUtil, file_reader}; +use core::task; static READ_SIZE: uint = 1024; pub fn factory() -> LoaderTask { let f: LoaderTask = |url, progress_chan| { - assert!(url.scheme == ~"file"); - do spawn { + assert!("file" == url.scheme); + do task::spawn { // FIXME: Resolve bug prevents us from moving the path out of the URL. match file_reader(&Path(url.path)) { Ok(reader) => { diff --git a/src/servo-gfx/resource/http_loader.rs b/src/servo-net/http_loader.rs similarity index 90% rename from src/servo-gfx/resource/http_loader.rs rename to src/servo-net/http_loader.rs index eed67c19065..72e9e0acd30 100644 --- a/src/servo-gfx/resource/http_loader.rs +++ b/src/servo-net/http_loader.rs @@ -2,18 +2,19 @@ * 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 resource_task::{Payload, Done, LoaderTask}; + use core::comm::SharedChan; -use core::task::spawn; -use resource::resource_task::{Payload, Done, LoaderTask}; +use core::task; +use http_client::uv_http_request; use http_client; -use http_client::{uv_http_request}; pub fn factory() -> LoaderTask { let f: LoaderTask = |url, progress_chan| { assert!(url.scheme == ~"http"); let progress_chan = SharedChan::new(progress_chan); - do spawn { + do task::spawn { debug!("http_loader: requesting via http: %?", url.clone()); let mut request = uv_http_request(url.clone()); let errored = @mut false; diff --git a/src/servo-gfx/image/base.rs b/src/servo-net/image/base.rs similarity index 99% rename from src/servo-gfx/image/base.rs rename to src/servo-net/image/base.rs index 7f62d6156de..ae9324c41f2 100644 --- a/src/servo-gfx/image/base.rs +++ b/src/servo-net/image/base.rs @@ -20,7 +20,6 @@ pub fn test_image_bin() -> ~[u8] { } pub fn load_from_memory(buffer: &[u8]) -> Option { - // Can't remember why we do this. Maybe it's what cairo wants static FORCE_DEPTH: uint = 4; diff --git a/src/servo-gfx/image/holder.rs b/src/servo-net/image/holder.rs similarity index 77% rename from src/servo-gfx/image/holder.rs rename to src/servo-net/image/holder.rs index bd6adce3d65..605eea39411 100644 --- a/src/servo-gfx/image/holder.rs +++ b/src/servo-net/image/holder.rs @@ -3,21 +3,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use image::base::Image; -use resource::image_cache_task::{ImageReady, ImageNotReady, ImageFailed}; -use resource::local_image_cache::LocalImageCache; +use image_cache_task::{ImageReady, ImageNotReady, ImageFailed}; +use local_image_cache::LocalImageCache; use core::util::replace; use geom::size::Size2D; use std::net::url::Url; use std::arc::{ARC, clone, get}; -// FIXME: Nasty coupling to resource here. This should probably be factored out into an interface -// and use dependency injection. +// FIXME: Nasty coupling here This will be a problem if we want to factor out image handling from +// the network stack. This should probably be factored out into an interface and use dependency +// injection. -/** A struct to store image data. The image will be loaded once, the - first time it is requested, and an arc will be stored. Clones of - this arc are given out on demand. - */ +/// A struct to store image data. The image will be loaded once the first time it is requested, +/// and an ARC will be stored. Clones of this ARC are given out on demand. pub struct ImageHolder { url: Url, image: Option>, @@ -46,18 +45,16 @@ pub impl ImageHolder { holder } - /** - This version doesn't perform any computation, but may be stale w.r.t. - newly-available image data that determines size. - - The intent is that the impure version is used during layout when - dimensions are used for computing layout. - */ + /// This version doesn't perform any computation, but may be stale w.r.t. newly-available image + /// data that determines size. + /// + /// The intent is that the impure version is used during layout when dimensions are used for + /// computing layout. fn size(&self) -> Size2D { self.cached_size } - /** Query and update current image size */ + /// Query and update the current image size. fn get_size(&mut self) -> Option> { debug!("get_size() %?", self.url); match self.get_image() { @@ -103,3 +100,4 @@ pub impl ImageHolder { return result; } } + diff --git a/src/servo-gfx/image/test.jpeg b/src/servo-net/image/test.jpeg similarity index 100% rename from src/servo-gfx/image/test.jpeg rename to src/servo-net/image/test.jpeg diff --git a/src/servo-gfx/resource/image_cache_task.rs b/src/servo-net/image_cache_task.rs similarity index 95% rename from src/servo-gfx/resource/image_cache_task.rs rename to src/servo-net/image_cache_task.rs index 07abb1d05d4..4a462cdc926 100644 --- a/src/servo-gfx/resource/image_cache_task.rs +++ b/src/servo-net/image_cache_task.rs @@ -3,46 +3,46 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use image::base::{Image, load_from_memory}; -use resource::resource_task; -use resource::resource_task::ResourceTask; +use resource_task; +use resource_task::ResourceTask; use servo_util::url::{UrlMap, url_map}; use clone_arc = std::arc::clone; +use core::cell::Cell; use core::comm::{Chan, Port, SharedChan, stream}; use core::task::spawn; use core::to_str::ToStr; use core::util::replace; use std::arc::ARC; use std::net::url::Url; -use core::cell::Cell; pub enum Msg { /// Tell the cache that we may need a particular image soon. Must be posted /// before Decode - pub Prefetch(Url), + Prefetch(Url), // FIXME: We can probably get rid of this Cell now /// Used be the prefetch tasks to post back image binaries priv StorePrefetchedImageData(Url, Result, ()>), /// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage - pub Decode(Url), + Decode(Url), /// Used by the decoder tasks to post decoded images back to the cache priv StoreImage(Url, Option>), /// Request an Image object for a URL. If the image is not is not immediately /// available then ImageNotReady is returned. - pub GetImage(Url, Chan), + GetImage(Url, Chan), /// Wait for an image to become available (or fail to load). - pub WaitForImage(Url, Chan), + WaitForImage(Url, Chan), /// For testing priv OnMsg(~fn(msg: &Msg)), /// Clients must wait for a response before shutting down the ResourceTask - pub Exit(Chan<()>) + Exit(Chan<()>), } pub enum ImageResponseMsg { @@ -54,9 +54,9 @@ pub enum ImageResponseMsg { impl ImageResponseMsg { fn clone(&self) -> ImageResponseMsg { match *self { - ImageReady(ref img) => ImageReady(clone_arc(img)), - ImageNotReady => ImageNotReady, - ImageFailed => ImageFailed + ImageReady(ref img) => ImageReady(clone_arc(img)), + ImageNotReady => ImageNotReady, + ImageFailed => ImageFailed, } } } @@ -65,17 +65,16 @@ impl Eq for ImageResponseMsg { fn eq(&self, other: &ImageResponseMsg) -> bool { // FIXME: Bad copies match (self.clone(), other.clone()) { - (ImageReady(*), ImageReady(*)) => fail!(~"unimplemented comparison"), - (ImageNotReady, ImageNotReady) => true, - (ImageFailed, ImageFailed) => true, + (ImageReady(*), ImageReady(*)) => fail!(~"unimplemented comparison"), + (ImageNotReady, ImageNotReady) => true, + (ImageFailed, ImageFailed) => true, - (ImageReady(*), _) - | (ImageNotReady, _) - | (ImageFailed, _) => false + (ImageReady(*), _) | (ImageNotReady, _) | (ImageFailed, _) => false } } + fn ne(&self, other: &ImageResponseMsg) -> bool { - return !(*self).eq(other); + !(*self).eq(other) } } @@ -87,9 +86,8 @@ pub fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask { ImageCacheTask_(resource_task, default_decoder_factory) } -pub fn ImageCacheTask_(resource_task: ResourceTask, - decoder_factory: DecoderFactory) - -> ImageCacheTask { +pub fn ImageCacheTask_(resource_task: ResourceTask, decoder_factory: DecoderFactory) + -> ImageCacheTask { // FIXME: Doing some dancing to avoid copying decoder_factory, our test // version of which contains an uncopyable type which rust will currently // copy unsoundly @@ -140,7 +138,7 @@ fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask { } } - return SharedChan::new(chan); + SharedChan::new(chan) } struct ImageCache { @@ -175,9 +173,7 @@ enum AfterPrefetch { #[allow(non_implicitly_copyable_typarams)] impl ImageCache { - pub fn run(&mut self) { - let mut msg_handlers: ~[~fn(msg: &Msg)] = ~[]; loop { @@ -397,26 +393,12 @@ impl ImageCache { priv fn get_image(&self, url: Url, response: Chan) { match self.get_state(copy url) { - Init => fail!(~"request for image before prefetch"), - - Prefetching(DoDecode) => { - response.send(ImageNotReady); - } - - Prefetching(DoNotDecode) - | Prefetched(*) => fail!(~"request for image before decode"), - - Decoding => { - response.send(ImageNotReady) - } - - Decoded(image) => { - response.send(ImageReady(clone_arc(image))); - } - - Failed => { - response.send(ImageFailed); - } + Init => fail!(~"request for image before prefetch"), + Prefetching(DoDecode) => response.send(ImageNotReady), + Prefetching(DoNotDecode) | Prefetched(*) => fail!(~"request for image before decode"), + Decoding => response.send(ImageNotReady), + Decoded(image) => response.send(ImageReady(clone_arc(image))), + Failed => response.send(ImageFailed), } } @@ -505,7 +487,6 @@ fn mock_resource_task(on_load: ~fn(resource: Chan)) #[test] fn should_exit_on_request() { - let mock_resource_task = mock_resource_task(|_response| () ); let image_cache_task = ImageCacheTask(mock_resource_task); @@ -518,7 +499,6 @@ fn should_exit_on_request() { #[test] #[should_fail] fn should_fail_if_unprefetched_image_is_requested() { - let mock_resource_task = mock_resource_task(|_response| () ); let image_cache_task = ImageCacheTask(mock_resource_task); @@ -552,7 +532,6 @@ fn should_request_url_from_resource_task_on_prefetch() { #[test] #[should_fail] fn should_fail_if_requesting_decode_of_an_unprefetched_image() { - let mock_resource_task = mock_resource_task(|_response| () ); let image_cache_task = ImageCacheTask(mock_resource_task); @@ -565,7 +544,6 @@ fn should_fail_if_requesting_decode_of_an_unprefetched_image() { #[test] #[should_fail] fn should_fail_if_requesting_image_before_requesting_decode() { - let mock_resource_task = do mock_resource_task |response| { response.send(resource_task::Done(result::Ok(()))); }; @@ -606,7 +584,6 @@ fn should_not_request_url_from_resource_task_on_multiple_prefetches() { #[test] fn should_return_image_not_ready_if_data_has_not_arrived() { - let (wait_chan, wait_port) = pipes::stream(); let mock_resource_task = do mock_resource_task |response| { @@ -632,7 +609,6 @@ fn should_return_image_not_ready_if_data_has_not_arrived() { #[test] fn should_return_decoded_image_data_if_data_has_arrived() { - let mock_resource_task = do mock_resource_task |response| { response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Done(result::Ok(()))); @@ -670,7 +646,6 @@ fn should_return_decoded_image_data_if_data_has_arrived() { #[test] fn should_return_decoded_image_data_for_multiple_requests() { - let mock_resource_task = do mock_resource_task |response| { response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Done(result::Ok(()))); @@ -710,7 +685,6 @@ fn should_return_decoded_image_data_for_multiple_requests() { #[test] fn should_not_request_image_from_resource_task_if_image_is_already_available() { - let image_bin_sent = comm::Port(); let image_bin_sent_chan = image_bin_sent.chan(); @@ -755,7 +729,6 @@ fn should_not_request_image_from_resource_task_if_image_is_already_available() { #[test] fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() { - let image_bin_sent = comm::Port(); let image_bin_sent_chan = image_bin_sent.chan(); @@ -802,7 +775,6 @@ fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() { #[test] fn should_return_failed_if_image_bin_cannot_be_fetched() { - let mock_resource_task = do mock_resource_task |response| { response.send(resource_task::Payload(test_image_bin())); // ERROR fetching image @@ -841,7 +813,6 @@ fn should_return_failed_if_image_bin_cannot_be_fetched() { #[test] fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() { - let mock_resource_task = do mock_resource_task |response | { response.send(resource_task::Payload(test_image_bin())); // ERROR fetching image @@ -888,7 +859,6 @@ fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_f #[test] fn should_return_not_ready_if_image_is_still_decoding() { - let (wait_to_decode_chan, wait_to_decode_port) = pipes::stream(); let mock_resource_task = do mock_resource_task |response| { @@ -943,7 +913,6 @@ fn should_return_not_ready_if_image_is_still_decoding() { #[test] fn should_return_failed_if_image_decode_fails() { - let mock_resource_task = do mock_resource_task |response| { // Bogus data response.send(resource_task::Payload(~[])); @@ -984,7 +953,6 @@ fn should_return_failed_if_image_decode_fails() { #[test] fn should_return_image_on_wait_if_image_is_already_loaded() { - let mock_resource_task = do mock_resource_task |response| { response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Done(result::Ok(()))); @@ -1022,7 +990,6 @@ fn should_return_image_on_wait_if_image_is_already_loaded() { #[test] fn should_return_image_on_wait_if_image_is_not_yet_loaded() { - let (wait_chan, wait_port) = pipes::stream(); let mock_resource_task = do mock_resource_task |response| { @@ -1053,7 +1020,6 @@ fn should_return_image_on_wait_if_image_is_not_yet_loaded() { #[test] fn should_return_image_failed_on_wait_if_image_fails_to_load() { - let (wait_chan, wait_port) = pipes::stream(); let mock_resource_task = do mock_resource_task |response| { @@ -1105,3 +1071,4 @@ fn sync_cache_should_wait_for_images() { image_cache_task.exit(); mock_resource_task.send(resource_task::Exit); } + diff --git a/src/servo-gfx/resource/local_image_cache.rs b/src/servo-net/local_image_cache.rs similarity index 96% rename from src/servo-gfx/resource/local_image_cache.rs rename to src/servo-net/local_image_cache.rs index a051f8e19de..8df7f082bb7 100644 --- a/src/servo-gfx/resource/local_image_cache.rs +++ b/src/servo-net/local_image_cache.rs @@ -8,12 +8,13 @@ extra message traffic, it also avoids waiting on the same image multiple times and thus triggering reflows multiple times. */ +use image_cache_task::{Decode, GetImage, ImageCacheTask, ImageFailed, ImageNotReady, ImageReady}; +use image_cache_task::{ImageResponseMsg, Prefetch, WaitForImage}; + use clone_arc = std::arc::clone; -use std::net::url::Url; use core::comm::Port; -use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg, Prefetch, Decode, GetImage}; -use resource::image_cache_task::{ WaitForImage, ImageReady, ImageNotReady, ImageFailed}; use servo_util::url::{UrlMap, url_map}; +use std::net::url::Url; pub fn LocalImageCache(image_cache_task: ImageCacheTask) -> LocalImageCache { LocalImageCache { diff --git a/src/servo-gfx/resource/resource_task.rs b/src/servo-net/resource_task.rs similarity index 96% rename from src/servo-gfx/resource/resource_task.rs rename to src/servo-net/resource_task.rs index 3b989f478e9..8fef9095387 100644 --- a/src/servo-gfx/resource/resource_task.rs +++ b/src/servo-net/resource_task.rs @@ -2,17 +2,15 @@ * 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/. */ -/*! +//! A task that takes a URL and streams back the binary data. -A task that takes a URL and streams back the binary data - -*/ +use file_loader; +use http_loader; use core::cell::Cell; use core::comm::{Chan, Port, SharedChan}; -use resource::util::spawn_listener; use std::net::url::{Url, to_str}; -use super::{file_loader, http_loader}; +use util::spawn_listener; pub enum ControlMsg { /// Request the data associated with a particular URL diff --git a/src/servo-net/servo_net.rc b/src/servo-net/servo_net.rc new file mode 100644 index 00000000000..739ec49c637 --- /dev/null +++ b/src/servo-net/servo_net.rc @@ -0,0 +1,33 @@ +/* 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/. */ + +#[link(name = "servo_net", + vers = "0.1", + uuid = "69c2b7b7-0d7d-4514-a48a-0eed61476039", + url = "http://servo.org/")]; +#[crate_type = "lib"]; + +extern mod geom; +extern mod http_client; +extern mod servo_util; +extern mod stb_image; +extern mod std; + +/// Image handling. +/// +/// It may be surprising that this goes in the network crate as opposed to the graphics crate. +/// However, image handling is generally very integrated with the network stack (especially where +/// caching is involved) and as a result it must live in here. +pub mod image { + pub mod base; + pub mod holder; +} + +pub mod file_loader; +pub mod http_loader; +pub mod image_cache_task; +pub mod local_image_cache; +pub mod resource_task; +pub mod util; + diff --git a/src/servo-gfx/resource/util.rs b/src/servo-net/util.rs similarity index 100% rename from src/servo-gfx/resource/util.rs rename to src/servo-net/util.rs diff --git a/src/servo/content/content_task.rs b/src/servo/content/content_task.rs index af9cd1aa2e1..56d0959923a 100644 --- a/src/servo/content/content_task.rs +++ b/src/servo/content/content_task.rs @@ -17,15 +17,13 @@ use layout::layout_task; use core::cell::Cell; use core::comm::{Port, SharedChan}; use core::either; -use core::io::{println, read_whole_file}; +use core::io::read_whole_file; use core::pipes::select2i; use core::ptr::null; use core::task::{SingleThreaded, task}; use core::util::replace; use dom; use geom::size::Size2D; -use gfx::resource::image_cache_task::ImageCacheTask; -use gfx::resource::resource_task::ResourceTask; use html; use js::JSVAL_NULL; use js::global::{global_class, debug_fns}; @@ -34,6 +32,8 @@ use js::jsapi::JSContext; use js::jsapi::bindgen::{JS_CallFunctionValue, JS_GetContextPrivate}; use js::rust::{Compartment, Cx}; use jsrt = js::rust::rt; +use servo_net::image_cache_task::ImageCacheTask; +use servo_net::resource_task::ResourceTask; use servo_util::tree::TreeNodeRef; use std::net::url::Url; use url_to_str = std::net::url::to_str; diff --git a/src/servo/engine.rs b/src/servo/engine.rs index d194535e8ed..ebf524c02cf 100644 --- a/src/servo/engine.rs +++ b/src/servo/engine.rs @@ -8,9 +8,6 @@ use content::content_task; use dom::event::Event; use layout::layout_task; use layout::layout_task::LayoutTask; -use resource::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; -use resource::resource_task::ResourceTask; -use resource::resource_task; use util::task::spawn_listener; use core::cell::Cell; @@ -18,6 +15,9 @@ use core::comm::{Chan, Port, SharedChan}; use gfx::opts::Opts; use gfx::render_task::RenderTask; use gfx::render_task; +use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; +use servo_net::resource_task::ResourceTask; +use servo_net::resource_task; use std::net::url::Url; pub type EngineTask = Chan; diff --git a/src/servo/html/cssparse.rs b/src/servo/html/cssparse.rs index 8149fc671d3..9ee789d6e3e 100644 --- a/src/servo/html/cssparse.rs +++ b/src/servo/html/cssparse.rs @@ -2,17 +2,14 @@ * 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/. */ -/*! -Some little helpers for hooking up the HTML parser with the CSS parser -*/ - -use resource::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done}; +/// Some little helpers for hooking up the HTML parser with the CSS parser. use core::cell::Cell; use core::comm::Port; use core::str; use newcss::stylesheet::Stylesheet; use newcss::util::DataStream; +use servo_net::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done}; use std::net::url::Url; /// Where a style sheet comes from. diff --git a/src/servo/html/hubbub_html_parser.rs b/src/servo/html/hubbub_html_parser.rs index fef7c6584a6..549f6ec5b0a 100644 --- a/src/servo/html/hubbub_html_parser.rs +++ b/src/servo/html/hubbub_html_parser.rs @@ -6,15 +6,15 @@ use dom::element::*; use dom::node::{AbstractNode, Comment, Doctype, Element, ElementNodeTypeId, Node, Text}; use html::cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser}; use newcss::stylesheet::Stylesheet; -use resource::image_cache_task::ImageCacheTask; -use resource::image_cache_task; -use resource::resource_task::{Done, Load, Payload, ResourceTask}; use util::task::spawn_conversation; use core::cell::Cell; use core::comm::{Chan, Port, SharedChan}; use core::str::eq_slice; use hubbub::hubbub; +use servo_net::image_cache_task::ImageCacheTask; +use servo_net::image_cache_task; +use servo_net::resource_task::{Done, Load, Payload, ResourceTask}; use servo_util::tree::TreeUtils; use servo_util::url::make_url; use std::net::url::Url; diff --git a/src/servo/layout/box.rs b/src/servo/layout/box.rs index 288e4a6151a..67d96dcef67 100644 --- a/src/servo/layout/box.rs +++ b/src/servo/layout/box.rs @@ -19,8 +19,6 @@ use geom::{Point2D, Rect, Size2D}; use gfx::display_list::{DisplayItem, DisplayList}; use gfx::font::{FontStyle, FontWeight300}; use gfx::geometry::Au; -use gfx::image::holder::ImageHolder; -use gfx::resource::local_image_cache::LocalImageCache; use newcss::color::rgb; use newcss::complete::CompleteStyle; use newcss::units::{Cursive, Em, Fantasy, Length, Monospace, Pt, Px, SansSerif, Serif}; @@ -28,6 +26,8 @@ use newcss::values::{CSSBorderWidthLength, CSSBorderWidthMedium}; use newcss::values::{CSSFontFamilyFamilyName, CSSFontFamilyGenericFamily}; use newcss::values::{CSSFontSizeLength, CSSFontStyleItalic, CSSFontStyleNormal}; use newcss::values::{CSSFontStyleOblique, CSSTextAlign}; +use servo_net::image::holder::ImageHolder; +use servo_net::local_image_cache::LocalImageCache; use servo_util::range::*; use std::arc; use std::cmp::FuzzyEq; diff --git a/src/servo/layout/context.rs b/src/servo/layout/context.rs index dabcdefbf40..8646b9faabc 100644 --- a/src/servo/layout/context.rs +++ b/src/servo/layout/context.rs @@ -2,14 +2,15 @@ * 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/. */ +//! Data needed by the layout task. + use geom::rect::Rect; use gfx::font_context::FontContext; use gfx::geometry::Au; -use gfx::resource::local_image_cache::LocalImageCache; +use servo_net::local_image_cache::LocalImageCache; use std::net::url::Url; -/* Represents layout task context. */ - +/// Data needed by the layout task. pub struct LayoutContext { font_ctx: @mut FontContext, image_cache: @mut LocalImageCache, diff --git a/src/servo/layout/layout_task.rs b/src/servo/layout/layout_task.rs index d03ac503e67..13fd258e40b 100644 --- a/src/servo/layout/layout_task.rs +++ b/src/servo/layout/layout_task.rs @@ -15,8 +15,6 @@ use layout::context::LayoutContext; use layout::debug::{BoxedMutDebugMethods, DebugMethods}; use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods}; use layout::flow::FlowContext; -use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg}; -use resource::local_image_cache::LocalImageCache; use util::task::spawn_listener; use util::time::time; @@ -34,6 +32,8 @@ use gfx::render_task::{RenderMsg, RenderTask}; use newcss::select::SelectCtx; use newcss::stylesheet::Stylesheet; 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; diff --git a/src/servo/servo.rc b/src/servo/servo.rc index e396341138c..a34e9f7e9d7 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -11,19 +11,18 @@ #[license = "MPL"]; #[crate_type = "lib"]; -#[legacy_records]; - extern mod azure; extern mod geom; extern mod gfx (name = "servo_gfx"); -extern mod servo_util (name = "servo_util"); extern mod glut; extern mod http_client; extern mod hubbub; extern mod js; extern mod layers; -extern mod opengles; extern mod newcss (name = "css"); +extern mod opengles; +extern mod servo_net; +extern mod servo_util (name = "servo_util"); extern mod sharegl; extern mod stb_image; extern mod std; @@ -36,10 +35,12 @@ extern mod core_text; use compositing::{AddKeyHandler, CompositorImpl}; use engine::{Engine, LoadUrlMsg}; -pub use gfx::opts::{Opts, Png, Screen}; // FIXME: Do we really want "Screen" and "Png" visible? -pub use gfx::resource; -pub use gfx::resource::image_cache_task::ImageCacheTask; -pub use gfx::resource::resource_task::ResourceTask; +use core::comm::SharedChan; +use gfx::opts; +use servo_net::image_cache_task::ImageCacheTask; +use servo_net::resource_task::ResourceTask; + +pub use gfx::opts::Opts; pub use gfx::text; pub use servo_util::url::make_url; @@ -122,27 +123,12 @@ pub mod platform; pub mod util; fn main() { - let args = os::args(); - run(&gfx::opts::from_cmdline_args(args)) + run(&opts::from_cmdline_args(os::args())) } -#[allow(non_implicitly_copyable_typarams)] fn run(opts: &Opts) { - match &opts.render_mode { - &Screen => run_pipeline_screen(opts), - &Png(ref outfile) => { - assert!(!opts.urls.is_empty()); - if opts.urls.len() > 1u { - fail!(~"servo asks that you stick to a single URL in PNG output mode") - } - run_pipeline_png(opts, *outfile) - } - } -} - -fn run_pipeline_screen(opts: &Opts) { let (dom_event_port, dom_event_chan) = comm::stream(); - let dom_event_chan = comm::SharedChan::new(dom_event_chan); + let dom_event_chan = SharedChan::new(dom_event_chan); // The platform event handler thread let compositor = CompositorImpl::new(dom_event_chan.clone(), copy *opts); @@ -163,14 +149,15 @@ fn run_pipeline_screen(opts: &Opts) { for opts.urls.each |filename| { let url = make_url(copy *filename, None); + debug!("master: Sending url `%s`", url.to_str()); engine_task.send(LoadUrlMsg(url)); - debug!("master: Waiting for keypress"); + debug!("master: Waiting for keypress"); match keypress_from_compositor.try_recv() { - Some(*) => { } - None => { error!("keypress stream closed unexpectedly") } - }; + Some(*) => {} + None => error!("keypress stream closed unexpectedly"), + } } // Shut everything down @@ -182,43 +169,3 @@ fn run_pipeline_screen(opts: &Opts) { compositor.chan.send(compositing::Exit); } -fn run_pipeline_png(_opts: &Opts, _outfile: &str) { - fail!(~"PNG compositor is broken"); -} - -#[cfg(broken)] -fn run_pipeline_png(url: ~str, outfile: &str) { - // Use a PNG encoder as the graphics compositor - use gfx::png_compositor; - use png_compositor::PngCompositor; - use io::{Writer, buffered_file_writer}; - use resource::resource_task::ResourceTask; - use resource::image_cache_task::SyncImageCacheTask; - - listen(|pngdata_from_compositor| { - let (dom_event_port, dom_event_chan) = comm::stream(); - let dom_event_chan = comm::SharedChan(dom_event_chan); - - let compositor = PngCompositor(pngdata_from_compositor); - let resource_task = ResourceTask(); - // For the PNG pipeline we are using a synchronous image task so that all images will be - // fulfilled before the first paint. - let image_cache_task = SyncImageCacheTask(resource_task); - let engine_task = Engine(copy compositor, - dom_event_port, - dom_event_chan, - resource_task, - image_cache_task); - engine_task.send(LoadUrlMsg(make_url(copy url, None))); - - match buffered_file_writer(&Path(outfile)) { - Ok(writer) => writer.write(pngdata_from_compositor.recv()), - Err(e) => fail!(e) - } - - let (exit_chan, exit_response_from_engine) = comm::stream(); - engine_task.send(engine::ExitMsg(exit_chan)); - exit_response_from_engine.recv(); - compositor.send(png_compositor::Exit); - }) -} From 7c40535dd8ef45c288ec09149cb7303ffc467959 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 9 May 2013 14:06:35 -0700 Subject: [PATCH 6/7] Add missing compositing/mod.rs --- src/servo/compositing/mod.rs | 303 +++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 src/servo/compositing/mod.rs diff --git a/src/servo/compositing/mod.rs b/src/servo/compositing/mod.rs new file mode 100644 index 00000000000..2be5d57f3ec --- /dev/null +++ b/src/servo/compositing/mod.rs @@ -0,0 +1,303 @@ +/* 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 compositing::resize_rate_limiter::ResizeRateLimiter; +use dom::event::Event; +use platform::{Application, Window}; + +use azure::azure_hl::{BackendType, B8G8R8A8, DataSourceSurface, DrawTarget, SourceSurfaceMethods}; +use core::cell::Cell; +use core::comm::{Chan, SharedChan, Port}; +use core::util; +use geom::matrix::identity; +use geom::point::Point2D; +use geom::rect::Rect; +use geom::size::Size2D; +use gfx::compositor::{Compositor, LayerBuffer, LayerBufferSet}; +use gfx::opts::Opts; +use layers; +use servo_util::time; + +mod resize_rate_limiter; + +/// Type of the function that is called when the screen is to be redisplayed. +pub type CompositeCallback = @fn(); + +/// Type of the function that is called when the window is resized. +pub type ResizeCallback = @fn(uint, uint); + +/// The implementation of the layers-based compositor. +#[deriving(Clone)] +pub struct CompositorImpl { + chan: SharedChan +} + +impl CompositorImpl { + /// Creates a new compositor instance. + pub fn new(dom_event_chan: SharedChan, opts: Opts) -> CompositorImpl { + let dom_event_chan = Cell(dom_event_chan); + let chan: Chan = do on_osmain |port| { + debug!("preparing to enter main loop"); + mainloop(port, dom_event_chan.take(), &opts); + }; + + CompositorImpl { + chan: SharedChan::new(chan) + } + } +} + +/// Messages to the compositor. +pub enum Msg { + BeginDrawing(Chan), + Draw(Chan, LayerBufferSet), + AddKeyHandler(Chan<()>), + Exit +} + +/// Azure surface wrapping to work with the layers infrastructure. +struct AzureDrawTargetImageData { + draw_target: DrawTarget, + data_source_surface: DataSourceSurface, + size: Size2D +} + +impl layers::layers::ImageData for AzureDrawTargetImageData { + fn size(&self) -> Size2D { + self.size + } + fn stride(&self) -> uint { + self.data_source_surface.stride() as uint + } + fn format(&self) -> layers::layers::Format { + // FIXME: This is not always correct. We should query the Azure draw target for the format. + layers::layers::ARGB32Format + } + fn with_data(&self, f: layers::layers::WithDataFn) { + do self.data_source_surface.with_data |data| { + f(data); + } + } +} + +fn mainloop(po: Port, dom_event_chan: SharedChan, opts: &Opts) { + let key_handlers: @mut ~[Chan<()>] = @mut ~[]; + + let app = Application::new(); + let window = Window::new(&app); + + let surfaces = @mut SurfaceSet(opts.render_backend); + + let context = layers::rendergl::init_render_context(); + + // Create an initial layer tree. + // + // TODO: There should be no initial layer tree until the renderer creates one from the display + // list. This is only here because we don't have that logic in the renderer yet. + let root_layer = @mut layers::layers::ContainerLayer(); + let original_layer_transform; + { + let image_data = @layers::layers::BasicImageData::new(Size2D(0u, 0u), + 0, + layers::layers::RGB24Format, + ~[]); + let image = @mut layers::layers::Image::new(image_data as @layers::layers::ImageData); + let image_layer = @mut layers::layers::ImageLayer(image); + original_layer_transform = image_layer.common.transform; + image_layer.common.set_transform(original_layer_transform.scale(800.0, 600.0, 1.0)); + root_layer.add_child(layers::layers::ImageLayerKind(image_layer)); + } + + + let scene = @mut layers::scene::Scene(layers::layers::ContainerLayerKind(root_layer), + Size2D(800.0, 600.0), + identity()); + + let done = @mut false; + let resize_rate_limiter = @mut ResizeRateLimiter(dom_event_chan); + let check_for_messages: @fn() = || { + // Periodically check if content responded to our last resize event + resize_rate_limiter.check_resize_response(); + + // Handle messages + while po.peek() { + match po.recv() { + AddKeyHandler(key_ch) => key_handlers.push(key_ch), + BeginDrawing(sender) => lend_surface(surfaces, sender), + Draw(sender, draw_target) => { + debug!("osmain: received new frame"); + return_surface(surfaces, draw_target); + lend_surface(surfaces, sender); + + // Iterate over the children of the container layer. + let mut current_layer_child = root_layer.first_child; + + // Replace the image layer data with the buffer data. + let buffers = util::replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]); + for buffers.each |buffer| { + let width = buffer.rect.size.width as uint; + let height = buffer.rect.size.height as uint; + + debug!("osmain: compositing buffer rect %?", &buffer.rect); + + let image_data = @AzureDrawTargetImageData { + draw_target: buffer.draw_target.clone(), + data_source_surface: buffer.draw_target.snapshot().get_data_surface(), + size: Size2D(width, height) + }; + let image = @mut layers::layers::Image::new(image_data as @layers::layers::ImageData); + + // Find or create an image layer. + let image_layer; + current_layer_child = match current_layer_child { + None => { + debug!("osmain: adding new image layer"); + image_layer = @mut layers::layers::ImageLayer(image); + root_layer.add_child(layers::layers::ImageLayerKind(image_layer)); + None + } + Some(layers::layers::ImageLayerKind(existing_image_layer)) => { + image_layer = existing_image_layer; + image_layer.set_image(image); + + // Move on to the next sibling. + do current_layer_child.get().with_common |common| { + common.next_sibling + } + } + Some(_) => fail!(~"found unexpected layer kind"), + }; + + // Set the layer's transform. + let x = buffer.rect.origin.x as f32; + let y = buffer.rect.origin.y as f32; + image_layer.common.set_transform( + original_layer_transform.translate(x, y, 0.0) + .scale(width as f32, height as f32, 1.0)); + } + surfaces.front.layer_buffer_set.buffers = buffers; + } + Exit => { + *done = true; + } + } + } + }; + + do window.set_composite_callback { + do time::time(~"compositing") { + // Adjust the layer dimensions as necessary to correspond to the size of the window. + scene.size = window.size(); + + // Render the scene. + layers::rendergl::render_scene(context, scene); + } + + window.present(); + } + + do window.set_resize_callback |width, height| { + debug!("osmain: window resized to %ux%u", width, height); + resize_rate_limiter.window_resized(width, height); + } + + // Enter the main event loop. + while !*done { + // Check for new messages coming from the rendering task. + check_for_messages(); + + // Check for messages coming from the windowing system. + window.check_loop(); + } +} + +/// Implementation of the abstract `Compositor` interface. +impl Compositor for CompositorImpl { + fn begin_drawing(&self, next_dt: Chan) { + self.chan.send(BeginDrawing(next_dt)) + } + fn draw(&self, next_dt: Chan, draw_me: LayerBufferSet) { + self.chan.send(Draw(next_dt, draw_me)) + } +} + +struct SurfaceSet { + front: Surface, + back: Surface, +} + +fn lend_surface(surfaces: &mut SurfaceSet, receiver: Chan) { + // We are in a position to lend out the surface? + assert!(surfaces.front.have); + // Ok then take it + let old_layer_buffers = util::replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]); + let new_layer_buffers = do old_layer_buffers.map |layer_buffer| { + let draw_target_ref = &layer_buffer.draw_target; + let layer_buffer = LayerBuffer { + draw_target: draw_target_ref.clone(), + rect: copy layer_buffer.rect, + stride: layer_buffer.stride + }; + debug!("osmain: lending surface %?", layer_buffer); + layer_buffer + }; + surfaces.front.layer_buffer_set.buffers = old_layer_buffers; + + let new_layer_buffer_set = LayerBufferSet { buffers: new_layer_buffers }; + receiver.send(new_layer_buffer_set); + // Now we don't have it + surfaces.front.have = false; + // But we (hopefully) have another! + surfaces.front <-> surfaces.back; + // Let's look + assert!(surfaces.front.have); +} + +fn return_surface(surfaces: &mut SurfaceSet, layer_buffer_set: LayerBufferSet) { + //#debug("osmain: returning surface %?", layer_buffer_set); + // We have room for a return + assert!(surfaces.front.have); + assert!(!surfaces.back.have); + + surfaces.back.layer_buffer_set = layer_buffer_set; + + // Now we have it again + surfaces.back.have = true; +} + +fn SurfaceSet(backend: BackendType) -> SurfaceSet { + SurfaceSet { front: Surface(backend), back: Surface(backend) } +} + +struct Surface { + layer_buffer_set: LayerBufferSet, + have: bool, +} + +fn Surface(backend: BackendType) -> Surface { + let layer_buffer = LayerBuffer { + draw_target: DrawTarget::new(backend, Size2D(800i32, 600i32), B8G8R8A8), + rect: Rect(Point2D(0u, 0u), Size2D(800u, 600u)), + stride: 800 * 4 + }; + let layer_buffer_set = LayerBufferSet { + buffers: ~[ layer_buffer ] + }; + Surface { + layer_buffer_set: layer_buffer_set, + have: true + } +} + +/// A function for spawning into the platform's main thread. +fn on_osmain(f: ~fn(po: Port)) -> Chan { + let (setup_po, setup_ch) = comm::stream(); + do task::task().sched_mode(task::PlatformThread).spawn { + let (po, ch) = comm::stream(); + setup_ch.send(ch); + f(po); + } + setup_po.recv() +} + From 4eb305e56815a4277c30b8910f3ef31b96294715 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 9 May 2013 15:01:21 -0700 Subject: [PATCH 7/7] servo: Address review comments --- src/servo/compositing/mod.rs | 11 ++---- src/servo/platform/common/glut_windowing.rs | 8 ++--- .../platform/common/shared_gl_windowing.rs | 6 ++-- src/servo/servo.rc | 2 ++ src/servo/windowing.rs | 34 +++++++++++++++++++ 5 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 src/servo/windowing.rs diff --git a/src/servo/compositing/mod.rs b/src/servo/compositing/mod.rs index 2be5d57f3ec..d2824674e4d 100644 --- a/src/servo/compositing/mod.rs +++ b/src/servo/compositing/mod.rs @@ -5,6 +5,7 @@ use compositing::resize_rate_limiter::ResizeRateLimiter; use dom::event::Event; use platform::{Application, Window}; +use windowing::{ApplicationMethods, WindowMethods}; use azure::azure_hl::{BackendType, B8G8R8A8, DataSourceSurface, DrawTarget, SourceSurfaceMethods}; use core::cell::Cell; @@ -21,12 +22,6 @@ use servo_util::time; mod resize_rate_limiter; -/// Type of the function that is called when the screen is to be redisplayed. -pub type CompositeCallback = @fn(); - -/// Type of the function that is called when the window is resized. -pub type ResizeCallback = @fn(uint, uint); - /// The implementation of the layers-based compositor. #[deriving(Clone)] pub struct CompositorImpl { @@ -84,8 +79,8 @@ impl layers::layers::ImageData for AzureDrawTargetImageData { fn mainloop(po: Port, dom_event_chan: SharedChan, opts: &Opts) { let key_handlers: @mut ~[Chan<()>] = @mut ~[]; - let app = Application::new(); - let window = Window::new(&app); + let app: Application = ApplicationMethods::new(); + let window: @mut Window = WindowMethods::new(&app); let surfaces = @mut SurfaceSet(opts.render_backend); diff --git a/src/servo/platform/common/glut_windowing.rs b/src/servo/platform/common/glut_windowing.rs index 4aa02260d6c..b4ab82ac5d8 100644 --- a/src/servo/platform/common/glut_windowing.rs +++ b/src/servo/platform/common/glut_windowing.rs @@ -7,7 +7,7 @@ /// GLUT is a very old and bare-bones toolkit. However, it has good cross-platform support, at /// least on desktops. It is designed for testing Servo without the need of a UI. -use compositing::{CompositeCallback, ResizeCallback}; +use windowing::{ApplicationMethods, CompositeCallback, ResizeCallback, WindowMethods}; use geom::size::Size2D; use glut::glut::{DOUBLE, WindowHeight, WindowWidth}; @@ -16,7 +16,7 @@ use glut::glut; /// A structure responsible for setting up and tearing down the entire windowing system. pub struct Application; -impl Application { +impl ApplicationMethods for Application { pub fn new() -> Application { glut::init(); glut::init_display_mode(DOUBLE); @@ -31,7 +31,7 @@ pub struct Window { resize_callback: Option, } -impl Window { +impl WindowMethods for Window { /// Creates a new window. pub fn new(_: &Application) -> @mut Window { // Create the GLUT window. @@ -64,7 +64,7 @@ impl Window { } /// Returns the size of the window. - pub fn size(&mut self) -> Size2D { + pub fn size(&self) -> Size2D { Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32) } diff --git a/src/servo/platform/common/shared_gl_windowing.rs b/src/servo/platform/common/shared_gl_windowing.rs index dda49e5c136..a859696a75e 100644 --- a/src/servo/platform/common/shared_gl_windowing.rs +++ b/src/servo/platform/common/shared_gl_windowing.rs @@ -11,7 +11,7 @@ /// along with the Servo process or trusted. If the OpenGL driver itself is untrusted, then this /// windowing implementation is not appropriate. -use compositing::{CompositeCallback, ResizeCallback}; +use windowing::{CompositeCallback, ResizeCallback}; use geom::size::Size2D; use sharegl::base::ShareContext; @@ -20,7 +20,7 @@ use sharegl::platform::Context; /// A structure responsible for setting up and tearing down the entire windowing system. pub struct Application; -impl Application { +impl ApplicationMethods for Application { pub fn new() -> Application { Application } @@ -29,7 +29,7 @@ impl Application { /// The type of a window. pub struct Window(Context); -impl Window { +impl WindowingMethods for Window { /// Creates a new window. pub fn new(_: &Application) -> @mut Window { let share_context: Context = ShareContext::new(Size2D(800, 600)); diff --git a/src/servo/servo.rc b/src/servo/servo.rc index a34e9f7e9d7..b628cd1e598 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -116,6 +116,8 @@ pub mod html { pub mod hubbub_html_parser; } +pub mod windowing; + #[path="platform/mod.rs"] pub mod platform; diff --git a/src/servo/windowing.rs b/src/servo/windowing.rs new file mode 100644 index 00000000000..bd7f0ce510f --- /dev/null +++ b/src/servo/windowing.rs @@ -0,0 +1,34 @@ +/* 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/. */ + +//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. + +use geom::size::Size2D; + +/// Type of the function that is called when the screen is to be redisplayed. +pub type CompositeCallback = @fn(); + +/// Type of the function that is called when the window is resized. +pub type ResizeCallback = @fn(uint, uint); + +/// Methods for an abstract Application. +pub trait ApplicationMethods { + fn new() -> Self; +} + +pub trait WindowMethods { + /// Creates a new window. + pub fn new(app: &A) -> @mut Self; + /// Returns the size of the window. + pub fn size(&self) -> Size2D; + /// Presents the window to the screen (perhaps by page flipping). + pub fn present(&mut self); + /// Registers a callback to run when a composite event occurs. + pub fn set_composite_callback(&mut self, new_composite_callback: CompositeCallback); + /// Registers a callback to run when a resize event occurs. + pub fn set_resize_callback(&mut self, new_resize_callback: ResizeCallback); + /// Spins the event loop. + pub fn check_loop(@mut self); +} +