1 //========================================================================
5 // Copyright 2003 Glyph & Cog, LLC
6 // Copyright 2004 Red Hat, Inc
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 //========================================================================
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"
52 #if HAVE_FCNTL_H && HAVE_SYS_MMAN_H && HAVE_SYS_STAT_H
56 #define CAN_CHECK_OPEN_FACES 1
59 #ifdef USE_GCC_PRAGMAS
60 #pragma implementation
64 # define fontEngineLocker() MutexLocker locker(&mutex)
66 # define fontEngineLocker()
69 //------------------------------------------------------------------------
71 //------------------------------------------------------------------------
73 CairoFont::CairoFont(Ref ref
,
74 cairo_font_face_t
*cairo_font_face
,
78 GBool printing
) : ref(ref
),
79 cairo_font_face(cairo_font_face
),
81 codeToGIDLen(codeToGIDLen
),
82 substitute(substitute
),
83 printing(printing
) { }
85 CairoFont::~CairoFont() {
86 cairo_font_face_destroy (cairo_font_face
);
91 CairoFont::matches(Ref
&other
, GBool printingA
) {
92 return (other
.num
== ref
.num
&& other
.gen
== ref
.gen
);
96 CairoFont::getFontFace(void) {
97 return cairo_font_face
;
101 CairoFont::getGlyph(CharCode code
,
102 Unicode
*u
, int uLen
) {
105 if (codeToGID
&& code
< codeToGIDLen
) {
106 gid
= (FT_UInt
)codeToGID
[code
];
114 CairoFont::getSubstitutionCorrection(GfxFont
*gfxFont
)
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') {
130 w1
= ((Gfx8BitFont
*)gfxFont
)->getWidth(code
);
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
) {
159 //------------------------------------------------------------------------
161 //------------------------------------------------------------------------
163 static cairo_user_data_key_t _ft_cairo_key
;
166 _ft_done_face_uncached (void *closure
)
168 FT_Face face
= (FT_Face
) closure
;
173 _ft_new_face_uncached (FT_Library lib
,
174 const char *filename
,
178 cairo_font_face_t
**font_face_out
)
181 cairo_font_face_t
*font_face
;
183 if (font_data
== NULL
) {
184 if (FT_New_Face (lib
, filename
, 0, &face
))
187 if (FT_New_Memory_Face (lib
, (unsigned char *)font_data
, font_data_len
, 0, &face
))
191 font_face
= cairo_ft_font_face_create_for_ft_face (face
,
194 if (cairo_font_face_set_user_data (font_face
,
197 _ft_done_face_uncached
))
199 _ft_done_face_uncached (face
);
200 cairo_font_face_destroy (font_face
);
205 *font_face_out
= font_face
;
209 #if CAN_CHECK_OPEN_FACES
210 static struct _ft_face_data
{
211 struct _ft_face_data
*prev
, *next
, **head
;
216 unsigned char *bytes
;
220 cairo_font_face_t
*font_face
;
224 _djb_hash (const unsigned char *bytes
, size_t len
)
226 unsigned long hash
= 5381;
228 unsigned char c
= *bytes
++;
236 _ft_face_data_equal (struct _ft_face_data
*a
, struct _ft_face_data
*b
)
238 if (a
->lib
!= b
->lib
)
240 if (a
->size
!= b
->size
)
242 if (a
->hash
!= b
->hash
)
245 return memcmp (a
->bytes
, b
->bytes
, a
->size
) == 0;
249 _ft_done_face (void *closure
)
251 struct _ft_face_data
*data
= (struct _ft_face_data
*) closure
;
254 data
->next
->prev
= data
->prev
;
256 data
->prev
->next
= data
->next
;
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
);
264 munmap (data
->bytes
, data
->size
);
271 FT_Done_Face (data
->face
);
276 _ft_new_face (FT_Library lib
,
277 const char *filename
,
281 cairo_font_face_t
**font_face_out
)
283 struct _ft_face_data
*l
;
285 struct _ft_face_data tmpl
;
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
);
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) {
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
,
303 if (tmpl
.bytes
== MAP_FAILED
) {
305 return _ft_new_face_uncached (lib
, filename
, font_data
, font_data_len
, face_out
, font_face_out
);
307 tmpl
.size
= st
.st_size
;
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 */
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
)) {
320 #if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
321 munmap ((char*)tmpl
.bytes
, tmpl
.size
);
323 munmap (tmpl
.bytes
, tmpl
.size
);
330 *font_face_out
= cairo_font_face_reference (l
->font_face
);
335 /* not a dup, open and insert into list */
336 if (FT_New_Memory_Face (lib
,
337 (FT_Byte
*) tmpl
.bytes
, tmpl
.size
,
341 #if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
342 munmap ((char*)tmpl
.bytes
, tmpl
.size
);
344 munmap (tmpl
.bytes
, tmpl
.size
);
352 l
= (struct _ft_face_data
*) gmallocn (1, sizeof (struct _ft_face_data
));
355 l
->next
= _ft_open_faces
;
357 _ft_open_faces
->prev
= l
;
360 l
->font_face
= cairo_ft_font_face_create_for_ft_face (tmpl
.face
,
363 if (cairo_font_face_set_user_data (l
->font_face
,
368 cairo_font_face_destroy (l
->font_face
);
374 *font_face_out
= l
->font_face
;
378 #define _ft_new_face _ft_new_face_uncached
381 CairoFreeTypeFont::CairoFreeTypeFont(Ref ref
,
382 cairo_font_face_t
*cairo_font_face
,
385 GBool substitute
) : CairoFont(ref
,
392 CairoFreeTypeFont::~CairoFreeTypeFont() { }
394 CairoFreeTypeFont
*CairoFreeTypeFont::create(GfxFont
*gfxFont
, XRef
*xref
,
395 FT_Library lib
, GBool useCIDs
) {
396 Object refObj
, strObj
;
402 GfxFontType fontType
;
410 cairo_font_face_t
*font_face
;
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()
435 if (fontLoc
->locType
== gfxFontLocEmbedded
) {
436 font_data
= gfxFont
->readEmbFontFile(xref
, &font_data_len
);
437 if (NULL
== font_data
)
441 } else { // gfxFontLocExternal
442 fileName
= fontLoc
->path
;
443 fontType
= fontLoc
->fontType
;
447 if (fileName
!= NULL
) {
448 fileNameC
= fileName
->getCString();
455 if (! _ft_new_face (lib
, fileNameC
, font_data
, font_data_len
, &face
, &font_face
)) {
456 error(errSyntaxError
, -1, "could not create type1 face");
460 enc
= ((Gfx8BitFont
*)gfxFont
)->getEncoding();
462 codeToGID
= (int *)gmallocn(256, sizeof(int));
464 for (i
= 0; i
< 256; ++i
) {
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
);
471 codeToGID
[i
] = FT_Get_Name_Index(face
, (char*)name
);
481 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
482 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
484 codeToGID
= (int *)gmallocn(n
, sizeof(int));
485 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
489 if (font_data
!= NULL
) {
490 ff
= FoFiTrueType::make(font_data
, font_data_len
);
492 ff
= FoFiTrueType::load(fileNameC
);
496 codeToGID
= ((GfxCIDFont
*)gfxFont
)->getCodeToGIDMap(ff
, &n
);
503 if (font_data
!= NULL
) {
504 ff
= FoFiTrueType::make(font_data
, font_data_len
);
506 ff
= FoFiTrueType::load(fileNameC
);
509 error(errSyntaxError
, -1, "failed to load truetype font\n");
512 /* This might be set already for the CIDType2 case */
513 if (fontType
== fontTrueType
|| fontType
== fontTrueTypeOT
) {
514 codeToGID
= ((Gfx8BitFont
*)gfxFont
)->getCodeToGIDMap(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");
532 if (font_data
!= NULL
) {
533 ff1c
= FoFiType1C::make(font_data
, font_data_len
);
535 ff1c
= FoFiType1C::load(fileNameC
);
538 codeToGID
= ff1c
->getCIDToGIDMap((int *)&codeToGIDLen
);
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");
549 case fontCIDType0COT
:
552 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
553 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
555 codeToGID
= (int *)gmallocn(n
, sizeof(int));
556 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
564 if (font_data
!= NULL
) {
565 ff
= FoFiTrueType::make(font_data
, font_data_len
);
567 ff
= FoFiTrueType::load(fileNameC
);
570 if (ff
->isOpenTypeCFF()) {
571 codeToGID
= ff
->getCIDToGIDMap((int *)&codeToGIDLen
);
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");
584 fprintf (stderr
, "font type %d not handled\n", (int)fontType
);
590 return new CairoFreeTypeFont(ref
,
592 codeToGID
, codeToGIDLen
,
600 fprintf (stderr
, "some font thing failed\n");
604 //------------------------------------------------------------------------
606 //------------------------------------------------------------------------
608 static const cairo_user_data_key_t type3_font_key
= {0};
610 typedef struct _type3_font_info
{
613 CairoFontEngine
*fontEngine
;
619 _free_type3_font_info(void *closure
)
621 type3_font_info_t
*info
= (type3_font_info_t
*) closure
;
623 info
->font
->decRefCnt();
627 static cairo_status_t
628 _init_type3_glyph (cairo_scaled_font_t
*scaled_font
,
630 cairo_font_extents_t
*extents
)
632 type3_font_info_t
*info
;
636 info
= (type3_font_info_t
*)
637 cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_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
,
654 cairo_text_extents_t
*metrics
)
658 CairoOutputDev
*output_dev
;
659 cairo_matrix_t matrix
, invert_y_axis
;
663 type3_font_info_t
*info
;
668 info
= (type3_font_info_t
*)
669 cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font
),
673 resDict
= ((Gfx8BitFont
*)font
)->getResources();
674 charProcs
= ((Gfx8BitFont
*)(info
->font
))->getCharProcs();
676 return CAIRO_STATUS_USER_FONT_ERROR
;
678 if ((int)glyph
>= charProcs
->getLength())
679 return CAIRO_STATUS_USER_FONT_ERROR
;
681 mat
= font
->getFontMatrix();
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();
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];
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
;
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
;
753 info
->fontEngine
= fontEngine
;
754 info
->printing
= printing
;
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));
762 for (i
= 0; i
< 256; ++i
) {
764 if (charProcs
&& (name
= enc
[i
])) {
765 for (j
= 0; j
< charProcs
->getLength(); j
++) {
766 if (strcmp(name
, charProcs
->getKey(j
)) == 0) {
773 return new CairoType3Font(ref
, doc
, font_face
, codeToGID
, codeToGIDLen
, printing
, xref
);
776 CairoType3Font::CairoType3Font(Ref ref
,
778 cairo_font_face_t
*cairo_font_face
,
781 GBool printing
, XRef
*xref
) : CairoFont(ref
,
789 CairoType3Font::~CairoType3Font() { }
792 CairoType3Font::matches(Ref
&other
, GBool printingA
) {
793 return (other
.num
== ref
.num
&& other
.gen
== ref
.gen
&& printing
== printingA
);
797 //------------------------------------------------------------------------
799 //------------------------------------------------------------------------
801 CairoFontEngine::CairoFontEngine(FT_Library libA
) {
805 for (i
= 0; i
< cairoFontCacheSize
; ++i
) {
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)));
819 CairoFontEngine::~CairoFontEngine() {
822 for (i
= 0; i
< cairoFontCacheSize
; ++i
) {
827 gDestroyMutex(&mutex
);
832 CairoFontEngine::getFont(GfxFont
*gfxFont
, PDFDoc
*doc
, GBool printing
, XRef
*xref
) {
836 GfxFontType fontType
;
839 ref
= *gfxFont
->getID();
841 for (i
= 0; i
< cairoFontCacheSize
; ++i
) {
843 if (font
&& font
->matches(ref
, printing
)) {
844 for (j
= i
; j
> 0; --j
) {
845 fontCache
[j
] = fontCache
[j
-1];
852 fontType
= gfxFont
->getType();
853 if (fontType
== fontType3
)
854 font
= CairoType3Font::create (gfxFont
, doc
, this, printing
, xref
);
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];