Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented the plumbing for paint worklets #17150

Merged
merged 1 commit into from Jun 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions components/layout/context.rs
Expand Up @@ -15,6 +15,7 @@ use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use opaque_node::OpaqueNodeMethods;
use parking_lot::RwLock;
use script_layout_interface::{PendingImage, PendingImageState};
use script_traits::PaintWorkletExecutor;
use script_traits::UntrustedNodeAddress;
use servo_url::ServoUrl;
use std::borrow::{Borrow, BorrowMut};
Expand Down Expand Up @@ -95,6 +96,9 @@ pub struct LayoutContext<'a> {
WebRenderImageInfo,
BuildHasherDefault<FnvHasher>>>>,

/// The executor for worklets
pub paint_worklet_executor: Option<Arc<PaintWorkletExecutor>>,

/// A list of in-progress image loads to be shared with the script thread.
/// A None value means that this layout was not initiated by the script thread.
pub pending_images: Option<Mutex<Vec<PendingImage>>>,
Expand Down
347 changes: 221 additions & 126 deletions components/layout/display_list_builder.rs

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions components/layout_thread/lib.rs
Expand Up @@ -90,6 +90,7 @@ use script_layout_interface::rpc::TextIndexResponse;
use script_layout_interface::wrapper_traits::LayoutNode;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
use script_traits::{ScrollState, UntrustedNodeAddress};
use script_traits::PaintWorkletExecutor;
use selectors::Element;
use servo_config::opts;
use servo_config::prefs::PREFS;
Expand Down Expand Up @@ -225,6 +226,9 @@ pub struct LayoutThread {

webrender_image_cache: Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder),
WebRenderImageInfo>>>,
/// The executor for paint worklets.
/// Will be None if the script thread hasn't added any paint worklet modules.
paint_worklet_executor: Option<Arc<PaintWorkletExecutor>>,

/// Webrender interface.
webrender_api: webrender_traits::RenderApi,
Expand Down Expand Up @@ -477,6 +481,7 @@ impl LayoutThread {
constellation_chan: constellation_chan.clone(),
time_profiler_chan: time_profiler_chan,
mem_profiler_chan: mem_profiler_chan,
paint_worklet_executor: None,
image_cache: image_cache.clone(),
font_cache_thread: font_cache_thread,
first_reflow: Cell::new(true),
Expand Down Expand Up @@ -574,6 +579,7 @@ impl LayoutThread {
webrender_image_cache: self.webrender_image_cache.clone(),
pending_images: if script_initiated_layout { Some(Mutex::new(vec![])) } else { None },
newly_transitioning_nodes: if script_initiated_layout { Some(Mutex::new(vec![])) } else { None },
paint_worklet_executor: self.paint_worklet_executor.clone(),
}
}

Expand Down Expand Up @@ -689,6 +695,11 @@ impl LayoutThread {
Msg::SetFinalUrl(final_url) => {
self.url = final_url;
},
Msg::SetPaintWorkletExecutor(executor) => {
debug!("Setting the paint worklet executor");
debug_assert!(self.paint_worklet_executor.is_none());
self.paint_worklet_executor = Some(executor);
},
Msg::PrepareToExit(response_chan) => {
self.prepare_to_exit(response_chan);
return false
Expand Down
36 changes: 15 additions & 21 deletions components/net/image_cache.rs
Expand Up @@ -57,9 +57,18 @@ fn get_placeholder_image(webrender_api: &webrender_traits::RenderApi, path: &Pat
let mut image_data = vec![];
try!(file.read_to_end(&mut image_data));
let mut image = load_from_memory(&image_data).unwrap();
set_webrender_image_key(webrender_api, &mut image);
Ok(Arc::new(image))
}

fn set_webrender_image_key(webrender_api: &webrender_traits::RenderApi, image: &mut Image) {
if image.id.is_some() { return; }
let format = convert_format(image.format);
let mut bytes = Vec::new();
bytes.extend_from_slice(&*image.bytes);
if format == webrender_traits::ImageFormat::RGBA8 {
premultiply(bytes.as_mut_slice());
}
let descriptor = webrender_traits::ImageDescriptor {
width: image.width,
height: image.height,
Expand All @@ -72,7 +81,6 @@ fn get_placeholder_image(webrender_api: &webrender_traits::RenderApi, path: &Pat
let image_key = webrender_api.generate_image_key();
webrender_api.add_image(image_key, descriptor, data, None);
image.id = Some(image_key);
Ok(Arc::new(image))
}

// TODO(gw): This is a port of the old is_image_opaque code from WR.
Expand Down Expand Up @@ -338,26 +346,7 @@ impl ImageCacheStore {
};

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);
if format == webrender_traits::ImageFormat::RGBA8 {
premultiply(bytes.as_mut_slice());
}
let descriptor = webrender_traits::ImageDescriptor {
width: image.width,
height: image.height,
stride: None,
format: format,
offset: 0,
is_opaque: is_image_opaque(format, &bytes),
};
let data = webrender_traits::ImageData::new(bytes);
let image_key = self.webrender_api.generate_image_key();
self.webrender_api.add_image(image_key, descriptor, data, None);
image.id = Some(image_key);
}
LoadResult::Loaded(ref mut image) => set_webrender_image_key(&self.webrender_api, image),
LoadResult::PlaceholderLoaded(..) | LoadResult::None => {}
}

Expand Down Expand Up @@ -576,4 +565,9 @@ impl ImageCache for ImageCacheImpl {
}
}
}

