use std::hash::Hash;
use std::sync::Arc;
use pdf_writer::types::BlendMode;
use pdf_writer::{Chunk, Finish, Name, Ref};
use crate::chunk_container::ChunkContainerFn;
use crate::configure::ValidationError;
use crate::geom::{Rect, Transform};
use crate::graphics::mask::Mask;
use crate::num::NormalizedF32;
use crate::resource;
use crate::resource::Resourceable;
use crate::serialize::{Cacheable, SerializeContext};
use crate::util::Deferred;
#[derive(Debug, Hash, PartialEq, Eq, Default, Clone)]
struct Repr {
non_stroking_alpha: Option<NormalizedF32>,
stroking_alpha: Option<NormalizedF32>,
blend_mode: Option<BlendMode>,
mask: Option<Ref>,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)]
pub(crate) struct ExtGState(Arc<Repr>);
impl ExtGState {
pub(crate) fn new() -> Self {
Self::default()
}
#[must_use]
pub(crate) fn stroking_alpha(mut self, stroking_alpha: NormalizedF32) -> Self {
Arc::make_mut(&mut self.0).stroking_alpha = Some(stroking_alpha);
self
}
#[must_use]
pub(crate) fn non_stroking_alpha(mut self, non_stroking_alpha: NormalizedF32) -> Self {
Arc::make_mut(&mut self.0).non_stroking_alpha = Some(non_stroking_alpha);
self
}
#[must_use]
pub(crate) fn blend_mode(mut self, blend_mode: BlendMode) -> Self {
Arc::make_mut(&mut self.0).blend_mode = Some(blend_mode);
self
}
#[must_use]
pub(crate) fn mask(mut self, mask: Mask, sc: &mut SerializeContext) -> Self {
let mask_ref = sc.register_cacheable(mask);
Arc::make_mut(&mut self.0).mask = Some(mask_ref);
self
}
pub(crate) fn empty(&self) -> bool {
self.0.mask.is_none()
&& self.0.stroking_alpha.is_none()
&& self.0.non_stroking_alpha.is_none()
&& self.0.blend_mode.is_none()
}
pub(crate) fn combine(&mut self, other: &ExtGState) {
if let Some(stroking_alpha) = other.0.stroking_alpha {
Arc::make_mut(&mut self.0).stroking_alpha = Some(stroking_alpha);
}
if let Some(non_stroking_alpha) = other.0.non_stroking_alpha {
Arc::make_mut(&mut self.0).non_stroking_alpha = Some(non_stroking_alpha);
}
if let Some(blend_mode) = other.0.blend_mode {
Arc::make_mut(&mut self.0).blend_mode = Some(blend_mode);
}
if let Some(mask) = other.0.mask {
Arc::make_mut(&mut self.0).mask = Some(mask);
}
}
}
impl Cacheable for ExtGState {
fn chunk_container(&self) -> ChunkContainerFn {
|cc| &mut cc.ext_g_states
}
fn serialize(self, sc: &mut SerializeContext, root_ref: Ref) -> Deferred<Chunk> {
let mut chunk = Chunk::new();
let mut ext_st = chunk.ext_graphics(root_ref);
if let Some(nsa) = self.0.non_stroking_alpha {
if nsa != NormalizedF32::ONE {
sc.register_validation_error(ValidationError::Transparency(sc.location));
}
ext_st.non_stroking_alpha(nsa.get());
}
if let Some(sa) = self.0.stroking_alpha {
if sa != NormalizedF32::ONE {
sc.register_validation_error(ValidationError::Transparency(sc.location));
}
ext_st.stroking_alpha(sa.get());
}
if let Some(bm) = self.0.blend_mode {
if bm != BlendMode::Normal {
sc.register_validation_error(ValidationError::Transparency(sc.location));
}
ext_st.blend_mode(bm);
}
if let Some(mask_ref) = self.0.mask {
sc.register_validation_error(ValidationError::Transparency(sc.location));
ext_st.pair(Name(b"SMask"), mask_ref);
}
ext_st.finish();
Deferred::new(|| chunk)
}
}
impl Resourceable for ExtGState {
type Resource = resource::ExtGState;
}
#[derive(Debug, PartialEq, Clone)]
pub(crate) struct GraphicsState {
ext_g_state: ExtGState,
ctm: Transform,
}
impl Eq for GraphicsState {}
impl Hash for GraphicsState {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ext_g_state.hash(state);
self.ctm.hash(state);
}
}
impl Default for GraphicsState {
fn default() -> Self {
Self {
ext_g_state: ExtGState::new(),
ctm: Transform::identity(),
}
}
}
impl GraphicsState {
pub(crate) fn combine(&mut self, other: &ExtGState) {
self.ext_g_state.combine(other);
}
pub(crate) fn concat_transform(&mut self, transform: Transform) {
self.ctm = self.ctm.pre_concat(transform);
}
pub(crate) fn transform(&self) -> Transform {
self.ctm
}
pub(crate) fn ext_g_state(&self) -> &ExtGState {
&self.ext_g_state
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct GraphicsStates {
graphics_states: Vec<GraphicsState>,
}
impl GraphicsStates {
pub(crate) fn new() -> Self {
GraphicsStates {
graphics_states: vec![GraphicsState::default()],
}
}
pub(crate) fn cur(&self) -> &GraphicsState {
self.graphics_states.last().unwrap()
}
pub(crate) fn cur_mut(&mut self) -> &mut GraphicsState {
self.graphics_states.last_mut().unwrap()
}
pub(crate) fn save_state(&mut self) {
let state = self.cur();
self.graphics_states.push(state.clone())
}
pub(crate) fn restore_state(&mut self) {
self.graphics_states.pop();
}
pub(crate) fn combine(&mut self, other: &ExtGState) {
self.cur_mut().combine(other);
}
pub(crate) fn transform(&mut self, transform: Transform) {
self.cur_mut().concat_transform(transform);
}
pub(crate) fn transform_bbox(&self, bbox: Rect) -> Rect {
bbox.transform(self.cur().transform()).unwrap()
}
}