use crate::error::Result;
use super::resolved::ResolvedPaintCmd;
pub(crate) trait PaintBackend {
type Surface<'s>
where
Self: 's;
fn begin_page(&mut self, _page_width_px: u32, _page_height_px: u32) -> Result<()> {
Ok(())
}
fn paint(&mut self, cmd: &ResolvedPaintCmd, surface: Self::Surface<'_>) -> Result<()>;
fn end_page(&mut self) -> Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::content::graphics_state::Matrix;
use smallvec::SmallVec;
use super::super::intent::{PaintKind, PaintSide};
use super::super::resolved::{BlendPlan, ClipPlan, InkSelector, OverprintPlan, ResolvedColor};
struct RecordingBackend {
begin_calls: Vec<(u32, u32)>,
paint_calls: usize,
end_calls: usize,
}
impl PaintBackend for RecordingBackend {
type Surface<'s> = &'s mut ();
fn begin_page(&mut self, w: u32, h: u32) -> Result<()> {
self.begin_calls.push((w, h));
Ok(())
}
fn paint(&mut self, _cmd: &ResolvedPaintCmd, _surface: Self::Surface<'_>) -> Result<()> {
self.paint_calls += 1;
Ok(())
}
fn end_page(&mut self) -> Result<()> {
self.end_calls += 1;
Ok(())
}
}
fn dummy_cmd() -> ResolvedPaintCmd<'static> {
ResolvedPaintCmd {
kind: PaintKind::Shading {
shading_name: "DummyShading",
},
side: PaintSide::Fill,
color: ResolvedColor::Rgba {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
},
overprint: OverprintPlan {
enabled: false,
mode: 0,
participating: SmallVec::new(),
selector: InkSelector::Listed,
all_tint: 0.0,
spot_source: None,
alt_cmyk_fallback: None,
},
blend: BlendPlan::Native(tiny_skia::BlendMode::SourceOver),
clip: ClipPlan::None,
ctm: Matrix::identity(),
}
}
#[test]
fn trait_lifecycle_is_begin_paint_end() {
let mut backend = RecordingBackend {
begin_calls: Vec::new(),
paint_calls: 0,
end_calls: 0,
};
backend.begin_page(100, 200).unwrap();
let cmd = dummy_cmd();
let mut surface = ();
backend.paint(&cmd, &mut surface).unwrap();
backend.paint(&cmd, &mut surface).unwrap();
backend.end_page().unwrap();
assert_eq!(backend.begin_calls, vec![(100, 200)]);
assert_eq!(backend.paint_calls, 2);
assert_eq!(backend.end_calls, 1);
}
struct NoOpBackend;
impl PaintBackend for NoOpBackend {
type Surface<'s> = &'s mut ();
fn paint(&mut self, _cmd: &ResolvedPaintCmd, _surface: Self::Surface<'_>) -> Result<()> {
Ok(())
}
}
#[test]
fn default_begin_and_end_are_no_ops() {
let mut backend = NoOpBackend;
backend.begin_page(0, 0).unwrap();
let cmd = dummy_cmd();
let mut surface = ();
backend.paint(&cmd, &mut surface).unwrap();
backend.end_page().unwrap();
}
}