use std::rc::Rc;
use crate::Engine;
use crate::cmd::Cmd;
use crate::eqtb::Meaning;
use crate::token::Token;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum VarKind {
Int,
Dimen,
Toks,
}
pub const H_ORIGIN: u32 = 28;
pub const V_ORIGIN: u32 = 29;
pub const COMPRESS_LEVEL: u32 = 137;
pub const DECIMAL_DIGITS: u32 = 138;
pub const OBJ_COMPRESS_LEVEL: u32 = 152;
pub const MINOR_VERSION: u32 = 143;
pub const MAJOR_VERSION: u32 = 142;
pub const PK_RESOLUTION: u32 = 140;
pub const PK_FIXED_DPI: u32 = 155;
pub const PAGE_ATTR: u32 = 11;
pub const PAGE_RESOURCES: u32 = 12;
pub const PAGES_ATTR: u32 = 13;
pub const TRAILER_ID: u32 = 17;
pub const PDF_VARIABLES: &[(&str, VarKind, u32)] = &[
("compresslevel", VarKind::Int, 137),
("decimaldigits", VarKind::Int, 138),
("imageresolution", VarKind::Int, 139),
("pkresolution", VarKind::Int, 140),
("uniqueresname", VarKind::Int, 141),
("majorversion", VarKind::Int, 142),
("minorversion", VarKind::Int, 143),
("pagebox", VarKind::Int, 144),
("inclusionerrorlevel", VarKind::Int, 145),
("ignoreunknownimages", VarKind::Int, 146),
("gamma", VarKind::Int, 147),
("imageapplygamma", VarKind::Int, 148),
("imagegamma", VarKind::Int, 149),
("imagehicolor", VarKind::Int, 150),
("imageaddfilename", VarKind::Int, 151),
("objcompresslevel", VarKind::Int, 152),
("inclusioncopyfonts", VarKind::Int, 153),
("gentounicode", VarKind::Int, 154),
("pkfixeddpi", VarKind::Int, 155),
("suppressoptionalinfo", VarKind::Int, 156),
("omitcidset", VarKind::Int, 157),
("recompress", VarKind::Int, 158),
("omitcharset", VarKind::Int, 159),
("omitinfodict", VarKind::Int, 160),
("omitmediabox", VarKind::Int, 161),
("omitprocset", VarKind::Int, 163),
("ptexprefix", VarKind::Int, 164),
("horigin", VarKind::Dimen, 28),
("vorigin", VarKind::Dimen, 29),
("threadmargin", VarKind::Dimen, 30),
("destmargin", VarKind::Dimen, 31),
("linkmargin", VarKind::Dimen, 32),
("xformmargin", VarKind::Dimen, 33),
("pageattr", VarKind::Toks, 11),
("pageresources", VarKind::Toks, 12),
("pagesattr", VarKind::Toks, 13),
("xformattr", VarKind::Toks, 14),
("xformresources", VarKind::Toks, 15),
("pkmode", VarKind::Toks, 16),
("trailerid", VarKind::Toks, 17),
];
impl Engine {
pub fn expand_backend_variable(&mut self) {
let found = PDF_VARIABLES
.iter()
.find(|(name, _, _)| self.scan_keyword(name))
.copied();
let Some((name, kind, index)) = found else {
return;
};
let cs = match self.backend_cs.get(name) {
Some(&cs) => cs,
None => {
let (label, cmd) = match kind {
VarKind::Int => ("[internal backend integer]", Cmd::AssignInt),
VarKind::Dimen => ("[internal backend dimension]", Cmd::AssignDimen),
VarKind::Toks => ("[internal backend tokenlist]", Cmd::AssignToks),
};
let cs = self.hash.new_internal(label.as_bytes());
self.eqtb.ensure_cs(cs);
self.eqtb.cs[cs.0 as usize].val = Meaning::prim(cmd, index);
self.eqtb.cs[cs.0 as usize].level = crate::eqtb::LEVEL_ONE;
self.backend_cs.insert(name, cs);
cs
}
};
self.cur_tok = Token::cs(cs);
self.back_input();
}
pub fn expand_backend_feedback(&mut self) {
if self.eqtb.int(crate::primitives_gen::assign_int::OUTPUTMODE) <= 0 {
self.print_err("unexpected use of \\pdffeedback");
self.help(&[]);
self.error();
return;
}
const KEYS: &[&str] = &[
"version",
"revision",
"lastlink",
"retval",
"lastobj",
"lastannot",
"xformname",
"creationdate",
"fontname",
"fontobjnum",
"fontsize",
"pageref",
"colorstackinit",
];
let key = KEYS.iter().find(|k| self.scan_keyword(k)).copied();
let text: Vec<u8> = match key {
Some("version") => b"140".to_vec(),
Some("lastobj") => self.pdf.last_obj.to_string().into_bytes(),
Some("lastannot") => self.pdf.last_annot.to_string().into_bytes(),
Some("lastlink") => self.pdf.last_link.to_string().into_bytes(),
Some("revision") => b"0".to_vec(),
Some("retval") => self.pdf.retval.to_string().into_bytes(),
Some("creationdate") => self.pdf_creation_date().into_bytes(),
Some(k @ ("fontname" | "fontobjnum" | "fontsize")) => {
self.scan_font_ident();
let f = self.cur_val.max(0) as u32;
if f == 0 {
let k = if k == "fontobjnum" { "objnum" } else { k };
self.pdf_fatal(&format!("invalid font identifier when asking '{k}'"));
}
match k {
"fontname" => self.pdf_font(f).0.to_string().into_bytes(),
"fontobjnum" => self.pdf_font(f).1.to_string().into_bytes(),
_ => {
let mut out = String::new();
retex_arith::print_scaled(&mut out, self.font(f).size);
out.push_str("pt");
out.into_bytes()
}
}
}
Some("xformname") => {
self.scan_int();
let n = self.cur_val;
if n <= 0 || n as usize > self.box_resources.len() {
self.pdf_fatal("cannot find referenced object");
} else {
n.to_string().into_bytes()
}
}
Some("pageref") => {
self.scan_int();
let page = self.cur_val;
if page <= 0 {
self.pdf_fatal("invalid page number when asking 'pageref'");
} else {
self.pdf_page_ref(page).to_string().into_bytes()
}
}
Some("colorstackinit") => {
let page = self.scan_keyword("page");
let direct = self.scan_keyword("direct");
let toks = self.scan_toks_expanded();
let init =
self.print_to_string(|e| e.show_token_list(&toks, 0, toks.len(), i64::MAX));
self.pdf_new_colorstack(
init,
page,
if direct {
crate::pdfext::literal_mode::DIRECT
} else {
crate::pdfext::literal_mode::ORIGIN
},
)
.to_string()
.into_bytes()
}
Some(_) => b"0".to_vec(),
None => Vec::new(),
};
let toks = crate::the::str_toks(&text);
self.ins_list(Rc::from(toks));
}
pub fn pdf_creation_date(&self) -> String {
self.start_time.pdf_date()
}
}