lib-font: Flaticon.woff2 is not parsing correctly.

Font

https://www.panoramicinfotech.com/wp-content/themes/engitech/fonts/Flaticon.woff2

Problem

table entries seem to resolve incorrectly.

Code

const font = new Font("flaticon");
font.onload = (evt) => testFont(evt.detail.font);
font.src = "./fonts/issue-114/Flaticon.woff2";

function testFont(font) {
  const { directory, tables } = font.opentype;
  console.log(directory);

  const nameEntry = directory.find(d => d.tag === `name`);
  console.log(nameEntry);

  const { name } = tables;
}

Results

Directory:

[
  Woff2TableDirectoryEntry {
    flags: 63,
    tagNumber: 63,
    tag: 'FFTM',
    transformVersion: 0,
    origLength: 28,
    offset: 0
  },
  Woff2TableDirectoryEntry {
    flags: 6,
    tagNumber: 6,
    tag: 'OS/2',
    transformVersion: 0,
    origLength: 96,
    offset: 28
  },
  Woff2TableDirectoryEntry {
    flags: 0,
    tagNumber: 0,
    tag: 'cmap',
    transformVersion: 0,
    origLength: 330,
    offset: 124
  },
  Woff2TableDirectoryEntry {
    flags: 8,
    tagNumber: 8,
    tag: 'cvt ',
    transformVersion: 0,
    origLength: 4,
    offset: 454
  },
  Woff2TableDirectoryEntry {
    flags: 17,
    tagNumber: 17,
    tag: 'gasp',
    transformVersion: 0,
    origLength: 8,
    offset: 458
  },
  Woff2TableDirectoryEntry {
    flags: 10,
    tagNumber: 10,
    tag: 'glyf',
    transformVersion: 0,
    origLength: 20836,
    transformLength: 16900,
    offset: 466
  },
  Woff2TableDirectoryEntry {
    flags: 11,
    tagNumber: 11,
    tag: 'loca',
    transformVersion: 0,
    origLength: 132,
    transformLength: 0,
    offset: 17366
  },
  Woff2TableDirectoryEntry {
    flags: 1,
    tagNumber: 1,
    tag: 'head',
    transformVersion: 0,
    origLength: 54,
    offset: 17498
  },
  Woff2TableDirectoryEntry {
    flags: 2,
    tagNumber: 2,
    tag: 'hhea',
    transformVersion: 0,
    origLength: 36,
    offset: 17552
  },
  Woff2TableDirectoryEntry {
    flags: 3,
    tagNumber: 3,
    tag: 'hmtx',
    transformVersion: 0,
    origLength: 140,
    offset: 17588
  },
  Woff2TableDirectoryEntry {
    flags: 4,
    tagNumber: 4,
    tag: 'maxp',
    transformVersion: 0,
    origLength: 32,
    offset: 17728
  },
  Woff2TableDirectoryEntry {
    flags: 5,
    tagNumber: 5,
    tag: 'name',
    transformVersion: 0,
    origLength: 447,
    offset: 17760
  },
  Woff2TableDirectoryEntry {
    flags: 7,
    tagNumber: 7,
    tag: 'post',
    transformVersion: 0,
    origLength: 895,
    offset: 18207
  }
]

Directory entry for name table:

Woff2TableDirectoryEntry {
  flags: 5,
  tagNumber: 5,
  tag: 'name',
  transformVersion: 0,
  origLength: 447,
  offset: 17760
}

Error when destructuring the name table itself:

parser getUint16 2 Parser {
  name: 'name',
  length: 447,
  start: 0,
  offset: 448,
  data: DataView {
    byteLength: 447,
    byteOffset: 0,
    buffer: ArrayBuffer {
      [Uint8Contents]: <00 03 00 4a 00 36 00 03 00 01 04 09 00 04 00 10 00 a8 00 03 00 01 04 09 00 05 00 20 00 c3 00 03 00 01 04 09 00 06 00 10 00 f6 00 
00 00 00 46 00 6c 00 61 00 74 00 69 00 63 00 6f 00 6e 00 00 46 6c 61 74 69 63 6f 6e 00 00 52 00 65 00 67 00 75 00 6c 00 61 00 72 00 00 52 65 67 75 6c 61 
72 00 00 46 00 6f ... 347 more bytes>,
      byteLength: 447
    }
  }
}
parser 0 448

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15 (15 by maintainers)

Most upvoted comments

Looking at our code for offset computation, we see:

    // parse the dictionary
    this.directory = [...new Array(this.numTables)].map(
      (_) => new Woff2TableDirectoryEntry(p)
    );
    let dictOffset = p.currentPosition; // = start of CompressedFontData block

    // compute table byte offsets in the decompressed data
    this.directory[0].offset = 0;
    this.directory.forEach((e, i) => {
      let next = this.directory[i + 1];
      if (next) {
        next.offset =
          e.offset + (e.transformLength ? e.transformLength : e.origLength);
      }
    });

and there’s our bug: e.transformLength is zero for the loca table, as per the WOFF2 spec, but zero is also a falsey value, and so the ternary does not do what we want: instead of adding 0 to the running offset tally, we incorrectly add the original length value (in this case, 132).

The fix is (of course) trivial:

    this.directory.forEach((e, i) => {
      let next = this.directory[i + 1];
      if (next) {
        next.offset =
          e.offset + (e.transformLength !== undefined ? e.transformLength : e.origLength);
      }
    });

That is, we use transformLength if it exists at all, not “if it’s truthy”.