summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/lib/json-reader/json-reader.c
blob: 6561cf0d7bb73718e6636f436437dfaffc5649a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include "support/util.h"
#include "otfcc/font.h"
#include "table/all.h"

static otfcc_font_subtype otfcc_decideFontSubtypeFromJson(const json_value *root) {
	if (json_obj_get_type(root, "CFF_", json_object) != NULL) {
		return FONTTYPE_CFF;
	} else {
		return FONTTYPE_TTF;
	}
}

// The default glyph_order object is completed using a two-step construction
enum { ORD_GLYPHORDER = 1, ORD_NOTDEF = 2, ORD_CMAP = 3, ORD_GLYF = 4 };

// Register a name->(orderType, orderEntry) map.
static void setOrderByName(otfcc_GlyphOrder *go, sds name, uint8_t orderType, uint32_t orderEntry) {
	otfcc_GlyphOrderEntry *s = NULL;
	HASH_FIND(hhName, go->byName, name, sdslen(name), s);
	if (!s) {
		NEW(s);
		s->gid = -1;
		s->name = name;
		s->orderType = orderType;
		s->orderEntry = orderEntry;
		HASH_ADD(hhName, go->byName, name[0], sdslen(s->name), s);
	} else if (s->orderType > orderType) {
		s->orderType = orderType;
		s->orderEntry = orderEntry;
	}
}

static int _byOrder(otfcc_GlyphOrderEntry *a, otfcc_GlyphOrderEntry *b) {
	if (a->orderType < b->orderType) return (-1);
	if (a->orderType > b->orderType) return (1);
	if (a->orderEntry < b->orderEntry) return (-1);
	if (a->orderEntry > b->orderEntry) return (1);
	return 0;
}

// Complete ClyphOrder
static void orderGlyphs(otfcc_GlyphOrder *go) {
	HASH_SRT(hhName, go->byName, _byOrder);
	otfcc_GlyphOrderEntry *current, *temp;
	glyphid_t gid = 0;
	HASH_ITER(hhName, go->byName, current, temp) {
		current->gid = gid;
		HASH_ADD(hhID, go->byGID, gid, sizeof(glyphid_t), current);
		gid += 1;
	}
}

static void escalateGlyphOrderByName(otfcc_GlyphOrder *go, sds name, uint8_t orderType,
                                     uint32_t orderEntry) {
	otfcc_GlyphOrderEntry *s = NULL;
	HASH_FIND(hhName, go->byName, name, sdslen(name), s);
	if (s && s->orderType > orderType) {
		s->orderType = orderType;
		s->orderEntry = orderEntry;
	}
}

static void placeOrderEntriesFromGlyf(json_value *table, otfcc_GlyphOrder *go) {
	for (uint32_t j = 0; j < table->u.object.length; j++) {
		sds gname =
		    sdsnewlen(table->u.object.values[j].name, table->u.object.values[j].name_length);
		if (strcmp(gname, ".notdef") == 0) {
			setOrderByName(go, gname, ORD_NOTDEF, 0);
		} else if (strcmp(gname, ".null") == 0) {
			setOrderByName(go, gname, ORD_NOTDEF, 1);
		} else {
			setOrderByName(go, gname, ORD_GLYF, j);
		}
	}
}
static void placeOrderEntriesFromCmap(json_value *table, otfcc_GlyphOrder *go) {
	for (uint32_t j = 0; j < table->u.object.length; j++) {
		sds unicodeStr =
		    sdsnewlen(table->u.object.values[j].name, table->u.object.values[j].name_length);
		json_value *item = table->u.object.values[j].value;
		int32_t unicode;
		if (sdslen(unicodeStr) > 2 && unicodeStr[0] == 'U' && unicodeStr[1] == '+') {
			unicode = strtol(unicodeStr + 2, NULL, 16);
		} else {
			unicode = atoi(unicodeStr);
		}
		sdsfree(unicodeStr);
		if (item->type == json_string && unicode > 0 &&
		    unicode <= 0x10FFFF) { // a valid unicode codepoint
			sds gname = sdsnewlen(item->u.string.ptr, item->u.string.length);
			escalateGlyphOrderByName(go, gname, ORD_CMAP, unicode);
			sdsfree(gname);
		}
	}
}
static void placeOrderEntriesFromSubtable(json_value *table, otfcc_GlyphOrder *go, bool zeroOnly) {
	uint32_t uplimit = table->u.array.length;
	if (uplimit >= 1 && zeroOnly) { uplimit = 1; }
	for (uint32_t j = 0; j < uplimit; j++) {
		json_value *item = table->u.array.values[j];
		if (item->type == json_string) {
			sds gname = sdsnewlen(item->u.string.ptr, item->u.string.length);
			escalateGlyphOrderByName(go, gname, ORD_GLYPHORDER, j);
			sdsfree(gname);
		}
	}
}

