otl_ChainingRule *GeneralReadContextualRule(font_file_pointer data, uint32_t tableLength, uint32_t offset, uint16_t startGID, bool minusOne, CoverageReaderHandler fn, void *userdata) { otl_ChainingRule *rule; NEW(rule); rule->match = NULL; rule->apply = NULL; uint16_t minusOneQ = (minusOne ? 1 : 0); checkLength(offset + 4); uint16_t nInput = read_16u(data + offset); uint16_t nApply = read_16u(data + offset + 2); checkLength(offset + 4 + 2 * nInput + 4 * nApply); rule->matchCount = nInput; rule->inputBegins = 0; rule->inputEnds = nInput; NEW(rule->match, rule->matchCount); uint16_t jj = 0; if (minusOne) { rule->match[jj++] = fn(data, tableLength, startGID, offset, 2, userdata); } for (uint16_t j = 0; j < nInput - minusOneQ; j++) { uint32_t gid = read_16u(data + offset + 4 + j * 2); rule->match[jj++] = fn(data, tableLength, gid, offset, 2, userdata); } rule->applyCount = nApply; NEW(rule->apply, rule->applyCount); for (tableid_t j = 0; j < nApply; j++) { rule->apply[j].index = rule->inputBegins + read_16u(data + offset + 4 + 2 * (rule->matchCount - minusOneQ) + j * 4); rule->apply[j].lookup = Handle.fromIndex(read_16u(data + offset + 4 + 2 * (rule->matchCount - minusOneQ) + j * 4 + 2)); } reverseBacktracks(rule); return rule; FAIL: DELETE(deleteRule, rule); return NULL; }
static void parseLanguage(font_file_pointer data, uint32_t tableLength, uint32_t base, otl_LanguageSystem *lang, otl_FeatureList *features) { checkLength(base + 6); tableid_t rid = read_16u(data + base + 2); if (rid < features->length) { lang->requiredFeature = features->items[rid]; } else { lang->requiredFeature = NULL; } tableid_t featureCount = read_16u(data + base + 4); for (tableid_t j = 0; j < featureCount; j++) { tableid_t featureIndex = read_16u(data + base + 6 + 2 * j); if (featureIndex < features->length) { otl_iFeatureRefList.push(&lang->features, features->items[featureIndex]); } } return; FAIL: otl_iFeatureRefList.dispose(&lang->features); lang->requiredFeature = NULL; return; }
static subtable_chaining *readContextualFormat2(subtable_chaining *subtable, const font_file_pointer data, uint32_t tableLength, uint32_t offset) { // Contextual Substitution Subtable, Class based. checkLength(offset + 8); classdefs *cds; NEW(cds); cds->bc = NULL; cds->ic = ClassDef.read(data, tableLength, offset + read_16u(data + offset + 4)); cds->fc = NULL; tableid_t chainSubClassSetCnt = read_16u(data + offset + 6); checkLength(offset + 12 + 2 * chainSubClassSetCnt); tableid_t totalRules = 0; for (tableid_t j = 0; j < chainSubClassSetCnt; j++) { uint32_t srcOffset = read_16u(data + offset + 8 + j * 2); if (srcOffset) { totalRules += read_16u(data + offset + srcOffset); } } subtable->rulesCount = totalRules; NEW(subtable->rules, totalRules); tableid_t jj = 0; for (tableid_t j = 0; j < chainSubClassSetCnt; j++) { uint32_t srcOffset = read_16u(data + offset + 8 + j * 2); if (srcOffset) { tableid_t srsCount = read_16u(data + offset + srcOffset); for (tableid_t k = 0; k < srsCount; k++) { uint32_t srOffset = offset + srcOffset + read_16u(data + offset + srcOffset + 2 + k * 2); subtable->rules[jj] = GeneralReadContextualRule(data, tableLength, srOffset, j, true, classCoverage, cds); jj += 1; } } } if (cds) { if (cds->bc) ClassDef.free(cds->bc); if (cds->ic) ClassDef.free(cds->ic); if (cds->fc) ClassDef.free(cds->fc); FREE(cds); } return subtable; FAIL: iSubtable_chaining.free(subtable); return NULL; }
static subtable_chaining *readContextualFormat1(subtable_chaining *subtable, const font_file_pointer data, uint32_t tableLength, uint32_t offset) { // Contextual Substitution Subtable, Simple. checkLength(offset + 6); uint16_t covOffset = offset + read_16u(data + offset + 2); otl_Coverage *firstCoverage = Coverage.read(data, tableLength, covOffset); tableid_t chainSubRuleSetCount = read_16u(data + offset + 4); if (chainSubRuleSetCount != firstCoverage->numGlyphs) goto FAIL; checkLength(offset + 6 + 2 * chainSubRuleSetCount); tableid_t totalRules = 0; for (tableid_t j = 0; j < chainSubRuleSetCount; j++) { uint32_t srsOffset = offset + read_16u(data + offset + 6 + j * 2); checkLength(srsOffset + 2); totalRules += read_16u(data + srsOffset); checkLength(srsOffset + 2 + 2 * read_16u(data + srsOffset)); } subtable->rulesCount = totalRules; NEW(subtable->rules, totalRules); tableid_t jj = 0; for (tableid_t j = 0; j < chainSubRuleSetCount; j++) { uint32_t srsOffset = offset + read_16u(data + offset + 6 + j * 2); tableid_t srsCount = read_16u(data + srsOffset); for (tableid_t k = 0; k < srsCount; k++) { uint32_t srOffset = srsOffset + read_16u(data + srsOffset + 2 + k * 2); subtable->rules[jj] = GeneralReadContextualRule(data, tableLength, srOffset, firstCoverage->glyphs[j].index, true, singleCoverage, NULL); jj += 1; } } Coverage.free(firstCoverage); return subtable; FAIL: iSubtable_chaining.free(subtable); return NULL; }
otl_Subtable *otl_read_gsub_reverse(const font_file_pointer data, uint32_t tableLength, uint32_t offset, const otfcc_Options *options) { subtable_gsub_reverse *subtable = iSubtable_gsub_reverse.create(); checkLength(offset + 6); tableid_t nBacktrack = read_16u(data + offset + 4); checkLength(offset + 6 + nBacktrack * 2); tableid_t nForward = read_16u(data + offset + 6 + nBacktrack * 2); checkLength(offset + 8 + (nBacktrack + nForward) * 2); tableid_t nReplacement = read_16u(data + offset + 8 + (nBacktrack + nForward) * 2); checkLength(offset + 10 + (nBacktrack + nForward + nReplacement) * 2); subtable->matchCount = nBacktrack + nForward + 1; NEW(subtable->match, subtable->matchCount); subtable->inputIndex = nBacktrack; for (tableid_t j = 0; j < nBacktrack; j++) { uint32_t covOffset = offset + read_16u(data + offset + 6 + j * 2); subtable->match[j] = Coverage.read(data, tableLength, covOffset); } { uint32_t covOffset = offset + read_16u(data + offset + 2); subtable->match[subtable->inputIndex] = Coverage.read(data, tableLength, covOffset); if (nReplacement != subtable->match[subtable->inputIndex]->numGlyphs) goto FAIL; } for (tableid_t j = 0; j < nForward; j++) { uint32_t covOffset = offset + read_16u(data + offset + 8 + nBacktrack * 2 + j * 2); subtable->match[nBacktrack + 1 + j] = Coverage.read(data, tableLength, covOffset); } NEW(subtable->to); subtable->to->numGlyphs = nReplacement; NEW(subtable->to->glyphs, nReplacement); for (tableid_t j = 0; j < nReplacement; j++) { subtable->to->glyphs[j] = Handle.fromIndex(read_16u(data + offset + 10 + (nBacktrack + nForward + j) * 2)); } reverseBacktracks(subtable->match, subtable->inputIndex); return (otl_Subtable *)subtable; FAIL: iSubtable_gsub_reverse.free(subtable); return NULL; }
otl_Subtable *otl_read_contextual(const font_file_pointer data, uint32_t tableLength, uint32_t offset, const otfcc_Options *options) { uint16_t format = 0; subtable_chaining *subtable = iSubtable_chaining.create(); subtable->type = otl_chaining_poly; checkLength(offset + 2); format = read_16u(data + offset); if (format == 1) { return (otl_Subtable *)readContextualFormat1(subtable, data, tableLength, offset); } else if (format == 2) { return (otl_Subtable *)readContextualFormat2(subtable, data, tableLength, offset); } else if (format == 3) { // Contextual Substitution Subtable, Coverage based. subtable->rulesCount = 1; NEW(subtable->rules, 1); subtable->rules[0] = GeneralReadContextualRule(data, tableLength, offset + 2, 0, false, format3Coverage, NULL); return (otl_Subtable *)subtable; } FAIL: logWarning("Unsupported format %d.\n", format); iSubtable_chaining.free(subtable); return NULL; }
static table_OTL *otfcc_readOtl_common(font_file_pointer data, uint32_t tableLength, otl_LookupType lookup_type_base, const otfcc_Options *options) { table_OTL *table = table_iOTL.create(); if (!table) goto FAIL; checkLength(10); uint32_t scriptListOffset = read_16u(data + 4); checkLength(scriptListOffset + 2); uint32_t featureListOffset = read_16u(data + 6); checkLength(featureListOffset + 2); uint32_t lookupListOffset = read_16u(data + 8); checkLength(lookupListOffset + 2); // parse lookup list { tableid_t lookupCount = read_16u(data + lookupListOffset); checkLength(lookupListOffset + 2 + lookupCount * 2); for (tableid_t j = 0; j < lookupCount; j++) { otl_Lookup *lookup; otl_iLookupPtr.init(&lookup); lookup->_offset = lookupListOffset + read_16u(data + lookupListOffset + 2 + 2 * j); checkLength(lookup->_offset + 6); lookup->type = read_16u(data + lookup->_offset) + lookup_type_base; otl_iLookupList.push(&table->lookups, lookup); } } // parse feature list { tableid_t featureCount = read_16u(data + featureListOffset); checkLength(featureListOffset + 2 + featureCount * 6); tableid_t lnk = 0; for (tableid_t j = 0; j < featureCount; j++) { otl_Feature *feature; otl_iFeaturePtr.init(&feature); uint32_t tag = read_32u(data + featureListOffset + 2 + j * 6); if (options->glyph_name_prefix) { feature->name = sdscatprintf(sdsempty(), "%c%c%c%c_%s_%05d", (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xff, tag & 0xff, options->glyph_name_prefix, j); } else { feature->name = sdscatprintf(sdsempty(), "%c%c%c%c_%05d", (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xff, tag & 0xff, j); } uint32_t featureOffset = featureListOffset + read_16u(data + featureListOffset + 2 + j * 6 + 4); checkLength(featureOffset + 4); tableid_t lookupCount = read_16u(data + featureOffset + 2); checkLength(featureOffset + 4 + lookupCount * 2); for (tableid_t k = 0; k < lookupCount; k++) { tableid_t lookupid = read_16u(data + featureOffset + 4 + k * 2); if (lookupid < table->lookups.length) { otl_Lookup *lookup = table->lookups.items[lookupid]; if (!lookup->name) { if (options->glyph_name_prefix) { lookup->name = sdscatprintf(sdsempty(), "lookup_%s_%c%c%c%c_%d", options->glyph_name_prefix, (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xff, tag & 0xff, lnk++); } else { lookup->name = sdscatprintf(sdsempty(), "lookup_%c%c%c%c_%d", (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xff, tag & 0xff, lnk++); } }
otl_subtable *caryll_read_gsub_ligature(font_file_pointer data, uint32_t tableLength, uint32_t offset) { otl_subtable *_subtable; NEW(_subtable); subtable_gsub_ligature *subtable = &(_subtable->gsub_ligature); subtable->from = NULL; subtable->to = NULL; checkLength(offset + 6); otl_coverage *startCoverage = caryll_read_coverage(data, tableLength, offset + read_16u(data + offset + 2)); if (!startCoverage) goto FAIL; uint16_t setCount = read_16u(data + offset + 4); if (setCount != startCoverage->numGlyphs) goto FAIL; checkLength(offset + 6 + setCount * 2); uint32_t ligatureCount = 0; for (uint16_t j = 0; j < setCount; j++) { uint32_t setOffset = offset + read_16u(data + offset + 6 + j * 2); checkLength(setOffset + 2); ligatureCount += read_16u(data + setOffset); checkLength(setOffset + 2 + read_16u(data + setOffset) * 2); } NEW(subtable->to); subtable->to->numGlyphs = ligatureCount; NEW_N(subtable->to->glyphs, ligatureCount); NEW_N(subtable->from, ligatureCount); for (uint16_t j = 0; j < ligatureCount; j++) { subtable->from[j] = NULL; }; uint16_t jj = 0; for (uint16_t j = 0; j < setCount; j++) { uint32_t setOffset = offset + read_16u(data + offset + 6 + j * 2); uint16_t lc = read_16u(data + setOffset); for (uint16_t k = 0; k < lc; k++) { uint32_t ligOffset = setOffset + read_16u(data + setOffset + 2 + k * 2); checkLength(ligOffset + 4); uint16_t ligComponents = read_16u(data + ligOffset + 2); checkLength(ligOffset + 2 + ligComponents * 2); subtable->to->glyphs[jj].gid = read_16u(data + ligOffset); subtable->to->glyphs[jj].name = NULL; NEW(subtable->from[jj]); subtable->from[jj]->numGlyphs = ligComponents; NEW_N(subtable->from[jj]->glyphs, ligComponents); subtable->from[jj]->glyphs[0].gid = startCoverage->glyphs[j].gid; subtable->from[jj]->glyphs[0].name = NULL; for (uint16_t m = 1; m < ligComponents; m++) { subtable->from[jj]->glyphs[m].gid = read_16u(data + ligOffset + 2 + m * 2); subtable->from[jj]->glyphs[m].name = NULL; } jj++; } } caryll_delete_coverage(startCoverage); return _subtable; FAIL: deleteGSUBLigatureSubtable(_subtable); return NULL; }
#include "LTSH.h" #include "support/util.h" static INLINE void disposeLTSH(MOVE table_LTSH *ltsh) { if (ltsh) { FREE(ltsh->yPels); } } caryll_standardRefType(table_LTSH, table_iLTSH, disposeLTSH); table_LTSH *otfcc_readLTSH(const otfcc_Packet packet, const otfcc_Options *options) { FOR_TABLE('LTSH', table) { font_file_pointer data = table.data; table_LTSH *LTSH; NEW(LTSH); LTSH->version = read_16u(data); LTSH->numGlyphs = read_16u(data + 2); NEW(LTSH->yPels, LTSH->numGlyphs); memcpy(LTSH->yPels, data + 4, LTSH->numGlyphs); return LTSH; } return NULL; } caryll_Buffer *otfcc_buildLTSH(const table_LTSH *ltsh, const otfcc_Options *options) { caryll_Buffer *buf = bufnew(); if (!ltsh) return buf; bufwrite16b(buf, 0); bufwrite16b(buf, ltsh->numGlyphs); for (uint16_t j = 0; j < ltsh->numGlyphs; j++) { bufwrite8(buf, ltsh->yPels[j]);
#include "PCLT.h" table_PCLT *caryll_read_PCLT(caryll_packet packet) { FOR_TABLE('PCLT', table) { font_file_pointer data = table.data; table_PCLT *PCLT = (table_PCLT *)malloc(sizeof(table_PCLT) * 1); PCLT->version = read_32u(data); PCLT->FontNumber = read_32u(data + 4); PCLT->Pitch = read_16u(data + 8); PCLT->xHeight = read_16u(data + 10); PCLT->Style = read_16u(data + 12); PCLT->TypeFamily = read_16u(data + 14); PCLT->CapHeight = read_16u(data + 16); PCLT->SymbolSet = read_16u(data + 18); memcpy(PCLT->Typeface, data + 20, 16); memcpy(PCLT->CharacterComplement, data + 36, 8); memcpy(PCLT->FileName, data + 44, 6); PCLT->StrokeWeight = *(data + 50); PCLT->WidthType = *(data + 51); PCLT->SerifStyle = *(data + 52); PCLT->pad = 0; return PCLT; } return NULL; }