File Coverage

src/pdfmake_font_cff.c
Criterion Covered Total %
statement 0 486 0.0
branch 0 290 0.0
condition n/a
subroutine n/a
pod n/a
total 0 776 0.0


line stmt bran cond sub pod time code
1             /*
2             * pdfmake_font_cff.c - CFF (Compact Font Format) parser
3             *
4             * Parses CFF fonts (Type 2 charstrings) for glyph outlines.
5             * CFF is used in OpenType fonts with PostScript outlines.
6             *
7             * Reference:
8             * - Adobe Tech Note #5176 "CFF Font Format Specification"
9             * - Adobe Tech Note #5177 "Type 2 Charstring Format"
10             */
11              
12             #include "pdfmake_text.h"
13             #include "pdfmake_render.h"
14             #include "pdfmake_arena.h"
15             #include
16             #include
17             #include
18              
19             /*============================================================================
20             * CFF Structures
21             *==========================================================================*/
22              
23             /* CFF Index structure */
24             typedef struct {
25             uint16_t count;
26             uint8_t off_size;
27             const uint8_t *offsets;
28             const uint8_t *data;
29             } cff_index_t;
30              
31             /* CFF Dict entry types */
32             typedef enum {
33             CFF_INT,
34             CFF_REAL,
35             } cff_operand_type_t;
36              
37             typedef struct {
38             cff_operand_type_t type;
39             union {
40             int32_t i;
41             double f;
42             } val;
43             } cff_operand_t;
44              
45             /* CFF Font info */
46             typedef struct {
47             const uint8_t *data;
48             size_t len;
49            
50             /* Header */
51             uint8_t major;
52             uint8_t minor;
53             uint8_t hdr_size;
54             uint8_t off_size;
55            
56             /* Indices */
57             cff_index_t name_index;
58             cff_index_t top_dict_index;
59             cff_index_t string_index;
60             cff_index_t gsubr_index;
61            
62             /* Top DICT values */
63             int32_t charset_offset;
64             int32_t encoding_offset;
65             int32_t charstrings_offset;
66             int32_t private_offset;
67             int32_t private_size;
68             int32_t fdarray_offset;
69             int32_t fdselect_offset;
70            
71             /* CharStrings Index */
72             cff_index_t charstrings_index;
73            
74             /* Subrs Index (from Private DICT) */
75             cff_index_t subr_index;
76             int32_t subr_bias;
77             int32_t gsubr_bias;
78            
79             /* Font metrics */
80             double font_matrix[6];
81             double font_bbox[4];
82             uint16_t default_width;
83             uint16_t nominal_width;
84             } cff_font_t;
85              
86             /*============================================================================
87             * CFF Index Parsing
88             *==========================================================================*/
89              
90 0           static int parse_cff_index(const uint8_t *p, const uint8_t *end, cff_index_t *idx)
91             {
92             size_t offsets_size;
93             uint32_t last_offset;
94             const uint8_t *op;
95             int i;
96              
97 0 0         if (p + 2 > end) return -1;
98            
99 0           idx->count = ((uint16_t)p[0] << 8) | p[1];
100 0           p += 2;
101            
102 0 0         if (idx->count == 0) {
103 0           idx->off_size = 0;
104 0           idx->offsets = NULL;
105 0           idx->data = p;
106 0           return 2;
107             }
108            
109 0 0         if (p >= end) return -1;
110 0           idx->off_size = *p++;
111            
112 0 0         if (idx->off_size < 1 || idx->off_size > 4) return -1;
    0          
113            
114 0           offsets_size = (idx->count + 1) * idx->off_size;
115 0 0         if (p + offsets_size > end) return -1;
116            
117 0           idx->offsets = p;
118 0           p += offsets_size;
119            
120             /* Get data start (first offset should be 1) */
121 0           idx->data = p - 1; /* Offsets are 1-based */
122            
123             /* Calculate total size */
124 0           last_offset = 0;
125 0           op = idx->offsets + idx->count * idx->off_size;
126 0 0         for (i = 0; i < idx->off_size; i++) {
127 0           last_offset = (last_offset << 8) | op[i];
128             }
129            
130 0           return 3 + offsets_size + last_offset - 1;
131             }
132              
133 0           static uint32_t get_index_offset(const cff_index_t *idx, uint16_t i)
134             {
135             const uint8_t *p;
136             uint32_t offset;
137             int j;
138              
139 0 0         if (!idx || i > idx->count) return 0;
    0          
140            
141 0           p = idx->offsets + i * idx->off_size;
142 0           offset = 0;
143            
144 0 0         for (j = 0; j < idx->off_size; j++) {
145 0           offset = (offset << 8) | p[j];
146             }
147            
148 0           return offset;
149             }
150              
151 0           static const uint8_t *get_index_data(const cff_index_t *idx, uint16_t i,
152             size_t *out_len)
153             {
154             uint32_t start;
155             uint32_t end;
156              
157 0 0         if (!idx || i >= idx->count) return NULL;
    0          
158            
159 0           start = get_index_offset(idx, i);
160 0           end = get_index_offset(idx, i + 1);
161            
162 0 0         if (out_len) *out_len = end - start;
163 0           return idx->data + start;
164             }
165              
166             /*============================================================================
167             * CFF DICT Parsing
168             *==========================================================================*/
169              
170 0           static int parse_cff_dict_operand(const uint8_t **pp, const uint8_t *end,
171             cff_operand_t *op)
172             {
173             uint8_t b0;
174             double rval;
175             int exp;
176             int frac_digits;
177             int in_frac;
178             int negative;
179             int exp_negative;
180             int done;
181             int n;
182             int i;
183             int32_t val;
184              
185 0 0         if (*pp >= end) return -1;
186            
187 0           b0 = *(*pp)++;
188            
189 0 0         if (b0 == 30) {
190             /* Real number */
191 0           op->type = CFF_REAL;
192             /* Parse BCD-encoded real - simplified */
193 0           rval = 0;
194 0           exp = 0;
195 0           frac_digits = 0;
196 0           in_frac = 0;
197 0           negative = 0;
198 0           exp_negative = 0;
199 0           done = 0;
200            
201 0 0         while (*pp < end && !done) {
    0          
202 0           uint8_t byte = *(*pp)++;
203 0 0         for (n = 0; n < 2 && !done; n++) {
    0          
204 0 0         int nibble = (n == 0) ? (byte >> 4) : (byte & 0xF);
205              
206 0           switch (nibble) {
207 0           case 0x0: case 0x1: case 0x2: case 0x3: case 0x4:
208             case 0x5: case 0x6: case 0x7: case 0x8: case 0x9:
209 0 0         if (in_frac) {
210 0           rval = rval * 10 + nibble;
211 0           frac_digits++;
212             } else {
213 0           rval = rval * 10 + nibble;
214             }
215 0           break;
216 0           case 0xA: /* . */
217 0           in_frac = 1;
218 0           break;
219 0           case 0xB: /* E+ */
220 0           break;
221 0           case 0xC: /* E- */
222 0           exp_negative = 1;
223 0           break;
224 0           case 0xE: /* - */
225 0           negative = 1;
226 0           break;
227 0           case 0xF: /* end */
228 0           done = 1;
229 0           break;
230             }
231             }
232             }
233            
234 0 0         for (i = 0; i < frac_digits; i++) {
235 0           rval /= 10.0;
236             }
237 0 0         if (negative) rval = -rval;
238 0 0         if (exp_negative) exp = -exp;
239 0           rval *= pow(10.0, exp);
240            
241 0           op->val.f = rval;
242 0           return 0;
243             }
244            
245             /* Integer */
246 0           op->type = CFF_INT;
247            
248 0 0         if (b0 >= 32 && b0 <= 246) {
    0          
249 0           val = b0 - 139;
250 0 0         } else if (b0 >= 247 && b0 <= 250) {
    0          
251 0 0         if (*pp >= end) return -1;
252 0           val = (b0 - 247) * 256 + *(*pp)++ + 108;
253 0 0         } else if (b0 >= 251 && b0 <= 254) {
    0          
254 0 0         if (*pp >= end) return -1;
255 0           val = -(b0 - 251) * 256 - *(*pp)++ - 108;
256 0 0         } else if (b0 == 28) {
257 0 0         if (*pp + 2 > end) return -1;
258 0           val = ((int16_t)(*pp)[0] << 8) | (*pp)[1];
259 0           *pp += 2;
260 0 0         } else if (b0 == 29) {
261 0 0         if (*pp + 4 > end) return -1;
262 0           val = ((int32_t)(*pp)[0] << 24) | ((int32_t)(*pp)[1] << 16) |
263 0           ((int32_t)(*pp)[2] << 8) | (*pp)[3];
264 0           *pp += 4;
265             } else {
266 0           return -1; /* Operator, not operand */
267             }
268            
269 0           op->val.i = val;
270 0           return 0;
271             }
272              
273             /*============================================================================
274             * Type 2 CharString Interpreter
275             *==========================================================================*/
276              
277             #define T2_STACK_MAX 48
278             #define T2_TRANS_MAX 32
279              
280             typedef struct {
281             pdfmake_path_t *path;
282             pdfmake_arena_t *arena;
283            
284             /* Operand stack */
285             double stack[T2_STACK_MAX];
286             int sp;
287            
288             /* Current point */
289             double x, y;
290            
291             /* Hints (ignored for outline) */
292             int num_hints;
293            
294             /* Width */
295             int width_parsed;
296             double width;
297            
298             /* Subroutines */
299             const cff_font_t *font;
300            
301             /* Call depth */
302             int depth;
303             } t2_state_t;
304              
305             static int t2_execute(t2_state_t *st, const uint8_t *cs, size_t len);
306              
307 0           static void t2_push(t2_state_t *st, double val)
308             {
309 0 0         if (st->sp < T2_STACK_MAX) {
310 0           st->stack[st->sp++] = val;
311             }
312 0           }
313              
314 0           static double t2_pop(t2_state_t *st)
315             {
316 0 0         return (st->sp > 0) ? st->stack[--st->sp] : 0;
317             }
318              
319 0           static void t2_rmoveto(t2_state_t *st)
320             {
321             double dx;
322             double dy;
323              
324 0 0         if (st->sp < 2) return;
325            
326 0           dy = t2_pop(st);
327 0           dx = t2_pop(st);
328            
329 0           st->x += dx;
330 0           st->y += dy;
331            
332 0           pdfmake_path_move_to(st->path, st->x, st->y);
333             }
334              
335 0           static void t2_rlineto(t2_state_t *st)
336             {
337             int i;
338 0 0         while (st->sp >= 2) {
339 0           double dx = st->stack[0];
340 0           double dy = st->stack[1];
341            
342 0           st->x += dx;
343 0           st->y += dy;
344            
345 0           pdfmake_path_line_to(st->path, st->x, st->y);
346            
347             /* Shift stack */
348 0 0         for (i = 2; i < st->sp; i++) {
349 0           st->stack[i-2] = st->stack[i];
350             }
351 0           st->sp -= 2;
352             }
353 0           }
354              
355 0           static void t2_rrcurveto(t2_state_t *st)
356             {
357             int i;
358 0 0         while (st->sp >= 6) {
359 0           double dx1 = st->stack[0];
360 0           double dy1 = st->stack[1];
361 0           double dx2 = st->stack[2];
362 0           double dy2 = st->stack[3];
363 0           double dx3 = st->stack[4];
364 0           double dy3 = st->stack[5];
365            
366 0           double x1 = st->x + dx1;
367 0           double y1 = st->y + dy1;
368 0           double x2 = x1 + dx2;
369 0           double y2 = y1 + dy2;
370 0           double x3 = x2 + dx3;
371 0           double y3 = y2 + dy3;
372            
373 0           pdfmake_path_curve_to(st->path, x1, y1, x2, y2, x3, y3);
374            
375 0           st->x = x3;
376 0           st->y = y3;
377            
378             /* Shift stack */
379 0 0         for (i = 6; i < st->sp; i++) {
380 0           st->stack[i-6] = st->stack[i];
381             }
382 0           st->sp -= 6;
383             }
384 0           }
385              
386 0           static int t2_execute(t2_state_t *st, const uint8_t *cs, size_t len)
387             {
388 0           const uint8_t *p = cs;
389 0           const uint8_t *end = cs + len;
390             int i;
391             int subr_num;
392             size_t subr_len;
393             const uint8_t *subr;
394             int32_t ival;
395             int consumed;
396            
397 0 0         while (p < end) {
398 0           uint8_t op = *p++;
399            
400             /* Operands */
401 0 0         if (op >= 32) {
402             double val;
403 0 0         if (op >= 32 && op <= 246) {
    0          
404 0           val = op - 139;
405 0 0         } else if (op >= 247 && op <= 250) {
    0          
406 0 0         if (p >= end) return -1;
407 0           val = (op - 247) * 256 + *p++ + 108;
408 0 0         } else if (op >= 251 && op <= 254) {
    0          
409 0 0         if (p >= end) return -1;
410 0           val = -(op - 251) * 256 - *p++ - 108;
411 0 0         } else if (op == 255) {
412 0 0         if (p + 4 > end) return -1;
413 0           ival = ((int32_t)p[0] << 24) | ((int32_t)p[1] << 16) |
414 0           ((int32_t)p[2] << 8) | p[3];
415 0           val = ival / 65536.0;
416 0           p += 4;
417 0 0         } else if (op == 28) {
418 0 0         if (p + 2 > end) return -1;
419 0           val = ((int16_t)p[0] << 8) | p[1];
420 0           p += 2;
421             } else {
422 0           return -1;
423             }
424 0           t2_push(st, val);
425 0           continue;
426             }
427            
428             /* Operators */
429 0           switch (op) {
430 0           case 1: case 3: /* hstem, vstem */
431             case 18: case 23: /* hstemhm, vstemhm */
432             /* Parse width if first */
433 0 0         if (!st->width_parsed && (st->sp & 1)) {
    0          
434 0           st->width = st->stack[0];
435 0 0         for (i = 1; i < st->sp; i++) {
436 0           st->stack[i-1] = st->stack[i];
437             }
438 0           st->sp--;
439 0           st->width_parsed = 1;
440             }
441 0           st->num_hints += st->sp / 2;
442 0           st->sp = 0;
443 0           break;
444            
445 0           case 4: /* vmoveto */
446 0 0         if (!st->width_parsed && st->sp > 1) {
    0          
447 0           st->width = st->stack[0];
448 0           st->stack[0] = st->stack[1];
449 0           st->sp--;
450 0           st->width_parsed = 1;
451             }
452 0           st->width_parsed = 1;
453 0           st->x += 0;
454 0           st->y += t2_pop(st);
455 0           pdfmake_path_move_to(st->path, st->x, st->y);
456 0           break;
457            
458 0           case 5: /* rlineto */
459 0           t2_rlineto(st);
460 0           break;
461            
462 0           case 6: /* hlineto */
463 0 0         while (st->sp > 0) {
464 0           st->x += t2_pop(st);
465 0           pdfmake_path_line_to(st->path, st->x, st->y);
466 0 0         if (st->sp > 0) {
467 0           st->y += t2_pop(st);
468 0           pdfmake_path_line_to(st->path, st->x, st->y);
469             }
470             }
471 0           break;
472            
473 0           case 7: /* vlineto */
474 0 0         while (st->sp > 0) {
475 0           st->y += t2_pop(st);
476 0           pdfmake_path_line_to(st->path, st->x, st->y);
477 0 0         if (st->sp > 0) {
478 0           st->x += t2_pop(st);
479 0           pdfmake_path_line_to(st->path, st->x, st->y);
480             }
481             }
482 0           break;
483            
484 0           case 8: /* rrcurveto */
485 0           t2_rrcurveto(st);
486 0           break;
487            
488 0           case 10: { /* callsubr */
489 0 0         if (st->sp < 1 || st->depth >= T2_TRANS_MAX) break;
    0          
490 0           subr_num = (int)t2_pop(st) + st->font->subr_bias;
491 0           subr = get_index_data(&st->font->subr_index,
492             subr_num, &subr_len);
493 0 0         if (subr) {
494 0           st->depth++;
495 0           t2_execute(st, subr, subr_len);
496 0           st->depth--;
497             }
498 0           break;
499             }
500            
501 0           case 11: /* return */
502 0           return 0;
503            
504 0           case 14: /* endchar */
505 0 0         if (!st->width_parsed && st->sp > 0) {
    0          
506 0           st->width = st->stack[0];
507             }
508 0           pdfmake_path_close(st->path);
509 0           return 0;
510            
511 0           case 19: case 20: /* hintmask, cntrmask */
512 0 0         if (!st->width_parsed && (st->sp & 1)) {
    0          
513 0           st->width = st->stack[0];
514 0           st->sp--;
515 0           st->width_parsed = 1;
516             }
517 0           st->num_hints += st->sp / 2;
518 0           st->sp = 0;
519             /* Skip hint mask bytes */
520 0           p += (st->num_hints + 7) / 8;
521 0           break;
522            
523 0           case 21: /* rmoveto */
524 0 0         if (!st->width_parsed && st->sp > 2) {
    0          
525 0           st->width = st->stack[0];
526 0           st->stack[0] = st->stack[1];
527 0           st->stack[1] = st->stack[2];
528 0           st->sp--;
529 0           st->width_parsed = 1;
530             }
531 0           st->width_parsed = 1;
532 0           t2_rmoveto(st);
533 0           break;
534            
535 0           case 22: /* hmoveto */
536 0 0         if (!st->width_parsed && st->sp > 1) {
    0          
537 0           st->width = st->stack[0];
538 0           st->stack[0] = st->stack[1];
539 0           st->sp--;
540 0           st->width_parsed = 1;
541             }
542 0           st->width_parsed = 1;
543 0           st->x += t2_pop(st);
544 0           pdfmake_path_move_to(st->path, st->x, st->y);
545 0           break;
546            
547 0           case 24: /* rcurveline */
548 0 0         while (st->sp >= 8) {
549 0           t2_rrcurveto(st);
550             }
551 0           t2_rlineto(st);
552 0           break;
553            
554 0           case 25: /* rlinecurve */
555 0 0         while (st->sp >= 8) {
556 0           t2_rlineto(st);
557             }
558 0           t2_rrcurveto(st);
559 0           break;
560            
561 0           case 26: /* vvcurveto */
562 0 0         if (st->sp & 1) {
563 0           st->x += st->stack[0];
564 0 0         for (i = 1; i < st->sp; i++) {
565 0           st->stack[i-1] = st->stack[i];
566             }
567 0           st->sp--;
568             }
569 0 0         while (st->sp >= 4) {
570 0           double dy1 = st->stack[0];
571 0           double dx2 = st->stack[1];
572 0           double dy2 = st->stack[2];
573 0           double dy3 = st->stack[3];
574            
575 0           double x1 = st->x;
576 0           double y1 = st->y + dy1;
577 0           double x2 = x1 + dx2;
578 0           double y2 = y1 + dy2;
579 0           double x3 = x2;
580 0           double y3 = y2 + dy3;
581            
582 0           pdfmake_path_curve_to(st->path, x1, y1, x2, y2, x3, y3);
583 0           st->x = x3;
584 0           st->y = y3;
585            
586 0 0         for (i = 4; i < st->sp; i++) {
587 0           st->stack[i-4] = st->stack[i];
588             }
589 0           st->sp -= 4;
590             }
591 0           break;
592            
593 0           case 27: /* hhcurveto */
594 0 0         if (st->sp & 1) {
595 0           st->y += st->stack[0];
596 0 0         for (i = 1; i < st->sp; i++) {
597 0           st->stack[i-1] = st->stack[i];
598             }
599 0           st->sp--;
600             }
601 0 0         while (st->sp >= 4) {
602 0           double dx1 = st->stack[0];
603 0           double dx2 = st->stack[1];
604 0           double dy2 = st->stack[2];
605 0           double dx3 = st->stack[3];
606            
607 0           double x1 = st->x + dx1;
608 0           double y1 = st->y;
609 0           double x2 = x1 + dx2;
610 0           double y2 = y1 + dy2;
611 0           double x3 = x2 + dx3;
612 0           double y3 = y2;
613            
614 0           pdfmake_path_curve_to(st->path, x1, y1, x2, y2, x3, y3);
615 0           st->x = x3;
616 0           st->y = y3;
617            
618 0 0         for (i = 4; i < st->sp; i++) {
619 0           st->stack[i-4] = st->stack[i];
620             }
621 0           st->sp -= 4;
622             }
623 0           break;
624            
625 0           case 29: { /* callgsubr */
626 0 0         if (st->sp < 1 || st->depth >= T2_TRANS_MAX) break;
    0          
627 0           subr_num = (int)t2_pop(st) + st->font->gsubr_bias;
628 0           subr = get_index_data(&st->font->gsubr_index,
629             subr_num, &subr_len);
630 0 0         if (subr) {
631 0           st->depth++;
632 0           t2_execute(st, subr, subr_len);
633 0           st->depth--;
634             }
635 0           break;
636             }
637            
638 0           case 30: /* vhcurveto */
639             case 31: /* hvcurveto */
640             /* Alternating curves */
641             {
642 0           int start_v = (op == 30);
643 0 0         while (st->sp >= 4) {
644 0           double d1 = st->stack[0];
645 0           double d2 = st->stack[1];
646 0           double d3 = st->stack[2];
647 0           double d4 = st->stack[3];
648 0 0         double d5 = (st->sp == 5) ? st->stack[4] : 0;
649            
650             double x1, y1, x2, y2, x3, y3;
651            
652 0 0         if (start_v) {
653 0           x1 = st->x;
654 0           y1 = st->y + d1;
655 0           x2 = x1 + d2;
656 0           y2 = y1 + d3;
657 0           x3 = x2 + d4;
658 0           y3 = y2 + d5;
659             } else {
660 0           x1 = st->x + d1;
661 0           y1 = st->y;
662 0           x2 = x1 + d2;
663 0           y2 = y1 + d3;
664 0           x3 = x2 + d5;
665 0           y3 = y2 + d4;
666             }
667            
668 0           pdfmake_path_curve_to(st->path, x1, y1, x2, y2, x3, y3);
669 0           st->x = x3;
670 0           st->y = y3;
671            
672 0 0         consumed = (st->sp == 5) ? 5 : 4;
673 0 0         for (i = consumed; i < st->sp; i++) {
674 0           st->stack[i-consumed] = st->stack[i];
675             }
676 0           st->sp -= consumed;
677 0           start_v = !start_v;
678             }
679             }
680 0           break;
681            
682 0           case 12: /* escape */
683 0 0         if (p >= end) return -1;
684 0           op = *p++;
685             /* Handle two-byte operators - most not needed for outlines */
686 0           break;
687            
688 0           default:
689             /* Unknown operator - skip */
690 0           break;
691             }
692             }
693            
694 0           return 0;
695             }
696              
697             /*============================================================================
698             * CFF Parsing
699             *==========================================================================*/
700              
701 0           static int compute_subr_bias(int count)
702             {
703 0 0         if (count < 1240) return 107;
704 0 0         if (count < 33900) return 1131;
705 0           return 32768;
706             }
707              
708 0           static int parse_cff_font(const uint8_t *data, size_t len, cff_font_t *font)
709             {
710             const uint8_t *p;
711             const uint8_t *end;
712             int size;
713             size_t dict_len;
714             const uint8_t *dict;
715             const uint8_t *dp;
716             const uint8_t *dict_end;
717             cff_operand_t operands[48];
718             int num_operands;
719             int i;
720             const uint8_t *cs_start;
721             const uint8_t *priv;
722             const uint8_t *priv_end;
723             int32_t subrs_offset;
724             const uint8_t *subrs;
725              
726 0           memset(font, 0, sizeof(*font));
727 0           font->data = data;
728 0           font->len = len;
729            
730 0 0         if (len < 4) return -1;
731            
732             /* Parse header */
733 0           font->major = data[0];
734 0           font->minor = data[1];
735 0           font->hdr_size = data[2];
736 0           font->off_size = data[3];
737            
738 0 0         if (font->major != 1) return -1; /* Only CFF version 1 */
739            
740 0           p = data + font->hdr_size;
741 0           end = data + len;
742            
743             /* Parse Name INDEX */
744 0           size = parse_cff_index(p, end, &font->name_index);
745 0 0         if (size < 0) return -1;
746 0           p += size;
747            
748             /* Parse Top DICT INDEX */
749 0           size = parse_cff_index(p, end, &font->top_dict_index);
750 0 0         if (size < 0) return -1;
751 0           p += size;
752            
753             /* Parse String INDEX */
754 0           size = parse_cff_index(p, end, &font->string_index);
755 0 0         if (size < 0) return -1;
756 0           p += size;
757            
758             /* Parse Global Subr INDEX */
759 0           size = parse_cff_index(p, end, &font->gsubr_index);
760 0 0         if (size < 0) return -1;
761            
762 0           font->gsubr_bias = compute_subr_bias(font->gsubr_index.count);
763            
764             /* Parse Top DICT to find CharStrings offset */
765 0           dict = get_index_data(&font->top_dict_index, 0, &dict_len);
766 0 0         if (!dict) return -1;
767            
768             /* Default values */
769 0           font->font_matrix[0] = 0.001;
770 0           font->font_matrix[1] = 0;
771 0           font->font_matrix[2] = 0;
772 0           font->font_matrix[3] = 0.001;
773 0           font->font_matrix[4] = 0;
774 0           font->font_matrix[5] = 0;
775            
776             /* Parse Top DICT entries */
777 0           dp = dict;
778 0           dict_end = dict + dict_len;
779 0           num_operands = 0;
780            
781 0 0         while (dp < dict_end) {
782 0           uint8_t b = *dp;
783            
784 0 0         if (b >= 32 || b == 28 || b == 29 || b == 30) {
    0          
    0          
    0          
785             /* Operand */
786 0 0         if (num_operands < 48) {
787 0 0         if (parse_cff_dict_operand(&dp, dict_end,
788             &operands[num_operands]) == 0) {
789 0           num_operands++;
790             }
791             }
792             } else {
793             /* Operator */
794 0           dp++;
795            
796 0 0         if (b == 12 && dp < dict_end) {
    0          
797             /* Two-byte operator */
798 0           uint8_t b2 = *dp++;
799            
800 0 0         if (b2 == 7 && num_operands >= 6) {
    0          
801             /* FontMatrix */
802 0 0         for (i = 0; i < 6; i++) {
803 0           font->font_matrix[i] = (operands[i].type == CFF_REAL) ?
804 0 0         operands[i].val.f : operands[i].val.i;
805             }
806             }
807             } else {
808 0           switch (b) {
809 0           case 15: /* charset */
810 0 0         if (num_operands > 0) {
811 0           font->charset_offset = operands[0].val.i;
812             }
813 0           break;
814 0           case 16: /* Encoding */
815 0 0         if (num_operands > 0) {
816 0           font->encoding_offset = operands[0].val.i;
817             }
818 0           break;
819 0           case 17: /* CharStrings */
820 0 0         if (num_operands > 0) {
821 0           font->charstrings_offset = operands[0].val.i;
822             }
823 0           break;
824 0           case 18: /* Private */
825 0 0         if (num_operands >= 2) {
826 0           font->private_size = operands[0].val.i;
827 0           font->private_offset = operands[1].val.i;
828             }
829 0           break;
830             }
831             }
832 0           num_operands = 0;
833             }
834             }
835            
836             /* Parse CharStrings INDEX */
837 0 0         if (font->charstrings_offset > 0) {
838 0           cs_start = data + font->charstrings_offset;
839 0           parse_cff_index(cs_start, end, &font->charstrings_index);
840             }
841            
842             /* Parse Private DICT for Subrs */
843 0 0         if (font->private_offset > 0 && font->private_size > 0) {
    0          
844 0           priv = data + font->private_offset;
845 0           priv_end = priv + font->private_size;
846            
847 0           num_operands = 0;
848 0 0         while (priv < priv_end) {
849 0           uint8_t b = *priv;
850            
851 0 0         if (b >= 32 || b == 28 || b == 29 || b == 30) {
    0          
    0          
    0          
852 0 0         if (num_operands < 48) {
853 0           parse_cff_dict_operand(&priv, priv_end,
854 0           &operands[num_operands++]);
855             }
856             } else {
857 0           priv++;
858            
859 0 0         if (b == 19 && num_operands > 0) {
    0          
860             /* Subrs */
861 0           subrs_offset = operands[0].val.i;
862 0           subrs = data + font->private_offset + subrs_offset;
863 0           parse_cff_index(subrs, end, &font->subr_index);
864 0           font->subr_bias = compute_subr_bias(font->subr_index.count);
865 0 0         } else if (b == 20 && num_operands > 0) {
    0          
866             /* defaultWidthX */
867 0           font->default_width = operands[0].val.i;
868 0 0         } else if (b == 21 && num_operands > 0) {
    0          
869             /* nominalWidthX */
870 0           font->nominal_width = operands[0].val.i;
871             }
872            
873 0           num_operands = 0;
874             }
875             }
876             }
877            
878 0           return 0;
879             }
880              
881             /*============================================================================
882             * Public API
883             *==========================================================================*/
884              
885 0           pdfmake_text_err_t pdfmake_cff_load_glyph(
886             pdfmake_glyph_outline_t *outline,
887             const uint8_t *cff_data,
888             size_t cff_len,
889             uint16_t glyph_id,
890             pdfmake_arena_t *arena)
891             {
892             cff_font_t font;
893             size_t cs_len;
894             const uint8_t *cs;
895             pdfmake_path_t *path;
896             t2_state_t st;
897              
898 0 0         if (!outline || !cff_data || !arena) {
    0          
    0          
899 0           return PDFMAKE_TEXT_ERR_NULL;
900             }
901            
902             /* Parse CFF */
903 0 0         if (parse_cff_font(cff_data, cff_len, &font) < 0) {
904 0           return PDFMAKE_TEXT_ERR_PARSE_ERROR;
905             }
906            
907             /* Get charstring */
908 0 0         if (glyph_id >= font.charstrings_index.count) {
909 0           return PDFMAKE_TEXT_ERR_GLYPH_NOT_FOUND;
910             }
911            
912 0           cs = get_index_data(&font.charstrings_index, glyph_id, &cs_len);
913 0 0         if (!cs) {
914 0           return PDFMAKE_TEXT_ERR_GLYPH_NOT_FOUND;
915             }
916            
917             /* Create path */
918 0           path = pdfmake_path_create();
919 0 0         if (!path) {
920 0           return PDFMAKE_TEXT_ERR_MEMORY;
921             }
922            
923             /* Execute charstring */
924 0           memset(&st, 0, sizeof(st));
925 0           st.path = path;
926 0           st.arena = arena;
927 0           st.font = &font;
928 0           st.width = font.default_width;
929            
930 0 0         if (t2_execute(&st, cs, cs_len) < 0) {
931 0           return PDFMAKE_TEXT_ERR_PARSE_ERROR;
932             }
933            
934             /* Set outline */
935 0           outline->path = path;
936 0           outline->glyph_id = glyph_id;
937 0           outline->advance_width = st.width + font.nominal_width;
938 0           outline->loaded = 1;
939            
940 0           return PDFMAKE_TEXT_OK;
941             }