//! Layer (optional content) visibility: what the view shows and what printing writes. use std::sync::Arc; use pdfcraft_render::{Layer, LayerOp, RenderPool}; use crate::{Document, render_threads}; /// Write `layers`' visibility into the default optional-content configuration of `cos` (a copy /// made for printing): `/BaseState /ON`, `/ON` the visible layers, `/OFF` the hidden ones. Its /// other entries (`/Order`, `/RBGroups`, `/AS`…) are kept. A document without `/OCProperties` /// is left alone. pub(crate) fn set_default_layer_state(cos: &mut pdfcraft_cos::Document, layers: &[Layer]) { use pdfcraft_cos::{Dict, ObjRef, Object}; let Some(root_ref) = cos.trailer().get(b"Root").and_then(Object::as_ref) else { return }; let Some(mut root) = cos.get(root_ref).as_dict().cloned() else { return }; let Some(properties) = root.get(b"OCProperties").cloned() else { return }; let Some(mut properties) = cos.resolve(&properties).as_dict().cloned() else { return }; let mut config = properties.get(b"D").and_then(|d| cos.resolve(d).as_dict().cloned()).unwrap_or_else(Dict::new); let refs = |visible: bool| Object::Array(layers.iter().filter(|l| l.visible == visible).map(|l| Object::Ref(ObjRef::new(l.id.0, l.id.1))).collect()); config.set(b"BaseState".to_vec(), Object::name("ON")); config.set(b"ON".to_vec(), refs(true)); config.set(b"OFF".to_vec(), refs(false)); properties.set(b"D".to_vec(), Object::Dict(config)); root.set(b"OCProperties".to_vec(), Object::Dict(properties)); cos.set(root_ref, Object::Dict(root)); } /// Render `doc` with the layer visibility in its `info.layers`. pub(crate) fn use_layer_choices(doc: &mut Document) { let overrides: Vec<(i32, i32, bool)> = doc.info.layers.iter().map(|l| (l.id.0 as i32, l.id.1 as i32, l.visible)).collect(); doc.config.layers = Arc::new(overrides); doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone()); } /// Apply a set-layer-visibility action to `layers`, one change at a time, so a toggle flips the /// state the changes before it left. Returns whether any layer ended up changed. pub(crate) fn apply_layer_state(layers: &mut [Layer], groups: &[Vec<(u32, u16)>], changes: &[(LayerOp, (u32, u16))], preserve_rb: bool) -> bool { let before: Vec = layers.iter().map(|l| l.visible).collect(); let index: std::collections::HashMap<(u32, u16), usize> = layers.iter().enumerate().map(|(i, l)| (l.id, i)).collect(); for &(op, ocg) in changes { let Some(layer) = index.get(&ocg).and_then(|&i| layers.get_mut(i)) else { continue }; let on = match op { LayerOp::On => true, LayerOp::Off => false, LayerOp::Toggle => !layer.visible, }; layer.visible = on; // Turning a layer off leaves the rest of its groups alone. if on && preserve_rb { for other in groups.iter().filter(|g| g.contains(&ocg)).flatten().filter(|&&o| o != ocg) { if let Some(l) = index.get(other).and_then(|&i| layers.get_mut(i)) { l.visible = false; } } } } layers.iter().zip(before).any(|(l, was)| l.visible != was) }