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