servo: Allow a render backend to be specified on the command line (-r)

This commit is contained in:
Patrick Walton 2012-11-09 10:51:02 -08:00
parent b1456dac39
commit 013f747fa8
10 changed files with 159 additions and 130 deletions

View file

@ -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<Msg>;
@ -33,6 +34,7 @@ struct Engine<C:Compositor Send Copy> {
}
fn Engine<C:Compositor Send Copy>(compositor: C,
opts: &Opts,
dom_event_port: pipes::Port<Event>,
dom_event_chan: pipes::SharedChan<Event>,
resource_task: ResourceTask,
@ -41,10 +43,11 @@ fn Engine<C:Compositor Send Copy>(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::<Msg> |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());

View file

@ -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 {

View file

@ -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<FontDescriptor, @Font>,
font_list: Option<FontList>, // 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::<FontDescriptor, @Font, cache::MonoCache<FontDescriptor, @Font>>(10),
font_list: move font_list,
handle: move handle,
backend: backend
}
}
@ -116,7 +114,7 @@ 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." }

View file

@ -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 {

View file

@ -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
};

View file

@ -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<Msg>;
pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
pub fn RenderTask<C: Compositor Send>(compositor: C, opts: Opts) -> RenderTask {
let compositor_cell = Cell(move compositor);
do task::spawn_listener |po: comm::Port<Msg>, move compositor_cell| {
let opts_cell = Cell(move opts);
do task::spawn_listener |po: comm::Port<Msg>, 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<C: Compositor Send>(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<C: Compositor Send> {
port: comm::Port<Msg>,
compositor: C,
layer_buffer_set_port: Cell<pipes::Port<LayerBufferSet>>,
font_ctx: @FontContext
font_ctx: @FontContext,
opts: Opts
}
impl<C: Compositor Send> Renderer<C> {
@ -92,11 +87,14 @@ impl<C: Compositor Send> Renderer<C> {
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.

View file

@ -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<Msg>;
@ -67,9 +64,10 @@ struct BuildData {
}
fn LayoutTask(render_task: RenderTask,
img_cache_task: ImageCacheTask) -> LayoutTask {
do spawn_listener::<Msg> |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::<Msg> |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<Msg>) -> Layout {
image_cache_task: ImageCacheTask,
from_content: comm::Port<Msg>,
opts: &Opts) -> Layout {
let fctx = @FontContext::new(true);
let fctx = @FontContext::new(opts.render_backend, true);
Layout {
render_task: render_task,

View file

@ -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,
}
}

View file

@ -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<Msg>;
@ -38,9 +38,9 @@ pub enum Msg {
Exit
}
fn OSMain(dom_event_chan: pipes::SharedChan<Event>) -> OSMain {
fn OSMain(dom_event_chan: pipes::SharedChan<Event>, opts: Opts) -> OSMain {
let dom_event_chan = Cell(move dom_event_chan);
do on_osmain::<Msg> |po, move dom_event_chan| {
do on_osmain::<Msg> |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<Event>) -> 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<Msg>, dom_event_chan: pipes::SharedChan<Event>) {
fn mainloop(mode: Mode,
po: comm::Port<Msg>,
dom_event_chan: pipes::SharedChan<Event>,
opts: &Opts) {
let key_handlers: @DVec<pipes::Chan<()>> = @DVec();
let window;
@ -97,7 +99,7 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
}
}
let surfaces = @SurfaceSet();
let surfaces = @SurfaceSet(opts.render_backend);
let context = layers::rendergl::init_render_context();
@ -137,7 +139,7 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
let mut current_layer_child = root_layer.first_child;
// Replace the image layer data with the buffer data.
let buffers = replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]);
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;
@ -204,7 +206,7 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
let composite: fn@() = || {
//#debug("osmain: drawing to screen");
do util::time::time(~"compositing") {
do time::time(~"compositing") {
adjust_for_window_resizing();
layers::rendergl::render_scene(context, scene);
}
@ -236,7 +238,7 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
ShareWindow(share_context) => {
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<LayerBufferSet>) {
// 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
};

View file

@ -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";
}