use std::borrow::Cow;
use kurbo::{Affine, Point, Rect, Shape};
use crate::{
Color, Error, FixedGradient, FixedLinearGradient, FixedRadialGradient, Image, LinearGradient,
RadialGradient, StrokeStyle, Text, TextLayout,
};
#[derive(Clone, Copy, PartialEq)]
pub enum InterpolationMode {
NearestNeighbor,
Bilinear,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive]
pub enum ImageFormat {
Grayscale,
Rgb,
RgbaSeparate,
RgbaPremul,
}
impl ImageFormat {
pub fn bytes_per_pixel(self) -> usize {
match self {
ImageFormat::Grayscale => 1,
ImageFormat::Rgb => 3,
ImageFormat::RgbaPremul | ImageFormat::RgbaSeparate => 4,
}
}
}
pub trait RenderContext
where
Self::Brush: IntoBrush<Self>,
{
type Brush: Clone;
type Text: Text<TextLayout = Self::TextLayout>;
type TextLayout: TextLayout;
type Image: Image;
fn status(&mut self) -> Result<(), Error>;
fn solid_brush(&mut self, color: Color) -> Self::Brush;
fn gradient(&mut self, gradient: impl Into<FixedGradient>) -> Result<Self::Brush, Error>;
fn clear(&mut self, color: Color);
fn stroke(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>, width: f64);
fn stroke_styled(
&mut self,
shape: impl Shape,
brush: &impl IntoBrush<Self>,
width: f64,
style: &StrokeStyle,
);
fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>);
fn fill_even_odd(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>);
fn clip(&mut self, shape: impl Shape);
fn text(&mut self) -> &mut Self::Text;
fn draw_text(&mut self, layout: &Self::TextLayout, pos: impl Into<Point>);
fn save(&mut self) -> Result<(), Error>;
fn restore(&mut self) -> Result<(), Error>;
fn with_save(&mut self, f: impl FnOnce(&mut Self) -> Result<(), Error>) -> Result<(), Error> {
self.save()?;
f(self).and(self.restore())
}
fn finish(&mut self) -> Result<(), Error>;
fn transform(&mut self, transform: Affine);
fn make_image(
&mut self,
width: usize,
height: usize,
buf: &[u8],
format: ImageFormat,
) -> Result<Self::Image, Error>;
fn draw_image(
&mut self,
image: &Self::Image,
dst_rect: impl Into<Rect>,
interp: InterpolationMode,
);
fn draw_image_area(
&mut self,
image: &Self::Image,
src_rect: impl Into<Rect>,
dst_rect: impl Into<Rect>,
interp: InterpolationMode,
);
fn blurred_rect(&mut self, rect: Rect, blur_radius: f64, brush: &impl IntoBrush<Self>);
fn current_transform(&self) -> Affine;
}
pub trait IntoBrush<P: RenderContext>
where
P: ?Sized,
{
fn make_brush<'a>(&'a self, piet: &mut P, bbox: impl FnOnce() -> Rect) -> Cow<'a, P::Brush>;
}
impl<P: RenderContext> IntoBrush<P> for Color {
fn make_brush<'a>(&'a self, piet: &mut P, _bbox: impl FnOnce() -> Rect) -> Cow<'a, P::Brush> {
Cow::Owned(piet.solid_brush(self.to_owned()))
}
}
#[derive(Debug, Clone)]
pub enum PaintBrush {
Color(Color),
Linear(LinearGradient),
Radial(RadialGradient),
Fixed(FixedGradient),
}
impl<P: RenderContext> IntoBrush<P> for PaintBrush {
fn make_brush<'a>(&'a self, piet: &mut P, bbox: impl FnOnce() -> Rect) -> Cow<'a, P::Brush> {
match self {
PaintBrush::Color(color) => color.make_brush(piet, bbox),
PaintBrush::Linear(linear) => linear.make_brush(piet, bbox),
PaintBrush::Radial(radial) => radial.make_brush(piet, bbox),
PaintBrush::Fixed(fixed) => fixed.make_brush(piet, bbox),
}
}
}
impl From<Color> for PaintBrush {
fn from(src: Color) -> PaintBrush {
PaintBrush::Color(src)
}
}
impl From<LinearGradient> for PaintBrush {
fn from(src: LinearGradient) -> PaintBrush {
PaintBrush::Linear(src)
}
}
impl From<RadialGradient> for PaintBrush {
fn from(src: RadialGradient) -> PaintBrush {
PaintBrush::Radial(src)
}
}
impl From<FixedGradient> for PaintBrush {
fn from(src: FixedGradient) -> PaintBrush {
PaintBrush::Fixed(src)
}
}
impl From<FixedLinearGradient> for PaintBrush {
fn from(src: FixedLinearGradient) -> PaintBrush {
PaintBrush::Fixed(src.into())
}
}
impl From<FixedRadialGradient> for PaintBrush {
fn from(src: FixedRadialGradient) -> PaintBrush {
PaintBrush::Fixed(src.into())
}
}