render: Implement drawing lines using canvas
This patch provides an efficient implementation of draw_line and draw_line_rect for canvas using strokes.
This commit is contained in:
parent
2ba5e47b59
commit
d86d69f791
|
@ -35,6 +35,8 @@ pub struct WebCanvasRenderBackend {
|
|||
viewport_width: u32,
|
||||
viewport_height: u32,
|
||||
rect: Path2d,
|
||||
line: Path2d,
|
||||
line_rect: Path2d,
|
||||
mask_state: MaskState,
|
||||
blend_modes: Vec<RenderBlendMode>,
|
||||
|
||||
|
@ -294,6 +296,17 @@ impl WebCanvasRenderBackend {
|
|||
let rect = Path2d::new().into_js_result()?;
|
||||
rect.rect(0.0, 0.0, 1.0, 1.0);
|
||||
|
||||
let line = Path2d::new().into_js_result()?;
|
||||
line.move_to(0.0, 0.0);
|
||||
line.line_to(1.0, 0.0);
|
||||
|
||||
let line_rect = Path2d::new().into_js_result()?;
|
||||
line_rect.move_to(0.0, 0.0);
|
||||
line_rect.line_to(1.0, 0.0);
|
||||
line_rect.line_to(1.0, 1.0);
|
||||
line_rect.line_to(0.0, 1.0);
|
||||
line_rect.close_path();
|
||||
|
||||
let renderer = Self {
|
||||
canvas: canvas.clone(),
|
||||
color_matrix,
|
||||
|
@ -302,6 +315,8 @@ impl WebCanvasRenderBackend {
|
|||
viewport_height: 0,
|
||||
viewport_scale_factor: 1.0,
|
||||
rect,
|
||||
line,
|
||||
line_rect,
|
||||
mask_state: MaskState::DrawContent,
|
||||
blend_modes: vec![RenderBlendMode::Builtin(BlendMode::Normal)],
|
||||
};
|
||||
|
@ -361,6 +376,23 @@ impl WebCanvasRenderBackend {
|
|||
self.context.set_global_alpha(1.0);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_line_style(&self, color: Color) {
|
||||
self.context.set_line_cap("butt");
|
||||
self.context.set_line_width(1.0);
|
||||
self.context.set_line_join("miter");
|
||||
self.context.set_stroke_style(
|
||||
&format!(
|
||||
"rgba({},{},{},{})",
|
||||
color.r,
|
||||
color.g,
|
||||
color.b,
|
||||
f32::from(color.a) / 255.0,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
fn apply_blend_mode(&mut self, blend: RenderBlendMode) {
|
||||
// TODO: Objects with a blend mode need to be rendered to an intermediate buffer first,
|
||||
// but for now we render each child directly to the canvas. This should look reasonable for most
|
||||
|
@ -428,6 +460,31 @@ impl WebCanvasRenderBackend {
|
|||
self.apply_blend_mode(current.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_lines(&mut self, color: Color, mut matrix: Matrix, rect: bool) {
|
||||
matrix.tx += Twips::HALF;
|
||||
matrix.ty += Twips::HALF;
|
||||
let dom_matrix = matrix.to_dom_matrix();
|
||||
let stroke = if rect { &self.line_rect } else { &self.line };
|
||||
match &self.mask_state {
|
||||
MaskState::DrawContent => {
|
||||
self.clear_color_filter();
|
||||
|
||||
// The transform needs to be applied to the path directly,
|
||||
// otherwise its thickness will also be transformed.
|
||||
let _ = self.context.reset_transform();
|
||||
let transformed_stroke = Path2d::new().expect("new Path2d");
|
||||
transformed_stroke.add_path_with_transformation(stroke, dom_matrix.unchecked_ref());
|
||||
|
||||
self.set_line_style(color);
|
||||
self.context.stroke_with_path(&transformed_stroke);
|
||||
}
|
||||
MaskState::DrawMask(mask_path) => {
|
||||
mask_path.add_path_with_transformation(stroke, dom_matrix.unchecked_ref());
|
||||
}
|
||||
MaskState::ClearMask => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderBackend for WebCanvasRenderBackend {
|
||||
|
@ -772,12 +829,12 @@ impl CommandHandler for WebCanvasRenderBackend {
|
|||
}
|
||||
}
|
||||
|
||||
fn draw_line(&mut self, _color: Color, _matrix: Matrix) {
|
||||
// TODO implement
|
||||
fn draw_line(&mut self, color: Color, matrix: Matrix) {
|
||||
self.draw_lines(color, matrix, false);
|
||||
}
|
||||
|
||||
fn draw_line_rect(&mut self, _color: Color, _matrix: Matrix) {
|
||||
// TODO implement
|
||||
fn draw_line_rect(&mut self, color: Color, matrix: Matrix) {
|
||||
self.draw_lines(color, matrix, true)
|
||||
}
|
||||
|
||||
fn push_mask(&mut self) {
|
||||
|
|
Loading…
Reference in New Issue