📄 fofitruetype.cc
字号:
0, 0, // ySuperscriptXOffset 0, 0, // ySuperscriptYOffset 0, 0, // yStrikeoutSize 0, 0, // yStrikeoutPosition 0, 0, // sFamilyClass 0, 0, 0, 0, 0, // panose 0, 0, 0, 0, 0, 0, 0, 0, 0, // ulUnicodeRange1 0, 0, 0, 0, // ulUnicodeRange2 0, 0, 0, 0, // ulUnicodeRange3 0, 0, 0, 0, // ulUnicodeRange4 0, 0, 0, 0, // achVendID 0, 0, // fsSelection 0, 0, // usFirstCharIndex 0, 0, // usLastCharIndex 0, 0, // sTypoAscender 0, 0, // sTypoDescender 0, 0, // sTypoLineGap 0, 0, // usWinAscent 0, 0, // usWinDescent 0, 0, 0, 0, // ulCodePageRange1 0, 0, 0, 0 // ulCodePageRange2 }; GBool missingCmap, missingName, missingPost, missingOS2; GBool unsortedLoca, badCmapLen, abbrevHMTX; int nZeroLengthTables; int nHMetrics, advWidth, lsb; TrueTypeLoca *locaTable; TrueTypeTable *newTables; char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab; int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; int newHHEALen, newHMTXLen; Guint locaChecksum, glyfChecksum, fileChecksum; char *tableDir; char locaBuf[4], checksumBuf[4]; GBool ok; Guint t; int pos, i, j, k, n; if (openTypeCFF) { return; } // check for missing tables // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver // will embed a PCL TrueType font with the pitch field set to zero, // which apparently causes divide-by-zero errors. As far as I can // tell, the only important field in the OS/2 table is // xAvgCharWidth.) missingCmap = (cmapIdx = seekTable("cmap")) < 0; missingName = seekTable("name") < 0; missingPost = seekTable("post") < 0; missingOS2 = seekTable("OS/2") < 0; // read the loca table, check to see if it's sorted locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); unsortedLoca = gFalse; i = seekTable("loca"); pos = tables[i].offset; ok = gTrue; for (i = 0; i <= nGlyphs; ++i) { if (locaFmt) { locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); } else { locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); } if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { unsortedLoca = gTrue; } // glyph descriptions must be at least 12 bytes long (nContours, // xMin, yMin, xMax, yMax, instructionLength - two bytes each); // invalid glyph descriptions (even if they're never used) make // Windows choke, so we work around that problem here (ideally, // this would parse the glyph descriptions in the glyf table and // remove any that were invalid, but this quick test is a decent // start) if (i > 0 && locaTable[i].origOffset - locaTable[i-1].origOffset > 0 && locaTable[i].origOffset - locaTable[i-1].origOffset < 12) { locaTable[i-1].origOffset = locaTable[i].origOffset; unsortedLoca = gTrue; } locaTable[i].idx = i; } // check for zero-length tables nZeroLengthTables = 0; for (i = 0; i < nTables; ++i) { if (tables[i].len == 0) { ++nZeroLengthTables; } } // check for an incorrect cmap table length badCmapLen = gFalse; cmapLen = 0; // make gcc happy if (!missingCmap) { cmapLen = cmaps[0].offset + cmaps[0].len; for (i = 1; i < nCmaps; ++i) { if (cmaps[i].offset + cmaps[i].len > cmapLen) { cmapLen = cmaps[i].offset + cmaps[i].len; } } cmapLen -= tables[cmapIdx].offset; if (cmapLen > tables[cmapIdx].len) { badCmapLen = gTrue; } } // check for an abbreviated hmtx table (this is completely legal, // but confuses the Microsoft PCL5 printer driver, which generates // embedded fonts with the pitch field set to zero) i = seekTable("hhea"); nHMetrics = getU16BE(tables[i].offset + 34, &ok); abbrevHMTX = nHMetrics < nGlyphs; // if nothing is broken, just write the TTF file as is if (!missingCmap && !missingName && !missingPost && !missingOS2 && !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 && !name && !codeToGID) { (*outputFunc)(outputStream, (char *)file, len); goto done1; } // sort the 'loca' table: some (non-compliant) fonts have // out-of-order loca tables; in order to correctly handle the case // where (compliant) fonts have empty entries in the middle of the // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, // and idx as its secondary key (ensuring that adjacent entries with // the same pos value remain in the same order) glyfLen = 0; // make gcc happy if (unsortedLoca) { qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaOffset); for (i = 0; i < nGlyphs; ++i) { locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; } locaTable[nGlyphs].len = 0; qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx); pos = 0; for (i = 0; i <= nGlyphs; ++i) { locaTable[i].newOffset = pos; pos += locaTable[i].len; if (pos & 3) { pos += 4 - (pos & 3); } } glyfLen = pos; } // compute checksums for the loca and glyf tables locaChecksum = glyfChecksum = 0; if (unsortedLoca) { if (locaFmt) { for (j = 0; j <= nGlyphs; ++j) { locaChecksum += locaTable[j].newOffset; } } else { for (j = 0; j <= nGlyphs; j += 2) { locaChecksum += locaTable[j].newOffset << 16; if (j + 1 <= nGlyphs) { locaChecksum += locaTable[j+1].newOffset; } } } pos = tables[seekTable("glyf")].offset; for (j = 0; j < nGlyphs; ++j) { n = locaTable[j].len; if (n > 0) { k = locaTable[j].origOffset; if (checkRegion(pos + k, n)) { glyfChecksum += computeTableChecksum(file + pos + k, n); } } } } // construct the new name table if (name) { n = strlen(name); newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; newNameTab = (char *)gmalloc(newNameLen); memset(newNameTab, 0, newNameLen); newNameTab[0] = 0; // format selector newNameTab[1] = 0; newNameTab[2] = 0; // number of name records newNameTab[3] = 4; newNameTab[4] = 0; // offset to start of string storage newNameTab[5] = 6 + 4*12; next = 0; for (i = 0; i < 4; ++i) { newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft newNameTab[6 + i*12 + 1] = 3; newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode newNameTab[6 + i*12 + 3] = 1; newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English newNameTab[6 + i*12 + 5] = 0x09; newNameTab[6 + i*12 + 6] = 0; // name ID newNameTab[6 + i*12 + 7] = i + 1; newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); newNameTab[6 + i*12 + 10] = next >> 8; // string offset newNameTab[6 + i*12 + 11] = next & 0xff; if (i+1 == 2) { memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); next += 14; } else { for (j = 0; j < n; ++j) { newNameTab[6 + 4*12 + next + 2*j] = 0; newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; } next += 2*n; } } } else { newNameLen = 0; newNameTab = NULL; } // construct the new cmap table if (codeToGID) { newCmapLen = 44 + 256 * 2; newCmapTab = (char *)gmalloc(newCmapLen); newCmapTab[0] = 0; // table version number = 0 newCmapTab[1] = 0; newCmapTab[2] = 0; // number of encoding tables = 1 newCmapTab[3] = 1; newCmapTab[4] = 0; // platform ID = Microsoft newCmapTab[5] = 3; newCmapTab[6] = 0; // encoding ID = Unicode newCmapTab[7] = 1; newCmapTab[8] = 0; // offset of subtable newCmapTab[9] = 0; newCmapTab[10] = 0; newCmapTab[11] = 12; newCmapTab[12] = 0; // subtable format = 4 newCmapTab[13] = 4; newCmapTab[14] = 0x02; // subtable length newCmapTab[15] = 0x20; newCmapTab[16] = 0; // subtable version = 0 newCmapTab[17] = 0; newCmapTab[18] = 0; // segment count * 2 newCmapTab[19] = 4; newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) newCmapTab[21] = 4; newCmapTab[22] = 0; // floor(log2(segCount)) newCmapTab[23] = 1; newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) newCmapTab[25] = 0; newCmapTab[26] = 0x00; // endCount[0] newCmapTab[27] = (char)0xff; newCmapTab[28] = (char)0xff; // endCount[1] newCmapTab[29] = (char)0xff; newCmapTab[30] = 0; // reserved newCmapTab[31] = 0; newCmapTab[32] = 0x00; // startCount[0] newCmapTab[33] = 0x00; newCmapTab[34] = (char)0xff; // startCount[1] newCmapTab[35] = (char)0xff; newCmapTab[36] = 0; // idDelta[0] newCmapTab[37] = 0; newCmapTab[38] = 0; // idDelta[1] newCmapTab[39] = 1; newCmapTab[40] = 0; // idRangeOffset[0] newCmapTab[41] = 4; newCmapTab[42] = 0; // idRangeOffset[1] newCmapTab[43] = 0; for (i = 0; i < 256; ++i) { newCmapTab[44 + 2*i] = codeToGID[i] >> 8; newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; } } else { newCmapLen = 0; newCmapTab = NULL; } // generate the new hmtx table and the updated hhea table if (abbrevHMTX) { i = seekTable("hhea"); pos = tables[i].offset; newHHEALen = 36; newHHEATab = (char *)gmalloc(newHHEALen); for (i = 0; i < newHHEALen; ++i) { newHHEATab[i] = getU8(pos++, &ok); } newHHEATab[34] = nGlyphs >> 8; newHHEATab[35] = nGlyphs & 0xff; i = seekTable("hmtx"); pos = tables[i].offset; newHMTXLen = 4 * nGlyphs; newHMTXTab = (char *)gmalloc(newHMTXLen); advWidth = 0; for (i = 0; i < nHMetrics; ++i) { advWidth = getU16BE(pos, &ok); lsb = getU16BE(pos + 2, &ok); pos += 4; newHMTXTab[4*i ] = advWidth >> 8; newHMTXTab[4*i + 1] = advWidth & 0xff; newHMTXTab[4*i + 2] = lsb >> 8; newHMTXTab[4*i + 3] = lsb & 0xff; } for (; i < nGlyphs; ++i) { lsb = getU16BE(pos, &ok); pos += 2; newHMTXTab[4*i ] = advWidth >> 8; newHMTXTab[4*i + 1] = advWidth & 0xff; newHMTXTab[4*i + 2] = lsb >> 8; newHMTXTab[4*i + 3] = lsb & 0xff; } } else { newHHEATab = newHMTXTab = NULL; newHHEALen = newHMTXLen = 0; // make gcc happy } // construct the new table directory: // - keep all original tables with non-zero length // - fix the cmap table's length, if necessary // - add missing tables // - sort the table by tag // - compute new table positions, including 4-byte alignment // - (re)compute table checksums nNewTables = nTables - nZeroLengthTables + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0); newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); j = 0; for (i = 0; i < nTables; ++i) { if (tables[i].len > 0) { newTables[j] = tables[i]; newTables[j].origOffset = tables[i].offset; if (checkRegion(tables[i].offset, newTables[i].len)) { newTables[j].checksum = computeTableChecksum(file + tables[i].offset, tables[i].len); if (tables[i].tag == headTag) { // don't include the file checksum newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); } } if (newTables[j].tag == cmapTag && codeToGID) { newTables[j].len = newCmapLen; newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, newCmapLen); } else if (newTables[j].tag == cmapTag && badCmapLen) { newTables[j].len = cmapLen; } else if (newTables[j].tag == locaTag && unsortedLoca) { newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); newTables[j].checksum = locaChecksum; } else if (newTables[j].tag == glyfTag && unsortedLoca) { newTables[j].len = glyfLen; newTables[j].checksum = glyfChecksum; } else if (newTables[j].tag == nameTag && name) { newTables[j].len = newNameLen; newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, newNameLen); } else if (newTables[j].tag == hheaTag && abbrevHMTX) { newTables[j].len = newHHEALen; newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab, newHHEALen); } else if (newTables[j].tag == hmtxTag && abbrevHMTX) { newTables[j].len = newHMTXLen; newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab, newHMTXLen); } ++j; } } if (missingCmap) { newTables[j].tag = cmapTag; if (codeToGID) { newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, newCmapLen); newTables[j].len = newCmapLen; } else { newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, sizeof(cmapTab)); newTables[j].len = sizeof(cmapTab); } ++j; } if (missingName) { newTables[j].tag = nameTag; if (name) { newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, newNameLen); newTables[j].len = newNameLen; } else { newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, sizeof(nameTab)); newTables[j].len = sizeof(nameTab); } ++j; } if (missingPost) { newTables[j].tag = postTag; newTables[j].checksum = computeTableChecksum((Guchar *)postTab, sizeof(postTab)); newTables[j].len = sizeof(postTab); ++j; } if (missingOS2) { newTables[j].tag = os2Tag; newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab, sizeof(os2Tab)); newTables[j].len = sizeof(os2Tab); ++j;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -