diff --git a/contributors/people.toml b/contributors/people.toml index f3c8629b7..db94e2a89 100644 --- a/contributors/people.toml +++ b/contributors/people.toml @@ -189,3 +189,7 @@ sync_github_name = false [people.WadahBadawi] display_name = "Wadah Badawi" sync_github_name = true + +[people.JonRC] +real_name = "Jonathan Cardoso" +display_name = "Jonathan Cardoso" diff --git a/crates/eps/src/import/interp.rs b/crates/eps/src/import/interp.rs index 12232624f..6126b4b32 100644 --- a/crates/eps/src/import/interp.rs +++ b/crates/eps/src/import/interp.rs @@ -1135,9 +1135,12 @@ impl<'a> Interp<'a> { PdfMark => { self.pop_to_mark()?; } + // True for a simple object, and for a composite one in global VM (PLRM 3rd ed., `gcheck`); + // every composite here is in local VM. Procsets that copy values into global VM leave + // alone those whose `gcheck` is true, such as a halftone's numbers. Gcheck | Scheck => { - self.pop()?; - self.push(Obj::Bool(false))?; + let simple = !self.pop()?.is_composite(); + self.push(Obj::Bool(simple))?; } CurrentShared => self.push(Obj::Bool(false))?, SetShared | SetVmThreshold | VmReclaim | Echo => { diff --git a/crates/eps/src/import/obj.rs b/crates/eps/src/import/obj.rs index b4dc34364..4f07678a7 100644 --- a/crates/eps/src/import/obj.rs +++ b/crates/eps/src/import/obj.rs @@ -286,6 +286,11 @@ impl Obj { Self::GState(_) => "gstatetype", } } + + /// A composite object, whose value lives in VM; the others are simple (PLRM 3rd ed., §3.3.1). + pub fn is_composite(&self) -> bool { + matches!(self, Self::Str(_) | Self::ExecStr(_) | Self::Array { .. } | Self::Dict(_) | Self::File { .. } | Self::Save(_) | Self::GState(_)) + } } /// The values of a string or an array: a run of storage that other strings or arrays may share diff --git a/crates/eps/src/import/tests_generators.rs b/crates/eps/src/import/tests_generators.rs index 2fe6ba324..4337b9474 100644 --- a/crates/eps/src/import/tests_generators.rs +++ b/crates/eps/src/import/tests_generators.rs @@ -592,6 +592,21 @@ showpage"##; assert!(near(bounds(&meshes[1]), Rect::new(150.0, 90.0, 190.0, 140.0)), "{:?}", bounds(&meshes[1])); } +/// Ghostscript 9's `eps2write` copies the initial graphics state (`currenthalftone`, +/// `currentcolortransfer`) into global VM before it draws, with a copier for each composite type. +/// It copies only what `gcheck` says is in local VM: `gcheck` is true for every simple object +/// (PLRM 3rd ed., `gcheck`), so the halftone's numbers stay as they are. Written from the PLRM. +#[test] +fn gcheck_is_true_for_simple_objects() { + super::tests::check("1 gcheck 2.5 gcheck and /n gcheck and true gcheck and null gcheck and /add load gcheck and mark gcheck and"); + super::tests::check("(s) gcheck not 1 dict gcheck not and {} gcheck not and 1 scheck and (s) scheck not and"); + super::tests::check( + "/copiers << /dicttype { << exch { cp2g } forall >> } /arraytype { [ exch { cp2g } forall ] } >> def \ + /cp2g { dup gcheck not { copiers 1 index type get exec } if } bind def \ + currenthalftone cp2g /Frequency get 60 eq [ currentcolortransfer ] cp2g length 4 eq and", + ); +} + /// A procset written as the PostScript Language Reference (3rd ed.) describes the Level 2 and 3 /// facilities programs probe before drawing: a resource category made from `Generic` and /// resources defined and found in it (§3.9), local and global VM (`currentglobal`, `setglobal`,