1 //========================================================================
2 //
3 // CairoFontEngine.cc
4 //
5 // Copyright 2003 Glyph & Cog, LLC
6 // Copyright 2004 Red Hat, Inc
7 //
8 //========================================================================
9 
10 //========================================================================
11 //
12 // Modified under the Poppler project - http://poppler.freedesktop.org
13 //
14 // All changes made under the Poppler project to this file are licensed
15 // under GPL version 2 or later
16 //
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, 2017-2019, 2021 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, 2017 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, 2016 Jason Crain <jason@aquaticape.us>
31 // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
32 // Copyright (C) 2019 Christian Persch <chpe@src.gnome.org>
33 // Copyright (C) 2020 Michal <sudolskym@gmail.com>
34 //
35 // To see a description of the changes please see the Changelog file that
36 // came with your tarball or type make ChangeLog if you are building from git
37 //
38 //========================================================================
39 
40 #include <config.h>
41 
42 #include "config.h"
43 #include <cstring>
44 #include <forward_list>
45 #include "CairoFontEngine.h"
46 #include "CairoOutputDev.h"
47 #include "GlobalParams.h"
48 #include <fofi/FoFiTrueType.h>
49 #include <fofi/FoFiType1C.h>
50 #include "goo/gfile.h"
51 #include "Error.h"
52 #include "XRef.h"
53 #include "Gfx.h"
54 #include "Page.h"
55 
56 #if defined(HAVE_FCNTL_H) && defined(HAVE_SYS_MMAN_H) && defined(HAVE_SYS_STAT_H)
57 #    include <fcntl.h>
58 #    include <sys/stat.h>
59 #    include <sys/mman.h>
60 #    define CAN_CHECK_OPEN_FACES 1
61 #endif
62 
63 //------------------------------------------------------------------------
64 // CairoFont
65 //------------------------------------------------------------------------
66 
CairoFont(Ref refA,cairo_font_face_t * cairo_font_faceA,int * codeToGIDA,unsigned int codeToGIDLenA,bool substituteA,bool printingA)67 CairoFont::CairoFont(Ref refA, cairo_font_face_t *cairo_font_faceA, int *codeToGIDA, unsigned int codeToGIDLenA, bool substituteA, bool printingA)
68     : ref(refA), cairo_font_face(cairo_font_faceA), codeToGID(codeToGIDA), codeToGIDLen(codeToGIDLenA), substitute(substituteA), printing(printingA)
69 {
70 }
71 
~CairoFont()72 CairoFont::~CairoFont()
73 {
74     cairo_font_face_destroy(cairo_font_face);
75     gfree(codeToGID);
76 }
77 
matches(Ref & other,bool printingA)78 bool CairoFont::matches(Ref &other, bool printingA)
79 {
80     return (other == ref);
81 }
82 
getFontFace()83 cairo_font_face_t *CairoFont::getFontFace()
84 {
85     return cairo_font_face;
86 }
87 
getGlyph(CharCode code,const Unicode * u,int uLen)88 unsigned long CairoFont::getGlyph(CharCode code, const Unicode *u, int uLen)
89 {
90     FT_UInt gid;
91 
92     if (codeToGID && code < codeToGIDLen) {
93         gid = (FT_UInt)codeToGID[code];
94     } else {
95         gid = (FT_UInt)code;
96     }
97     return gid;
98 }
99 
getSubstitutionCorrection(GfxFont * gfxFont)100 double CairoFont::getSubstitutionCorrection(GfxFont *gfxFont)
101 {
102     double w1, w2, w3;
103     CharCode code;
104     const char *name;
105 
106     // for substituted fonts: adjust the font matrix -- compare the
107     // width of 'm' in the original font and the substituted font
108     if (isSubstitute() && !gfxFont->isCIDFont()) {
109         for (code = 0; code < 256; ++code) {
110             if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && name[0] == 'm' && name[1] == '\0') {
111                 break;
112             }
113         }
114         if (code < 256) {
115             w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
116             {
117                 cairo_matrix_t m;
118                 cairo_matrix_init_identity(&m);
119                 cairo_font_options_t *options = cairo_font_options_create();
120                 cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
121                 cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF);
122                 cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options);
123 
124                 cairo_text_extents_t extents;
125                 cairo_scaled_font_text_extents(scaled_font, "m", &extents);
126 
127                 cairo_scaled_font_destroy(scaled_font);
128                 cairo_font_options_destroy(options);
129                 w2 = extents.x_advance;
130             }
131             w3 = ((Gfx8BitFont *)gfxFont)->getWidth(0);
132             if (!gfxFont->isSymbolic() && w2 > 0 && w1 > w3) {
133                 // if real font is substantially narrower than substituted
134                 // font, reduce the font size accordingly
135                 if (w1 > 0.01 && w1 < 0.9 * w2) {
136                     w1 /= w2;
137                     return w1;
138                 }
139             }
140         }
141     }
142     return 1.0;
143 }
144 
145 //------------------------------------------------------------------------
146 // CairoFreeTypeFont
147 //------------------------------------------------------------------------
148 
149 static cairo_user_data_key_t _ft_cairo_key;
150 
_ft_done_face_uncached(void * closure)151 static void _ft_done_face_uncached(void *closure)
152 {
153     FT_Face face = (FT_Face)closure;
154     FT_Done_Face(face);
155 }
156 
_ft_new_face_uncached(FT_Library lib,const char * filename,char * font_data,int font_data_len,FT_Face * face_out,cairo_font_face_t ** font_face_out)157 static bool _ft_new_face_uncached(FT_Library lib, const char *filename, char *font_data, int font_data_len, FT_Face *face_out, cairo_font_face_t **font_face_out)
158 {
159     FT_Face face;
160     cairo_font_face_t *font_face;
161 
162     if (font_data == nullptr) {
163         if (FT_New_Face(lib, filename, 0, &face))
164             return false;
165     } else {
166         if (FT_New_Memory_Face(lib, (unsigned char *)font_data, font_data_len, 0, &face))
167             return false;
168     }
169 
170     font_face = cairo_ft_font_face_create_for_ft_face(face, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
171     if (cairo_font_face_set_user_data(font_face, &_ft_cairo_key, face, _ft_done_face_uncached)) {
172         _ft_done_face_uncached(face);
173         cairo_font_face_destroy(font_face);
174         return false;
175     }
176 
177     *face_out = face;
178     *font_face_out = font_face;
179     return true;
180 }
181 
182 #ifdef CAN_CHECK_OPEN_FACES
183 struct _ft_face_data
184 {
185     int fd;
186     unsigned long hash;
187     size_t size;
188     unsigned char *bytes;
189 
190     FT_Library lib;
191     FT_Face face;
192     cairo_font_face_t *font_face;
193 };
194 
195 class _FtFaceDataProxy
196 {
197     _ft_face_data *_data;
198 
199 public:
_FtFaceDataProxy(_ft_face_data * data)200     explicit _FtFaceDataProxy(_ft_face_data *data) : _data(data) { cairo_font_face_reference(_data->font_face); }
201     _FtFaceDataProxy(_FtFaceDataProxy &&) = delete;
~_FtFaceDataProxy()202     ~_FtFaceDataProxy() { cairo_font_face_destroy(_data->font_face); }
operator _ft_face_data*()203     explicit operator _ft_face_data *() { return _data; }
204 };
205 
206 static thread_local std::forward_list<_FtFaceDataProxy> _local_open_faces;
207 
_djb_hash(const unsigned char * bytes,size_t len)208 static unsigned long _djb_hash(const unsigned char *bytes, size_t len)
209 {
210     unsigned long hash = 5381;
211     while (len--) {
212         unsigned char c = *bytes++;
213         hash *= 33;
214         hash ^= c;
215     }
216     return hash;
217 }
218 
_ft_face_data_equal(struct _ft_face_data * a,struct _ft_face_data * b)219 static bool _ft_face_data_equal(struct _ft_face_data *a, struct _ft_face_data *b)
220 {
221     if (a->lib != b->lib)
222         return false;
223     if (a->size != b->size)
224         return false;
225     if (a->hash != b->hash)
226         return false;
227 
228     return memcmp(a->bytes, b->bytes, a->size) == 0;
229 }
230 
_ft_done_face(void * closure)231 static void _ft_done_face(void *closure)
232 {
233     struct _ft_face_data *data = (struct _ft_face_data *)closure;
234 
235     if (data->fd != -1) {
236 #    if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
237         munmap((char *)data->bytes, data->size);
238 #    else
239         munmap(data->bytes, data->size);
240 #    endif
241         close(data->fd);
242     } else {
243         gfree(data->bytes);
244     }
245 
246     FT_Done_Face(data->face);
247     gfree(data);
248 }
249 
_ft_new_face(FT_Library lib,const char * filename,char * font_data,int font_data_len,FT_Face * face_out,cairo_font_face_t ** font_face_out)250 static bool _ft_new_face(FT_Library lib, const char *filename, char *font_data, int font_data_len, FT_Face *face_out, cairo_font_face_t **font_face_out)
251 {
252     struct stat st;
253     struct _ft_face_data tmpl;
254 
255     tmpl.fd = -1;
256 
257     if (font_data == nullptr) {
258         /* if we fail to mmap the file, just pass it to FreeType instead */
259         tmpl.fd = openFileDescriptor(filename, O_RDONLY);
260         if (tmpl.fd == -1)
261             return _ft_new_face_uncached(lib, filename, font_data, font_data_len, face_out, font_face_out);
262 
263         if (fstat(tmpl.fd, &st) == -1) {
264             close(tmpl.fd);
265             return _ft_new_face_uncached(lib, filename, font_data, font_data_len, face_out, font_face_out);
266         }
267 
268         tmpl.bytes = (unsigned char *)mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, tmpl.fd, 0);
269         if (tmpl.bytes == MAP_FAILED) {
270             close(tmpl.fd);
271             return _ft_new_face_uncached(lib, filename, font_data, font_data_len, face_out, font_face_out);
272         }
273         tmpl.size = st.st_size;
274     } else {
275         tmpl.bytes = (unsigned char *)font_data;
276         tmpl.size = font_data_len;
277     }
278 
279     /* check to see if this is a duplicate of any of the currently open fonts */
280     tmpl.lib = lib;
281     tmpl.hash = _djb_hash(tmpl.bytes, tmpl.size);
282 
283     for (_FtFaceDataProxy &face_proxy : _local_open_faces) {
284         _ft_face_data *l = static_cast<_ft_face_data *>(face_proxy);
285         if (_ft_face_data_equal(l, &tmpl)) {
286             if (tmpl.fd != -1) {
287 #    if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
288                 munmap((char *)tmpl.bytes, tmpl.size);
289 #    else
290                 munmap(tmpl.bytes, tmpl.size);
291 #    endif
292                 close(tmpl.fd);
293             } else {
294                 gfree(tmpl.bytes);
295             }
296             *face_out = l->face;
297             *font_face_out = cairo_font_face_reference(l->font_face);
298             return true;
299         }
300     }
301 
302     /* not a dup, open and insert into list */
303     if (FT_New_Memory_Face(lib, (FT_Byte *)tmpl.bytes, tmpl.size, 0, &tmpl.face)) {
304         if (tmpl.fd != -1) {
305 #    if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
306             munmap((char *)tmpl.bytes, tmpl.size);
307 #    else
308             munmap(tmpl.bytes, tmpl.size);
309 #    endif
310 
311             close(tmpl.fd);
312         }
313         return false;
314     }
315 
316     struct _ft_face_data *l = (struct _ft_face_data *)gmallocn(1, sizeof(struct _ft_face_data));
317     *l = tmpl;
318 
319     l->font_face = cairo_ft_font_face_create_for_ft_face(tmpl.face, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
320     if (cairo_font_face_set_user_data(l->font_face, &_ft_cairo_key, l, _ft_done_face)) {
321         cairo_font_face_destroy(l->font_face);
322         _ft_done_face(l);
323         return false;
324     }
325 
326     _local_open_faces.remove_if([](_FtFaceDataProxy &face_proxy) {
327         _ft_face_data *data = static_cast<_ft_face_data *>(face_proxy);
328         return cairo_font_face_get_reference_count(data->font_face) == 1;
329     });
330     _local_open_faces.emplace_front(l);
331 
332     *face_out = l->face;
333     *font_face_out = l->font_face;
334     return true;
335 }
336 #else
337 #    define _ft_new_face _ft_new_face_uncached
338 #endif
339 
CairoFreeTypeFont(Ref refA,cairo_font_face_t * cairo_font_faceA,int * codeToGIDA,unsigned int codeToGIDLenA,bool substituteA)340 CairoFreeTypeFont::CairoFreeTypeFont(Ref refA, cairo_font_face_t *cairo_font_faceA, int *codeToGIDA, unsigned int codeToGIDLenA, bool substituteA) : CairoFont(refA, cairo_font_faceA, codeToGIDA, codeToGIDLenA, substituteA, true) { }
341 
~CairoFreeTypeFont()342 CairoFreeTypeFont::~CairoFreeTypeFont() { }
343 
create(GfxFont * gfxFont,XRef * xref,FT_Library lib,bool useCIDs)344 CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref, FT_Library lib, bool useCIDs)
345 {
346     GooString *fileName;
347     const char *fileNameC;
348     char *font_data;
349     int font_data_len;
350     int i, n;
351     GfxFontType fontType;
352     GfxFontLoc *fontLoc;
353     char **enc;
354     const char *name;
355     FoFiTrueType *ff;
356     FoFiType1C *ff1c;
357     Ref ref;
358     FT_Face face;
359     cairo_font_face_t *font_face;
360 
361     int *codeToGID;
362     unsigned int codeToGIDLen;
363 
364     codeToGID = nullptr;
365     codeToGIDLen = 0;
366     font_data = nullptr;
367     font_data_len = 0;
368     fileName = nullptr;
369     fileNameC = nullptr;
370 
371     bool substitute = false;
372 
373     ref = *gfxFont->getID();
374     fontType = gfxFont->getType();
375 
376     if (!(fontLoc = gfxFont->locateFont(xref, nullptr))) {
377         error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->c_str() : "(unnamed)");
378         goto err2;
379     }
380 
381     // embedded font
382     if (fontLoc->locType == gfxFontLocEmbedded) {
383         font_data = gfxFont->readEmbFontFile(xref, &font_data_len);
384         if (nullptr == font_data)
385             goto err2;
386 
387         // external font
388     } else { // gfxFontLocExternal
389         fileName = fontLoc->path;
390         fontType = fontLoc->fontType;
391         substitute = true;
392     }
393 
394     if (fileName != nullptr) {
395         fileNameC = fileName->c_str();
396     }
397 
398     switch (fontType) {
399     case fontType1:
400     case fontType1C:
401     case fontType1COT:
402         if (!_ft_new_face(lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
403             error(errSyntaxError, -1, "could not create type1 face");
404             goto err2;
405         }
406 
407         enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
408 
409         codeToGID = (int *)gmallocn(256, sizeof(int));
410         codeToGIDLen = 256;
411         for (i = 0; i < 256; ++i) {
412             codeToGID[i] = 0;
413             if ((name = enc[i])) {
414                 codeToGID[i] = FT_Get_Name_Index(face, (char *)name);
415                 if (codeToGID[i] == 0) {
416                     Unicode u;
417                     u = globalParams->mapNameToUnicodeText(name);
418                     codeToGID[i] = FT_Get_Char_Index(face, u);
419                 }
420                 if (codeToGID[i] == 0) {
421                     name = GfxFont::getAlternateName(name);
422                     if (name) {
423                         codeToGID[i] = FT_Get_Name_Index(face, (char *)name);
424                     }
425                 }
426             }
427         }
428         break;
429     case fontCIDType2:
430     case fontCIDType2OT:
431         codeToGID = nullptr;
432         n = 0;
433         if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
434             n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
435             if (n) {
436                 codeToGID = (int *)gmallocn(n, sizeof(int));
437                 memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(int));
438             }
439         } else {
440             if (font_data != nullptr) {
441                 ff = FoFiTrueType::make(font_data, font_data_len);
442             } else {
443                 ff = FoFiTrueType::load(fileNameC);
444             }
445             if (!ff)
446                 goto err2;
447             codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
448             delete ff;
449         }
450         codeToGIDLen = n;
451         /* Fall through */
452     case fontTrueType:
453     case fontTrueTypeOT:
454         if (font_data != nullptr) {
455             ff = FoFiTrueType::make(font_data, font_data_len);
456         } else {
457             ff = FoFiTrueType::load(fileNameC);
458         }
459         if (!ff) {
460             error(errSyntaxError, -1, "failed to load truetype font\n");
461             goto err2;
462         }
463         /* This might be set already for the CIDType2 case */
464         if (fontType == fontTrueType || fontType == fontTrueTypeOT) {
465             codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
466             codeToGIDLen = 256;
467         }
468         delete ff;
469         if (!_ft_new_face(lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
470             error(errSyntaxError, -1, "could not create truetype face\n");
471             goto err2;
472         }
473         break;
474 
475     case fontCIDType0:
476     case fontCIDType0C:
477 
478         codeToGID = nullptr;
479         codeToGIDLen = 0;
480 
481         if (!useCIDs) {
482             if (font_data != nullptr) {
483                 ff1c = FoFiType1C::make(font_data, font_data_len);
484             } else {
485                 ff1c = FoFiType1C::load(fileNameC);
486             }
487             if (ff1c) {
488                 codeToGID = ff1c->getCIDToGIDMap((int *)&codeToGIDLen);
489                 delete ff1c;
490             }
491         }
492 
493         if (!_ft_new_face(lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
494             error(errSyntaxError, -1, "could not create cid face\n");
495             goto err2;
496         }
497         break;
498 
499     case fontCIDType0COT:
500         codeToGID = nullptr;
501         n = 0;
502         if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
503             n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
504             if (n) {
505                 codeToGID = (int *)gmallocn(n, sizeof(int));
506                 memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(int));
507             }
508         }
509         codeToGIDLen = n;
510 
511         if (!codeToGID) {
512             if (!useCIDs) {
513                 if (font_data != nullptr) {
514                     ff = FoFiTrueType::make(font_data, font_data_len);
515                 } else {
516                     ff = FoFiTrueType::load(fileNameC);
517                 }
518                 if (ff) {
519                     if (ff->isOpenTypeCFF()) {
520                         codeToGID = ff->getCIDToGIDMap((int *)&codeToGIDLen);
521                     }
522                     delete ff;
523                 }
524             }
525         }
526         if (!_ft_new_face(lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
527             error(errSyntaxError, -1, "could not create cid (OT) face\n");
528             goto err2;
529         }
530         break;
531 
532     default:
533         fprintf(stderr, "font type %d not handled\n", (int)fontType);
534         goto err2;
535         break;
536     }
537 
538     delete fontLoc;
539     return new CairoFreeTypeFont(ref, font_face, codeToGID, codeToGIDLen, substitute);
540 
541 err2:
542     /* hmm? */
543     delete fontLoc;
544     gfree(codeToGID);
545     gfree(font_data);
546     fprintf(stderr, "some font thing failed\n");
547     return nullptr;
548 }
549 
550 //------------------------------------------------------------------------
551 // CairoType3Font
552 //------------------------------------------------------------------------
553 
554 static const cairo_user_data_key_t type3_font_key = { 0 };
555 
556 typedef struct _type3_font_info
557 {
558     GfxFont *font;
559     PDFDoc *doc;
560     CairoFontEngine *fontEngine;
561     bool printing;
562     XRef *xref;
563 } type3_font_info_t;
564 
_free_type3_font_info(void * closure)565 static void _free_type3_font_info(void *closure)
566 {
567     type3_font_info_t *info = (type3_font_info_t *)closure;
568 
569     info->font->decRefCnt();
570     free(info);
571 }
572 
_init_type3_glyph(cairo_scaled_font_t * scaled_font,cairo_t * cr,cairo_font_extents_t * extents)573 static cairo_status_t _init_type3_glyph(cairo_scaled_font_t *scaled_font, cairo_t *cr, cairo_font_extents_t *extents)
574 {
575     type3_font_info_t *info;
576     GfxFont *font;
577 
578     info = (type3_font_info_t *)cairo_font_face_get_user_data(cairo_scaled_font_get_font_face(scaled_font), &type3_font_key);
579     font = info->font;
580     const double *mat = font->getFontBBox();
581     extents->ascent = mat[3]; /* y2 */
582     extents->descent = -mat[3]; /* -y1 */
583     extents->height = extents->ascent + extents->descent;
584     extents->max_x_advance = mat[2] - mat[1]; /* x2 - x1 */
585     extents->max_y_advance = 0;
586 
587     return CAIRO_STATUS_SUCCESS;
588 }
589 
_render_type3_glyph(cairo_scaled_font_t * scaled_font,unsigned long glyph,cairo_t * cr,cairo_text_extents_t * metrics)590 static cairo_status_t _render_type3_glyph(cairo_scaled_font_t *scaled_font, unsigned long glyph, cairo_t *cr, cairo_text_extents_t *metrics)
591 {
592     Dict *charProcs;
593     Object charProc;
594     CairoOutputDev *output_dev;
595     cairo_matrix_t matrix, invert_y_axis;
596     const double *mat;
597     double wx, wy;
598     PDFRectangle box;
599     type3_font_info_t *info;
600     GfxFont *font;
601     Dict *resDict;
602     Gfx *gfx;
603 
604     info = (type3_font_info_t *)cairo_font_face_get_user_data(cairo_scaled_font_get_font_face(scaled_font), &type3_font_key);
605 
606     font = info->font;
607     resDict = ((Gfx8BitFont *)font)->getResources();
608     charProcs = ((Gfx8BitFont *)(info->font))->getCharProcs();
609     if (!charProcs)
610         return CAIRO_STATUS_USER_FONT_ERROR;
611 
612     if ((int)glyph >= charProcs->getLength())
613         return CAIRO_STATUS_USER_FONT_ERROR;
614 
615     mat = font->getFontMatrix();
616     matrix.xx = mat[0];
617     matrix.yx = mat[1];
618     matrix.xy = mat[2];
619     matrix.yy = mat[3];
620     matrix.x0 = mat[4];
621     matrix.y0 = mat[5];
622     cairo_matrix_init_scale(&invert_y_axis, 1, -1);
623     cairo_matrix_multiply(&matrix, &matrix, &invert_y_axis);
624     cairo_transform(cr, &matrix);
625 
626     output_dev = new CairoOutputDev();
627     output_dev->setCairo(cr);
628     output_dev->setPrinting(info->printing);
629 
630     mat = font->getFontBBox();
631     box.x1 = mat[0];
632     box.y1 = mat[1];
633     box.x2 = mat[2];
634     box.y2 = mat[3];
635     gfx = new Gfx(info->doc, output_dev, resDict, &box, nullptr);
636     output_dev->startDoc(info->doc, info->fontEngine);
637     output_dev->startPage(1, gfx->getState(), gfx->getXRef());
638     output_dev->setInType3Char(true);
639     charProc = charProcs->getVal(glyph);
640     gfx->display(&charProc);
641 
642     output_dev->getType3GlyphWidth(&wx, &wy);
643     cairo_matrix_transform_distance(&matrix, &wx, &wy);
644     metrics->x_advance = wx;
645     metrics->y_advance = wy;
646     if (output_dev->hasType3GlyphBBox()) {
647         double *bbox = output_dev->getType3GlyphBBox();
648 
649         cairo_matrix_transform_point(&matrix, &bbox[0], &bbox[1]);
650         cairo_matrix_transform_point(&matrix, &bbox[2], &bbox[3]);
651         metrics->x_bearing = bbox[0];
652         metrics->y_bearing = bbox[1];
653         metrics->width = bbox[2] - bbox[0];
654         metrics->height = bbox[3] - bbox[1];
655     }
656 
657     delete gfx;
658     delete output_dev;
659 
660     return CAIRO_STATUS_SUCCESS;
661 }
662 
create(GfxFont * gfxFont,PDFDoc * doc,CairoFontEngine * fontEngine,bool printing,XRef * xref)663 CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc, CairoFontEngine *fontEngine, bool printing, XRef *xref)
664 {
665     type3_font_info_t *info;
666     cairo_font_face_t *font_face;
667     Ref ref;
668     int *codeToGID;
669     unsigned int codeToGIDLen;
670     int i, j;
671     char **enc;
672     Dict *charProcs;
673     char *name;
674 
675     charProcs = ((Gfx8BitFont *)gfxFont)->getCharProcs();
676     info = (type3_font_info_t *)malloc(sizeof(*info));
677     ref = *gfxFont->getID();
678     font_face = cairo_user_font_face_create();
679     cairo_user_font_face_set_init_func(font_face, _init_type3_glyph);
680     cairo_user_font_face_set_render_glyph_func(font_face, _render_type3_glyph);
681     gfxFont->incRefCnt();
682     info->font = gfxFont;
683     info->doc = doc;
684     info->fontEngine = fontEngine;
685     info->printing = printing;
686     info->xref = xref;
687 
688     cairo_font_face_set_user_data(font_face, &type3_font_key, (void *)info, _free_type3_font_info);
689 
690     enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
691     codeToGID = (int *)gmallocn(256, sizeof(int));
692     codeToGIDLen = 256;
693     for (i = 0; i < 256; ++i) {
694         codeToGID[i] = 0;
695         if (charProcs && (name = enc[i])) {
696             for (j = 0; j < charProcs->getLength(); j++) {
697                 if (strcmp(name, charProcs->getKey(j)) == 0) {
698                     codeToGID[i] = j;
699                 }
700             }
701         }
702     }
703 
704     return new CairoType3Font(ref, font_face, codeToGID, codeToGIDLen, printing, xref);
705 }
706 
CairoType3Font(Ref refA,cairo_font_face_t * cairo_font_faceA,int * codeToGIDA,unsigned int codeToGIDLenA,bool printingA,XRef * xref)707 CairoType3Font::CairoType3Font(Ref refA, cairo_font_face_t *cairo_font_faceA, int *codeToGIDA, unsigned int codeToGIDLenA, bool printingA, XRef *xref) : CairoFont(refA, cairo_font_faceA, codeToGIDA, codeToGIDLenA, false, printingA) { }
708 
~CairoType3Font()709 CairoType3Font::~CairoType3Font() { }
710 
matches(Ref & other,bool printingA)711 bool CairoType3Font::matches(Ref &other, bool printingA)
712 {
713     return (other == ref && printing == printingA);
714 }
715 
716 //------------------------------------------------------------------------
717 // CairoFontEngine
718 //------------------------------------------------------------------------
719 
720 #define fontEngineLocker() std::unique_lock<std::recursive_mutex> locker(mutex)
721 
CairoFontEngine(FT_Library libA)722 CairoFontEngine::CairoFontEngine(FT_Library libA)
723 {
724     int i;
725 
726     lib = libA;
727     for (i = 0; i < cairoFontCacheSize; ++i) {
728         fontCache[i] = nullptr;
729     }
730 
731     FT_Int major, minor, patch;
732     // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
733     FT_Library_Version(lib, &major, &minor, &patch);
734     useCIDs = major > 2 || (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
735 }
736 
~CairoFontEngine()737 CairoFontEngine::~CairoFontEngine()
738 {
739     int i;
740 
741     for (i = 0; i < cairoFontCacheSize; ++i) {
742         if (fontCache[i])
743             delete fontCache[i];
744     }
745 }
746 
getFont(GfxFont * gfxFont,PDFDoc * doc,bool printing,XRef * xref)747 CairoFont *CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, bool printing, XRef *xref)
748 {
749     int i, j;
750     Ref ref;
751     CairoFont *font;
752     GfxFontType fontType;
753 
754     fontEngineLocker();
755     ref = *gfxFont->getID();
756 
757     for (i = 0; i < cairoFontCacheSize; ++i) {
758         font = fontCache[i];
759         if (font && font->matches(ref, printing)) {
760             for (j = i; j > 0; --j) {
761                 fontCache[j] = fontCache[j - 1];
762             }
763             fontCache[0] = font;
764             return font;
765         }
766     }
767 
768     fontType = gfxFont->getType();
769     if (fontType == fontType3)
770         font = CairoType3Font::create(gfxFont, doc, this, printing, xref);
771     else
772         font = CairoFreeTypeFont::create(gfxFont, xref, lib, useCIDs);
773 
774     // XXX: if font is null should we still insert it into the cache?
775     if (fontCache[cairoFontCacheSize - 1]) {
776         delete fontCache[cairoFontCacheSize - 1];
777     }
778     for (j = cairoFontCacheSize - 1; j > 0; --j) {
779         fontCache[j] = fontCache[j - 1];
780     }
781     fontCache[0] = font;
782     return font;
783 }
784