use crate::CacheKey;
use crate::color::Color;
use crate::pattern::Pattern;
use crate::util::hash128;
use crate::x_object::ImageXObject;
use kurbo::{BezPath, Cap, Join};
use smallvec::{SmallVec, smallvec};
#[derive(Debug, Clone)]
pub struct ClipPath {
pub path: BezPath,
pub fill: FillRule,
}
impl CacheKey for ClipPath {
fn cache_key(&self) -> u128 {
hash128(&(&self.path.to_svg(), &self.fill))
}
}
pub struct StencilImage<'a, 'b> {
pub(crate) paint: Paint<'a>,
pub(crate) image_xobject: ImageXObject<'b>,
}
impl<'a, 'b> StencilImage<'a, 'b> {
pub fn with_stencil(
&self,
func: impl FnOnce(LumaData, &Paint<'a>),
target_dimension: Option<(u32, u32)>,
) {
if let Some(luma) = self
.image_xobject
.decoded_object(target_dimension)
.and_then(|d| d.luma_data)
{
func(luma, &self.paint);
}
}
#[doc(hidden)]
pub fn width(&self) -> u32 {
self.image_xobject.width()
}
#[doc(hidden)]
pub fn height(&self) -> u32 {
self.image_xobject.height()
}
}
impl CacheKey for StencilImage<'_, '_> {
fn cache_key(&self) -> u128 {
self.image_xobject.cache_key()
}
}
pub struct RasterImage<'a>(pub(crate) ImageXObject<'a>);
impl RasterImage<'_> {
pub fn with_rgba(
&self,
func: impl FnOnce(RgbData, Option<LumaData>),
target_dimension: Option<(u32, u32)>,
) {
let decoded = self.0.decoded_object(target_dimension);
if let Some(decoded) = decoded
&& let Some(rgb) = decoded.rgb_data
{
func(rgb, decoded.luma_data);
}
}
pub fn with_device_cmyk(
&self,
func: impl FnOnce(CmykData, Option<LumaData>),
target_dimension: Option<(u32, u32)>,
) {
let decoded = self.0.decoded_object(target_dimension);
if let Some(decoded) = decoded
&& let Some(cmyk) = decoded.cmyk_data
{
func(cmyk, decoded.luma_data);
}
}
#[doc(hidden)]
pub fn width(&self) -> u32 {
self.0.width()
}
#[doc(hidden)]
pub fn height(&self) -> u32 {
self.0.height()
}
}
impl CacheKey for RasterImage<'_> {
fn cache_key(&self) -> u128 {
self.0.cache_key()
}
}
pub enum Image<'a, 'b> {
Stencil(StencilImage<'a, 'b>),
Raster(RasterImage<'b>),
}
impl Image<'_, '_> {
#[doc(hidden)]
pub fn width(&self) -> u32 {
match self {
Image::Stencil(s) => s.width(),
Image::Raster(r) => r.width(),
}
}
#[doc(hidden)]
pub fn height(&self) -> u32 {
match self {
Image::Stencil(s) => s.height(),
Image::Raster(r) => r.height(),
}
}
}
impl CacheKey for Image<'_, '_> {
fn cache_key(&self) -> u128 {
match self {
Image::Stencil(i) => i.cache_key(),
Image::Raster(i) => i.cache_key(),
}
}
}
#[derive(Clone)]
pub struct RgbData {
pub data: Vec<u8>,
pub width: u32,
pub height: u32,
pub interpolate: bool,
pub scale_factors: (f32, f32),
}
#[derive(Clone)]
pub struct CmykData {
pub data: Vec<u8>,
pub width: u32,
pub height: u32,
pub interpolate: bool,
pub scale_factors: (f32, f32),
}
#[derive(Clone)]
pub struct LumaData {
pub data: Vec<u8>,
pub width: u32,
pub height: u32,
pub interpolate: bool,
pub scale_factors: (f32, f32),
}
#[derive(Clone, Debug)]
pub enum Paint<'a> {
Color(Color),
Pattern(Box<Pattern<'a>>),
}
impl CacheKey for Paint<'_> {
fn cache_key(&self) -> u128 {
match self {
Paint::Color(c) => {
hash128(&c.to_rgba().to_rgba8())
}
Paint::Pattern(p) => p.cache_key(),
}
}
}
#[derive(Clone, Debug)]
pub enum PathDrawMode {
Fill(FillRule),
Stroke(StrokeProps),
}
#[derive(Clone, Debug)]
pub enum GlyphDrawMode {
Fill,
Stroke(StrokeProps),
Invisible,
}
#[derive(Clone, Debug)]
pub struct StrokeProps {
pub line_width: f32,
pub line_cap: Cap,
pub line_join: Join,
pub miter_limit: f32,
pub dash_array: SmallVec<[f32; 4]>,
pub dash_offset: f32,
}
impl Default for StrokeProps {
fn default() -> Self {
Self {
line_width: 1.0,
line_cap: Cap::Butt,
line_join: Join::Miter,
miter_limit: 10.0,
dash_array: smallvec![],
dash_offset: 0.0,
}
}
}
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
pub enum FillRule {
NonZero,
EvenOdd,
}
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq, Default)]
pub enum BlendMode {
#[default]
Normal,
Multiply,
Screen,
Overlay,
Darken,
Lighten,
ColorDodge,
ColorBurn,
HardLight,
SoftLight,
Difference,
Exclusion,
Hue,
Saturation,
Color,
Luminosity,
}