M2: the operand-cap patch is hayro-syntax patch 28 (#4260)

Main took hayro-syntax patches 26 and 27 (xref streams), so the patch
that keeps up to 256 operands per instruction moves to 28 in
vendor/README.md and in every comment that cites it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC
This commit is contained in:
mtlcl410
2026-10-24 11:45:23 +08:00
co-authored by Claude Opus 5.5
parent 0142a96ca3
commit 098f221e12
4 changed files with 13 additions and 13 deletions
+1 -1
View File
@@ -8170,7 +8170,7 @@ trailer << /Root 1 0 R >>
mod default_colour_spaces;
// #4260: DeviceN colours with many inks, and tint transforms that cannot be evaluated
// (vendored hayro-syntax patch 26, hayro-interpret patch 55).
// (vendored hayro-syntax patch 28, hayro-interpret patch 55).
mod devicen_inks;
/// #3109 / #3116: clipping-only text (`7 Tr`) installs a clip for subsequent painting
@@ -1,7 +1,7 @@
//! #4260: a DeviceN colour with more inks than the content parser held operands for, and a
//! colour whose tint transform cannot be evaluated (ISO 32000-2 §8.6.6.5).
//!
//! The content parser kept at most ten operands per operator (vendored hayro-syntax patch 26):
//! The content parser kept at most ten operands per operator (vendored hayro-syntax patch 28):
//! the eleventh operand of a twelve-ink `scn` ended the whole content stream, so the page came
//! out blank with no error. A tint transform that cannot be evaluated painted the alternate
//! space's initial colour without a word (vendored hayro-interpret patch 55): it now says so.
+9 -9
View File
@@ -50,10 +50,10 @@ use smallvec::SmallVec;
// 6 operands are used for example for ctm or cubic curves,
// but anything above should be pretty rare (only for example for
// DeviceN color spaces, or invalid PDF files). So we settle on 10.
// PdfCraft patch (26): this is now only how many operands are held inline; see `MAX_OPERANDS`.
// PdfCraft patch (28): this is now only how many operands are held inline; see `MAX_OPERANDS`.
const OPERANDS_THRESHOLD: usize = 10;
/// PdfCraft patch (26): the most operands one instruction keeps. The stack held ten, and the
/// PdfCraft patch (28): the most operands one instruction keeps. The stack held ten, and the
/// eleventh operand of an instruction ended the whole content stream, so a DeviceN colour of
/// eleven or more inks (ISO 32000-2 §8.6.6.5 allows "an arbitrary number of colour
/// components") blanked the rest of the page (#4260). An `SCN`/`scn` for the largest DeviceN
@@ -445,7 +445,7 @@ impl<'a> UntypedIter<'a> {
self.operator = Some(operator);
self.committed = self.reader.offset();
// PdfCraft patch (26): operands in reading order, if some were dropped.
// PdfCraft patch (28): operands in reading order, if some were dropped.
self.stack.settle();
return Some(Instruction {
operands: &self.stack,
@@ -605,12 +605,12 @@ impl<'b, 'a> Instruction<'b, 'a> {
pub struct Stack<'a> {
// TODO: Explore using an object pool to avoid repeatedly
// allocating/deallocating objects.
// PdfCraft patch (26): up to `MAX_OPERANDS` operands, the first `OPERANDS_THRESHOLD` inline.
// PdfCraft patch (28): up to `MAX_OPERANDS` operands, the first `OPERANDS_THRESHOLD` inline.
data: SmallVec<[Object<'a>; OPERANDS_THRESHOLD]>,
/// PdfCraft patch (26): once `data` is full, the slot of its oldest operand, which the next
/// PdfCraft patch (28): once `data` is full, the slot of its oldest operand, which the next
/// operand replaces. Always 0 while the stack is not full, and after `settle`.
oldest: usize,
/// PdfCraft patch (26): whether operands were dropped since the stack was last settled.
/// PdfCraft patch (28): whether operands were dropped since the stack was last settled.
dropped: bool,
}
@@ -630,7 +630,7 @@ impl<'a> Stack<'a> {
}
}
/// PdfCraft patch (26): push an operand, dropping the oldest once `MAX_OPERANDS` are held
/// PdfCraft patch (28): push an operand, dropping the oldest once `MAX_OPERANDS` are held
/// (see `MAX_OPERANDS`). Never fails: it used to, and the failure ended the content stream.
fn push(&mut self, operand: Object<'a>) -> Option<()> {
if self.data.len() < MAX_OPERANDS {
@@ -646,7 +646,7 @@ impl<'a> Stack<'a> {
Some(())
}
/// PdfCraft patch (26): put the operands back in the order they were read, oldest first,
/// PdfCraft patch (28): put the operands back in the order they were read, oldest first,
/// after `push` dropped some. Called before the instruction is handed out.
fn settle(&mut self) {
if self.dropped {
@@ -703,7 +703,7 @@ impl Debug for Stack<'_> {
impl Clone for Stack<'_> {
fn clone(&self) -> Self {
// PdfCraft patch (26): a plain copy (pushing each operand again could no longer fail).
// PdfCraft patch (28): a plain copy (pushing each operand again could no longer fail).
Self {
data: self.data.clone(),
oldest: self.oldest,
+2 -2
View File
@@ -152,7 +152,7 @@ f
assert!(iter.next().is_none());
}
/// PdfCraft patch (26): a twelve-ink DeviceN colour's `scn` keeps all twelve operands, and
/// PdfCraft patch (28): a twelve-ink DeviceN colour's `scn` keeps all twelve operands, and
/// the instructions after it are still read (#4260). The eleventh operand ended the stream.
#[test]
fn scn_with_twelve_components_keeps_them_all() {
@@ -171,7 +171,7 @@ f
assert!(iter.next().is_none());
}
/// PdfCraft patch (26): past the operand cap the oldest operands are dropped, in order, and
/// PdfCraft patch (28): past the operand cap the oldest operands are dropped, in order, and
/// the operator reads the ones nearest to it.
#[test]
fn operands_past_the_cap_keep_the_latest_in_order() {