Auto merge of #21850 - servo:webgl, r=jdm

Don't use an intermediate PNG buffer in HTMLCanvasElement::ToDataURL

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21850)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-10-03 06:00:50 -04:00 committed by GitHub
commit 74e7736720
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 209 additions and 174 deletions

View file

@ -35,7 +35,7 @@ pub struct CanvasData<'a> {
impl<'a> CanvasData<'a> { impl<'a> CanvasData<'a> {
pub fn new( pub fn new(
size: Size2D<i32>, size: Size2D<u32>,
webrender_api_sender: webrender_api::RenderApiSender, webrender_api_sender: webrender_api::RenderApiSender,
antialias: AntialiasMode, antialias: AntialiasMode,
canvas_id: CanvasId canvas_id: CanvasId
@ -369,11 +369,12 @@ impl<'a> CanvasData<'a> {
self.state.draw_options.set_composition_op(op.to_azure_style()); self.state.draw_options.set_composition_op(op.to_azure_style());
} }
pub fn create(size: Size2D<i32>) -> DrawTarget { pub fn create(size: Size2D<u32>) -> DrawTarget {
DrawTarget::new(BackendType::Skia, size, SurfaceFormat::B8G8R8A8) // FIXME(nox): Why is the size made of i32 values?
DrawTarget::new(BackendType::Skia, size.to_i32(), SurfaceFormat::B8G8R8A8)
} }
pub fn recreate(&mut self, size: Size2D<i32>) { pub fn recreate(&mut self, size: Size2D<u32>) {
self.drawtarget = CanvasData::create(size); self.drawtarget = CanvasData::create(size);
self.state = CanvasPaintState::new(self.state.draw_options.antialias); self.state = CanvasPaintState::new(self.state.draw_options.antialias);
self.saved_states.clear(); self.saved_states.clear();
@ -901,9 +902,9 @@ pub trait ToAzurePattern {
impl ToAzurePattern for FillOrStrokeStyle { impl ToAzurePattern for FillOrStrokeStyle {
fn to_azure_pattern(&self, drawtarget: &DrawTarget) -> Option<Pattern> { fn to_azure_pattern(&self, drawtarget: &DrawTarget) -> Option<Pattern> {
match *self { Some(match *self {
FillOrStrokeStyle::Color(ref color) => { FillOrStrokeStyle::Color(ref color) => {
Some(Pattern::Color(ColorPattern::new(color.to_azure_style()))) Pattern::Color(ColorPattern::new(color.to_azure_style()))
}, },
FillOrStrokeStyle::LinearGradient(ref linear_gradient_style) => { FillOrStrokeStyle::LinearGradient(ref linear_gradient_style) => {
let gradient_stops: Vec<GradientStop> = linear_gradient_style.stops.iter().map(|s| { let gradient_stops: Vec<GradientStop> = linear_gradient_style.stops.iter().map(|s| {
@ -913,11 +914,12 @@ impl ToAzurePattern for FillOrStrokeStyle {
} }
}).collect(); }).collect();
Some(Pattern::LinearGradient(LinearGradientPattern::new( Pattern::LinearGradient(LinearGradientPattern::new(
&Point2D::new(linear_gradient_style.x0 as AzFloat, linear_gradient_style.y0 as AzFloat), &Point2D::new(linear_gradient_style.x0 as AzFloat, linear_gradient_style.y0 as AzFloat),
&Point2D::new(linear_gradient_style.x1 as AzFloat, linear_gradient_style.y1 as AzFloat), &Point2D::new(linear_gradient_style.x1 as AzFloat, linear_gradient_style.y1 as AzFloat),
drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp), drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp),
&Transform2D::identity()))) &Transform2D::identity(),
))
}, },
FillOrStrokeStyle::RadialGradient(ref radial_gradient_style) => { FillOrStrokeStyle::RadialGradient(ref radial_gradient_style) => {
let gradient_stops: Vec<GradientStop> = radial_gradient_style.stops.iter().map(|s| { let gradient_stops: Vec<GradientStop> = radial_gradient_style.stops.iter().map(|s| {
@ -927,28 +929,31 @@ impl ToAzurePattern for FillOrStrokeStyle {
} }
}).collect(); }).collect();
Some(Pattern::RadialGradient(RadialGradientPattern::new( Pattern::RadialGradient(RadialGradientPattern::new(
&Point2D::new(radial_gradient_style.x0 as AzFloat, radial_gradient_style.y0 as AzFloat), &Point2D::new(radial_gradient_style.x0 as AzFloat, radial_gradient_style.y0 as AzFloat),
&Point2D::new(radial_gradient_style.x1 as AzFloat, radial_gradient_style.y1 as AzFloat), &Point2D::new(radial_gradient_style.x1 as AzFloat, radial_gradient_style.y1 as AzFloat),
radial_gradient_style.r0 as AzFloat, radial_gradient_style.r1 as AzFloat, radial_gradient_style.r0 as AzFloat, radial_gradient_style.r1 as AzFloat,
drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp), drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp),
&Transform2D::identity()))) &Transform2D::identity(),
))
}, },
FillOrStrokeStyle::Surface(ref surface_style) => { FillOrStrokeStyle::Surface(ref surface_style) => {
drawtarget.create_source_surface_from_data(&surface_style.surface_data, let source_surface = drawtarget.create_source_surface_from_data(
surface_style.surface_size, &surface_style.surface_data,
surface_style.surface_size.width * 4, // FIXME(nox): Why are those i32 values?
SurfaceFormat::B8G8R8A8) surface_style.surface_size.to_i32(),
.map(|source_surface| { surface_style.surface_size.width as i32 * 4,
SurfaceFormat::B8G8R8A8,
)?;
Pattern::Surface(SurfacePattern::new( Pattern::Surface(SurfacePattern::new(
source_surface.azure_source_surface, source_surface.azure_source_surface,
surface_style.repeat_x, surface_style.repeat_x,
surface_style.repeat_y, surface_style.repeat_y,
&Transform2D::identity())) &Transform2D::identity(),
))
}
}) })
} }
}
}
} }
impl ToAzureStyle for RGBA { impl ToAzureStyle for RGBA {

View file

@ -80,7 +80,7 @@ impl<'a> CanvasPaintThread <'a> {
pub fn create_canvas( pub fn create_canvas(
&mut self, &mut self,
size: Size2D<i32>, size: Size2D<u32>,
webrender_api_sender: webrender_api::RenderApiSender, webrender_api_sender: webrender_api::RenderApiSender,
antialias: bool antialias: bool
) -> CanvasId { ) -> CanvasId {

View file

@ -47,63 +47,71 @@ impl GLContextFactory {
pub fn new_shared_context( pub fn new_shared_context(
&self, &self,
webgl_version: WebGLVersion, webgl_version: WebGLVersion,
size: Size2D<i32>, size: Size2D<u32>,
attributes: GLContextAttributes attributes: GLContextAttributes
) -> Result<GLContextWrapper, &'static str> { ) -> Result<GLContextWrapper, &'static str> {
match *self { Ok(match *self {
GLContextFactory::Native(ref handle, ref dispatcher) => { GLContextFactory::Native(ref handle, ref dispatcher) => {
let dispatcher = dispatcher.as_ref().map(|d| Box::new(d.clone()) as Box<_>); let dispatcher = dispatcher.as_ref().map(|d| Box::new(d.clone()) as Box<_>);
let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size, GLContextWrapper::Native(GLContext::new_shared_with_dispatcher(
// FIXME(nox): Why are those i32 values?
size.to_i32(),
attributes, attributes,
ColorAttachmentType::Texture, ColorAttachmentType::Texture,
gl::GlType::default(), gl::GlType::default(),
Self::gl_version(webgl_version), Self::gl_version(webgl_version),
Some(handle), Some(handle),
dispatcher); dispatcher,
ctx.map(GLContextWrapper::Native) )?)
} }
GLContextFactory::OSMesa(ref handle) => { GLContextFactory::OSMesa(ref handle) => {
let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(), GLContextWrapper::OSMesa(GLContext::new_shared_with_dispatcher(
// FIXME(nox): Why are those i32 values?
size.to_i32(),
attributes, attributes,
ColorAttachmentType::Texture, ColorAttachmentType::Texture,
gl::GlType::default(), gl::GlType::default(),
Self::gl_version(webgl_version), Self::gl_version(webgl_version),
Some(handle), Some(handle),
None); None,
ctx.map(GLContextWrapper::OSMesa) )?)
}
} }
})
} }
/// Creates a new non-shared GLContext /// Creates a new non-shared GLContext
pub fn new_context( pub fn new_context(
&self, &self,
webgl_version: WebGLVersion, webgl_version: WebGLVersion,
size: Size2D<i32>, size: Size2D<u32>,
attributes: GLContextAttributes attributes: GLContextAttributes
) -> Result<GLContextWrapper, &'static str> { ) -> Result<GLContextWrapper, &'static str> {
match *self { Ok(match *self {
GLContextFactory::Native(..) => { GLContextFactory::Native(..) => {
let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size, GLContextWrapper::Native(GLContext::new_shared_with_dispatcher(
// FIXME(nox): Why are those i32 values?
size.to_i32(),
attributes, attributes,
ColorAttachmentType::Texture, ColorAttachmentType::Texture,
gl::GlType::default(), gl::GlType::default(),
Self::gl_version(webgl_version), Self::gl_version(webgl_version),
None, None,
None); None,
ctx.map(GLContextWrapper::Native) )?)
} }
GLContextFactory::OSMesa(_) => { GLContextFactory::OSMesa(_) => {
let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(), GLContextWrapper::OSMesa(GLContext::new_shared_with_dispatcher(
// FIXME(nox): Why are those i32 values?
size.to_i32(),
attributes, attributes,
ColorAttachmentType::Texture, ColorAttachmentType::Texture,
gl::GlType::default(), gl::GlType::default(),
Self::gl_version(webgl_version), Self::gl_version(webgl_version),
None, None,
None); None,
ctx.map(GLContextWrapper::OSMesa) )?)
}
} }
})
} }
fn gl_version(webgl_version: WebGLVersion) -> GLVersion { fn gl_version(webgl_version: WebGLVersion) -> GLVersion {
@ -196,13 +204,15 @@ impl GLContextWrapper {
} }
} }
pub fn resize(&mut self, size: Size2D<i32>) -> Result<(), &'static str> { pub fn resize(&mut self, size: Size2D<u32>) -> Result<(), &'static str> {
match *self { match *self {
GLContextWrapper::Native(ref mut ctx) => { GLContextWrapper::Native(ref mut ctx) => {
ctx.resize(size) // FIXME(nox): Why are those i32 values?
ctx.resize(size.to_i32())
} }
GLContextWrapper::OSMesa(ref mut ctx) => { GLContextWrapper::OSMesa(ref mut ctx) => {
ctx.resize(size) // FIXME(nox): Why are those i32 values?
ctx.resize(size.to_i32())
} }
} }
} }

