File Coverage

src/pdfmake_font.c
Criterion Covered Total %
statement 43 89 48.3
branch 16 54 29.6
condition n/a
subroutine n/a
pod n/a
total 59 143 41.2


line stmt bran cond sub pod time code
1             /*
2             * pdfmake_font.c - Font management implementation
3             *
4             * Implements Standard 14 font constructor, TrueType font loading,
5             * width calculations, and PDF output.
6             */
7              
8             #include "pdfmake_font.h"
9             #include "pdfmake_arena.h"
10             #include
11             #include
12             #include
13              
14             /*============================================================================
15             * Standard 14 font constructor
16             *==========================================================================*/
17              
18 93           pdfmake_font_t *pdfmake_font_standard14(pdfmake_arena_t *arena, const char *base_font) {
19             int id;
20             const pdfmake_std14_data_t *data;
21             pdfmake_font_t *font;
22              
23 93 50         if (!arena || !base_font) return NULL;
    50          
24              
25             /* Look up by name */
26 93           id = pdfmake_std14_lookup(base_font);
27 93 100         if (id < 0) return NULL;
28              
29 92           data = pdfmake_std14_get(id);
30 92 50         if (!data) return NULL;
31              
32 92           font = pdfmake_arena_alloc(arena, sizeof(pdfmake_font_t));
33 92 50         if (!font) return NULL;
34 92           memset(font, 0, sizeof(pdfmake_font_t));
35              
36 92           font->arena = arena;
37 92           font->type = PDFMAKE_FONT_TYPE1;
38 92           font->std14_id = id;
39 92           font->base_font = data->name;
40 92           font->metrics = data->metrics;
41 92           font->ttf = NULL;
42              
43 92           return font;
44             }
45              
46             /*============================================================================
47             * Font destructor
48             *==========================================================================*/
49              
50 92           void pdfmake_font_free(pdfmake_font_t *font) {
51             /* Fonts are arena-allocated, nothing to free */
52             (void)font;
53 92           }
54              
55             /*============================================================================
56             * Width calculations
57             *==========================================================================*/
58              
59 879821           double pdfmake_font_advance(const pdfmake_font_t *font, uint32_t codepoint, double font_size) {
60 879821           int width_units = 0;
61              
62 879821 50         if (!font) return 0;
63              
64 879821           switch (font->type) {
65 879821           case PDFMAKE_FONT_TYPE1:
66             /* Standard 14 font - use std14 width table */
67 879821           width_units = pdfmake_std14_width(font->std14_id, codepoint);
68 879821           break;
69              
70 0           case PDFMAKE_FONT_TRUETYPE:
71             case PDFMAKE_FONT_CID_TRUETYPE:
72             /* TrueType font - lookup in TTF */
73 0 0         if (font->ttf) {
74 0           uint16_t glyph = pdfmake_ttf_cmap_lookup(font->ttf, codepoint);
75 0           width_units = pdfmake_ttf_glyph_advance(font->ttf, glyph);
76             }
77 0           break;
78             }
79              
80             /* Convert from 1/1000 em to PDF points */
81 879821           return (width_units * font_size) / 1000.0;
82             }
83              
84 15506           double pdfmake_font_string_width(const pdfmake_font_t *font, const char *utf8,
85             size_t len, double font_size) {
86 15506           double total = 0;
87             const uint8_t *p;
88             const uint8_t *end;
89              
90 15506 50         if (!font || !utf8) return 0;
    50          
91              
92 15506           p = (const uint8_t *)utf8;
93 15506           end = p + len;
94              
95 895308 100         while (p < end) {
96             uint32_t cp;
97            
98             /* Decode UTF-8 */
99 879802 100         if ((*p & 0x80) == 0) {
100 879801           cp = *p++;
101 1 50         } else if ((*p & 0xE0) == 0xC0) {
102 1 50         if (p + 1 >= end) break;
103 1           cp = (*p++ & 0x1F) << 6;
104 1           cp |= (*p++ & 0x3F);
105 0 0         } else if ((*p & 0xF0) == 0xE0) {
106 0 0         if (p + 2 >= end) break;
107 0           cp = (*p++ & 0x0F) << 12;
108 0           cp |= (*p++ & 0x3F) << 6;
109 0           cp |= (*p++ & 0x3F);
110 0 0         } else if ((*p & 0xF8) == 0xF0) {
111 0 0         if (p + 3 >= end) break;
112 0           cp = (*p++ & 0x07) << 18;
113 0           cp |= (*p++ & 0x3F) << 12;
114 0           cp |= (*p++ & 0x3F) << 6;
115 0           cp |= (*p++ & 0x3F);
116             } else {
117             /* Invalid UTF-8, skip byte */
118 0           p++;
119 0           continue;
120             }
121            
122 879802           total += pdfmake_font_advance(font, cp, font_size);
123             }
124            
125 15506           return total;
126             }
127              
128 8           const pdfmake_font_metrics_t *pdfmake_font_metrics(const pdfmake_font_t *font) {
129 8 50         if (!font) return NULL;
130 8           return &font->metrics;
131             }
132              
133             /*============================================================================
134             * TrueType font creation
135             *==========================================================================*/
136              
137 0           pdfmake_font_t *pdfmake_font_from_ttf(pdfmake_arena_t *arena,
138             const uint8_t *ttf_bytes, size_t len) {
139             pdfmake_ttf_t *ttf;
140             pdfmake_font_t *font;
141             int upm;
142             pdfmake_font_metrics_t *m;
143              
144 0 0         if (!arena || !ttf_bytes || len == 0) return NULL;
    0          
    0          
145              
146 0           ttf = pdfmake_ttf_parse(arena, ttf_bytes, len);
147 0 0         if (!ttf) return NULL;
148              
149 0           font = pdfmake_arena_alloc(arena, sizeof(pdfmake_font_t));
150 0 0         if (!font) return NULL;
151 0           memset(font, 0, sizeof(pdfmake_font_t));
152              
153 0           font->arena = arena;
154 0           font->type = PDFMAKE_FONT_TRUETYPE;
155 0           font->std14_id = -1;
156 0           font->ttf = ttf;
157              
158             /* Derive metrics from TTF */
159 0 0         upm = ttf->units_per_em > 0 ? ttf->units_per_em : 1000;
160 0           m = &font->metrics;
161              
162 0           m->ascent = (ttf->ascender * 1000) / upm;
163 0           m->descent = (ttf->descender * 1000) / upm;
164            
165 0 0         if (ttf->has_os2) {
166 0 0         m->cap_height = ttf->s_cap_height > 0 ? (ttf->s_cap_height * 1000) / upm : m->ascent;
167 0 0         m->x_height = ttf->s_x_height > 0 ? (ttf->s_x_height * 1000) / upm : m->cap_height * 7 / 10;
168             } else {
169 0           m->cap_height = m->ascent;
170 0           m->x_height = m->cap_height * 7 / 10;
171             }
172            
173 0           m->stem_v = 80;
174 0           m->stem_h = 80;
175 0           m->bbox[0] = (ttf->x_min * 1000) / upm;
176 0           m->bbox[1] = (ttf->y_min * 1000) / upm;
177 0           m->bbox[2] = (ttf->x_max * 1000) / upm;
178 0           m->bbox[3] = (ttf->y_max * 1000) / upm;
179 0           m->flags = PDFMAKE_FONT_FLAG_NONSYMBOLIC;
180            
181 0           return font;
182             }