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
|
#include "gpos-single.h"
#include "gpos-common.h"
static void deleteGposSingleEntry(otl_GposSingleEntry *entry) {
Handle.dispose(&entry->target);
}
static caryll_ElementInterface(otl_GposSingleEntry) gss_typeinfo = {
.init = NULL, .copy = NULL, .dispose = deleteGposSingleEntry};
caryll_standardVectorImpl(subtable_gpos_single, otl_GposSingleEntry, gss_typeinfo,
iSubtable_gpos_single);
otl_Subtable *otl_read_gpos_single(const font_file_pointer data, uint32_t tableLength,
uint32_t offset, const glyphid_t maxGlyphs,
const otfcc_Options *options) {
subtable_gpos_single *subtable = iSubtable_gpos_single.create();
otl_Coverage *targets = NULL;
checkLength(offset + 6);
uint16_t subtableFormat = read_16u(data + offset);
targets = Coverage.read(data, tableLength, offset + read_16u(data + offset + 2));
if (!targets || targets->numGlyphs == 0) goto FAIL;
if (subtableFormat == 1) {
otl_PositionValue v =
read_gpos_value(data, tableLength, offset + 6, read_16u(data + offset + 4));
for (glyphid_t j = 0; j < targets->numGlyphs; j++) {
iSubtable_gpos_single.push(subtable,
((otl_GposSingleEntry){
.target = Handle.dup(targets->glyphs[j]), .value = v,
}));
}
} else {
uint16_t valueFormat = read_16u(data + offset + 4);
uint16_t valueCount = read_16u(data + offset + 6);
checkLength(offset + 8 + position_format_length(valueFormat) * valueCount);
if (valueCount != targets->numGlyphs) goto FAIL;
for (glyphid_t j = 0; j < targets->numGlyphs; j++) {
iSubtable_gpos_single.push(
subtable,
((otl_GposSingleEntry){
.target = Handle.dup(targets->glyphs[j]),
.value = read_gpos_value(data, tableLength,
offset + 8 + j * position_format_length(valueFormat),
valueFormat),
}));
}
}
if (targets) Coverage.free(targets);
return (otl_Subtable *)subtable;
FAIL:
if (targets) Coverage.free(targets);
iSubtable_gpos_single.free(subtable);
return NULL;
}
json_value *otl_gpos_dump_single(const otl_Subtable *_subtable) {
const subtable_gpos_single *subtable = &(_subtable->gpos_single);
json_value *st = json_object_new(subtable->length);
for (glyphid_t j = 0; j < subtable->length; j++) {
json_object_push(st, subtable->items[j].target.name,
gpos_dump_value(subtable->items[j].value));
}
return st;
}
otl_Subtable *otl_gpos_parse_single(const json_value *_subtable, const otfcc_Options *options) {
subtable_gpos_single *subtable = iSubtable_gpos_single.create();
for (glyphid_t j = 0; j < _subtable->u.object.length; j++) {
if (_subtable->u.object.values[j].value &&
_subtable->u.object.values[j].value->type == json_object) {
sds gname = sdsnewlen(_subtable->u.object.values[j].name,
_subtable->u.object.values[j].name_length);
iSubtable_gpos_single.push(
subtable, ((otl_GposSingleEntry){
.target = Handle.fromName(gname),
.value = gpos_parse_value(_subtable->u.object.values[j].value),
}));
}
}
return (otl_Subtable *)subtable;
}
caryll_Buffer *otfcc_build_gpos_single(const otl_Subtable *_subtable, otl_BuildHeuristics heuristics) {
const subtable_gpos_single *subtable = &(_subtable->gpos_single);
bool isConst = subtable->length > 0;
uint16_t format = 0;
if (subtable->length > 0) {
for (glyphid_t j = 0; j < subtable->length; j++) {
isConst = isConst && (subtable->items[j].value.dx == subtable->items[0].value.dx) &&
(subtable->items[j].value.dy == subtable->items[0].value.dy) &&
(subtable->items[j].value.dWidth == subtable->items[0].value.dWidth) &&
(subtable->items[j].value.dHeight == subtable->items[0].value.dHeight);
format |= required_position_format(subtable->items[j].value);
}
}
otl_Coverage *cov = Coverage.create();
for (glyphid_t j = 0; j < subtable->length; j++) {
Coverage.push(cov, Handle.dup(subtable->items[j].target));
}
caryll_Buffer *coverageBuf = Coverage.build(cov);
if (isConst) {
bk_Block *b =
(bk_new_Block(b16, 1, // Format
p16, bk_newBlockFromBuffer(coverageBuf), // coverage
b16, format, // format
bkembed, bk_gpos_value(subtable->items[0].value, format), // value
bkover));
Coverage.free(cov);
return bk_build_Block(b);
} else {
bk_Block *b = bk_new_Block(b16, 2, // Format
p16, bk_newBlockFromBuffer(coverageBuf), // coverage
b16, format, // format
b16, subtable->length, // quantity
bkover);
for (glyphid_t k = 0; k < subtable->length; k++) {
bk_push(b, bkembed, bk_gpos_value(subtable->items[k].value, format), // value
bkover);
}
Coverage.free(cov);
return bk_build_Block(b);
}
}
|