Thijs Meijerink
Thijs Meijerink

Reputation: 33

a negative unsigned int?

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

Answers (2)

Julien Zakaib
Julien Zakaib

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 :enter image description here

I want the index for the character code 97 (lowercase 'a').

  1. 97 is greater than 32 and smaller than 126, so we use index 2 of the mappings.
  2. idDelta[2] == 65507
  3. glyphIndex = (65507 + 97) % 65536 === 68 which is the same as (65507 - 65536) + 97 === 68

Upvotes: 2

Roland Smith
Roland Smith

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

Related Questions