mirror of
https://github.com/servo/servo.git
synced 2025-08-02 12:10:29 +01:00
webgl: texImage2D with a canvas argument
This commit is contained in:
parent
a58e731abd
commit
e2b7a01055
5 changed files with 78 additions and 71 deletions
|
@ -143,6 +143,10 @@ impl CanvasRenderingContext2D {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn ipc_renderer(&self) -> IpcSender<CanvasMsg> {
|
||||
self.ipc_renderer.clone()
|
||||
}
|
||||
|
||||
fn mark_as_dirty(&self) {
|
||||
let canvas = self.canvas.root();
|
||||
let node = NodeCast::from_ref(canvas.r());
|
||||
|
@ -245,6 +249,7 @@ impl CanvasRenderingContext2D {
|
|||
// Pixels come from cache in BGRA order and drawImage expects RGBA so we
|
||||
// have to swap the color values
|
||||
byte_swap(&mut data);
|
||||
let size = Size2D::new(size.width as f64, size.height as f64);
|
||||
(data, size)
|
||||
},
|
||||
None => return Err(InvalidState),
|
||||
|
@ -338,7 +343,7 @@ impl CanvasRenderingContext2D {
|
|||
|
||||
fn fetch_image_data(&self,
|
||||
image_element: &HTMLImageElement)
|
||||
-> Option<(Vec<u8>, Size2D<f64>)> {
|
||||
-> Option<(Vec<u8>, Size2D<i32>)> {
|
||||
let url = match image_element.get_url() {
|
||||
Some(url) => url,
|
||||
None => return None,
|
||||
|
@ -351,7 +356,7 @@ impl CanvasRenderingContext2D {
|
|||
}
|
||||
};
|
||||
|
||||
let image_size = Size2D::new(img.width as f64, img.height as f64);
|
||||
let image_size = Size2D::new(img.width as i32, img.height as i32);
|
||||
let image_data = match img.format {
|
||||
PixelFormat::RGBA8 => img.bytes.to_vec(),
|
||||
PixelFormat::K8 => panic!("K8 color type not supported"),
|
||||
|
@ -362,28 +367,6 @@ impl CanvasRenderingContext2D {
|
|||
Some((image_data, image_size))
|
||||
}
|
||||
|
||||
// TODO(ecoal95): Move this to `HTMLCanvasElement`, and support WebGL contexts
|
||||
fn fetch_canvas_data(&self,
|
||||
canvas_element: &HTMLCanvasElement,
|
||||
source_rect: Rect<f64>)
|
||||
-> Option<(Vec<u8>, Size2D<f64>)> {
|
||||
let context = match canvas_element.get_or_init_2d_context() {
|
||||
Some(context) => context,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let canvas_size = canvas_element.get_size();
|
||||
let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
|
||||
|
||||
let renderer = context.r().get_ipc_renderer();
|
||||
let (sender, receiver) = ipc::channel::<Vec<u8>>().unwrap();
|
||||
// Reads pixels from source canvas
|
||||
renderer.send(CanvasMsg::Canvas2d(Canvas2dMsg::GetImageData(source_rect.to_i32(),
|
||||
image_size, sender))).unwrap();
|
||||
|
||||
Some((receiver.recv().unwrap(), image_size))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn request_image_from_cache(&self, url: Url) -> ImageResponse {
|
||||
let canvas = self.canvas.root();
|
||||
|
@ -975,26 +958,20 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
}
|
||||
},
|
||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => {
|
||||
let canvas_element = canvas.r();
|
||||
let canvas = canvas.r();
|
||||
let _ = canvas.get_or_init_2d_context();
|
||||
|
||||
let canvas_size = canvas_element.get_size();
|
||||
let source_rect = Rect::new(Point2D::zero(),
|
||||
Size2D::new(canvas_size.width as f64, canvas_size.height as f64));
|
||||
|
||||
match self.fetch_canvas_data(&canvas_element, source_rect) {
|
||||
match canvas.fetch_all_data() {
|
||||
Some((data, size)) => (data, size),
|
||||
None => return Err(InvalidState),
|
||||
}
|
||||
},
|
||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(context) => {
|
||||
let canvas = context.r().Canvas();
|
||||
let canvas_element = canvas.r();
|
||||
let canvas = canvas.r();
|
||||
let _ = canvas.get_or_init_2d_context();
|
||||
|
||||
let canvas_size = canvas_element.get_size();
|
||||
let source_rect = Rect::new(Point2D::zero(),
|
||||
Size2D::new(canvas_size.width as f64, canvas_size.height as f64));
|
||||
|
||||
match self.fetch_canvas_data(&canvas_element, source_rect) {
|
||||
match canvas.fetch_all_data() {
|
||||
Some((data, size)) => (data, size),
|
||||
None => return Err(InvalidState),
|
||||
}
|
||||
|
@ -1004,7 +981,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
|
||||
return Ok(CanvasPattern::new(self.global.root().r(),
|
||||
image_data,
|
||||
Size2D::new(image_size.width as i32, image_size.height as i32),
|
||||
image_size,
|
||||
rep));
|
||||
}
|
||||
return Err(Syntax);
|
||||
|
|
|
@ -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;
|
||||
use canvas_traits::{CanvasMsg, FromLayoutMsg};
|
||||
use dom::attr::Attr;
|
||||
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
|
||||
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
|
||||
|
@ -22,7 +22,7 @@ use dom::node::{Node, NodeTypeId, window_from_node};
|
|||
use dom::virtualmethods::VirtualMethods;
|
||||
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
|
||||
use euclid::size::Size2D;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use js::jsapi::{HandleValue, JSContext};
|
||||
use offscreen_gl_context::GLContextAttributes;
|
||||
use std::cell::Cell;
|
||||
|
@ -150,6 +150,17 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
|
|||
|
||||
|
||||
impl HTMLCanvasElement {
|
||||
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
|
||||
if let Some(context) = self.context.get() {
|
||||
match context {
|
||||
CanvasContext::Context2d(context) => Some(context.root().r().ipc_renderer()),
|
||||
CanvasContext::WebGL(context) => Some(context.root().r().ipc_renderer()),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
|
||||
if self.context.get().is_none() {
|
||||
let window = window_from_node(self);
|
||||
|
@ -200,6 +211,27 @@ impl HTMLCanvasElement {
|
|||
pub fn is_valid(&self) -> bool {
|
||||
self.height.get() != 0 && self.width.get() != 0
|
||||
}
|
||||
|
||||
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
|
||||
let size = self.get_size();
|
||||
|
||||
if size.width == 0 || size.height == 0 {
|
||||
return None
|
||||
}
|
||||
|
||||
let renderer = match self.ipc_renderer() {
|
||||
Some(renderer) => renderer,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendPixelContents(sender));
|
||||
renderer.send(msg).unwrap();
|
||||
|
||||
let data = receiver.recv().unwrap().to_vec();
|
||||
|
||||
Some((data, size))
|
||||
}
|
||||
}
|
||||
|
||||
impl HTMLCanvasElementMethods for HTMLCanvasElement {
|
||||
|
|
|
@ -124,6 +124,27 @@ impl WebGLRenderingContext {
|
|||
self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap();
|
||||
}
|
||||
|
||||
pub fn ipc_renderer(&self) -> IpcSender<CanvasMsg> {
|
||||
self.ipc_renderer.clone()
|
||||
}
|
||||
|
||||
pub fn webgl_error(&self, err: WebGLError) {
|
||||
// If an error has been detected no further errors must be
|
||||
// recorded until `getError` has been called
|
||||
if self.last_error.get().is_none() {
|
||||
self.last_error.set(Some(err));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bound_texture_for(&self, target: u32) -> Option<JS<WebGLTexture>> {
|
||||
match target {
|
||||
constants::TEXTURE_2D => self.bound_texture_2d.get(),
|
||||
constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(),
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_as_dirty(&self) {
|
||||
let canvas = self.canvas.root();
|
||||
let node = NodeCast::from_ref(canvas.r());
|
||||
|
@ -845,8 +866,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
},
|
||||
// TODO(ecoal95): Getting canvas data is implemented in CanvasRenderingContext2D, but
|
||||
// we need to refactor it moving it to `HTMLCanvasElement` and supporting WebGLContext
|
||||
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLCanvasElement(_rooted_canvas)
|
||||
=> unimplemented!(),
|
||||
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLCanvasElement(canvas) => {
|
||||
let canvas = canvas.r();
|
||||
if let Some((mut data, size)) = canvas.fetch_all_data() {
|
||||
byte_swap(&mut data);
|
||||
(data, size)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
},
|
||||
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLVideoElement(_rooted_video)
|
||||
=> unimplemented!(),
|
||||
};
|
||||
|
@ -898,26 +926,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl WebGLRenderingContext {
|
||||
pub fn webgl_error(&self, err: WebGLError) {
|
||||
// If an error has been detected no further errors must be
|
||||
// recorded until `getError` has been called
|
||||
if self.last_error.get().is_none() {
|
||||
self.last_error.set(Some(err));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bound_texture_for(&self, target: u32) -> Option<JS<WebGLTexture>> {
|
||||
match target {
|
||||
constants::TEXTURE_2D => self.bound_texture_2d.get(),
|
||||
constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(),
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LayoutCanvasWebGLRenderingContextHelpers {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn get_renderer_id(&self) -> usize;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue