use crate::renderer::RenderContext;
use crate::utils::{DirtyRegion, RenderError};
#[cfg(feature = "analysis-integration")]
use ass_core::analysis::ScriptAnalysis;
use ass_core::parser::{Event, Script};
use smallvec::SmallVec;
#[cfg(feature = "nostd")]
use alloc::{string::String, vec::Vec};
#[cfg(not(feature = "nostd"))]
use std::{string::String, vec::Vec};
pub mod animation;
pub mod compositing;
pub mod drawing;
pub mod font_loader;
pub mod shaping;
pub mod tag_processor;
pub mod text_segmenter;
pub mod transform;
pub mod validation;
mod build;
pub use build::SoftwarePipeline;
pub trait Pipeline: Send + Sync {
fn prepare_script(
&mut self,
script: &Script,
#[cfg(feature = "analysis-integration")] analysis: Option<&ScriptAnalysis>,
#[cfg(not(feature = "analysis-integration"))] _analysis: Option<()>,
) -> Result<(), RenderError>;
fn script(&self) -> Option<&Script<'_>>;
fn process_events(
&mut self,
events: &[&Event],
time_cs: u32,
context: &RenderContext,
) -> Result<Vec<IntermediateLayer>, RenderError>;
fn compute_dirty_regions(
&self,
events: &[&Event],
time_cs: u32,
prev_time_cs: u32,
) -> Result<Vec<DirtyRegion>, RenderError>;
}
#[derive(Debug, Clone, Copy)]
pub enum PipelineStage {
Shaping,
Drawing,
Effects,
Compositing,
}
pub enum IntermediateLayer {
Raster(RasterData),
Vector(VectorData),
Text(TextData),
}
impl IntermediateLayer {
pub fn intersects_region(&self, region: &DirtyRegion) -> bool {
match self {
Self::Raster(data) => {
let layer_bounds = (data.x, data.y, data.x + data.width, data.y + data.height);
region.intersects(layer_bounds)
}
Self::Vector(data) => {
if let Some(bounds) = &data.bounds {
region.intersects(*bounds)
} else {
true
}
}
Self::Text(data) => {
let approx_bounds = (
data.x as u32,
data.y as u32,
(data.x + 200.0) as u32,
(data.y + data.font_size * 1.5) as u32,
);
region.intersects(approx_bounds)
}
}
}
}
pub struct RasterData {
pub pixels: Vec<u8>,
pub x: u32,
pub y: u32,
pub width: u32,
pub height: u32,
pub opacity: u8,
}
pub struct VectorData {
pub path: Option<tiny_skia::Path>,
pub color: [u8; 4],
pub stroke: Option<StrokeInfo>,
pub bounds: Option<(u32, u32, u32, u32)>,
pub clip: Option<(f32, f32, f32, f32, bool)>,
pub blur: f32,
}
pub struct StrokeInfo {
pub color: [u8; 4],
pub width: f32,
}
pub struct TextData {
pub text: String,
pub font_family: String,
pub font_size: f32,
pub color: [u8; 4],
pub x: f32,
pub y: f32,
pub effects: SmallVec<[TextEffect; 4]>,
pub spacing: f32,
}
#[derive(Clone, Debug)]
pub enum TextEffect {
Bold,
Italic,
Underline,
Strikethrough,
Outline {
color: [u8; 4],
width_x: f32,
width_y: f32,
},
Shadow {
color: [u8; 4],
x_offset: f32,
y_offset: f32,
},
Blur { radius: f32 },
EdgeBlur { radius: f32 },
Karaoke {
progress: f32,
style: u8,
secondary: [u8; 4],
},
Rotation {
x: f32,
y: f32,
z: f32,
origin: Option<(f32, f32)>,
},
Shear { x: f32, y: f32 },
Scale { x: f32, y: f32 },
Clip {
x1: f32,
y1: f32,
x2: f32,
y2: f32,
inverse: bool,
},
OpaqueBox {
color: [u8; 4],
padding_x: f32,
padding_y: f32,
},
}