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