use strict_num::PositiveF32;
use svgrtypes::AspectRatio;
use crate::{
BlendMode, Color, Group, ImageRendering, NonEmptyString, NonZeroF32, NonZeroRect, Opacity,
};
#[derive(Debug)]
pub struct Filter {
pub(crate) id: NonEmptyString,
pub(crate) rect: NonZeroRect,
pub(crate) primitives: Vec<Primitive>,
}
impl std::hash::Hash for Filter {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
use crate::hashers::CustomHash;
self.id.hash(state);
self.rect.custom_hash(state);
self.primitives.hash(state);
}
}
impl Filter {
pub fn id(&self) -> &str {
self.id.get()
}
pub fn rect(&self) -> NonZeroRect {
self.rect
}
pub fn primitives(&self) -> &[Primitive] {
&self.primitives
}
}
#[derive(Clone, Debug)]
pub struct Primitive {
pub(crate) rect: NonZeroRect,
pub(crate) color_interpolation: ColorInterpolation,
pub(crate) result: String,
pub(crate) kind: Kind,
}
impl std::hash::Hash for Primitive {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
use crate::hashers::CustomHash;
self.rect.custom_hash(state);
self.color_interpolation.hash(state);
self.result.hash(state);
self.kind.hash(state);
}
}
impl Primitive {
pub fn rect(&self) -> NonZeroRect {
self.rect
}
pub fn color_interpolation(&self) -> ColorInterpolation {
self.color_interpolation
}
pub fn result(&self) -> &str {
&self.result
}
pub fn kind(&self) -> &Kind {
&self.kind
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug, Hash)]
pub enum Kind {
Blend(Blend),
ColorMatrix(ColorMatrix),
ComponentTransfer(ComponentTransfer),
Composite(Composite),
ConvolveMatrix(ConvolveMatrix),
DiffuseLighting(DiffuseLighting),
DisplacementMap(DisplacementMap),
DropShadow(DropShadow),
Flood(Flood),
GaussianBlur(GaussianBlur),
Image(Image),
Merge(Merge),
Morphology(Morphology),
Offset(Offset),
SpecularLighting(SpecularLighting),
Tile(Tile),
Turbulence(Turbulence),
}
impl Kind {
pub fn has_input(&self, input: &Input) -> bool {
match self {
Kind::Blend(ref fe) => fe.input1 == *input || fe.input2 == *input,
Kind::ColorMatrix(ref fe) => fe.input == *input,
Kind::ComponentTransfer(ref fe) => fe.input == *input,
Kind::Composite(ref fe) => fe.input1 == *input || fe.input2 == *input,
Kind::ConvolveMatrix(ref fe) => fe.input == *input,
Kind::DiffuseLighting(ref fe) => fe.input == *input,
Kind::DisplacementMap(ref fe) => fe.input1 == *input || fe.input2 == *input,
Kind::DropShadow(ref fe) => fe.input == *input,
Kind::Flood(_) => false,
Kind::GaussianBlur(ref fe) => fe.input == *input,
Kind::Image(_) => false,
Kind::Merge(ref fe) => fe.inputs.iter().any(|i| i == input),
Kind::Morphology(ref fe) => fe.input == *input,
Kind::Offset(ref fe) => fe.input == *input,
Kind::SpecularLighting(ref fe) => fe.input == *input,
Kind::Tile(ref fe) => fe.input == *input,
Kind::Turbulence(_) => false,
}
}
}
#[allow(missing_docs)]
#[derive(Clone, PartialEq, Debug, Hash)]
pub enum Input {
SourceGraphic,
SourceAlpha,
Reference(String),
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug, Hash, Eq)]
pub enum ColorInterpolation {
SRGB,
LinearRGB,
}
impl Default for ColorInterpolation {
fn default() -> Self {
ColorInterpolation::LinearRGB
}
}
#[derive(Clone, Debug, Hash)]
pub struct Blend {
pub(crate) input1: Input,
pub(crate) input2: Input,
pub(crate) mode: BlendMode,
}
impl Blend {
pub fn input1(&self) -> &Input {
&self.input1
}
pub fn input2(&self) -> &Input {
&self.input2
}
pub fn mode(&self) -> BlendMode {
self.mode
}
}
#[derive(Clone, Debug, Hash)]
pub struct ColorMatrix {
pub(crate) input: Input,
pub(crate) kind: ColorMatrixKind,
}
impl ColorMatrix {
pub fn input(&self) -> &Input {
&self.input
}
pub fn kind(&self) -> &ColorMatrixKind {
&self.kind
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub enum ColorMatrixKind {
Matrix(Vec<f32>), Saturate(PositiveF32),
HueRotate(f32),
LuminanceToAlpha,
}
impl std::hash::Hash for ColorMatrixKind {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
ColorMatrixKind::Matrix(m) => {
for v in m {
v.to_bits().hash(state);
}
}
ColorMatrixKind::Saturate(v) => {
v.get().to_bits().hash(state);
}
ColorMatrixKind::HueRotate(v) => {
v.to_bits().hash(state);
}
ColorMatrixKind::LuminanceToAlpha => {
0u8.hash(state);
}
}
}
}
impl Default for ColorMatrixKind {
fn default() -> Self {
ColorMatrixKind::Matrix(vec![
1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0,
])
}
}
#[derive(Clone, Debug, Hash)]
pub struct ComponentTransfer {
pub(crate) input: Input,
pub(crate) func_r: TransferFunction,
pub(crate) func_g: TransferFunction,
pub(crate) func_b: TransferFunction,
pub(crate) func_a: TransferFunction,
}
impl ComponentTransfer {
pub fn input(&self) -> &Input {
&self.input
}
pub fn func_r(&self) -> &TransferFunction {
&self.func_r
}
pub fn func_g(&self) -> &TransferFunction {
&self.func_g
}
pub fn func_b(&self) -> &TransferFunction {
&self.func_b
}
pub fn func_a(&self) -> &TransferFunction {
&self.func_a
}
}
#[derive(Clone, Debug)]
pub enum TransferFunction {
Identity,
Table(Vec<f32>),
Discrete(Vec<f32>),
#[allow(missing_docs)]
Linear { slope: f32, intercept: f32 },
#[allow(missing_docs)]
Gamma {
amplitude: f32,
exponent: f32,
offset: f32,
},
}
impl std::hash::Hash for TransferFunction {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
TransferFunction::Identity => 0.hash(state),
TransferFunction::Table(values) => {
1u8.hash(state);
values
.iter()
.map(|f| f.to_bits().hash(state))
.collect::<Vec<_>>()
.hash(state);
}
TransferFunction::Discrete(values) => {
2u8.hash(state);
values
.iter()
.map(|f| f.to_bits().hash(state))
.collect::<Vec<_>>()
.hash(state);
}
TransferFunction::Linear { slope, intercept } => {
3u8.hash(state);
slope.to_bits().hash(state);
intercept.to_bits().hash(state);
}
TransferFunction::Gamma {
amplitude,
exponent,
offset,
} => {
4u8.hash(state);
amplitude.to_bits().hash(state);
exponent.to_bits().hash(state);
offset.to_bits().hash(state);
}
}
}
}
#[derive(Clone, Debug, Hash)]
pub struct Composite {
pub(crate) input1: Input,
pub(crate) input2: Input,
pub(crate) operator: CompositeOperator,
}
impl Composite {
pub fn input1(&self) -> &Input {
&self.input1
}
pub fn input2(&self) -> &Input {
&self.input2
}
pub fn operator(&self) -> CompositeOperator {
self.operator
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum CompositeOperator {
Over,
In,
Out,
Atop,
Xor,
Arithmetic { k1: f32, k2: f32, k3: f32, k4: f32 },
}
impl std::hash::Hash for CompositeOperator {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
CompositeOperator::Over => {
0u8.hash(state);
}
CompositeOperator::In => {
1u8.hash(state);
}
CompositeOperator::Out => {
2u8.hash(state);
}
CompositeOperator::Atop => {
3u8.hash(state);
}
CompositeOperator::Xor => {
4u8.hash(state);
}
CompositeOperator::Arithmetic { k1, k2, k3, k4 } => {
5u8.hash(state);
k1.to_bits().hash(state);
k2.to_bits().hash(state);
k3.to_bits().hash(state);
k4.to_bits().hash(state);
}
}
}
}
#[derive(Clone, Debug)]
pub struct ConvolveMatrix {
pub(crate) input: Input,
pub(crate) matrix: ConvolveMatrixData,
pub(crate) divisor: NonZeroF32,
pub(crate) bias: f32,
pub(crate) edge_mode: EdgeMode,
pub(crate) preserve_alpha: bool,
}
impl std::hash::Hash for ConvolveMatrix {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.input.hash(state);
self.matrix.hash(state);
self.divisor.hash(state);
self.bias.to_bits().hash(state);
self.edge_mode.hash(state);
self.preserve_alpha.hash(state);
}
}
impl ConvolveMatrix {
pub fn input(&self) -> &Input {
&self.input
}
pub fn matrix(&self) -> &ConvolveMatrixData {
&self.matrix
}
pub fn divisor(&self) -> NonZeroF32 {
self.divisor
}
pub fn bias(&self) -> f32 {
self.bias
}
pub fn edge_mode(&self) -> EdgeMode {
self.edge_mode
}
pub fn preserve_alpha(&self) -> bool {
self.preserve_alpha
}
}
#[derive(Clone, Debug)]
pub struct ConvolveMatrixData {
pub(crate) target_x: u32,
pub(crate) target_y: u32,
pub(crate) columns: u32,
pub(crate) rows: u32,
pub(crate) data: Vec<f32>,
}
impl std::hash::Hash for ConvolveMatrixData {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.target_x.hash(state);
self.target_y.hash(state);
self.columns.hash(state);
self.rows.hash(state);
self.data
.iter()
.map(|f| f.to_bits())
.collect::<Vec<_>>()
.hash(state);
}
}
impl ConvolveMatrixData {
pub fn target_x(&self) -> u32 {
self.target_x
}
pub fn target_y(&self) -> u32 {
self.target_y
}
pub fn columns(&self) -> u32 {
self.columns
}
pub fn rows(&self) -> u32 {
self.rows
}
pub fn data(&self) -> &[f32] {
&self.data
}
}
impl ConvolveMatrixData {
pub(crate) fn new(
target_x: u32,
target_y: u32,
columns: u32,
rows: u32,
data: Vec<f32>,
) -> Option<Self> {
if (columns * rows) as usize != data.len() || target_x >= columns || target_y >= rows {
return None;
}
Some(ConvolveMatrixData {
target_x,
target_y,
columns,
rows,
data,
})
}
pub fn get(&self, x: u32, y: u32) -> f32 {
self.data[(y * self.columns + x) as usize]
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug, Hash, Eq)]
pub enum EdgeMode {
None,
Duplicate,
Wrap,
}
#[derive(Clone, Debug)]
pub struct DisplacementMap {
pub(crate) input1: Input,
pub(crate) input2: Input,
pub(crate) scale: f32,
pub(crate) x_channel_selector: ColorChannel,
pub(crate) y_channel_selector: ColorChannel,
}
impl std::hash::Hash for DisplacementMap {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.input1.hash(state);
self.input2.hash(state);
self.scale.to_bits().hash(state);
self.x_channel_selector.hash(state);
self.y_channel_selector.hash(state);
}
}
impl DisplacementMap {
pub fn input1(&self) -> &Input {
&self.input1
}
pub fn input2(&self) -> &Input {
&self.input2
}
pub fn scale(&self) -> f32 {
self.scale
}
pub fn x_channel_selector(&self) -> ColorChannel {
self.x_channel_selector
}
pub fn y_channel_selector(&self) -> ColorChannel {
self.y_channel_selector
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug, Hash, Eq)]
pub enum ColorChannel {
R,
G,
B,
A,
}
#[derive(Clone, Debug)]
pub struct DropShadow {
pub(crate) input: Input,
pub(crate) dx: f32,
pub(crate) dy: f32,
pub(crate) std_dev_x: PositiveF32,
pub(crate) std_dev_y: PositiveF32,
pub(crate) color: Color,
pub(crate) opacity: Opacity,
}
impl std::hash::Hash for DropShadow {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.input.hash(state);
self.dx.to_bits().hash(state);
self.dy.to_bits().hash(state);
self.std_dev_x.hash(state);
self.std_dev_y.hash(state);
self.color.hash(state);
self.opacity.hash(state);
}
}
impl DropShadow {
pub fn input(&self) -> &Input {
&self.input
}
pub fn dx(&self) -> f32 {
self.dx
}
pub fn dy(&self) -> f32 {
self.dy
}
pub fn std_dev_x(&self) -> PositiveF32 {
self.std_dev_x
}
pub fn std_dev_y(&self) -> PositiveF32 {
self.std_dev_y
}
pub fn color(&self) -> Color {
self.color
}
pub fn opacity(&self) -> Opacity {
self.opacity
}
}
#[derive(Clone, Copy, Debug, Hash)]
pub struct Flood {
pub(crate) color: Color,
pub(crate) opacity: Opacity,
}
impl Flood {
pub fn color(&self) -> Color {
self.color
}
pub fn opacity(&self) -> Opacity {
self.opacity
}
}
#[derive(Clone, Debug, Hash)]
pub struct GaussianBlur {
pub(crate) input: Input,
pub(crate) std_dev_x: PositiveF32,
pub(crate) std_dev_y: PositiveF32,
}
impl GaussianBlur {
pub fn input(&self) -> &Input {
&self.input
}
pub fn std_dev_x(&self) -> PositiveF32 {
self.std_dev_x
}
pub fn std_dev_y(&self) -> PositiveF32 {
self.std_dev_y
}
}
#[derive(Clone, Debug)]
pub struct Image {
pub(crate) original_href: Option<String>,
pub(crate) aspect: AspectRatio,
pub(crate) rendering_mode: ImageRendering,
pub(crate) data: ImageKind,
}
impl std::hash::Hash for Image {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.original_href.hash(state);
self.aspect.hash(state);
self.rendering_mode.hash(state);
}
}
impl Image {
pub fn aspect(&self) -> AspectRatio {
self.aspect
}
pub fn rendering_mode(&self) -> ImageRendering {
self.rendering_mode
}
pub fn data(&self) -> &ImageKind {
&self.data
}
}
#[derive(Clone, Debug)]
pub enum ImageKind {
Image(crate::ImageKind),
Use(Box<Group>),
}
#[derive(Clone, Debug)]
pub struct DiffuseLighting {
pub(crate) input: Input,
pub(crate) surface_scale: f32,
pub(crate) diffuse_constant: f32,
pub(crate) lighting_color: Color,
pub(crate) light_source: LightSource,
}
impl std::hash::Hash for DiffuseLighting {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.input.hash(state);
self.surface_scale.to_bits().hash(state);
self.diffuse_constant.to_bits().hash(state);
self.lighting_color.hash(state);
self.light_source.hash(state);
}
}
impl DiffuseLighting {
pub fn input(&self) -> &Input {
&self.input
}
pub fn surface_scale(&self) -> f32 {
self.surface_scale
}
pub fn diffuse_constant(&self) -> f32 {
self.diffuse_constant
}
pub fn lighting_color(&self) -> Color {
self.lighting_color
}
pub fn light_source(&self) -> LightSource {
self.light_source
}
}
#[derive(Clone, Debug)]
pub struct SpecularLighting {
pub(crate) input: Input,
pub(crate) surface_scale: f32,
pub(crate) specular_constant: f32,
pub(crate) specular_exponent: f32,
pub(crate) lighting_color: Color,
pub(crate) light_source: LightSource,
}
impl std::hash::Hash for SpecularLighting {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.input.hash(state);
self.surface_scale.to_bits().hash(state);
self.specular_constant.to_bits().hash(state);
self.specular_exponent.to_bits().hash(state);
self.lighting_color.hash(state);
self.light_source.hash(state);
}
}
impl SpecularLighting {
pub fn input(&self) -> &Input {
&self.input
}
pub fn surface_scale(&self) -> f32 {
self.surface_scale
}
pub fn specular_constant(&self) -> f32 {
self.specular_constant
}
pub fn specular_exponent(&self) -> f32 {
self.specular_exponent
}
pub fn lighting_color(&self) -> Color {
self.lighting_color
}
pub fn light_source(&self) -> LightSource {
self.light_source
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Hash)]
pub enum LightSource {
DistantLight(DistantLight),
PointLight(PointLight),
SpotLight(SpotLight),
}
#[derive(Clone, Copy, Debug)]
pub struct DistantLight {
pub azimuth: f32,
pub elevation: f32,
}
#[derive(Clone, Copy, Debug)]
pub struct PointLight {
pub x: f32,
pub y: f32,
pub z: f32,
}
#[derive(Clone, Copy, Debug)]
pub struct SpotLight {
pub x: f32,
pub y: f32,
pub z: f32,
pub points_at_x: f32,
pub points_at_y: f32,
pub points_at_z: f32,
pub specular_exponent: PositiveF32,
pub limiting_cone_angle: Option<f32>,
}
impl std::hash::Hash for DistantLight {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.azimuth.to_bits().hash(state);
self.elevation.to_bits().hash(state);
}
}
impl std::hash::Hash for PointLight {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.x.to_bits().hash(state);
self.y.to_bits().hash(state);
self.z.to_bits().hash(state);
}
}
impl std::hash::Hash for SpotLight {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.x.to_bits().hash(state);
self.y.to_bits().hash(state);
self.z.to_bits().hash(state);
self.points_at_x.to_bits().hash(state);
self.points_at_y.to_bits().hash(state);
self.points_at_z.to_bits().hash(state);
self.specular_exponent.hash(state);
self.limiting_cone_angle.map(|v| v.to_bits().hash(state));
}
}
#[derive(Clone, Debug, Hash)]
pub struct Merge {
pub(crate) inputs: Vec<Input>,
}
impl Merge {
pub fn inputs(&self) -> &[Input] {
&self.inputs
}
}
#[derive(Clone, Debug, Hash)]
pub struct Morphology {
pub(crate) input: Input,
pub(crate) operator: MorphologyOperator,
pub(crate) radius_x: PositiveF32,
pub(crate) radius_y: PositiveF32,
}
impl Morphology {
pub fn input(&self) -> &Input {
&self.input
}
pub fn operator(&self) -> MorphologyOperator {
self.operator
}
pub fn radius_x(&self) -> PositiveF32 {
self.radius_x
}
pub fn radius_y(&self) -> PositiveF32 {
self.radius_y
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug, Hash, Eq)]
pub enum MorphologyOperator {
Erode,
Dilate,
}
#[derive(Clone, Debug)]
pub struct Offset {
pub(crate) input: Input,
pub(crate) dx: f32,
pub(crate) dy: f32,
}
impl std::hash::Hash for Offset {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.input.hash(state);
self.dx.to_bits().hash(state);
self.dy.to_bits().hash(state);
}
}
impl Offset {
pub fn input(&self) -> &Input {
&self.input
}
pub fn dx(&self) -> f32 {
self.dx
}
pub fn dy(&self) -> f32 {
self.dy
}
}
#[derive(Clone, Debug, Hash)]
pub struct Tile {
pub(crate) input: Input,
}
impl Tile {
pub fn input(&self) -> &Input {
&self.input
}
}
#[derive(Clone, Copy, Debug, Hash)]
pub struct Turbulence {
pub(crate) base_frequency_x: PositiveF32,
pub(crate) base_frequency_y: PositiveF32,
pub(crate) num_octaves: u32,
pub(crate) seed: i32,
pub(crate) stitch_tiles: bool,
pub(crate) kind: TurbulenceKind,
}
impl Turbulence {
pub fn base_frequency_x(&self) -> PositiveF32 {
self.base_frequency_x
}
pub fn base_frequency_y(&self) -> PositiveF32 {
self.base_frequency_y
}
pub fn num_octaves(&self) -> u32 {
self.num_octaves
}
pub fn seed(&self) -> i32 {
self.seed
}
pub fn stitch_tiles(&self) -> bool {
self.stitch_tiles
}
pub fn kind(&self) -> TurbulenceKind {
self.kind
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug, Hash, Eq)]
pub enum TurbulenceKind {
FractalNoise,
Turbulence,
}