aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-02-19 00:54:06 +0530
committerbors-servo <lbergstrom+bors@mozilla.com>2016-02-19 00:54:06 +0530
commitab07b06823ea9748a6091aee2281495f86f00bce (patch)
tree2dd06ac4834d5bc4bcba6e4ada3aab12bb2c12d9 /components
parentfe70efe07f6d72665f10c752884e5705d5bdc600 (diff)
parentc0531c312fdb0783e4d121b4c2d7f15d4f5cdc1f (diff)
downloadservo-ab07b06823ea9748a6091aee2281495f86f00bce.tar.gz
servo-ab07b06823ea9748a6091aee2281495f86f00bce.zip
Auto merge of #9589 - glennw:webrender, r=pcwalton
Add WebRender integration to Servo. WebRender is an experimental GPU accelerated rendering backend for Servo. The WebRender backend can be specified by running Servo with the -w option (otherwise the default rendering backend will be used). WebRender has many bugs, and missing features - but it is usable to browse most websites - please report any WebRender specific rendering bugs you encounter! <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9589) <!-- Reviewable:end -->
Diffstat (limited to 'components')
-rw-r--r--components/canvas/Cargo.toml3
-rw-r--r--components/canvas/canvas_paint_thread.rs39
-rw-r--r--components/canvas/lib.rs2
-rw-r--r--components/canvas/webgl_paint_thread.rs565
-rw-r--r--components/canvas_traits/Cargo.toml3
-rw-r--r--components/canvas_traits/lib.rs194
-rw-r--r--components/compositing/Cargo.toml6
-rw-r--r--components/compositing/compositor.rs321
-rw-r--r--components/compositing/compositor_thread.rs15
-rw-r--r--components/compositing/constellation.rs17
-rw-r--r--components/compositing/lib.rs2
-rw-r--r--components/compositing/pipeline.rs8
-rw-r--r--components/gfx/Cargo.toml3
-rw-r--r--components/gfx/display_list/mod.rs37
-rw-r--r--components/gfx/font.rs2
-rw-r--r--components/gfx/font_cache_thread.rs55
-rw-r--r--components/gfx/font_context.rs31
-rw-r--r--components/gfx/lib.rs1
-rw-r--r--components/gfx/platform/freetype/font_template.rs19
-rw-r--r--components/gfx/platform/macos/font_template.rs36
-rw-r--r--components/gfx/text/text_run.rs3
-rw-r--r--components/layout/Cargo.toml3
-rw-r--r--components/layout/display_list_builder.rs126
-rw-r--r--components/layout/layout_thread.rs56
-rw-r--r--components/layout/lib.rs2
-rw-r--r--components/layout/webrender_helpers.rs481
-rw-r--r--components/layout_traits/Cargo.toml3
-rw-r--r--components/layout_traits/lib.rs4
-rw-r--r--components/msg/Cargo.toml3
-rw-r--r--components/msg/constellation_msg.rs30
-rw-r--r--components/msg/lib.rs1
-rw-r--r--components/net/Cargo.toml3
-rw-r--r--components/net/image_cache_thread.rs63
-rw-r--r--components/net/lib.rs1
-rw-r--r--components/net_traits/image/base.rs20
-rw-r--r--components/script/dom/htmlcanvaselement.rs13
-rw-r--r--components/script/dom/webglrenderingcontext.rs2
-rw-r--r--components/servo/Cargo.lock88
-rw-r--r--components/servo/Cargo.toml6
-rw-r--r--components/servo/lib.rs49
-rw-r--r--components/util/opts.rs28
41 files changed, 1513 insertions, 831 deletions
diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml
index 96f7a3c0777..34451e67931 100644
--- a/components/canvas/Cargo.toml
+++ b/components/canvas/Cargo.toml
@@ -33,6 +33,9 @@ git = "https://github.com/ecoal95/rust-offscreen-rendering-context"
[dependencies.ipc-channel]
git = "https://github.com/servo/ipc-channel"
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
[dependencies]
log = "0.3"
num = "0.1.24"
diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs
index 92b3863cdf9..1bcf294d3b6 100644
--- a/components/canvas/canvas_paint_thread.rs
+++ b/components/canvas/canvas_paint_thread.rs
@@ -24,6 +24,7 @@ use std::sync::mpsc::{Sender, channel};
use util::opts;
use util::thread::spawn_named;
use util::vec::byte_swap;
+use webrender_traits;
impl<'a> CanvasPaintThread<'a> {
/// It reads image data from the canvas
@@ -63,6 +64,8 @@ pub struct CanvasPaintThread<'a> {
path_builder: PathBuilder,
state: CanvasPaintState<'a>,
saved_states: Vec<CanvasPaintState<'a>>,
+ webrender_api: Option<webrender_traits::RenderApi>,
+ webrender_image_key: Option<webrender_traits::ImageKey>,
}
#[derive(Clone)]
@@ -102,27 +105,34 @@ impl<'a> CanvasPaintState<'a> {
}
impl<'a> CanvasPaintThread<'a> {
- fn new(size: Size2D<i32>) -> CanvasPaintThread<'a> {
+ fn new(size: Size2D<i32>,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> CanvasPaintThread<'a> {
let draw_target = CanvasPaintThread::create(size);
let path_builder = draw_target.create_path_builder();
+ let webrender_api = webrender_api_sender.map(|wr| wr.create_api());
+ let webrender_image_key = webrender_api.as_ref().map(|wr| wr.alloc_image());
CanvasPaintThread {
drawtarget: draw_target,
path_builder: path_builder,
state: CanvasPaintState::new(),
saved_states: Vec::new(),
+ webrender_api: webrender_api,
+ webrender_image_key: webrender_image_key,
}
}
/// Creates a new `CanvasPaintThread` and returns the out-of-process sender and the in-process
/// sender for it.
- pub fn start(size: Size2D<i32>) -> (IpcSender<CanvasMsg>, Sender<CanvasMsg>) {
+ pub fn start(size: Size2D<i32>,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>)
+ -> (IpcSender<CanvasMsg>, Sender<CanvasMsg>) {
// TODO(pcwalton): Ask the pipeline to create this for us instead of spawning it directly.
// This will be needed for multiprocess Servo.
let (out_of_process_chan, out_of_process_port) = ipc::channel::<CanvasMsg>().unwrap();
let (in_process_chan, in_process_port) = channel();
ROUTER.route_ipc_receiver_to_mpsc_sender(out_of_process_port, in_process_chan.clone());
spawn_named("CanvasThread".to_owned(), move || {
- let mut painter = CanvasPaintThread::new(size);
+ let mut painter = CanvasPaintThread::new(size, webrender_api_sender);
loop {
let msg = in_process_port.recv();
match msg.unwrap() {
@@ -190,8 +200,8 @@ impl<'a> CanvasPaintThread<'a> {
},
CanvasMsg::FromLayout(message) => {
match message {
- FromLayoutMsg::SendPixelContents(chan) => {
- painter.send_pixel_contents(chan)
+ FromLayoutMsg::SendData(chan) => {
+ painter.send_data(chan)
}
}
}
@@ -519,9 +529,24 @@ impl<'a> CanvasPaintThread<'a> {
self.drawtarget = CanvasPaintThread::create(size);
}
- fn send_pixel_contents(&mut self, chan: IpcSender<IpcSharedMemory>) {
+ fn send_data(&mut self, chan: IpcSender<CanvasData>) {
self.drawtarget.snapshot().get_data_surface().with_data(|element| {
- chan.send(IpcSharedMemory::from_bytes(element)).unwrap();
+ if let Some(ref webrender_api) = self.webrender_api {
+ let size = self.drawtarget.get_size();
+ let mut bytes = Vec::new();
+ bytes.extend_from_slice(element);
+ webrender_api.update_image(self.webrender_image_key.unwrap(),
+ size.width as u32,
+ size.height as u32,
+ webrender_traits::ImageFormat::RGBA8,
+ bytes);
+ }
+
+ let pixel_data = CanvasPixelData {
+ image_data: IpcSharedMemory::from_bytes(element),
+ image_key: self.webrender_image_key,
+ };
+ chan.send(CanvasData::Pixels(pixel_data)).unwrap();
})
}
diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs
index 7377e0385c7..5ee82053005 100644
--- a/components/canvas/lib.rs
+++ b/components/canvas/lib.rs
@@ -2,7 +2,6 @@
* 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/. */
-#![feature(nonzero)]
#![feature(plugin)]
#![plugin(plugins)]
@@ -19,6 +18,7 @@ extern crate log;
extern crate num;
extern crate offscreen_gl_context;
extern crate util;
+extern crate webrender_traits;
pub mod canvas_paint_thread;
mod premultiplytable;
diff --git a/components/canvas/webgl_paint_thread.rs b/components/canvas/webgl_paint_thread.rs
index 913ef1b33ce..271ba0e2052 100644
--- a/components/canvas/webgl_paint_thread.rs
+++ b/components/canvas/webgl_paint_thread.rs
@@ -2,9 +2,8 @@
* 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 canvas_traits::{CanvasCommonMsg, CanvasMsg, CanvasWebGLMsg, FromLayoutMsg, FromPaintMsg};
-use canvas_traits::{WebGLError, WebGLFramebufferBindingRequest, WebGLParameter, WebGLResult};
-use core::nonzero::NonZero;
+use canvas_traits::{CanvasCommonMsg, CanvasMsg, CanvasPixelData, CanvasData, CanvasWebGLMsg};
+use canvas_traits::{FromLayoutMsg, FromPaintMsg};
use euclid::size::Size2D;
use gleam::gl;
use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
@@ -15,186 +14,59 @@ use std::borrow::ToOwned;
use std::sync::mpsc::{Sender, channel};
use util::thread::spawn_named;
use util::vec::byte_swap;
+use webrender_traits;
+
+enum WebGLPaintTaskData {
+ WebRender(webrender_traits::RenderApi, webrender_traits::WebGLContextId),
+ Servo(GLContext<NativeGLContext>),
+}
pub struct WebGLPaintThread {
size: Size2D<i32>,
- original_context_size: Size2D<i32>,
- gl_context: GLContext<NativeGLContext>,
+ data: WebGLPaintTaskData,
}
impl WebGLPaintThread {
- fn new(size: Size2D<i32>, attrs: GLContextAttributes) -> Result<WebGLPaintThread, &'static str> {
- let context = try!(GLContext::new(size, attrs, ColorAttachmentType::Texture, None));
-
- // NOTE: As of right now this is always equal to the size parameter,
- // but this doesn't have to be true. Firefox after failing with
- // the requested size, tries with the nearest powers of two, for example.
- let real_size = context.borrow_draw_buffer().unwrap().size();
+ fn new(size: Size2D<i32>,
+ attrs: GLContextAttributes,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Result<WebGLPaintThread, String> {
+ let data = if let Some(sender) = webrender_api_sender {
+ let webrender_api = sender.create_api();
+ let id = try!(webrender_api.request_webgl_context(&size, attrs));
+ WebGLPaintTaskData::WebRender(webrender_api, id)
+ } else {
+ let context = try!(GLContext::<NativeGLContext>::new(size, attrs, ColorAttachmentType::Texture, None));
+ WebGLPaintTaskData::Servo(context)
+ };
Ok(WebGLPaintThread {
- size: real_size,
- original_context_size: real_size,
- gl_context: context
+ size: size,
+ data: data,
})
}
- /// In this function the gl commands are called.
- /// Those messages that just involve a gl call have the call inlined,
- /// processing of messages that require extra work are moved to functions
- ///
- /// NB: Not gl-related validations (names, lengths, accepted parameters...) are
- /// done in the corresponding DOM interfaces
pub fn handle_webgl_message(&self, message: CanvasWebGLMsg) {
debug!("WebGL message: {:?}", message);
-
- match message {
- CanvasWebGLMsg::GetContextAttributes(sender) =>
- self.context_attributes(sender),
- CanvasWebGLMsg::ActiveTexture(target) =>
- gl::active_texture(target),
- CanvasWebGLMsg::AttachShader(program_id, shader_id) =>
- gl::attach_shader(program_id, shader_id),
- CanvasWebGLMsg::BindAttribLocation(program_id, index, name) =>
- gl::bind_attrib_location(program_id, index, &name),
- CanvasWebGLMsg::BlendColor(r, g, b, a) =>
- gl::blend_color(r, g, b, a),
- CanvasWebGLMsg::BlendEquation(mode) =>
- gl::blend_equation(mode),
- CanvasWebGLMsg::BlendEquationSeparate(mode_rgb, mode_alpha) =>
- gl::blend_equation_separate(mode_rgb, mode_alpha),
- CanvasWebGLMsg::BlendFunc(src, dest) =>
- gl::blend_func(src, dest),
- CanvasWebGLMsg::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) =>
- gl::blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha),
- CanvasWebGLMsg::BufferData(buffer_type, data, usage) =>
- gl::buffer_data(buffer_type, &data, usage),
- CanvasWebGLMsg::BufferSubData(buffer_type, offset, data) =>
- gl::buffer_sub_data(buffer_type, offset, &data),
- CanvasWebGLMsg::Clear(mask) =>
- gl::clear(mask),
- CanvasWebGLMsg::ClearColor(r, g, b, a) =>
- gl::clear_color(r, g, b, a),
- CanvasWebGLMsg::ClearDepth(depth) =>
- gl::clear_depth(depth),
- CanvasWebGLMsg::ClearStencil(stencil) =>
- gl::clear_stencil(stencil),
- CanvasWebGLMsg::ColorMask(r, g, b, a) =>
- gl::color_mask(r, g, b, a),
- CanvasWebGLMsg::CullFace(mode) =>
- gl::cull_face(mode),
- CanvasWebGLMsg::DepthFunc(func) =>
- gl::depth_func(func),
- CanvasWebGLMsg::DepthMask(flag) =>
- gl::depth_mask(flag),
- CanvasWebGLMsg::DepthRange(near, far) =>
- gl::depth_range(near, far),
- CanvasWebGLMsg::Disable(cap) =>
- gl::disable(cap),
- CanvasWebGLMsg::Enable(cap) =>
- gl::enable(cap),
- CanvasWebGLMsg::FrontFace(mode) =>
- gl::front_face(mode),
- CanvasWebGLMsg::DrawArrays(mode, first, count) =>
- gl::draw_arrays(mode, first, count),
- CanvasWebGLMsg::DrawElements(mode, count, type_, offset) =>
- gl::draw_elements(mode, count, type_, offset as u32),
- CanvasWebGLMsg::Hint(name, val) =>
- gl::hint(name, val),
- CanvasWebGLMsg::LineWidth(width) =>
- gl::line_width(width),
- CanvasWebGLMsg::PixelStorei(name, val) =>
- gl::pixel_store_i(name, val),
- CanvasWebGLMsg::PolygonOffset(factor, units) =>
- gl::polygon_offset(factor, units),
- CanvasWebGLMsg::Scissor(x, y, width, height) =>
- gl::scissor(x, y, width, height),
- CanvasWebGLMsg::EnableVertexAttribArray(attrib_id) =>
- gl::enable_vertex_attrib_array(attrib_id),
- CanvasWebGLMsg::GetAttribLocation(program_id, name, chan) =>
- self.attrib_location(program_id, name, chan),
- CanvasWebGLMsg::GetBufferParameter(target, param_id, chan) =>
- self.buffer_parameter(target, param_id, chan),
- CanvasWebGLMsg::GetParameter(param_id, chan) =>
- self.parameter(param_id, chan),
- CanvasWebGLMsg::GetProgramParameter(program_id, param_id, chan) =>
- self.program_parameter(program_id, param_id, chan),
- CanvasWebGLMsg::GetShaderParameter(shader_id, param_id, chan) =>
- self.shader_parameter(shader_id, param_id, chan),
- CanvasWebGLMsg::GetUniformLocation(program_id, name, chan) =>
- self.uniform_location(program_id, name, chan),
- CanvasWebGLMsg::CompileShader(shader_id, source) =>
- self.compile_shader(shader_id, source),
- CanvasWebGLMsg::CreateBuffer(chan) =>
- self.create_buffer(chan),
- CanvasWebGLMsg::CreateFramebuffer(chan) =>
- self.create_framebuffer(chan),
- CanvasWebGLMsg::CreateRenderbuffer(chan) =>
- self.create_renderbuffer(chan),
- CanvasWebGLMsg::CreateTexture(chan) =>
- self.create_texture(chan),
- CanvasWebGLMsg::CreateProgram(chan) =>
- self.create_program(chan),
- CanvasWebGLMsg::CreateShader(shader_type, chan) =>
- self.create_shader(shader_type, chan),
- CanvasWebGLMsg::DeleteBuffer(id) =>
- gl::delete_buffers(&[id]),
- CanvasWebGLMsg::DeleteFramebuffer(id) =>
- gl::delete_framebuffers(&[id]),
- CanvasWebGLMsg::DeleteRenderbuffer(id) =>
- gl::delete_renderbuffers(&[id]),
- CanvasWebGLMsg::DeleteTexture(id) =>
- gl::delete_textures(&[id]),
- CanvasWebGLMsg::DeleteProgram(id) =>
- gl::delete_program(id),
- CanvasWebGLMsg::DeleteShader(id) =>
- gl::delete_shader(id),
- CanvasWebGLMsg::BindBuffer(target, id) =>
- gl::bind_buffer(target, id),
- CanvasWebGLMsg::BindFramebuffer(target, request) =>
- self.bind_framebuffer(target, request),
- CanvasWebGLMsg::BindRenderbuffer(target, id) =>
- gl::bind_renderbuffer(target, id),
- CanvasWebGLMsg::BindTexture(target, id) =>
- gl::bind_texture(target, id),
- CanvasWebGLMsg::LinkProgram(program_id) =>
- gl::link_program(program_id),
- CanvasWebGLMsg::Uniform1f(uniform_id, x) =>
- gl::uniform_1f(uniform_id, x),
- CanvasWebGLMsg::Uniform4f(uniform_id, x, y, z, w) =>
- gl::uniform_4f(uniform_id, x, y, z, w),
- CanvasWebGLMsg::UseProgram(program_id) =>
- gl::use_program(program_id),
- CanvasWebGLMsg::VertexAttrib(attrib_id, x, y, z, w) =>
- gl::vertex_attrib_4f(attrib_id, x, y, z, w),
- CanvasWebGLMsg::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) =>
- gl::vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset as u32),
- CanvasWebGLMsg::Viewport(x, y, width, height) =>
- gl::viewport(x, y, width, height),
- CanvasWebGLMsg::TexImage2D(target, level, internal, width, height, format, data_type, data) =>
- gl::tex_image_2d(target, level, internal, width, height, /*border*/0, format, data_type, Some(&data)),
- CanvasWebGLMsg::TexParameteri(target, name, value) =>
- gl::tex_parameter_i(target, name, value),
- CanvasWebGLMsg::TexParameterf(target, name, value) =>
- gl::tex_parameter_f(target, name, value),
- CanvasWebGLMsg::DrawingBufferWidth(sender) =>
- self.send_drawing_buffer_width(sender),
- CanvasWebGLMsg::DrawingBufferHeight(sender) =>
- self.send_drawing_buffer_height(sender),
+ match self.data {
+ WebGLPaintTaskData::WebRender(ref api, id) => {
+ api.send_webgl_command(id, message);
+ }
+ WebGLPaintTaskData::Servo(ref ctx) => {
+ message.apply(ctx);
+ }
}
-
- // FIXME: Use debug_assertions once tests are run with them
- let error = gl::get_error();
- assert!(error == gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error);
}
/// Creates a new `WebGLPaintThread` and returns the out-of-process sender and the in-process
/// sender for it.
- pub fn start(size: Size2D<i32>, attrs: GLContextAttributes)
- -> Result<(IpcSender<CanvasMsg>, Sender<CanvasMsg>), &'static str> {
+ pub fn start(size: Size2D<i32>,
+ attrs: GLContextAttributes,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>)
+ -> Result<(IpcSender<CanvasMsg>, Sender<CanvasMsg>), String> {
let (in_process_chan, in_process_port) = channel();
let (result_chan, result_port) = channel();
spawn_named("WebGLThread".to_owned(), move || {
- let mut painter = match WebGLPaintThread::new(size, attrs) {
+ let mut painter = match WebGLPaintThread::new(size, attrs, webrender_api_sender) {
Ok(thread) => {
result_chan.send(Ok(())).unwrap();
thread
@@ -217,8 +89,8 @@ impl WebGLPaintThread {
},
CanvasMsg::FromLayout(message) => {
match message {
- FromLayoutMsg::SendPixelContents(chan) =>
- painter.send_pixel_contents(chan),
+ FromLayoutMsg::SendData(chan) =>
+ painter.send_data(chan),
}
}
CanvasMsg::FromPaint(message) => {
@@ -239,319 +111,40 @@ impl WebGLPaintThread {
})
}
- #[inline]
- fn context_attributes(&self, sender: IpcSender<GLContextAttributes>) {
- sender.send(*self.gl_context.borrow_attributes()).unwrap()
- }
-
- #[inline]
- fn send_drawing_buffer_width(&self, sender: IpcSender<i32>) {
- sender.send(self.size.width).unwrap()
- }
-
- #[inline]
- fn send_drawing_buffer_height(&self, sender: IpcSender<i32>) {
- sender.send(self.size.height).unwrap()
- }
-
- fn create_buffer(&self, chan: IpcSender<Option<NonZero<u32>>>) {
- let buffer = gl::gen_buffers(1)[0];
- let buffer = if buffer == 0 {
- None
- } else {
- Some(unsafe { NonZero::new(buffer) })
- };
- chan.send(buffer).unwrap();
- }
-
- fn create_framebuffer(&self, chan: IpcSender<Option<NonZero<u32>>>) {
- let framebuffer = gl::gen_framebuffers(1)[0];
- let framebuffer = if framebuffer == 0 {
- None
- } else {
- Some(unsafe { NonZero::new(framebuffer) })
- };
- chan.send(framebuffer).unwrap();
- }
-
- fn create_renderbuffer(&self, chan: IpcSender<Option<NonZero<u32>>>) {
- let renderbuffer = gl::gen_renderbuffers(1)[0];
- let renderbuffer = if renderbuffer == 0 {
- None
- } else {
- Some(unsafe { NonZero::new(renderbuffer) })
- };
- chan.send(renderbuffer).unwrap();
- }
-
- fn create_texture(&self, chan: IpcSender<Option<NonZero<u32>>>) {
- let texture = gl::gen_framebuffers(1)[0];
- let texture = if texture == 0 {
- None
- } else {
- Some(unsafe { NonZero::new(texture) })
- };
- chan.send(texture).unwrap();
- }
-
- fn create_program(&self, chan: IpcSender<Option<NonZero<u32>>>) {
- let program = gl::create_program();
- let program = if program == 0 {
- None
- } else {
- Some(unsafe { NonZero::new(program) })
- };
-
- chan.send(program).unwrap();
- }
-
- fn create_shader(&self, shader_type: u32, chan: IpcSender<Option<NonZero<u32>>>) {
- let shader = gl::create_shader(shader_type);
- let shader = if shader == 0 {
- None
- } else {
- Some(unsafe { NonZero::new(shader) })
- };
- chan.send(shader).unwrap();
- }
-
- #[inline]
- fn bind_framebuffer(&self, target: u32, request: WebGLFramebufferBindingRequest) {
- let id = match request {
- WebGLFramebufferBindingRequest::Explicit(id) => id,
- WebGLFramebufferBindingRequest::Default =>
- self.gl_context.borrow_draw_buffer().unwrap().get_framebuffer(),
- };
-
- gl::bind_framebuffer(target, id);
- }
-
- #[inline]
- fn compile_shader(&self, shader_id: u32, source: String) {
- gl::shader_source(shader_id, &[source.as_bytes()]);
- gl::compile_shader(shader_id);
- }
-
- fn attrib_location(&self, program_id: u32, name: String, chan: IpcSender<Option<i32>> ) {
- let attrib_location = gl::get_attrib_location(program_id, &name);
-
- let attrib_location = if attrib_location == -1 {
- None
- } else {
- Some(attrib_location)
- };
-
- chan.send(attrib_location).unwrap();
- }
-
- fn parameter(&self,
- param_id: u32,
- chan: IpcSender<WebGLResult<WebGLParameter>>) {
- let result = match param_id {
- gl::ACTIVE_TEXTURE |
- //gl::ALPHA_BITS |
- gl::BLEND_DST_ALPHA |
- gl::BLEND_DST_RGB |
- gl::BLEND_EQUATION_ALPHA |
- gl::BLEND_EQUATION_RGB |
- gl::BLEND_SRC_ALPHA |
- gl::BLEND_SRC_RGB |
- //gl::BLUE_BITS |
- gl::CULL_FACE_MODE |
- //gl::DEPTH_BITS |
- gl::DEPTH_FUNC |
- gl::FRONT_FACE |
- //gl::GENERATE_MIPMAP_HINT |
- //gl::GREEN_BITS |
- //gl::IMPLEMENTATION_COLOR_READ_FORMAT |
- //gl::IMPLEMENTATION_COLOR_READ_TYPE |
- gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS |
- gl::MAX_CUBE_MAP_TEXTURE_SIZE |
- //gl::MAX_FRAGMENT_UNIFORM_VECTORS |
- gl::MAX_RENDERBUFFER_SIZE |
- gl::MAX_TEXTURE_IMAGE_UNITS |
- gl::MAX_TEXTURE_SIZE |
- //gl::MAX_VARYING_VECTORS |
- gl::MAX_VERTEX_ATTRIBS |
- gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS |
- //gl::MAX_VERTEX_UNIFORM_VECTORS |
- gl::PACK_ALIGNMENT |
- //gl::RED_BITS |
- gl::SAMPLE_BUFFERS |
- gl::SAMPLES |
- gl::STENCIL_BACK_FAIL |
- gl::STENCIL_BACK_FUNC |
- gl::STENCIL_BACK_PASS_DEPTH_FAIL |
- gl::STENCIL_BACK_PASS_DEPTH_PASS |
- gl::STENCIL_BACK_REF |
- gl::STENCIL_BACK_VALUE_MASK |
- gl::STENCIL_BACK_WRITEMASK |
- //gl::STENCIL_BITS |
- gl::STENCIL_CLEAR_VALUE |
- gl::STENCIL_FAIL |
- gl::STENCIL_FUNC |
- gl::STENCIL_PASS_DEPTH_FAIL |
- gl::STENCIL_PASS_DEPTH_PASS |
- gl::STENCIL_REF |
- gl::STENCIL_VALUE_MASK |
- gl::STENCIL_WRITEMASK |
- gl::SUBPIXEL_BITS |
- gl::UNPACK_ALIGNMENT =>
- //gl::UNPACK_COLORSPACE_CONVERSION_WEBGL =>
- Ok(WebGLParameter::Int(gl::get_integer_v(param_id))),
-
- gl::BLEND |
- gl::CULL_FACE |
- gl::DEPTH_TEST |
- gl::DEPTH_WRITEMASK |
- gl::DITHER |
- gl::POLYGON_OFFSET_FILL |
- gl::SAMPLE_COVERAGE_INVERT |
- gl::STENCIL_TEST =>
- //gl::UNPACK_FLIP_Y_WEBGL |
- //gl::UNPACK_PREMULTIPLY_ALPHA_WEBGL =>
- Ok(WebGLParameter::Bool(gl::get_boolean_v(param_id) != 0)),
-
- gl::DEPTH_CLEAR_VALUE |
- gl::LINE_WIDTH |
- gl::POLYGON_OFFSET_FACTOR |
- gl::POLYGON_OFFSET_UNITS |
- gl::SAMPLE_COVERAGE_VALUE =>
- Ok(WebGLParameter::Float(gl::get_float_v(param_id))),
-
- gl::VERSION => Ok(WebGLParameter::String("WebGL 1.0".to_owned())),
- gl::RENDERER |
- gl::VENDOR => Ok(WebGLParameter::String("Mozilla/Servo".to_owned())),
- gl::SHADING_LANGUAGE_VERSION => Ok(WebGLParameter::String("WebGL GLSL ES 1.0".to_owned())),
-
- // TODO(zbarsky, ecoal95): Implement support for the following valid parameters
- // Float32Array
- gl::ALIASED_LINE_WIDTH_RANGE |
- //gl::ALIASED_POINT_SIZE_RANGE |
- //gl::BLEND_COLOR |
- gl::COLOR_CLEAR_VALUE |
- gl::DEPTH_RANGE |
-
- // WebGLBuffer
- gl::ARRAY_BUFFER_BINDING |
- gl::ELEMENT_ARRAY_BUFFER_BINDING |
-
- // WebGLFrameBuffer
- gl::FRAMEBUFFER_BINDING |
-
- // WebGLRenderBuffer
- gl::RENDERBUFFER_BINDING |
-
- // WebGLProgram
- gl::CURRENT_PROGRAM |
-
- // WebGLTexture
- gl::TEXTURE_BINDING_2D |
- gl::TEXTURE_BINDING_CUBE_MAP |
-
- // sequence<GlBoolean>
- gl::COLOR_WRITEMASK |
-
- // Uint32Array
- gl::COMPRESSED_TEXTURE_FORMATS |
-
- // Int32Array
- gl::MAX_VIEWPORT_DIMS |
- gl::SCISSOR_BOX |
- gl::VIEWPORT => Err(WebGLError::InvalidEnum),
-
- // Invalid parameters
- _ => Err(WebGLError::InvalidEnum)
- };
-
- chan.send(result).unwrap();
- }
-
- fn buffer_parameter(&self,
- target: u32,
- param_id: u32,
- chan: IpcSender<WebGLResult<WebGLParameter>>) {
- let result = match param_id {
- gl::BUFFER_SIZE |
- gl::BUFFER_USAGE =>
- Ok(WebGLParameter::Int(gl::get_buffer_parameter_iv(target, param_id))),
- _ => Err(WebGLError::InvalidEnum),
- };
-
- chan.send(result).unwrap();
- }
-
- fn program_parameter(&self,
- program_id: u32,
- param_id: u32,
- chan: IpcSender<WebGLResult<WebGLParameter>>) {
- let result = match param_id {
- gl::DELETE_STATUS |
- gl::LINK_STATUS |
- gl::VALIDATE_STATUS =>
- Ok(WebGLParameter::Bool(gl::get_program_iv(program_id, param_id) != 0)),
- gl::ATTACHED_SHADERS |
- gl::ACTIVE_ATTRIBUTES |
- gl::ACTIVE_UNIFORMS =>
- Ok(WebGLParameter::Int(gl::get_program_iv(program_id, param_id))),
- _ => Err(WebGLError::InvalidEnum),
- };
-
- chan.send(result).unwrap();
- }
-
- fn shader_parameter(&self,
- shader_id: u32,
- param_id: u32,
- chan: IpcSender<WebGLResult<WebGLParameter>>) {
- let result = match param_id {
- gl::SHADER_TYPE =>
- Ok(WebGLParameter::Int(gl::get_shader_iv(shader_id, param_id))),
- gl::DELETE_STATUS |
- gl::COMPILE_STATUS =>
- Ok(WebGLParameter::Bool(gl::get_shader_iv(shader_id, param_id) != 0)),
- _ => Err(WebGLError::InvalidEnum),
- };
-
- chan.send(result).unwrap();
- }
-
- fn uniform_location(&self, program_id: u32, name: String, chan: IpcSender<Option<i32>>) {
- let location = gl::get_uniform_location(program_id, &name);
- let location = if location == -1 {
- None
- } else {
- Some(location)
- };
+ fn send_data(&mut self, chan: IpcSender<CanvasData>) {
+ match self.data {
+ WebGLPaintTaskData::Servo(_) => {
+ let width = self.size.width as usize;
+ let height = self.size.height as usize;
+
+ let mut pixels = gl::read_pixels(0, 0,
+ self.size.width as gl::GLsizei,
+ self.size.height as gl::GLsizei,
+ gl::RGBA, gl::UNSIGNED_BYTE);
+ // flip image vertically (texture is upside down)
+ let orig_pixels = pixels.clone();
+ let stride = width * 4;
+ for y in 0..height {
+ let dst_start = y * stride;
+ let src_start = (height - y - 1) * stride;
+ let src_slice = &orig_pixels[src_start .. src_start + stride];
+ (&mut pixels[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]);
+ }
- chan.send(location).unwrap();
- }
+ // rgba -> bgra
+ byte_swap(&mut pixels);
- fn send_pixel_contents(&mut self, chan: IpcSender<IpcSharedMemory>) {
- // FIXME(#5652, dmarcos) Instead of a readback strategy we have
- // to layerize the canvas.
- // TODO(pcwalton): We'd save a copy if we had an `IpcSharedMemoryBuilder` abstraction that
- // allowed you to mutate in-place before freezing the object for sending.
- let width = self.size.width as usize;
- let height = self.size.height as usize;
+ let pixel_data = CanvasPixelData {
+ image_data: IpcSharedMemory::from_bytes(&pixels[..]),
+ image_key: None,
+ };
- let mut pixels = gl::read_pixels(0, 0,
- self.size.width as gl::GLsizei,
- self.size.height as gl::GLsizei,
- gl::RGBA, gl::UNSIGNED_BYTE);
- // flip image vertically (texture is upside down)
- let orig_pixels = pixels.clone();
- let stride = width * 4;
- for y in 0..height {
- let dst_start = y * stride;
- let src_start = (height - y - 1) * stride;
- let src_slice = &orig_pixels[src_start .. src_start + stride];
- (&mut pixels[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]);
+ chan.send(CanvasData::Pixels(pixel_data)).unwrap();
+ }
+ WebGLPaintTaskData::WebRender(_, id) => {
+ chan.send(CanvasData::WebGL(id)).unwrap();
+ }
}
-
- // rgba -> bgra
- byte_swap(&mut pixels);
- chan.send(IpcSharedMemory::from_bytes(&pixels[..])).unwrap();
}
fn send_native_surface(&self, _: Sender<NativeSurface>) {
@@ -561,18 +154,28 @@ impl WebGLPaintThread {
}
fn recreate(&mut self, size: Size2D<i32>) -> Result<(), &'static str> {
- if size.width > self.original_context_size.width ||
- size.height > self.original_context_size.height {
- try!(self.gl_context.resize(size));
- self.size = self.gl_context.borrow_draw_buffer().unwrap().size();
- } else {
- self.size = size;
- unsafe { gl::Scissor(0, 0, size.width, size.height); }
+ match self.data {
+ WebGLPaintTaskData::Servo(ref mut context) => {
+ if size.width > self.size.width ||
+ size.height > self.size.height {
+ try!(context.resize(size));
+ self.size = context.borrow_draw_buffer().unwrap().size();
+ } else {
+ self.size = size;
+ unsafe { gl::Scissor(0, 0, size.width, size.height); }
+ }
+ }
+ WebGLPaintTaskData::WebRender(_, _) => {
+ // TODO
+ }
}
+
Ok(())
}
fn init(&mut self) {
- self.gl_context.make_current().unwrap();
+ if let WebGLPaintTaskData::Servo(ref context) = self.data {
+ context.make_current().unwrap();
+ }
}
}
diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml
index 0b5962e5802..d1985af2a6b 100644
--- a/components/canvas_traits/Cargo.toml
+++ b/components/canvas_traits/Cargo.toml
@@ -34,6 +34,9 @@ path = "../plugins"
[dependencies.util]
path = "../util"
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
[dependencies]
cssparser = {version = "0.5.3", features = ["heap_size", "serde-serialization"]}
euclid = {version = "0.6.2", features = ["plugins"]}
diff --git a/components/canvas_traits/lib.rs b/components/canvas_traits/lib.rs
index 4dc0a5904f8..8d6769da02a 100644
--- a/components/canvas_traits/lib.rs
+++ b/components/canvas_traits/lib.rs
@@ -5,7 +5,6 @@
#![crate_name = "canvas_traits"]
#![crate_type = "rlib"]
#![feature(custom_derive)]
-#![feature(nonzero)]
#![feature(plugin)]
#![plugin(heapsize_plugin, plugins, serde_macros)]
@@ -20,13 +19,13 @@ extern crate layers;
extern crate offscreen_gl_context;
extern crate serde;
extern crate util;
+extern crate webrender_traits;
use azure::azure::{AzColor, AzFloat};
use azure::azure_hl::{CapStyle, CompositionOp, JoinStyle};
use azure::azure_hl::{ColorPattern, DrawTarget, Pattern};
use azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGradientPattern};
use azure::azure_hl::{SurfaceFormat, SurfacePattern};
-use core::nonzero::NonZero;
use cssparser::RGBA;
use euclid::matrix2d::Matrix2D;
use euclid::point::Point2D;
@@ -35,13 +34,14 @@ use euclid::size::Size2D;
use gfx_traits::color;
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
use layers::platform::surface::NativeSurface;
-use offscreen_gl_context::GLContextAttributes;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::default::Default;
-use std::fmt;
use std::str::FromStr;
use std::sync::mpsc::Sender;
+pub use webrender_traits::{WebGLFramebufferBindingRequest, WebGLError, WebGLParameter, WebGLResult, WebGLContextId};
+pub use webrender_traits::WebGLCommand as CanvasWebGLMsg;
+
#[derive(Clone, Deserialize, Serialize)]
pub enum FillRule {
Nonzero,
@@ -64,8 +64,20 @@ pub enum CanvasCommonMsg {
}
#[derive(Clone, Deserialize, Serialize)]
+pub enum CanvasData {
+ Pixels(CanvasPixelData),
+ WebGL(WebGLContextId),
+}
+
+#[derive(Clone, Deserialize, Serialize)]
+pub struct CanvasPixelData {
+ pub image_data: IpcSharedMemory,
+ pub image_key: Option<webrender_traits::ImageKey>,
+}
+
+#[derive(Clone, Deserialize, Serialize)]
pub enum FromLayoutMsg {
- SendPixelContents(IpcSender<IpcSharedMemory>),
+ SendData(IpcSender<CanvasData>),
}
#[derive(Clone)]
@@ -124,178 +136,6 @@ pub enum Canvas2dMsg {
SetShadowColor(RGBA),
}
-#[derive(Clone, Deserialize, Serialize)]
-pub enum CanvasWebGLMsg {
- GetContextAttributes(IpcSender<GLContextAttributes>),
- ActiveTexture(u32),
- BlendColor(f32, f32, f32, f32),
- BlendEquation(u32),
- BlendEquationSeparate(u32, u32),
- BlendFunc(u32, u32),
- BlendFuncSeparate(u32, u32, u32, u32),
- AttachShader(u32, u32),
- BindAttribLocation(u32, u32, String),
- BufferData(u32, Vec<u8>, u32),
- BufferSubData(u32, isize, Vec<u8>),
- Clear(u32),
- ClearColor(f32, f32, f32, f32),
- ClearDepth(f64),
- ClearStencil(i32),
- ColorMask(bool, bool, bool, bool),
- CullFace(u32),
- FrontFace(u32),
- DepthFunc(u32),
- DepthMask(bool),
- DepthRange(f64, f64),
- Enable(u32),
- Disable(u32),
- CompileShader(u32, String),
- CreateBuffer(IpcSender<Option<NonZero<u32>>>),
- CreateFramebuffer(IpcSender<Option<NonZero<u32>>>),
- CreateRenderbuffer(IpcSender<Option<NonZero<u32>>>),
- CreateTexture(IpcSender<Option<NonZero<u32>>>),
- CreateProgram(IpcSender<Option<NonZero<u32>>>),
- CreateShader(u32, IpcSender<Option<NonZero<u32>>>),
- DeleteBuffer(u32),
- DeleteFramebuffer(u32),
- DeleteRenderbuffer(u32),
- DeleteTexture(u32),
- DeleteProgram(u32),
- DeleteShader(u32),
- BindBuffer(u32, u32),
- BindFramebuffer(u32, WebGLFramebufferBindingRequest),
- BindRenderbuffer(u32, u32),
- BindTexture(u32, u32),
- DrawArrays(u32, i32, i32),
- DrawElements(u32, i32, u32, i64),
- EnableVertexAttribArray(u32),
- GetBufferParameter(u32, u32, IpcSender<WebGLResult<WebGLParameter>>),
- GetParameter(u32, IpcSender<WebGLResult<WebGLParameter>>),
- GetProgramParameter(u32, u32, IpcSender<WebGLResult<WebGLParameter>>),
- GetShaderParameter(u32, u32, IpcSender<WebGLResult<WebGLParameter>>),
- GetAttribLocation(u32, String, IpcSender<Option<i32>>),
- GetUniformLocation(u32, String, IpcSender<Option<i32>>),
- PolygonOffset(f32, f32),
- Scissor(i32, i32, i32, i32),
- Hint(u32, u32),
- LineWidth(f32),
- PixelStorei(u32, i32),
- LinkProgram(u32),
- Uniform1f(i32, f32),
- Uniform4f(i32, f32, f32, f32, f32),
- UseProgram(u32),
- VertexAttrib(u32, f32, f32, f32, f32),
- VertexAttribPointer2f(u32, i32, bool, i32, u32),
- Viewport(i32, i32, i32, i32),
- TexImage2D(u32, i32, i32, i32, i32, u32, u32, Vec<u8>),
- TexParameteri(u32, u32, i32),
- TexParameterf(u32, u32, f32),
- DrawingBufferWidth(IpcSender<i32>),
- DrawingBufferHeight(IpcSender<i32>),
-}
-
-impl fmt::Debug for CanvasWebGLMsg {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use CanvasWebGLMsg::*;
- let name = match *self {
- GetContextAttributes(..) => "GetContextAttributes",
- ActiveTexture(..) => "ActiveTexture",
- BlendColor(..) => "BlendColor",
- BlendEquation(..) => "BlendEquation",
- BlendEquationSeparate(..) => "BlendEquationSeparate",
- BlendFunc(..) => "BlendFunc",
- BlendFuncSeparate(..) => "BlendFuncSeparate",
- AttachShader(..) => "AttachShader",
- BindAttribLocation(..) => "BindAttribLocation",
- BufferData(..) => "BufferData",
- BufferSubData(..) => "BufferSubData",
- Clear(..) => "Clear",
- ClearColor(..) => "ClearColor",
- ClearDepth(..) => "ClearDepth",
- ClearStencil(..) => "ClearStencil",
- ColorMask(..) => "ColorMask",
- CullFace(..) => "CullFace",
- FrontFace(..) => "FrontFace",
- DepthFunc(..) => "DepthFunc",
- DepthMask(..) => "DepthMask",
- DepthRange(..) => "DepthRange",
- Enable(..) => "Enable",
- Disable(..) => "Disable",
- CompileShader(..) => "CompileShader",
- CreateBuffer(..) => "CreateBuffer",
- CreateFramebuffer(..) => "CreateFramebuffer",
- CreateRenderbuffer(..) => "CreateRenderbuffer",
- CreateTexture(..) => "CreateTexture",
- CreateProgram(..) => "CreateProgram",
- CreateShader(..) => "CreateShader",
- DeleteBuffer(..) => "DeleteBuffer",
- DeleteFramebuffer(..) => "DeleteFramebuffer",
- DeleteRenderbuffer(..) => "DeleteRenderBuffer",
- DeleteTexture(..) => "DeleteTexture",
- DeleteProgram(..) => "DeleteProgram",
- DeleteShader(..) => "DeleteShader",
- BindBuffer(..) => "BindBuffer",
- BindFramebuffer(..) => "BindFramebuffer",
- BindRenderbuffer(..) => "BindRenderbuffer",
- BindTexture(..) => "BindTexture",
- DrawArrays(..) => "DrawArrays",
- DrawElements(..) => "DrawElements",
- EnableVertexAttribArray(..) => "EnableVertexAttribArray",
- GetBufferParameter(..) => "GetBufferParameter",
- GetParameter(..) => "GetParameter",
- GetProgramParameter(..) => "GetProgramParameter",
- GetShaderParameter(..) => "GetShaderParameter",
- GetAttribLocation(..) => "GetAttribLocation",
- GetUniformLocation(..) => "GetUniformLocation",
- PolygonOffset(..) => "PolygonOffset",
- Scissor(..) => "Scissor",
- Hint(..) => "Hint",
- LineWidth(..) => "LineWidth",
- PixelStorei(..) => "PixelStorei",
- LinkProgram(..) => "LinkProgram",
- Uniform4f(..) => "Uniform4f",
- Uniform1f(..) => "Uniform1f",
- UseProgram(..) => "UseProgram",
- VertexAttrib(..) => "VertexAttrib",
- VertexAttribPointer2f(..) => "VertexAttribPointer2f",
- Viewport(..) => "Viewport",
- TexImage2D(..) => "TexImage2D",
- TexParameteri(..) => "TexParameteri",
- TexParameterf(..) => "TexParameterf",
- DrawingBufferWidth(..) => "DrawingBufferWidth",
- DrawingBufferHeight(..) => "DrawingBufferHeight",
- };
-
- write!(f, "CanvasWebGLMsg::{}(..)", name)
- }
-}
-
-#[derive(Clone, Copy, PartialEq, Deserialize, Serialize, HeapSizeOf)]
-pub enum WebGLError {
- InvalidEnum,
- InvalidOperation,
- InvalidValue,
- OutOfMemory,
- ContextLost,
-}
-
-pub type WebGLResult<T> = Result<T, WebGLError>;
-
-#[derive(Clone, Deserialize, Serialize)]
-pub enum WebGLFramebufferBindingRequest {
- Explicit(u32),
- Default,
-}
-
-#[derive(Clone, Deserialize, Serialize)]
-pub enum WebGLParameter {
- Int(i32),
- Bool(bool),
- String(String),
- Float(f32),
- Invalid,
-}
-
#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
pub struct CanvasGradientStop {
pub offset: f64,
diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml
index a190ddb73f2..389b669d607 100644
--- a/components/compositing/Cargo.toml
+++ b/components/compositing/Cargo.toml
@@ -81,6 +81,12 @@ git = "https://github.com/servo/gaol"
[target.aarch64-unknown-linux-gnu.dependencies.gaol]
git = "https://github.com/servo/gaol"
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
+[dependencies.webrender]
+git = "https://github.com/glennw/webrender"
+
[dependencies]
app_units = {version = "0.2.1", features = ["plugins"]}
euclid = {version = "0.6.2", features = ["plugins"]}
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index f75126cab28..e8ac9a88c22 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -6,7 +6,7 @@ use CompositorMsg as ConstellationMsg;
use app_units::Au;
use compositor_layer::{CompositorData, CompositorLayer, RcCompositorLayer, WantsScrollEventsFlag};
use compositor_thread::{CompositorEventListener, CompositorProxy};
-use compositor_thread::{CompositorReceiver, InitialCompositorState, Msg};
+use compositor_thread::{CompositorReceiver, InitialCompositorState, Msg, RenderListener};
use constellation::SendableFrameTree;
use euclid::point::TypedPoint2D;
use euclid::rect::TypedRect;
@@ -27,15 +27,15 @@ use layers::rendergl;
use layers::rendergl::RenderContext;
use layers::scene::Scene;
use layout_traits::LayoutControlChan;
-use msg::constellation_msg::{Image, PixelFormat};
+use msg::constellation_msg::{ConvertPipelineIdFromWebRender, ConvertPipelineIdToWebRender, Image, PixelFormat};
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
use msg::constellation_msg::{NavigationDirection, PipelineId, WindowSizeData};
use pipeline::CompositionPipeline;
use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest};
use profile_traits::time::{self, ProfilerCategory, profile};
-use script_traits::CompositorEvent::{MouseMoveEvent, TouchEvent};
+use script_traits::CompositorEvent::{MouseMoveEvent, MouseButtonEvent, TouchEvent};
use script_traits::{AnimationState, ConstellationControlMsg, LayoutControlMsg};
-use script_traits::{MouseButton, TouchEventType, TouchId};
+use script_traits::{MouseButton, MouseEventType, TouchEventType, TouchId};
use scrolling::ScrollingTimerProxy;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{HashMap, HashSet};
@@ -51,6 +51,8 @@ use url::Url;
use util::geometry::{PagePx, ScreenPx, ViewportPx};
use util::opts;
use util::print_tree::PrintTree;
+use webrender;
+use webrender_traits;
use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
#[derive(Debug, PartialEq)]
@@ -192,6 +194,12 @@ pub struct IOCompositor<Window: WindowMethods> {
/// The id of the pipeline that was last sent a mouse move event, if any.
last_mouse_move_recipient: Option<PipelineId>,
+
+ /// The webrender renderer, if enabled.
+ webrender: Option<webrender::Renderer>,
+
+ /// The webrender interface, if enabled.
+ webrender_api: Option<webrender_traits::RenderApi>,
}
pub struct ScrollZoomEvent {
@@ -261,7 +269,23 @@ pub enum CompositeTarget {
PngFile
}
-fn initialize_png(width: usize, height: usize) -> (Vec<gl::GLuint>, Vec<gl::GLuint>) {
+struct RenderTargetInfo {
+ framebuffer_ids: Vec<gl::GLuint>,
+ texture_ids: Vec<gl::GLuint>,
+ renderbuffer_ids: Vec<gl::GLuint>,
+}
+
+impl RenderTargetInfo {
+ fn empty() -> RenderTargetInfo {
+ RenderTargetInfo {
+ framebuffer_ids: Vec::new(),
+ texture_ids: Vec::new(),
+ renderbuffer_ids: Vec::new()
+ }
+ }
+}
+
+fn initialize_png(width: usize, height: usize) -> RenderTargetInfo {
let framebuffer_ids = gl::gen_framebuffers(1);
gl::bind_framebuffer(gl::FRAMEBUFFER, framebuffer_ids[0]);
@@ -278,13 +302,64 @@ fn initialize_png(width: usize, height: usize) -> (Vec<gl::GLuint>, Vec<gl::GLui
gl::bind_texture(gl::TEXTURE_2D, 0);
- (framebuffer_ids, texture_ids)
+ let renderbuffer_ids = if opts::get().use_webrender {
+ let renderbuffer_ids = gl::gen_renderbuffers(1);
+ gl::bind_renderbuffer(gl::RENDERBUFFER, renderbuffer_ids[0]);
+ gl::renderbuffer_storage(gl::RENDERBUFFER,
+ gl::STENCIL_INDEX8,
+ width as GLsizei,
+ height as GLsizei);
+ gl::framebuffer_renderbuffer(gl::FRAMEBUFFER,
+ gl::STENCIL_ATTACHMENT,
+ gl::RENDERBUFFER,
+ renderbuffer_ids[0]);
+ renderbuffer_ids
+ } else {
+ Vec::new()
+ };
+
+ RenderTargetInfo {
+ framebuffer_ids: framebuffer_ids,
+ texture_ids: texture_ids,
+ renderbuffer_ids: renderbuffer_ids
+ }
}
pub fn reporter_name() -> String {
"compositor-reporter".to_owned()
}
+struct RenderNotifier {
+ compositor_proxy: Box<CompositorProxy>,
+ constellation_chan: Sender<ConstellationMsg>,
+}
+
+impl RenderNotifier {
+ fn new(compositor_proxy: Box<CompositorProxy>,
+ constellation_chan: Sender<ConstellationMsg>) -> RenderNotifier {
+ RenderNotifier {
+ compositor_proxy: compositor_proxy,
+ constellation_chan: constellation_chan,
+ }
+ }
+}
+
+impl webrender_traits::RenderNotifier for RenderNotifier {
+ fn new_frame_ready(&mut self) {
+ self.compositor_proxy.recomposite();
+ }
+
+ fn pipeline_size_changed(&mut self,
+ pipeline_id: webrender_traits::PipelineId,
+ size: Option<Size2D<f32>>) {
+ let pipeline_id = pipeline_id.from_webrender();
+ let size = size.unwrap_or(Size2D::zero());
+
+ self.constellation_chan.send(ConstellationMsg::FrameSize(pipeline_id,
+ size)).unwrap();
+ }
+}
+
impl<Window: WindowMethods> IOCompositor<Window> {
fn new(window: Rc<Window>, state: InitialCompositorState)
-> IOCompositor<Window> {
@@ -306,6 +381,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
Some(_) => CompositeTarget::PngFile,
None => CompositeTarget::Window
};
+
+ let webrender_api = state.webrender_api_sender.map(|sender| {
+ sender.create_api()
+ });
+
let native_display = window.native_display();
IOCompositor {
window: window,
@@ -345,6 +425,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
surface_map: SurfaceMap::new(BUFFER_MAP_SIZE),
pending_subpages: HashSet::new(),
last_mouse_move_recipient: None,
+ webrender: state.webrender,
+ webrender_api: webrender_api,
}
}
@@ -352,6 +434,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
-> IOCompositor<Window> {
let mut compositor = IOCompositor::new(window, state);
+ if let Some(ref mut webrender) = compositor.webrender {
+ let compositor_proxy_for_webrender = compositor.channel_to_self
+ .clone_compositor_proxy();
+ let render_notifier = RenderNotifier::new(compositor_proxy_for_webrender,
+ compositor.constellation_chan.clone());
+ webrender.set_render_notifier(Box::new(render_notifier));
+ }
+
// Set the size of the root layer.
compositor.update_zoom_transform();
@@ -674,6 +764,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.root_pipeline = Some(frame_tree.pipeline.clone());
+ if let Some(ref webrender_api) = self.webrender_api {
+ let pipeline_id = frame_tree.pipeline.id.to_webrender();
+ webrender_api.set_root_pipeline(pipeline_id);
+ }
+
// If we have an old root layer, release all old tiles before replacing it.
let old_root_layer = self.scene.root.take();
if let Some(ref old_root_layer) = old_root_layer {
@@ -1172,6 +1267,36 @@ impl<Window: WindowMethods> IOCompositor<Window> {
MouseWindowEvent::MouseDown(_, p) => p,
MouseWindowEvent::MouseUp(_, p) => p,
};
+
+ if let Some(ref webrender_api) = self.webrender_api {
+ let root_pipeline_id = match self.get_root_pipeline_id() {
+ Some(root_pipeline_id) => root_pipeline_id,
+ None => return,
+ };
+ let root_pipeline = match self.pipeline(root_pipeline_id) {
+ Some(root_pipeline) => root_pipeline,
+ None => return,
+ };
+
+ let translated_point =
+ webrender_api.translate_point_to_layer_space(&point.to_untyped());
+ let event_to_send = match mouse_window_event {
+ MouseWindowEvent::Click(button, _) => {
+ MouseButtonEvent(MouseEventType::Click, button, translated_point)
+ }
+ MouseWindowEvent::MouseDown(button, _) => {
+ MouseButtonEvent(MouseEventType::MouseDown, button, translated_point)
+ }
+ MouseWindowEvent::MouseUp(button, _) => {
+ MouseButtonEvent(MouseEventType::MouseUp, button, translated_point)
+ }
+ };
+ root_pipeline.script_chan
+ .send(ConstellationControlMsg::SendEvent(root_pipeline_id,
+ event_to_send))
+ .unwrap();
+ }
+
match self.find_topmost_layer_at_point(point / self.scene.scale) {
Some(result) => result.layer.send_mouse_event(self, mouse_window_event, result.point),
None => {},
@@ -1184,6 +1309,25 @@ impl<Window: WindowMethods> IOCompositor<Window> {
return
}
+ if let Some(ref webrender_api) = self.webrender_api {
+ let root_pipeline_id = match self.get_root_pipeline_id() {
+ Some(root_pipeline_id) => root_pipeline_id,
+ None => return,
+ };
+ let root_pipeline = match self.pipeline(root_pipeline_id) {
+ Some(root_pipeline) => root_pipeline,
+ None => return,
+ };
+
+ let translated_point =
+ webrender_api.translate_point_to_layer_space(&cursor.to_untyped());
+ let event_to_send = MouseMoveEvent(Some(translated_point));
+ root_pipeline.script_chan
+ .send(ConstellationControlMsg::SendEvent(root_pipeline_id,
+ event_to_send))
+ .unwrap();
+ }
+
match self.find_topmost_layer_at_point(cursor / self.scene.scale) {
Some(result) => {
// In the case that the mouse was previously over a different layer,
@@ -1285,30 +1429,52 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn process_pending_scroll_events(&mut self) {
let had_events = self.pending_scroll_zoom_events.len() > 0;
- for event in std_mem::replace(&mut self.pending_scroll_zoom_events,
- Vec::new()) {
- let delta = event.delta / self.scene.scale;
- let cursor = event.cursor.as_f32() / self.scene.scale;
- if let Some(ref mut layer) = self.scene.root {
- layer.handle_scroll_event(delta, cursor);
+ match self.webrender_api {
+ Some(ref webrender_api) => {
+ // Batch up all scroll events into one, or else we'll do way too much painting.
+ let mut total_delta = None;
+ let mut last_cursor = Point2D::zero();
+ for scroll_event in self.pending_scroll_zoom_events.drain(..) {
+ let this_delta = scroll_event.delta / self.scene.scale;
+ last_cursor = scroll_event.cursor.as_f32() / self.scene.scale;
+ match total_delta {
+ None => total_delta = Some(this_delta),
+ Some(ref mut total_delta) => *total_delta = *total_delta + this_delta,
+ }
+ }
+ // TODO(gw): Support zoom (WR issue #28).
+ if let Some(total_delta) = total_delta {
+ webrender_api.scroll(total_delta.to_untyped(), last_cursor.to_untyped());
+ }
}
+ None => {
+ for event in std_mem::replace(&mut self.pending_scroll_zoom_events,
+ Vec::new()) {
+ let delta = event.delta / self.scene.scale;
+ let cursor = event.cursor.as_f32() / self.scene.scale;
- if event.magnification != 1.0 {
- self.zoom_action = true;
- self.zoom_time = precise_time_s();
- self.viewport_zoom = ScaleFactor::new(
- (self.viewport_zoom.get() * event.magnification)
- .min(self.max_viewport_zoom.as_ref().map_or(MAX_ZOOM, ScaleFactor::get))
- .max(self.min_viewport_zoom.as_ref().map_or(MIN_ZOOM, ScaleFactor::get)));
- self.update_zoom_transform();
- }
+ if let Some(ref mut layer) = self.scene.root {
+ layer.handle_scroll_event(delta, cursor);
+ }
- self.perform_updates_after_scroll();
- }
+ if event.magnification != 1.0 {
+ self.zoom_action = true;
+ self.zoom_time = precise_time_s();
+ self.viewport_zoom = ScaleFactor::new(
+ (self.viewport_zoom.get() * event.magnification)
+ .min(self.max_viewport_zoom.as_ref().map_or(MAX_ZOOM, ScaleFactor::get))
+ .max(self.min_viewport_zoom.as_ref().map_or(MIN_ZOOM, ScaleFactor::get)));
+ self.update_zoom_transform();
+ }
+
+ self.perform_updates_after_scroll();
+ }
- if had_events {
- self.send_viewport_rects_for_all_layers();
+ if had_events {
+ self.send_viewport_rects_for_all_layers();
+ }
+ }
}
}
@@ -1542,6 +1708,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
/// Returns true if any buffer requests were sent or false otherwise.
fn send_buffer_requests_for_all_layers(&mut self) -> bool {
+ if self.webrender.is_some() {
+ return false;
+ }
+
if let Some(ref root_layer) = self.scene.root {
root_layer.update_transform_state(&Matrix4::identity(),
&Matrix4::identity(),
@@ -1656,7 +1826,15 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// frame tree.
let mut pipeline_epochs = HashMap::new();
for (id, details) in &self.pipeline_details {
- pipeline_epochs.insert(*id, details.current_epoch);
+ if let Some(ref webrender) = self.webrender {
+ let webrender_pipeline_id = id.to_webrender();
+ if let Some(webrender_traits::Epoch(epoch)) = webrender.current_epoch(webrender_pipeline_id) {
+ let epoch = Epoch(epoch);
+ pipeline_epochs.insert(*id, epoch);
+ }
+ } else {
+ pipeline_epochs.insert(*id, details.current_epoch);
+ }
}
// Pass the pipeline/epoch states to the constellation and check
@@ -1707,7 +1885,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
/// is WindowAndPng Ok(Some(png::Image)) is returned.
pub fn composite_specific_target(&mut self, target: CompositeTarget) -> Result<Option<Image>, UnableToComposite> {
- if !self.context.is_some() {
+ if self.context.is_none() && self.webrender.is_none() {
return Err(UnableToComposite::NoContext)
}
let (width, height) =
@@ -1716,6 +1894,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
return Err(UnableToComposite::WindowUnprepared)
}
+ if let Some(ref mut webrender) = self.webrender {
+ assert!(self.context.is_none());
+ webrender.update();
+ }
+
let wait_for_stable_image = match target {
CompositeTarget::WindowAndPng | CompositeTarget::PngFile => true,
CompositeTarget::Window => opts::get().exit_after_load,
@@ -1738,8 +1921,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
- let (framebuffer_ids, texture_ids) = match target {
- CompositeTarget::Window => (vec!(), vec!()),
+ let render_target_info = match target {
+ CompositeTarget::Window => RenderTargetInfo::empty(),
_ => initialize_png(width, height)
};
@@ -1760,7 +1943,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
};
// Paint the scene.
- if let Some(ref layer) = self.scene.root {
+ if let Some(ref mut webrender) = self.webrender {
+ assert!(self.context.is_none());
+ webrender.render(self.window_size.to_untyped());
+ } else if let Some(ref layer) = self.scene.root {
match self.context {
Some(context) => {
if let Some((point, size)) = self.viewport {
@@ -1790,16 +1976,21 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let rv = match target {
CompositeTarget::Window => None,
CompositeTarget::WindowAndPng => {
- let img = self.draw_img(framebuffer_ids, texture_ids, width, height);
+ let img = self.draw_img(render_target_info,
+ width,
+ height);
Some(Image {
width: img.width(),
height: img.height(),
format: PixelFormat::RGB8,
bytes: IpcSharedMemory::from_bytes(&*img),
+ id: None,
})
}
CompositeTarget::PngFile => {
- let img = self.draw_img(framebuffer_ids, texture_ids, width, height);
+ let img = self.draw_img(render_target_info,
+ width,
+ height);
let path = opts::get().output_file.as_ref().unwrap();
let mut file = File::create(path).unwrap();
DynamicImage::ImageRgb8(img).save(&mut file, ImageFormat::PNG).unwrap();
@@ -1820,8 +2011,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
fn draw_img(&self,
- framebuffer_ids: Vec<gl::GLuint>,
- texture_ids: Vec<gl::GLuint>,
+ render_target_info: RenderTargetInfo,
width: usize,
height: usize)
-> RgbImage {
@@ -1832,8 +2022,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
gl::bind_framebuffer(gl::FRAMEBUFFER, 0);
- gl::delete_buffers(&texture_ids);
- gl::delete_frame_buffers(&framebuffer_ids);
+ gl::delete_buffers(&render_target_info.texture_ids);
+ gl::delete_frame_buffers(&render_target_info.framebuffer_ids);
+ if opts::get().use_webrender {
+ gl::delete_renderbuffers(&render_target_info.renderbuffer_ids);
+ }
// flip image vertically (texture is upside down)
let orig_pixels = pixels.clone();
@@ -1859,10 +2052,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
fn initialize_compositing(&mut self) {
- let show_debug_borders = opts::get().show_debug_borders;
- self.context = Some(rendergl::RenderContext::new(self.native_display.clone(),
- show_debug_borders,
- opts::get().output_file.is_some()))
+ if self.webrender.is_none() {
+ let show_debug_borders = opts::get().show_debug_borders;
+ self.context = Some(rendergl::RenderContext::new(self.native_display.clone(),
+ show_debug_borders,
+ opts::get().output_file.is_some()))
+ }
}
fn find_topmost_layer_at_point_for_layer(&self,
@@ -1951,6 +2146,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.surface_map.insert_surfaces(&self.native_display, surfaces);
}
+ fn get_root_pipeline_id(&self) -> Option<PipelineId> {
+ self.scene.root.as_ref().map(|root_layer| root_layer.extra_data.borrow().pipeline_id)
+ }
+
#[allow(dead_code)]
fn dump_layer_tree(&self) {
if !opts::get().dump_layer_tree {
@@ -2076,19 +2275,37 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
///
/// This is used when resizing the window.
fn repaint_synchronously(&mut self) {
- while self.shutdown_state != ShutdownState::ShuttingDown {
- let msg = self.port.recv_compositor_msg();
- let received_new_buffers = match msg {
- Msg::AssignPaintedBuffers(..) => true,
- _ => false,
- };
- let keep_going = self.handle_browser_message(msg);
- if received_new_buffers {
- self.composite();
- break
+ if self.webrender.is_none() {
+ while self.shutdown_state != ShutdownState::ShuttingDown {
+ let msg = self.port.recv_compositor_msg();
+ let received_new_buffers = match msg {
+ Msg::AssignPaintedBuffers(..) => true,
+ _ => false,
+ };
+ let keep_going = self.handle_browser_message(msg);
+ if received_new_buffers {
+ self.composite();
+ break
+ }
+ if !keep_going {
+ break
+ }
}
- if !keep_going {
- break
+ } else {
+ while self.shutdown_state != ShutdownState::ShuttingDown {
+ let msg = self.port.recv_compositor_msg();
+ let need_recomposite = match msg {
+ Msg::RecompositeAfterScroll => true,
+ _ => false,
+ };
+ let keep_going = self.handle_browser_message(msg);
+ if need_recomposite {
+ self.composite();
+ break
+ }
+ if !keep_going {
+ break
+ }
}
}
}
diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs
index 618bac9674b..f9f0c03d1e3 100644
--- a/components/compositing/compositor_thread.rs
+++ b/components/compositing/compositor_thread.rs
@@ -26,6 +26,8 @@ use url::Url;
use windowing::{WindowEvent, WindowMethods};
pub use constellation::SendableFrameTree;
pub use windowing;
+use webrender;
+use webrender_traits;
/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
@@ -100,6 +102,16 @@ pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'stati
}
}
+pub trait RenderListener {
+ fn recomposite(&mut self);
+}
+
+impl RenderListener for Box<CompositorProxy + 'static> {
+ fn recomposite(&mut self) {
+ self.send(Msg::RecompositeAfterScroll);
+ }
+}
+
/// Implementation of the abstract `PaintListener` interface.
impl PaintListener for Box<CompositorProxy + 'static + Send> {
fn native_display(&mut self) -> Option<NativeDisplay> {
@@ -301,4 +313,7 @@ pub struct InitialCompositorState {
pub time_profiler_chan: time::ProfilerChan,
/// A channel to the memory profiler thread.
pub mem_profiler_chan: mem::ProfilerChan,
+ /// Instance of webrender API if enabled
+ pub webrender: Option<webrender::Renderer>,
+ pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
}
diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs
index a08687bb680..b7a57f7069e 100644
--- a/components/compositing/constellation.rs
+++ b/components/compositing/constellation.rs
@@ -63,6 +63,7 @@ use url::Url;
use util::geometry::PagePx;
use util::thread::spawn_named;
use util::{opts, prefs};
+use webrender_traits;
#[derive(Debug, PartialEq)]
enum ReadyToSave {
@@ -181,6 +182,9 @@ pub struct Constellation<LTF, STF> {
/// Document states for loaded pipelines (used only when writing screenshots).
document_states: HashMap<PipelineId, DocumentState>,
+
+ // Webrender interface, if enabled.
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>,
}
/// State needed to construct a constellation.
@@ -203,6 +207,8 @@ pub struct InitialConstellationState {
pub mem_profiler_chan: mem::ProfilerChan,
/// Whether the constellation supports the clipboard.
pub supports_clipboard: bool,
+ /// Optional webrender API reference (if enabled).
+ pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
}
/// Stores the navigation context for a single frame in the frame tree.
@@ -347,6 +353,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
scheduler_chan: TimerScheduler::start(),
child_processes: Vec::new(),
document_states: HashMap::new(),
+ webrender_api_sender: state.webrender_api_sender,
};
let namespace_id = constellation.next_pipeline_namespace_id();
PipelineNamespace::install(namespace_id);
@@ -399,6 +406,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
load_data: load_data,
device_pixel_ratio: self.window_size.device_pixel_ratio,
pipeline_namespace_id: self.next_pipeline_namespace_id(),
+ webrender_api_sender: self.webrender_api_sender.clone(),
});
if spawning_paint_only {
@@ -1196,7 +1204,9 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
size: &Size2D<i32>,
response_sender: IpcSender<(IpcSender<CanvasMsg>, usize)>) {
let id = self.canvas_paint_threads.len();
- let (out_of_process_sender, in_process_sender) = CanvasPaintThread::start(*size);
+ let webrender_api = self.webrender_api_sender.clone();
+ let (out_of_process_sender, in_process_sender) = CanvasPaintThread::start(*size,
+ webrender_api);
self.canvas_paint_threads.push(in_process_sender);
response_sender.send((out_of_process_sender, id)).unwrap()
}
@@ -1206,13 +1216,14 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
size: &Size2D<i32>,
attributes: GLContextAttributes,
response_sender: IpcSender<Result<(IpcSender<CanvasMsg>, usize), String>>) {
- let response = match WebGLPaintThread::start(*size, attributes) {
+ let webrender_api = self.webrender_api_sender.clone();
+ let response = match WebGLPaintThread::start(*size, attributes, webrender_api) {
Ok((out_of_process_sender, in_process_sender)) => {
let id = self.webgl_paint_threads.len();
self.webgl_paint_threads.push(in_process_sender);
Ok((out_of_process_sender, id))
},
- Err(msg) => Err(msg.to_owned()),
+ Err(msg) => Err(msg),
};
response_sender.send(response).unwrap()
diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs
index 6434c3a8939..410b007a3a6 100644
--- a/components/compositing/lib.rs
+++ b/components/compositing/lib.rs
@@ -48,6 +48,8 @@ extern crate time;
extern crate url;
#[macro_use]
extern crate util;
+extern crate webrender;
+extern crate webrender_traits;
pub use compositor_thread::{CompositorEventListener, CompositorProxy, CompositorThread};
pub use constellation::Constellation;
diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs
index 2a4e3b1999e..bbf892048c8 100644
--- a/components/compositing/pipeline.rs
+++ b/components/compositing/pipeline.rs
@@ -35,6 +35,7 @@ use util::geometry::{PagePx, ViewportPx};
use util::ipc::OptionalIpcSender;
use util::opts::{self, Opts};
use util::prefs;
+use webrender_traits;
/// A uniquely-identifiable pipeline of script thread, layout thread, and paint thread.
pub struct Pipeline {
@@ -113,6 +114,8 @@ pub struct InitialPipelineState {
pub load_data: LoadData,
/// The ID of the pipeline namespace for this script thread.
pub pipeline_namespace_id: PipelineNamespaceId,
+ /// Optional webrender api (if enabled).
+ pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
}
impl Pipeline {
@@ -225,6 +228,7 @@ impl Pipeline {
layout_content_process_shutdown_port: layout_content_process_shutdown_port,
script_content_process_shutdown_chan: script_content_process_shutdown_chan,
script_content_process_shutdown_port: script_content_process_shutdown_port,
+ webrender_api_sender: state.webrender_api_sender,
};
let privileged_pipeline_content = PrivilegedPipelineContent {
@@ -376,6 +380,7 @@ pub struct UnprivilegedPipelineContent {
layout_content_process_shutdown_port: IpcReceiver<()>,
script_content_process_shutdown_chan: IpcSender<()>,
script_content_process_shutdown_port: IpcReceiver<()>,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>,
}
impl UnprivilegedPipelineContent {
@@ -419,7 +424,8 @@ impl UnprivilegedPipelineContent {
self.time_profiler_chan,
self.mem_profiler_chan,
self.layout_shutdown_chan,
- self.layout_content_process_shutdown_chan.clone());
+ self.layout_content_process_shutdown_chan.clone(),
+ self.webrender_api_sender);
if wait_for_completion {
self.script_content_process_shutdown_port.recv().unwrap();
diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml
index b9e577d3e90..58863a275c1 100644
--- a/components/gfx/Cargo.toml
+++ b/components/gfx/Cargo.toml
@@ -69,6 +69,9 @@ features = ["plugins"]
[dependencies.ipc-channel]
git = "https://github.com/servo/ipc-channel"
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
[target.x86_64-apple-darwin.dependencies]
core-foundation = "0.2"
core-graphics = "0.2"
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs
index f3aad7848c7..5b0e3935904 100644
--- a/components/gfx/display_list/mod.rs
+++ b/components/gfx/display_list/mod.rs
@@ -45,6 +45,7 @@ use util::linked_list::prepend_from;
use util::opts;
use util::print_tree::PrintTree;
use util::range::Range;
+use webrender_traits::WebGLContextId;
pub use style::dom::OpaqueNode;
@@ -641,7 +642,10 @@ impl StackingContext {
layer_info: layer_info,
last_child_layer_info: None,
};
- StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
+ // webrender doesn't care about layers in the display list - it's handled internally.
+ if !opts::get().use_webrender {
+ StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
+ }
stacking_context
}
@@ -681,7 +685,8 @@ impl StackingContext {
// TODO(gw): This is a hack to avoid running the DL optimizer
// on 3d transformed tiles. We should have a better solution
// than just disabling the opts here.
- if paint_context.layer_kind == LayerKind::HasTransform {
+ if paint_context.layer_kind == LayerKind::HasTransform ||
+ opts::get().use_webrender { // webrender takes care of all culling via aabb tree!
self.draw_into_context(&self.display_list,
paint_context,
&transform,
@@ -775,6 +780,9 @@ struct StackingContextLayerCreator {
impl StackingContextLayerCreator {
fn new() -> StackingContextLayerCreator {
+ // webrender doesn't care about layers in the display list - it's handled internally.
+ debug_assert!(!opts::get().use_webrender);
+
StackingContextLayerCreator {
display_list_for_next_layer: None,
next_layer_info: None,
@@ -969,6 +977,7 @@ pub enum DisplayItem {
SolidColorClass(Box<SolidColorDisplayItem>),
TextClass(Box<TextDisplayItem>),
ImageClass(Box<ImageDisplayItem>),
+ WebGLClass(Box<WebGLDisplayItem>),
BorderClass(Box<BorderDisplayItem>),
GradientClass(Box<GradientDisplayItem>),
LineClass(Box<LineDisplayItem>),
@@ -976,6 +985,7 @@ pub enum DisplayItem {
StackingContextClass(Arc<StackingContext>),
LayeredItemClass(Box<LayeredItem>),
NoopClass(Box<BaseDisplayItem>),
+ IframeClass(Box<IframeDisplayItem>),
}
/// Information common to all display items.
@@ -1236,6 +1246,20 @@ pub struct ImageDisplayItem {
pub image_rendering: image_rendering::T,
}
+#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
+pub struct WebGLDisplayItem {
+ pub base: BaseDisplayItem,
+ #[ignore_heap_size_of = "Defined in webrender_traits"]
+ pub context_id: WebGLContextId,
+}
+
+
+/// Paints an iframe.
+#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
+pub struct IframeDisplayItem {
+ pub base: BaseDisplayItem,
+ pub iframe: PipelineId,
+}
/// Paints a gradient.
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
@@ -1450,6 +1474,10 @@ impl DisplayItem {
image_item.image_rendering.clone());
}
+ DisplayItem::WebGLClass(_) => {
+ panic!("Shouldn't be here, WebGL display items are created just with webrender");
+ }
+
DisplayItem::BorderClass(ref border) => {
paint_context.draw_border(&border.base.bounds,
&border.border_widths,
@@ -1499,6 +1527,7 @@ impl DisplayItem {
DisplayItem::LayeredItemClass(_) => panic!("Found layered item during drawing."),
DisplayItem::NoopClass(_) => { }
+ DisplayItem::IframeClass(..) => {}
}
}
@@ -1507,6 +1536,7 @@ impl DisplayItem {
DisplayItem::SolidColorClass(ref solid_color) => Some(&solid_color.base),
DisplayItem::TextClass(ref text) => Some(&text.base),
DisplayItem::ImageClass(ref image_item) => Some(&image_item.base),
+ DisplayItem::WebGLClass(ref webgl_item) => Some(&webgl_item.base),
DisplayItem::BorderClass(ref border) => Some(&border.base),
DisplayItem::GradientClass(ref gradient) => Some(&gradient.base),
DisplayItem::LineClass(ref line) => Some(&line.base),
@@ -1514,6 +1544,7 @@ impl DisplayItem {
DisplayItem::LayeredItemClass(ref layered_item) => layered_item.item.base(),
DisplayItem::NoopClass(ref base_item) => Some(base_item),
DisplayItem::StackingContextClass(_) => None,
+ DisplayItem::IframeClass(ref iframe) => Some(&iframe.base),
}
}
@@ -1563,6 +1594,7 @@ impl fmt::Debug for DisplayItem {
solid_color.color.a),
DisplayItem::TextClass(_) => "Text".to_owned(),
DisplayItem::ImageClass(_) => "Image".to_owned(),
+ DisplayItem::WebGLClass(_) => "WebGL".to_owned(),
DisplayItem::BorderClass(_) => "Border".to_owned(),
DisplayItem::GradientClass(_) => "Gradient".to_owned(),
DisplayItem::LineClass(_) => "Line".to_owned(),
@@ -1571,6 +1603,7 @@ impl fmt::Debug for DisplayItem {
DisplayItem::LayeredItemClass(ref layered_item) =>
format!("LayeredItem({:?})", layered_item.item),
DisplayItem::NoopClass(_) => "Noop".to_owned(),
+ DisplayItem::IframeClass(_) => "Iframe".to_owned(),
},
self.bounds(),
)
diff --git a/components/gfx/font.rs b/components/gfx/font.rs
index bb9ff7b3d45..8e5a80939ab 100644
--- a/components/gfx/font.rs
+++ b/components/gfx/font.rs
@@ -23,6 +23,7 @@ use text::shaping::ShaperMethods;
use time;
use unicode_script::Script;
use util::cache::HashCache;
+use webrender_traits;
static TEXT_SHAPING_PERFORMANCE_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
@@ -100,6 +101,7 @@ pub struct Font {
pub shaper: Option<Shaper>,
pub shape_cache: HashCache<ShapeCacheEntry, Arc<GlyphStore>>,
pub glyph_advance_cache: HashCache<u32, FractionalPixel>,
+ pub font_key: Option<webrender_traits::FontKey>,
}
bitflags! {
diff --git a/components/gfx/font_cache_thread.rs b/components/gfx/font_cache_thread.rs
index 6a2b5b4a033..89eefe9205b 100644
--- a/components/gfx/font_cache_thread.rs
+++ b/components/gfx/font_cache_thread.rs
@@ -24,12 +24,19 @@ use url::Url;
use util::prefs;
use util::str::LowercaseString;
use util::thread::spawn_named;
+use webrender_traits;
/// A list of font templates that make up a given font family.
struct FontTemplates {
templates: Vec<FontTemplate>,
}
+#[derive(Serialize, Deserialize, Debug)]
+pub struct FontTemplateInfo {
+ pub font_template: Arc<FontTemplateData>,
+ pub font_key: Option<webrender_traits::FontKey>,
+}
+
impl FontTemplates {
fn new() -> FontTemplates {
FontTemplates {
@@ -73,7 +80,8 @@ impl FontTemplates {
}
}
- let template = FontTemplate::new(identifier, maybe_data);
+ let template = FontTemplate::new(identifier,
+ maybe_data);
self.templates.push(template);
}
}
@@ -91,7 +99,7 @@ pub enum Command {
/// Reply messages sent from the font cache thread to the FontContext caller.
#[derive(Deserialize, Serialize, Debug)]
pub enum Reply {
- GetFontTemplateReply(Option<Arc<FontTemplateData>>),
+ GetFontTemplateReply(Option<FontTemplateInfo>),
}
/// The font cache thread itself. It maintains a list of reference counted
@@ -104,6 +112,8 @@ struct FontCache {
web_families: HashMap<LowercaseString, FontTemplates>,
font_context: FontContextHandle,
resource_thread: ResourceThread,
+ webrender_api: Option<webrender_traits::RenderApi>,
+ webrender_fonts: HashMap<Atom, webrender_traits::FontKey>,
}
fn populate_generic_fonts() -> HashMap<FontFamily, LowercaseString> {
@@ -285,24 +295,46 @@ impl FontCache {
}
}
+ fn get_font_template_info(&mut self, template: Arc<FontTemplateData>) -> FontTemplateInfo {
+ let webrender_fonts = &mut self.webrender_fonts;
+ let font_key = self.webrender_api.as_ref().map(|webrender_api| {
+ *webrender_fonts.entry(template.identifier.clone()).or_insert_with(|| {
+ match (template.bytes_if_in_memory(), template.native_font()) {
+ (Some(bytes), _) => webrender_api.add_raw_font(bytes),
+ (None, Some(native_font)) => webrender_api.add_native_font(native_font),
+ (None, None) => webrender_api.add_raw_font(template.bytes().clone()),
+ }
+ })
+ });
+
+ FontTemplateInfo {
+ font_template: template,
+ font_key: font_key,
+ }
+ }
+
fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
- -> Option<Arc<FontTemplateData>> {
- self.find_font_in_web_family(family, desc)
+ -> Option<FontTemplateInfo> {
+ let template = self.find_font_in_web_family(family, desc)
.or_else(|| {
let transformed_family = self.transform_family(family);
self.find_font_in_local_family(&transformed_family, desc)
- })
+ });
+
+ template.map(|template| {
+ self.get_font_template_info(template)
+ })
}
fn last_resort_font_template(&mut self, desc: &FontTemplateDescriptor)
- -> Arc<FontTemplateData> {
+ -> FontTemplateInfo {
let last_resort = last_resort_font_families();
for family in &last_resort {
let family = LowercaseString::new(family);
let maybe_font_in_family = self.find_font_in_local_family(&family, desc);
if let Some(family) = maybe_font_in_family {
- return family;
+ return self.get_font_template_info(family)
}
}
@@ -318,7 +350,8 @@ pub struct FontCacheThread {
}
impl FontCacheThread {
- pub fn new(resource_thread: ResourceThread) -> FontCacheThread {
+ pub fn new(resource_thread: ResourceThread,
+ webrender_api: Option<webrender_traits::RenderApi>) -> FontCacheThread {
let (chan, port) = ipc::channel().unwrap();
let channel_to_self = chan.clone();
@@ -334,6 +367,8 @@ impl FontCacheThread {
web_families: HashMap::new(),
font_context: FontContextHandle::new(),
resource_thread: resource_thread,
+ webrender_api: webrender_api,
+ webrender_fonts: HashMap::new(),
};
cache.refresh_local_families();
@@ -346,7 +381,7 @@ impl FontCacheThread {
}
pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor)
- -> Option<Arc<FontTemplateData>> {
+ -> Option<FontTemplateInfo> {
let (response_chan, response_port) = ipc::channel().unwrap();
self.chan.send(Command::GetFontTemplate(family, desc, response_chan)).unwrap();
@@ -361,7 +396,7 @@ impl FontCacheThread {
}
pub fn last_resort_font_template(&self, desc: FontTemplateDescriptor)
- -> Arc<FontTemplateData> {
+ -> FontTemplateInfo {
let (response_chan, response_port) = ipc::channel().unwrap();
self.chan.send(Command::GetLastResortFontTemplate(desc, response_chan)).unwrap();
diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs
index 8262b0d15fb..7cb95e6fc54 100644
--- a/components/gfx/font_context.rs
+++ b/components/gfx/font_context.rs
@@ -28,6 +28,7 @@ use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use string_cache::Atom;
use style::computed_values::{font_style, font_variant};
use util::cache::HashCache;
+use webrender_traits;
#[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
@@ -105,9 +106,12 @@ impl FontContext {
}
/// Create a font for use in layout calculations.
- fn create_layout_font(&self, template: Arc<FontTemplateData>,
- descriptor: FontTemplateDescriptor, pt_size: Au,
- variant: font_variant::T) -> Result<Font, ()> {
+ fn create_layout_font(&self,
+ template: Arc<FontTemplateData>,
+ descriptor: FontTemplateDescriptor,
+ pt_size: Au,
+ variant: font_variant::T,
+ font_key: Option<webrender_traits::FontKey>) -> Result<Font, ()> {
// TODO: (Bug #3463): Currently we only support fake small-caps
// painting. We should also support true small-caps (where the
// font supports it) in the future.
@@ -133,6 +137,7 @@ impl FontContext {
metrics: metrics,
shape_cache: HashCache::new(),
glyph_advance_cache: HashCache::new(),
+ font_key: font_key,
}
})
}
@@ -201,14 +206,15 @@ impl FontContext {
}
if !cache_hit {
- let font_template = self.font_cache_thread.find_font_template(family.clone(),
- desc.clone());
- match font_template {
- Some(font_template) => {
- let layout_font = self.create_layout_font(font_template,
+ let template_info = self.font_cache_thread.find_font_template(family.clone(),
+ desc.clone());
+ match template_info {
+ Some(template_info) => {
+ let layout_font = self.create_layout_font(template_info.font_template,
desc.clone(),
style.font_size,
- style.font_variant);
+ style.font_variant,
+ template_info.font_key);
let font = match layout_font {
Ok(layout_font) => {
let layout_font = Rc::new(RefCell::new(layout_font));
@@ -250,11 +256,12 @@ impl FontContext {
}
if !cache_hit {
- let font_template = self.font_cache_thread.last_resort_font_template(desc.clone());
- let layout_font = self.create_layout_font(font_template,
+ let template_info = self.font_cache_thread.last_resort_font_template(desc.clone());
+ let layout_font = self.create_layout_font(template_info.font_template,
desc.clone(),
style.font_size,
- style.font_variant);
+ style.font_variant,
+ template_info.font_key);
match layout_font {
Ok(layout_font) => {
let layout_font = Rc::new(RefCell::new(layout_font));
diff --git a/components/gfx/lib.rs b/components/gfx/lib.rs
index 4d17ad41cb1..cb2576dba5c 100644
--- a/components/gfx/lib.rs
+++ b/components/gfx/lib.rs
@@ -75,6 +75,7 @@ extern crate unicode_script;
extern crate url;
#[macro_use]
extern crate util;
+extern crate webrender_traits;
pub use paint_context::PaintContext;
diff --git a/components/gfx/platform/freetype/font_template.rs b/components/gfx/platform/freetype/font_template.rs
index 30f4ffd5437..55a530a7050 100644
--- a/components/gfx/platform/freetype/font_template.rs
+++ b/components/gfx/platform/freetype/font_template.rs
@@ -5,6 +5,7 @@
use std::fs::File;
use std::io::Read;
use string_cache::Atom;
+use webrender_traits::NativeFontHandle;
/// Platform specific font representation for Linux.
/// The identifier is an absolute path, and the bytes
@@ -36,4 +37,22 @@ impl FontTemplateData {
identifier: identifier,
}
}
+
+ /// Returns a clone of the data in this font. This may be a hugely expensive
+ /// operation (depending on the platform) which performs synchronous disk I/O
+ /// and should never be done lightly.
+ pub fn bytes(&self) -> Vec<u8> {
+ self.bytes.clone()
+ }
+
+ /// Returns a clone of the bytes in this font if they are in memory. This function never
+ /// performs disk I/O.
+ pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> {
+ Some(self.bytes())
+ }
+
+ /// Returns the native font that underlies this font template, if applicable.
+ pub fn native_font(&self) -> Option<NativeFontHandle> {
+ None
+ }
}
diff --git a/components/gfx/platform/macos/font_template.rs b/components/gfx/platform/macos/font_template.rs
index d6ee6b9f3f0..f15527e6a9f 100644
--- a/components/gfx/platform/macos/font_template.rs
+++ b/components/gfx/platform/macos/font_template.rs
@@ -9,9 +9,12 @@ use core_text::font::CTFont;
use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::ToOwned;
+use std::fs::File;
+use std::io::Read;
use std::ops::Deref;
use std::sync::Mutex;
use string_cache::Atom;
+use url::Url;
/// Platform specific font representation for mac.
/// The identifier is a PostScript font name. The
@@ -62,6 +65,39 @@ impl FontTemplateData {
}
ctfont.as_ref().map(|ctfont| (*ctfont).clone())
}
+
+ /// Returns a clone of the data in this font. This may be a hugely expensive
+ /// operation (depending on the platform) which performs synchronous disk I/O
+ /// and should never be done lightly.
+ pub fn bytes(&self) -> Vec<u8> {
+ match self.bytes_if_in_memory() {
+ Some(font_data) => return font_data,
+ None => {}
+ }
+
+ let path = Url::parse(&*self.ctfont()
+ .expect("No Core Text font available!")
+ .url()
+ .expect("No URL for Core Text font!")
+ .get_string()
+ .to_string()).expect("Couldn't parse Core Text font URL!")
+ .to_file_path()
+ .expect("Core Text font didn't name a path!");
+ let mut bytes = Vec::new();
+ File::open(path).expect("Couldn't open font file!").read_to_end(&mut bytes).unwrap();
+ bytes
+ }
+
+ /// Returns a clone of the bytes in this font if they are in memory. This function never
+ /// performs disk I/O.
+ pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> {
+ self.font_data.clone()
+ }
+
+ /// Returns the native font that underlies this font template, if applicable.
+ pub fn native_font(&self) -> Option<CGFont> {
+ self.ctfont().map(|ctfont| ctfont.copy_to_CGFont())
+ }
}
#[derive(Debug)]
diff --git a/components/gfx/text/text_run.rs b/components/gfx/text/text_run.rs
index 5b8acb5e1c5..5a3d086de7e 100644
--- a/components/gfx/text/text_run.rs
+++ b/components/gfx/text/text_run.rs
@@ -13,6 +13,7 @@ use std::sync::Arc;
use text::glyph::{CharIndex, GlyphStore};
use util::range::Range;
use util::vec::{Comparator, FullBinarySearchMethods};
+use webrender_traits;
thread_local! {
static INDEX_OF_FIRST_GLYPH_RUN_CACHE: Cell<Option<(*const TextRun, CharIndex, usize)>> =
@@ -27,6 +28,7 @@ pub struct TextRun {
pub font_template: Arc<FontTemplateData>,
pub actual_pt_size: Au,
pub font_metrics: FontMetrics,
+ pub font_key: Option<webrender_traits::FontKey>,
/// The glyph runs that make up this text run.
pub glyphs: Arc<Vec<GlyphRun>>,
pub bidi_level: u8,
@@ -177,6 +179,7 @@ impl<'a> TextRun {
text: Arc::new(text),
font_metrics: font.metrics.clone(),
font_template: font.handle.template(),
+ font_key: font.font_key,
actual_pt_size: font.actual_pt_size,
glyphs: Arc::new(glyphs),
bidi_level: bidi_level,
diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml
index d549967e753..99bf99cd47a 100644
--- a/components/layout/Cargo.toml
+++ b/components/layout/Cargo.toml
@@ -56,6 +56,9 @@ path = "../util"
[dependencies.ipc-channel]
git = "https://github.com/servo/ipc-channel"
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
[dependencies]
app_units = {version = "0.2.1", features = ["plugins"]}
bitflags = "0.3"
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index d49f4f4813b..efd7b0a2394 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -13,7 +13,7 @@
use app_units::{Au, AU_PER_PX};
use azure::azure_hl::Color;
use block::BlockFlow;
-use canvas_traits::{CanvasMsg, FromLayoutMsg};
+use canvas_traits::{CanvasMsg, CanvasPixelData, CanvasData, FromLayoutMsg};
use context::LayoutContext;
use euclid::num::Zero;
use euclid::{Matrix4, Point2D, Point3D, Rect, SideOffsets2D, Size2D};
@@ -26,7 +26,7 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayIte
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection};
use gfx::display_list::{GradientDisplayItem};
-use gfx::display_list::{GradientStop, ImageDisplayItem, LayeredItem, LayerInfo};
+use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGLDisplayItem, LayeredItem, LayerInfo};
use gfx::display_list::{LineDisplayItem, OpaqueNode, SolidColorDisplayItem};
use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation};
use gfx::paint_thread::THREAD_TINT_COLORS;
@@ -51,8 +51,7 @@ use style::properties::style_structs::Border;
use style::properties::{self, ComputedValues};
use style::values::RGBA;
use style::values::computed;
-use style::values::computed::LinearGradient;
-use style::values::computed::{LengthOrNone, LengthOrPercentage, LengthOrPercentageOrAuto};
+use style::values::computed::{LengthOrNone, LengthOrPercentage, LengthOrPercentageOrAuto, LinearGradient};
use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
use style_traits::cursor::Cursor;
use table_cell::CollapsedBordersForCell;
@@ -948,9 +947,12 @@ impl FragmentDisplayListBuilding for Fragment {
stacking_relative_flow_origin,
self);
- if !stacking_relative_border_box.intersects(stacking_relative_display_port) {
- debug!("Fragment::build_display_list: outside display port");
- return
+ // webrender deals with all culling via aabb
+ if !opts::get().use_webrender {
+ if !stacking_relative_border_box.intersects(stacking_relative_display_port) {
+ debug!("Fragment::build_display_list: outside display port");
+ return
+ }
}
// Calculate the clip rect. If there's nothing to render at all, don't even construct
@@ -1112,20 +1114,31 @@ impl FragmentDisplayListBuilding for Fragment {
}
SpecificFragmentInfo::Iframe(ref fragment_info) => {
if !stacking_relative_content_box.is_empty() {
- let layer_id = self.layer_id();
- display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem {
- item: DisplayItem::NoopClass(
- box BaseDisplayItem::new(&stacking_relative_content_box,
- DisplayItemMetadata::new(self.node,
- &*self.style,
- Cursor::DefaultCursor),
- clip)),
- layer_id: layer_id
- }));
-
- display_list.layer_info.push_back(LayerInfo::new(layer_id,
- ScrollPolicy::Scrollable,
- Some(fragment_info.pipeline_id)));
+ if opts::get().use_webrender {
+ display_list.content.push_back(DisplayItem::IframeClass(box IframeDisplayItem {
+ base: BaseDisplayItem::new(&stacking_relative_content_box,
+ DisplayItemMetadata::new(self.node,
+ &*self.style,
+ Cursor::DefaultCursor),
+ clip),
+ iframe: fragment_info.pipeline_id,
+ }));
+ } else {
+ let layer_id = self.layer_id();
+ display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem {
+ item: DisplayItem::NoopClass(
+ box BaseDisplayItem::new(&stacking_relative_content_box,
+ DisplayItemMetadata::new(self.node,
+ &*self.style,
+ Cursor::DefaultCursor),
+ clip)),
+ layer_id: layer_id
+ }));
+
+ display_list.layer_info.push_back(LayerInfo::new(layer_id,
+ ScrollPolicy::Scrollable,
+ Some(fragment_info.pipeline_id)));
+ }
}
}
SpecificFragmentInfo::Image(ref mut image_fragment) => {
@@ -1144,7 +1157,6 @@ impl FragmentDisplayListBuilding for Fragment {
}
}
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
- // TODO(ecoal95): make the canvas with a renderer use the custom layer
let width = canvas_fragment_info.replaced_image_fragment_info
.computed_inline_size.map_or(0, |w| w.to_px() as usize);
let height = canvas_fragment_info.replaced_image_fragment_info
@@ -1156,7 +1168,7 @@ impl FragmentDisplayListBuilding for Fragment {
let ipc_renderer = ipc_renderer.lock().unwrap();
let (sender, receiver) = ipc::channel().unwrap();
ipc_renderer.send(CanvasMsg::FromLayout(
- FromLayoutMsg::SendPixelContents(sender))).unwrap();
+ FromLayoutMsg::SendData(sender))).unwrap();
let data = receiver.recv().unwrap();
// Propagate the layer and the renderer to the paint thread.
@@ -1165,31 +1177,54 @@ impl FragmentDisplayListBuilding for Fragment {
data
},
- None => IpcSharedMemory::from_byte(0xFFu8, width * height * 4),
- };
- let display_item = DisplayItem::ImageClass(box ImageDisplayItem {
- base: BaseDisplayItem::new(&stacking_relative_content_box,
- DisplayItemMetadata::new(self.node,
- &*self.style,
- Cursor::DefaultCursor),
- clip),
- image: Arc::new(Image {
- width: width as u32,
- height: height as u32,
- format: PixelFormat::RGBA8,
- bytes: canvas_data,
+ None => CanvasData::Pixels(CanvasPixelData {
+ image_data: IpcSharedMemory::from_byte(0xFFu8, width * height * 4),
+ image_key: None,
}),
- stretch_size: stacking_relative_content_box.size,
- image_rendering: image_rendering::T::Auto,
- });
+ };
- display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem {
- item: display_item,
- layer_id: layer_id
- }));
+ let display_item = match canvas_data {
+ CanvasData::Pixels(canvas_data) => {
+ DisplayItem::ImageClass(box ImageDisplayItem {
+ base: BaseDisplayItem::new(&stacking_relative_content_box,
+ DisplayItemMetadata::new(self.node,
+ &*self.style,
+ Cursor::DefaultCursor),
+ clip),
+ image: Arc::new(Image {
+ width: width as u32,
+ height: height as u32,
+ format: PixelFormat::RGBA8,
+ bytes: canvas_data.image_data,
+ id: canvas_data.image_key,
+ }),
+ stretch_size: stacking_relative_content_box.size,
+ image_rendering: image_rendering::T::Auto,
+ })
+ }
+ CanvasData::WebGL(context_id) => {
+ DisplayItem::WebGLClass(box WebGLDisplayItem {
+ base: BaseDisplayItem::new(&stacking_relative_content_box,
+ DisplayItemMetadata::new(self.node,
+ &*self.style,
+ Cursor::DefaultCursor),
+ clip),
+ context_id: context_id,
+ })
+ }
+ };
+
+ if opts::get().use_webrender {
+ display_list.content.push_back(display_item);
+ } else {
+ display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem {
+ item: display_item,
+ layer_id: layer_id
+ }));
- display_list.layer_info.push_back(
- LayerInfo::new(layer_id, ScrollPolicy::Scrollable, None));
+ display_list.layer_info.push_back(
+ LayerInfo::new(layer_id, ScrollPolicy::Scrollable, None));
+ }
}
}
SpecificFragmentInfo::UnscannedText(_) => {
@@ -1993,4 +2028,3 @@ pub enum StackingContextCreationMode {
OuterScrollWrapper,
InnerScrollWrapper,
}
-
diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs
index e5f72a395e4..fbc1cd26daf 100644
--- a/components/layout/layout_thread.rs
+++ b/components/layout/layout_thread.rs
@@ -35,7 +35,7 @@ use ipc_channel::router::ROUTER;
use layout_debug;
use layout_traits::LayoutThreadFactory;
use log;
-use msg::constellation_msg::{ConstellationChan, Failure, PipelineId};
+use msg::constellation_msg::{ConstellationChan, ConvertPipelineIdToWebRender, Failure, PipelineId};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
use parallel;
use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
@@ -80,6 +80,8 @@ use util::opts;
use util::thread;
use util::thread_state;
use util::workqueue::WorkQueue;
+use webrender_helpers::WebRenderStackingContextConverter;
+use webrender_traits;
use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode, ThreadSafeLayoutNode};
/// The number of screens of data we're allowed to generate display lists for in each direction.
@@ -221,6 +223,8 @@ pub struct LayoutThread {
/// The CSS error reporter for all CSS loaded in this layout thread
error_reporter: CSSErrorReporter,
+ // Webrender interface, if enabled.
+ webrender_api: Option<webrender_traits::RenderApi>,
}
impl LayoutThreadFactory for LayoutThread {
@@ -240,7 +244,8 @@ impl LayoutThreadFactory for LayoutThread {
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan,
shutdown_chan: IpcSender<()>,
- content_process_shutdown_chan: IpcSender<()>) {
+ content_process_shutdown_chan: IpcSender<()>,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>) {
let ConstellationChan(con_chan) = constellation_chan.clone();
thread::spawn_named_with_send_on_failure(format!("LayoutThread {:?}", id),
thread_state::LAYOUT,
@@ -258,7 +263,8 @@ impl LayoutThreadFactory for LayoutThread {
image_cache_thread,
font_cache_thread,
time_profiler_chan,
- mem_profiler_chan.clone());
+ mem_profiler_chan.clone(),
+ webrender_api_sender);
let reporter_name = format!("layout-reporter-{}", id);
mem_profiler_chan.run_with_memory_reporting(|| {
@@ -367,7 +373,8 @@ impl LayoutThread {
image_cache_thread: ImageCacheThread,
font_cache_thread: FontCacheThread,
time_profiler_chan: time::ProfilerChan,
- mem_profiler_chan: mem::ProfilerChan)
+ mem_profiler_chan: mem::ProfilerChan,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>)
-> LayoutThread {
let device = Device::new(
MediaType::Screen,
@@ -437,6 +444,7 @@ impl LayoutThread {
expired_animations: Arc::new(RwLock::new(HashMap::new())),
epoch: Epoch(0),
viewport_size: Size2D::new(Au(0), Au(0)),
+ webrender_api: webrender_api_sender.map(|wr| wr.create_api()),
rw_data: Arc::new(Mutex::new(
LayoutThreadData {
constellation_chan: constellation_chan,
@@ -705,7 +713,8 @@ impl LayoutThread {
self.time_profiler_chan.clone(),
self.mem_profiler_chan.clone(),
info.layout_shutdown_chan,
- info.content_process_shutdown_chan);
+ info.content_process_shutdown_chan,
+ self.webrender_api.as_ref().map(|wr| wr.clone_sender()));
}
/// Enters a quiescent state in which no new messages will be processed until an `ExitNow` is
@@ -908,9 +917,40 @@ impl LayoutThread {
debug!("Layout done!");
self.epoch.next();
- self.paint_chan
- .send(LayoutToPaintMsg::PaintInit(self.epoch, paint_layer))
- .unwrap();
+
+ if opts::get().use_webrender {
+ let api = self.webrender_api.as_ref().unwrap();
+ // TODO: Avoid the temporary conversion and build webrender sc/dl directly!
+ let Epoch(epoch_number) = self.epoch;
+ let epoch = webrender_traits::Epoch(epoch_number);
+ let pipeline_id = self.id.to_webrender();
+
+ // TODO(gw) For now only create a root scrolling layer!
+ let root_scroll_layer_id = webrender_traits::ScrollLayerId::new(pipeline_id, 0);
+ let sc_id = rw_data.stacking_context.as_ref()
+ .unwrap()
+ .convert_to_webrender(&self.webrender_api.as_ref().unwrap(),
+ pipeline_id,
+ epoch,
+ Some(root_scroll_layer_id));
+ let root_background_color = webrender_traits::ColorF::new(root_background_color.r,
+ root_background_color.g,
+ root_background_color.b,
+ root_background_color.a);
+
+ let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(),
+ self.viewport_size.height.to_f32_px());
+
+ api.set_root_stacking_context(sc_id,
+ root_background_color,
+ epoch,
+ pipeline_id,
+ viewport_size);
+ } else {
+ self.paint_chan
+ .send(LayoutToPaintMsg::PaintInit(self.epoch, paint_layer))
+ .unwrap();
+ }
}
});
}
diff --git a/components/layout/lib.rs b/components/layout/lib.rs
index 498e91fb206..431f576ca78 100644
--- a/components/layout/lib.rs
+++ b/components/layout/lib.rs
@@ -59,6 +59,7 @@ extern crate unicode_script;
extern crate url;
#[macro_use]
extern crate util;
+extern crate webrender_traits;
#[macro_use]
mod layout_debug;
@@ -95,4 +96,5 @@ mod table_rowgroup;
mod table_wrapper;
mod text;
mod traversal;
+mod webrender_helpers;
mod wrapper;
diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs
new file mode 100644
index 00000000000..a1ab8fac3fe
--- /dev/null
+++ b/components/layout/webrender_helpers.rs
@@ -0,0 +1,481 @@
+/* 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/. */
+
+// TODO(gw): This contains helper traits and implementations for converting Servo display lists
+// into WebRender display lists. In the future, this step should be completely removed.
+// This might be achieved by sharing types between WR and Servo display lists, or
+// completely converting layout to directly generate WebRender display lists, for example.
+
+use app_units::Au;
+use azure::azure_hl::Color;
+use euclid::num::Zero;
+use euclid::{Point2D, Rect, Size2D};
+use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion};
+use gfx::display_list::{DisplayItem, DisplayList};
+use gfx::display_list::{GradientStop, StackingContext};
+use gfx_traits::ScrollPolicy;
+use msg::constellation_msg::ConvertPipelineIdToWebRender;
+use style::computed_values::filter::{self, Filter};
+use style::computed_values::{image_rendering, mix_blend_mode};
+use style::values::computed::BorderStyle;
+use webrender_traits;
+
+pub trait WebRenderStackingContextConverter {
+ fn convert_to_webrender(&self,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch,
+ scroll_layer_id: Option<webrender_traits::ScrollLayerId>)
+ -> webrender_traits::StackingContextId;
+}
+
+trait WebRenderDisplayListConverter {
+ fn convert_to_webrender(&self,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch) -> webrender_traits::DisplayListBuilder;
+}
+
+trait WebRenderDisplayItemConverter {
+ fn convert_to_webrender(&self,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch,
+ level: webrender_traits::StackingLevel,
+ builder: &mut webrender_traits::DisplayListBuilder);
+}
+
+trait ToBorderStyle {
+ fn to_border_style(&self) -> webrender_traits::BorderStyle;
+}
+
+impl ToBorderStyle for BorderStyle {
+ fn to_border_style(&self) -> webrender_traits::BorderStyle {
+ match *self {
+ BorderStyle::none => webrender_traits::BorderStyle::None,
+ BorderStyle::solid => webrender_traits::BorderStyle::Solid,
+ BorderStyle::double => webrender_traits::BorderStyle::Double,
+ BorderStyle::dotted => webrender_traits::BorderStyle::Dotted,
+ BorderStyle::dashed => webrender_traits::BorderStyle::Dashed,
+ BorderStyle::hidden => webrender_traits::BorderStyle::Hidden,
+ BorderStyle::groove => webrender_traits::BorderStyle::Groove,
+ BorderStyle::ridge => webrender_traits::BorderStyle::Ridge,
+ BorderStyle::inset => webrender_traits::BorderStyle::Inset,
+ BorderStyle::outset => webrender_traits::BorderStyle::Outset,
+ }
+ }
+}
+
+trait ToBoxShadowClipMode {
+ fn to_clip_mode(&self) -> webrender_traits::BoxShadowClipMode;
+}
+
+impl ToBoxShadowClipMode for BoxShadowClipMode {
+ fn to_clip_mode(&self) -> webrender_traits::BoxShadowClipMode {
+ match *self {
+ BoxShadowClipMode::None => webrender_traits::BoxShadowClipMode::None,
+ BoxShadowClipMode::Inset => webrender_traits::BoxShadowClipMode::Inset,
+ BoxShadowClipMode::Outset => webrender_traits::BoxShadowClipMode::Outset,
+ }
+ }
+}
+
+trait ToSizeF {
+ fn to_sizef(&self) -> Size2D<f32>;
+}
+
+trait ToPointF {
+ fn to_pointf(&self) -> Point2D<f32>;
+}
+
+impl ToPointF for Point2D<Au> {
+ fn to_pointf(&self) -> Point2D<f32> {
+ Point2D::new(self.x.to_f32_px(), self.y.to_f32_px())
+ }
+}
+
+impl ToSizeF for Size2D<Au> {
+ fn to_sizef(&self) -> Size2D<f32> {
+ Size2D::new(self.width.to_f32_px(), self.height.to_f32_px())
+ }
+}
+
+trait ToRectF {
+ fn to_rectf(&self) -> Rect<f32>;
+}
+
+impl ToRectF for Rect<Au> {
+ fn to_rectf(&self) -> Rect<f32> {
+ let x = self.origin.x.to_f32_px();
+ let y = self.origin.y.to_f32_px();
+ let w = self.size.width.to_f32_px();
+ let h = self.size.height.to_f32_px();
+ Rect::new(Point2D::new(x, y), Size2D::new(w, h))
+ }
+}
+
+trait ToColorF {
+ fn to_colorf(&self) -> webrender_traits::ColorF;
+}
+
+impl ToColorF for Color {
+ fn to_colorf(&self) -> webrender_traits::ColorF {
+ webrender_traits::ColorF::new(self.r, self.g, self.b, self.a)
+ }
+}
+
+trait ToGradientStop {
+ fn to_gradient_stop(&self) -> webrender_traits::GradientStop;
+}
+
+impl ToGradientStop for GradientStop {
+ fn to_gradient_stop(&self) -> webrender_traits::GradientStop {
+ webrender_traits::GradientStop {
+ offset: self.offset,
+ color: self.color.to_colorf(),
+ }
+ }
+}
+
+trait ToClipRegion {
+ fn to_clip_region(&self) -> webrender_traits::ClipRegion;
+}
+
+impl ToClipRegion for ClippingRegion {
+ fn to_clip_region(&self) -> webrender_traits::ClipRegion {
+ webrender_traits::ClipRegion::new(self.main.to_rectf(),
+ self.complex.iter().map(|complex_clipping_region| {
+ webrender_traits::ComplexClipRegion::new(
+ complex_clipping_region.rect.to_rectf(),
+ complex_clipping_region.radii.to_border_radius(),
+ )
+ }).collect())
+ }
+}
+
+trait ToBorderRadius {
+ fn to_border_radius(&self) -> webrender_traits::BorderRadius;
+}
+
+impl ToBorderRadius for BorderRadii<Au> {
+ fn to_border_radius(&self) -> webrender_traits::BorderRadius {
+ webrender_traits::BorderRadius {
+ top_left: self.top_left.to_sizef(),
+ top_right: self.top_right.to_sizef(),
+ bottom_left: self.bottom_left.to_sizef(),
+ bottom_right: self.bottom_right.to_sizef(),
+ }
+ }
+}
+
+trait ToBlendMode {
+ fn to_blend_mode(&self) -> webrender_traits::MixBlendMode;
+}
+
+impl ToBlendMode for mix_blend_mode::T {
+ fn to_blend_mode(&self) -> webrender_traits::MixBlendMode {
+ match *self {
+ mix_blend_mode::T::normal => webrender_traits::MixBlendMode::Normal,
+ mix_blend_mode::T::multiply => webrender_traits::MixBlendMode::Multiply,
+ mix_blend_mode::T::screen => webrender_traits::MixBlendMode::Screen,
+ mix_blend_mode::T::overlay => webrender_traits::MixBlendMode::Overlay,
+ mix_blend_mode::T::darken => webrender_traits::MixBlendMode::Darken,
+ mix_blend_mode::T::lighten => webrender_traits::MixBlendMode::Lighten,
+ mix_blend_mode::T::color_dodge => webrender_traits::MixBlendMode::ColorDodge,
+ mix_blend_mode::T::color_burn => webrender_traits::MixBlendMode::ColorBurn,
+ mix_blend_mode::T::hard_light => webrender_traits::MixBlendMode::HardLight,
+ mix_blend_mode::T::soft_light => webrender_traits::MixBlendMode::SoftLight,
+ mix_blend_mode::T::difference => webrender_traits::MixBlendMode::Difference,
+ mix_blend_mode::T::exclusion => webrender_traits::MixBlendMode::Exclusion,
+ mix_blend_mode::T::hue => webrender_traits::MixBlendMode::Hue,
+ mix_blend_mode::T::saturation => webrender_traits::MixBlendMode::Saturation,
+ mix_blend_mode::T::color => webrender_traits::MixBlendMode::Color,
+ mix_blend_mode::T::luminosity => webrender_traits::MixBlendMode::Luminosity,
+ }
+ }
+}
+
+trait ToImageRendering {
+ fn to_image_rendering(&self) -> webrender_traits::ImageRendering;
+}
+
+impl ToImageRendering for image_rendering::T {
+ fn to_image_rendering(&self) -> webrender_traits::ImageRendering {
+ match *self {
+ image_rendering::T::CrispEdges => webrender_traits::ImageRendering::CrispEdges,
+ image_rendering::T::Auto => webrender_traits::ImageRendering::Auto,
+ image_rendering::T::Pixelated => webrender_traits::ImageRendering::Pixelated,
+ }
+ }
+}
+
+trait ToFilterOps {
+ fn to_filter_ops(&self) -> Vec<webrender_traits::FilterOp>;
+}
+
+impl ToFilterOps for filter::T {
+ fn to_filter_ops(&self) -> Vec<webrender_traits::FilterOp> {
+ let mut result = Vec::with_capacity(self.filters.len());
+ for filter in self.filters.iter() {
+ match *filter {
+ Filter::Blur(radius) => result.push(webrender_traits::FilterOp::Blur(radius)),
+ Filter::Brightness(amount) => result.push(webrender_traits::FilterOp::Brightness(amount)),
+ Filter::Contrast(amount) => result.push(webrender_traits::FilterOp::Contrast(amount)),
+ Filter::Grayscale(amount) => result.push(webrender_traits::FilterOp::Grayscale(amount)),
+ Filter::HueRotate(angle) => result.push(webrender_traits::FilterOp::HueRotate(angle.0)),
+ Filter::Invert(amount) => result.push(webrender_traits::FilterOp::Invert(amount)),
+ Filter::Opacity(amount) => result.push(webrender_traits::FilterOp::Opacity(amount)),
+ Filter::Saturate(amount) => result.push(webrender_traits::FilterOp::Saturate(amount)),
+ Filter::Sepia(amount) => result.push(webrender_traits::FilterOp::Sepia(amount)),
+ }
+ }
+ result
+ }
+}
+
+impl WebRenderStackingContextConverter for StackingContext {
+ fn convert_to_webrender(&self,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch,
+ scroll_layer_id: Option<webrender_traits::ScrollLayerId>)
+ -> webrender_traits::StackingContextId {
+ let scroll_policy = self.layer_info
+ .map_or(webrender_traits::ScrollPolicy::Scrollable, |info| {
+ match info.scroll_policy {
+ ScrollPolicy::Scrollable => webrender_traits::ScrollPolicy::Scrollable,
+ ScrollPolicy::FixedPosition => webrender_traits::ScrollPolicy::Fixed,
+ }
+ });
+
+ let mut sc = webrender_traits::StackingContext::new(scroll_layer_id,
+ scroll_policy,
+ self.bounds.to_rectf(),
+ self.overflow.to_rectf(),
+ self.z_index,
+ &self.transform,
+ &self.perspective,
+ self.establishes_3d_context,
+ self.blend_mode.to_blend_mode(),
+ self.filters.to_filter_ops());
+
+ let dl_builder = self.display_list.convert_to_webrender(api,
+ pipeline_id,
+ epoch);
+ api.add_display_list(dl_builder, &mut sc, pipeline_id, epoch);
+
+ api.add_stacking_context(sc, pipeline_id, epoch)
+ }
+}
+
+impl WebRenderDisplayListConverter for Box<DisplayList> {
+ fn convert_to_webrender(&self,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch) -> webrender_traits::DisplayListBuilder {
+ let mut builder = webrender_traits::DisplayListBuilder::new();
+
+ for item in &self.background_and_borders {
+ item.convert_to_webrender(api,
+ pipeline_id,
+ epoch,
+ webrender_traits::StackingLevel::BackgroundAndBorders,
+ &mut builder);
+ }
+
+ for item in &self.block_backgrounds_and_borders {
+ item.convert_to_webrender(api,
+ pipeline_id,
+ epoch,
+ webrender_traits::StackingLevel::BlockBackgroundAndBorders,
+ &mut builder);
+ }
+
+ for item in &self.floats {
+ item.convert_to_webrender(api,
+ pipeline_id,
+ epoch,
+ webrender_traits::StackingLevel::Floats,
+ &mut builder);
+ }
+
+ for item in &self.content {
+ item.convert_to_webrender(api,
+ pipeline_id,
+ epoch,
+ webrender_traits::StackingLevel::Content,
+ &mut builder);
+ }
+
+ for item in &self.positioned_content {
+ item.convert_to_webrender(api,
+ pipeline_id,
+ epoch,
+ webrender_traits::StackingLevel::PositionedContent,
+ &mut builder);
+ }
+
+ for item in &self.outlines {
+ item.convert_to_webrender(api,
+ pipeline_id,
+ epoch,
+ webrender_traits::StackingLevel::Outlines,
+ &mut builder);
+ }
+
+ builder
+ }
+}
+
+impl WebRenderDisplayItemConverter for DisplayItem {
+ fn convert_to_webrender(&self,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch,
+ level: webrender_traits::StackingLevel,
+ builder: &mut webrender_traits::DisplayListBuilder) {
+ match *self {
+ DisplayItem::SolidColorClass(ref item) => {
+ let color = item.color.to_colorf();
+ if color.a > 0.0 {
+ builder.push_rect(level,
+ item.base.bounds.to_rectf(),
+ item.base.clip.to_clip_region(),
+ color);
+ }
+ }
+ DisplayItem::TextClass(ref item) => {
+ let mut origin = item.baseline_origin.clone();
+ let mut glyphs = vec!();
+
+ for slice in item.text_run.natural_word_slices_in_visual_order(&item.range) {
+ for glyph in slice.glyphs.iter_glyphs_for_char_range(&slice.range) {
+ let glyph_advance = glyph.advance();
+ let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
+ let glyph = webrender_traits::GlyphInstance {
+ index: glyph.id(),
+ x: (origin.x + glyph_offset.x).to_f32_px(),
+ y: (origin.y + glyph_offset.y).to_f32_px(),
+ };
+ origin = Point2D::new(origin.x + glyph_advance, origin.y);
+ glyphs.push(glyph);
+ };
+ }
+
+ if glyphs.len() > 0 {
+ builder.push_text(level,
+ item.base.bounds.to_rectf(),
+ item.base.clip.to_clip_region(),
+ glyphs,
+ item.text_run.font_key.expect("Font not added to webrender!"),
+ item.text_color.to_colorf(),
+ item.text_run.actual_pt_size,
+ item.blur_radius);
+ }
+ }
+ DisplayItem::ImageClass(ref item) => {
+ if let Some(id) = item.image.id {
+ if item.stretch_size.width > Au(0) &&
+ item.stretch_size.height > Au(0) {
+ builder.push_image(level,
+ item.base.bounds.to_rectf(),
+ item.base.clip.to_clip_region(),
+ item.stretch_size.to_sizef(),
+ item.image_rendering.to_image_rendering(),
+ id);
+ }
+ }
+ }
+ DisplayItem::WebGLClass(ref item) => {
+ builder.push_webgl_canvas(level,
+ item.base.bounds.to_rectf(),
+ item.base.clip.to_clip_region(),
+ item.context_id);
+ }
+ DisplayItem::BorderClass(ref item) => {
+ let rect = item.base.bounds.to_rectf();
+ let left = webrender_traits::BorderSide {
+ width: item.border_widths.left.to_f32_px(),
+ color: item.color.left.to_colorf(),
+ style: item.style.left.to_border_style(),
+ };
+ let top = webrender_traits::BorderSide {
+ width: item.border_widths.top.to_f32_px(),
+ color: item.color.top.to_colorf(),
+ style: item.style.top.to_border_style(),
+ };
+ let right = webrender_traits::BorderSide {
+ width: item.border_widths.right.to_f32_px(),
+ color: item.color.right.to_colorf(),
+ style: item.style.right.to_border_style(),
+ };
+ let bottom = webrender_traits::BorderSide {
+ width: item.border_widths.bottom.to_f32_px(),
+ color: item.color.bottom.to_colorf(),
+ style: item.style.bottom.to_border_style(),
+ };
+ let radius = item.radius.to_border_radius();
+ builder.push_border(level,
+ rect,
+ item.base.clip.to_clip_region(),
+ left,
+ top,
+ right,
+ bottom,
+ radius);
+ }
+ DisplayItem::GradientClass(ref item) => {
+ let rect = item.base.bounds.to_rectf();
+ let start_point = item.start_point.to_pointf();
+ let end_point = item.end_point.to_pointf();
+ let mut stops = Vec::new();
+ for stop in &item.stops {
+ stops.push(stop.to_gradient_stop());
+ }
+ builder.push_gradient(level,
+ rect,
+ item.base.clip.to_clip_region(),
+ start_point,
+ end_point,
+ stops);
+ }
+ DisplayItem::LineClass(..) => {
+ println!("TODO DisplayItem::LineClass");
+ }
+ DisplayItem::LayeredItemClass(..) |
+ DisplayItem::NoopClass(..) => {
+ panic!("Unexpected in webrender!");
+ }
+ DisplayItem::BoxShadowClass(ref item) => {
+ let rect = item.base.bounds.to_rectf();
+ let box_bounds = item.box_bounds.to_rectf();
+ builder.push_box_shadow(level,
+ rect,
+ item.base.clip.to_clip_region(),
+ box_bounds,
+ item.offset.to_pointf(),
+ item.color.to_colorf(),
+ item.blur_radius.to_f32_px(),
+ item.spread_radius.to_f32_px(),
+ item.border_radius.to_f32_px(),
+ item.clip_mode.to_clip_mode());
+ }
+ DisplayItem::IframeClass(ref item) => {
+ let rect = item.base.bounds.to_rectf();
+ let pipeline_id = item.iframe.to_webrender();
+ builder.push_iframe(level,
+ rect,
+ item.base.clip.to_clip_region(),
+ pipeline_id);
+ }
+ DisplayItem::StackingContextClass(ref item) => {
+ let stacking_context_id = item.convert_to_webrender(api,
+ pipeline_id,
+ epoch,
+ None);
+ builder.push_stacking_context(level, stacking_context_id);
+ }
+ }
+ }
+}
diff --git a/components/layout_traits/Cargo.toml b/components/layout_traits/Cargo.toml
index 33353c52773..1afb7d9b920 100644
--- a/components/layout_traits/Cargo.toml
+++ b/components/layout_traits/Cargo.toml
@@ -28,6 +28,9 @@ path = "../util"
[dependencies.ipc-channel]
git = "https://github.com/servo/ipc-channel"
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
[dependencies]
serde = "0.6"
serde_macros = "0.6"
diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs
index e5b39a1db4b..2be15566199 100644
--- a/components/layout_traits/lib.rs
+++ b/components/layout_traits/lib.rs
@@ -14,6 +14,7 @@ extern crate script_traits;
extern crate serde;
extern crate url;
extern crate util;
+extern crate webrender_traits;
// This module contains traits in layout used generically
// in the rest of Servo.
@@ -54,5 +55,6 @@ pub trait LayoutThreadFactory {
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan,
shutdown_chan: IpcSender<()>,
- content_process_shutdown_chan: IpcSender<()>);
+ content_process_shutdown_chan: IpcSender<()>,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>);
}
diff --git a/components/msg/Cargo.toml b/components/msg/Cargo.toml
index b96bdeb953a..05f84756a5f 100644
--- a/components/msg/Cargo.toml
+++ b/components/msg/Cargo.toml
@@ -20,6 +20,9 @@ git = "https://github.com/servo/ipc-channel"
[dependencies.plugins]
path = "../plugins"
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
[dependencies]
bitflags = "0.3"
cssparser = {version = "0.5.3", features = ["heap_size", "serde-serialization"]}
diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs
index adefb76010c..83f308b26fd 100644
--- a/components/msg/constellation_msg.rs
+++ b/components/msg/constellation_msg.rs
@@ -17,6 +17,7 @@ use std::fmt;
use url::Url;
use util::geometry::{PagePx, ViewportPx};
use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
+use webrender_traits;
#[derive(Deserialize, Serialize)]
pub struct ConstellationChan<T: Deserialize + Serialize>(pub IpcSender<T>);
@@ -207,7 +208,7 @@ pub enum WebDriverCommandMsg {
TakeScreenshot(PipelineId, IpcSender<Option<Image>>),
}
-#[derive(Deserialize, Eq, PartialEq, Serialize, HeapSizeOf)]
+#[derive(Clone, Copy, Deserialize, Eq, PartialEq, Serialize, HeapSizeOf)]
pub enum PixelFormat {
K8, // Luminance channel only
KA8, // Luminance + alpha
@@ -228,6 +229,8 @@ pub struct Image {
pub format: PixelFormat,
#[ignore_heap_size_of = "Defined in ipc-channel"]
pub bytes: IpcSharedMemory,
+ #[ignore_heap_size_of = "Defined in webrender_traits"]
+ pub id: Option<webrender_traits::ImageKey>,
}
/// Similar to net::resource_thread::LoadData
@@ -353,3 +356,28 @@ impl fmt::Display for PipelineId {
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct SubpageId(pub u32);
+
+pub trait ConvertPipelineIdToWebRender {
+ fn to_webrender(&self) -> webrender_traits::PipelineId;
+}
+
+pub trait ConvertPipelineIdFromWebRender {
+ fn from_webrender(&self) -> PipelineId;
+}
+
+impl ConvertPipelineIdToWebRender for PipelineId {
+ fn to_webrender(&self) -> webrender_traits::PipelineId {
+ let PipelineNamespaceId(namespace_id) = self.namespace_id;
+ let PipelineIndex(index) = self.index;
+ webrender_traits::PipelineId(namespace_id, index)
+ }
+}
+
+impl ConvertPipelineIdFromWebRender for webrender_traits::PipelineId {
+ fn from_webrender(&self) -> PipelineId {
+ PipelineId {
+ namespace_id: PipelineNamespaceId(self.0),
+ index: PipelineIndex(self.1),
+ }
+ }
+}
diff --git a/components/msg/lib.rs b/components/msg/lib.rs
index febf188fd77..93a513ef742 100644
--- a/components/msg/lib.rs
+++ b/components/msg/lib.rs
@@ -16,6 +16,7 @@ extern crate rustc_serialize;
extern crate serde;
extern crate url;
extern crate util;
+extern crate webrender_traits;
pub mod constellation_msg;
pub mod webdriver_msg;
diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml
index 5aef635d0fe..ae03f560029 100644
--- a/components/net/Cargo.toml
+++ b/components/net/Cargo.toml
@@ -28,6 +28,9 @@ path = "../msg"
[dependencies.ipc-channel]
git = "https://github.com/servo/ipc-channel"
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
[dependencies]
hyper = { version = "0.7", features = [ "serde-serialization" ] }
log = "0.3"
diff --git a/components/net/image_cache_thread.rs b/components/net/image_cache_thread.rs
index e7d960068e0..22797bda379 100644
--- a/components/net/image_cache_thread.rs
+++ b/components/net/image_cache_thread.rs
@@ -5,7 +5,7 @@
use immeta::load_from_buf;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
-use net_traits::image::base::{Image, ImageMetadata, load_from_memory};
+use net_traits::image::base::{Image, ImageMetadata, load_from_memory, PixelFormat};
use net_traits::image_cache_thread::ImageResponder;
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheCommand, ImageCacheThread, ImageState};
use net_traits::image_cache_thread::{ImageCacheResult, ImageOrMetadataAvailable, ImageResponse, UsePlaceholder};
@@ -23,6 +23,7 @@ use url::Url;
use util::resource_files::resources_dir_path;
use util::thread::spawn_named;
use util::threadpool::ThreadPool;
+use webrender_traits;
///
/// TODO(gw): Remaining work on image cache:
@@ -51,6 +52,12 @@ struct PendingLoad {
url: Arc<Url>
}
+enum LoadResult {
+ Loaded(Image),
+ PlaceholderLoaded(Arc<Image>),
+ None
+}
+
impl PendingLoad {
fn new(url: Arc<Url>) -> PendingLoad {
PendingLoad {
@@ -250,6 +257,9 @@ struct ImageCache {
// The placeholder image used when an image fails to load
placeholder_image: Option<Arc<Image>>,
+
+ // Webrender API instance, if enabled.
+ webrender_api: Option<webrender_traits::RenderApi>,
}
/// Message that the decoder worker threads send to main image cache thread.
@@ -265,6 +275,16 @@ enum SelectResult {
Decoder(DecoderMsg),
}
+fn convert_format(format: PixelFormat) -> webrender_traits::ImageFormat {
+ match format {
+ PixelFormat::K8 | PixelFormat::KA8 => {
+ panic!("Not support by webrender yet");
+ }
+ PixelFormat::RGB8 => webrender_traits::ImageFormat::RGB8,
+ PixelFormat::RGBA8 => webrender_traits::ImageFormat::RGBA8,
+ }
+}
+
impl ImageCache {
fn run(&mut self) {
let mut exit_sender: Option<IpcSender<()>> = None;
@@ -381,10 +401,10 @@ impl ImageCache {
Err(_) => {
match self.placeholder_image.clone() {
Some(placeholder_image) => {
- self.complete_load(msg.key, ImageResponse::PlaceholderLoaded(
+ self.complete_load(msg.key, LoadResult::PlaceholderLoaded(
placeholder_image))
}
- None => self.complete_load(msg.key, ImageResponse::None),
+ None => self.complete_load(msg.key, LoadResult::None),
}
}
}
@@ -395,16 +415,34 @@ impl ImageCache {
// Handle a message from one of the decoder worker threads
fn handle_decoder(&mut self, msg: DecoderMsg) {
let image = match msg.image {
- None => ImageResponse::None,
- Some(image) => ImageResponse::Loaded(Arc::new(image)),
+ None => LoadResult::None,
+ Some(image) => LoadResult::Loaded(image),
};
self.complete_load(msg.key, image);
}
// Change state of a url from pending -> loaded.
- fn complete_load(&mut self, key: LoadKey, image_response: ImageResponse) {
+ fn complete_load(&mut self, key: LoadKey, mut load_result: LoadResult) {
let pending_load = self.pending_loads.remove(&key).unwrap();
+ if let Some(ref webrender_api) = self.webrender_api {
+ match load_result {
+ LoadResult::Loaded(ref mut image) => {
+ let format = convert_format(image.format);
+ let mut bytes = Vec::new();
+ bytes.extend_from_slice(&*image.bytes);
+ image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes));
+ }
+ LoadResult::PlaceholderLoaded(..) | LoadResult::None => {}
+ }
+ }
+
+ let image_response = match load_result {
+ LoadResult::Loaded(image) => ImageResponse::Loaded(Arc::new(image)),
+ LoadResult::PlaceholderLoaded(image) => ImageResponse::PlaceholderLoaded(image),
+ LoadResult::None => ImageResponse::None,
+ };
+
let completed_load = CompletedLoad::new(image_response.clone());
self.completed_loads.insert(pending_load.url, completed_load);
@@ -510,7 +548,8 @@ impl ImageCache {
}
/// Create a new image cache.
-pub fn new_image_cache_thread(resource_thread: ResourceThread) -> ImageCacheThread {
+pub fn new_image_cache_thread(resource_thread: ResourceThread,
+ webrender_api: Option<webrender_traits::RenderApi>) -> ImageCacheThread {
let (ipc_command_sender, ipc_command_receiver) = ipc::channel().unwrap();
let (progress_sender, progress_receiver) = channel();
let (decoder_sender, decoder_receiver) = channel();
@@ -526,7 +565,14 @@ pub fn new_image_cache_thread(resource_thread: ResourceThread) -> ImageCacheThre
file.read_to_end(&mut image_data)
});
let placeholder_image = result.ok().map(|_| {
- Arc::new(load_from_memory(&image_data).unwrap())
+ let mut image = load_from_memory(&image_data).unwrap();
+ if let Some(ref webrender_api) = webrender_api {
+ let format = convert_format(image.format);
+ let mut bytes = Vec::new();
+ bytes.extend_from_slice(&*image.bytes);
+ image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes));
+ }
+ Arc::new(image)
});
// Ask the router to proxy messages received over IPC to us.
@@ -543,6 +589,7 @@ pub fn new_image_cache_thread(resource_thread: ResourceThread) -> ImageCacheThre
completed_loads: HashMap::new(),
resource_thread: resource_thread,
placeholder_image: placeholder_image,
+ webrender_api: webrender_api,
};
cache.run();
diff --git a/components/net/lib.rs b/components/net/lib.rs
index 143672962cb..fa354bfc439 100644
--- a/components/net/lib.rs
+++ b/components/net/lib.rs
@@ -27,6 +27,7 @@ extern crate time;
extern crate url;
extern crate util;
extern crate uuid;
+extern crate webrender_traits;
extern crate websocket;
pub mod about_loader;
diff --git a/components/net_traits/image/base.rs b/components/net_traits/image/base.rs
index 7faf439e34b..84612aae52b 100644
--- a/components/net_traits/image/base.rs
+++ b/components/net_traits/image/base.rs
@@ -5,6 +5,7 @@
use ipc_channel::ipc::IpcSharedMemory;
use piston_image::{self, DynamicImage, GenericImage, ImageFormat};
use stb_image::image as stb_image2;
+use util::opts;
use util::vec::byte_swap;
pub use msg::constellation_msg::{Image, ImageMetadata, PixelFormat};
@@ -15,14 +16,25 @@ pub use msg::constellation_msg::{Image, ImageMetadata, PixelFormat};
// TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this.
fn byte_swap_and_premultiply(data: &mut [u8]) {
let length = data.len();
+
+ // No need to pre-multiply alpha when using direct GPU rendering.
+ let premultiply_alpha = !opts::get().use_webrender;
+
for i in (0..length).step_by(4) {
let r = data[i + 2];
let g = data[i + 1];
let b = data[i + 0];
let a = data[i + 3];
- data[i + 0] = ((r as u32) * (a as u32) / 255) as u8;
- data[i + 1] = ((g as u32) * (a as u32) / 255) as u8;
- data[i + 2] = ((b as u32) * (a as u32) / 255) as u8;
+
+ if premultiply_alpha {
+ data[i + 0] = ((r as u32) * (a as u32) / 255) as u8;
+ data[i + 1] = ((g as u32) * (a as u32) / 255) as u8;
+ data[i + 2] = ((b as u32) * (a as u32) / 255) as u8;
+ } else {
+ data[i + 0] = r;
+ data[i + 1] = g;
+ data[i + 2] = b;
+ }
}
}
@@ -58,6 +70,7 @@ pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
height: image.height as u32,
format: PixelFormat::RGBA8,
bytes: IpcSharedMemory::from_bytes(&image.data[..]),
+ id: None,
})
}
stb_image2::LoadResult::ImageF32(_image) => {
@@ -83,6 +96,7 @@ pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
height: rgba.height(),
format: PixelFormat::RGBA8,
bytes: IpcSharedMemory::from_bytes(&*rgba),
+ id: None,
})
}
Err(e) => {
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index 3ab122d2bf7..0288efc206a 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -2,7 +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 canvas_traits::{CanvasMsg, FromLayoutMsg};
+use canvas_traits::{CanvasMsg, FromLayoutMsg, CanvasData};
use dom::attr::Attr;
use dom::attr::AttrValue;
use dom::bindings::cell::DOMRefCell;
@@ -202,10 +202,17 @@ impl HTMLCanvasElement {
let data = if let Some(renderer) = self.ipc_renderer() {
let (sender, receiver) = ipc::channel().unwrap();
- let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendPixelContents(sender));
+ let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendData(sender));
renderer.send(msg).unwrap();
- receiver.recv().unwrap().to_vec()
+ match receiver.recv().unwrap() {
+ CanvasData::Pixels(pixel_data)
+ => pixel_data.image_data.to_vec(),
+ CanvasData::WebGL(_)
+ // TODO(ecoal95): Not sure if WebGL canvas is required for 2d spec,
+ // but I think it's not.
+ => return None,
+ }
} else {
repeat(0xffu8).take((size.height as usize) * (size.width as usize) * 4).collect()
};
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index ff2d6968e9a..aba9e32b45f 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -72,6 +72,7 @@ pub struct WebGLRenderingContext {
#[ignore_heap_size_of = "Defined in ipc-channel"]
ipc_renderer: IpcSender<CanvasMsg>,
canvas: JS<HTMLCanvasElement>,
+ #[ignore_heap_size_of = "Defined in webrender_traits"]
last_error: Cell<Option<WebGLError>>,
texture_unpacking_settings: Cell<TextureUnpacking>,
bound_texture_2d: MutNullableHeap<JS<WebGLTexture>>,
@@ -462,6 +463,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Some(data) => data,
None => return self.webgl_error(InvalidValue),
};
+
if offset < 0 {
return self.webgl_error(InvalidValue);
}
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index 39b651e0912..9c4a7af6185 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -15,7 +15,7 @@ dependencies = [
"gaol 0.0.1 (git+https://github.com/servo/gaol)",
"gfx 0.0.1",
"gfx_tests 0.0.1",
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin_app 0.0.1",
"image 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)",
@@ -42,6 +42,8 @@ dependencies = [
"util 0.0.1",
"util_tests 0.0.1",
"webdriver_server 0.0.1",
+ "webrender 0.1.0 (git+https://github.com/glennw/webrender)",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
]
[[package]]
@@ -152,7 +154,7 @@ dependencies = [
"canvas_traits 0.0.1",
"euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_traits 0.0.1",
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)",
"layers 0.2.2 (git+https://github.com/servo/rust-layers)",
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -160,6 +162,7 @@ dependencies = [
"offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
"plugins 0.0.1",
"util 0.0.1",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
]
[[package]]
@@ -179,6 +182,7 @@ dependencies = [
"serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
]
[[package]]
@@ -200,7 +204,7 @@ name = "cgl"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -273,7 +277,7 @@ dependencies = [
"gaol 0.0.1 (git+https://github.com/servo/gaol)",
"gfx 0.0.1",
"gfx_traits 0.0.1",
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)",
"layers 0.2.2 (git+https://github.com/servo/rust-layers)",
@@ -292,6 +296,8 @@ dependencies = [
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
+ "webrender 0.1.0 (git+https://github.com/glennw/webrender)",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
]
[[package]]
@@ -680,6 +686,7 @@ dependencies = [
"unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
]
[[package]]
@@ -728,7 +735,7 @@ dependencies = [
[[package]]
name = "gleam"
-version = "0.2.3"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -748,7 +755,7 @@ dependencies = [
"cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"compositing 0.0.1",
"euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"layers 0.2.2 (git+https://github.com/servo/rust-layers)",
"msg 0.0.1",
"net_traits 0.0.1",
@@ -904,7 +911,7 @@ dependencies = [
"cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -965,7 +972,7 @@ dependencies = [
"cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"glx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_plugin 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1018,6 +1025,7 @@ dependencies = [
"unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
]
[[package]]
@@ -1034,6 +1042,7 @@ dependencies = [
"serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
]
[[package]]
@@ -1194,6 +1203,7 @@ dependencies = [
"serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
]
[[package]]
@@ -1218,6 +1228,7 @@ dependencies = [
"url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
"websocket 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1334,7 +1345,7 @@ dependencies = [
"core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1560,6 +1571,22 @@ version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "rustc_version"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "scoped_threadpool"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc_version 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "script"
version = "0.0.1"
dependencies = [
@@ -1660,6 +1687,11 @@ dependencies = [
]
[[package]]
+name = "semver"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "serde"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1766,7 +1798,7 @@ dependencies = [
"cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"expat-sys 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"glx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"io-surface 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2175,6 +2207,42 @@ dependencies = [
]
[[package]]
+name = "webrender"
+version = "0.1.0"
+source = "git+https://github.com/glennw/webrender#90cd6afdd64cdb48f606dbe0ce5d1ac352329004"
+dependencies = [
+ "app_units 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-text 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)",
+ "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
+ "scoped_threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
+ "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)",
+]
+
+[[package]]
+name = "webrender_traits"
+version = "0.1.0"
+source = "git+https://github.com/glennw/webrender_traits#8ccc1608590d219d1df54e49f2f1e887995b4d60"
+dependencies = [
+ "app_units 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)",
+ "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
+ "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "websocket"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml
index c4d2c6d9f36..9bea00cd956 100644
--- a/components/servo/Cargo.toml
+++ b/components/servo/Cargo.toml
@@ -52,6 +52,12 @@ name = "reftest"
path = "../../tests/reftest.rs"
harness = false
+[dependencies.webrender_traits]
+git = "https://github.com/glennw/webrender_traits"
+
+[dependencies.webrender]
+git = "https://github.com/glennw/webrender"
+
[features]
default = ["glutin_app", "window", "webdriver"]
window = ["glutin_app/window"]
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index 6544b69e002..67b6875da48 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -48,6 +48,9 @@ mod export {
#[cfg(feature = "webdriver")]
extern crate webdriver_server;
+extern crate webrender;
+extern crate webrender_traits;
+
#[cfg(feature = "webdriver")]
fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
webdriver_server::start_server(port, constellation);
@@ -82,6 +85,7 @@ use std::borrow::Borrow;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use util::opts;
+use util::resource_files::resources_dir_path;
pub use _util as util;
pub use export::canvas;
@@ -147,6 +151,35 @@ impl Browser {
devtools::start_server(port)
});
+ let (webrender, webrender_api_sender) = if opts::get().use_webrender {
+ let mut resource_path = resources_dir_path();
+ resource_path.push("shaders");
+
+ // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up!
+ let hidpi_factor = window.as_ref()
+ .map(|window| window.hidpi_factor().get())
+ .unwrap_or(1.0);
+ let device_pixel_ratio = match opts.device_pixels_per_px {
+ Some(device_pixels_per_px) => device_pixels_per_px,
+ None => match opts.output_file {
+ Some(_) => 1.0,
+ None => hidpi_factor,
+ }
+ };
+
+ let (webrender, webrender_sender) =
+ webrender::Renderer::new(webrender::RendererOptions {
+ device_pixel_ratio: device_pixel_ratio,
+ resource_path: resource_path,
+ enable_aa: opts.enable_text_antialiasing,
+ enable_msaa: opts.use_msaa,
+ enable_profiler: opts.webrender_stats,
+ });
+ (Some(webrender), Some(webrender_sender))
+ } else {
+ (None, None)
+ };
+
// Create the constellation, which maintains the engine
// pipelines, including the script and layout threads, as well
// as the navigation context.
@@ -155,7 +188,8 @@ impl Browser {
time_profiler_chan.clone(),
mem_profiler_chan.clone(),
devtools_chan,
- supports_clipboard);
+ supports_clipboard,
+ webrender_api_sender.clone());
if cfg!(feature = "webdriver") {
if let Some(port) = opts.webdriver_port {
@@ -171,6 +205,8 @@ impl Browser {
constellation_chan: constellation_chan,
time_profiler_chan: time_profiler_chan,
mem_profiler_chan: mem_profiler_chan,
+ webrender: webrender,
+ webrender_api_sender: webrender_api_sender,
});
Browser {
@@ -200,11 +236,13 @@ fn create_constellation(opts: opts::Opts,
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan,
devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
- supports_clipboard: bool) -> Sender<ConstellationMsg> {
+ supports_clipboard: bool,
+ webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Sender<ConstellationMsg> {
let resource_thread = new_resource_thread(opts.user_agent.clone(), devtools_chan.clone());
-
- let image_cache_thread = new_image_cache_thread(resource_thread.clone());
- let font_cache_thread = FontCacheThread::new(resource_thread.clone());
+ let image_cache_thread = new_image_cache_thread(resource_thread.clone(),
+ webrender_api_sender.as_ref().map(|wr| wr.create_api()));
+ let font_cache_thread = FontCacheThread::new(resource_thread.clone(),
+ webrender_api_sender.as_ref().map(|wr| wr.create_api()));
let storage_thread: StorageThread = StorageThreadFactory::new();
let initial_state = InitialConstellationState {
@@ -217,6 +255,7 @@ fn create_constellation(opts: opts::Opts,
time_profiler_chan: time_profiler_chan,
mem_profiler_chan: mem_profiler_chan,
supports_clipboard: supports_clipboard,
+ webrender_api_sender: webrender_api_sender,
};
let constellation_chan =
Constellation::<layout::layout_thread::LayoutThread,
diff --git a/components/util/opts.rs b/components/util/opts.rs
index b154abe211f..d2dbdc1c382 100644
--- a/components/util/opts.rs
+++ b/components/util/opts.rs
@@ -183,6 +183,15 @@ pub struct Opts {
/// Enable vsync in the compositor
pub enable_vsync: bool,
+
+ /// True to enable the webrender painting/compositing backend.
+ pub use_webrender: bool,
+
+ /// True to show webrender profiling stats on screen.
+ pub webrender_stats: bool,
+
+ /// True if WebRender should use multisample antialiasing.
+ pub use_msaa: bool,
}
fn print_usage(app: &str, opts: &Options) {
@@ -272,6 +281,12 @@ pub struct DebugOptions {
/// Disable vsync in the compositor
pub disable_vsync: bool,
+
+ /// Show webrender profiling stats on screen.
+ pub webrender_stats: bool,
+
+ /// Use multisample antialiasing in WebRender.
+ pub use_msaa: bool,
}
@@ -307,6 +322,8 @@ impl DebugOptions {
"gc-profile" => debug_options.gc_profile = true,
"load-webfonts-synchronously" => debug_options.load_webfonts_synchronously = true,
"disable-vsync" => debug_options.disable_vsync = true,
+ "wr-stats" => debug_options.webrender_stats = true,
+ "msaa" => debug_options.use_msaa = true,
"" => {},
_ => return Err(option)
};
@@ -354,6 +371,8 @@ pub fn print_debug_usage(app: &str) -> ! {
"Load web fonts synchronously to avoid non-deterministic network-driven reflows");
print_option("disable-vsync",
"Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate");
+ print_option("wr-stats", "Show WebRender profiler on screen.");
+ print_option("msaa", "Use multisample antialiasing in WebRender.");
println!("");
@@ -483,6 +502,9 @@ pub fn default_opts() -> Opts {
exit_after_load: false,
no_native_titlebar: false,
enable_vsync: true,
+ use_webrender: false,
+ webrender_stats: false,
+ use_msaa: false,
}
}
@@ -526,6 +548,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
opts.optmulti("", "pref",
"A preference to set to enable", "dom.mozbrowser.enabled");
opts.optflag("b", "no-native-titlebar", "Do not use native titlebar");
+ opts.optflag("w", "webrender", "Use webrender backend");
let opt_match = match opts.parse(args) {
Ok(m) => m,
@@ -668,6 +691,8 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
(contents, url)
}).collect();
+ let use_webrender = opt_match.opt_present("w") && !opt_match.opt_present("z");
+
let opts = Opts {
is_running_problem_test: is_running_problem_test,
url: Some(url),
@@ -717,6 +742,9 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
exit_after_load: opt_match.opt_present("x"),
no_native_titlebar: opt_match.opt_present("b"),
enable_vsync: !debug_options.disable_vsync,
+ use_webrender: use_webrender,
+ webrender_stats: debug_options.webrender_stats,
+ use_msaa: debug_options.use_msaa,
};
set_defaults(opts);