| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* |
|
2
|
|
|
|
|
|
|
* pdfmake_font_widths.c — Glyph-advance + descriptor metrics resolution. |
|
3
|
|
|
|
|
|
|
* |
|
4
|
|
|
|
|
|
|
* PDF spec references: |
|
5
|
|
|
|
|
|
|
* §9.2.4 Simple font /FirstChar, /LastChar, /Widths |
|
6
|
|
|
|
|
|
|
* §9.7.4.3 CID /W array (formats 1 and 2), /DW default width |
|
7
|
|
|
|
|
|
|
* §9.8.1 Font descriptor /Ascent, /Descent, /CapHeight, /XHeight |
|
8
|
|
|
|
|
|
|
*/ |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#include "pdfmake_font_widths.h" |
|
11
|
|
|
|
|
|
|
#include "pdfmake_reader.h" |
|
12
|
|
|
|
|
|
|
#include "pdfmake_parser.h" |
|
13
|
|
|
|
|
|
|
#include "pdfmake_font.h" |
|
14
|
|
|
|
|
|
|
#include "pdfmake_arena.h" |
|
15
|
|
|
|
|
|
|
#include "pdfmake_buf.h" |
|
16
|
|
|
|
|
|
|
#include |
|
17
|
|
|
|
|
|
|
#include |
|
18
|
|
|
|
|
|
|
#include |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
/*============================================================================ |
|
21
|
|
|
|
|
|
|
* Helpers |
|
22
|
|
|
|
|
|
|
*==========================================================================*/ |
|
23
|
|
|
|
|
|
|
|
|
24
|
2518
|
|
|
|
|
|
static int16_t int_of(const pdfmake_obj_t *o, int16_t fallback) { |
|
25
|
2518
|
50
|
|
|
|
|
if (!o) return fallback; |
|
26
|
2518
|
50
|
|
|
|
|
if (o->kind == PDFMAKE_INT) return (int16_t)o->as.i; |
|
27
|
0
|
0
|
|
|
|
|
if (o->kind == PDFMAKE_REAL) return (int16_t)o->as.r; |
|
28
|
0
|
|
|
|
|
|
return fallback; |
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
|
|
31
|
90
|
|
|
|
|
|
static int32_t int32_of(const pdfmake_obj_t *o, int32_t fallback) { |
|
32
|
90
|
50
|
|
|
|
|
if (!o) return fallback; |
|
33
|
90
|
50
|
|
|
|
|
if (o->kind == PDFMAKE_INT) return (int32_t)o->as.i; |
|
34
|
0
|
0
|
|
|
|
|
if (o->kind == PDFMAKE_REAL) return (int32_t)o->as.r; |
|
35
|
0
|
|
|
|
|
|
return fallback; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
/*============================================================================ |
|
39
|
|
|
|
|
|
|
* Descriptor metrics |
|
40
|
|
|
|
|
|
|
*==========================================================================*/ |
|
41
|
|
|
|
|
|
|
|
|
42
|
0
|
|
|
|
|
|
static void fill_descriptor_metrics(pdfmake_arena_t *arena, |
|
43
|
|
|
|
|
|
|
pdfmake_obj_t *descriptor, |
|
44
|
|
|
|
|
|
|
pdfmake_font_widths_t *out) |
|
45
|
|
|
|
|
|
|
{ |
|
46
|
|
|
|
|
|
|
uint32_t ascent_k; |
|
47
|
|
|
|
|
|
|
uint32_t descent_k; |
|
48
|
|
|
|
|
|
|
uint32_t cap_k; |
|
49
|
|
|
|
|
|
|
uint32_t xh_k; |
|
50
|
|
|
|
|
|
|
uint32_t mw_k; |
|
51
|
|
|
|
|
|
|
pdfmake_obj_t *mw; |
|
52
|
0
|
0
|
|
|
|
|
if (!descriptor || descriptor->kind != PDFMAKE_DICT) return; |
|
|
|
0
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
|
|
54
|
0
|
|
|
|
|
|
ascent_k = pdfmake_arena_intern_name(arena, "Ascent", 6); |
|
55
|
0
|
|
|
|
|
|
descent_k = pdfmake_arena_intern_name(arena, "Descent", 7); |
|
56
|
0
|
|
|
|
|
|
cap_k = pdfmake_arena_intern_name(arena, "CapHeight", 9); |
|
57
|
0
|
|
|
|
|
|
xh_k = pdfmake_arena_intern_name(arena, "XHeight", 7); |
|
58
|
0
|
|
|
|
|
|
mw_k = pdfmake_arena_intern_name(arena, "MissingWidth", 12); |
|
59
|
|
|
|
|
|
|
|
|
60
|
0
|
|
|
|
|
|
out->ascent = int_of(pdfmake_dict_get(descriptor, ascent_k), out->ascent); |
|
61
|
0
|
|
|
|
|
|
out->descent = int_of(pdfmake_dict_get(descriptor, descent_k), out->descent); |
|
62
|
0
|
|
|
|
|
|
out->cap_height = int_of(pdfmake_dict_get(descriptor, cap_k), out->cap_height); |
|
63
|
0
|
|
|
|
|
|
out->x_height = int_of(pdfmake_dict_get(descriptor, xh_k), out->x_height); |
|
64
|
|
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
|
mw = pdfmake_dict_get(descriptor, mw_k); |
|
66
|
0
|
0
|
|
|
|
|
if (mw) out->default_width = int_of(mw, out->default_width); |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
/*============================================================================ |
|
70
|
|
|
|
|
|
|
* Simple font /Widths |
|
71
|
|
|
|
|
|
|
*==========================================================================*/ |
|
72
|
|
|
|
|
|
|
|
|
73
|
46
|
|
|
|
|
|
void pdfmake_font_widths_init(pdfmake_font_widths_t *w) { |
|
74
|
46
|
|
|
|
|
|
memset(w, 0, sizeof(*w)); |
|
75
|
46
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
|
|
77
|
45
|
|
|
|
|
|
int pdfmake_font_widths_from_simple( |
|
78
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
79
|
|
|
|
|
|
|
pdfmake_obj_t *font_dict, |
|
80
|
|
|
|
|
|
|
pdfmake_font_widths_t *out) |
|
81
|
|
|
|
|
|
|
{ |
|
82
|
|
|
|
|
|
|
uint32_t first_k; |
|
83
|
|
|
|
|
|
|
uint32_t last_k; |
|
84
|
|
|
|
|
|
|
uint32_t widths_k; |
|
85
|
|
|
|
|
|
|
uint32_t fd_k; |
|
86
|
|
|
|
|
|
|
pdfmake_obj_t *fd; |
|
87
|
|
|
|
|
|
|
pdfmake_obj_t *first; |
|
88
|
|
|
|
|
|
|
pdfmake_obj_t *last; |
|
89
|
|
|
|
|
|
|
pdfmake_obj_t *widths; |
|
90
|
|
|
|
|
|
|
int32_t fc; |
|
91
|
|
|
|
|
|
|
int32_t lc; |
|
92
|
|
|
|
|
|
|
size_t n; |
|
93
|
|
|
|
|
|
|
size_t have; |
|
94
|
|
|
|
|
|
|
int16_t *table; |
|
95
|
|
|
|
|
|
|
size_t i; |
|
96
|
|
|
|
|
|
|
|
|
97
|
45
|
|
|
|
|
|
pdfmake_font_widths_init(out); |
|
98
|
45
|
50
|
|
|
|
|
if (!font_dict || font_dict->kind != PDFMAKE_DICT || !arena) return -1; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
|
100
|
45
|
|
|
|
|
|
first_k = pdfmake_arena_intern_name(arena, "FirstChar", 9); |
|
101
|
45
|
|
|
|
|
|
last_k = pdfmake_arena_intern_name(arena, "LastChar", 8); |
|
102
|
45
|
|
|
|
|
|
widths_k = pdfmake_arena_intern_name(arena, "Widths", 6); |
|
103
|
45
|
|
|
|
|
|
fd_k = pdfmake_arena_intern_name(arena, "FontDescriptor", 14); |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
/* Always pull descriptor metrics even if /Widths is absent */ |
|
106
|
45
|
|
|
|
|
|
fd = pdfmake_dict_get(font_dict, fd_k); |
|
107
|
45
|
50
|
|
|
|
|
if (fd && fd->kind == PDFMAKE_DICT) { |
|
|
|
50
|
|
|
|
|
|
|
108
|
0
|
|
|
|
|
|
fill_descriptor_metrics(arena, fd, out); |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
45
|
|
|
|
|
|
first = pdfmake_dict_get(font_dict, first_k); |
|
112
|
45
|
|
|
|
|
|
last = pdfmake_dict_get(font_dict, last_k); |
|
113
|
45
|
|
|
|
|
|
widths = pdfmake_dict_get(font_dict, widths_k); |
|
114
|
|
|
|
|
|
|
|
|
115
|
45
|
50
|
|
|
|
|
if (!first || !last || !widths) return -1; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
116
|
45
|
50
|
|
|
|
|
if (widths->kind != PDFMAKE_ARRAY) return -1; |
|
117
|
|
|
|
|
|
|
|
|
118
|
45
|
|
|
|
|
|
fc = int32_of(first, -1); |
|
119
|
45
|
|
|
|
|
|
lc = int32_of(last, -1); |
|
120
|
45
|
50
|
|
|
|
|
if (fc < 0 || lc < fc || fc > 0xFFFF || lc > 0xFFFF) return -1; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
|
|
122
|
45
|
|
|
|
|
|
n = (size_t)(lc - fc + 1); |
|
123
|
45
|
|
|
|
|
|
have = pdfmake_array_len(widths); |
|
124
|
45
|
50
|
|
|
|
|
if (have < n) n = have; |
|
125
|
|
|
|
|
|
|
|
|
126
|
45
|
|
|
|
|
|
table = pdfmake_arena_alloc(arena, n * sizeof(int16_t)); |
|
127
|
45
|
50
|
|
|
|
|
if (!table) return -1; |
|
128
|
|
|
|
|
|
|
|
|
129
|
2563
|
100
|
|
|
|
|
for (i = 0; i < n; i++) { |
|
130
|
2518
|
|
|
|
|
|
pdfmake_obj_t *w = pdfmake_array_get(widths, i); |
|
131
|
2518
|
|
|
|
|
|
table[i] = int_of(w, 0); |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
45
|
|
|
|
|
|
out->table = table; |
|
135
|
45
|
|
|
|
|
|
out->first_char = (uint16_t)fc; |
|
136
|
45
|
|
|
|
|
|
out->last_char = (uint16_t)(fc + n - 1); |
|
137
|
45
|
|
|
|
|
|
return 0; |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
/*============================================================================ |
|
141
|
|
|
|
|
|
|
* CID font /W array |
|
142
|
|
|
|
|
|
|
* |
|
143
|
|
|
|
|
|
|
* Two entry formats, mixed freely in one array: |
|
144
|
|
|
|
|
|
|
* 1. first [ w1 w2 w3 ... ] codes first..first+n-1 have widths wi |
|
145
|
|
|
|
|
|
|
* 2. first last w codes first..last all have width w |
|
146
|
|
|
|
|
|
|
*==========================================================================*/ |
|
147
|
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
|
static int add_range(pdfmake_arena_t *arena, |
|
149
|
|
|
|
|
|
|
pdfmake_width_range_t **list, size_t *count, size_t *cap, |
|
150
|
|
|
|
|
|
|
uint32_t lo, uint32_t hi, int16_t w) |
|
151
|
|
|
|
|
|
|
{ |
|
152
|
|
|
|
|
|
|
pdfmake_width_range_t *r; |
|
153
|
0
|
0
|
|
|
|
|
if (*count >= *cap) { |
|
154
|
0
|
0
|
|
|
|
|
size_t new_cap = *cap ? *cap * 2 : 16; |
|
155
|
0
|
|
|
|
|
|
pdfmake_width_range_t *n = pdfmake_arena_alloc( |
|
156
|
|
|
|
|
|
|
arena, new_cap * sizeof(pdfmake_width_range_t)); |
|
157
|
0
|
0
|
|
|
|
|
if (!n) return -1; |
|
158
|
0
|
0
|
|
|
|
|
if (*list && *count > 0) { |
|
|
|
0
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
memcpy(n, *list, *count * sizeof(pdfmake_width_range_t)); |
|
160
|
|
|
|
|
|
|
} |
|
161
|
0
|
|
|
|
|
|
*list = n; |
|
162
|
0
|
|
|
|
|
|
*cap = new_cap; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
0
|
|
|
|
|
|
r = &(*list)[(*count)++]; |
|
165
|
0
|
|
|
|
|
|
r->lo = lo; |
|
166
|
0
|
|
|
|
|
|
r->hi = hi; |
|
167
|
0
|
|
|
|
|
|
r->width = w; |
|
168
|
0
|
|
|
|
|
|
return 0; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
|
|
171
|
0
|
|
|
|
|
|
static int range_cmp(const void *a, const void *b) { |
|
172
|
0
|
|
|
|
|
|
const pdfmake_width_range_t *ra = a; |
|
173
|
0
|
|
|
|
|
|
const pdfmake_width_range_t *rb = b; |
|
174
|
0
|
0
|
|
|
|
|
if (ra->lo < rb->lo) return -1; |
|
175
|
0
|
0
|
|
|
|
|
if (ra->lo > rb->lo) return 1; |
|
176
|
0
|
|
|
|
|
|
return 0; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
0
|
|
|
|
|
|
static int parse_w_array(pdfmake_arena_t *arena, |
|
180
|
|
|
|
|
|
|
pdfmake_obj_t *w_arr, |
|
181
|
|
|
|
|
|
|
pdfmake_font_widths_t *out) |
|
182
|
|
|
|
|
|
|
{ |
|
183
|
|
|
|
|
|
|
pdfmake_width_range_t *list; |
|
184
|
|
|
|
|
|
|
size_t count, cap; |
|
185
|
|
|
|
|
|
|
size_t n; |
|
186
|
|
|
|
|
|
|
size_t i; |
|
187
|
0
|
0
|
|
|
|
|
if (!w_arr || w_arr->kind != PDFMAKE_ARRAY) return -1; |
|
|
|
0
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
list = NULL; |
|
190
|
0
|
|
|
|
|
|
count = 0; cap = 0; |
|
191
|
0
|
|
|
|
|
|
n = pdfmake_array_len(w_arr); |
|
192
|
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
i = 0; |
|
194
|
0
|
0
|
|
|
|
|
while (i < n) { |
|
195
|
0
|
|
|
|
|
|
pdfmake_obj_t *first = pdfmake_array_get(w_arr, i++); |
|
196
|
0
|
|
|
|
|
|
int32_t fc = int32_of(first, -1); |
|
197
|
|
|
|
|
|
|
pdfmake_obj_t *next; |
|
198
|
0
|
0
|
|
|
|
|
if (fc < 0 || i >= n) break; |
|
|
|
0
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
|
|
200
|
0
|
|
|
|
|
|
next = pdfmake_array_get(w_arr, i); |
|
201
|
0
|
0
|
|
|
|
|
if (!next) break; |
|
202
|
|
|
|
|
|
|
|
|
203
|
0
|
0
|
|
|
|
|
if (next->kind == PDFMAKE_ARRAY) { |
|
204
|
|
|
|
|
|
|
/* Format 1: first [ w w w ... ] */ |
|
205
|
0
|
|
|
|
|
|
size_t m = pdfmake_array_len(next); |
|
206
|
|
|
|
|
|
|
size_t j; |
|
207
|
|
|
|
|
|
|
/* Expand as consecutive single-code ranges for uniform lookup. |
|
208
|
|
|
|
|
|
|
* Could compress runs of equal widths, but not worth the complexity. */ |
|
209
|
0
|
0
|
|
|
|
|
for (j = 0; j < m; j++) { |
|
210
|
0
|
|
|
|
|
|
int16_t w = int_of(pdfmake_array_get(next, j), 0); |
|
211
|
0
|
0
|
|
|
|
|
if (add_range(arena, &list, &count, &cap, |
|
212
|
|
|
|
|
|
|
(uint32_t)(fc + j), (uint32_t)(fc + j), w) < 0) { |
|
213
|
0
|
|
|
|
|
|
return -1; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
} |
|
216
|
0
|
|
|
|
|
|
i++; |
|
217
|
|
|
|
|
|
|
} else { |
|
218
|
|
|
|
|
|
|
/* Format 2: first last w */ |
|
219
|
0
|
|
|
|
|
|
int32_t lc = int32_of(next, fc); |
|
220
|
|
|
|
|
|
|
int16_t w; |
|
221
|
0
|
0
|
|
|
|
|
if (lc < fc) lc = fc; |
|
222
|
0
|
0
|
|
|
|
|
if (i + 1 >= n) break; |
|
223
|
0
|
|
|
|
|
|
w = int_of(pdfmake_array_get(w_arr, i + 1), 0); |
|
224
|
0
|
0
|
|
|
|
|
if (add_range(arena, &list, &count, &cap, |
|
225
|
|
|
|
|
|
|
(uint32_t)fc, (uint32_t)lc, w) < 0) { |
|
226
|
0
|
|
|
|
|
|
return -1; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
0
|
|
|
|
|
|
i += 2; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
} |
|
231
|
|
|
|
|
|
|
|
|
232
|
0
|
0
|
|
|
|
|
if (count > 1) qsort(list, count, sizeof(*list), range_cmp); |
|
233
|
0
|
|
|
|
|
|
out->ranges = list; |
|
234
|
0
|
|
|
|
|
|
out->range_count = count; |
|
235
|
0
|
|
|
|
|
|
return 0; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
|
|
238
|
1
|
|
|
|
|
|
int pdfmake_font_widths_from_cid( |
|
239
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
240
|
|
|
|
|
|
|
pdfmake_obj_t *font_dict, |
|
241
|
|
|
|
|
|
|
pdfmake_font_widths_t *out) |
|
242
|
|
|
|
|
|
|
{ |
|
243
|
|
|
|
|
|
|
uint32_t desc_k; |
|
244
|
|
|
|
|
|
|
pdfmake_obj_t *desc_arr; |
|
245
|
1
|
|
|
|
|
|
pdfmake_obj_t *cidfont = NULL; |
|
246
|
|
|
|
|
|
|
uint32_t w_k; |
|
247
|
|
|
|
|
|
|
uint32_t dw_k; |
|
248
|
|
|
|
|
|
|
uint32_t fd_k; |
|
249
|
|
|
|
|
|
|
pdfmake_obj_t *dw; |
|
250
|
|
|
|
|
|
|
pdfmake_obj_t *fd; |
|
251
|
|
|
|
|
|
|
pdfmake_obj_t *w_arr; |
|
252
|
|
|
|
|
|
|
|
|
253
|
1
|
|
|
|
|
|
pdfmake_font_widths_init(out); |
|
254
|
1
|
|
|
|
|
|
out->default_width = 1000; /* Per §9.7.4.3: /DW defaults to 1000 */ |
|
255
|
|
|
|
|
|
|
|
|
256
|
1
|
50
|
|
|
|
|
if (!font_dict || font_dict->kind != PDFMAKE_DICT || !arena) return -1; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
/* For Type0 fonts, widths live on /DescendantFonts[0] */ |
|
259
|
1
|
|
|
|
|
|
desc_k = pdfmake_arena_intern_name(arena, "DescendantFonts", 15); |
|
260
|
1
|
|
|
|
|
|
desc_arr = pdfmake_dict_get(font_dict, desc_k); |
|
261
|
1
|
50
|
|
|
|
|
if (desc_arr && desc_arr->kind == PDFMAKE_ARRAY && pdfmake_array_len(desc_arr) > 0) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
262
|
1
|
|
|
|
|
|
cidfont = pdfmake_array_get(desc_arr, 0); |
|
263
|
|
|
|
|
|
|
} |
|
264
|
1
|
50
|
|
|
|
|
if (!cidfont) cidfont = font_dict; /* Might already be the CIDFont */ |
|
265
|
1
|
50
|
|
|
|
|
if (cidfont->kind != PDFMAKE_DICT) return -1; |
|
266
|
|
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
w_k = pdfmake_arena_intern_name(arena, "W", 1); |
|
268
|
0
|
|
|
|
|
|
dw_k = pdfmake_arena_intern_name(arena, "DW", 2); |
|
269
|
0
|
|
|
|
|
|
fd_k = pdfmake_arena_intern_name(arena, "FontDescriptor", 14); |
|
270
|
|
|
|
|
|
|
|
|
271
|
0
|
|
|
|
|
|
dw = pdfmake_dict_get(cidfont, dw_k); |
|
272
|
0
|
0
|
|
|
|
|
if (dw) out->default_width = int_of(dw, out->default_width); |
|
273
|
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
|
fd = pdfmake_dict_get(cidfont, fd_k); |
|
275
|
0
|
0
|
|
|
|
|
if (fd && fd->kind == PDFMAKE_DICT) { |
|
|
|
0
|
|
|
|
|
|
|
276
|
0
|
|
|
|
|
|
fill_descriptor_metrics(arena, fd, out); |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
w_arr = pdfmake_dict_get(cidfont, w_k); |
|
280
|
0
|
0
|
|
|
|
|
if (w_arr) parse_w_array(arena, w_arr, out); |
|
281
|
|
|
|
|
|
|
|
|
282
|
0
|
|
|
|
|
|
return 0; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
/*============================================================================ |
|
286
|
|
|
|
|
|
|
* Lookup |
|
287
|
|
|
|
|
|
|
*==========================================================================*/ |
|
288
|
|
|
|
|
|
|
|
|
289
|
12698
|
|
|
|
|
|
int16_t pdfmake_font_widths_lookup(const pdfmake_font_widths_t *w, |
|
290
|
|
|
|
|
|
|
uint32_t code) |
|
291
|
|
|
|
|
|
|
{ |
|
292
|
12698
|
50
|
|
|
|
|
if (!w) return 0; |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
/* Simple font table */ |
|
295
|
12698
|
100
|
|
|
|
|
if (w->table && code >= w->first_char && code <= w->last_char) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
296
|
12692
|
|
|
|
|
|
int16_t v = w->table[code - w->first_char]; |
|
297
|
12692
|
50
|
|
|
|
|
if (v != 0) return v; |
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
/* CID range list — binary search */ |
|
301
|
6
|
50
|
|
|
|
|
if (w->ranges && w->range_count > 0) { |
|
|
|
0
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
size_t lo = 0, hi = w->range_count; |
|
303
|
|
|
|
|
|
|
/* Find last range with range.lo <= code */ |
|
304
|
0
|
0
|
|
|
|
|
while (lo < hi) { |
|
305
|
0
|
|
|
|
|
|
size_t mid = (lo + hi) / 2; |
|
306
|
0
|
0
|
|
|
|
|
if (w->ranges[mid].lo <= code) lo = mid + 1; |
|
307
|
0
|
|
|
|
|
|
else hi = mid; |
|
308
|
|
|
|
|
|
|
} |
|
309
|
0
|
0
|
|
|
|
|
if (lo > 0) { |
|
310
|
0
|
|
|
|
|
|
const pdfmake_width_range_t *r = &w->ranges[lo - 1]; |
|
311
|
0
|
0
|
|
|
|
|
if (code >= r->lo && code <= r->hi) return r->width; |
|
|
|
0
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
|
|
315
|
6
|
|
|
|
|
|
return w->default_width; |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
/*============================================================================ |
|
319
|
|
|
|
|
|
|
* Phase 6: Enhance widths from embedded /FontFile2 TTF data. |
|
320
|
|
|
|
|
|
|
*==========================================================================*/ |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
/* Resolve /FontFile2 (or /FontFile3) stream from a font descriptor. |
|
323
|
|
|
|
|
|
|
* Returns the decoded stream bytes (owned by `out_buf`) on success. */ |
|
324
|
0
|
|
|
|
|
|
static int fetch_font_file_stream( |
|
325
|
|
|
|
|
|
|
struct pdfmake_reader *reader, |
|
326
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
327
|
|
|
|
|
|
|
pdfmake_obj_t *descriptor, |
|
328
|
|
|
|
|
|
|
pdfmake_buf_t *out_buf) |
|
329
|
|
|
|
|
|
|
{ |
|
330
|
|
|
|
|
|
|
uint32_t ff2_k; |
|
331
|
|
|
|
|
|
|
uint32_t ff3_k; |
|
332
|
|
|
|
|
|
|
pdfmake_obj_t *ref; |
|
333
|
0
|
0
|
|
|
|
|
if (!descriptor || descriptor->kind != PDFMAKE_DICT) return -1; |
|
|
|
0
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
|
|
335
|
0
|
|
|
|
|
|
ff2_k = pdfmake_arena_intern_name(arena, "FontFile2", 9); |
|
336
|
0
|
|
|
|
|
|
ff3_k = pdfmake_arena_intern_name(arena, "FontFile3", 9); |
|
337
|
0
|
|
|
|
|
|
ref = pdfmake_dict_get(descriptor, ff2_k); |
|
338
|
0
|
0
|
|
|
|
|
if (!ref) ref = pdfmake_dict_get(descriptor, ff3_k); |
|
339
|
0
|
0
|
|
|
|
|
if (!ref || ref->kind != PDFMAKE_REF) return -1; |
|
|
|
0
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
|
|
341
|
0
|
|
|
|
|
|
return pdfmake_reader_resolve_stream(reader, ref->as.ref.num, |
|
342
|
0
|
|
|
|
|
|
ref->as.ref.gen, out_buf) == PDFMAKE_OK |
|
343
|
0
|
0
|
|
|
|
|
? 0 : -1; |
|
344
|
|
|
|
|
|
|
} |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
/* Parse /CIDToGIDMap. For /Identity (or missing), returns NULL and sets |
|
347
|
|
|
|
|
|
|
* is_identity=1. For a stream, returns a uint16_t[num_cids] array in arena. */ |
|
348
|
0
|
|
|
|
|
|
static uint16_t *resolve_cid_to_gid_map( |
|
349
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
350
|
|
|
|
|
|
|
struct pdfmake_reader *reader, |
|
351
|
|
|
|
|
|
|
pdfmake_obj_t *cidfont_dict, |
|
352
|
|
|
|
|
|
|
size_t *out_count, |
|
353
|
|
|
|
|
|
|
int *out_is_identity) |
|
354
|
|
|
|
|
|
|
{ |
|
355
|
|
|
|
|
|
|
uint32_t k; |
|
356
|
|
|
|
|
|
|
pdfmake_obj_t *m; |
|
357
|
|
|
|
|
|
|
pdfmake_buf_t buf; |
|
358
|
|
|
|
|
|
|
size_t count; |
|
359
|
|
|
|
|
|
|
uint16_t *map; |
|
360
|
|
|
|
|
|
|
const uint8_t *d; |
|
361
|
|
|
|
|
|
|
size_t i; |
|
362
|
|
|
|
|
|
|
|
|
363
|
0
|
|
|
|
|
|
*out_count = 0; |
|
364
|
0
|
|
|
|
|
|
*out_is_identity = 0; |
|
365
|
|
|
|
|
|
|
|
|
366
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "CIDToGIDMap", 11); |
|
367
|
0
|
|
|
|
|
|
m = pdfmake_dict_get(cidfont_dict, k); |
|
368
|
0
|
0
|
|
|
|
|
if (!m) { *out_is_identity = 1; return NULL; } |
|
369
|
|
|
|
|
|
|
|
|
370
|
0
|
0
|
|
|
|
|
if (m->kind == PDFMAKE_NAME) { |
|
371
|
|
|
|
|
|
|
/* /Identity is the only named form */ |
|
372
|
0
|
|
|
|
|
|
*out_is_identity = 1; |
|
373
|
0
|
|
|
|
|
|
return NULL; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
0
|
0
|
|
|
|
|
if (m->kind != PDFMAKE_REF) return NULL; |
|
377
|
|
|
|
|
|
|
|
|
378
|
0
|
0
|
|
|
|
|
if (pdfmake_buf_init(&buf) != PDFMAKE_OK) return NULL; |
|
379
|
0
|
0
|
|
|
|
|
if (pdfmake_reader_resolve_stream(reader, m->as.ref.num, m->as.ref.gen, &buf) |
|
380
|
|
|
|
|
|
|
!= PDFMAKE_OK) { |
|
381
|
0
|
|
|
|
|
|
pdfmake_buf_free(&buf); |
|
382
|
0
|
|
|
|
|
|
return NULL; |
|
383
|
|
|
|
|
|
|
} |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
/* Stream is a sequence of big-endian 2-byte GIDs indexed by CID */ |
|
386
|
0
|
|
|
|
|
|
count = pdfmake_buf_len(&buf) / 2; |
|
387
|
0
|
0
|
|
|
|
|
if (count == 0) { pdfmake_buf_free(&buf); return NULL; } |
|
388
|
|
|
|
|
|
|
|
|
389
|
0
|
|
|
|
|
|
map = pdfmake_arena_alloc(arena, count * sizeof(uint16_t)); |
|
390
|
0
|
0
|
|
|
|
|
if (!map) { pdfmake_buf_free(&buf); return NULL; } |
|
391
|
|
|
|
|
|
|
|
|
392
|
0
|
|
|
|
|
|
d = pdfmake_buf_data(&buf); |
|
393
|
0
|
0
|
|
|
|
|
for (i = 0; i < count; i++) { |
|
394
|
0
|
|
|
|
|
|
map[i] = ((uint16_t)d[i * 2] << 8) | d[i * 2 + 1]; |
|
395
|
|
|
|
|
|
|
} |
|
396
|
0
|
|
|
|
|
|
pdfmake_buf_free(&buf); |
|
397
|
0
|
|
|
|
|
|
*out_count = count; |
|
398
|
0
|
|
|
|
|
|
return map; |
|
399
|
|
|
|
|
|
|
} |
|
400
|
|
|
|
|
|
|
|
|
401
|
46
|
|
|
|
|
|
int pdfmake_font_widths_enhance_with_ttf( |
|
402
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
403
|
|
|
|
|
|
|
struct pdfmake_reader *reader, |
|
404
|
|
|
|
|
|
|
pdfmake_obj_t *font_dict, |
|
405
|
|
|
|
|
|
|
int is_cid, |
|
406
|
|
|
|
|
|
|
const uint32_t *byte_to_unicode, |
|
407
|
|
|
|
|
|
|
pdfmake_font_widths_t *out) |
|
408
|
|
|
|
|
|
|
{ |
|
409
|
|
|
|
|
|
|
pdfmake_obj_t *descriptor_owner; |
|
410
|
|
|
|
|
|
|
uint32_t fd_k; |
|
411
|
|
|
|
|
|
|
pdfmake_obj_t *descriptor; |
|
412
|
|
|
|
|
|
|
pdfmake_buf_t ttf_buf; |
|
413
|
|
|
|
|
|
|
pdfmake_ttf_t *ttf; |
|
414
|
|
|
|
|
|
|
|
|
415
|
46
|
50
|
|
|
|
|
if (!arena || !reader || !font_dict || !out) return -1; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
/* Find the font dict that owns the descriptor. For CID fonts, that's the |
|
418
|
|
|
|
|
|
|
* descendant CIDFont, not the Type0 wrapper. */ |
|
419
|
46
|
|
|
|
|
|
descriptor_owner = font_dict; |
|
420
|
46
|
100
|
|
|
|
|
if (is_cid) { |
|
421
|
1
|
|
|
|
|
|
uint32_t df_k = pdfmake_arena_intern_name(arena, "DescendantFonts", 15); |
|
422
|
1
|
|
|
|
|
|
pdfmake_obj_t *df_arr = pdfmake_dict_get(font_dict, df_k); |
|
423
|
2
|
50
|
|
|
|
|
if (df_arr && df_arr->kind == PDFMAKE_ARRAY && |
|
424
|
1
|
|
|
|
|
|
pdfmake_array_len(df_arr) > 0) { |
|
425
|
1
|
|
|
|
|
|
pdfmake_obj_t *cidfont = pdfmake_array_get(df_arr, 0); |
|
426
|
1
|
50
|
|
|
|
|
if (cidfont && cidfont->kind == PDFMAKE_DICT) { |
|
|
|
50
|
|
|
|
|
|
|
427
|
0
|
|
|
|
|
|
descriptor_owner = cidfont; |
|
428
|
|
|
|
|
|
|
} |
|
429
|
|
|
|
|
|
|
} |
|
430
|
|
|
|
|
|
|
} |
|
431
|
|
|
|
|
|
|
|
|
432
|
46
|
|
|
|
|
|
fd_k = pdfmake_arena_intern_name(arena, "FontDescriptor", 14); |
|
433
|
46
|
|
|
|
|
|
descriptor = pdfmake_dict_get(descriptor_owner, fd_k); |
|
434
|
46
|
100
|
|
|
|
|
if (!descriptor || descriptor->kind != PDFMAKE_DICT) return -1; |
|
|
|
50
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
|
|
436
|
0
|
0
|
|
|
|
|
if (pdfmake_buf_init(&ttf_buf) != PDFMAKE_OK) return -1; |
|
437
|
0
|
0
|
|
|
|
|
if (fetch_font_file_stream(reader, arena, descriptor, &ttf_buf) != 0) { |
|
438
|
0
|
|
|
|
|
|
pdfmake_buf_free(&ttf_buf); |
|
439
|
0
|
|
|
|
|
|
return -1; |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
|
|
442
|
0
|
|
|
|
|
|
ttf = pdfmake_ttf_parse(arena, |
|
443
|
|
|
|
|
|
|
pdfmake_buf_data(&ttf_buf), |
|
444
|
|
|
|
|
|
|
pdfmake_buf_len(&ttf_buf)); |
|
445
|
|
|
|
|
|
|
/* Note: pdfmake_ttf_parse may reference the input buffer internally. |
|
446
|
|
|
|
|
|
|
* We must keep ttf_buf alive for the lifetime of the TTF object. */ |
|
447
|
0
|
0
|
|
|
|
|
if (!ttf) { |
|
448
|
0
|
|
|
|
|
|
pdfmake_buf_free(&ttf_buf); |
|
449
|
0
|
|
|
|
|
|
return -1; |
|
450
|
|
|
|
|
|
|
} |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
/* Pull better ascent/descent from OS/2 if available */ |
|
453
|
0
|
0
|
|
|
|
|
if (ttf->has_os2 && ttf->units_per_em) { |
|
|
|
0
|
|
|
|
|
|
|
454
|
0
|
|
|
|
|
|
out->ascent = (int16_t)((int32_t)ttf->s_typo_ascender * 1000 / ttf->units_per_em); |
|
455
|
0
|
|
|
|
|
|
out->descent = (int16_t)((int32_t)ttf->s_typo_descender * 1000 / ttf->units_per_em); |
|
456
|
0
|
0
|
|
|
|
|
if (ttf->s_cap_height) |
|
457
|
0
|
|
|
|
|
|
out->cap_height = (int16_t)((int32_t)ttf->s_cap_height * 1000 / ttf->units_per_em); |
|
458
|
0
|
0
|
|
|
|
|
if (ttf->s_x_height) |
|
459
|
0
|
|
|
|
|
|
out->x_height = (int16_t)((int32_t)ttf->s_x_height * 1000 / ttf->units_per_em); |
|
460
|
0
|
0
|
|
|
|
|
} else if (ttf->units_per_em) { |
|
461
|
0
|
|
|
|
|
|
out->ascent = (int16_t)((int32_t)ttf->ascender * 1000 / ttf->units_per_em); |
|
462
|
0
|
|
|
|
|
|
out->descent = (int16_t)((int32_t)ttf->descender * 1000 / ttf->units_per_em); |
|
463
|
|
|
|
|
|
|
} |
|
464
|
|
|
|
|
|
|
|
|
465
|
0
|
0
|
|
|
|
|
if (is_cid) { |
|
466
|
|
|
|
|
|
|
/* Build a range list: CID -> advance via /CIDToGIDMap + hmtx. |
|
467
|
|
|
|
|
|
|
* Only populate CIDs that the map actually covers. */ |
|
468
|
0
|
|
|
|
|
|
size_t cid_count = 0; |
|
469
|
0
|
|
|
|
|
|
int is_identity = 0; |
|
470
|
|
|
|
|
|
|
uint16_t *cidmap; |
|
471
|
|
|
|
|
|
|
size_t new_cap; |
|
472
|
|
|
|
|
|
|
pdfmake_width_range_t *merged; |
|
473
|
|
|
|
|
|
|
size_t out_count; |
|
474
|
|
|
|
|
|
|
size_t cid; |
|
475
|
|
|
|
|
|
|
|
|
476
|
0
|
|
|
|
|
|
cidmap = resolve_cid_to_gid_map(arena, reader, descriptor_owner, |
|
477
|
|
|
|
|
|
|
&cid_count, &is_identity); |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
/* For Identity mapping, treat GID == CID up to num_glyphs. */ |
|
480
|
0
|
0
|
|
|
|
|
if (is_identity) { |
|
481
|
0
|
|
|
|
|
|
cid_count = ttf->num_glyphs; |
|
482
|
|
|
|
|
|
|
} |
|
483
|
0
|
0
|
|
|
|
|
if (!is_identity && !cidmap) { |
|
|
|
0
|
|
|
|
|
|
|
484
|
0
|
|
|
|
|
|
pdfmake_buf_free(&ttf_buf); |
|
485
|
0
|
|
|
|
|
|
return 0; /* metrics updated, widths unchanged */ |
|
486
|
|
|
|
|
|
|
} |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
/* Append TTF-derived widths to the existing range list, where they |
|
489
|
|
|
|
|
|
|
* fill gaps. For simplicity, emit one range per CID — the lookup |
|
490
|
|
|
|
|
|
|
* code binary-searches so O(log n) either way. |
|
491
|
|
|
|
|
|
|
* |
|
492
|
|
|
|
|
|
|
* Skip CIDs already covered by the PDF's /W array (PDF values win). */ |
|
493
|
0
|
|
|
|
|
|
new_cap = out->range_count + cid_count; |
|
494
|
0
|
|
|
|
|
|
merged = pdfmake_arena_alloc( |
|
495
|
|
|
|
|
|
|
arena, new_cap * sizeof(*merged)); |
|
496
|
0
|
0
|
|
|
|
|
if (!merged) { pdfmake_buf_free(&ttf_buf); return 0; } |
|
497
|
|
|
|
|
|
|
|
|
498
|
0
|
0
|
|
|
|
|
if (out->ranges && out->range_count) |
|
|
|
0
|
|
|
|
|
|
|
499
|
0
|
|
|
|
|
|
memcpy(merged, out->ranges, out->range_count * sizeof(*merged)); |
|
500
|
0
|
|
|
|
|
|
out_count = out->range_count; |
|
501
|
|
|
|
|
|
|
|
|
502
|
0
|
0
|
|
|
|
|
for (cid = 0; cid < cid_count; cid++) { |
|
503
|
0
|
0
|
|
|
|
|
uint16_t gid = is_identity ? (uint16_t)cid : cidmap[cid]; |
|
504
|
|
|
|
|
|
|
uint16_t w; |
|
505
|
|
|
|
|
|
|
int covered; |
|
506
|
|
|
|
|
|
|
size_t j; |
|
507
|
0
|
0
|
|
|
|
|
if (gid == 0) continue; |
|
508
|
0
|
|
|
|
|
|
w = pdfmake_ttf_glyph_advance(ttf, gid); |
|
509
|
0
|
0
|
|
|
|
|
if (w == 0) continue; |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
/* Check if CID is already in existing ranges */ |
|
512
|
0
|
|
|
|
|
|
covered = 0; |
|
513
|
0
|
0
|
|
|
|
|
for (j = 0; j < out->range_count; j++) { |
|
514
|
0
|
0
|
|
|
|
|
if (cid >= out->ranges[j].lo && cid <= out->ranges[j].hi) { |
|
|
|
0
|
|
|
|
|
|
|
515
|
0
|
|
|
|
|
|
covered = 1; |
|
516
|
0
|
|
|
|
|
|
break; |
|
517
|
|
|
|
|
|
|
} |
|
518
|
|
|
|
|
|
|
} |
|
519
|
0
|
0
|
|
|
|
|
if (covered) continue; |
|
520
|
|
|
|
|
|
|
|
|
521
|
0
|
|
|
|
|
|
merged[out_count].lo = (uint32_t)cid; |
|
522
|
0
|
|
|
|
|
|
merged[out_count].hi = (uint32_t)cid; |
|
523
|
0
|
|
|
|
|
|
merged[out_count].width = (int16_t)w; |
|
524
|
0
|
|
|
|
|
|
out_count++; |
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
/* Sort merged ranges for binary search */ |
|
528
|
0
|
0
|
|
|
|
|
if (out_count > 1) { |
|
529
|
0
|
|
|
|
|
|
qsort(merged, out_count, sizeof(*merged), range_cmp); |
|
530
|
|
|
|
|
|
|
} |
|
531
|
0
|
|
|
|
|
|
out->ranges = merged; |
|
532
|
0
|
|
|
|
|
|
out->range_count = out_count; |
|
533
|
|
|
|
|
|
|
} else { |
|
534
|
|
|
|
|
|
|
/* Simple font: populate a 256-entry table indexed by byte code. |
|
535
|
|
|
|
|
|
|
* charcode -> Unicode (from /Encoding) -> GID (from TTF cmap) |
|
536
|
|
|
|
|
|
|
* -> advance (from hmtx) |
|
537
|
|
|
|
|
|
|
* |
|
538
|
|
|
|
|
|
|
* Only overwrite entries that are currently 0 (unset by /Widths) — |
|
539
|
|
|
|
|
|
|
* PDF's declared /Widths array takes precedence. */ |
|
540
|
|
|
|
|
|
|
int16_t *table; |
|
541
|
|
|
|
|
|
|
uint16_t first; |
|
542
|
|
|
|
|
|
|
uint16_t last; |
|
543
|
|
|
|
|
|
|
size_t tbl_len; |
|
544
|
|
|
|
|
|
|
int code; |
|
545
|
0
|
0
|
|
|
|
|
if (!byte_to_unicode) { |
|
546
|
0
|
|
|
|
|
|
pdfmake_buf_free(&ttf_buf); |
|
547
|
0
|
|
|
|
|
|
return 0; |
|
548
|
|
|
|
|
|
|
} |
|
549
|
|
|
|
|
|
|
|
|
550
|
0
|
|
|
|
|
|
table = out->table; |
|
551
|
0
|
|
|
|
|
|
first = out->first_char; |
|
552
|
0
|
|
|
|
|
|
last = out->last_char; |
|
553
|
0
|
0
|
|
|
|
|
tbl_len = table ? (size_t)(last - first + 1) : 0; |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
/* If no existing table, allocate full 256-entry one */ |
|
556
|
0
|
0
|
|
|
|
|
if (!table) { |
|
557
|
0
|
|
|
|
|
|
table = pdfmake_arena_alloc(arena, 256 * sizeof(int16_t)); |
|
558
|
0
|
0
|
|
|
|
|
if (!table) { pdfmake_buf_free(&ttf_buf); return 0; } |
|
559
|
0
|
|
|
|
|
|
memset(table, 0, 256 * sizeof(int16_t)); |
|
560
|
0
|
|
|
|
|
|
first = 0; |
|
561
|
0
|
|
|
|
|
|
last = 255; |
|
562
|
0
|
|
|
|
|
|
tbl_len = 256; |
|
563
|
0
|
0
|
|
|
|
|
} else if (first > 0 || last < 255) { |
|
|
|
0
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
/* Expand to full 256-entry so we can cover the full byte range */ |
|
565
|
0
|
|
|
|
|
|
int16_t *expanded = pdfmake_arena_alloc(arena, 256 * sizeof(int16_t)); |
|
566
|
|
|
|
|
|
|
size_t i; |
|
567
|
0
|
0
|
|
|
|
|
if (!expanded) { pdfmake_buf_free(&ttf_buf); return 0; } |
|
568
|
0
|
|
|
|
|
|
memset(expanded, 0, 256 * sizeof(int16_t)); |
|
569
|
0
|
0
|
|
|
|
|
for (i = 0; i < tbl_len; i++) |
|
570
|
0
|
|
|
|
|
|
expanded[first + i] = table[i]; |
|
571
|
0
|
|
|
|
|
|
table = expanded; |
|
572
|
0
|
|
|
|
|
|
first = 0; |
|
573
|
0
|
|
|
|
|
|
last = 255; |
|
574
|
0
|
|
|
|
|
|
tbl_len = 256; |
|
575
|
|
|
|
|
|
|
} |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
/* Fill gaps from TTF */ |
|
578
|
0
|
0
|
|
|
|
|
for (code = 0; code < 256; code++) { |
|
579
|
|
|
|
|
|
|
uint32_t uni; |
|
580
|
|
|
|
|
|
|
uint16_t gid; |
|
581
|
|
|
|
|
|
|
uint16_t w; |
|
582
|
0
|
0
|
|
|
|
|
if (table[code] != 0) continue; /* honour PDF /Widths */ |
|
583
|
0
|
|
|
|
|
|
uni = byte_to_unicode[code]; |
|
584
|
0
|
0
|
|
|
|
|
if (uni == 0) continue; |
|
585
|
0
|
|
|
|
|
|
gid = pdfmake_ttf_cmap_lookup(ttf, uni); |
|
586
|
0
|
0
|
|
|
|
|
if (gid == 0) continue; |
|
587
|
0
|
|
|
|
|
|
w = pdfmake_ttf_glyph_advance(ttf, gid); |
|
588
|
0
|
0
|
|
|
|
|
if (w == 0) continue; |
|
589
|
0
|
|
|
|
|
|
table[code] = (int16_t)w; |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
|
|
592
|
0
|
|
|
|
|
|
out->table = table; |
|
593
|
0
|
|
|
|
|
|
out->first_char = first; |
|
594
|
0
|
|
|
|
|
|
out->last_char = last; |
|
595
|
|
|
|
|
|
|
} |
|
596
|
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
/* NB: ttf_buf backs the ttf->data pointer. Keeping it leaked-into-arena |
|
598
|
|
|
|
|
|
|
* isn't possible (buf uses malloc), but the TTF parse copied nothing. |
|
599
|
|
|
|
|
|
|
* For the simple font path we've already consumed all data via lookups, |
|
600
|
|
|
|
|
|
|
* so freeing here is safe. |
|
601
|
|
|
|
|
|
|
* |
|
602
|
|
|
|
|
|
|
* Actually: pdfmake_ttf_cmap_lookup walks ttf->data, so for the CID path |
|
603
|
|
|
|
|
|
|
* we might have read partial data if lookups happen after this function |
|
604
|
|
|
|
|
|
|
* returns. We therefore arena-copy the buffer first. |
|
605
|
|
|
|
|
|
|
* |
|
606
|
|
|
|
|
|
|
* Currently all TTF reads happen inside this function, so freeing is |
|
607
|
|
|
|
|
|
|
* safe. If that changes, hoist the memcpy-to-arena into parse above. */ |
|
608
|
0
|
|
|
|
|
|
pdfmake_buf_free(&ttf_buf); |
|
609
|
0
|
|
|
|
|
|
return 0; |
|
610
|
|
|
|
|
|
|
} |