fontstruetypeopentype

Can idDelta and idRangeOffset both be non zero in TrueType fonts?


Is it possible that in cmap format 4 of a TrueType font that idDelta and idRangeOffset of a segment are both non-zero? And if so, why?

Why would you need to add idDelta if the glyph index taken from glyphIndexArray can be whatever the font manufacturer wants?


Solution

  • As per https://learn.microsoft.com/en-us/typography/opentype/otspec140/cmap#format-4-segment-mapping-to-delta-values, this would not make sense, as an idRangeOffset that is non-zero means the parser needs to consult the glyphIdArray, which does not involve the idDelta value in any way, whereas an idRangeOffset:0 means that the segment's glyph id is based on adding the idDelta to the character code offset, and does not use the glyphIdArray. So, can they both be non-zero? Sure. The math will still work.

    But it'd also be really weird, mostly due to the answer to your question "why would you need to add idDelta if the glyph index taken from glyphIndexArray can be whatever the font manufacturer wants?": because that suggests you misunderstood how idDelta and idRangeOffset work.

    Quoting the spec:

    If the idRangeOffset value for the segment is not 0, the mapping of character codes relies on glyphIdArray. The character code offset from startCode is added to the idRangeOffset value. This sum is used as an offset from the current location within idRangeOffset itself to index out the correct glyphIdArray value. This obscure indexing trick works because glyphIdArray immediately follows idRangeOffset in the font file. The C expression that yields the glyph index is:

    *(idRangeOffset[i]/2 + (c - startCount[i]) + &idRangeOffset[i])

    The value c is the character code in question, and i is the segment index in which c appears. If the value obtained from the indexing operation is not 0 (which indicates missingGlyph), idDelta[i] is added to it to get the glyph index. The idDelta arithmetic is modulo 65536.

    If the idRangeOffset is 0, the idDelta value is added directly to the character code offset (i.e. idDelta[i] + c) to get the corresponding glyph index. Again, the idDelta arithmetic is modulo 65536.

    And while the spec assumes you know how C works, folks these days don't: the * at the front means that we're computing a byte offset, relative to the start of the file. The & means "the memory location of this thing" (although in this case that means byte offset into our font file).

    So: we're adding a number (idRangeOffset[i]/2 + (c - startCount[i])) to the byte location of the ith range offset (&idRangeOffset[i]), which gives us a new offset. If we start reading the font bytes starting at the byte offset corresponding to that number, we'll be at the correct spot to read in our glyph id. In this situation, we don't want an idDelta: we already have a complete offset.