From 013f747fa87c4b2803a299338fa8775eb775447e Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 9 Nov 2012 10:51:02 -0800 Subject: [PATCH] servo: Allow a render backend to be specified on the command line (-r) --- src/servo/engine.rs | 29 +++++++++--------- src/servo/gfx/font.rs | 11 +++++-- src/servo/gfx/font_context.rs | 22 +++++++------- src/servo/gfx/render_context.rs | 20 ++++++------- src/servo/gfx/render_layers.rs | 6 ++-- src/servo/gfx/render_task.rs | 48 +++++++++++++++--------------- src/servo/layout/layout_task.rs | 51 ++++++++++++++++---------------- src/servo/opts.rs | 33 ++++++++++++++++++--- src/servo/platform/osmain.rs | 52 +++++++++++++++++---------------- src/servo/servo.rs | 17 +++++------ 10 files changed, 159 insertions(+), 130 deletions(-) diff --git a/src/servo/engine.rs b/src/servo/engine.rs index e3ced2b35bb..76de3a7217b 100644 --- a/src/servo/engine.rs +++ b/src/servo/engine.rs @@ -1,19 +1,20 @@ +use content::content_task::{ContentTask, ExecuteMsg, ParseMsg, ExitMsg}; +use content::content_task; +use dom::event::Event; use gfx::compositor::Compositor; -use mod gfx::render_task; use gfx::render_task::RenderTask; -use task::spawn_listener; +use gfx::render_task; use layout::layout_task; use layout_task::LayoutTask; -use mod content::content_task; -use content::content_task::{ContentTask, ExecuteMsg, ParseMsg, ExitMsg}; -use resource::resource_task; +use opts::Opts; +use resource::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; use resource::resource_task::ResourceTask; -use std::net::url::Url; -use resource::image_cache_task; -use image_cache_task::{ImageCacheTask, image_cache_task, ImageCacheTaskClient}; -use pipes::{Port, Chan}; -use dom::event::Event; +use resource::resource_task; + +use core::pipes::{Port, Chan}; +use core::task::spawn_listener; use std::cell::Cell; +use std::net::url::Url; pub type EngineTask = comm::Chan; @@ -33,6 +34,7 @@ struct Engine { } fn Engine(compositor: C, + opts: &Opts, dom_event_port: pipes::Port, dom_event_chan: pipes::SharedChan, resource_task: ResourceTask, @@ -41,10 +43,11 @@ fn Engine(compositor: C, let dom_event_port = Cell(move dom_event_port); let dom_event_chan = Cell(move dom_event_chan); + let opts = Cell(copy *opts); do spawn_listener:: |request, move dom_event_port, move dom_event_chan, - move image_cache_task| { - let render_task = RenderTask(compositor); - let layout_task = LayoutTask(render_task, image_cache_task.clone()); + move image_cache_task, move opts| { + let render_task = RenderTask(compositor, opts.with_ref(|o| copy *o)); + let layout_task = LayoutTask(render_task, image_cache_task.clone(), opts.take()); let content_task = ContentTask(layout_task, dom_event_port.take(), dom_event_chan.take(), resource_task, image_cache_task.clone()); diff --git a/src/servo/gfx/font.rs b/src/servo/gfx/font.rs index cc051150629..49d3ce14e81 100644 --- a/src/servo/gfx/font.rs +++ b/src/servo/gfx/font.rs @@ -13,7 +13,7 @@ use text::{ TextRun, }; -use azure::azure_hl::CairoBackend; +use azure::azure_hl::BackendType; use core::dvec::DVec; // FontHandle encapsulates access to the platform's font API, @@ -256,6 +256,7 @@ struct Font { priv mut shaper: Option<@Shaper>, style: UsedFontStyle, metrics: FontMetrics, + backend: BackendType, drop { use azure::bindgen::AzReleaseScaledFont; @@ -265,7 +266,10 @@ struct Font { impl Font { // TODO: who should own fontbuf? - static fn new(fontbuf: @~[u8], handle: FontHandle, style: UsedFontStyle) -> Font { + static fn new(fontbuf: @~[u8], + handle: FontHandle, + style: UsedFontStyle, + backend: BackendType) -> Font { let metrics = handle.get_metrics(); Font { @@ -275,6 +279,7 @@ impl Font { shaper: None, style: move style, metrics: move metrics, + backend: backend } } @@ -299,7 +304,7 @@ impl Font { let ct_font = &self.handle.ctfont; let size = self.style.pt_size as AzFloat; - let scaled_font = azure::scaled_font::ScaledFont::new(CairoBackend, ct_font, size); + let scaled_font = azure::scaled_font::ScaledFont::new(self.backend, ct_font, size); let azure_scaled_font; unsafe { diff --git a/src/servo/gfx/font_context.rs b/src/servo/gfx/font_context.rs index e735f7ad6b8..23c2096165e 100644 --- a/src/servo/gfx/font_context.rs +++ b/src/servo/gfx/font_context.rs @@ -1,14 +1,10 @@ -use dvec::DVec; - -use util::cache; -use gfx::{ - FontDescriptor, - FontList, - FontSelector, - FontStyle, -}; +use gfx::{FontDescriptor, FontList, FontSelector, FontStyle}; use gfx::font::{SelectorPlatformName, SelectorStubDummy, SpecifiedFontStyle}; use gfx::native::FontHandle; +use util::cache; + +use azure::azure_hl::BackendType; +use core::dvec::DVec; // TODO(Issue #164): delete, and get default font from font list const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf"); @@ -54,10 +50,11 @@ pub struct FontContext { instance_cache: cache::MonoCache, font_list: Option, // only needed by layout handle: FontContextHandle, + backend: BackendType, } pub impl FontContext { - static fn new(needs_font_list: bool) -> FontContext { + static fn new(backend: BackendType, needs_font_list: bool) -> FontContext { let handle = FontContextHandle::new(); let font_list = if needs_font_list { Some(FontList::new(&handle)) } else { None }; FontContext { @@ -65,6 +62,7 @@ pub impl FontContext { instance_cache: cache::new::>(10), font_list: move font_list, handle: move handle, + backend: backend } } @@ -116,10 +114,10 @@ pub impl FontContext { return Err(handle.get_err()); }; - return Ok(@Font::new(font_bin, move handle, copy desc.style)); + return Ok(@Font::new(font_bin, move handle, copy desc.style, self.backend)); }, // TODO(Issue #174): implement by-platform-name font selectors. SelectorPlatformName(_) => { fail ~"FontContext::create_font_instance() can't yet handle SelectorPlatformName." } } } -} \ No newline at end of file +} diff --git a/src/servo/gfx/render_context.rs b/src/servo/gfx/render_context.rs index ec7208ab827..c82081c0376 100644 --- a/src/servo/gfx/render_context.rs +++ b/src/servo/gfx/render_context.rs @@ -1,28 +1,26 @@ use compositor::LayerBuffer; use gfx::au; -use gfx::{ - Au, - Font, - FontContext, -}; +use gfx::{Au, Font, FontContext}; use image::base::Image; +use opts::Opts; use text::TextRun; use util::range::Range; +use azure::azure_hl::{AsAzureRect, B8G8R8A8, Color, ColorPattern, DrawOptions}; +use azure::azure_hl::{DrawSurfaceOptions, DrawTarget, Linear, StrokeOptions}; +use azure::{AzDrawOptions, AzFloat}; +use core::dvec::DVec; use core::libc::types::common::c99::uint16_t; use core::ptr::to_unsafe_ptr; -use core::dvec::DVec; -use std::arc::ARC; -use geom::size::Size2D; use geom::point::Point2D; use geom::rect::Rect; -use azure::{AzDrawOptions, AzFloat}; -use azure::azure_hl::{AsAzureRect, B8G8R8A8, Color, ColorPattern, DrawOptions, DrawSurfaceOptions, StrokeOptions}; -use azure::azure_hl::{DrawTarget, Linear}; +use geom::size::Size2D; +use std::arc::ARC; struct RenderContext { canvas: &LayerBuffer, font_ctx: @FontContext, + opts: &Opts } impl RenderContext { diff --git a/src/servo/gfx/render_layers.rs b/src/servo/gfx/render_layers.rs index 2bccd8ee04c..1c979409f7d 100644 --- a/src/servo/gfx/render_layers.rs +++ b/src/servo/gfx/render_layers.rs @@ -1,8 +1,9 @@ use gfx::display_list::DisplayList; use gfx::compositor::{LayerBuffer, LayerBufferSet}; +use opts::Opts; use azure::AzFloat; -use azure::azure_hl::{B8G8R8A8, CairoBackend, DrawTarget}; +use azure::azure_hl::{B8G8R8A8, DrawTarget}; use core::libc::c_int; use geom::matrix2d::Matrix2D; use geom::point::Point2D; @@ -23,6 +24,7 @@ pub struct RenderLayer { /// might be the old layer buffer if it had the appropriate size and format). pub fn render_layers(layer: &RenderLayer, buffer_set: LayerBufferSet, + opts: &Opts, f: &fn(layer: &RenderLayer, buffer: &LayerBuffer) -> bool) -> LayerBufferSet { let mut buffers = match move buffer_set { LayerBufferSet { buffers: move b } => move b }; @@ -61,7 +63,7 @@ pub fn render_layers(layer: &RenderLayer, debug!("creating tile, (%u, %u)", x, y); let size = Size2D(stride as i32, height as i32); buffer = LayerBuffer { - draw_target: DrawTarget::new(CairoBackend, size, B8G8R8A8), + draw_target: DrawTarget::new(opts.render_backend, size, B8G8R8A8), rect: tile_rect, stride: stride }; diff --git a/src/servo/gfx/render_task.rs b/src/servo/gfx/render_task.rs index ecc20a0a8c1..788faa20451 100644 --- a/src/servo/gfx/render_task.rs +++ b/src/servo/gfx/render_task.rs @@ -1,26 +1,18 @@ -use comm::*; -use libc::size_t; -use libc::types::common::c99::uint16_t; -use pipes::{Port, Chan}; -use std::cell::Cell; - -use azure::AzFloat; -use geom::matrix2d::Matrix2D; - use dl = display_list; -use gfx::{ - FontContext, - RenderContext, - RenderLayer, -}; -use gfx::compositor::{ - Compositor, - LayerBufferSet, -}; -use mod gfx::render_layers; +use gfx::{FontContext, RenderContext, RenderLayer}; +use gfx::compositor::{Compositor, LayerBufferSet}; +use gfx::render_layers; +use opts::Opts; use platform::osmain; use render_layers::render_layers; +use azure::AzFloat; +use core::comm::*; +use core::libc::size_t; +use core::libc::types::common::c99::uint16_t; +use core::pipes::{Port, Chan}; +use geom::matrix2d::Matrix2D; +use std::cell::Cell; pub enum Msg { RenderMsg(RenderLayer), @@ -29,9 +21,10 @@ pub enum Msg { pub type RenderTask = comm::Chan; -pub fn RenderTask(compositor: C) -> RenderTask { +pub fn RenderTask(compositor: C, opts: Opts) -> RenderTask { let compositor_cell = Cell(move compositor); - do task::spawn_listener |po: comm::Port, move compositor_cell| { + let opts_cell = Cell(move opts); + do task::spawn_listener |po: comm::Port, move compositor_cell, move opts_cell| { let (layer_buffer_channel, layer_buffer_set_port) = pipes::stream(); let compositor = compositor_cell.take(); @@ -41,7 +34,8 @@ pub fn RenderTask(compositor: C) -> RenderTask { port: po, compositor: move compositor, mut layer_buffer_set_port: Cell(move layer_buffer_set_port), - font_ctx: @FontContext::new(false), + font_ctx: @FontContext::new(opts_cell.with_ref(|o| o.render_backend), false), + opts: opts_cell.take() }.start(); } } @@ -50,7 +44,8 @@ priv struct Renderer { port: comm::Port, compositor: C, layer_buffer_set_port: Cell>, - font_ctx: @FontContext + font_ctx: @FontContext, + opts: Opts } impl Renderer { @@ -92,11 +87,14 @@ impl Renderer { let layer_buffer_set = layer_buffer_set_cell.take(); let layer_buffer_set_channel = layer_buffer_set_channel_cell.take(); - let layer_buffer_set = for render_layers(&render_layer, move layer_buffer_set) + let layer_buffer_set = for render_layers(&render_layer, + move layer_buffer_set, + &self.opts) |render_layer, layer_buffer| { let ctx = RenderContext { canvas: layer_buffer, - font_ctx: self.font_ctx + font_ctx: self.font_ctx, + opts: &self.opts }; // Apply the translation to render the tile we want. diff --git a/src/servo/layout/layout_task.rs b/src/servo/layout/layout_task.rs index f77b5cdea71..f923a328c2e 100644 --- a/src/servo/layout/layout_task.rs +++ b/src/servo/layout/layout_task.rs @@ -4,40 +4,37 @@ */ use content::content_task; -use core::dvec::DVec; -use newcss::stylesheet::Stylesheet; +use css::select::new_css_select_ctx; use dom::event::{Event, ReflowEvent}; use dom::node::{Node, LayoutData}; -use geom::point::Point2D; -use geom::rect::Rect; -use geom::size::Size2D; -use gfx::{au, dl}; -use gfx::{ - Au, - DisplayList, - FontContext, - RenderLayer, -}; use gfx::render_task; +use gfx::{Au, DisplayList, FontContext, RenderLayer}; +use gfx::{au, dl}; use layout::box::RenderBox; use layout::box_builder::LayoutTreeBuilder; use layout::context::LayoutContext; +use layout::traverse::*; use opt = core::option; +use opts::Opts; use render_task::RenderTask; use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg}; use resource::local_image_cache::LocalImageCache; -use std::arc::ARC; -use std::net::url::Url; -use core::util::replace; use util::time::time; -use std::cell::Cell; -use layout::traverse::*; -use comm::*; -use task::*; + +use core::comm::*; +use core::dvec::DVec; use core::mutable::Mut; +use core::task::*; +use core::util::replace; +use geom::point::Point2D; +use geom::rect::Rect; +use geom::size::Size2D; use newcss::select::SelectCtx; +use newcss::stylesheet::Stylesheet; use newcss::types::OriginAuthor; -use css::select::new_css_select_ctx; +use std::arc::ARC; +use std::cell::Cell; +use std::net::url::Url; pub type LayoutTask = comm::Chan; @@ -67,9 +64,10 @@ struct BuildData { } fn LayoutTask(render_task: RenderTask, - img_cache_task: ImageCacheTask) -> LayoutTask { - do spawn_listener:: |from_content, move img_cache_task| { - Layout(render_task, img_cache_task.clone(), from_content).start(); + img_cache_task: ImageCacheTask, + opts: Opts) -> LayoutTask { + do spawn_listener:: |from_content, move img_cache_task, move opts| { + Layout(render_task, img_cache_task.clone(), from_content, &opts).start(); } } @@ -86,10 +84,11 @@ struct Layout { } fn Layout(render_task: RenderTask, - image_cache_task: ImageCacheTask, - from_content: comm::Port) -> Layout { + image_cache_task: ImageCacheTask, + from_content: comm::Port, + opts: &Opts) -> Layout { - let fctx = @FontContext::new(true); + let fctx = @FontContext::new(opts.render_backend, true); Layout { render_task: render_task, diff --git a/src/servo/opts.rs b/src/servo/opts.rs index e3bfb6661fb..4db8cd8a0cd 100644 --- a/src/servo/opts.rs +++ b/src/servo/opts.rs @@ -1,9 +1,13 @@ //! Configuration options for a single run of the servo application. Created //! from command line arguments. +use azure::azure_hl::{BackendType, CairoBackend, CoreGraphicsBackend}; +use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBackend}; + pub struct Opts { urls: ~[~str], - render_mode: RenderMode + render_mode: RenderMode, + render_backend: BackendType } pub enum RenderMode { @@ -18,7 +22,8 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts { let args = args.tail(); let opts = ~[ - getopts::optopt(~"o") + getopts::optopt(~"o"), + getopts::optopt(~"r") ]; let opt_match = match getopts::getopts(args, opts) { @@ -32,13 +37,33 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts { copy opt_match.free }; - let render_mode = match getopts::opt_maybe_str(move opt_match, ~"o") { + let render_mode = match getopts::opt_maybe_str(copy opt_match, ~"o") { Some(move output_file) => { Png(move output_file) } None => { Screen } }; + let render_backend = match getopts::opt_maybe_str(move opt_match, ~"r") { + Some(move backend_str) => { + if backend_str == ~"direct2d" { + Direct2DBackend + } else if backend_str == ~"core-graphics" { + CoreGraphicsBackend + } else if backend_str == ~"core-graphics-accelerated" { + CoreGraphicsAcceleratedBackend + } else if backend_str == ~"cairo" { + CairoBackend + } else if backend_str == ~"skia" { + SkiaBackend + } else { + fail ~"unknown backend type" + } + } + None => CairoBackend + }; + Opts { urls: move urls, - render_mode: move render_mode + render_mode: move render_mode, + render_backend: move render_backend, } } diff --git a/src/servo/platform/osmain.rs b/src/servo/platform/osmain.rs index 4ca2f5097dc..a16b8662b5a 100644 --- a/src/servo/platform/osmain.rs +++ b/src/servo/platform/osmain.rs @@ -1,22 +1,22 @@ use ShareGlContext = sharegl::platform::Context; -use azure::azure_hl; -use azure::azure_hl::{B8G8R8A8, CairoBackend, DataSourceSurface, DrawTarget}; -use azure::azure_hl::{SourceSurfaceMethods}; -use core::util::replace; use dom::event::{Event, ResizeEvent}; -use dvec::DVec; +use gfx::compositor::{Compositor, LayerBuffer, LayerBufferSet}; +use layers::ImageLayer; +use opts::Opts; +use resize_rate_limiter::ResizeRateLimiter; +use util::time; + +use azure::azure_hl::{BackendType, B8G8R8A8, DataSourceSurface, DrawTarget, SourceSurfaceMethods}; +use core::dvec::DVec; +use core::pipes::Chan; +use core::task::TaskBuilder; +use core::util; use geom::matrix::{Matrix4, identity}; use geom::point::Point2D; use geom::rect::Rect; use geom::size::Size2D; -use gfx::compositor::{Compositor, LayerBuffer, LayerBufferSet}; -use layers::ImageLayer; -use pipes::Chan; -use resize_rate_limiter::ResizeRateLimiter; use std::cell::Cell; use std::cmp::FuzzyEq; -use task::TaskBuilder; -use vec::push; pub type OSMain = comm::Chan; @@ -38,9 +38,9 @@ pub enum Msg { Exit } -fn OSMain(dom_event_chan: pipes::SharedChan) -> OSMain { +fn OSMain(dom_event_chan: pipes::SharedChan, opts: Opts) -> OSMain { let dom_event_chan = Cell(move dom_event_chan); - do on_osmain:: |po, move dom_event_chan| { + do on_osmain:: |po, move dom_event_chan, move opts| { do platform::runmain { #debug("preparing to enter main loop"); @@ -51,7 +51,7 @@ fn OSMain(dom_event_chan: pipes::SharedChan) -> OSMain { None => mode = GlutMode } - mainloop(mode, po, dom_event_chan.take()); + mainloop(mode, po, dom_event_chan.take(), &opts); } } } @@ -77,8 +77,10 @@ impl AzureDrawTargetImageData : layers::layers::ImageData { } } -fn mainloop(mode: Mode, po: comm::Port, dom_event_chan: pipes::SharedChan) { - +fn mainloop(mode: Mode, + po: comm::Port, + dom_event_chan: pipes::SharedChan, + opts: &Opts) { let key_handlers: @DVec> = @DVec(); let window; @@ -97,7 +99,7 @@ fn mainloop(mode: Mode, po: comm::Port, dom_event_chan: pipes::SharedChan, dom_event_chan: pipes::SharedChan, dom_event_chan: pipes::SharedChan, dom_event_chan: pipes::SharedChan { loop { check_for_messages(); - do util::time::time(~"compositing") { + do time::time(~"compositing") { layers::rendergl::render_scene(context, scene); } @@ -268,7 +270,7 @@ fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan) { // We are in a position to lend out the surface? assert surfaces.front.have; // Ok then take it - let old_layer_buffers = replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]); + 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 { @@ -303,8 +305,8 @@ fn return_surface(surfaces: &SurfaceSet, layer_buffer_set: LayerBufferSet) { surfaces.back.have = true; } -fn SurfaceSet() -> SurfaceSet { - SurfaceSet { front: Surface(), back: Surface() } +fn SurfaceSet(backend: BackendType) -> SurfaceSet { + SurfaceSet { front: Surface(backend), back: Surface(backend) } } struct Surface { @@ -312,9 +314,9 @@ struct Surface { mut have: bool, } -fn Surface() -> Surface { +fn Surface(backend: BackendType) -> Surface { let layer_buffer = LayerBuffer { - draw_target: DrawTarget::new(CairoBackend, Size2D(800i32, 600i32), B8G8R8A8), + draw_target: DrawTarget::new(backend, Size2D(800i32, 600i32), B8G8R8A8), rect: Rect(Point2D(0u, 0u), Size2D(800u, 600u)), stride: 800 }; diff --git a/src/servo/servo.rs b/src/servo/servo.rs index 2c80cad3cec..18ea420883a 100644 --- a/src/servo/servo.rs +++ b/src/servo/servo.rs @@ -24,24 +24,23 @@ fn main() { #[allow(non_implicitly_copyable_typarams)] fn run(opts: &Opts) { match opts.render_mode { - Screen => run_pipeline_screen(opts.urls), + Screen => run_pipeline_screen(opts), Png(outfile) => { assert opts.urls.is_not_empty(); if opts.urls.len() > 1u { fail ~"servo asks that you stick to a single URL in PNG output mode" } - run_pipeline_png(opts.urls.head(), outfile) + run_pipeline_png(opts, outfile) } } } -fn run_pipeline_screen(urls: &[~str]) { - +fn run_pipeline_screen(opts: &Opts) { let (dom_event_chan, dom_event_port) = pipes::stream(); let dom_event_chan = pipes::SharedChan(move dom_event_chan); // The platform event handler thread - let osmain = OSMain(dom_event_chan.clone()); + let osmain = OSMain(dom_event_chan.clone(), copy *opts); // Send each file to render then wait for keypress let (keypress_to_engine, keypress_from_osmain) = pipes::stream(); @@ -50,10 +49,10 @@ fn run_pipeline_screen(urls: &[~str]) { // Create a servo instance let resource_task = ResourceTask(); let image_cache_task = ImageCacheTask(copy resource_task); - let engine_task = Engine(osmain, move dom_event_port, move dom_event_chan, move resource_task, - move image_cache_task); + let engine_task = Engine(osmain, opts, move dom_event_port, move dom_event_chan, + move resource_task, move image_cache_task); - for urls.each |filename| { + for opts.urls.each |filename| { let url = make_url(copy *filename, None); #debug["master: Sending url `%s`", url.to_str()]; engine_task.send(LoadURLMsg(move url)); @@ -74,7 +73,7 @@ fn run_pipeline_screen(urls: &[~str]) { osmain.send(osmain::Exit); } -fn run_pipeline_png(_url: ~str, _outfile: &str) { +fn run_pipeline_png(_opts: &Opts, _outfile: &str) { fail ~"PNG compositor is broken"; }