Implemented paint worklet rendering context.

This commit is contained in:
Alan Jeffrey 2017-06-09 12:47:39 -05:00
parent d47de6ccfc
commit 328fb25a65
15 changed files with 547 additions and 110 deletions

View file

@ -1174,21 +1174,30 @@ impl FragmentDisplayListBuilding for Fragment {
// TODO: add a one-place cache to avoid drawing the paint image every time.
// https://github.com/servo/servo/issues/17369
debug!("Drawing a paint image {}({},{}).", name, size.width.to_px(), size.height.to_px());
let mut image = match executor.draw_a_paint_image(name, size) {
Ok(image) => image,
Err(err) => return warn!("Error running paint worklet ({:?}).", err),
let (sender, receiver) = ipc::channel().unwrap();
executor.draw_a_paint_image(name, size, sender);
// TODO: timeout
let webrender_image = match receiver.recv() {
Ok(CanvasData::Image(canvas_data)) => {
WebRenderImageInfo {
// TODO: it would be nice to get this data back from the canvas
width: size.width.to_px().abs() as u32,
height: size.height.to_px().abs() as u32,
format: PixelFormat::BGRA8,
key: Some(canvas_data.image_key),
}
},
Ok(CanvasData::WebGL(_)) => return warn!("Paint worklet generated WebGL."),
Err(err) => return warn!("Paint worklet recv generated error ({}).", err),
};
// Make sure the image has a webrender key.
state.layout_context.image_cache.set_webrender_image_key(&mut image);
debug!("Drew a paint image ({},{}).", image.width, image.height);
self.build_display_list_for_webrender_image(state,
style,
display_list_section,
absolute_bounds,
clip,
WebRenderImageInfo::from_image(&image),
webrender_image,
index);
}

View file

@ -127,6 +127,7 @@ impl TrustedPromise {
struct RejectPromise(TrustedPromise, Error);
impl Runnable for RejectPromise {
fn main_thread_handler(self: Box<Self>, script_thread: &ScriptThread) {
debug!("Rejecting promise.");
let this = *self;
let cx = script_thread.get_cx();
let promise = this.0.root();
@ -145,6 +146,7 @@ impl TrustedPromise {
struct ResolvePromise<T>(TrustedPromise, T);
impl<T: ToJSValConvertible> Runnable for ResolvePromise<T> {
fn main_thread_handler(self: Box<Self>, script_thread: &ScriptThread) {
debug!("Resolving promise.");
let this = *self;
let cx = script_thread.get_cx();
let promise = this.0.root();

View file

@ -61,7 +61,9 @@ pub struct CanvasRenderingContext2D {
reflector_: Reflector,
#[ignore_heap_size_of = "Defined in ipc-channel"]
ipc_renderer: IpcSender<CanvasMsg>,
canvas: JS<HTMLCanvasElement>,
// For rendering contexts created by an HTML canvas element, this is Some,
// for ones created by a paint worklet, this is None.
canvas: Option<JS<HTMLCanvasElement>>,
state: DOMRefCell<CanvasContextState>,
saved_states: DOMRefCell<Vec<CanvasContextState>>,
origin_clean: Cell<bool>,
@ -109,18 +111,21 @@ impl CanvasContextState {
}
impl CanvasRenderingContext2D {
fn new_inherited(global: &GlobalScope,
canvas: &HTMLCanvasElement,
size: Size2D<i32>)
-> CanvasRenderingContext2D {
pub fn new_inherited(global: &GlobalScope,
canvas: Option<&HTMLCanvasElement>,
size: Size2D<i32>)
-> CanvasRenderingContext2D {
debug!("Creating new canvas rendering context.");
let (sender, receiver) = ipc::channel().unwrap();
let constellation_chan = global.constellation_chan();
debug!("Asking constellation to create new canvas thread.");
constellation_chan.send(ConstellationMsg::CreateCanvasPaintThread(size, sender)).unwrap();
let ipc_renderer = receiver.recv().unwrap();
debug!("Done.");
CanvasRenderingContext2D {
reflector_: Reflector::new(),
ipc_renderer: ipc_renderer,
canvas: JS::from_ref(canvas),
canvas: canvas.map(JS::from_ref),
state: DOMRefCell::new(CanvasContextState::new()),
saved_states: DOMRefCell::new(Vec::new()),
origin_clean: Cell::new(true),
@ -131,7 +136,7 @@ impl CanvasRenderingContext2D {
canvas: &HTMLCanvasElement,
size: Size2D<i32>)
-> Root<CanvasRenderingContext2D> {
reflect_dom_object(box CanvasRenderingContext2D::new_inherited(global, canvas, size),
reflect_dom_object(box CanvasRenderingContext2D::new_inherited(global, Some(canvas), size),
global,
CanvasRenderingContext2DBinding::Wrap)
}
@ -155,7 +160,9 @@ impl CanvasRenderingContext2D {
}
fn mark_as_dirty(&self) {
self.canvas.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
if let Some(ref canvas) = self.canvas {
canvas.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
}
fn update_transform(&self) {
@ -226,8 +233,12 @@ impl CanvasRenderingContext2D {
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::CanvasRenderingContext2D(image) =>
image.origin_is_clean(),
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::HTMLImageElement(image) => {
let canvas = match self.canvas {
Some(ref canvas) => canvas,
None => return false,
};
let image_origin = image.get_origin().expect("Image's origin is missing");
let document = document_from_node(&*self.canvas);
let document = document_from_node(&**canvas);
document.url().clone().origin() == image_origin
}
}
@ -347,7 +358,7 @@ impl CanvasRenderingContext2D {
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
if &*self.canvas == canvas {
if self.canvas.as_ref().map_or(false, |c| &**c == canvas) {
let msg = CanvasMsg::Canvas2d(Canvas2dMsg::DrawImageSelf(
image_size, dest_rect, source_rect, smoothing_enabled));
self.ipc_renderer.send(msg).unwrap();
@ -442,8 +453,10 @@ impl CanvasRenderingContext2D {
#[inline]
fn request_image_from_cache(&self, url: ServoUrl) -> ImageResponse {
let window = window_from_node(&*self.canvas);
canvas_utils::request_image_from_cache(&window, url)
self.canvas.as_ref()
.map(|canvas| window_from_node(&**canvas))
.map(|window| canvas_utils::request_image_from_cache(&window, url))
.unwrap_or(ImageResponse::None)
}
fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option<Rect<f32>> {
@ -472,12 +485,20 @@ impl CanvasRenderingContext2D {
// TODO: will need to check that the context bitmap mode is fixed
// once we implement CanvasProxy
let window = window_from_node(&*self.canvas);
let canvas = match self.canvas {
// https://drafts.css-houdini.org/css-paint-api/#2d-rendering-context
// Whenever "currentColor" is used as a color in the PaintRenderingContext2D API,
// it is treated as opaque black.
None => return Ok(RGBA::new(0, 0, 0, 255)),
Some(ref canvas) => &**canvas,
};
let style = window.GetComputedStyle(&*self.canvas.upcast(), None);
let window = window_from_node(canvas);
let style = window.GetComputedStyle(canvas.upcast(), None);
let element_not_rendered =
!self.canvas.upcast::<Node>().is_in_doc() ||
!canvas.upcast::<Node>().is_in_doc() ||
style.GetPropertyValue(DOMString::from("display")) == "none";
if element_not_rendered {
@ -530,7 +551,9 @@ impl LayoutCanvasRenderingContext2DHelpers for LayoutJS<CanvasRenderingContext2D
impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-canvas
fn Canvas(&self) -> Root<HTMLCanvasElement> {
Root::from_ref(&*self.canvas)
// This method is not called from a paint worklet rendering context,
// so it's OK to panic if self.canvas is None.
Root::from_ref(self.canvas.as_ref().expect("No canvas."))
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-save
@ -1037,7 +1060,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
let (sender, receiver) = ipc::channel::<Vec<u8>>().unwrap();
let dest_rect = Rect::new(Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()),
Size2D::new(sw as i32, sh as i32));
let canvas_size = self.canvas.get_size();
let canvas_size = self.canvas.as_ref().map(|c| c.get_size()).unwrap_or(Size2D::zero());
let canvas_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
self.ipc_renderer
.send(CanvasMsg::Canvas2d(Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender)))

View file

@ -2,28 +2,377 @@
* 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 canvas_traits::CanvasData;
use canvas_traits::CanvasMsg;
use canvas_traits::FromLayoutMsg;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineCap;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods;
use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding;
use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding::PaintRenderingContext2DMethods;
use dom::bindings::codegen::UnionTypes::HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D;
use dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern;
use dom::bindings::error::ErrorResult;
use dom::bindings::error::Fallible;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::reflector::Reflector;
use dom::bindings::num::Finite;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::canvasgradient::CanvasGradient;
use dom::canvaspattern::CanvasPattern;
use dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
use dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use dom_struct::dom_struct;
use euclid::Size2D;
use ipc_channel::ipc::IpcSender;
#[dom_struct]
pub struct PaintRenderingContext2D {
reflector: Reflector,
context: CanvasRenderingContext2D,
}
impl PaintRenderingContext2D {
fn new_inherited() -> PaintRenderingContext2D {
fn new_inherited(global: &PaintWorkletGlobalScope) -> PaintRenderingContext2D {
let size = Size2D::zero();
PaintRenderingContext2D {
reflector: Reflector::new(),
context: CanvasRenderingContext2D::new_inherited(global.upcast(), None, size),
}
}
pub fn new(global: &PaintWorkletGlobalScope) -> Root<PaintRenderingContext2D> {
reflect_dom_object(box PaintRenderingContext2D::new_inherited(),
reflect_dom_object(box PaintRenderingContext2D::new_inherited(global),
global,
PaintRenderingContext2DBinding::Wrap)
}
pub fn send_data(&self, sender: IpcSender<CanvasData>) {
let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendData(sender));
let _ = self.context.ipc_renderer().send(msg);
}
pub fn set_bitmap_dimensions(&self, size: Size2D<Au>) {
let size = Size2D::new(size.width.to_px(), size.height.to_px());
self.context.set_bitmap_dimensions(size);
}
}
impl PaintRenderingContext2DMethods for PaintRenderingContext2D {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-save
fn Save(&self) {
self.context.Save()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-restore
fn Restore(&self) {
self.context.Restore()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-scale
fn Scale(&self, x: f64, y: f64) {
self.context.Scale(x, y)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-rotate
fn Rotate(&self, angle: f64) {
self.context.Rotate(angle)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-translate
fn Translate(&self, x: f64, y: f64) {
self.context.Translate(x, y)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-transform
fn Transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
self.context.Transform(a, b, c, d, e, f)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform
fn SetTransform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
self.context.SetTransform(a, b, c, d, e, f)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-resettransform
fn ResetTransform(&self) {
self.context.ResetTransform()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha
fn GlobalAlpha(&self) -> f64 {
self.context.GlobalAlpha()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha
fn SetGlobalAlpha(&self, alpha: f64) {
self.context.SetGlobalAlpha(alpha)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalcompositeoperation
fn GlobalCompositeOperation(&self) -> DOMString {
self.context.GlobalCompositeOperation()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalcompositeoperation
fn SetGlobalCompositeOperation(&self, op_str: DOMString) {
self.context.SetGlobalCompositeOperation(op_str)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-fillrect
fn FillRect(&self, x: f64, y: f64, width: f64, height: f64) {
self.context.FillRect(x, y, width, height)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clearrect
fn ClearRect(&self, x: f64, y: f64, width: f64, height: f64) {
self.context.ClearRect(x, y, width, height)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokerect
fn StrokeRect(&self, x: f64, y: f64, width: f64, height: f64) {
self.context.StrokeRect(x, y, width, height)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-beginpath
fn BeginPath(&self) {
self.context.BeginPath()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-closepath
fn ClosePath(&self) {
self.context.ClosePath()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-fill
fn Fill(&self, fill_rule: CanvasFillRule) {
self.context.Fill(fill_rule)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke
fn Stroke(&self) {
self.context.Stroke()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
fn Clip(&self, fill_rule: CanvasFillRule) {
self.context.Clip(fill_rule)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath
fn IsPointInPath(&self, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
self.context.IsPointInPath(x, y, fill_rule)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage(&self,
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D,
dx: f64,
dy: f64)
-> ErrorResult {
self.context.DrawImage(image, dx, dy)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage_(&self,
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D,
dx: f64,
dy: f64,
dw: f64,
dh: f64)
-> ErrorResult {
self.context.DrawImage_(image, dx, dy, dw, dh)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage__(&self,
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D,
sx: f64,
sy: f64,
sw: f64,
sh: f64,
dx: f64,
dy: f64,
dw: f64,
dh: f64)
-> ErrorResult {
self.context.DrawImage__(image, sx, sy, sw, sh, dx, dy, dw, dh)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-moveto
fn MoveTo(&self, x: f64, y: f64) {
self.context.MoveTo(x, y)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-lineto
fn LineTo(&self, x: f64, y: f64) {
self.context.LineTo(x, y)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-rect
fn Rect(&self, x: f64, y: f64, width: f64, height: f64) {
self.context.Rect(x, y, width, height)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-quadraticcurveto
fn QuadraticCurveTo(&self, cpx: f64, cpy: f64, x: f64, y: f64) {
self.context.QuadraticCurveTo(cpx, cpy, x, y)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-beziercurveto
fn BezierCurveTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
self.context.BezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-arc
fn Arc(&self, x: f64, y: f64, r: f64, start: f64, end: f64, ccw: bool) -> ErrorResult {
self.context.Arc(x, y, r, start, end, ccw)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-arcto
fn ArcTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, r: f64) -> ErrorResult {
self.context.ArcTo(cp1x, cp1y, cp2x, cp2y, r)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-imagesmoothingenabled
fn ImageSmoothingEnabled(&self) -> bool {
self.context.ImageSmoothingEnabled()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-imagesmoothingenabled
fn SetImageSmoothingEnabled(&self, value: bool) {
self.context.SetImageSmoothingEnabled(value)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle
fn StrokeStyle(&self) -> StringOrCanvasGradientOrCanvasPattern {
self.context.StrokeStyle()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle
fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) {
self.context.SetStrokeStyle(value)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle
fn FillStyle(&self) -> StringOrCanvasGradientOrCanvasPattern {
self.context.FillStyle()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle
fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) {
self.context.SetFillStyle(value)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient
fn CreateLinearGradient(&self,
x0: Finite<f64>,
y0: Finite<f64>,
x1: Finite<f64>,
y1: Finite<f64>)
-> Root<CanvasGradient> {
self.context.CreateLinearGradient(x0, y0, x1, y1)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient
fn CreateRadialGradient(&self,
x0: Finite<f64>,
y0: Finite<f64>,
r0: Finite<f64>,
x1: Finite<f64>,
y1: Finite<f64>,
r1: Finite<f64>)
-> Fallible<Root<CanvasGradient>> {
self.context.CreateRadialGradient(x0, y0, r0, x1, y1, r1)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
fn CreatePattern(&self,
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D,
repetition: DOMString)
-> Fallible<Root<CanvasPattern>> {
self.context.CreatePattern(image, repetition)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
fn LineWidth(&self) -> f64 {
self.context.LineWidth()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
fn SetLineWidth(&self, width: f64) {
self.context.SetLineWidth(width)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap
fn LineCap(&self) -> CanvasLineCap {
self.context.LineCap()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap
fn SetLineCap(&self, cap: CanvasLineCap) {
self.context.SetLineCap(cap)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin
fn LineJoin(&self) -> CanvasLineJoin {
self.context.LineJoin()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin
fn SetLineJoin(&self, join: CanvasLineJoin) {
self.context.SetLineJoin(join)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit
fn MiterLimit(&self) -> f64 {
self.context.MiterLimit()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit
fn SetMiterLimit(&self, limit: f64) {
self.context.SetMiterLimit(limit)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsetx
fn ShadowOffsetX(&self) -> f64 {
self.context.ShadowOffsetX()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsetx
fn SetShadowOffsetX(&self, value: f64) {
self.context.SetShadowOffsetX(value)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsety
fn ShadowOffsetY(&self) -> f64 {
self.context.ShadowOffsetY()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsety
fn SetShadowOffsetY(&self, value: f64) {
self.context.SetShadowOffsetY(value)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowblur
fn ShadowBlur(&self) -> f64 {
self.context.ShadowBlur()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowblur
fn SetShadowBlur(&self, value: f64) {
self.context.SetShadowBlur(value)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
fn ShadowColor(&self) -> DOMString {
self.context.ShadowColor()
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
fn SetShadowColor(&self, value: DOMString) {
self.context.SetShadowColor(value)
}
}

View file

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use app_units::Au;
use canvas_traits::CanvasData;
use canvas_traits::CanvasImageData;
use dom::bindings::callback::CallbackContainer;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PaintWorkletGlobalScopeBinding;
@ -13,6 +15,7 @@ use dom::bindings::conversions::get_property;
use dom::bindings::conversions::get_property_jsval;
use dom::bindings::error::Error;
use dom::bindings::error::Fallible;
use dom::bindings::js::JS;
use dom::bindings::js::Root;
use dom::bindings::reflector::DomObject;
use dom::bindings::str::DOMString;
@ -22,6 +25,7 @@ use dom::workletglobalscope::WorkletGlobalScope;
use dom::workletglobalscope::WorkletGlobalScopeInit;
use dom_struct::dom_struct;
use euclid::Size2D;
use ipc_channel::ipc::IpcSender;
use ipc_channel::ipc::IpcSharedMemory;
use js::jsapi::Call;
use js::jsapi::Construct1;
@ -40,7 +44,7 @@ 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 net_traits::image_cache::ImageCache;
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::cell::Cell;
@ -48,19 +52,20 @@ use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ptr::null_mut;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use std::sync::Arc;
/// https://drafts.css-houdini.org/css-paint-api/#paintworkletglobalscope
#[dom_struct]
pub struct PaintWorkletGlobalScope {
/// The worklet global for this object
worklet_global: WorkletGlobalScope,
/// The image cache (used for generating invalid images).
#[ignore_heap_size_of = "Arc"]
image_cache: Arc<ImageCache>,
/// https://drafts.css-houdini.org/css-paint-api/#paint-definitions
paint_definitions: DOMRefCell<HashMap<Atom, Box<PaintDefinition>>>,
/// https://drafts.css-houdini.org/css-paint-api/#paint-class-instances
paint_class_instances: DOMRefCell<HashMap<Atom, Box<Heap<JSVal>>>>,
/// A buffer to draw into
buffer: DOMRefCell<Vec<u8>>,
}
impl PaintWorkletGlobalScope {
@ -73,9 +78,9 @@ impl 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),
image_cache: init.image_cache.clone(),
paint_definitions: Default::default(),
paint_class_instances: Default::default(),
buffer: Default::default(),
};
unsafe { PaintWorkletGlobalScopeBinding::Wrap(runtime.cx(), global) }
}
@ -90,7 +95,7 @@ impl PaintWorkletGlobalScope {
fn draw_a_paint_image(&self,
name: Atom,
size: Size2D<Au>,
sender: Sender<Result<Image, PaintWorkletError>>)
sender: IpcSender<CanvasData>)
{
// TODO: document paint definitions.
self.invoke_a_paint_callback(name, size, sender);
@ -101,7 +106,7 @@ impl PaintWorkletGlobalScope {
fn invoke_a_paint_callback(&self,
name: Atom,
size: Size2D<Au>,
sender: Sender<Result<Image, PaintWorkletError>>)
sender: IpcSender<CanvasData>)
{
let width = size.width.to_px().abs() as u32;
let height = size.height.to_px().abs() as u32;
@ -114,24 +119,21 @@ impl PaintWorkletGlobalScope {
// Step 2.2-5.1.
rooted!(in(cx) let mut class_constructor = UndefinedValue());
rooted!(in(cx) let mut paint_function = UndefinedValue());
match self.paint_definitions.borrow().get(&name) {
let rendering_context = match self.paint_definitions.borrow().get(&name) {
None => {
// Step 2.2.
warn!("Drawing un-registered paint definition {}.", name);
let image = self.placeholder_image(width, height, [0x00, 0x00, 0xFF, 0xFF]);
let _ = sender.send(Ok(image));
return;
return self.send_invalid_image(size, sender);
}
Some(definition) => {
// Step 5.1
if !definition.constructor_valid_flag.get() {
debug!("Drawing invalid paint definition {}.", name);
let image = self.placeholder_image(width, height, [0x00, 0x00, 0xFF, 0xFF]);
let _ = sender.send(Ok(image));
return;
return self.send_invalid_image(size, sender);
}
class_constructor.set(definition.class_constructor.get());
paint_function.set(definition.paint_function.get());
Root::from_ref(&*definition.context)
}
};
@ -155,9 +157,7 @@ impl PaintWorkletGlobalScope {
self.paint_definitions.borrow_mut().get_mut(&name)
.expect("Vanishing paint definition.")
.constructor_valid_flag.set(false);
let image = self.placeholder_image(width, height, [0x00, 0x00, 0xFF, 0xFF]);
let _ = sender.send(Ok(image));
return;
return self.send_invalid_image(size, sender);
}
// Step 5.4
entry.insert(Box::new(Heap::default())).set(paint_instance.get());
@ -166,7 +166,9 @@ impl PaintWorkletGlobalScope {
// TODO: Steps 6-7
// Step 8
let rendering_context = PaintRenderingContext2D::new(self);
// TODO: the spec requires creating a new paint rendering context each time,
// this code recycles the same one.
rendering_context.set_bitmap_dimensions(size);
// Step 9
let paint_size = PaintSize::new(self, size);
@ -186,37 +188,37 @@ impl PaintWorkletGlobalScope {
if unsafe { JS_IsExceptionPending(cx) } {
debug!("Paint function threw an exception {}.", name);
unsafe { JS_ClearPendingException(cx); }
let image = self.placeholder_image(width, height, [0x00, 0x00, 0xFF, 0xFF]);
let _ = sender.send(Ok(image));
return;
return self.send_invalid_image(size, sender);
}
// For now, we just build a dummy image.
let image = self.placeholder_image(width, height, [0xFF, 0x00, 0x00, 0xFF]);
let _ = sender.send(Ok(image));
rendering_context.send_data(sender);
}
fn placeholder_image(&self, width: u32, height: u32, pixel: [u8; 4]) -> Image {
let area = (width as usize) * (height as usize);
let old_buffer_size = self.buffer.borrow().len();
let new_buffer_size = area * 4;
if new_buffer_size > old_buffer_size {
self.buffer.borrow_mut().extend(pixel.iter().cycle().take(new_buffer_size - old_buffer_size));
} else {
self.buffer.borrow_mut().truncate(new_buffer_size);
}
Image {
fn send_invalid_image(&self, size: Size2D<Au>, sender: IpcSender<CanvasData>) {
debug!("Sending an invalid image.");
let width = size.width.to_px().abs() as u32;
let height = size.height.to_px().abs() as u32;
let len = (width as usize) * (height as usize) * 4;
let pixel = [0xFF, 0x00, 0x00, 0xFF];
let bytes: Vec<u8> = pixel.iter().cloned().cycle().take(len).collect();
let mut image = Image {
width: width,
height: height,
format: PixelFormat::BGRA8,
bytes: IpcSharedMemory::from_bytes(&*self.buffer.borrow()),
bytes: IpcSharedMemory::from_bytes(&*bytes),
id: None,
}
};
self.image_cache.set_webrender_image_key(&mut image);
let image_key = image.id.expect("Image cache should set image key.");
let image_data = CanvasImageData { image_key: image_key };
let canvas_data = CanvasData::Image(image_data);
let _ = sender.send(canvas_data);
}
}
impl PaintWorkletGlobalScopeMethods for PaintWorkletGlobalScope {
#[allow(unsafe_code)]
#[allow(unrooted_must_root)]
/// https://drafts.css-houdini.org/css-paint-api/#dom-paintworkletglobalscope-registerpaint
fn RegisterPaint(&self, name: DOMString, paint_ctor: Rc<VoidFunction>) -> Fallible<()> {
let name = Atom::from(name);
@ -279,11 +281,17 @@ impl PaintWorkletGlobalScopeMethods for PaintWorkletGlobalScope {
return Err(Error::Type(String::from("Paint function is not callable.")));
}
// Steps 19-20.
// Step 19.
let context = PaintRenderingContext2D::new(self);
let definition = PaintDefinition::new(paint_val.handle(),
paint_function.handle(),
input_properties,
alpha,
&*context);
// Step 20.
debug!("Registering definition {}.", name);
self.paint_definitions.borrow_mut()
.insert(name,
PaintDefinition::new(paint_val.handle(), paint_function.handle(), input_properties, alpha));
self.paint_definitions.borrow_mut().insert(name, definition);
// TODO: Step 21.
@ -293,7 +301,7 @@ impl PaintWorkletGlobalScopeMethods for PaintWorkletGlobalScope {
/// Tasks which can be peformed by a paint worklet
pub enum PaintWorkletTask {
DrawAPaintImage(Atom, Size2D<Au>, Sender<Result<Image, PaintWorkletError>>)
DrawAPaintImage(Atom, Size2D<Au>, IpcSender<CanvasData>)
}
/// A paint definition
@ -308,13 +316,18 @@ struct PaintDefinition {
constructor_valid_flag: Cell<bool>,
input_properties: Vec<DOMString>,
context_alpha_flag: bool,
// TODO: the spec calls for fresh rendering contexts each time a paint image is drawn,
// but to avoid having the primary worklet thread create a new renering context,
// we recycle them.
context: JS<PaintRenderingContext2D>,
}
impl PaintDefinition {
fn new(class_constructor: HandleValue,
paint_function: HandleValue,
input_properties: Vec<DOMString>,
alpha: bool)
alpha: bool,
context: &PaintRenderingContext2D)
-> Box<PaintDefinition>
{
let result = Box::new(PaintDefinition {
@ -323,6 +336,7 @@ impl PaintDefinition {
constructor_valid_flag: Cell::new(true),
input_properties: input_properties,
context_alpha_flag: alpha,
context: JS::from_ref(context),
});
result.class_constructor.set(class_constructor.get());
result.paint_function.set(paint_function.get());

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://html.spec.whatwg.org/multipage/#canvasgradient
[Exposed=(Window, PaintWorklet)]
interface CanvasGradient {
// opaque object
[Throws]

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://html.spec.whatwg.org/multipage/#canvaspattern
[Exposed=(Window, PaintWorklet)]
interface CanvasPattern {
//void setTransform(SVGMatrix matrix);
};

View file

@ -41,14 +41,14 @@ CanvasRenderingContext2D implements CanvasPathDrawingStyles;
CanvasRenderingContext2D implements CanvasTextDrawingStyles;
CanvasRenderingContext2D implements CanvasPath;
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasState {
// state
void save(); // push state on state stack
void restore(); // pop state stack and restore state
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasTransform {
// transformations (default transform is the identity matrix)
void scale(unrestricted double x, unrestricted double y);
@ -72,21 +72,21 @@ interface CanvasTransform {
void resetTransform();
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasCompositing {
// compositing
attribute unrestricted double globalAlpha; // (default 1.0)
attribute DOMString globalCompositeOperation; // (default source-over)
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasImageSmoothing {
// image smoothing
attribute boolean imageSmoothingEnabled; // (default true)
// attribute ImageSmoothingQuality imageSmoothingQuality; // (default low)
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasFillStrokeStyles {
// colours and styles (see also the CanvasDrawingStyles interface)
@ -99,7 +99,7 @@ interface CanvasFillStrokeStyles {
CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasShadowStyles {
// shadows
attribute unrestricted double shadowOffsetX; // (default 0)
@ -108,7 +108,7 @@ interface CanvasShadowStyles {
attribute DOMString shadowColor; // (default transparent black)
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasRect {
// rects
//[LenientFloat]
@ -119,7 +119,7 @@ interface CanvasRect {
void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasDrawPath {
// path API (see also CanvasPathMethods)
void beginPath();
@ -157,7 +157,7 @@ interface CanvasText {
//TextMetrics measureText(DOMString text);
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasDrawImage {
// drawing images
[Throws]
@ -205,7 +205,7 @@ enum CanvasTextAlign { "start", "end", "left", "right", "center" };
enum CanvasTextBaseline { "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" };
enum CanvasDirection { "ltr", "rtl", "inherit" };
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window, PaintWorklet)]
interface CanvasPathDrawingStyles {
// line caps/joins
attribute unrestricted double lineWidth; // (default 1)
@ -229,7 +229,7 @@ interface CanvasTextDrawingStyles {
//attribute CanvasDirection direction; // "ltr", "rtl", "inherit" (default: "inherit")
};
[NoInterfaceObject, Exposed=(Window,Worker)]
[NoInterfaceObject, Exposed=(Window, Worker, PaintWorklet)]
interface CanvasPath {
// shared path API methods
void closePath();

View file

@ -6,14 +6,14 @@
[Exposed=PaintWorklet]
interface PaintRenderingContext2D {
};
// PaintRenderingContext2D implements CanvasState;
// PaintRenderingContext2D implements CanvasTransform;
// PaintRenderingContext2D implements CanvasCompositing;
// PaintRenderingContext2D implements CanvasImageSmoothing;
// PaintRenderingContext2D implements CanvasFillStrokeStyles;
// PaintRenderingContext2D implements CanvasShadowStyles;
// PaintRenderingContext2D implements CanvasRect;
// PaintRenderingContext2D implements CanvasDrawPath;
// PaintRenderingContext2D implements CanvasDrawImage;
// PaintRenderingContext2D implements CanvasPathDrawingStyles;
// PaintRenderingContext2D implements CanvasPath;
PaintRenderingContext2D implements CanvasState;
PaintRenderingContext2D implements CanvasTransform;
PaintRenderingContext2D implements CanvasCompositing;
PaintRenderingContext2D implements CanvasImageSmoothing;
PaintRenderingContext2D implements CanvasFillStrokeStyles;
PaintRenderingContext2D implements CanvasShadowStyles;
PaintRenderingContext2D implements CanvasRect;
PaintRenderingContext2D implements CanvasDrawPath;
PaintRenderingContext2D implements CanvasDrawImage;
PaintRenderingContext2D implements CanvasPathDrawingStyles;
PaintRenderingContext2D implements CanvasPath;

View file

@ -152,6 +152,7 @@ pub enum ReflowReason {
ImageLoaded,
RequestAnimationFrame,
WebFontLoaded,
WorkletLoaded,
FramedContentChanged,
IFrameLoadEvent,
MissingExplicitReflow,
@ -1939,6 +1940,7 @@ fn debug_reflow_events(id: PipelineId, goal: &ReflowGoal, query_type: &ReflowQue
ReflowReason::ImageLoaded => "\tImageLoaded",
ReflowReason::RequestAnimationFrame => "\tRequestAnimationFrame",
ReflowReason::WebFontLoaded => "\tWebFontLoaded",
ReflowReason::WorkletLoaded => "\tWorkletLoaded",
ReflowReason::FramedContentChanged => "\tFramedContentChanged",
ReflowReason::IFrameLoadEvent => "\tIFrameLoadEvent",
ReflowReason::MissingExplicitReflow => "\tMissingExplicitReflow",

View file

@ -11,6 +11,7 @@
//! a backup thread, not on the primary worklet thread.
use app_units::Au;
use canvas_traits::CanvasData;
use dom::bindings::codegen::Bindings::RequestBinding::RequestCredentials;
use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use dom::bindings::codegen::Bindings::WorkletBinding::WorkletMethods;
@ -38,6 +39,7 @@ use dom::workletglobalscope::WorkletGlobalScopeType;
use dom::workletglobalscope::WorkletTask;
use dom_struct::dom_struct;
use euclid::Size2D;
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSGCParamKey;
use js::jsapi::JSTracer;
use js::jsapi::JS_GC;
@ -45,7 +47,6 @@ use js::jsapi::JS_GetGCParameter;
use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use net_traits::IpcSend;
use net_traits::image::base::Image;
use net_traits::load_whole_resource;
use net_traits::request::Destination;
use net_traits::request::RequestInit;
@ -58,7 +59,6 @@ use script_runtime::new_rt_and_cx;
use script_thread::MainThreadScriptMsg;
use script_thread::Runnable;
use script_thread::ScriptThread;
use script_traits::PaintWorkletError;
use script_traits::PaintWorkletExecutor;
use servo_atoms::Atom;
use servo_rand;
@ -76,7 +76,6 @@ use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::thread;
use std::time::Duration;
use style::thread_state;
use swapper::Swapper;
use swapper::swapper;
@ -85,7 +84,6 @@ use uuid::Uuid;
// Magic numbers
const WORKLET_THREAD_POOL_SIZE: u32 = 3;
const MIN_GC_THRESHOLD: u32 = 1_000_000;
const PAINT_TIMEOUT_MILLISECONDS: u64 = 10;
#[dom_struct]
/// https://drafts.css-houdini.org/worklets/#worklet
@ -163,6 +161,7 @@ impl WorkletMethods for Worklet {
&promise);
// Step 5.
debug!("Returning promise.");
promise
}
}
@ -234,6 +233,17 @@ impl PendingTasksStruct {
/// The thread pool lives in the script thread, and is initialized
/// when a worklet adds a module. It is dropped when the script thread
/// is dropped, and asks each of the worklet threads to quit.
///
/// The layout thread can end up blocking on the primary worklet thread
/// (e.g. when invoking a paint callback), so it is important to avoid
/// deadlock by making sure the primary worklet thread doesn't end up
/// blocking waiting on layout. In particular, since the constellation
/// can block waiting on layout, this means the primary worklet thread
/// can't block waiting on the constellation. In general, the primary
/// worklet thread shouldn't perform any blocking operations. If a worklet
/// thread needs to do anything blocking, it should send a control
/// message, to make sure that the blocking operation is performed
/// by a backup thread, not by the primary thread.
#[derive(Clone, JSTraceable)]
pub struct WorkletThreadPool {
@ -551,6 +561,7 @@ impl WorkletThread {
match self.global_scopes.entry(worklet_id) {
hash_map::Entry::Occupied(entry) => Root::from_ref(entry.get()),
hash_map::Entry::Vacant(entry) => {
debug!("Creating new worklet global scope.");
let result = global_type.new(&self.runtime, pipeline_id, base_url, &self.global_init);
entry.insert(JS::from_ref(&*result));
result
@ -562,6 +573,7 @@ impl WorkletThread {
/// https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script
fn fetch_and_invoke_a_worklet_script(&self,
global_scope: &WorkletGlobalScope,
pipeline_id: PipelineId,
origin: ImmutableOrigin,
script_url: ServoUrl,
credentials: RequestCredentials,
@ -612,7 +624,9 @@ impl WorkletThread {
debug!("Finished adding script.");
let old_counter = pending_tasks_struct.decrement_counter_by(1);
if old_counter == 1 {
// TODO: trigger a reflow?
debug!("Resolving promise.");
let msg = MainThreadScriptMsg::WorkletLoaded(pipeline_id);
self.script_sender.send(msg).expect("Worklet thread outlived script thread.");
self.run_in_script_thread(promise.resolve_runnable(()));
}
}
@ -638,6 +652,7 @@ impl WorkletThread {
global_type,
base_url);
self.fetch_and_invoke_a_worklet_script(&*global,
pipeline_id,
origin,
script_url,
credentials,
@ -678,13 +693,10 @@ impl PaintWorkletExecutor for WorkletExecutor {
/// https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image
fn draw_a_paint_image(&self,
name: Atom,
concrete_object_size: Size2D<Au>)
-> Result<Image, PaintWorkletError>
concrete_object_size: Size2D<Au>,
sender: IpcSender<CanvasData>)
{
let (sender, receiver) = mpsc::channel();
let task = WorkletTask::Paint(PaintWorkletTask::DrawAPaintImage(name, concrete_object_size, sender));
let timeout = Duration::from_millis(PAINT_TIMEOUT_MILLISECONDS);
self.schedule_a_worklet_task(task);
receiver.recv_timeout(timeout)?
}
}

View file

@ -20,6 +20,7 @@ use microtask::Microtask;
use microtask::MicrotaskQueue;
use msg::constellation_msg::PipelineId;
use net_traits::ResourceThreads;
use net_traits::image_cache::ImageCache;
use profile_traits::mem;
use profile_traits::time;
use script_traits::ScriptMsg;
@ -27,6 +28,7 @@ use script_traits::TimerSchedulerMsg;
use servo_url::ImmutableOrigin;
use servo_url::MutableOrigin;
use servo_url::ServoUrl;
use std::sync::Arc;
#[dom_struct]
/// https://drafts.css-houdini.org/worklets/#workletglobalscope
@ -123,6 +125,8 @@ pub struct WorkletGlobalScopeInit {
pub constellation_chan: IpcSender<ScriptMsg>,
/// Message to send to the scheduler
pub scheduler_chan: IpcSender<TimerSchedulerMsg>,
/// The image cache
pub image_cache: Arc<ImageCache>,
}
/// https://drafts.css-houdini.org/worklets/#worklet-global-scope-type

View file

@ -256,6 +256,9 @@ pub enum MainThreadScriptMsg {
DOMManipulation(DOMManipulationTask),
/// Tasks that originate from the user interaction task source
UserInteraction(UserInteractionTask),
/// Notifies the script thread that a new worklet has been loaded, and thus the page should be
/// reflowed.
WorkletLoaded(PipelineId),
}
impl OpaqueSender<CommonScriptMsg> for Box<ScriptChan + Send> {
@ -724,6 +727,7 @@ impl ScriptThread {
devtools_chan: script_thread.devtools_chan.clone(),
constellation_chan: script_thread.constellation_chan.clone(),
scheduler_chan: script_thread.scheduler_chan.clone(),
image_cache: script_thread.image_cache.clone(),
};
Rc::new(WorkletThreadPool::spawn(chan, init))
}).clone()
@ -828,6 +832,7 @@ impl ScriptThread {
debug!("Starting script thread.");
while self.handle_msgs() {
// Go on...
debug!("Running script thread.");
}
debug!("Stopped script thread.");
}
@ -856,6 +861,7 @@ impl ScriptThread {
let mut sequential = vec![];
// Receive at least one message so we don't spinloop.
debug!("Waiting for event.");
let mut event = {
let sel = Select::new();
let mut script_port = sel.handle(&self.port);
@ -887,6 +893,7 @@ impl ScriptThread {
panic!("unexpected select result")
}
};
debug!("Got event.");
// Squash any pending resize, reflow, animation tick, and mouse-move events in the queue.
let mut mouse_move_event_index = None;
@ -983,6 +990,7 @@ impl ScriptThread {
}
// Process the gathered events.
debug!("Processing events.");
for msg in sequential {
debug!("Processing event {:?}.", msg);
let category = self.categorize_msg(&msg);
@ -1025,6 +1033,7 @@ impl ScriptThread {
// Issue batched reflows on any pages that require it (e.g. if images loaded)
// TODO(gw): In the future we could probably batch other types of reflows
// into this loop too, but for now it's only images.
debug!("Issuing batched reflows.");
for (_, document) in self.documents.borrow().iter() {
let window = document.window();
let pending_reflows = window.get_pending_reflow_count();
@ -1189,11 +1198,16 @@ impl ScriptThread {
// The category of the runnable is ignored by the pattern, however
// it is still respected by profiling (see categorize_msg).
if !runnable.is_cancelled() {
debug!("Running runnable.");
runnable.main_thread_handler(self)
} else {
debug!("Not running cancelled runnable.");
}
}
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) =>
self.collect_reports(reports_chan),
MainThreadScriptMsg::WorkletLoaded(pipeline_id) =>
self.handle_worklet_loaded(pipeline_id),
MainThreadScriptMsg::DOMManipulation(task) =>
task.handle_task(self),
MainThreadScriptMsg::UserInteraction(task) =>
@ -1759,6 +1773,14 @@ impl ScriptThread {
}
}
/// Handles a worklet being loaded. Does nothing if the page no longer exists.
fn handle_worklet_loaded(&self, pipeline_id: PipelineId) {
let document = self.documents.borrow().find_document(pipeline_id);
if let Some(document) = document {
self.rebuild_and_force_reflow(&document, ReflowReason::WorkletLoaded);
}
}
/// Notify a window of a storage event
fn handle_storage_event(&self, pipeline_id: PipelineId, storage_type: StorageType, url: ServoUrl,
key: Option<String>, old_value: Option<String>, new_value: Option<String>) {

View file

@ -41,6 +41,7 @@ pub mod webdriver_msg;
use app_units::Au;
use bluetooth_traits::BluetoothRequest;
use canvas_traits::CanvasData;
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
use euclid::{Size2D, Length, Point2D, Vector2D, Rect, ScaleFactor, TypedSize2D};
use gfx_traits::Epoch;
@ -826,12 +827,12 @@ impl From<RecvTimeoutError> for PaintWorkletError {
}
}
/// Execute paint code in the worklet thread pool.<
/// Execute paint code in the worklet thread pool.
pub trait PaintWorkletExecutor: Sync + Send {
/// https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image
fn draw_a_paint_image(&self,
name: Atom,
concrete_object_size: Size2D<Au>)
-> Result<Image, PaintWorkletError>;
concrete_object_size: Size2D<Au>,
sender: IpcSender<CanvasData>);
}

View file

@ -1,3 +0,0 @@
[test_paint_worklet.html]
type: reftest
expected: FAIL