1use std::rc::Rc;
11
12use crate::Engine;
13use crate::cmd::Cmd;
14use crate::eqtb::Meaning;
15use crate::token::Token;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub enum VarKind {
20 Int,
22 Dimen,
24 Toks,
26}
27
28pub const H_ORIGIN: u32 = 28;
30pub const V_ORIGIN: u32 = 29;
32pub const COMPRESS_LEVEL: u32 = 137;
34pub const DECIMAL_DIGITS: u32 = 138;
36pub const OBJ_COMPRESS_LEVEL: u32 = 152;
38pub const MINOR_VERSION: u32 = 143;
40
41pub const MAJOR_VERSION: u32 = 142;
43pub const PK_RESOLUTION: u32 = 140;
45pub const PK_FIXED_DPI: u32 = 155;
47pub const PAGE_ATTR: u32 = 11;
49pub const PAGE_RESOURCES: u32 = 12;
51pub const PAGES_ATTR: u32 = 13;
53pub const TRAILER_ID: u32 = 17;
55
56pub const PDF_VARIABLES: &[(&str, VarKind, u32)] = &[
58 ("compresslevel", VarKind::Int, 137),
59 ("decimaldigits", VarKind::Int, 138),
60 ("imageresolution", VarKind::Int, 139),
61 ("pkresolution", VarKind::Int, 140),
62 ("uniqueresname", VarKind::Int, 141),
63 ("majorversion", VarKind::Int, 142),
64 ("minorversion", VarKind::Int, 143),
65 ("pagebox", VarKind::Int, 144),
66 ("inclusionerrorlevel", VarKind::Int, 145),
67 ("ignoreunknownimages", VarKind::Int, 146),
68 ("gamma", VarKind::Int, 147),
69 ("imageapplygamma", VarKind::Int, 148),
70 ("imagegamma", VarKind::Int, 149),
71 ("imagehicolor", VarKind::Int, 150),
72 ("imageaddfilename", VarKind::Int, 151),
73 ("objcompresslevel", VarKind::Int, 152),
74 ("inclusioncopyfonts", VarKind::Int, 153),
75 ("gentounicode", VarKind::Int, 154),
76 ("pkfixeddpi", VarKind::Int, 155),
77 ("suppressoptionalinfo", VarKind::Int, 156),
78 ("omitcidset", VarKind::Int, 157),
79 ("recompress", VarKind::Int, 158),
80 ("omitcharset", VarKind::Int, 159),
81 ("omitinfodict", VarKind::Int, 160),
82 ("omitmediabox", VarKind::Int, 161),
83 ("omitprocset", VarKind::Int, 163),
84 ("ptexprefix", VarKind::Int, 164),
85 ("horigin", VarKind::Dimen, 28),
86 ("vorigin", VarKind::Dimen, 29),
87 ("threadmargin", VarKind::Dimen, 30),
88 ("destmargin", VarKind::Dimen, 31),
89 ("linkmargin", VarKind::Dimen, 32),
90 ("xformmargin", VarKind::Dimen, 33),
91 ("pageattr", VarKind::Toks, 11),
92 ("pageresources", VarKind::Toks, 12),
93 ("pagesattr", VarKind::Toks, 13),
94 ("xformattr", VarKind::Toks, 14),
95 ("xformresources", VarKind::Toks, 15),
96 ("pkmode", VarKind::Toks, 16),
97 ("trailerid", VarKind::Toks, 17),
98];
99
100impl Engine {
101 pub fn expand_backend_variable(&mut self) {
103 let found = PDF_VARIABLES
104 .iter()
105 .find(|(name, _, _)| self.scan_keyword(name))
106 .copied();
107 let Some((name, kind, index)) = found else {
108 return;
109 };
110 let cs = match self.backend_cs.get(name) {
111 Some(&cs) => cs,
112 None => {
113 let (label, cmd) = match kind {
114 VarKind::Int => ("[internal backend integer]", Cmd::AssignInt),
115 VarKind::Dimen => ("[internal backend dimension]", Cmd::AssignDimen),
116 VarKind::Toks => ("[internal backend tokenlist]", Cmd::AssignToks),
117 };
118 let cs = self.hash.new_internal(label.as_bytes());
119 self.eqtb.ensure_cs(cs);
120 self.eqtb.cs[cs.0 as usize].val = Meaning::prim(cmd, index);
121 self.eqtb.cs[cs.0 as usize].level = crate::eqtb::LEVEL_ONE;
122 self.backend_cs.insert(name, cs);
123 cs
124 }
125 };
126 self.cur_tok = Token::cs(cs);
127 self.back_input();
128 }
129
130 pub fn expand_backend_feedback(&mut self) {
132 if self.eqtb.int(crate::primitives_gen::assign_int::OUTPUTMODE) <= 0 {
133 self.print_err("unexpected use of \\pdffeedback");
135 self.help(&[]);
136 self.error();
137 return;
138 }
139 const KEYS: &[&str] = &[
140 "version",
141 "revision",
142 "lastlink",
143 "retval",
144 "lastobj",
145 "lastannot",
146 "xformname",
147 "creationdate",
148 "fontname",
149 "fontobjnum",
150 "fontsize",
151 "pageref",
152 "colorstackinit",
153 ];
154 let key = KEYS.iter().find(|k| self.scan_keyword(k)).copied();
155 let text: Vec<u8> = match key {
156 Some("version") => b"140".to_vec(),
157 Some("lastobj") => self.pdf.last_obj.to_string().into_bytes(),
158 Some("lastannot") => self.pdf.last_annot.to_string().into_bytes(),
159 Some("lastlink") => self.pdf.last_link.to_string().into_bytes(),
160 Some("revision") => b"0".to_vec(),
161 Some("retval") => self.pdf.retval.to_string().into_bytes(),
162 Some("creationdate") => self.pdf_creation_date().into_bytes(),
163 Some(k @ ("fontname" | "fontobjnum" | "fontsize")) => {
164 self.scan_font_ident();
165 let f = self.cur_val.max(0) as u32;
166 if f == 0 {
167 let k = if k == "fontobjnum" { "objnum" } else { k };
170 self.pdf_fatal(&format!("invalid font identifier when asking '{k}'"));
171 }
172 match k {
173 "fontname" => self.pdf_font(f).0.to_string().into_bytes(),
174 "fontobjnum" => self.pdf_font(f).1.to_string().into_bytes(),
175 _ => {
176 let mut out = String::new();
177 retex_arith::print_scaled(&mut out, self.font(f).size);
178 out.push_str("pt");
179 out.into_bytes()
180 }
181 }
182 }
183 Some("xformname") => {
184 self.scan_int();
187 let n = self.cur_val;
188 if n <= 0 || n as usize > self.box_resources.len() {
189 self.pdf_fatal("cannot find referenced object");
190 } else {
191 n.to_string().into_bytes()
192 }
193 }
194 Some("pageref") => {
195 self.scan_int();
196 let page = self.cur_val;
197 if page <= 0 {
198 self.pdf_fatal("invalid page number when asking 'pageref'");
199 } else {
200 self.pdf_page_ref(page).to_string().into_bytes()
201 }
202 }
203 Some("colorstackinit") => {
204 let page = self.scan_keyword("page");
205 let direct = self.scan_keyword("direct");
206 let toks = self.scan_toks_expanded();
207 let init =
208 self.print_to_string(|e| e.show_token_list(&toks, 0, toks.len(), i64::MAX));
209 self.pdf_new_colorstack(
210 init,
211 page,
212 if direct {
213 crate::pdfext::literal_mode::DIRECT
214 } else {
215 crate::pdfext::literal_mode::ORIGIN
216 },
217 )
218 .to_string()
219 .into_bytes()
220 }
221 Some(_) => b"0".to_vec(),
222 None => Vec::new(),
223 };
224 let toks = crate::the::str_toks(&text);
225 self.ins_list(Rc::from(toks));
226 }
227
228 pub fn pdf_creation_date(&self) -> String {
230 self.start_time.pdf_date()
231 }
232}