/// Ensure an image has a webrender key.
fn set_webrender_image_key(&self, image: &mut Image) {
set_webrender_image_key(&self.store.lock().unwrap().webrender_api, image);
}
}
3 changes: 3 additions & 0 deletions components/net_traits/image_cache.rs
Expand Up @@ -118,4 +118,7 @@ pub trait ImageCache: Sync + Send {

/// Inform the image cache about a response for a pending request.
fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg);

/// Ensure an image has a webrender key.
fn set_webrender_image_key(&self, image: &mut Image);
}
1 change: 1 addition & 0 deletions components/script/dom/mod.rs
Expand Up @@ -391,6 +391,7 @@ pub mod node;
pub mod nodeiterator;
pub mod nodelist;
pub mod pagetransitionevent;
pub mod paintworkletglobalscope;
pub mod performance;
pub mod performancetiming;
pub mod permissions;
Expand Down
97 changes: 97 additions & 0 deletions components/script/dom/paintworkletglobalscope.rs
@@ -0,0 +1,97 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PaintWorkletGlobalScopeBinding;
use dom::bindings::codegen::Bindings::PaintWorkletGlobalScopeBinding::PaintWorkletGlobalScopeMethods;
use dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
use dom::bindings::js::Root;
use dom::bindings::str::DOMString;
use dom::workletglobalscope::WorkletGlobalScope;
use dom::workletglobalscope::WorkletGlobalScopeInit;
use dom_struct::dom_struct;
use euclid::Size2D;
use ipc_channel::ipc::IpcSharedMemory;
use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use net_traits::image::base::Image;
use net_traits::image::base::PixelFormat;
use script_traits::PaintWorkletError;
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::rc::Rc;
use std::sync::mpsc::Sender;

#[dom_struct]
/// https://drafts.css-houdini.org/css-paint-api/#paintworkletglobalscope
pub struct PaintWorkletGlobalScope {
/// The worklet global for this object
worklet_global: WorkletGlobalScope,
/// A buffer to draw into
buffer: DOMRefCell<Vec<u8>>,
}

impl PaintWorkletGlobalScope {
#[allow(unsafe_code)]
pub fn new(runtime: &Runtime,
pipeline_id: PipelineId,
base_url: ServoUrl,
init: &WorkletGlobalScopeInit)
-> Root<PaintWorkletGlobalScope> {
debug!("Creating paint worklet global scope for pipeline {}.", pipeline_id);
let global = box PaintWorkletGlobalScope {
worklet_global: WorkletGlobalScope::new_inherited(pipeline_id, base_url, init),
buffer: Default::default(),
};
unsafe { PaintWorkletGlobalScopeBinding::Wrap(runtime.cx(), global) }
}

pub fn perform_a_worklet_task(&self, task: PaintWorkletTask) {
match task {
PaintWorkletTask::DrawAPaintImage(name, size, sender) => self.draw_a_paint_image(name, size, sender),
}
}

fn draw_a_paint_image(&self,
name: Atom,
concrete_object_size: Size2D<Au>,
sender: Sender<Result<Image, PaintWorkletError>>) {
let width = concrete_object_size.width.to_px().abs() as u32;
let height = concrete_object_size.height.to_px().abs() as u32;
let area = (width as usize) * (height as usize);
let old_buffer_size = self.buffer.borrow().len();
let new_buffer_size = area * 4;
debug!("Drawing a paint image {}({},{}).", name, width, height);
// TODO: call into script to create the image.
// For now, we just build a dummy.
if new_buffer_size > old_buffer_size {
let pixel = [0xFF, 0x00, 0x00, 0xFF];
self.buffer.borrow_mut().extend(pixel.iter().cycle().take(new_buffer_size - old_buffer_size));
} else {
self.buffer.borrow_mut().truncate(new_buffer_size);
}
let image = Image {
width: width,
height: height,
format: PixelFormat::RGBA8,
bytes: IpcSharedMemory::from_bytes(&*self.buffer.borrow()),
id: None,
};
let _ = sender.send(Ok(image));
}
}

impl PaintWorkletGlobalScopeMethods for PaintWorkletGlobalScope {
/// https://drafts.css-houdini.org/css-paint-api/#dom-paintworkletglobalscope-registerpaint
fn RegisterPaint(&self, name: DOMString, _paintCtor: Rc<VoidFunction>) {
debug!("Registering paint image name {}.", name);
// TODO
}
}

/// Tasks which can be peformed by a paint worklet
pub enum PaintWorkletTask {
DrawAPaintImage(Atom, Size2D<Au>, Sender<Result<Image, PaintWorkletError>>)
}
9 changes: 9 additions & 0 deletions components/script/dom/webidls/PaintWorkletGlobalScope.webidl
@@ -0,0 +1,9 @@
/* 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/. */

// https://drafts.css-houdini.org/css-paint-api/#paintworkletglobalscope
[Global=(Worklet,PaintWorklet), Exposed=PaintWorklet]
interface PaintWorkletGlobalScope : WorkletGlobalScope {
void registerPaint(DOMString name, VoidFunction paintCtor);
};
4 changes: 4 additions & 0 deletions components/script/dom/webidls/Window.webidl
Expand Up @@ -204,3 +204,7 @@ partial interface Window {
//readonly attribute EventSender eventSender;
};

// https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet
partial interface Window {
[SameObject] readonly attribute Worklet paintWorklet;
};
17 changes: 17 additions & 0 deletions components/script/dom/window.rs
Expand Up @@ -51,6 +51,7 @@ use dom::storage::Storage;
use dom::testrunner::TestRunner;
use dom::windowproxy::WindowProxy;
use dom::worklet::Worklet;
use dom::workletglobalscope::WorkletGlobalScopeType;
use dom_struct::dom_struct;
use euclid::{Point2D, Rect, Size2D};
use fetch;
Expand Down Expand Up @@ -279,6 +280,8 @@ pub struct Window {

/// Worklets
test_worklet: MutNullableJS<Worklet>,
/// https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet
paint_worklet: MutNullableJS<Worklet>,
}

impl Window {
Expand Down Expand Up @@ -373,6 +376,14 @@ impl Window {
self.webvr_thread.clone()
}

fn new_paint_worklet(&self) -> Root<Worklet> {
debug!("Creating new paint worklet.");
let worklet = Worklet::new(self, WorkletGlobalScopeType::Paint);
let executor = Arc::new(worklet.executor());
let _ = self.layout_chan.send(Msg::SetPaintWorkletExecutor(executor));
worklet
}

pub fn permission_state_invocation_results(&self) -> &DOMRefCell<HashMap<String, PermissionState>> {
&self.permission_state_invocation_results
}
Expand Down Expand Up @@ -1011,6 +1022,11 @@ impl WindowMethods for Window {
fetch::Fetch(&self.upcast(), input, init)
}

// https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet
fn PaintWorklet(&self) -> Root<Worklet> {
self.paint_worklet.or_init(|| self.new_paint_worklet())
}

fn TestRunner(&self) -> Root<TestRunner> {
self.test_runner.or_init(|| TestRunner::new(self.upcast()))
}
Expand Down Expand Up @@ -1856,6 +1872,7 @@ impl Window {
pending_layout_images: DOMRefCell::new(HashMap::new()),
unminified_js_dir: DOMRefCell::new(None),
test_worklet: Default::default(),
paint_worklet: Default::default(),
};

unsafe {
Expand Down