mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
canvas: Make script/canvas thread boundry mostly stateless (#38164)
This PR removes all `Set*` commands as we will send needed options on each request. This will allow us to remove most of state handling from canvas paint thread (currently it's still stateful). Testing: Existing WPT tests work towards #38022 try run: https://github.com/sagudev/servo/actions/runs/16413823963 --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
8a1cc69717
commit
cd340fa8b9
3 changed files with 379 additions and 116 deletions
|
@ -5,7 +5,7 @@
|
|||
use std::borrow::ToOwned;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::{f32, thread};
|
||||
|
||||
use canvas_traits::ConstellationCanvasMsg;
|
||||
use canvas_traits::canvas::*;
|
||||
|
@ -134,76 +134,149 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
|
||||
fn process_canvas_2d_message(&mut self, message: Canvas2dMsg, canvas_id: CanvasId) {
|
||||
match message {
|
||||
Canvas2dMsg::FillText(text, x, y, max_width, style, is_rtl) => {
|
||||
self.canvas(canvas_id).set_fill_style(style);
|
||||
self.canvas(canvas_id)
|
||||
.fill_text(text, x, y, max_width, is_rtl);
|
||||
Canvas2dMsg::FillText(
|
||||
text,
|
||||
x,
|
||||
y,
|
||||
max_width,
|
||||
style,
|
||||
is_rtl,
|
||||
text_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.set_fill_style(style);
|
||||
canvas.set_text_options(text_options);
|
||||
canvas.set_shadow_options(shadow_options);
|
||||
canvas.set_composition_options(composition_options);
|
||||
canvas.fill_text(text, x, y, max_width, is_rtl);
|
||||
},
|
||||
Canvas2dMsg::FillRect(rect, style) => {
|
||||
self.canvas(canvas_id).set_fill_style(style);
|
||||
self.canvas(canvas_id).fill_rect(&rect);
|
||||
Canvas2dMsg::FillRect(rect, style, shadow_options, composition_options, transform) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.set_fill_style(style);
|
||||
canvas.set_shadow_options(shadow_options);
|
||||
canvas.set_composition_options(composition_options);
|
||||
canvas.fill_rect(&rect);
|
||||
},
|
||||
Canvas2dMsg::StrokeRect(rect, style) => {
|
||||
self.canvas(canvas_id).set_stroke_style(style);
|
||||
self.canvas(canvas_id).stroke_rect(&rect);
|
||||
Canvas2dMsg::StrokeRect(
|
||||
rect,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.set_stroke_style(style);
|
||||
canvas.set_line_options(line_options);
|
||||
canvas.set_shadow_options(shadow_options);
|
||||
canvas.set_composition_options(composition_options);
|
||||
canvas.stroke_rect(&rect);
|
||||
},
|
||||
Canvas2dMsg::ClearRect(ref rect) => self.canvas(canvas_id).clear_rect(rect),
|
||||
Canvas2dMsg::FillPath(style, path) => {
|
||||
self.canvas(canvas_id).set_fill_style(style);
|
||||
self.canvas(canvas_id).fill_path(&path);
|
||||
Canvas2dMsg::ClearRect(ref rect, transform) => {
|
||||
self.canvas(canvas_id).set_transform(&transform);
|
||||
self.canvas(canvas_id).clear_rect(rect)
|
||||
},
|
||||
Canvas2dMsg::StrokePath(style, path) => {
|
||||
self.canvas(canvas_id).set_stroke_style(style);
|
||||
self.canvas(canvas_id).stroke_path(&path);
|
||||
Canvas2dMsg::FillPath(style, path, shadow_options, composition_options, transform) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.set_fill_style(style);
|
||||
canvas.set_shadow_options(shadow_options);
|
||||
canvas.set_composition_options(composition_options);
|
||||
canvas.fill_path(&path);
|
||||
},
|
||||
Canvas2dMsg::ClipPath(path) => self.canvas(canvas_id).clip_path(&path),
|
||||
Canvas2dMsg::DrawImage(snapshot, dest_rect, source_rect, smoothing_enabled) => {
|
||||
self.canvas(canvas_id).draw_image(
|
||||
Canvas2dMsg::StrokePath(
|
||||
path,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.set_stroke_style(style);
|
||||
canvas.set_line_options(line_options);
|
||||
canvas.set_shadow_options(shadow_options);
|
||||
canvas.set_composition_options(composition_options);
|
||||
canvas.stroke_path(&path);
|
||||
},
|
||||
Canvas2dMsg::ClipPath(path, transform) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.clip_path(&path);
|
||||
},
|
||||
Canvas2dMsg::DrawImage(
|
||||
snapshot,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.set_shadow_options(shadow_options);
|
||||
canvas.set_composition_options(composition_options);
|
||||
canvas.draw_image(
|
||||
snapshot.to_owned(),
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
)
|
||||
},
|
||||
Canvas2dMsg::DrawEmptyImage(image_size, dest_rect, source_rect) => self
|
||||
.canvas(canvas_id)
|
||||
.draw_image(Snapshot::cleared(image_size), dest_rect, source_rect, false),
|
||||
Canvas2dMsg::DrawEmptyImage(
|
||||
image_size,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.set_shadow_options(shadow_options);
|
||||
canvas.set_composition_options(composition_options);
|
||||
self.canvas(canvas_id).draw_image(
|
||||
Snapshot::cleared(image_size),
|
||||
dest_rect,
|
||||
source_rect,
|
||||
false,
|
||||
)
|
||||
},
|
||||
Canvas2dMsg::DrawImageInOther(
|
||||
other_canvas_id,
|
||||
image_size,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
) => {
|
||||
let snapshot = self
|
||||
.canvas(canvas_id)
|
||||
.read_pixels(Some(source_rect.to_u32()), Some(image_size));
|
||||
self.canvas(other_canvas_id).draw_image(
|
||||
snapshot,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing,
|
||||
);
|
||||
let canvas = self.canvas(other_canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.set_composition_options(composition_options);
|
||||
canvas.set_shadow_options(shadow_options);
|
||||
canvas.draw_image(snapshot, dest_rect, source_rect, smoothing);
|
||||
},
|
||||
Canvas2dMsg::MeasureText(text, sender) => {
|
||||
let metrics = self.canvas(canvas_id).measure_text(text);
|
||||
Canvas2dMsg::MeasureText(text, sender, text_options) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_text_options(text_options);
|
||||
let metrics = canvas.measure_text(text);
|
||||
sender.send(metrics).unwrap();
|
||||
},
|
||||
Canvas2dMsg::RestoreContext => self.canvas(canvas_id).restore_context_state(),
|
||||
Canvas2dMsg::SaveContext => self.canvas(canvas_id).save_context_state(),
|
||||
Canvas2dMsg::SetLineWidth(width) => self.canvas(canvas_id).set_line_width(width),
|
||||
Canvas2dMsg::SetLineCap(cap) => self.canvas(canvas_id).set_line_cap(cap),
|
||||
Canvas2dMsg::SetLineJoin(join) => self.canvas(canvas_id).set_line_join(join),
|
||||
Canvas2dMsg::SetMiterLimit(limit) => self.canvas(canvas_id).set_miter_limit(limit),
|
||||
Canvas2dMsg::SetLineDash(items) => self.canvas(canvas_id).set_line_dash(items),
|
||||
Canvas2dMsg::SetLineDashOffset(offset) => {
|
||||
self.canvas(canvas_id).set_line_dash_offset(offset)
|
||||
},
|
||||
Canvas2dMsg::SetTransform(ref matrix) => self.canvas(canvas_id).set_transform(matrix),
|
||||
Canvas2dMsg::SetGlobalAlpha(alpha) => self.canvas(canvas_id).set_global_alpha(alpha),
|
||||
Canvas2dMsg::SetGlobalComposition(op) => {
|
||||
self.canvas(canvas_id).set_global_composition(op)
|
||||
},
|
||||
Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender) => {
|
||||
let snapshot = self
|
||||
.canvas(canvas_id)
|
||||
|
@ -214,21 +287,6 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
self.canvas(canvas_id)
|
||||
.put_image_data(snapshot.to_owned(), rect);
|
||||
},
|
||||
Canvas2dMsg::SetShadowOffsetX(value) => {
|
||||
self.canvas(canvas_id).set_shadow_offset_x(value)
|
||||
},
|
||||
Canvas2dMsg::SetShadowOffsetY(value) => {
|
||||
self.canvas(canvas_id).set_shadow_offset_y(value)
|
||||
},
|
||||
Canvas2dMsg::SetShadowBlur(value) => self.canvas(canvas_id).set_shadow_blur(value),
|
||||
Canvas2dMsg::SetShadowColor(color) => self.canvas(canvas_id).set_shadow_color(color),
|
||||
Canvas2dMsg::SetFont(font_style) => self.canvas(canvas_id).set_font(font_style),
|
||||
Canvas2dMsg::SetTextAlign(text_align) => {
|
||||
self.canvas(canvas_id).set_text_align(text_align)
|
||||
},
|
||||
Canvas2dMsg::SetTextBaseline(text_baseline) => {
|
||||
self.canvas(canvas_id).set_text_baseline(text_baseline)
|
||||
},
|
||||
Canvas2dMsg::UpdateImage(sender) => {
|
||||
self.canvas(canvas_id).update_image_rendering();
|
||||
sender.send(()).unwrap();
|
||||
|
@ -455,4 +513,41 @@ impl Canvas<'_> {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.recreate(size),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_text_options(&mut self, text_options: TextOptions) {
|
||||
if let Some(font) = text_options.font {
|
||||
self.set_font(font);
|
||||
}
|
||||
self.set_text_align(text_options.align);
|
||||
self.set_text_baseline(text_options.baseline);
|
||||
}
|
||||
|
||||
fn set_shadow_options(&mut self, shadow_options: ShadowOptions) {
|
||||
self.set_shadow_color(shadow_options.color);
|
||||
self.set_shadow_offset_x(shadow_options.offset_x);
|
||||
self.set_shadow_offset_y(shadow_options.offset_y);
|
||||
self.set_shadow_blur(shadow_options.blur);
|
||||
}
|
||||
|
||||
fn set_composition_options(&mut self, composition_options: CompositionOptions) {
|
||||
self.set_global_alpha(composition_options.alpha as f32);
|
||||
self.set_global_composition(composition_options.composition_operation);
|
||||
}
|
||||
|
||||
fn set_line_options(&mut self, line_options: LineOptions) {
|
||||
let LineOptions {
|
||||
width,
|
||||
cap_style,
|
||||
join_style,
|
||||
miter_limit,
|
||||
dash,
|
||||
dash_offset,
|
||||
} = line_options;
|
||||
self.set_line_width(width as f32);
|
||||
self.set_line_cap(cap_style);
|
||||
self.set_line_join(join_style);
|
||||
self.set_miter_limit(miter_limit as f32);
|
||||
self.set_line_dash(dash);
|
||||
self.set_line_dash_offset(dash_offset as f32);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ use std::str::FromStr;
|
|||
use std::sync::Arc;
|
||||
|
||||
use canvas_traits::canvas::{
|
||||
Canvas2dMsg, CanvasId, CanvasMsg, CompositionOrBlending, Direction, FillOrStrokeStyle,
|
||||
FillRule, LineCapStyle, LineJoinStyle, LinearGradientStyle, Path, RadialGradientStyle,
|
||||
RepetitionStyle, TextAlign, TextBaseline, TextMetrics as CanvasTextMetrics,
|
||||
Canvas2dMsg, CanvasId, CanvasMsg, CompositionOptions, CompositionOrBlending, Direction,
|
||||
FillOrStrokeStyle, FillRule, LineCapStyle, LineJoinStyle, LineOptions, LinearGradientStyle,
|
||||
Path, RadialGradientStyle, RepetitionStyle, ShadowOptions, TextAlign, TextBaseline,
|
||||
TextMetrics as CanvasTextMetrics, TextOptions,
|
||||
};
|
||||
use constellation_traits::ScriptToConstellationMessage;
|
||||
use cssparser::color::clamp_unit_f32;
|
||||
|
@ -146,6 +147,41 @@ impl CanvasContextState {
|
|||
line_dash_offset: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn text_options(&self) -> TextOptions {
|
||||
TextOptions {
|
||||
font: self.font_style.clone(),
|
||||
align: self.text_align,
|
||||
baseline: self.text_baseline,
|
||||
}
|
||||
}
|
||||
|
||||
fn composition_options(&self) -> CompositionOptions {
|
||||
CompositionOptions {
|
||||
alpha: self.global_alpha,
|
||||
composition_operation: self.global_composition,
|
||||
}
|
||||
}
|
||||
|
||||
fn shadow_options(&self) -> ShadowOptions {
|
||||
ShadowOptions {
|
||||
offset_x: self.shadow_offset_x,
|
||||
offset_y: self.shadow_offset_y,
|
||||
blur: self.shadow_blur,
|
||||
color: self.shadow_color,
|
||||
}
|
||||
}
|
||||
|
||||
fn line_options(&self) -> LineOptions {
|
||||
LineOptions {
|
||||
width: self.line_width,
|
||||
cap_style: self.line_cap,
|
||||
join_style: self.line_join,
|
||||
miter_limit: self.miter_limit,
|
||||
dash: self.line_dash.iter().map(|x| *x as f32).collect(),
|
||||
dash_offset: self.line_dash_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
|
@ -302,7 +338,10 @@ impl CanvasState {
|
|||
return;
|
||||
}
|
||||
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::ClearRect(self.size.get().to_f32().into()));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::ClearRect(
|
||||
self.size.get().to_f32().into(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
}
|
||||
|
||||
fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option<Rect<f32>> {
|
||||
|
@ -563,6 +602,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
|
||||
self.mark_as_dirty(canvas);
|
||||
|
@ -609,6 +651,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
|
||||
self.mark_as_dirty(canvas);
|
||||
|
@ -657,6 +702,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
},
|
||||
OffscreenRenderingContext::BitmapRenderer(ref context) => {
|
||||
|
@ -669,6 +717,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
},
|
||||
OffscreenRenderingContext::Detached => return Err(Error::InvalidState),
|
||||
|
@ -678,6 +729,9 @@ impl CanvasState {
|
|||
image_size,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -728,6 +782,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
},
|
||||
RenderingContext::BitmapRenderer(ref context) => {
|
||||
|
@ -740,6 +797,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
},
|
||||
RenderingContext::Placeholder(ref context) => {
|
||||
|
@ -754,6 +814,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
)),
|
||||
OffscreenRenderingContext::BitmapRenderer(ref context) => {
|
||||
let Some(snapshot) = context.get_image_data() else {
|
||||
|
@ -765,6 +828,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
},
|
||||
OffscreenRenderingContext::Detached => return Err(Error::InvalidState),
|
||||
|
@ -777,6 +843,9 @@ impl CanvasState {
|
|||
image_size,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -824,6 +893,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
self.mark_as_dirty(canvas);
|
||||
Ok(())
|
||||
|
@ -870,6 +942,9 @@ impl CanvasState {
|
|||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
|
||||
self.mark_as_dirty(canvas);
|
||||
|
@ -952,7 +1027,6 @@ impl CanvasState {
|
|||
.borrow_mut()
|
||||
.transform(state.transform.cast());
|
||||
state.transform = transform;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetTransform(state.transform));
|
||||
if let Some(inverse) = transform.inverse() {
|
||||
self.current_default_path
|
||||
.borrow_mut()
|
||||
|
@ -964,14 +1038,20 @@ impl CanvasState {
|
|||
pub(crate) fn fill_rect(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
if let Some(rect) = self.create_drawable_rect(x, y, width, height) {
|
||||
let style = self.state.borrow().fill_style.to_fill_or_stroke_style();
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::FillRect(rect, style));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::FillRect(
|
||||
rect,
|
||||
style,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clearrect
|
||||
pub(crate) fn clear_rect(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
if let Some(rect) = self.create_drawable_rect(x, y, width, height) {
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::ClearRect(rect));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::ClearRect(rect, self.state.borrow().transform));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -979,7 +1059,14 @@ impl CanvasState {
|
|||
pub(crate) fn stroke_rect(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
if let Some(rect) = self.create_drawable_rect(x, y, width, height) {
|
||||
let style = self.state.borrow().stroke_style.to_fill_or_stroke_style();
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::StrokeRect(rect, style));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::StrokeRect(
|
||||
rect,
|
||||
style,
|
||||
self.state.borrow().line_options(),
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -994,7 +1081,6 @@ impl CanvasState {
|
|||
return;
|
||||
}
|
||||
self.state.borrow_mut().shadow_offset_x = value;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetShadowOffsetX(value))
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsety
|
||||
|
@ -1008,7 +1094,6 @@ impl CanvasState {
|
|||
return;
|
||||
}
|
||||
self.state.borrow_mut().shadow_offset_y = value;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetShadowOffsetY(value))
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowblur
|
||||
|
@ -1022,7 +1107,6 @@ impl CanvasState {
|
|||
return;
|
||||
}
|
||||
self.state.borrow_mut().shadow_blur = value;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetShadowBlur(value))
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
|
||||
|
@ -1041,7 +1125,6 @@ impl CanvasState {
|
|||
) {
|
||||
if let Ok(rgba) = parse_color(canvas, &value, can_gc) {
|
||||
self.state.borrow_mut().shadow_color = rgba;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetShadowColor(rgba))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1286,7 +1369,6 @@ impl CanvasState {
|
|||
}
|
||||
|
||||
self.state.borrow_mut().global_alpha = alpha;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetGlobalAlpha(alpha as f32))
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalcompositeoperation
|
||||
|
@ -1301,7 +1383,6 @@ impl CanvasState {
|
|||
pub(crate) fn set_global_composite_operation(&self, op_str: DOMString) {
|
||||
if let Ok(op) = CompositionOrBlending::from_str(&op_str) {
|
||||
self.state.borrow_mut().global_composition = op;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetGlobalComposition(op))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1353,6 +1434,10 @@ impl CanvasState {
|
|||
max_width,
|
||||
style,
|
||||
is_rtl,
|
||||
self.state.borrow().text_options(),
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -1373,7 +1458,11 @@ impl CanvasState {
|
|||
}
|
||||
|
||||
let (sender, receiver) = ipc::channel::<CanvasTextMetrics>().unwrap();
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::MeasureText(text.into(), sender));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::MeasureText(
|
||||
text.into(),
|
||||
sender,
|
||||
self.state.borrow().text_options(),
|
||||
));
|
||||
let metrics = receiver.recv().unwrap();
|
||||
|
||||
TextMetrics::new(
|
||||
|
@ -1413,7 +1502,6 @@ impl CanvasState {
|
|||
None => return, // syntax error
|
||||
};
|
||||
self.state.borrow_mut().font_style = Some((*resolved_font_style).clone());
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetFont((*resolved_font_style).clone()));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-font
|
||||
|
@ -1449,7 +1537,6 @@ impl CanvasState {
|
|||
CanvasTextAlign::Center => TextAlign::Center,
|
||||
};
|
||||
self.state.borrow_mut().text_align = text_align;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetTextAlign(text_align));
|
||||
}
|
||||
|
||||
pub(crate) fn text_baseline(&self) -> CanvasTextBaseline {
|
||||
|
@ -1473,7 +1560,6 @@ impl CanvasState {
|
|||
CanvasTextBaseline::Bottom => TextBaseline::Bottom,
|
||||
};
|
||||
self.state.borrow_mut().text_baseline = text_baseline;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetTextBaseline(text_baseline));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-direction
|
||||
|
@ -1507,7 +1593,6 @@ impl CanvasState {
|
|||
}
|
||||
|
||||
self.state.borrow_mut().line_width = width;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetLineWidth(width as f32))
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap
|
||||
|
@ -1527,7 +1612,6 @@ impl CanvasState {
|
|||
CanvasLineCap::Square => LineCapStyle::Square,
|
||||
};
|
||||
self.state.borrow_mut().line_cap = line_cap;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetLineCap(line_cap));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin
|
||||
|
@ -1547,7 +1631,6 @@ impl CanvasState {
|
|||
CanvasLineJoin::Miter => LineJoinStyle::Miter,
|
||||
};
|
||||
self.state.borrow_mut().line_join = line_join;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetLineJoin(line_join));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit
|
||||
|
@ -1562,7 +1645,6 @@ impl CanvasState {
|
|||
}
|
||||
|
||||
self.state.borrow_mut().miter_limit = limit;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetMiterLimit(limit as f32))
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-getlinedash>
|
||||
|
@ -1594,9 +1676,6 @@ impl CanvasState {
|
|||
|
||||
// > Let the object's dash list be segments.
|
||||
self.state.borrow_mut().line_dash = line_dash.clone();
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetLineDash(
|
||||
line_dash.into_iter().map(|dash| dash as f32).collect(),
|
||||
))
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset>
|
||||
|
@ -1615,7 +1694,6 @@ impl CanvasState {
|
|||
|
||||
// > other values must change the current value to the new value.
|
||||
self.state.borrow_mut().line_dash_offset = offset;
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetLineDashOffset(offset as f32));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata
|
||||
|
@ -1858,7 +1936,13 @@ impl CanvasState {
|
|||
pub(crate) fn fill_(&self, path: Path, _fill_rule: CanvasFillRule) {
|
||||
// TODO: Process fill rule
|
||||
let style = self.state.borrow().fill_style.to_fill_or_stroke_style();
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::FillPath(style, path));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::FillPath(
|
||||
style,
|
||||
path,
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke
|
||||
|
@ -1869,7 +1953,14 @@ impl CanvasState {
|
|||
|
||||
pub(crate) fn stroke_(&self, path: Path) {
|
||||
let style = self.state.borrow().stroke_style.to_fill_or_stroke_style();
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::StrokePath(style, path));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::StrokePath(
|
||||
path,
|
||||
style,
|
||||
self.state.borrow().line_options(),
|
||||
self.state.borrow().shadow_options(),
|
||||
self.state.borrow().composition_options(),
|
||||
self.state.borrow().transform,
|
||||
));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
|
||||
|
@ -1881,7 +1972,7 @@ impl CanvasState {
|
|||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
|
||||
pub(crate) fn clip_(&self, path: Path, _fill_rule: CanvasFillRule) {
|
||||
// TODO: Process fill rule
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::ClipPath(path));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::ClipPath(path, self.state.borrow().transform));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath
|
||||
|
|
|
@ -400,6 +400,38 @@ pub enum FillRule {
|
|||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
pub struct CanvasId(pub u64);
|
||||
|
||||
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
pub struct CompositionOptions {
|
||||
pub alpha: f64,
|
||||
pub composition_operation: CompositionOrBlending,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
pub struct ShadowOptions {
|
||||
pub offset_x: f64,
|
||||
pub offset_y: f64,
|
||||
pub blur: f64,
|
||||
pub color: AbsoluteColor,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
pub struct LineOptions {
|
||||
pub width: f64,
|
||||
pub cap_style: LineCapStyle,
|
||||
pub join_style: LineJoinStyle,
|
||||
pub miter_limit: f64,
|
||||
pub dash: Vec<f32>,
|
||||
pub dash_offset: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
pub struct TextOptions {
|
||||
pub font: Option<FontStyleStruct>,
|
||||
pub align: TextAlign,
|
||||
pub baseline: TextBaseline,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum CanvasMsg {
|
||||
Canvas2d(Canvas2dMsg, CanvasId),
|
||||
|
@ -410,37 +442,82 @@ pub enum CanvasMsg {
|
|||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum Canvas2dMsg {
|
||||
DrawImage(IpcSnapshot, Rect<f64>, Rect<f64>, bool),
|
||||
DrawEmptyImage(Size2D<u32>, Rect<f64>, Rect<f64>),
|
||||
DrawImageInOther(CanvasId, Size2D<u32>, Rect<f64>, Rect<f64>, bool),
|
||||
ClearRect(Rect<f32>),
|
||||
ClipPath(Path),
|
||||
FillPath(FillOrStrokeStyle, Path),
|
||||
FillText(String, f64, f64, Option<f64>, FillOrStrokeStyle, bool),
|
||||
FillRect(Rect<f32>, FillOrStrokeStyle),
|
||||
DrawImage(
|
||||
IpcSnapshot,
|
||||
Rect<f64>,
|
||||
Rect<f64>,
|
||||
bool,
|
||||
ShadowOptions,
|
||||
CompositionOptions,
|
||||
Transform2D<f32>,
|
||||
),
|
||||
DrawEmptyImage(
|
||||
Size2D<u32>,
|
||||
Rect<f64>,
|
||||
Rect<f64>,
|
||||
ShadowOptions,
|
||||
CompositionOptions,
|
||||
Transform2D<f32>,
|
||||
),
|
||||
DrawImageInOther(
|
||||
CanvasId,
|
||||
Size2D<u32>,
|
||||
Rect<f64>,
|
||||
Rect<f64>,
|
||||
bool,
|
||||
ShadowOptions,
|
||||
CompositionOptions,
|
||||
Transform2D<f32>,
|
||||
),
|
||||
ClearRect(Rect<f32>, Transform2D<f32>),
|
||||
ClipPath(Path, Transform2D<f32>),
|
||||
FillPath(
|
||||
FillOrStrokeStyle,
|
||||
Path,
|
||||
ShadowOptions,
|
||||
CompositionOptions,
|
||||
Transform2D<f32>,
|
||||
),
|
||||
FillText(
|
||||
String,
|
||||
f64,
|
||||
f64,
|
||||
Option<f64>,
|
||||
FillOrStrokeStyle,
|
||||
bool,
|
||||
TextOptions,
|
||||
ShadowOptions,
|
||||
CompositionOptions,
|
||||
Transform2D<f32>,
|
||||
),
|
||||
FillRect(
|
||||
Rect<f32>,
|
||||
FillOrStrokeStyle,
|
||||
ShadowOptions,
|
||||
CompositionOptions,
|
||||
Transform2D<f32>,
|
||||
),
|
||||
GetImageData(Rect<u32>, Size2D<u32>, IpcSender<IpcSnapshot>),
|
||||
MeasureText(String, IpcSender<TextMetrics>),
|
||||
MeasureText(String, IpcSender<TextMetrics>, TextOptions),
|
||||
PutImageData(Rect<u32>, IpcSnapshot),
|
||||
RestoreContext,
|
||||
SaveContext,
|
||||
StrokeRect(Rect<f32>, FillOrStrokeStyle),
|
||||
StrokePath(FillOrStrokeStyle, Path),
|
||||
SetLineWidth(f32),
|
||||
SetLineCap(LineCapStyle),
|
||||
SetLineJoin(LineJoinStyle),
|
||||
SetMiterLimit(f32),
|
||||
SetLineDash(Vec<f32>),
|
||||
SetLineDashOffset(f32),
|
||||
SetGlobalAlpha(f32),
|
||||
SetGlobalComposition(CompositionOrBlending),
|
||||
SetTransform(Transform2D<f32>),
|
||||
SetShadowOffsetX(f64),
|
||||
SetShadowOffsetY(f64),
|
||||
SetShadowBlur(f64),
|
||||
SetShadowColor(AbsoluteColor),
|
||||
SetFont(FontStyleStruct),
|
||||
SetTextAlign(TextAlign),
|
||||
SetTextBaseline(TextBaseline),
|
||||
StrokeRect(
|
||||
Rect<f32>,
|
||||
FillOrStrokeStyle,
|
||||
LineOptions,
|
||||
ShadowOptions,
|
||||
CompositionOptions,
|
||||
Transform2D<f32>,
|
||||
),
|
||||
StrokePath(
|
||||
Path,
|
||||
FillOrStrokeStyle,
|
||||
LineOptions,
|
||||
ShadowOptions,
|
||||
CompositionOptions,
|
||||
Transform2D<f32>,
|
||||
),
|
||||
UpdateImage(IpcSender<()>),
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue