mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
canvas: Fully stateless backend (#38214)
I think this simplifies canvas backends greatly. Before there were many (needless) hoops from abstract to concrete (backend) and back, now we can do most stuff on abstract types. Testing: Existing WPT tests Fixes: #38022 try run: https://github.com/sagudev/servo/actions/runs/16450978211 Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
86d8317460
commit
d39e701b46
6 changed files with 650 additions and 806 deletions
|
@ -2,6 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use std::borrow::ToOwned;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
@ -18,26 +20,24 @@ use ipc_channel::router::ROUTER;
|
|||
use log::warn;
|
||||
use net_traits::ResourceThreads;
|
||||
use pixels::Snapshot;
|
||||
use style::color::AbsoluteColor;
|
||||
use style::properties::style_structs::Font as FontStyleStruct;
|
||||
use webrender_api::ImageKey;
|
||||
|
||||
use crate::canvas_data::*;
|
||||
use crate::raqote_backend::RaqoteBackend;
|
||||
|
||||
pub struct CanvasPaintThread<'a> {
|
||||
canvases: HashMap<CanvasId, Canvas<'a>>,
|
||||
pub struct CanvasPaintThread {
|
||||
canvases: HashMap<CanvasId, Canvas>,
|
||||
next_canvas_id: CanvasId,
|
||||
compositor_api: CrossProcessCompositorApi,
|
||||
font_context: Arc<FontContext>,
|
||||
}
|
||||
|
||||
impl<'a> CanvasPaintThread<'a> {
|
||||
impl CanvasPaintThread {
|
||||
fn new(
|
||||
compositor_api: CrossProcessCompositorApi,
|
||||
system_font_service: Arc<SystemFontServiceProxy>,
|
||||
resource_threads: ResourceThreads,
|
||||
) -> CanvasPaintThread<'a> {
|
||||
) -> CanvasPaintThread {
|
||||
CanvasPaintThread {
|
||||
canvases: HashMap::new(),
|
||||
next_canvas_id: CanvasId(0),
|
||||
|
@ -146,21 +146,27 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
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);
|
||||
self.canvas(canvas_id).fill_text(
|
||||
text,
|
||||
x,
|
||||
y,
|
||||
max_width,
|
||||
is_rtl,
|
||||
style,
|
||||
text_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
);
|
||||
},
|
||||
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);
|
||||
self.canvas(canvas_id).fill_rect(
|
||||
&rect,
|
||||
style,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
);
|
||||
},
|
||||
Canvas2dMsg::StrokeRect(
|
||||
rect,
|
||||
|
@ -170,25 +176,26 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
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);
|
||||
self.canvas(canvas_id).stroke_rect(
|
||||
&rect,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
);
|
||||
},
|
||||
Canvas2dMsg::ClearRect(ref rect, transform) => {
|
||||
self.canvas(canvas_id).set_transform(&transform);
|
||||
self.canvas(canvas_id).clear_rect(rect)
|
||||
self.canvas(canvas_id).clear_rect(rect, transform)
|
||||
},
|
||||
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);
|
||||
self.canvas(canvas_id).fill_path(
|
||||
&path,
|
||||
style,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
);
|
||||
},
|
||||
Canvas2dMsg::StrokePath(
|
||||
path,
|
||||
|
@ -198,18 +205,17 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
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);
|
||||
self.canvas(canvas_id).stroke_path(
|
||||
&path,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
);
|
||||
},
|
||||
Canvas2dMsg::ClipPath(path, transform) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_transform(&transform);
|
||||
canvas.clip_path(&path);
|
||||
self.canvas(canvas_id).clip_path(&path, transform);
|
||||
},
|
||||
Canvas2dMsg::DrawImage(
|
||||
snapshot,
|
||||
|
@ -219,18 +225,15 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
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,
|
||||
)
|
||||
},
|
||||
) => self.canvas(canvas_id).draw_image(
|
||||
snapshot.to_owned(),
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
Canvas2dMsg::DrawEmptyImage(
|
||||
image_size,
|
||||
dest_rect,
|
||||
|
@ -238,18 +241,15 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
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,
|
||||
)
|
||||
},
|
||||
) => self.canvas(canvas_id).draw_image(
|
||||
Snapshot::cleared(image_size),
|
||||
dest_rect,
|
||||
source_rect,
|
||||
false,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
Canvas2dMsg::DrawImageInOther(
|
||||
other_canvas_id,
|
||||
image_size,
|
||||
|
@ -263,20 +263,20 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
let snapshot = self
|
||||
.canvas(canvas_id)
|
||||
.read_pixels(Some(source_rect.to_u32()), Some(image_size));
|
||||
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);
|
||||
self.canvas(other_canvas_id).draw_image(
|
||||
snapshot,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
);
|
||||
},
|
||||
Canvas2dMsg::MeasureText(text, sender, text_options) => {
|
||||
let canvas = self.canvas(canvas_id);
|
||||
canvas.set_text_options(text_options);
|
||||
let metrics = canvas.measure_text(text);
|
||||
let metrics = self.canvas(canvas_id).measure_text(text, text_options);
|
||||
sender.send(metrics).unwrap();
|
||||
},
|
||||
Canvas2dMsg::RestoreContext => self.canvas(canvas_id).restore_context_state(),
|
||||
Canvas2dMsg::SaveContext => self.canvas(canvas_id).save_context_state(),
|
||||
Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender) => {
|
||||
let snapshot = self
|
||||
.canvas(canvas_id)
|
||||
|
@ -291,64 +291,130 @@ impl<'a> CanvasPaintThread<'a> {
|
|||
self.canvas(canvas_id).update_image_rendering();
|
||||
sender.send(()).unwrap();
|
||||
},
|
||||
Canvas2dMsg::PopClip => self.canvas(canvas_id).pop_clip(),
|
||||
}
|
||||
}
|
||||
|
||||
fn canvas(&mut self, canvas_id: CanvasId) -> &mut Canvas<'a> {
|
||||
fn canvas(&mut self, canvas_id: CanvasId) -> &mut Canvas {
|
||||
self.canvases.get_mut(&canvas_id).expect("Bogus canvas id")
|
||||
}
|
||||
}
|
||||
|
||||
enum Canvas<'a> {
|
||||
Raqote(CanvasData<'a, RaqoteBackend>),
|
||||
enum Canvas {
|
||||
Raqote(CanvasData<RaqoteBackend>),
|
||||
}
|
||||
|
||||
impl Canvas<'_> {
|
||||
fn set_fill_style(&mut self, style: FillOrStrokeStyle) {
|
||||
impl Canvas {
|
||||
fn pop_clip(&mut self) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_fill_style(style),
|
||||
Canvas::Raqote(canvas_data) => canvas_data.pop_clip(),
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_text(&mut self, text: String, x: f64, y: f64, max_width: Option<f64>, is_rtl: bool) {
|
||||
fn fill_text(
|
||||
&mut self,
|
||||
text: String,
|
||||
x: f64,
|
||||
y: f64,
|
||||
max_width: Option<f64>,
|
||||
is_rtl: bool,
|
||||
style: FillOrStrokeStyle,
|
||||
text_options: TextOptions,
|
||||
shadow_options: ShadowOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.fill_text(text, x, y, max_width, is_rtl),
|
||||
Canvas::Raqote(canvas_data) => canvas_data.fill_text(
|
||||
text,
|
||||
x,
|
||||
y,
|
||||
max_width,
|
||||
is_rtl,
|
||||
style,
|
||||
text_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_rect(&mut self, rect: &Rect<f32>) {
|
||||
fn fill_rect(
|
||||
&mut self,
|
||||
rect: &Rect<f32>,
|
||||
style: FillOrStrokeStyle,
|
||||
shadow_options: ShadowOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.fill_rect(rect),
|
||||
Canvas::Raqote(canvas_data) => {
|
||||
canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn set_stroke_style(&mut self, style: FillOrStrokeStyle) {
|
||||
fn stroke_rect(
|
||||
&mut self,
|
||||
rect: &Rect<f32>,
|
||||
style: FillOrStrokeStyle,
|
||||
line_options: LineOptions,
|
||||
shadow_options: ShadowOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_stroke_style(style),
|
||||
Canvas::Raqote(canvas_data) => canvas_data.stroke_rect(
|
||||
rect,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn stroke_rect(&mut self, rect: &Rect<f32>) {
|
||||
fn fill_path(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
style: FillOrStrokeStyle,
|
||||
shadow_options: ShadowOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.stroke_rect(rect),
|
||||
Canvas::Raqote(canvas_data) => {
|
||||
canvas_data.fill_path(path, style, shadow_options, composition_options, transform)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_path(&mut self, path: &Path) {
|
||||
fn stroke_path(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
style: FillOrStrokeStyle,
|
||||
line_options: LineOptions,
|
||||
shadow_options: ShadowOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.fill_path(path),
|
||||
Canvas::Raqote(canvas_data) => canvas_data.stroke_path(
|
||||
path,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn stroke_path(&mut self, path: &Path) {
|
||||
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.stroke_path(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_rect(&mut self, rect: &Rect<f32>) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.clear_rect(rect),
|
||||
Canvas::Raqote(canvas_data) => canvas_data.clear_rect(rect, transform),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,11 +424,20 @@ impl Canvas<'_> {
|
|||
dest_rect: Rect<f64>,
|
||||
source_rect: Rect<f64>,
|
||||
smoothing_enabled: bool,
|
||||
shadow_options: ShadowOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => {
|
||||
canvas_data.draw_image(snapshot, dest_rect, source_rect, smoothing_enabled)
|
||||
},
|
||||
Canvas::Raqote(canvas_data) => canvas_data.draw_image(
|
||||
snapshot,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,123 +451,15 @@ impl Canvas<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn restore_context_state(&mut self) {
|
||||
fn measure_text(&mut self, text: String, text_options: TextOptions) -> TextMetrics {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.restore_context_state(),
|
||||
Canvas::Raqote(canvas_data) => canvas_data.measure_text(text, text_options),
|
||||
}
|
||||
}
|
||||
|
||||
fn save_context_state(&mut self) {
|
||||
fn clip_path(&mut self, path: &Path, transform: Transform2D<f32>) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.save_context_state(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_line_width(&mut self, width: f32) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_line_width(width),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_line_cap(&mut self, cap: LineCapStyle) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_line_cap(cap),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_line_join(&mut self, join: LineJoinStyle) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_line_join(join),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_miter_limit(&mut self, limit: f32) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_miter_limit(limit),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_line_dash(&mut self, items: Vec<f32>) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_line_dash(items),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_line_dash_offset(&mut self, offset: f32) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_line_dash_offset(offset),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_transform(&mut self, matrix: &Transform2D<f32>) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_transform(matrix),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_global_alpha(&mut self, alpha: f32) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_global_alpha(alpha),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_global_composition(&mut self, op: CompositionOrBlending) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_global_composition(op),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_shadow_offset_x(&mut self, value: f64) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_shadow_offset_x(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_shadow_offset_y(&mut self, value: f64) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_shadow_offset_y(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_shadow_blur(&mut self, value: f64) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_shadow_blur(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_shadow_color(&mut self, color: AbsoluteColor) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_shadow_color(color),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_font(&mut self, font_style: FontStyleStruct) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_font(font_style),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_text_align(&mut self, text_align: TextAlign) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_text_align(text_align),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_text_baseline(&mut self, text_baseline: TextBaseline) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.set_text_baseline(text_baseline),
|
||||
}
|
||||
}
|
||||
|
||||
fn measure_text(&mut self, text: String) -> TextMetrics {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.measure_text(text),
|
||||
}
|
||||
}
|
||||
|
||||
fn clip_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
Canvas::Raqote(canvas_data) => canvas_data.clip_path(path),
|
||||
Canvas::Raqote(canvas_data) => canvas_data.clip_path(path, transform),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,41 +480,4 @@ 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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue