mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Use IpcSharedMemory
for Canvas2dMsg::DrawImage
(#30544)
* Use `IpcSharedMemory` for `Canvas2DMsg::DrawImage` * Fix `Canvas2dMsg::DrawEmptyImage` crashes * Do not premultiply canvas image data * Move `image_data` back to its original position
This commit is contained in:
parent
66258bfbbd
commit
2d7dfb06c0
4 changed files with 37 additions and 25 deletions
|
@ -446,11 +446,12 @@ impl<'a> CanvasData<'a> {
|
||||||
|
|
||||||
pub fn draw_image(
|
pub fn draw_image(
|
||||||
&mut self,
|
&mut self,
|
||||||
image_data: Vec<u8>,
|
image_data: &[u8],
|
||||||
image_size: Size2D<f64>,
|
image_size: Size2D<f64>,
|
||||||
dest_rect: Rect<f64>,
|
dest_rect: Rect<f64>,
|
||||||
source_rect: Rect<f64>,
|
source_rect: Rect<f64>,
|
||||||
smoothing_enabled: bool,
|
smoothing_enabled: bool,
|
||||||
|
premultiply: bool,
|
||||||
) {
|
) {
|
||||||
// We round up the floating pixel values to draw the pixels
|
// We round up the floating pixel values to draw the pixels
|
||||||
let source_rect = source_rect.ceil();
|
let source_rect = source_rect.ceil();
|
||||||
|
@ -469,6 +470,7 @@ impl<'a> CanvasData<'a> {
|
||||||
source_rect.size,
|
source_rect.size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
smoothing_enabled,
|
smoothing_enabled,
|
||||||
|
premultiply,
|
||||||
&draw_options,
|
&draw_options,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1306,17 +1308,24 @@ pub struct CanvasPaintState<'a> {
|
||||||
/// image_size: The size of the image to be written
|
/// image_size: The size of the image to be written
|
||||||
/// dest_rect: Area of the destination target where the pixels will be copied
|
/// dest_rect: Area of the destination target where the pixels will be copied
|
||||||
/// smoothing_enabled: It determines if smoothing is applied to the image result
|
/// smoothing_enabled: It determines if smoothing is applied to the image result
|
||||||
|
/// premultiply: Determines whenever the image data should be premultiplied or not
|
||||||
fn write_image(
|
fn write_image(
|
||||||
draw_target: &mut dyn GenericDrawTarget,
|
draw_target: &mut dyn GenericDrawTarget,
|
||||||
image_data: Vec<u8>,
|
mut image_data: Vec<u8>,
|
||||||
image_size: Size2D<f64>,
|
image_size: Size2D<f64>,
|
||||||
dest_rect: Rect<f64>,
|
dest_rect: Rect<f64>,
|
||||||
smoothing_enabled: bool,
|
smoothing_enabled: bool,
|
||||||
|
premultiply: bool,
|
||||||
draw_options: &DrawOptions,
|
draw_options: &DrawOptions,
|
||||||
) {
|
) {
|
||||||
if image_data.is_empty() {
|
if image_data.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if premultiply {
|
||||||
|
pixels::rgba8_premultiply_inplace(&mut image_data);
|
||||||
|
}
|
||||||
|
|
||||||
let image_rect = Rect::new(Point2D::zero(), image_size);
|
let image_rect = Rect::new(Point2D::zero(), image_size);
|
||||||
|
|
||||||
// From spec https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
// From spec https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||||
|
|
|
@ -175,22 +175,27 @@ impl<'a> CanvasPaintThread<'a> {
|
||||||
.canvas(canvas_id)
|
.canvas(canvas_id)
|
||||||
.is_point_in_path(x, y, fill_rule, chan),
|
.is_point_in_path(x, y, fill_rule, chan),
|
||||||
Canvas2dMsg::DrawImage(
|
Canvas2dMsg::DrawImage(
|
||||||
imagedata,
|
ref image_data,
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
smoothing_enabled,
|
smoothing_enabled,
|
||||||
) => {
|
) => self.canvas(canvas_id).draw_image(
|
||||||
let data = imagedata.map_or_else(
|
&*image_data,
|
||||||
|| vec![0; image_size.width as usize * image_size.height as usize * 4],
|
image_size,
|
||||||
|bytes| bytes.into_vec(),
|
dest_rect,
|
||||||
);
|
source_rect,
|
||||||
|
smoothing_enabled,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
Canvas2dMsg::DrawEmptyImage(image_size, dest_rect, source_rect) => {
|
||||||
self.canvas(canvas_id).draw_image(
|
self.canvas(canvas_id).draw_image(
|
||||||
data,
|
&vec![0; image_size.area() as usize * 4],
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
smoothing_enabled,
|
false,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
Canvas2dMsg::DrawImageInOther(
|
Canvas2dMsg::DrawImageInOther(
|
||||||
|
@ -204,11 +209,12 @@ impl<'a> CanvasPaintThread<'a> {
|
||||||
.canvas(canvas_id)
|
.canvas(canvas_id)
|
||||||
.read_pixels(source_rect.to_u64(), image_size.to_u64());
|
.read_pixels(source_rect.to_u64(), image_size.to_u64());
|
||||||
self.canvas(other_canvas_id).draw_image(
|
self.canvas(other_canvas_id).draw_image(
|
||||||
image_data.into(),
|
&image_data,
|
||||||
source_rect.size,
|
source_rect.size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
smoothing,
|
smoothing,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Canvas2dMsg::MoveTo(ref point) => self.canvas(canvas_id).move_to(point),
|
Canvas2dMsg::MoveTo(ref point) => self.canvas(canvas_id).move_to(point),
|
||||||
|
|
|
@ -41,7 +41,8 @@ pub struct CanvasImageData {
|
||||||
pub enum Canvas2dMsg {
|
pub enum Canvas2dMsg {
|
||||||
Arc(Point2D<f32>, f32, f32, f32, bool),
|
Arc(Point2D<f32>, f32, f32, f32, bool),
|
||||||
ArcTo(Point2D<f32>, Point2D<f32>, f32),
|
ArcTo(Point2D<f32>, Point2D<f32>, f32),
|
||||||
DrawImage(Option<ByteBuf>, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
|
DrawImage(IpcSharedMemory, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
|
||||||
|
DrawEmptyImage(Size2D<f64>, Rect<f64>, Rect<f64>),
|
||||||
DrawImageInOther(CanvasId, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
|
DrawImageInOther(CanvasId, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
|
||||||
BeginPath,
|
BeginPath,
|
||||||
BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
|
BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
|
||||||
|
|
|
@ -15,13 +15,12 @@ use canvas_traits::canvas::{
|
||||||
use cssparser::{Color as CSSColor, Parser, ParserInput, RGBA};
|
use cssparser::{Color as CSSColor, Parser, ParserInput, RGBA};
|
||||||
use euclid::default::{Point2D, Rect, Size2D, Transform2D};
|
use euclid::default::{Point2D, Rect, Size2D, Transform2D};
|
||||||
use euclid::vec2;
|
use euclid::vec2;
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
|
||||||
use net_traits::image_cache::{ImageCache, ImageResponse};
|
use net_traits::image_cache::{ImageCache, ImageResponse};
|
||||||
use net_traits::request::CorsSettings;
|
use net_traits::request::CorsSettings;
|
||||||
use pixels::PixelFormat;
|
use pixels::PixelFormat;
|
||||||
use profile_traits::ipc as profiled_ipc;
|
use profile_traits::ipc as profiled_ipc;
|
||||||
use script_traits::ScriptMsg;
|
use script_traits::ScriptMsg;
|
||||||
use serde_bytes::ByteBuf;
|
|
||||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps;
|
use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps;
|
||||||
use style::properties::style_structs::Font;
|
use style::properties::style_structs::Font;
|
||||||
|
@ -260,7 +259,7 @@ impl CanvasState {
|
||||||
&self,
|
&self,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
cors_setting: Option<CorsSettings>,
|
cors_setting: Option<CorsSettings>,
|
||||||
) -> Option<(Vec<u8>, Size2D<u32>)> {
|
) -> Option<(IpcSharedMemory, Size2D<u32>)> {
|
||||||
let img = match self.request_image_from_cache(url, cors_setting) {
|
let img = match self.request_image_from_cache(url, cors_setting) {
|
||||||
ImageResponse::Loaded(img, _) => img,
|
ImageResponse::Loaded(img, _) => img,
|
||||||
ImageResponse::PlaceholderLoaded(_, _) |
|
ImageResponse::PlaceholderLoaded(_, _) |
|
||||||
|
@ -272,7 +271,7 @@ impl CanvasState {
|
||||||
|
|
||||||
let image_size = Size2D::new(img.width, img.height);
|
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.clone(),
|
||||||
pixel_format => unimplemented!("unsupported pixel format ({:?})", pixel_format),
|
pixel_format => unimplemented!("unsupported pixel format ({:?})", pixel_format),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -492,12 +491,10 @@ impl CanvasState {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
|
self.send_canvas_2d_msg(Canvas2dMsg::DrawEmptyImage(
|
||||||
None,
|
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
smoothing_enabled,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,12 +551,10 @@ impl CanvasState {
|
||||||
_ => return Err(Error::InvalidState),
|
_ => return Err(Error::InvalidState),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
|
self.send_canvas_2d_msg(Canvas2dMsg::DrawEmptyImage(
|
||||||
None,
|
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
smoothing_enabled,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,10 +577,9 @@ impl CanvasState {
|
||||||
dh: Option<f64>,
|
dh: Option<f64>,
|
||||||
) -> ErrorResult {
|
) -> ErrorResult {
|
||||||
debug!("Fetching image {}.", url);
|
debug!("Fetching image {}.", url);
|
||||||
let (mut image_data, image_size) = self
|
let (image_data, image_size) = self
|
||||||
.fetch_image_data(url, cors_setting)
|
.fetch_image_data(url, cors_setting)
|
||||||
.ok_or(Error::InvalidState)?;
|
.ok_or(Error::InvalidState)?;
|
||||||
pixels::rgba8_premultiply_inplace(&mut image_data);
|
|
||||||
let image_size = image_size.to_f64();
|
let image_size = image_size.to_f64();
|
||||||
|
|
||||||
let dw = dw.unwrap_or(image_size.width);
|
let dw = dw.unwrap_or(image_size.width);
|
||||||
|
@ -603,7 +597,7 @@ impl CanvasState {
|
||||||
|
|
||||||
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
|
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
|
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
|
||||||
Some(ByteBuf::from(image_data)),
|
image_data,
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
|
@ -916,6 +910,7 @@ impl CanvasState {
|
||||||
.and_then(|url| {
|
.and_then(|url| {
|
||||||
self.fetch_image_data(url, cors_setting_for_element(image.upcast()))
|
self.fetch_image_data(url, cors_setting_for_element(image.upcast()))
|
||||||
})
|
})
|
||||||
|
.map(|data| (data.0.to_vec(), data.1))
|
||||||
.ok_or(Error::InvalidState)?
|
.ok_or(Error::InvalidState)?
|
||||||
},
|
},
|
||||||
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
||||||
|
@ -935,6 +930,7 @@ impl CanvasState {
|
||||||
CanvasImageSource::CSSStyleValue(ref value) => value
|
CanvasImageSource::CSSStyleValue(ref value) => value
|
||||||
.get_url(self.base_url.clone())
|
.get_url(self.base_url.clone())
|
||||||
.and_then(|url| self.fetch_image_data(url, None))
|
.and_then(|url| self.fetch_image_data(url, None))
|
||||||
|
.map(|data| (data.0.to_vec(), data.1))
|
||||||
.ok_or(Error::InvalidState)?,
|
.ok_or(Error::InvalidState)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue