1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:57:45 +00:00

LibPDF: Move type1 subr 1 and 2 handling into othersubr handler

https://adobe-type-tools.github.io/font-tech-notes/pdfs/T1_SPEC.pdf,
8.4 First Four Subrs Entries:

"""If Flex or hint replacement is used in a Type 1 font program, the
first four entries in the Subrs array in the Private dictionary must be
assigned charstrings that correspond to the following code sequences. If
neither Flex nor hint replacement is used in the font program, then this
requirement is removed, and the first Subrs entry may be a normal
charstring subroutine sequence. The first four Subrs entries contain:

[...]

Subrs entry number 1:
0 1 callothersubr return

Subrs entry number 2:
0 2 callothersubr return
"""

So subr entry numbers 1 and 2 just call othersubr 1 and and 2, which
means we can just move the handling code over.

No behavior change if flex is used, but more correct if it isn't.

(This only works because our `return` handler is empty, else we would
have to make the callothersubr handler start a call frame.)
This commit is contained in:
Nico Weber 2023-10-31 08:57:25 -04:00 committed by Tim Flynn
parent f630a5ca71
commit 0bb8249780

View file

@ -398,9 +398,9 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
return error("Subroutine index out of range"); return error("Subroutine index out of range");
if (!is_type2) { if (!is_type2) {
// FIXME: Hardcoding subrs 0-2 here is incorrect, since some fonts don't use the flex feature. // FIXME: Hardcoding subr 0 here is incorrect, since some fonts don't use the flex feature.
// For the ones that do, subrs 0-2 have fixed contents that have callothersubr instructions. // For the ones that do, subrs 0 has fixed contents that have callothersubr instructions.
// The right thing to do is to implement callothersubr for subrs 0-3 and remove the hardcoding here. // The right thing to do is to implement callothersubr for subrs 0 and remove the hardcoding here.
// Subroutines 0-2 handle the flex feature. // Subroutines 0-2 handle the flex feature.
if (subr_number == 0) { if (subr_number == 0) {
@ -422,16 +422,6 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
state.sp = 0; state.sp = 0;
break; break;
} }
if (subr_number == 1) {
state.flex_feature = true;
state.flex_index = 0;
state.sp = 0;
break;
}
if (subr_number == 2) {
state.sp = 0;
break;
}
} }
auto const& subr = subroutines[subr_number]; auto const& subr = subroutines[subr_number];
if (subr.is_empty()) if (subr.is_empty())
@ -474,10 +464,41 @@ PDFErrorOr<Type1FontProgram::Glyph> Type1FontProgram::parse_glyph(ReadonlyBytes
} }
case CallOtherSubr: { case CallOtherSubr: {
[[maybe_unused]] auto othersubr_number = pop(); // Type 1 spec, 8.3 Flex:
// "5. Insert at the beginning of the sequence the coordinate of the reference point relative to the starting point.
// There are now seven coordinate values (14 numbers) in the sequence.
// 6. Place a call to Subrs entry 1 at the beginning of this sequence of coordinates, and place an rmoveto command
// and a call to Subrs entry 2 after each of the seven coordinate pairs in the sequence.
// 7. Place the Flex height control parameter and the final coordinate expressed in absolute terms (in character space)
// followed by a call to Subrs entry 0 at the end."
enum OtherSubrCommand {
StartFlex = 1,
AddFlexPoint = 2,
};
auto othersubr_number = (OtherSubrCommand)pop();
auto n = static_cast<int>(pop()); auto n = static_cast<int>(pop());
for (int i = 0; i < n; ++i)
state.postscript_stack[state.postscript_sp++] = pop(); switch ((OtherSubrCommand)othersubr_number) {
case StartFlex:
if (n != 0)
return error("Unexpected argument code for othersubr 1");
state.flex_feature = true;
state.flex_index = 0;
state.sp = 0;
break;
case AddFlexPoint:
if (n != 0)
return error("Unexpected argument code for othersubr 2");
// We do this directly in move_to().
state.sp = 0;
break;
default:
for (int i = 0; i < n; ++i)
state.postscript_stack[state.postscript_sp++] = pop();
break;
}
break; break;
} }