beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / CairoFontEngine.cc
blob3cff917a42513d48f0882dd5891deb754ae9cac9
1 //========================================================================
2 //
3 // CairoFontEngine.cc
4 //
5 // Copyright 2003 Glyph & Cog, LLC
6 // Copyright 2004 Red Hat, Inc
7 //
8 //========================================================================
10 //========================================================================
12 // Modified under the Poppler project - http://poppler.freedesktop.org
14 // All changes made under the Poppler project to this file are licensed
15 // under GPL version 2 or later
17 // Copyright (C) 2005-2007 Jeff Muizelaar <jeff@infidigm.net>
18 // Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
19 // Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
20 // Copyright (C) 2005, 2009, 2012, 2013, 2015 Albert Astals Cid <aacid@kde.org>
21 // Copyright (C) 2006, 2007, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
22 // Copyright (C) 2007 Koji Otani <sho@bbr.jp>
23 // Copyright (C) 2008, 2009 Chris Wilson <chris@chris-wilson.co.uk>
24 // Copyright (C) 2008, 2012, 2014, 2016 Adrian Johnson <ajohnson@redneon.com>
25 // Copyright (C) 2009 Darren Kenny <darren.kenny@sun.com>
26 // Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
27 // Copyright (C) 2010 Jan Kümmel <jan+freedesktop@snorc.org>
28 // Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
29 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
30 // Copyright (C) 2015 Jason Crain <jason@aquaticape.us>
32 // To see a description of the changes please see the Changelog file that
33 // came with your tarball or type make ChangeLog if you are building from git
35 //========================================================================
37 #include <config.h>
39 #include "config.h"
40 #include <string.h>
41 #include "CairoFontEngine.h"
42 #include "CairoOutputDev.h"
43 #include "GlobalParams.h"
44 #include <fofi/FoFiTrueType.h>
45 #include <fofi/FoFiType1C.h>
46 #include "goo/gfile.h"
47 #include "Error.h"
48 #include "XRef.h"
49 #include "Gfx.h"
50 #include "Page.h"
52 #if HAVE_FCNTL_H && HAVE_SYS_MMAN_H && HAVE_SYS_STAT_H
53 #include <fcntl.h>
54 #include <sys/stat.h>
55 #include <sys/mman.h>
56 #define CAN_CHECK_OPEN_FACES 1
57 #endif
59 #ifdef USE_GCC_PRAGMAS
60 #pragma implementation
61 #endif
63 #if MULTITHREADED
64 # define fontEngineLocker() MutexLocker locker(&mutex)
65 #else
66 # define fontEngineLocker()
67 #endif
69 //------------------------------------------------------------------------
70 // CairoFont
71 //------------------------------------------------------------------------
73 CairoFont::CairoFont(Ref ref,
74 cairo_font_face_t *cairo_font_face,
75 int *codeToGID,
76 Guint codeToGIDLen,
77 GBool substitute,
78 GBool printing) : ref(ref),
79 cairo_font_face(cairo_font_face),
80 codeToGID(codeToGID),
81 codeToGIDLen(codeToGIDLen),
82 substitute(substitute),
83 printing(printing) { }
85 CairoFont::~CairoFont() {
86 cairo_font_face_destroy (cairo_font_face);
87 gfree(codeToGID);
90 GBool
91 CairoFont::matches(Ref &other, GBool printingA) {
92 return (other.num == ref.num && other.gen == ref.gen);
95 cairo_font_face_t *
96 CairoFont::getFontFace(void) {
97 return cairo_font_face;
100 unsigned long
101 CairoFont::getGlyph(CharCode code,
102 Unicode *u, int uLen) {
103 FT_UInt gid;
105 if (codeToGID && code < codeToGIDLen) {
106 gid = (FT_UInt)codeToGID[code];
107 } else {
108 gid = (FT_UInt)code;
110 return gid;
113 double
114 CairoFont::getSubstitutionCorrection(GfxFont *gfxFont)
116 double w1, w2;
117 CharCode code;
118 char *name;
120 // for substituted fonts: adjust the font matrix -- compare the
121 // width of 'm' in the original font and the substituted font
122 if (isSubstitute() && !gfxFont->isCIDFont()) {
123 for (code = 0; code < 256; ++code) {
124 if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
125 name[0] == 'm' && name[1] == '\0') {
126 break;
129 if (code < 256) {
130 w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
132 cairo_matrix_t m;
133 cairo_matrix_init_identity(&m);
134 cairo_font_options_t *options = cairo_font_options_create();
135 cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
136 cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF);
137 cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options);
139 cairo_text_extents_t extents;
140 cairo_scaled_font_text_extents(scaled_font, "m", &extents);
142 cairo_scaled_font_destroy(scaled_font);
143 cairo_font_options_destroy(options);
144 w2 = extents.x_advance;
146 if (!gfxFont->isSymbolic()) {
147 // if real font is substantially narrower than substituted
148 // font, reduce the font size accordingly
149 if (w1 > 0.01 && w1 < 0.9 * w2) {
150 w1 /= w2;
151 return w1;
156 return 1.0;
159 //------------------------------------------------------------------------
160 // CairoFreeTypeFont
161 //------------------------------------------------------------------------
163 static cairo_user_data_key_t _ft_cairo_key;
165 static void
166 _ft_done_face_uncached (void *closure)
168 FT_Face face = (FT_Face) closure;
169 FT_Done_Face (face);
172 static GBool
173 _ft_new_face_uncached (FT_Library lib,
174 const char *filename,
175 char *font_data,
176 int font_data_len,
177 FT_Face *face_out,
178 cairo_font_face_t **font_face_out)
180 FT_Face face;
181 cairo_font_face_t *font_face;
183 if (font_data == NULL) {
184 if (FT_New_Face (lib, filename, 0, &face))
185 return gFalse;
186 } else {
187 if (FT_New_Memory_Face (lib, (unsigned char *)font_data, font_data_len, 0, &face))
188 return gFalse;
191 font_face = cairo_ft_font_face_create_for_ft_face (face,
192 FT_LOAD_NO_HINTING |
193 FT_LOAD_NO_BITMAP);
194 if (cairo_font_face_set_user_data (font_face,
195 &_ft_cairo_key,
196 face,
197 _ft_done_face_uncached))
199 _ft_done_face_uncached (face);
200 cairo_font_face_destroy (font_face);
201 return gFalse;
204 *face_out = face;
205 *font_face_out = font_face;
206 return gTrue;
209 #if CAN_CHECK_OPEN_FACES
210 static struct _ft_face_data {
211 struct _ft_face_data *prev, *next, **head;
213 int fd;
214 unsigned long hash;
215 size_t size;
216 unsigned char *bytes;
218 FT_Library lib;
219 FT_Face face;
220 cairo_font_face_t *font_face;
221 } *_ft_open_faces;
223 static unsigned long
224 _djb_hash (const unsigned char *bytes, size_t len)
226 unsigned long hash = 5381;
227 while (len--) {
228 unsigned char c = *bytes++;
229 hash *= 33;
230 hash ^= c;
232 return hash;
235 static GBool
236 _ft_face_data_equal (struct _ft_face_data *a, struct _ft_face_data *b)
238 if (a->lib != b->lib)
239 return gFalse;
240 if (a->size != b->size)
241 return gFalse;
242 if (a->hash != b->hash)
243 return gFalse;
245 return memcmp (a->bytes, b->bytes, a->size) == 0;
248 static void
249 _ft_done_face (void *closure)
251 struct _ft_face_data *data = (struct _ft_face_data *) closure;
253 if (data->next)
254 data->next->prev = data->prev;
255 if (data->prev)
256 data->prev->next = data->next;
257 else
258 _ft_open_faces = data->next;
260 if (data->fd != -1) {
261 #if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
262 munmap ((char*)data->bytes, data->size);
263 #else
264 munmap (data->bytes, data->size);
265 #endif
266 close (data->fd);
267 } else {
268 gfree (data->bytes);
271 FT_Done_Face (data->face);
272 gfree (data);
275 static GBool
276 _ft_new_face (FT_Library lib,
277 const char *filename,
278 char *font_data,
279 int font_data_len,
280 FT_Face *face_out,
281 cairo_font_face_t **font_face_out)
283 struct _ft_face_data *l;
284 struct stat st;
285 struct _ft_face_data tmpl;
287 tmpl.fd = -1;
289 if (font_data == NULL) {
290 /* if we fail to mmap the file, just pass it to FreeType instead */
291 tmpl.fd = open (filename, O_RDONLY);
292 if (tmpl.fd == -1)
293 return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
295 if (fstat (tmpl.fd, &st) == -1) {
296 close (tmpl.fd);
297 return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
300 tmpl.bytes = (unsigned char *) mmap (NULL, st.st_size,
301 PROT_READ, MAP_PRIVATE,
302 tmpl.fd, 0);
303 if (tmpl.bytes == MAP_FAILED) {
304 close (tmpl.fd);
305 return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
307 tmpl.size = st.st_size;
308 } else {
309 tmpl.bytes = (unsigned char*) font_data;
310 tmpl.size = font_data_len;
313 /* check to see if this is a duplicate of any of the currently open fonts */
314 tmpl.lib = lib;
315 tmpl.hash = _djb_hash (tmpl.bytes, tmpl.size);
317 for (l = _ft_open_faces; l; l = l->next) {
318 if (_ft_face_data_equal (l, &tmpl)) {
319 if (tmpl.fd != -1) {
320 #if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
321 munmap ((char*)tmpl.bytes, tmpl.size);
322 #else
323 munmap (tmpl.bytes, tmpl.size);
324 #endif
325 close (tmpl.fd);
326 } else {
327 gfree (tmpl.bytes);
329 *face_out = l->face;
330 *font_face_out = cairo_font_face_reference (l->font_face);
331 return gTrue;
335 /* not a dup, open and insert into list */
336 if (FT_New_Memory_Face (lib,
337 (FT_Byte *) tmpl.bytes, tmpl.size,
338 0, &tmpl.face))
340 if (tmpl.fd != -1) {
341 #if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
342 munmap ((char*)tmpl.bytes, tmpl.size);
343 #else
344 munmap (tmpl.bytes, tmpl.size);
345 #endif
347 close (tmpl.fd);
349 return gFalse;
352 l = (struct _ft_face_data *) gmallocn (1, sizeof (struct _ft_face_data));
353 *l = tmpl;
354 l->prev = NULL;
355 l->next = _ft_open_faces;
356 if (_ft_open_faces)
357 _ft_open_faces->prev = l;
358 _ft_open_faces = l;
360 l->font_face = cairo_ft_font_face_create_for_ft_face (tmpl.face,
361 FT_LOAD_NO_HINTING |
362 FT_LOAD_NO_BITMAP);
363 if (cairo_font_face_set_user_data (l->font_face,
364 &_ft_cairo_key,
366 _ft_done_face))
368 cairo_font_face_destroy (l->font_face);
369 _ft_done_face (l);
370 return gFalse;
373 *face_out = l->face;
374 *font_face_out = l->font_face;
375 return gTrue;
377 #else
378 #define _ft_new_face _ft_new_face_uncached
379 #endif
381 CairoFreeTypeFont::CairoFreeTypeFont(Ref ref,
382 cairo_font_face_t *cairo_font_face,
383 int *codeToGID,
384 Guint codeToGIDLen,
385 GBool substitute) : CairoFont(ref,
386 cairo_font_face,
387 codeToGID,
388 codeToGIDLen,
389 substitute,
390 gTrue) { }
392 CairoFreeTypeFont::~CairoFreeTypeFont() { }
394 CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
395 FT_Library lib, GBool useCIDs) {
396 Object refObj, strObj;
397 GooString *fileName;
398 char *fileNameC;
399 char *font_data;
400 int font_data_len;
401 int i, n;
402 GfxFontType fontType;
403 GfxFontLoc *fontLoc;
404 char **enc;
405 const char *name;
406 FoFiTrueType *ff;
407 FoFiType1C *ff1c;
408 Ref ref;
409 FT_Face face;
410 cairo_font_face_t *font_face;
412 int *codeToGID;
413 Guint codeToGIDLen;
415 codeToGID = NULL;
416 codeToGIDLen = 0;
417 font_data = NULL;
418 font_data_len = 0;
419 fileName = NULL;
420 fileNameC = NULL;
422 GBool substitute = gFalse;
424 ref = *gfxFont->getID();
425 fontType = gfxFont->getType();
427 if (!(fontLoc = gfxFont->locateFont(xref, NULL))) {
428 error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
429 gfxFont->getName() ? gfxFont->getName()->getCString()
430 : "(unnamed)");
431 goto err2;
434 // embedded font
435 if (fontLoc->locType == gfxFontLocEmbedded) {
436 font_data = gfxFont->readEmbFontFile(xref, &font_data_len);
437 if (NULL == font_data)
438 goto err2;
440 // external font
441 } else { // gfxFontLocExternal
442 fileName = fontLoc->path;
443 fontType = fontLoc->fontType;
444 substitute = gTrue;
447 if (fileName != NULL) {
448 fileNameC = fileName->getCString();
451 switch (fontType) {
452 case fontType1:
453 case fontType1C:
454 case fontType1COT:
455 if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
456 error(errSyntaxError, -1, "could not create type1 face");
457 goto err2;
460 enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
462 codeToGID = (int *)gmallocn(256, sizeof(int));
463 codeToGIDLen = 256;
464 for (i = 0; i < 256; ++i) {
465 codeToGID[i] = 0;
466 if ((name = enc[i])) {
467 codeToGID[i] = FT_Get_Name_Index(face, (char*)name);
468 if (codeToGID[i] == 0) {
469 name = GfxFont::getAlternateName(name);
470 if (name) {
471 codeToGID[i] = FT_Get_Name_Index(face, (char*)name);
476 break;
477 case fontCIDType2:
478 case fontCIDType2OT:
479 codeToGID = NULL;
480 n = 0;
481 if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
482 n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
483 if (n) {
484 codeToGID = (int *)gmallocn(n, sizeof(int));
485 memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
486 n * sizeof(int));
488 } else {
489 if (font_data != NULL) {
490 ff = FoFiTrueType::make(font_data, font_data_len);
491 } else {
492 ff = FoFiTrueType::load(fileNameC);
494 if (! ff)
495 goto err2;
496 codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
497 delete ff;
499 codeToGIDLen = n;
500 /* Fall through */
501 case fontTrueType:
502 case fontTrueTypeOT:
503 if (font_data != NULL) {
504 ff = FoFiTrueType::make(font_data, font_data_len);
505 } else {
506 ff = FoFiTrueType::load(fileNameC);
508 if (! ff) {
509 error(errSyntaxError, -1, "failed to load truetype font\n");
510 goto err2;
512 /* This might be set already for the CIDType2 case */
513 if (fontType == fontTrueType || fontType == fontTrueTypeOT) {
514 codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
515 codeToGIDLen = 256;
517 delete ff;
518 if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
519 error(errSyntaxError, -1, "could not create truetype face\n");
520 goto err2;
522 break;
524 case fontCIDType0:
525 case fontCIDType0C:
527 codeToGID = NULL;
528 codeToGIDLen = 0;
530 if (!useCIDs)
532 if (font_data != NULL) {
533 ff1c = FoFiType1C::make(font_data, font_data_len);
534 } else {
535 ff1c = FoFiType1C::load(fileNameC);
537 if (ff1c) {
538 codeToGID = ff1c->getCIDToGIDMap((int *)&codeToGIDLen);
539 delete ff1c;
543 if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
544 error(errSyntaxError, -1, "could not create cid face\n");
545 goto err2;
547 break;
549 case fontCIDType0COT:
550 codeToGID = NULL;
551 n = 0;
552 if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
553 n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
554 if (n) {
555 codeToGID = (int *)gmallocn(n, sizeof(int));
556 memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
557 n * sizeof(int));
560 codeToGIDLen = n;
562 if (!codeToGID) {
563 if (!useCIDs) {
564 if (font_data != NULL) {
565 ff = FoFiTrueType::make(font_data, font_data_len);
566 } else {
567 ff = FoFiTrueType::load(fileNameC);
569 if (ff) {
570 if (ff->isOpenTypeCFF()) {
571 codeToGID = ff->getCIDToGIDMap((int *)&codeToGIDLen);
573 delete ff;
577 if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
578 error(errSyntaxError, -1, "could not create cid (OT) face\n");
579 goto err2;
581 break;
583 default:
584 fprintf (stderr, "font type %d not handled\n", (int)fontType);
585 goto err2;
586 break;
589 delete fontLoc;
590 return new CairoFreeTypeFont(ref,
591 font_face,
592 codeToGID, codeToGIDLen,
593 substitute);
595 err2:
596 /* hmm? */
597 delete fontLoc;
598 gfree (codeToGID);
599 gfree (font_data);
600 fprintf (stderr, "some font thing failed\n");
601 return NULL;
604 //------------------------------------------------------------------------
605 // CairoType3Font
606 //------------------------------------------------------------------------
608 static const cairo_user_data_key_t type3_font_key = {0};
610 typedef struct _type3_font_info {
611 GfxFont *font;
612 PDFDoc *doc;
613 CairoFontEngine *fontEngine;
614 GBool printing;
615 XRef *xref;
616 } type3_font_info_t;
618 static void
619 _free_type3_font_info(void *closure)
621 type3_font_info_t *info = (type3_font_info_t *) closure;
623 info->font->decRefCnt();
624 free (info);
627 static cairo_status_t
628 _init_type3_glyph (cairo_scaled_font_t *scaled_font,
629 cairo_t *cr,
630 cairo_font_extents_t *extents)
632 type3_font_info_t *info;
633 GfxFont *font;
634 double *mat;
636 info = (type3_font_info_t *)
637 cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
638 &type3_font_key);
639 font = info->font;
640 mat = font->getFontBBox();
641 extents->ascent = mat[3]; /* y2 */
642 extents->descent = -mat[3]; /* -y1 */
643 extents->height = extents->ascent + extents->descent;
644 extents->max_x_advance = mat[2] - mat[1]; /* x2 - x1 */
645 extents->max_y_advance = 0;
647 return CAIRO_STATUS_SUCCESS;
650 static cairo_status_t
651 _render_type3_glyph (cairo_scaled_font_t *scaled_font,
652 unsigned long glyph,
653 cairo_t *cr,
654 cairo_text_extents_t *metrics)
656 Dict *charProcs;
657 Object charProc;
658 CairoOutputDev *output_dev;
659 cairo_matrix_t matrix, invert_y_axis;
660 double *mat;
661 double wx, wy;
662 PDFRectangle box;
663 type3_font_info_t *info;
664 GfxFont *font;
665 Dict *resDict;
666 Gfx *gfx;
668 info = (type3_font_info_t *)
669 cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
670 &type3_font_key);
672 font = info->font;
673 resDict = ((Gfx8BitFont *)font)->getResources();
674 charProcs = ((Gfx8BitFont *)(info->font))->getCharProcs();
675 if (!charProcs)
676 return CAIRO_STATUS_USER_FONT_ERROR;
678 if ((int)glyph >= charProcs->getLength())
679 return CAIRO_STATUS_USER_FONT_ERROR;
681 mat = font->getFontMatrix();
682 matrix.xx = mat[0];
683 matrix.yx = mat[1];
684 matrix.xy = mat[2];
685 matrix.yy = mat[3];
686 matrix.x0 = mat[4];
687 matrix.y0 = mat[5];
688 cairo_matrix_init_scale (&invert_y_axis, 1, -1);
689 cairo_matrix_multiply (&matrix, &matrix, &invert_y_axis);
690 cairo_transform (cr, &matrix);
692 output_dev = new CairoOutputDev();
693 output_dev->setCairo(cr);
694 output_dev->setPrinting(info->printing);
696 mat = font->getFontBBox();
697 box.x1 = mat[0];
698 box.y1 = mat[1];
699 box.x2 = mat[2];
700 box.y2 = mat[3];
701 gfx = new Gfx(info->doc, output_dev, resDict, &box, NULL);
702 output_dev->startDoc(info->doc, info->fontEngine);
703 output_dev->startPage (1, gfx->getState(), gfx->getXRef());
704 output_dev->setInType3Char(gTrue);
705 gfx->display(charProcs->getVal(glyph, &charProc));
707 output_dev->getType3GlyphWidth (&wx, &wy);
708 cairo_matrix_transform_distance (&matrix, &wx, &wy);
709 metrics->x_advance = wx;
710 metrics->y_advance = wy;
711 if (output_dev->hasType3GlyphBBox()) {
712 double *bbox = output_dev->getType3GlyphBBox();
714 cairo_matrix_transform_point (&matrix, &bbox[0], &bbox[1]);
715 cairo_matrix_transform_point (&matrix, &bbox[2], &bbox[3]);
716 metrics->x_bearing = bbox[0];
717 metrics->y_bearing = bbox[1];
718 metrics->width = bbox[2] - bbox[0];
719 metrics->height = bbox[3] - bbox[1];
722 delete gfx;
723 delete output_dev;
724 charProc.free();
726 return CAIRO_STATUS_SUCCESS;
730 CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc,
731 CairoFontEngine *fontEngine,
732 GBool printing, XRef *xref) {
733 Object refObj, strObj;
734 type3_font_info_t *info;
735 cairo_font_face_t *font_face;
736 Ref ref;
737 int *codeToGID;
738 Guint codeToGIDLen;
739 int i, j;
740 char **enc;
741 Dict *charProcs;
742 char *name;
744 charProcs = ((Gfx8BitFont *)gfxFont)->getCharProcs();
745 info = (type3_font_info_t *) malloc(sizeof(*info));
746 ref = *gfxFont->getID();
747 font_face = cairo_user_font_face_create();
748 cairo_user_font_face_set_init_func (font_face, _init_type3_glyph);
749 cairo_user_font_face_set_render_glyph_func (font_face, _render_type3_glyph);
750 gfxFont->incRefCnt();
751 info->font = gfxFont;
752 info->doc = doc;
753 info->fontEngine = fontEngine;
754 info->printing = printing;
755 info->xref = xref;
757 cairo_font_face_set_user_data (font_face, &type3_font_key, (void *) info, _free_type3_font_info);
759 enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
760 codeToGID = (int *)gmallocn(256, sizeof(int));
761 codeToGIDLen = 256;
762 for (i = 0; i < 256; ++i) {
763 codeToGID[i] = 0;
764 if (charProcs && (name = enc[i])) {
765 for (j = 0; j < charProcs->getLength(); j++) {
766 if (strcmp(name, charProcs->getKey(j)) == 0) {
767 codeToGID[i] = j;
773 return new CairoType3Font(ref, doc, font_face, codeToGID, codeToGIDLen, printing, xref);
776 CairoType3Font::CairoType3Font(Ref ref,
777 PDFDoc *doc,
778 cairo_font_face_t *cairo_font_face,
779 int *codeToGID,
780 Guint codeToGIDLen,
781 GBool printing, XRef *xref) : CairoFont(ref,
782 cairo_font_face,
783 codeToGID,
784 codeToGIDLen,
785 gFalse,
786 printing),
787 doc(doc) { }
789 CairoType3Font::~CairoType3Font() { }
791 GBool
792 CairoType3Font::matches(Ref &other, GBool printingA) {
793 return (other.num == ref.num && other.gen == ref.gen && printing == printingA);
797 //------------------------------------------------------------------------
798 // CairoFontEngine
799 //------------------------------------------------------------------------
801 CairoFontEngine::CairoFontEngine(FT_Library libA) {
802 int i;
804 lib = libA;
805 for (i = 0; i < cairoFontCacheSize; ++i) {
806 fontCache[i] = NULL;
809 FT_Int major, minor, patch;
810 // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
811 FT_Library_Version(lib, &major, &minor, &patch);
812 useCIDs = major > 2 ||
813 (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
814 #if MULTITHREADED
815 gInitMutex(&mutex);
816 #endif
819 CairoFontEngine::~CairoFontEngine() {
820 int i;
822 for (i = 0; i < cairoFontCacheSize; ++i) {
823 if (fontCache[i])
824 delete fontCache[i];
826 #if MULTITHREADED
827 gDestroyMutex(&mutex);
828 #endif
831 CairoFont *
832 CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref) {
833 int i, j;
834 Ref ref;
835 CairoFont *font;
836 GfxFontType fontType;
838 fontEngineLocker();
839 ref = *gfxFont->getID();
841 for (i = 0; i < cairoFontCacheSize; ++i) {
842 font = fontCache[i];
843 if (font && font->matches(ref, printing)) {
844 for (j = i; j > 0; --j) {
845 fontCache[j] = fontCache[j-1];
847 fontCache[0] = font;
848 return font;
852 fontType = gfxFont->getType();
853 if (fontType == fontType3)
854 font = CairoType3Font::create (gfxFont, doc, this, printing, xref);
855 else
856 font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs);
858 //XXX: if font is null should we still insert it into the cache?
859 if (fontCache[cairoFontCacheSize - 1]) {
860 delete fontCache[cairoFontCacheSize - 1];
862 for (j = cairoFontCacheSize - 1; j > 0; --j) {
863 fontCache[j] = fontCache[j-1];
865 fontCache[0] = font;
866 return font;