1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//! Turning a page-object graph back into content-stream operators
//! (ISO 32000-1 §8, §9).
//!
//! A page whose objects were modified is rewritten from the graph rather than
//! patched, so these bytes *are* the round trip: any divergence here shows up
//! as pixels.
//!
//! # This is lossy, and the losses are limits rather than a requirement
//!
//! Each thing the emitter drops is something it cannot yet express. Nothing
//! requires it to drop them: no comparison anywhere scores a regenerated page
//! against another producer's regenerated page, so emitting *more* than some
//! other writer does costs nothing.
//!
//! The losses, in full:
//!
//! - **Colour.** Only `rg` and `RG` are ever written, but **every colour space
//! converts to them** — see `emit::expressible_rgb`, which carries the
//! `[oracle-bug]` citation. Only a **pattern** emits nothing and inherits the
//! black the per-stream prologue set, because a pattern paints through a
//! resource no `rg` can name.
//! - **Shadings.** A shading page object emits nothing at all.
//! - **Text.** Only `Tm`, `Tf`, `Tr` and `TJ`. All positioning collapses into
//! `Tm`; `Td`, `TD`, `T*`, `Tj`, `'`, `"`, `Tc`, `Tw`, `Tz`, `TL` and `Ts`
//! are never emitted, so character and word spacing are lost. A Type 3 font
//! drops its whole text object.
//! - **Graphics state.** Only `ca`, `CA` and `BM` reach an `/ExtGState`. The
//! miter limit and soft masks do not.
//! - **Clips.** Path clips only: text clips, clip-path soft masks and shading
//! clips are never written.
//!
//! # No state diffing, ever
//!
//! Each object is wrapped in its own `q`/`Q` and states everything it needs
//! from scratch, comparing each value against the *hardcoded PDF default* —
//! never against the object emitted before it. That makes the output longer
//! than a hand-written stream and makes every object independently
//! relocatable, which is what lets objects from several source streams
//! interleave into new ones without a fixup pass.
//!
//! # An unsupported object contributes nothing
//!
//! Two C++ paths write a prefix and then bail, leaving a `q ` — and for text
//! a `BT ` — unclosed. We build each object's bytes into a scratch buffer and
//! commit them only on success, so an object we cannot express contributes
//! *nothing* rather than an unbalanced fragment. The rendered result is the
//! same for well-formed input, because the stream-level `Q` closes the C++'s
//! stray `q` anyway; the difference is that our output stays parseable.
// `pdfium_test` has no save flag, so there is no such thing as the oracle's
// regenerated page (`conformance/src/saveroundtrip.rs:6-8`). Tier-B compares
// our render against a golden of the *original*
// (`conformance/src/run.rs:339-361`). The one sweep that does regenerate
// compares two renders of the **same** regenerated bytes, so a content loss
// dropped on both sides cannot score either way
// (`conformance/src/mutation.rs:12-17`, `:41-44`) — and it is a separate
// command, not on the board.
pub
// What the crate root re-exports. Everything else this module holds is
// `pub(crate)`: the emitter's internals are the writer's, not a caller's.
pub use ;
pub use ;
pub use ;
pub use ResourceTable;