2020-05-21 16:36:25 +00:00
|
|
|
use crate::context::RenderContext;
|
2020-06-14 01:24:09 +00:00
|
|
|
use gc_arena::Collect;
|
2022-08-13 23:16:17 +00:00
|
|
|
use ruffle_render::backend::ShapeHandle;
|
2022-08-13 22:52:16 +00:00
|
|
|
use ruffle_render::bitmap::{BitmapInfo, BitmapSource};
|
2022-08-13 23:03:00 +00:00
|
|
|
use ruffle_render::bounding_box::BoundingBox;
|
2022-09-03 17:22:57 +00:00
|
|
|
use ruffle_render::commands::CommandHandler;
|
2022-08-13 23:05:38 +00:00
|
|
|
use ruffle_render::shape_utils::{DistilledShape, DrawCommand, DrawPath};
|
2020-05-21 16:36:25 +00:00
|
|
|
use std::cell::Cell;
|
2020-05-21 14:45:22 +00:00
|
|
|
use swf::{FillStyle, LineStyle, Twips};
|
2020-05-21 13:49:59 +00:00
|
|
|
|
2020-06-14 01:24:09 +00:00
|
|
|
#[derive(Clone, Debug, Collect)]
|
|
|
|
#[collect(require_static)]
|
2020-05-21 13:49:59 +00:00
|
|
|
pub struct Drawing {
|
2020-05-21 16:36:25 +00:00
|
|
|
render_handle: Cell<Option<ShapeHandle>>,
|
2020-05-21 13:49:59 +00:00
|
|
|
shape_bounds: BoundingBox,
|
|
|
|
edge_bounds: BoundingBox,
|
2020-05-21 16:36:25 +00:00
|
|
|
dirty: Cell<bool>,
|
2022-01-26 08:11:41 +00:00
|
|
|
paths: Vec<DrawingPath>,
|
2021-06-13 21:44:16 +00:00
|
|
|
bitmaps: Vec<BitmapInfo>,
|
2021-10-31 23:01:58 +00:00
|
|
|
current_fill: Option<DrawingFill>,
|
|
|
|
current_line: Option<DrawingLine>,
|
2022-01-26 07:04:01 +00:00
|
|
|
pending_lines: Vec<DrawingLine>,
|
2020-05-21 14:45:22 +00:00
|
|
|
cursor: (Twips, Twips),
|
2021-10-31 23:01:58 +00:00
|
|
|
fill_start: (Twips, Twips),
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
|
2021-02-27 02:09:27 +00:00
|
|
|
impl Default for Drawing {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-21 13:49:59 +00:00
|
|
|
impl Drawing {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
2020-05-21 16:36:25 +00:00
|
|
|
render_handle: Cell::new(None),
|
2020-05-21 13:49:59 +00:00
|
|
|
shape_bounds: BoundingBox::default(),
|
|
|
|
edge_bounds: BoundingBox::default(),
|
2020-05-21 16:36:25 +00:00
|
|
|
dirty: Cell::new(false),
|
2022-01-26 08:11:41 +00:00
|
|
|
paths: Vec::new(),
|
2021-06-13 21:44:16 +00:00
|
|
|
bitmaps: Vec::new(),
|
2020-05-21 13:49:59 +00:00
|
|
|
current_fill: None,
|
|
|
|
current_line: None,
|
2022-01-26 07:04:01 +00:00
|
|
|
pending_lines: Vec::new(),
|
2021-06-08 05:50:07 +00:00
|
|
|
cursor: (Twips::ZERO, Twips::ZERO),
|
2021-10-31 23:01:58 +00:00
|
|
|
fill_start: (Twips::ZERO, Twips::ZERO),
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-05 04:03:12 +00:00
|
|
|
pub fn from_swf_shape(shape: &swf::Shape) -> Self {
|
|
|
|
let mut this = Self {
|
|
|
|
render_handle: Cell::new(None),
|
2022-09-02 12:23:34 +00:00
|
|
|
shape_bounds: (&shape.shape_bounds).into(),
|
|
|
|
edge_bounds: (&shape.edge_bounds).into(),
|
2021-03-05 04:03:12 +00:00
|
|
|
dirty: Cell::new(true),
|
2022-01-26 08:11:41 +00:00
|
|
|
paths: Vec::new(),
|
2021-06-13 21:44:16 +00:00
|
|
|
bitmaps: Vec::new(),
|
2021-03-05 04:03:12 +00:00
|
|
|
current_fill: None,
|
|
|
|
current_line: None,
|
2022-01-26 07:04:01 +00:00
|
|
|
pending_lines: Vec::new(),
|
2021-06-08 05:50:07 +00:00
|
|
|
cursor: (Twips::ZERO, Twips::ZERO),
|
2021-10-31 23:01:58 +00:00
|
|
|
fill_start: (Twips::ZERO, Twips::ZERO),
|
2021-03-05 04:03:12 +00:00
|
|
|
};
|
|
|
|
|
2021-06-22 10:04:27 +00:00
|
|
|
let shape: DistilledShape = shape.into();
|
2021-03-05 04:03:12 +00:00
|
|
|
for path in shape.paths {
|
|
|
|
match path {
|
|
|
|
DrawPath::Stroke {
|
|
|
|
style,
|
|
|
|
is_closed: _,
|
|
|
|
commands,
|
|
|
|
} => {
|
|
|
|
this.set_line_style(Some(style.clone()));
|
|
|
|
|
|
|
|
for command in commands {
|
|
|
|
this.draw_command(command);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.set_line_style(None);
|
|
|
|
}
|
|
|
|
DrawPath::Fill { style, commands } => {
|
|
|
|
this.set_fill_style(Some(style.clone()));
|
|
|
|
|
|
|
|
for command in commands {
|
|
|
|
this.draw_command(command);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.set_fill_style(None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this
|
|
|
|
}
|
|
|
|
|
2020-05-21 13:49:59 +00:00
|
|
|
pub fn set_fill_style(&mut self, style: Option<FillStyle>) {
|
2021-10-31 23:01:58 +00:00
|
|
|
self.close_path();
|
2020-05-21 13:49:59 +00:00
|
|
|
if let Some(existing) = self.current_fill.take() {
|
2022-01-26 08:11:41 +00:00
|
|
|
self.paths.push(DrawingPath::Fill(existing));
|
|
|
|
}
|
|
|
|
self.paths
|
|
|
|
.extend(self.pending_lines.drain(..).map(DrawingPath::Line));
|
|
|
|
if let Some(mut existing) = self.current_line.take() {
|
|
|
|
existing.is_closed = self.cursor == self.fill_start;
|
|
|
|
let style = existing.style.clone();
|
|
|
|
self.paths.push(DrawingPath::Line(existing));
|
|
|
|
self.current_line = Some(DrawingLine {
|
|
|
|
style,
|
|
|
|
commands: vec![DrawCommand::MoveTo {
|
|
|
|
x: self.cursor.0,
|
|
|
|
y: self.cursor.1,
|
|
|
|
}],
|
|
|
|
is_closed: false,
|
|
|
|
});
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
if let Some(style) = style {
|
2021-10-31 23:01:58 +00:00
|
|
|
self.current_fill = Some(DrawingFill {
|
2020-05-21 14:45:22 +00:00
|
|
|
style,
|
2021-10-31 23:01:58 +00:00
|
|
|
commands: vec![DrawCommand::MoveTo {
|
2020-05-21 14:45:22 +00:00
|
|
|
x: self.cursor.0,
|
|
|
|
y: self.cursor.1,
|
|
|
|
}],
|
2021-10-31 23:01:58 +00:00
|
|
|
});
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
2021-10-31 23:01:58 +00:00
|
|
|
self.fill_start = self.cursor;
|
2020-05-21 16:36:25 +00:00
|
|
|
self.dirty.set(true);
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clear(&mut self) {
|
|
|
|
self.current_fill = None;
|
|
|
|
self.current_line = None;
|
2022-01-26 08:11:41 +00:00
|
|
|
self.pending_lines.clear();
|
|
|
|
self.paths.clear();
|
2021-06-13 21:44:16 +00:00
|
|
|
self.bitmaps.clear();
|
2020-05-21 13:49:59 +00:00
|
|
|
self.edge_bounds = BoundingBox::default();
|
|
|
|
self.shape_bounds = BoundingBox::default();
|
2020-05-21 16:36:25 +00:00
|
|
|
self.dirty.set(true);
|
2021-06-08 05:50:07 +00:00
|
|
|
self.cursor = (Twips::ZERO, Twips::ZERO);
|
2021-10-31 23:01:58 +00:00
|
|
|
self.fill_start = (Twips::ZERO, Twips::ZERO);
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_line_style(&mut self, style: Option<LineStyle>) {
|
2021-10-31 23:01:58 +00:00
|
|
|
if let Some(mut existing) = self.current_line.take() {
|
|
|
|
existing.is_closed = self.cursor == self.fill_start;
|
2022-01-26 08:11:41 +00:00
|
|
|
if self.current_fill.is_some() {
|
|
|
|
self.pending_lines.push(existing);
|
|
|
|
} else {
|
|
|
|
self.paths.push(DrawingPath::Line(existing));
|
|
|
|
}
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
if let Some(style) = style {
|
2021-10-31 23:01:58 +00:00
|
|
|
self.current_line = Some(DrawingLine {
|
2020-05-21 14:45:22 +00:00
|
|
|
style,
|
2021-10-31 23:01:58 +00:00
|
|
|
commands: vec![DrawCommand::MoveTo {
|
2020-05-21 14:45:22 +00:00
|
|
|
x: self.cursor.0,
|
|
|
|
y: self.cursor.1,
|
|
|
|
}],
|
2021-10-31 23:01:58 +00:00
|
|
|
is_closed: false,
|
|
|
|
});
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 16:36:25 +00:00
|
|
|
self.dirty.set(true);
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn draw_command(&mut self, command: DrawCommand) {
|
2022-01-02 02:21:24 +00:00
|
|
|
let add_to_bounds = if let DrawCommand::MoveTo { x, y } = command {
|
2021-10-31 23:01:58 +00:00
|
|
|
// Close any pending fills before moving.
|
|
|
|
self.close_path();
|
2022-01-02 02:21:24 +00:00
|
|
|
self.fill_start = (x, y);
|
2021-10-31 23:01:58 +00:00
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
};
|
|
|
|
|
|
|
|
// Add command to current fill.
|
|
|
|
if let Some(fill) = &mut self.current_fill {
|
|
|
|
fill.commands.push(command.clone());
|
|
|
|
}
|
|
|
|
// Add command to current line.
|
|
|
|
let stroke_width = if let Some(line) = &mut self.current_line {
|
|
|
|
line.commands.push(command.clone());
|
2022-04-09 18:17:40 +00:00
|
|
|
line.style.width()
|
2020-05-21 18:34:48 +00:00
|
|
|
} else {
|
2021-06-08 05:50:07 +00:00
|
|
|
Twips::ZERO
|
2020-05-21 18:34:48 +00:00
|
|
|
};
|
2020-05-21 13:49:59 +00:00
|
|
|
|
2021-10-31 23:01:58 +00:00
|
|
|
// Expand bounds.
|
|
|
|
if add_to_bounds {
|
|
|
|
if self.fill_start == self.cursor {
|
|
|
|
// If this is the initial command after a move, include the starting point.
|
|
|
|
let command = DrawCommand::MoveTo {
|
|
|
|
x: self.cursor.0,
|
|
|
|
y: self.cursor.1,
|
|
|
|
};
|
2020-05-21 18:34:48 +00:00
|
|
|
stretch_bounding_box(&mut self.shape_bounds, &command, stroke_width);
|
2021-06-08 05:50:07 +00:00
|
|
|
stretch_bounding_box(&mut self.edge_bounds, &command, Twips::ZERO);
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
2021-10-31 23:01:58 +00:00
|
|
|
stretch_bounding_box(&mut self.shape_bounds, &command, stroke_width);
|
|
|
|
stretch_bounding_box(&mut self.edge_bounds, &command, Twips::ZERO);
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 14:45:22 +00:00
|
|
|
self.cursor = command.end_point();
|
2020-05-21 16:36:25 +00:00
|
|
|
self.dirty.set(true);
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
|
2021-06-13 21:44:16 +00:00
|
|
|
pub fn add_bitmap(&mut self, bitmap: BitmapInfo) -> u16 {
|
|
|
|
let id = self.bitmaps.len() as u16;
|
|
|
|
self.bitmaps.push(bitmap);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
2021-06-14 01:31:28 +00:00
|
|
|
pub fn render(&self, context: &mut RenderContext) {
|
2020-05-21 16:36:25 +00:00
|
|
|
if self.dirty.get() {
|
|
|
|
self.dirty.set(false);
|
2022-01-26 08:11:41 +00:00
|
|
|
let mut paths = Vec::with_capacity(self.paths.len());
|
|
|
|
|
|
|
|
for path in &self.paths {
|
|
|
|
match path {
|
|
|
|
DrawingPath::Fill(fill) => {
|
|
|
|
paths.push(DrawPath::Fill {
|
|
|
|
style: &fill.style,
|
|
|
|
commands: fill.commands.to_owned(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
DrawingPath::Line(line) => {
|
|
|
|
paths.push(DrawPath::Stroke {
|
|
|
|
style: &line.style,
|
|
|
|
commands: line.commands.to_owned(),
|
|
|
|
is_closed: line.is_closed,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
|
2021-10-31 23:01:58 +00:00
|
|
|
if let Some(fill) = &self.current_fill {
|
2020-05-21 13:49:59 +00:00
|
|
|
paths.push(DrawPath::Fill {
|
2021-10-31 23:01:58 +00:00
|
|
|
style: &fill.style,
|
|
|
|
commands: fill.commands.to_owned(),
|
2020-05-21 13:49:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-01-26 08:11:41 +00:00
|
|
|
for line in &self.pending_lines {
|
|
|
|
let mut commands = line.commands.to_owned();
|
|
|
|
let is_closed = if self.current_fill.is_some() {
|
|
|
|
commands.push(DrawCommand::LineTo {
|
|
|
|
x: self.fill_start.0,
|
|
|
|
y: self.fill_start.1,
|
|
|
|
});
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
self.cursor == self.fill_start
|
|
|
|
};
|
2020-05-21 13:49:59 +00:00
|
|
|
paths.push(DrawPath::Stroke {
|
2021-10-31 23:01:58 +00:00
|
|
|
style: &line.style,
|
2022-01-26 08:11:41 +00:00
|
|
|
commands,
|
|
|
|
is_closed,
|
2020-05-21 13:49:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-10-31 23:01:58 +00:00
|
|
|
if let Some(line) = &self.current_line {
|
|
|
|
let mut commands = line.commands.to_owned();
|
|
|
|
let is_closed = if self.current_fill.is_some() {
|
|
|
|
commands.push(DrawCommand::LineTo {
|
|
|
|
x: self.fill_start.0,
|
|
|
|
y: self.fill_start.1,
|
|
|
|
});
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
self.cursor == self.fill_start
|
|
|
|
};
|
2020-05-21 13:49:59 +00:00
|
|
|
paths.push(DrawPath::Stroke {
|
2021-10-31 23:01:58 +00:00
|
|
|
style: &line.style,
|
|
|
|
commands,
|
|
|
|
is_closed,
|
2020-05-21 13:49:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
let shape = DistilledShape {
|
|
|
|
paths,
|
|
|
|
shape_bounds: self.shape_bounds.clone(),
|
2020-05-21 18:34:48 +00:00
|
|
|
edge_bounds: self.edge_bounds.clone(),
|
2020-05-21 13:49:59 +00:00
|
|
|
id: 0,
|
|
|
|
};
|
2020-05-21 16:36:25 +00:00
|
|
|
if let Some(handle) = self.render_handle.get() {
|
2021-06-13 21:44:16 +00:00
|
|
|
context.renderer.replace_shape(shape, self, handle);
|
2020-05-21 13:49:59 +00:00
|
|
|
} else {
|
2020-05-21 16:36:25 +00:00
|
|
|
self.render_handle
|
2021-06-13 21:44:16 +00:00
|
|
|
.set(Some(context.renderer.register_shape(shape, self)));
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-21 16:36:25 +00:00
|
|
|
if let Some(handle) = self.render_handle.get() {
|
2020-05-21 13:49:59 +00:00
|
|
|
context
|
2022-09-03 17:22:57 +00:00
|
|
|
.commands
|
2020-05-21 13:49:59 +00:00
|
|
|
.render_shape(handle, context.transform_stack.transform());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn self_bounds(&self) -> BoundingBox {
|
|
|
|
self.shape_bounds.clone()
|
|
|
|
}
|
2020-08-21 06:25:31 +00:00
|
|
|
|
2022-08-13 23:01:54 +00:00
|
|
|
pub fn hit_test(
|
|
|
|
&self,
|
|
|
|
point: (Twips, Twips),
|
|
|
|
local_matrix: &ruffle_render::matrix::Matrix,
|
|
|
|
) -> bool {
|
2022-08-13 23:05:38 +00:00
|
|
|
use ruffle_render::shape_utils;
|
2022-01-26 08:11:41 +00:00
|
|
|
for path in &self.paths {
|
|
|
|
match path {
|
|
|
|
DrawingPath::Fill(fill) => {
|
|
|
|
if shape_utils::draw_command_fill_hit_test(&fill.commands, point) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DrawingPath::Line(line) => {
|
|
|
|
if shape_utils::draw_command_stroke_hit_test(
|
|
|
|
&line.commands,
|
2022-04-09 18:17:40 +00:00
|
|
|
line.style.width(),
|
2022-01-26 08:11:41 +00:00
|
|
|
point,
|
|
|
|
local_matrix,
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2020-08-21 06:25:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 23:01:58 +00:00
|
|
|
// The pending fill will auto-close.
|
|
|
|
if let Some(fill) = &self.current_fill {
|
|
|
|
if shape_utils::draw_command_fill_hit_test(&fill.commands, point) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-26 07:04:01 +00:00
|
|
|
for line in &self.pending_lines {
|
|
|
|
if shape_utils::draw_command_stroke_hit_test(
|
|
|
|
&line.commands,
|
2022-04-09 18:17:40 +00:00
|
|
|
line.style.width(),
|
2022-01-26 07:04:01 +00:00
|
|
|
point,
|
|
|
|
local_matrix,
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 23:01:58 +00:00
|
|
|
if let Some(line) = &self.current_line {
|
|
|
|
if shape_utils::draw_command_stroke_hit_test(
|
|
|
|
&line.commands,
|
2022-04-09 18:17:40 +00:00
|
|
|
line.style.width(),
|
2021-10-31 23:01:58 +00:00
|
|
|
point,
|
|
|
|
local_matrix,
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stroke auto-closes if part of a fill; also check the closing line segment.
|
|
|
|
if self.current_fill.is_some()
|
|
|
|
&& self.cursor != self.fill_start
|
|
|
|
&& shape_utils::draw_command_stroke_hit_test(
|
|
|
|
&[
|
|
|
|
DrawCommand::MoveTo {
|
|
|
|
x: self.cursor.0,
|
|
|
|
y: self.cursor.1,
|
|
|
|
},
|
|
|
|
DrawCommand::LineTo {
|
|
|
|
x: self.fill_start.0,
|
|
|
|
y: self.fill_start.1,
|
|
|
|
},
|
|
|
|
],
|
2022-04-09 18:17:40 +00:00
|
|
|
line.style.width(),
|
2021-10-31 23:01:58 +00:00
|
|
|
point,
|
|
|
|
local_matrix,
|
|
|
|
)
|
2020-08-21 06:25:31 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
2021-10-31 23:01:58 +00:00
|
|
|
|
|
|
|
// Ensures that the path is closed for a pending fill.
|
|
|
|
fn close_path(&mut self) {
|
|
|
|
if let Some(fill) = &mut self.current_fill {
|
|
|
|
if self.cursor != self.fill_start {
|
|
|
|
fill.commands.push(DrawCommand::LineTo {
|
|
|
|
x: self.fill_start.0,
|
|
|
|
y: self.fill_start.1,
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(line) = &mut self.current_line {
|
|
|
|
line.commands.push(DrawCommand::LineTo {
|
|
|
|
x: self.fill_start.0,
|
|
|
|
y: self.fill_start.1,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
self.dirty.set(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-21 13:49:59 +00:00
|
|
|
}
|
2020-05-21 16:20:27 +00:00
|
|
|
|
2021-06-13 21:44:16 +00:00
|
|
|
impl BitmapSource for Drawing {
|
|
|
|
fn bitmap(&self, id: u16) -> Option<BitmapInfo> {
|
|
|
|
self.bitmaps.get(id as usize).cloned()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 23:01:58 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
struct DrawingFill {
|
|
|
|
style: FillStyle,
|
|
|
|
commands: Vec<DrawCommand>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
struct DrawingLine {
|
|
|
|
style: LineStyle,
|
|
|
|
commands: Vec<DrawCommand>,
|
|
|
|
is_closed: bool,
|
|
|
|
}
|
|
|
|
|
2022-01-26 08:11:41 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
enum DrawingPath {
|
|
|
|
Fill(DrawingFill),
|
|
|
|
Line(DrawingLine),
|
|
|
|
}
|
|
|
|
|
2020-05-21 18:34:48 +00:00
|
|
|
fn stretch_bounding_box(
|
|
|
|
bounding_box: &mut BoundingBox,
|
|
|
|
command: &DrawCommand,
|
|
|
|
stroke_width: Twips,
|
|
|
|
) {
|
|
|
|
let radius = stroke_width / 2;
|
2020-05-21 16:20:27 +00:00
|
|
|
match *command {
|
|
|
|
DrawCommand::MoveTo { x, y } => {
|
2020-05-21 18:34:48 +00:00
|
|
|
bounding_box.encompass(x - radius, y - radius);
|
|
|
|
bounding_box.encompass(x + radius, y + radius);
|
2020-05-21 16:20:27 +00:00
|
|
|
}
|
|
|
|
DrawCommand::LineTo { x, y } => {
|
2020-05-21 18:34:48 +00:00
|
|
|
bounding_box.encompass(x - radius, y - radius);
|
|
|
|
bounding_box.encompass(x + radius, y + radius);
|
2020-05-21 16:20:27 +00:00
|
|
|
}
|
|
|
|
DrawCommand::CurveTo { x1, y1, x2, y2 } => {
|
2020-05-21 18:34:48 +00:00
|
|
|
bounding_box.encompass(x1 - radius, y1 - radius);
|
|
|
|
bounding_box.encompass(x1 + radius, y1 + radius);
|
|
|
|
bounding_box.encompass(x2 - radius, y2 - radius);
|
|
|
|
bounding_box.encompass(x2 + radius, y2 + radius);
|
2020-05-21 16:20:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|