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; }
PersonTime_Grid PersonTime_New(const double sigma[], int m, const double tau[], int n) { PersonTime_Grid result; int i, j; assert(m >= 2); assert(n >= 2); NEW(result); result->m = m - 1; result->n = n - 1; NEW_N(result->rect, result->m); for (i = 0; i < result->m; i++) { NEW_N(result->rect[i], result->n); for (j = 0; j < result->n; j++) { assert(sigma[i] < sigma[i + 1]); result->rect[i][j].sigmaMin = sigma[i]; result->rect[i][j].sigmaMax = sigma[i + 1]; assert(tau[j] < tau[j + 1]); result->rect[i][j].tauMin = tau[j]; result->rect[i][j].tauMax = tau[j + 1]; result->rect[i][j].personTime = 0.0; } } return result; }
otl_subtable *caryll_read_gpos_mark_to_ligature(font_file_pointer data, uint32_t tableLength, uint32_t offset) { otl_subtable *_subtable; NEW(_subtable); subtable_gpos_mark_to_ligature *subtable = &(_subtable->gpos_mark_to_ligature); if (tableLength < offset + 12) goto FAIL; subtable->marks = caryll_read_coverage(data, tableLength, offset + read_16u(data + offset + 2)); subtable->bases = caryll_read_coverage(data, tableLength, offset + read_16u(data + offset + 4)); if (!subtable->marks || subtable->marks->numGlyphs == 0 || !subtable->bases || subtable->bases->numGlyphs == 0) goto FAIL; subtable->classCount = read_16u(data + offset + 6); uint32_t markArrayOffset = offset + read_16u(data + offset + 8); subtable->markArray = otl_read_mark_array(data, tableLength, markArrayOffset); if (!subtable->markArray || subtable->markArray->markCount != subtable->marks->numGlyphs) goto FAIL; uint32_t ligArrayOffset = offset + read_16u(data + offset + 10); checkLength(ligArrayOffset + 2 + 2 * subtable->bases->numGlyphs); if (read_16u(data + ligArrayOffset) != subtable->bases->numGlyphs) goto FAIL; NEW_N(subtable->ligArray, subtable->bases->numGlyphs); for (uint16_t j = 0; j < subtable->bases->numGlyphs; j++) { subtable->ligArray[j] = NULL; } for (uint16_t j = 0; j < subtable->bases->numGlyphs; j++) { uint32_t ligAttachOffset = ligArrayOffset + read_16u(data + ligArrayOffset + 2 + j * 2); NEW(subtable->ligArray[j]); subtable->ligArray[j]->anchors = NULL; checkLength(ligAttachOffset + 2); subtable->ligArray[j]->componentCount = read_16u(data + ligAttachOffset); checkLength(ligAttachOffset + 2 + 2 * subtable->ligArray[j]->componentCount * subtable->classCount); NEW_N(subtable->ligArray[j]->anchors, subtable->ligArray[j]->componentCount); uint32_t _offset = ligAttachOffset + 2; for (uint16_t k = 0; k < subtable->ligArray[j]->componentCount; k++) { NEW_N(subtable->ligArray[j]->anchors[k], subtable->classCount); for (uint16_t m = 0; m < subtable->classCount; m++) { uint32_t anchorOffset = read_16u(data + _offset); if (anchorOffset) { subtable->ligArray[j]->anchors[k][m] = otl_read_anchor(data, tableLength, ligAttachOffset + anchorOffset); } else { subtable->ligArray[j]->anchors[k][m].present = false; subtable->ligArray[j]->anchors[k][m].x = 0; subtable->ligArray[j]->anchors[k][m].y = 0; } _offset += 2; } } } goto OK; FAIL: DELETE(delete_mtl_subtable, _subtable); OK: return _subtable; }
bool consolidate_gsub_single(caryll_font *font, table_otl *table, otl_subtable *_subtable, sds lookupName) { subtable_gsub_single *subtable = &(_subtable->gsub_single); consolidate_coverage(font, subtable->from, lookupName); consolidate_coverage(font, subtable->to, lookupName); uint16_t len = (subtable->from->numGlyphs < subtable->to->numGlyphs ? subtable->from->numGlyphs : subtable->from->numGlyphs); gsub_single_map_hash *h = NULL; for (uint16_t k = 0; k < len; k++) { if (subtable->from->glyphs[k].name && subtable->to->glyphs[k].name) { gsub_single_map_hash *s; int fromid = subtable->from->glyphs[k].gid; HASH_FIND_INT(h, &fromid, s); if (s) { fprintf(stderr, "[Consolidate] Double-mapping a glyph in a " "single substitution /%s.\n", subtable->from->glyphs[k].name); } else { NEW(s); s->fromid = subtable->from->glyphs[k].gid; s->toid = subtable->to->glyphs[k].gid; s->fromname = subtable->from->glyphs[k].name; s->toname = subtable->to->glyphs[k].name; HASH_ADD_INT(h, fromid, s); } } } HASH_SORT(h, by_from_id); if (HASH_COUNT(h) != subtable->from->numGlyphs || HASH_COUNT(h) != subtable->to->numGlyphs) { fprintf(stderr, "[Consolidate] In single subsitution lookup %s, some " "mappings are ignored.\n", lookupName); } subtable->from->numGlyphs = HASH_COUNT(h); subtable->to->numGlyphs = HASH_COUNT(h); FREE(subtable->from->glyphs); FREE(subtable->to->glyphs); NEW_N(subtable->from->glyphs, subtable->from->numGlyphs); NEW_N(subtable->to->glyphs, subtable->to->numGlyphs); { gsub_single_map_hash *s, *tmp; uint16_t j = 0; HASH_ITER(hh, h, s, tmp) { subtable->from->glyphs[j].gid = s->fromid; subtable->from->glyphs[j].name = s->fromname; subtable->to->glyphs[j].gid = s->toid; subtable->to->glyphs[j].name = s->toname; j++; HASH_DEL(h, s); free(s); } }
caryll_buffer *caryll_write_gsub_ligature_subtable(otl_subtable *_subtable) { caryll_buffer *buf = bufnew(); subtable_gsub_ligature *subtable = &(_subtable->gsub_ligature); ligature_aggerator *h = NULL, *s, *tmp; uint16_t nLigatures = subtable->to->numGlyphs; for (uint16_t j = 0; j < nLigatures; j++) { int sgid = subtable->from[j]->glyphs[0].gid; HASH_FIND_INT(h, &sgid, s); if (!s) { NEW(s); s->gid = sgid; s->ligid = HASH_COUNT(h); HASH_ADD_INT(h, gid, s); } } HASH_SORT(h, by_gid); otl_coverage *startCoverage; NEW(startCoverage); startCoverage->numGlyphs = HASH_COUNT(h); NEW_N(startCoverage->glyphs, startCoverage->numGlyphs); uint16_t jj = 0; foreach_hash(s, h) { s->ligid = jj; startCoverage->glyphs[jj].gid = s->gid; startCoverage->glyphs[jj].name = NULL; jj++; }
static void parseBases(json_value *_bases, subtable_gpos_mark_to_ligature *subtable, classname_hash **h) { uint16_t classCount = HASH_COUNT(*h); NEW(subtable->bases); subtable->bases->numGlyphs = _bases->u.object.length; NEW_N(subtable->bases->glyphs, subtable->bases->numGlyphs); NEW_N(subtable->ligArray, _bases->u.object.length); for (uint16_t j = 0; j < _bases->u.object.length; j++) { subtable->bases->glyphs[j].name = sdsnewlen(_bases->u.object.values[j].name, _bases->u.object.values[j].name_length); NEW(subtable->ligArray[j]); subtable->ligArray[j]->componentCount = 0; subtable->ligArray[j]->anchors = NULL; json_value *baseRecord = _bases->u.object.values[j].value; if (!baseRecord || baseRecord->type != json_array) continue; subtable->ligArray[j]->componentCount = baseRecord->u.array.length; NEW_N(subtable->ligArray[j]->anchors, subtable->ligArray[j]->componentCount); for (uint16_t k = 0; k < subtable->ligArray[j]->componentCount; k++) { json_value *_componentRecord = baseRecord->u.array.values[k]; NEW_N(subtable->ligArray[j]->anchors[k], classCount); for (uint16_t m = 0; m < classCount; m++) { subtable->ligArray[j]->anchors[k][m] = otl_anchor_absent(); } if (!_componentRecord || _componentRecord->type != json_object) { continue; } for (uint16_t m = 0; m < _componentRecord->u.object.length; m++) { sds className = sdsnewlen(_componentRecord->u.object.values[m].name, _componentRecord->u.object.values[m].name_length); classname_hash *s; HASH_FIND_STR(*h, className, s); if (!s) goto NEXT; subtable->ligArray[j]->anchors[k][s->classID] = otl_anchor_from_json(_componentRecord->u.object.values[m].value); NEXT: sdsfree(className); } } } }
otl_subtable *caryll_gsub_ligature_from_json(json_value *_subtable) { otl_subtable *_st; NEW(_st); subtable_gsub_ligature *st = &(_st->gsub_ligature); NEW(st->to); st->to->numGlyphs = _subtable->u.object.length; NEW_N(st->to->glyphs, st->to->numGlyphs); NEW_N(st->from, st->to->numGlyphs); uint16_t jj = 0; for (uint16_t k = 0; k < st->to->numGlyphs; k++) { json_value *_from = _subtable->u.object.values[k].value; if (!_from || _from->type != json_array) continue; st->to->glyphs[jj].name = sdsnewlen(_subtable->u.object.values[k].name, _subtable->u.object.values[k].name_length); st->from[jj] = caryll_coverage_from_json(_from); jj += 1; } st->to->numGlyphs = jj; return _st; }
static void parseMarks(json_value *_marks, subtable_gpos_mark_to_ligature *subtable, classname_hash **h) { NEW(subtable->marks); subtable->marks->numGlyphs = _marks->u.object.length; NEW_N(subtable->marks->glyphs, subtable->marks->numGlyphs); NEW(subtable->markArray); subtable->markArray->markCount = _marks->u.object.length; NEW_N(subtable->markArray->records, subtable->markArray->markCount); for (uint16_t j = 0; j < _marks->u.object.length; j++) { char *gname = _marks->u.object.values[j].name; json_value *anchorRecord = _marks->u.object.values[j].value; subtable->marks->glyphs[j].name = sdsnewlen(gname, _marks->u.object.values[j].name_length); subtable->markArray->records[j].markClass = 0; subtable->markArray->records[j].anchor = otl_anchor_absent(); if (!anchorRecord || anchorRecord->type != json_object) continue; json_value *_className = json_obj_get_type(anchorRecord, "class", json_string); if (!_className) continue; sds className = sdsnewlen(_className->u.string.ptr, _className->u.string.length); classname_hash *s; HASH_FIND_STR(*h, className, s); if (!s) { NEW(s); s->className = className; s->classID = HASH_COUNT(*h); HASH_ADD_STR(*h, className, s); } else { sdsfree(className); } subtable->markArray->records[j].markClass = s->classID; subtable->markArray->records[j].anchor.present = true; subtable->markArray->records[j].anchor.x = json_obj_getnum(anchorRecord, "x"); subtable->markArray->records[j].anchor.y = json_obj_getnum(anchorRecord, "y"); } }
int main(void) { t_set set; t_test *const nodes = NEW_N(t_test, TEST_SIZE); set = SET(&test_cmp, 0); { uint32_t i; uint32_t occur; i = 0; while (i < TEST_SIZE) { nodes[i] = TEST(ft_rand(-TEST_SIZE/2, TEST_SIZE/2)); occur = count_occur(&set, nodes[i].key); ft_set_insert(&set, &nodes[i], &nodes[i].key); ASSERT(occur == count_occur(&set, nodes[i].key) - 1, "INSERT ERROR"); i++; } } ASSERT(test_order_count(&set) == TEST_SIZE, "COUNT ERROR"); test_get(&set); test_begin(&set); ASSERT(max_height(set.root) <= min_height(set.root) * 2, "BALANCE ERROR"); TRACE("INSERT OK"); t_vec2u range; range.x = ft_rand(0, TEST_SIZE / 2); range.y = ft_rand(TEST_SIZE / 2, TEST_SIZE); { uint32_t i; uint32_t occur; i = range.x; while (i < range.y) { occur = count_occur(&set, nodes[i].key); ft_set_remove(&set, &nodes[i]); ASSERT(occur == count_occur(&set, nodes[i].key) + 1, "REMOVE ERROR"); i++; } } test_order_count(&set); test_get(&set); test_begin(&set); ASSERT(max_height(set.root) <= min_height(set.root) * 2, "BALANCE ERROR"); TRACE("REMOVE OK"); { uint32_t i; i = range.y; while (--i >= range.x) { nodes[i].key = range.x; ft_set_insert(&set, &nodes[i], &nodes[i].key); } } test_order_count(&set); test_get(&set); test_begin(&set); ASSERT(max_height(set.root) <= min_height(set.root) * 2, "BALANCE ERROR"); TRACE("INSERT REV SORTED OK"); { uint32_t i; i = 0; while (i < TEST_SIZE) { ft_set_remove(&set, &nodes[0]); nodes[0].key = i; ft_set_insert(&set, &nodes[0], &nodes[0].key); i++; } } test_order_count(&set); test_get(&set); test_begin(&set); ASSERT(max_height(set.root) <= min_height(set.root) * 2, "BALANCE ERROR"); TRACE("INSERT SORTED OK"); { #define DUP_COUNT 100000 uint32_t i; t_test *before; t_test *tmp; t_test *const insert = NEW_N(t_test, DUP_COUNT); before = ft_set_get(&set, &nodes[ft_rand(0, TEST_SIZE - 1)].key); i = 0; while (i < DUP_COUNT) { while ((tmp = ft_set_prev(before)) != NULL && tmp->key == before->key) before = tmp; insert[i] = TEST(before->key - 1); ft_set_insert_before(&set, &insert[i], before); tmp = ft_set_prev(before); ASSERT(tmp == &insert[i], "INSERT_BEFORE (prev) ERROR"); tmp = ft_set_next(&insert[i]); ASSERT(tmp == before, "INSERT_BEFORE (next) ERROR"); before = &insert[i]; i++; } } test_order_count(&set); test_get(&set); test_begin(&set); ASSERT(max_height(set.root) <= min_height(set.root) * 2, "BALANCE ERROR"); TRACE("INSERT_BEFORE OK"); // print_tree(set.root); // print_iter(&set); return (0); }