Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4680 | right-hear | 1 | #include "fitz.h" |
2 | |||
3 | #include |
||
4 | #include FT_FREETYPE_H |
||
5 | #include FT_STROKER_H |
||
6 | |||
7 | static void fz_finalize_freetype(void); |
||
8 | |||
9 | static fz_font * |
||
10 | fz_new_font(char *name) |
||
11 | { |
||
12 | fz_font *font; |
||
13 | |||
14 | font = fz_malloc(sizeof(fz_font)); |
||
15 | font->refs = 1; |
||
16 | |||
17 | if (name) |
||
18 | fz_strlcpy(font->name, name, sizeof font->name); |
||
19 | else |
||
20 | fz_strlcpy(font->name, "(null)", sizeof font->name); |
||
21 | |||
22 | font->ft_face = NULL; |
||
23 | font->ft_substitute = 0; |
||
24 | font->ft_bold = 0; |
||
25 | font->ft_italic = 0; |
||
26 | font->ft_hint = 0; |
||
27 | |||
28 | font->ft_file = NULL; |
||
29 | font->ft_data = NULL; |
||
30 | font->ft_size = 0; |
||
31 | |||
32 | font->t3matrix = fz_identity; |
||
33 | font->t3resources = NULL; |
||
34 | font->t3procs = NULL; |
||
35 | font->t3widths = NULL; |
||
36 | font->t3xref = NULL; |
||
37 | font->t3run = NULL; |
||
38 | |||
39 | font->bbox.x0 = 0; |
||
40 | font->bbox.y0 = 0; |
||
41 | font->bbox.x1 = 1000; |
||
42 | font->bbox.y1 = 1000; |
||
43 | |||
44 | font->width_count = 0; |
||
45 | font->width_table = NULL; |
||
46 | |||
47 | return font; |
||
48 | } |
||
49 | |||
50 | fz_font * |
||
51 | fz_keep_font(fz_font *font) |
||
52 | { |
||
53 | font->refs ++; |
||
54 | return font; |
||
55 | } |
||
56 | |||
57 | void |
||
58 | fz_drop_font(fz_font *font) |
||
59 | { |
||
60 | int fterr; |
||
61 | int i; |
||
62 | |||
63 | if (font && --font->refs == 0) |
||
64 | { |
||
65 | if (font->t3procs) |
||
66 | { |
||
67 | if (font->t3resources) |
||
68 | fz_drop_obj(font->t3resources); |
||
69 | for (i = 0; i < 256; i++) |
||
70 | if (font->t3procs[i]) |
||
71 | fz_drop_buffer(font->t3procs[i]); |
||
72 | fz_free(font->t3procs); |
||
73 | fz_free(font->t3widths); |
||
74 | } |
||
75 | |||
76 | if (font->ft_face) |
||
77 | { |
||
78 | fterr = FT_Done_Face((FT_Face)font->ft_face); |
||
79 | if (fterr) |
||
80 | fz_warn("freetype finalizing face: %s", ft_error_string(fterr)); |
||
81 | fz_finalize_freetype(); |
||
82 | } |
||
83 | |||
84 | if (font->ft_file) |
||
85 | fz_free(font->ft_file); |
||
86 | if (font->ft_data) |
||
87 | fz_free(font->ft_data); |
||
88 | |||
89 | if (font->width_table) |
||
90 | fz_free(font->width_table); |
||
91 | |||
92 | fz_free(font); |
||
93 | } |
||
94 | } |
||
95 | |||
96 | void |
||
97 | fz_set_font_bbox(fz_font *font, float xmin, float ymin, float xmax, float ymax) |
||
98 | { |
||
99 | font->bbox.x0 = xmin; |
||
100 | font->bbox.y0 = ymin; |
||
101 | font->bbox.x1 = xmax; |
||
102 | font->bbox.y1 = ymax; |
||
103 | } |
||
104 | |||
105 | /* |
||
106 | * Freetype hooks |
||
107 | */ |
||
108 | |||
109 | static FT_Library fz_ftlib = NULL; |
||
110 | static int fz_ftlib_refs = 0; |
||
111 | |||
112 | #undef __FTERRORS_H__ |
||
113 | #define FT_ERRORDEF(e, v, s) { (e), (s) }, |
||
114 | #define FT_ERROR_START_LIST |
||
115 | #define FT_ERROR_END_LIST { 0, NULL } |
||
116 | |||
117 | struct ft_error |
||
118 | { |
||
119 | int err; |
||
120 | char *str; |
||
121 | }; |
||
122 | |||
123 | static const struct ft_error ft_errors[] = |
||
124 | { |
||
125 | #include FT_ERRORS_H |
||
126 | }; |
||
127 | |||
128 | char *ft_error_string(int err) |
||
129 | { |
||
130 | const struct ft_error *e; |
||
131 | |||
132 | for (e = ft_errors; e->str != NULL; e++) |
||
133 | if (e->err == err) |
||
134 | return e->str; |
||
135 | |||
136 | return "Unknown error"; |
||
137 | } |
||
138 | |||
139 | static fz_error |
||
140 | fz_init_freetype(void) |
||
141 | { |
||
142 | int fterr; |
||
143 | int maj, min, pat; |
||
144 | |||
145 | if (fz_ftlib) |
||
146 | { |
||
147 | fz_ftlib_refs++; |
||
148 | return fz_okay; |
||
149 | } |
||
150 | |||
151 | fterr = FT_Init_FreeType(&fz_ftlib); |
||
152 | if (fterr) |
||
153 | return fz_throw("cannot init freetype: %s", ft_error_string(fterr)); |
||
154 | |||
155 | FT_Library_Version(fz_ftlib, &maj, &min, &pat); |
||
156 | if (maj == 2 && min == 1 && pat < 7) |
||
157 | { |
||
158 | fterr = FT_Done_FreeType(fz_ftlib); |
||
159 | if (fterr) |
||
160 | fz_warn("freetype finalizing: %s", ft_error_string(fterr)); |
||
161 | return fz_throw("freetype version too old: %d.%d.%d", maj, min, pat); |
||
162 | } |
||
163 | |||
164 | fz_ftlib_refs++; |
||
165 | return fz_okay; |
||
166 | } |
||
167 | |||
168 | static void |
||
169 | fz_finalize_freetype(void) |
||
170 | { |
||
171 | int fterr; |
||
172 | |||
173 | if (--fz_ftlib_refs == 0) |
||
174 | { |
||
175 | fterr = FT_Done_FreeType(fz_ftlib); |
||
176 | if (fterr) |
||
177 | fz_warn("freetype finalizing: %s", ft_error_string(fterr)); |
||
178 | fz_ftlib = NULL; |
||
179 | } |
||
180 | } |
||
181 | |||
182 | fz_error |
||
183 | fz_new_font_from_file(fz_font **fontp, char *path, int index) |
||
184 | { |
||
185 | FT_Face face; |
||
186 | fz_error error; |
||
187 | fz_font *font; |
||
188 | int fterr; |
||
189 | |||
190 | error = fz_init_freetype(); |
||
191 | if (error) |
||
192 | return fz_rethrow(error, "cannot init freetype library"); |
||
193 | |||
194 | fterr = FT_New_Face(fz_ftlib, path, index, &face); |
||
195 | if (fterr) |
||
196 | return fz_throw("freetype: cannot load font: %s", ft_error_string(fterr)); |
||
197 | |||
198 | font = fz_new_font(face->family_name); |
||
199 | font->ft_face = face; |
||
200 | font->bbox.x0 = face->bbox.xMin * 1000 / face->units_per_EM; |
||
201 | font->bbox.y0 = face->bbox.yMin * 1000 / face->units_per_EM; |
||
202 | font->bbox.x1 = face->bbox.xMax * 1000 / face->units_per_EM; |
||
203 | font->bbox.y1 = face->bbox.yMax * 1000 / face->units_per_EM; |
||
204 | |||
205 | *fontp = font; |
||
206 | return fz_okay; |
||
207 | } |
||
208 | |||
209 | fz_error |
||
210 | fz_new_font_from_memory(fz_font **fontp, unsigned char *data, int len, int index) |
||
211 | { |
||
212 | FT_Face face; |
||
213 | fz_error error; |
||
214 | fz_font *font; |
||
215 | int fterr; |
||
216 | |||
217 | error = fz_init_freetype(); |
||
218 | if (error) |
||
219 | return fz_rethrow(error, "cannot init freetype library"); |
||
220 | |||
221 | fterr = FT_New_Memory_Face(fz_ftlib, data, len, index, &face); |
||
222 | if (fterr) |
||
223 | return fz_throw("freetype: cannot load font: %s", ft_error_string(fterr)); |
||
224 | |||
225 | font = fz_new_font(face->family_name); |
||
226 | font->ft_face = face; |
||
227 | font->bbox.x0 = face->bbox.xMin * 1000 / face->units_per_EM; |
||
228 | font->bbox.y0 = face->bbox.yMin * 1000 / face->units_per_EM; |
||
229 | font->bbox.x1 = face->bbox.xMax * 1000 / face->units_per_EM; |
||
230 | font->bbox.y1 = face->bbox.yMax * 1000 / face->units_per_EM; |
||
231 | |||
232 | *fontp = font; |
||
233 | return fz_okay; |
||
234 | } |
||
235 | |||
236 | static fz_matrix |
||
237 | fz_adjust_ft_glyph_width(fz_font *font, int gid, fz_matrix trm) |
||
238 | { |
||
239 | /* Fudge the font matrix to stretch the glyph if we've substituted the font. */ |
||
240 | if (font->ft_substitute && gid < font->width_count) |
||
241 | { |
||
242 | FT_Error fterr; |
||
243 | int subw; |
||
244 | int realw; |
||
245 | float scale; |
||
246 | |||
247 | /* TODO: use FT_Get_Advance */ |
||
248 | fterr = FT_Set_Char_Size(font->ft_face, 1000, 1000, 72, 72); |
||
249 | if (fterr) |
||
250 | fz_warn("freetype setting character size: %s", ft_error_string(fterr)); |
||
251 | |||
252 | fterr = FT_Load_Glyph(font->ft_face, gid, |
||
253 | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); |
||
254 | if (fterr) |
||
255 | fz_warn("freetype failed to load glyph: %s", ft_error_string(fterr)); |
||
256 | |||
257 | realw = ((FT_Face)font->ft_face)->glyph->metrics.horiAdvance; |
||
258 | subw = font->width_table[gid]; |
||
259 | if (realw) |
||
260 | scale = (float) subw / realw; |
||
261 | else |
||
262 | scale = 1; |
||
263 | |||
264 | return fz_concat(fz_scale(scale, 1), trm); |
||
265 | } |
||
266 | |||
267 | return trm; |
||
268 | } |
||
269 | |||
270 | static fz_pixmap * |
||
271 | fz_copy_ft_bitmap(int left, int top, FT_Bitmap *bitmap) |
||
272 | { |
||
273 | fz_pixmap *pixmap; |
||
274 | int y; |
||
275 | |||
276 | pixmap = fz_new_pixmap(NULL, bitmap->width, bitmap->rows); |
||
277 | pixmap->x = left; |
||
278 | pixmap->y = top - bitmap->rows; |
||
279 | |||
280 | if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) |
||
281 | { |
||
282 | for (y = 0; y < pixmap->h; y++) |
||
283 | { |
||
284 | unsigned char *out = pixmap->samples + y * pixmap->w; |
||
285 | unsigned char *in = bitmap->buffer + (pixmap->h - y - 1) * bitmap->pitch; |
||
286 | unsigned char bit = 0x80; |
||
287 | int w = pixmap->w; |
||
288 | while (w--) |
||
289 | { |
||
290 | *out++ = (*in & bit) ? 255 : 0; |
||
291 | bit >>= 1; |
||
292 | if (bit == 0) |
||
293 | { |
||
294 | bit = 0x80; |
||
295 | in++; |
||
296 | } |
||
297 | } |
||
298 | } |
||
299 | } |
||
300 | else |
||
301 | { |
||
302 | for (y = 0; y < pixmap->h; y++) |
||
303 | { |
||
304 | memcpy(pixmap->samples + y * pixmap->w, |
||
305 | bitmap->buffer + (pixmap->h - y - 1) * bitmap->pitch, |
||
306 | pixmap->w); |
||
307 | } |
||
308 | } |
||
309 | |||
310 | return pixmap; |
||
311 | } |
||
312 | |||
313 | fz_pixmap * |
||
314 | fz_render_ft_glyph(fz_font *font, int gid, fz_matrix trm) |
||
315 | { |
||
316 | FT_Face face = font->ft_face; |
||
317 | FT_Matrix m; |
||
318 | FT_Vector v; |
||
319 | FT_Error fterr; |
||
320 | |||
321 | trm = fz_adjust_ft_glyph_width(font, gid, trm); |
||
322 | |||
323 | if (font->ft_italic) |
||
324 | trm = fz_concat(fz_shear(0.3f, 0), trm); |
||
325 | |||
326 | /* |
||
327 | Freetype mutilates complex glyphs if they are loaded |
||
328 | with FT_Set_Char_Size 1.0. it rounds the coordinates |
||
329 | before applying transformation. to get more precision in |
||
330 | freetype, we shift part of the scale in the matrix |
||
331 | into FT_Set_Char_Size instead |
||
332 | */ |
||
333 | |||
334 | m.xx = trm.a * 64; /* should be 65536 */ |
||
335 | m.yx = trm.b * 64; |
||
336 | m.xy = trm.c * 64; |
||
337 | m.yy = trm.d * 64; |
||
338 | v.x = trm.e * 64; |
||
339 | v.y = trm.f * 64; |
||
340 | |||
341 | fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ |
||
342 | if (fterr) |
||
343 | fz_warn("freetype setting character size: %s", ft_error_string(fterr)); |
||
344 | FT_Set_Transform(face, &m, &v); |
||
345 | |||
346 | if (fz_get_aa_level() == 0) |
||
347 | { |
||
348 | /* If you really want grid fitting, enable this code. */ |
||
349 | float scale = fz_matrix_expansion(trm); |
||
350 | m.xx = trm.a * 65536 / scale; |
||
351 | m.xy = trm.b * 65536 / scale; |
||
352 | m.yx = trm.c * 65536 / scale; |
||
353 | m.yy = trm.d * 65536 / scale; |
||
354 | v.x = 0; |
||
355 | v.y = 0; |
||
356 | |||
357 | fterr = FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); |
||
358 | if (fterr) |
||
359 | fz_warn("freetype setting character size: %s", ft_error_string(fterr)); |
||
360 | FT_Set_Transform(face, &m, &v); |
||
361 | fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_TARGET_MONO); |
||
362 | if (fterr) |
||
363 | fz_warn("freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); |
||
364 | } |
||
365 | else if (font->ft_hint) |
||
366 | { |
||
367 | /* |
||
368 | Enable hinting, but keep the huge char size so that |
||
369 | it is hinted for a character. This will in effect nullify |
||
370 | the effect of grid fitting. This form of hinting should |
||
371 | only be used for DynaLab and similar tricky TrueType fonts, |
||
372 | so that we get the correct outline shape. |
||
373 | */ |
||
374 | fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP); |
||
375 | if (fterr) |
||
376 | fz_warn("freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); |
||
377 | } |
||
378 | else |
||
379 | { |
||
380 | fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); |
||
381 | if (fterr) |
||
382 | { |
||
383 | fz_warn("freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); |
||
384 | return NULL; |
||
385 | } |
||
386 | } |
||
387 | |||
388 | if (font->ft_bold) |
||
389 | { |
||
390 | float strength = fz_matrix_expansion(trm) * 0.04f; |
||
391 | FT_Outline_Embolden(&face->glyph->outline, strength * 64); |
||
392 | FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); |
||
393 | } |
||
394 | |||
395 | fterr = FT_Render_Glyph(face->glyph, fz_get_aa_level() > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); |
||
396 | if (fterr) |
||
397 | { |
||
398 | fz_warn("freetype render glyph (gid %d): %s", gid, ft_error_string(fterr)); |
||
399 | return NULL; |
||
400 | } |
||
401 | |||
402 | return fz_copy_ft_bitmap(face->glyph->bitmap_left, face->glyph->bitmap_top, &face->glyph->bitmap); |
||
403 | } |
||
404 | |||
405 | fz_pixmap * |
||
406 | fz_render_ft_stroked_glyph(fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *state) |
||
407 | { |
||
408 | FT_Face face = font->ft_face; |
||
409 | float expansion = fz_matrix_expansion(ctm); |
||
410 | int linewidth = state->linewidth * expansion * 64 / 2; |
||
411 | FT_Matrix m; |
||
412 | FT_Vector v; |
||
413 | FT_Error fterr; |
||
414 | FT_Stroker stroker; |
||
415 | FT_Glyph glyph; |
||
416 | FT_BitmapGlyph bitmap; |
||
417 | fz_pixmap *pixmap; |
||
418 | |||
419 | trm = fz_adjust_ft_glyph_width(font, gid, trm); |
||
420 | |||
421 | if (font->ft_italic) |
||
422 | trm = fz_concat(fz_shear(0.3f, 0), trm); |
||
423 | |||
424 | m.xx = trm.a * 64; /* should be 65536 */ |
||
425 | m.yx = trm.b * 64; |
||
426 | m.xy = trm.c * 64; |
||
427 | m.yy = trm.d * 64; |
||
428 | v.x = trm.e * 64; |
||
429 | v.y = trm.f * 64; |
||
430 | |||
431 | fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ |
||
432 | if (fterr) |
||
433 | { |
||
434 | fz_warn("FT_Set_Char_Size: %s", ft_error_string(fterr)); |
||
435 | return NULL; |
||
436 | } |
||
437 | |||
438 | FT_Set_Transform(face, &m, &v); |
||
439 | |||
440 | fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); |
||
441 | if (fterr) |
||
442 | { |
||
443 | fz_warn("FT_Load_Glyph(gid %d): %s", gid, ft_error_string(fterr)); |
||
444 | return NULL; |
||
445 | } |
||
446 | |||
447 | fterr = FT_Stroker_New(fz_ftlib, &stroker); |
||
448 | if (fterr) |
||
449 | { |
||
450 | fz_warn("FT_Stroker_New: %s", ft_error_string(fterr)); |
||
451 | return NULL; |
||
452 | } |
||
453 | |||
454 | FT_Stroker_Set(stroker, linewidth, state->start_cap, state->linejoin, state->miterlimit * 65536); |
||
455 | |||
456 | fterr = FT_Get_Glyph(face->glyph, &glyph); |
||
457 | if (fterr) |
||
458 | { |
||
459 | fz_warn("FT_Get_Glyph: %s", ft_error_string(fterr)); |
||
460 | FT_Stroker_Done(stroker); |
||
461 | return NULL; |
||
462 | } |
||
463 | |||
464 | fterr = FT_Glyph_Stroke(&glyph, stroker, 1); |
||
465 | if (fterr) |
||
466 | { |
||
467 | fz_warn("FT_Glyph_Stroke: %s", ft_error_string(fterr)); |
||
468 | FT_Done_Glyph(glyph); |
||
469 | FT_Stroker_Done(stroker); |
||
470 | return NULL; |
||
471 | } |
||
472 | |||
473 | FT_Stroker_Done(stroker); |
||
474 | |||
475 | fterr = FT_Glyph_To_Bitmap(&glyph, fz_get_aa_level() > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1); |
||
476 | if (fterr) |
||
477 | { |
||
478 | fz_warn("FT_Glyph_To_Bitmap: %s", ft_error_string(fterr)); |
||
479 | FT_Done_Glyph(glyph); |
||
480 | return NULL; |
||
481 | } |
||
482 | |||
483 | bitmap = (FT_BitmapGlyph)glyph; |
||
484 | pixmap = fz_copy_ft_bitmap(bitmap->left, bitmap->top, &bitmap->bitmap); |
||
485 | FT_Done_Glyph(glyph); |
||
486 | |||
487 | return pixmap; |
||
488 | } |
||
489 | |||
490 | /* |
||
491 | * Type 3 fonts... |
||
492 | */ |
||
493 | |||
494 | fz_font * |
||
495 | fz_new_type3_font(char *name, fz_matrix matrix) |
||
496 | { |
||
497 | fz_font *font; |
||
498 | int i; |
||
499 | |||
500 | font = fz_new_font(name); |
||
501 | font->t3procs = fz_calloc(256, sizeof(fz_buffer*)); |
||
502 | font->t3widths = fz_calloc(256, sizeof(float)); |
||
503 | |||
504 | font->t3matrix = matrix; |
||
505 | for (i = 0; i < 256; i++) |
||
506 | { |
||
507 | font->t3procs[i] = NULL; |
||
508 | font->t3widths[i] = 0; |
||
509 | } |
||
510 | |||
511 | return font; |
||
512 | } |
||
513 | |||
514 | fz_pixmap * |
||
515 | fz_render_t3_glyph(fz_font *font, int gid, fz_matrix trm, fz_colorspace *model) |
||
516 | { |
||
517 | fz_error error; |
||
518 | fz_matrix ctm; |
||
519 | fz_buffer *contents; |
||
520 | fz_bbox bbox; |
||
521 | fz_device *dev; |
||
522 | fz_glyph_cache *cache; |
||
523 | fz_pixmap *glyph; |
||
524 | fz_pixmap *result; |
||
525 | |||
526 | if (gid < 0 || gid > 255) |
||
527 | return NULL; |
||
528 | |||
529 | contents = font->t3procs[gid]; |
||
530 | if (!contents) |
||
531 | return NULL; |
||
532 | |||
533 | ctm = fz_concat(font->t3matrix, trm); |
||
534 | dev = fz_new_bbox_device(&bbox); |
||
535 | error = font->t3run(font->t3xref, font->t3resources, contents, dev, ctm); |
||
536 | if (error) |
||
537 | fz_catch(error, "cannot draw type3 glyph"); |
||
538 | |||
539 | if (dev->flags & FZ_CHARPROC_MASK) |
||
540 | { |
||
541 | if (dev->flags & FZ_CHARPROC_COLOR) |
||
542 | fz_warn("type3 glyph claims to be both masked and colored"); |
||
543 | model = NULL; |
||
544 | } |
||
545 | else if (dev->flags & FZ_CHARPROC_COLOR) |
||
546 | { |
||
547 | if (model == NULL) |
||
548 | fz_warn("colored type3 glyph wanted in masked context"); |
||
549 | } |
||
550 | else |
||
551 | { |
||
552 | fz_warn("type3 glyph doesn't specify masked or colored"); |
||
553 | model = NULL; /* Treat as masked */ |
||
554 | } |
||
555 | |||
556 | fz_free_device(dev); |
||
557 | |||
558 | bbox.x0--; |
||
559 | bbox.y0--; |
||
560 | bbox.x1++; |
||
561 | bbox.y1++; |
||
562 | |||
563 | glyph = fz_new_pixmap_with_rect(model ? model : fz_device_gray, bbox); |
||
564 | fz_clear_pixmap(glyph); |
||
565 | |||
566 | cache = fz_new_glyph_cache(); |
||
567 | dev = fz_new_draw_device_type3(cache, glyph); |
||
568 | error = font->t3run(font->t3xref, font->t3resources, contents, dev, ctm); |
||
569 | if (error) |
||
570 | fz_catch(error, "cannot draw type3 glyph"); |
||
571 | fz_free_device(dev); |
||
572 | fz_free_glyph_cache(cache); |
||
573 | |||
574 | if (model == NULL) |
||
575 | { |
||
576 | result = fz_alpha_from_gray(glyph, 0); |
||
577 | fz_drop_pixmap(glyph); |
||
578 | } |
||
579 | else |
||
580 | result = glyph; |
||
581 | |||
582 | return result; |
||
583 | } |
||
584 | |||
585 | void |
||
586 | fz_debug_font(fz_font *font) |
||
587 | { |
||
588 | printf("font '%s' {\n", font->name); |
||
589 | |||
590 | if (font->ft_face) |
||
591 | { |
||
592 | printf("\tfreetype face %p\n", font->ft_face); |
||
593 | if (font->ft_substitute) |
||
594 | printf("\tsubstitute font\n"); |
||
595 | } |
||
596 | |||
597 | if (font->t3procs) |
||
598 | { |
||
599 | printf("\ttype3 matrix [%g %g %g %g]\n", |
||
600 | font->t3matrix.a, font->t3matrix.b, |
||
601 | font->t3matrix.c, font->t3matrix.d); |
||
602 | } |
||
603 | |||
604 | printf("\tbbox [%g %g %g %g]\n", |
||
605 | font->bbox.x0, font->bbox.y0, |
||
606 | font->bbox.x1, font->bbox.y1); |
||
607 | |||
608 | printf("}\n"); |
||
609 | }>>>>>>> |