View file

@ -216,28 +216,31 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
} }
/// Creates a new WebGLContext /// Creates a new WebGLContext
fn create_webgl_context(&mut self, fn create_webgl_context(
&mut self,
version: WebGLVersion, version: WebGLVersion,
size: Size2D<i32>, size: Size2D<u32>,
attributes: GLContextAttributes) attributes: GLContextAttributes,
-> Result<(WebGLContextId, GLLimits, WebGLContextShareMode), String> { ) -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode), String> {
// First try to create a shared context for the best performance.
// Fallback to readback mode if the shared context creation fails.
let result = self.gl_factory.new_shared_context(version, size, attributes)
.map(|r| (r, WebGLContextShareMode::SharedTexture))
.or_else(|err| {
warn!("Couldn't create shared GL context ({}), using slow \
readback context instead.", err);
let ctx = self.gl_factory.new_context(version, size, attributes);
ctx.map(|r| (r, WebGLContextShareMode::Readback))
});
// Creating a new GLContext may make the current bound context_id dirty. // Creating a new GLContext may make the current bound context_id dirty.
// Clear it to ensure that make_current() is called in subsequent commands. // Clear it to ensure that make_current() is called in subsequent commands.
self.bound_context_id = None; self.bound_context_id = None;
match result { // First try to create a shared context for the best performance.
Ok((ctx, share_mode)) => { // Fallback to readback mode if the shared context creation fails.
let (ctx, share_mode) = self.gl_factory
.new_shared_context(version, size, attributes)
.map(|r| (r, WebGLContextShareMode::SharedTexture))
.or_else(|err| {
warn!(
"Couldn't create shared GL context ({}), using slow readback context instead.",
err
);
let ctx = self.gl_factory.new_context(version, size, attributes)?;
Ok((ctx, WebGLContextShareMode::Readback))
})
.map_err(|msg: &str| msg.to_owned())?;
let id = WebGLContextId(self.next_webgl_id); let id = WebGLContextId(self.next_webgl_id);
let (size, texture_id, limits) = ctx.get_info(); let (size, texture_id, limits) = ctx.get_info();
self.next_webgl_id += 1; self.next_webgl_id += 1;
@ -255,18 +258,15 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
}); });
Ok((id, limits, share_mode)) Ok((id, limits, share_mode))
},
Err(msg) => {
Err(msg.to_owned())
}
}
} }
/// Resizes a WebGLContext /// Resizes a WebGLContext
fn resize_webgl_context(&mut self, fn resize_webgl_context(
&mut self,
context_id: WebGLContextId, context_id: WebGLContextId,
size: Size2D<i32>, size: Size2D<u32>,
sender: WebGLSender<Result<(), String>>) { sender: WebGLSender<Result<(), String>>,
) {
let data = Self::make_current_if_needed_mut( let data = Self::make_current_if_needed_mut(
context_id, context_id,
&mut self.contexts, &mut self.contexts,
@ -798,8 +798,12 @@ impl WebGLImpl {
ctx.gl().renderbuffer_storage(target, format, width, height), ctx.gl().renderbuffer_storage(target, format, width, height),
WebGLCommand::SampleCoverage(value, invert) => WebGLCommand::SampleCoverage(value, invert) =>
ctx.gl().sample_coverage(value, invert), ctx.gl().sample_coverage(value, invert),
WebGLCommand::Scissor(x, y, width, height) => WebGLCommand::Scissor(x, y, width, height) => {
ctx.gl().scissor(x, y, width, height), // FIXME(nox): Kinda unfortunate that some u32 values could
// end up as negative numbers here, but I don't even think
// that can happen in the real world.
ctx.gl().scissor(x, y, width as i32, height as i32);
},
WebGLCommand::StencilFunc(func, ref_, mask) => WebGLCommand::StencilFunc(func, ref_, mask) =>
ctx.gl().stencil_func(func, ref_, mask), ctx.gl().stencil_func(func, ref_, mask),
WebGLCommand::StencilFuncSeparate(face, func, ref_, mask) => WebGLCommand::StencilFuncSeparate(face, func, ref_, mask) =>

View file

@ -22,10 +22,10 @@ pub struct CanvasId(pub u64);
#[derive(Clone, Deserialize, Serialize)] #[derive(Clone, Deserialize, Serialize)]
pub enum CanvasMsg { pub enum CanvasMsg {
Canvas2d(Canvas2dMsg, CanvasId), Canvas2d(Canvas2dMsg, CanvasId),
Create(IpcSender<CanvasId>, Size2D<i32>, webrender_api::RenderApiSender, bool), Create(IpcSender<CanvasId>, Size2D<u32>, webrender_api::RenderApiSender, bool),
FromLayout(FromLayoutMsg, CanvasId), FromLayout(FromLayoutMsg, CanvasId),
FromScript(FromScriptMsg, CanvasId), FromScript(FromScriptMsg, CanvasId),
Recreate(Size2D<i32>, CanvasId), Recreate(Size2D<u32>, CanvasId),
Close(CanvasId), Close(CanvasId),
} }
@ -143,7 +143,7 @@ impl RadialGradientStyle {
#[derive(Clone, Deserialize, Serialize)] #[derive(Clone, Deserialize, Serialize)]
pub struct SurfaceStyle { pub struct SurfaceStyle {
pub surface_data: ByteBuf, pub surface_data: ByteBuf,
pub surface_size: Size2D<i32>, pub surface_size: Size2D<u32>,
pub repeat_x: bool, pub repeat_x: bool,
pub repeat_y: bool, pub repeat_y: bool,
} }
@ -151,7 +151,7 @@ pub struct SurfaceStyle {
impl SurfaceStyle { impl SurfaceStyle {
pub fn new( pub fn new(
surface_data: Vec<u8>, surface_data: Vec<u8>,
surface_size: Size2D<i32>, surface_size: Size2D<u32>,
repeat_x: bool, repeat_x: bool,
repeat_y: bool, repeat_y: bool,
) -> Self { ) -> Self {

View file

@ -36,10 +36,14 @@ pub struct WebGLCommandBacktrace {
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub enum WebGLMsg { pub enum WebGLMsg {
/// Creates a new WebGLContext. /// Creates a new WebGLContext.
CreateContext(WebGLVersion, Size2D<i32>, GLContextAttributes, CreateContext(
WebGLSender<Result<(WebGLCreateContextResult), String>>), WebGLVersion,
Size2D<u32>,
GLContextAttributes,
WebGLSender<Result<(WebGLCreateContextResult), String>>,
),
/// Resizes a WebGLContext. /// Resizes a WebGLContext.
ResizeContext(WebGLContextId, Size2D<i32>, WebGLSender<Result<(), String>>), ResizeContext(WebGLContextId, Size2D<u32>, WebGLSender<Result<(), String>>),
/// Drops a WebGLContext. /// Drops a WebGLContext.
RemoveContext(WebGLContextId), RemoveContext(WebGLContextId),
/// Runs a WebGLCommand in a specific WebGLContext. /// Runs a WebGLCommand in a specific WebGLContext.
@ -141,10 +145,11 @@ impl WebGLMsgSender {
/// Send a resize message /// Send a resize message
#[inline] #[inline]
pub fn send_resize(&self, pub fn send_resize(
size: Size2D<i32>, &self,
sender: WebGLSender<Result<(), String>>) size: Size2D<u32>,
-> WebGLSendResult { sender: WebGLSender<Result<(), String>>,
) -> WebGLSendResult {
self.sender.send(WebGLMsg::ResizeContext(self.ctx_id, size, sender)) self.sender.send(WebGLMsg::ResizeContext(self.ctx_id, size, sender))
} }
@ -224,7 +229,7 @@ pub enum WebGLCommand {
RenderbufferStorage(u32, u32, i32, i32), RenderbufferStorage(u32, u32, i32, i32),
ReadPixels(i32, i32, i32, i32, u32, u32, IpcBytesSender), ReadPixels(i32, i32, i32, i32, u32, u32, IpcBytesSender),
SampleCoverage(f32, bool), SampleCoverage(f32, bool),
Scissor(i32, i32, i32, i32), Scissor(i32, i32, u32, u32),
StencilFunc(u32, i32, u32), StencilFunc(u32, i32, u32),
StencilFuncSeparate(u32, u32, i32, u32), StencilFuncSeparate(u32, u32, i32, u32),
StencilMask(u32), StencilMask(u32),

View file

@ -1195,7 +1195,7 @@ where
} }
}, },
FromScriptMsg::CreateCanvasPaintThread(size, sender) => { FromScriptMsg::CreateCanvasPaintThread(size, sender) => {
self.handle_create_canvas_paint_thread_msg(&size, sender) self.handle_create_canvas_paint_thread_msg(size, sender)
}, },
FromScriptMsg::SetDocumentState(state) => { FromScriptMsg::SetDocumentState(state) => {
self.document_states.insert(source_pipeline_id, state); self.document_states.insert(source_pipeline_id, state);
@ -2850,7 +2850,7 @@ where
fn handle_create_canvas_paint_thread_msg( fn handle_create_canvas_paint_thread_msg(
&mut self, &mut self,
size: &Size2D<i32>, size: Size2D<u32>,
response_sender: IpcSender<(IpcSender<CanvasMsg>, CanvasId)>, response_sender: IpcSender<(IpcSender<CanvasMsg>, CanvasId)>,
) { ) {
let webrender_api = self.webrender_api_sender.clone(); let webrender_api = self.webrender_api_sender.clone();
@ -2860,7 +2860,7 @@ where
if let Err(e) = sender.send(CanvasMsg::Create( if let Err(e) = sender.send(CanvasMsg::Create(
canvas_id_sender, canvas_id_sender,
*size, size,
webrender_api, webrender_api,
opts::get().enable_canvas_antialiasing, opts::get().enable_canvas_antialiasing,
)) { )) {

View file

@ -261,7 +261,13 @@ unsafe impl<T: JSTraceable> JSTraceable for VecDeque<T> {
} }
} }
unsafe impl<T: JSTraceable> JSTraceable for (T, T, T, T) { unsafe impl<A, B, C, D> JSTraceable for (A, B, C, D)
where
A: JSTraceable,
B: JSTraceable,
C: JSTraceable,
D: JSTraceable,
{
unsafe fn trace(&self, trc: *mut JSTracer) { unsafe fn trace(&self, trc: *mut JSTracer) {
self.0.trace(trc); self.0.trace(trc);
self.1.trace(trc); self.1.trace(trc);
@ -616,6 +622,13 @@ unsafe impl<U> JSTraceable for TypedSize2D<f32, U> {
} }
} }
unsafe impl<U> JSTraceable for TypedSize2D<u32, U> {
#[inline]
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing
}
}
unsafe impl JSTraceable for StyleLocked<FontFaceRule> { unsafe impl JSTraceable for StyleLocked<FontFaceRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.

View file

@ -16,7 +16,7 @@ use euclid::Size2D;
pub struct CanvasPattern { pub struct CanvasPattern {
reflector_: Reflector, reflector_: Reflector,
surface_data: Vec<u8>, surface_data: Vec<u8>,
surface_size: Size2D<i32>, surface_size: Size2D<u32>,
repeat_x: bool, repeat_x: bool,
repeat_y: bool, repeat_y: bool,
origin_clean: bool, origin_clean: bool,
@ -25,7 +25,7 @@ pub struct CanvasPattern {
impl CanvasPattern { impl CanvasPattern {
fn new_inherited( fn new_inherited(
surface_data: Vec<u8>, surface_data: Vec<u8>,
surface_size: Size2D<i32>, surface_size: Size2D<u32>,
repeat: RepetitionStyle, repeat: RepetitionStyle,
origin_clean: bool, origin_clean: bool,
) -> CanvasPattern { ) -> CanvasPattern {
@ -39,7 +39,7 @@ impl CanvasPattern {
CanvasPattern { CanvasPattern {
reflector_: Reflector::new(), reflector_: Reflector::new(),
surface_data: surface_data, surface_data: surface_data,
surface_size: surface_size, surface_size,
repeat_x: x, repeat_x: x,
repeat_y: y, repeat_y: y,
origin_clean: origin_clean, origin_clean: origin_clean,
@ -48,7 +48,7 @@ impl CanvasPattern {
pub fn new( pub fn new(
global: &GlobalScope, global: &GlobalScope,
surface_data: Vec<u8>, surface_data: Vec<u8>,
surface_size: Size2D<i32>, surface_size: Size2D<u32>,
repeat: RepetitionStyle, repeat: RepetitionStyle,
origin_clean: bool, origin_clean: bool,
) -> DomRoot<CanvasPattern> { ) -> DomRoot<CanvasPattern> {

View file

@ -128,7 +128,7 @@ impl CanvasRenderingContext2D {
canvas: Option<&HTMLCanvasElement>, canvas: Option<&HTMLCanvasElement>,
image_cache: Arc<ImageCache>, image_cache: Arc<ImageCache>,
base_url: ServoUrl, base_url: ServoUrl,
size: Size2D<i32>, size: Size2D<u32>,
) -> CanvasRenderingContext2D { ) -> CanvasRenderingContext2D {
debug!("Creating new canvas rendering context."); debug!("Creating new canvas rendering context.");
let (sender, receiver) = let (sender, receiver) =
@ -157,7 +157,7 @@ impl CanvasRenderingContext2D {
pub fn new( pub fn new(
global: &GlobalScope, global: &GlobalScope,
canvas: &HTMLCanvasElement, canvas: &HTMLCanvasElement,
size: Size2D<i32>, size: Size2D<u32>,
) -> DomRoot<CanvasRenderingContext2D> { ) -> DomRoot<CanvasRenderingContext2D> {
let window = window_from_node(canvas); let window = window_from_node(canvas);
let image_cache = window.image_cache(); let image_cache = window.image_cache();
@ -173,7 +173,7 @@ impl CanvasRenderingContext2D {
} }
// https://html.spec.whatwg.org/multipage/#concept-canvas-set-bitmap-dimensions // https://html.spec.whatwg.org/multipage/#concept-canvas-set-bitmap-dimensions
pub fn set_bitmap_dimensions(&self, size: Size2D<i32>) { pub fn set_bitmap_dimensions(&self, size: Size2D<u32>) {
self.reset_to_initial_state(); self.reset_to_initial_state();
self.ipc_renderer self.ipc_renderer
.send(CanvasMsg::Recreate(size, self.get_canvas_id())) .send(CanvasMsg::Recreate(size, self.get_canvas_id()))
@ -456,7 +456,7 @@ impl CanvasRenderingContext2D {
Ok(()) Ok(())
} }
fn fetch_image_data(&self, url: ServoUrl) -> Option<(Vec<u8>, Size2D<i32>)> { fn fetch_image_data(&self, url: ServoUrl) -> Option<(Vec<u8>, Size2D<u32>)> {
let img = match self.request_image_from_cache(url) { let img = match self.request_image_from_cache(url) {
ImageResponse::Loaded(img, _) => img, ImageResponse::Loaded(img, _) => img,
ImageResponse::PlaceholderLoaded(_, _) | ImageResponse::PlaceholderLoaded(_, _) |
@ -466,7 +466,7 @@ impl CanvasRenderingContext2D {
}, },
}; };
let image_size = Size2D::new(img.width as i32, img.height as i32); let image_size = Size2D::new(img.width, img.height);
let image_data = match img.format { let image_data = match img.format {
PixelFormat::BGRA8 => img.bytes.to_vec(), PixelFormat::BGRA8 => img.bytes.to_vec(),
PixelFormat::K8 => panic!("K8 color type not supported"), PixelFormat::K8 => panic!("K8 color type not supported"),

View file

@ -98,8 +98,8 @@ impl HTMLCanvasElement {
} }
} }
pub fn get_size(&self) -> Size2D<i32> { pub fn get_size(&self) -> Size2D<u32> {
Size2D::new(self.Width() as i32, self.Height() as i32) Size2D::new(self.Width(), self.Height())
} }
pub fn origin_is_clean(&self) -> bool { pub fn origin_is_clean(&self) -> bool {
@ -277,7 +277,7 @@ impl HTMLCanvasElement {
self.Height() != 0 && self.Width() != 0 self.Height() != 0 && self.Width() != 0
} }
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> { pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<u32>)> {
let size = self.get_size(); let size = self.get_size();
if size.width == 0 || size.height == 0 { if size.width == 0 || size.height == 0 {
@ -383,12 +383,11 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
None => return Ok(USVString("data:,".into())), None => return Ok(USVString("data:,".into())),
} }
}, },
Some(CanvasContext::WebGL2(ref context)) => match context Some(CanvasContext::WebGL2(ref context)) => {
.base_context() match context.base_context().get_image_data(self.Width(), self.Height()) {
.get_image_data(self.Width(), self.Height())
{
Some(data) => data, Some(data) => data,
None => return Ok(USVString("data:,".into())), None => return Ok(USVString("data:,".into())),
}
}, },
None => { None => {
// Each pixel is fully-transparent black. // Each pixel is fully-transparent black.
@ -396,19 +395,16 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
}, },
}; };
// Only handle image/png for now. // FIXME: Only handle image/png for now.
let mime_type = "image/png"; let mut png = Vec::new();
PNGEncoder::new(&mut png)
let mut encoded = Vec::new();
{
let encoder: PNGEncoder<&mut Vec<u8>> = PNGEncoder::new(&mut encoded);
encoder
.encode(&raw_data, self.Width(), self.Height(), ColorType::RGBA(8)) .encode(&raw_data, self.Width(), self.Height(), ColorType::RGBA(8))
.unwrap(); .unwrap();
} let mut url = "data:image/png;base64,".to_owned();
// FIXME(nox): Should this use base64::URL_SAFE?
let encoded = base64::encode(&encoded); // FIXME(nox): https://github.com/alicemaz/rust-base64/pull/56
Ok(USVString(format!("data:{};base64,{}", mime_type, encoded))) base64::encode_config_buf(&png, base64::STANDARD, &mut url);
Ok(USVString(url))
} }
} }

View file

@ -149,8 +149,8 @@ impl ImageData {
} }
} }
pub fn get_size(&self) -> Size2D<i32> { pub fn get_size(&self) -> Size2D<u32> {
Size2D::new(self.Width() as i32, self.Height() as i32) Size2D::new(self.Width(), self.Height())
} }
} }

View file

@ -85,8 +85,7 @@ impl PaintRenderingContext2D {
) { ) {
let size = size * device_pixel_ratio; let size = size * device_pixel_ratio;
self.device_pixel_ratio.set(device_pixel_ratio); self.device_pixel_ratio.set(device_pixel_ratio);
self.context self.context.set_bitmap_dimensions(size.to_untyped().to_u32());
.set_bitmap_dimensions(size.to_untyped().to_i32());
self.scale_by_device_pixel_ratio(); self.scale_by_device_pixel_ratio();
} }

View file

@ -49,7 +49,7 @@ impl WebGL2RenderingContext {
fn new_inherited( fn new_inherited(
window: &Window, window: &Window,
canvas: &HTMLCanvasElement, canvas: &HTMLCanvasElement,
size: Size2D<i32>, size: Size2D<u32>,
attrs: GLContextAttributes, attrs: GLContextAttributes,
) -> Option<WebGL2RenderingContext> { ) -> Option<WebGL2RenderingContext> {
let base = WebGLRenderingContext::new(window, canvas, WebGLVersion::WebGL2, size, attrs)?; let base = WebGLRenderingContext::new(window, canvas, WebGLVersion::WebGL2, size, attrs)?;
@ -63,7 +63,7 @@ impl WebGL2RenderingContext {
pub fn new( pub fn new(
window: &Window, window: &Window,
canvas: &HTMLCanvasElement, canvas: &HTMLCanvasElement,
size: Size2D<i32>, size: Size2D<u32>,
attrs: GLContextAttributes, attrs: GLContextAttributes,
) -> Option<DomRoot<WebGL2RenderingContext>> { ) -> Option<DomRoot<WebGL2RenderingContext>> {
WebGL2RenderingContext::new_inherited(window, canvas, size, attrs).map(|ctx| { WebGL2RenderingContext::new_inherited(window, canvas, size, attrs).map(|ctx| {
@ -73,7 +73,7 @@ impl WebGL2RenderingContext {
} }
impl WebGL2RenderingContext { impl WebGL2RenderingContext {
pub fn recreate(&self, size: Size2D<i32>) { pub fn recreate(&self, size: Size2D<u32>) {
self.base.recreate(size) self.base.recreate(size)
} }

View file

@ -157,7 +157,7 @@ pub struct WebGLRenderingContext {
#[ignore_malloc_size_of = "Because it's small"] #[ignore_malloc_size_of = "Because it's small"]
current_vertex_attrib_0: Cell<(f32, f32, f32, f32)>, current_vertex_attrib_0: Cell<(f32, f32, f32, f32)>,
#[ignore_malloc_size_of = "Because it's small"] #[ignore_malloc_size_of = "Because it's small"]
current_scissor: Cell<(i32, i32, i32, i32)>, current_scissor: Cell<(i32, i32, u32, u32)>,
#[ignore_malloc_size_of = "Because it's small"] #[ignore_malloc_size_of = "Because it's small"]
current_clear_color: Cell<(f32, f32, f32, f32)>, current_clear_color: Cell<(f32, f32, f32, f32)>,
extension_manager: WebGLExtensions, extension_manager: WebGLExtensions,
@ -172,7 +172,7 @@ impl WebGLRenderingContext {
window: &Window, window: &Window,
canvas: &HTMLCanvasElement, canvas: &HTMLCanvasElement,
webgl_version: WebGLVersion, webgl_version: WebGLVersion,
size: Size2D<i32>, size: Size2D<u32>,
attrs: GLContextAttributes, attrs: GLContextAttributes,
) -> Result<WebGLRenderingContext, String> { ) -> Result<WebGLRenderingContext, String> {
if let Some(true) = PREFS if let Some(true) = PREFS
@ -229,7 +229,7 @@ impl WebGLRenderingContext {
window: &Window, window: &Window,
canvas: &HTMLCanvasElement, canvas: &HTMLCanvasElement,
webgl_version: WebGLVersion, webgl_version: WebGLVersion,
size: Size2D<i32>, size: Size2D<u32>,
attrs: GLContextAttributes, attrs: GLContextAttributes,
) -> Option<DomRoot<WebGLRenderingContext>> { ) -> Option<DomRoot<WebGLRenderingContext>> {
match WebGLRenderingContext::new_inherited(window, canvas, webgl_version, size, attrs) { match WebGLRenderingContext::new_inherited(window, canvas, webgl_version, size, attrs) {
@ -266,7 +266,7 @@ impl WebGLRenderingContext {
}) })
} }
pub fn recreate(&self, size: Size2D<i32>) { pub fn recreate(&self, size: Size2D<u32>) {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.webgl_sender.send_resize(size, sender).unwrap(); self.webgl_sender.send_resize(size, sender).unwrap();
@ -517,7 +517,7 @@ impl WebGLRenderingContext {
fn get_image_pixels( fn get_image_pixels(
&self, &self,
source: TexImageSource, source: TexImageSource,
) -> Fallible<Option<(Vec<u8>, Size2D<i32>, bool)>> { ) -> Fallible<Option<(Vec<u8>, Size2D<u32>, bool)>> {
Ok(Some(match source { Ok(Some(match source {
TexImageSource::ImageData(image_data) => { TexImageSource::ImageData(image_data) => {
(image_data.get_data_array(), image_data.get_size(), false) (image_data.get_data_array(), image_data.get_size(), false)
@ -542,7 +542,7 @@ impl WebGLRenderingContext {
ImageResponse::MetadataLoaded(_) => return Ok(None), ImageResponse::MetadataLoaded(_) => return Ok(None),
}; };
let size = Size2D::new(img.width as i32, img.height as i32); let size = Size2D::new(img.width, img.height);
// For now Servo's images are all stored as BGRA8 internally. // For now Servo's images are all stored as BGRA8 internally.
let mut data = match img.format { let mut data = match img.format {
@ -2940,6 +2940,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
return self.webgl_error(InvalidValue); return self.webgl_error(InvalidValue);
} }
let width = width as u32;
let height = height as u32;
self.current_scissor.set((x, y, width, height)); self.current_scissor.set((x, y, width, height));
self.send_command(WebGLCommand::Scissor(x, y, width, height)); self.send_command(WebGLCommand::Scissor(x, y, width, height));
} }
@ -3791,8 +3794,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
target, target,
level, level,
internal_format, internal_format,
size.width, size.width as i32,
size.height, size.height as i32,
0, 0,
format, format,
data_type, data_type,
@ -4003,8 +4006,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
target, target,
level, level,
format, format,
size.width, size.width as i32,
size.height, size.height as i32,
0, 0,
format, format,
data_type, data_type,

View file

@ -103,7 +103,7 @@ pub enum ScriptMsg {
ChangeRunningAnimationsState(AnimationState), ChangeRunningAnimationsState(AnimationState),
/// Requests that a new 2D canvas thread be created. (This is done in the constellation because /// Requests that a new 2D canvas thread be created. (This is done in the constellation because
/// 2D canvases may use the GPU and we don't want to give untrusted content access to the GPU.) /// 2D canvases may use the GPU and we don't want to give untrusted content access to the GPU.)
CreateCanvasPaintThread(Size2D<i32>, IpcSender<(IpcSender<CanvasMsg>, CanvasId)>), CreateCanvasPaintThread(Size2D<u32>, IpcSender<(IpcSender<CanvasMsg>, CanvasId)>),
/// Notifies the constellation that this frame has received focus. /// Notifies the constellation that this frame has received focus.
Focus, Focus,
/// Requests that the constellation retrieve the current contents of the clipboard /// Requests that the constellation retrieve the current contents of the clipboard