Reputation: 33
I'm trying to wrap my head around the truetype specification. On this page, in the section 'cmap' format 4, the parameter idDelta is listed as an unsigned 16-bits integer (UInt16). Yet, further down, a few examples are given, and here idDelta is given the values -9, -18, -27 and 1. How is this possible?
Upvotes: 2
Views: 261
Reputation: 194
This is not a bug in the spec. The reason they show negative numbers in the idDelta
row for the examples is that All idDelta[i] arithmetic is modulo 65536.
(quoted from the section just above). Here's how that works.
The formula to get the glyph index is
glyphIndex = idDelta[i] + c
where c
is the character code. Since this expression must be modulo 65536, that's equivalent to the following expression if you were using integers larger than 2 bytes :
glyphIndex = (idDelta[i] + c) % 65536
idDelta
is a u16, so let's say it had the max value 65535 (0xFFFF
), then glyphIndex
would be equal to c - 1
since:
0xFFFF + 2 = 0x10001
0x10001 % 0x10000 = 1
You can think of this as a 16 integer wrapping around to 0 when an overflow occurs.
Now remember that a modulo is repeated division, keeping the remainder. Well in this case, since idDelta
is only 16 bits, the max amount of divisions a modulo will need to do is 1, since the max value you can get from adding two 16 bit integers is 0x1FFFE
, which is smaller than 0x100000
. That means that a shortcut is to subtract 65536 (0x10000
) instead of performing the modulo.
glyphIndex = (idDelta[i] - 0x10000) + c
And this is what the example shows as the values in the table. Here's an actual example from a .ttf file I've decoded :
I want the index for the character code 97 (lowercase 'a').
idDelta[2] == 65507
glyphIndex = (65507 + 97) % 65536 === 68
which is the same as (65507 - 65536) + 97 === 68
Upvotes: 2
Reputation: 43495
The definition and use of idDelta
on that page is not consistent. In the struct subheader
it is defined as an int16
, while a little earlier the same subheader is listed as UInt16*4
.
It's probably a bug in the spec.
If you look at actual implementations, like this one from perl Tk, you'll see that idDelta is usually given as signed:
typedef struct SUBHEADER {
USHORT firstCode; /* First valid low byte for subHeader. */
USHORT entryCount; /* Number valid low bytes for subHeader. */
SHORT idDelta; /* Constant adder to get base glyph index. */
USHORT idRangeOffset; /* Byte offset from here to appropriate
* glyphIndexArray. */
} SUBHEADER;
Or see the implementation from libpdfxx:
struct SubHeader
{
USHORT firstCode;
USHORT entryCount;
SHORT idDelta;
USHORT idRangeOffset;
};
Upvotes: 0