static otfcc_GlyphOrder *parseGlyphOrder(const json_value *root, const otfcc_Options *options) {
	otfcc_GlyphOrder *go = GlyphOrder.create();
	if (root->type != json_object) return go;
	json_value *table;

	if ((table = json_obj_get_type(root, "glyf", json_object))) {
		placeOrderEntriesFromGlyf(table, go);
		if ((table = json_obj_get_type(root, "cmap", json_object))) {
			placeOrderEntriesFromCmap(table, go);
		}
		if ((table = json_obj_get_type(root, "glyph_order", json_array))) {
			bool ignoreGlyphOrder = options->ignore_glyph_order;
			if (ignoreGlyphOrder && !!json_obj_get_type(root, "SVG_", json_array)) {
				logNotice("OpenType SVG table detected. Glyph order is preserved.");
				ignoreGlyphOrder = false;
			}
			placeOrderEntriesFromSubtable(table, go, ignoreGlyphOrder);
		}
	}
	orderGlyphs(go);
	return go;
}

static otfcc_Font *readJson(void *_root, uint32_t index, const otfcc_Options *options) {
	const json_value *root = (json_value *)_root;
	otfcc_Font *font = otfcc_iFont.create();
	if (!font) return NULL;
	font->subtype = otfcc_decideFontSubtypeFromJson(root);
	font->glyph_order = parseGlyphOrder(root, options);
	font->glyf = otfcc_parseGlyf(root, font->glyph_order, options);
	font->CFF_ = otfcc_parseCFF(root, options);
	font->head = otfcc_parseHead(root, options);
	font->hhea = otfcc_parseHhea(root, options);
	font->OS_2 = otfcc_parseOS_2(root, options);
	font->maxp = otfcc_parseMaxp(root, options);
	font->post = otfcc_parsePost(root, options);
	font->name = otfcc_parseName(root, options);
	font->meta = otfcc_parseMeta(root, options);
	font->cmap = otfcc_parseCmap(root, options);
	if (!options->ignore_hints) {
		font->fpgm = otfcc_parseFpgmPrep(root, options, "fpgm");
		font->prep = otfcc_parseFpgmPrep(root, options, "prep");
		font->cvt_ = otfcc_parseCvt(root, options, "cvt_");
		font->gasp = otfcc_parseGasp(root, options);
	}
	font->VDMX = otfcc_parseVDMX(root, options);
	font->vhea = otfcc_parseVhea(root, options);
	if (font->glyf) {
		font->GSUB = otfcc_parseOtl(root, options, "GSUB");
		font->GPOS = otfcc_parseOtl(root, options, "GPOS");
		font->GDEF = otfcc_parseGDEF(root, options);
	}
	font->BASE = otfcc_parseBASE(root, options);
	font->CPAL = otfcc_parseCPAL(root, options);
	font->COLR = otfcc_parseCOLR(root, options);
	font->SVG_ = otfcc_parseSVG(root, options);

	font->TSI_01 = otfcc_parseTSI(root, options, "TSI_01");
	font->TSI_23 = otfcc_parseTSI(root, options, "TSI_23");
	font->TSI5 = otfcc_parseTSI5(root, options);

	return font;
}
static INLINE void freeReader(otfcc_IFontBuilder *self) {
	free(self);
}
otfcc_IFontBuilder *otfcc_newJsonReader() {
	otfcc_IFontBuilder *reader;
	NEW(reader);
	reader->read = readJson;
	reader->free = freeReader;
	return reader;
}