use std::sync::Arc;
use crate::content::graphics_state::{GraphicsState, Matrix};
use crate::fonts::FontInfo;
use crate::object::Object;
use smallvec::SmallVec;
#[derive(Clone, Copy)]
pub(crate) enum PaintKind<'a> {
ColorOnly,
Path {
path: &'a tiny_skia::Path,
fill_rule: tiny_skia::FillRule,
},
Glyph {
glyph_id: u16,
font: &'a Arc<FontInfo>,
advance_user: f32,
},
Image { xobj_name: &'a str },
Shading { shading_name: &'a str },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum PaintSide {
Fill,
Stroke,
}
pub(crate) enum LogicalColor<'a> {
Device(DeviceColor),
Spaced {
space: &'a Object,
components: SmallVec<[f32; 8]>,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum DeviceColor {
Gray(f32),
Rgb(f32, f32, f32),
Cmyk(f32, f32, f32, f32),
}
pub(crate) struct PaintIntent<'a> {
pub(crate) kind: PaintKind<'a>,
pub(crate) side: PaintSide,
pub(crate) gs: &'a GraphicsState,
pub(crate) color: LogicalColor<'a>,
pub(crate) ctm: Matrix,
}
#[cfg(test)]
mod tests {
use super::*;
use smallvec::smallvec;
#[test]
fn device_gray_round_trip() {
let c = DeviceColor::Gray(0.5);
assert_eq!(c, DeviceColor::Gray(0.5));
assert_ne!(c, DeviceColor::Gray(0.6));
}
#[test]
fn device_rgb_inequality_per_channel() {
let a = DeviceColor::Rgb(1.0, 0.0, 0.0);
let b = DeviceColor::Rgb(1.0, 0.0, 0.0);
let c = DeviceColor::Rgb(1.0, 0.5, 0.0);
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn device_cmyk_construction() {
let c = DeviceColor::Cmyk(0.1, 0.2, 0.3, 0.4);
let DeviceColor::Cmyk(c0, m0, y0, k0) = c else {
panic!("expected Cmyk variant");
};
assert!((c0 - 0.1).abs() < 1e-6);
assert!((m0 - 0.2).abs() < 1e-6);
assert!((y0 - 0.3).abs() < 1e-6);
assert!((k0 - 0.4).abs() < 1e-6);
}
#[test]
fn logical_color_spaced_holds_components_inline() {
let space = Object::Name("DeviceCMYK".to_string());
let comps: SmallVec<[f32; 8]> = smallvec![0.1, 0.2, 0.3, 0.4];
let lc = LogicalColor::Spaced {
space: &space,
components: comps,
};
match lc {
LogicalColor::Spaced { components, .. } => {
assert_eq!(components.len(), 4);
assert!(!components.spilled(), "≤8 components must stay inline");
},
_ => panic!("expected Spaced variant"),
}
}
#[test]
fn paint_side_is_two_valued() {
assert_ne!(PaintSide::Fill, PaintSide::Stroke);
}
}