1 //========================================================================
5 // Copyright 2003 Glyph & Cog, LLC
6 // Copyright 2004 Red Hat, Inc
8 //========================================================================
14 #include "CairoFontEngine.h"
15 #include "CharCodeToUnicode.h"
16 #include "GlobalParams.h"
17 #include <fofi/FoFiTrueType.h>
18 #include <fofi/FoFiType1C.h>
19 #include "goo/gfile.h"
22 #ifdef USE_GCC_PRAGMAS
23 #pragma implementation
26 static void fileWrite(void *stream
, char *data
, int len
) {
27 fwrite(data
, 1, len
, (FILE *)stream
);
30 //------------------------------------------------------------------------
32 //------------------------------------------------------------------------
34 static void cairo_font_face_destroy (void *data
)
36 CairoFont
*font
= (CairoFont
*) data
;
41 CairoFont
*CairoFont::create(GfxFont
*gfxFont
, XRef
*xref
, FT_Library lib
, GBool useCIDs
) {
43 Object refObj
, strObj
;
44 GooString
*tmpFileName
, *fileName
, *substName
,*tmpFileName2
;
45 DisplayFontParam
*dfp
;
47 int c
, i
, n
, code
, cmap
;
53 CharCodeToUnicode
*ctu
;
56 static cairo_user_data_key_t cairo_font_face_key
;
57 cairo_font_face_t
*cairo_font_face
;
66 cairo_font_face
= NULL
;
68 ref
= *gfxFont
->getID();
69 fontType
= gfxFont
->getType();
73 if (gfxFont
->getEmbeddedFontID(&embRef
)) {
74 if (!openTempFile(&tmpFileName
, &tmpFile
, "wb", NULL
)) {
75 error(-1, "Couldn't create temporary font file");
79 refObj
.initRef(embRef
.num
, embRef
.gen
);
80 refObj
.fetch(xref
, &strObj
);
83 while ((c
= strObj
.streamGetChar()) != EOF
) {
89 fileName
= tmpFileName
;
91 } else if (!(fileName
= gfxFont
->getExtFontFile())) {
92 // look for a display font mapping or a substitute font
94 if (gfxFont
->getName()) {
95 dfp
= globalParams
->getDisplayFont(gfxFont
);
98 error(-1, "Couldn't find a font for '%s'",
99 gfxFont
->getName() ? gfxFont
->getName()->getCString()
105 fileName
= dfp
->t1
.fileName
;
106 fontType
= gfxFont
->isCIDFont() ? fontCIDType0
: fontType1
;
109 fileName
= dfp
->tt
.fileName
;
110 fontType
= gfxFont
->isCIDFont() ? fontCIDType2
: fontTrueType
;
118 if (FT_New_Face(lib
, fileName
->getCString(), 0, &face
)) {
119 error(-1, "could not create type1 face");
123 enc
= ((Gfx8BitFont
*)gfxFont
)->getEncoding();
125 codeToGID
= (Gushort
*)gmallocn(256, sizeof(int));
127 for (i
= 0; i
< 256; ++i
) {
129 if ((name
= enc
[i
])) {
130 codeToGID
[i
] = (Gushort
)FT_Get_Name_Index(face
, name
);
139 // create a CID-to-GID mapping, via Unicode
140 if ((ctu
= ((GfxCIDFont
*)gfxFont
)->getToUnicode())) {
141 if ((ff
= FoFiTrueType::load(fileName
->getCString()))) {
142 // look for a Unicode cmap
143 for (cmap
= 0; cmap
< ff
->getNumCmaps(); ++cmap
) {
144 if ((ff
->getCmapPlatform(cmap
) == 3 &&
145 ff
->getCmapEncoding(cmap
) == 1) ||
146 ff
->getCmapPlatform(cmap
) == 0) {
150 if (cmap
< ff
->getNumCmaps()) {
151 // map CID -> Unicode -> GID
152 n
= ctu
->getLength();
153 codeToGID
= (Gushort
*)gmallocn(n
, sizeof(Gushort
));
154 for (code
= 0; code
< n
; ++code
) {
155 if (ctu
->mapToUnicode(code
, uBuf
, 8) > 0) {
156 codeToGID
[code
] = ff
->mapCodeToGID(cmap
, uBuf
[0]);
166 error(-1, "Couldn't find a mapping to Unicode for font '%s'",
167 gfxFont
->getName() ? gfxFont
->getName()->getCString()
172 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
173 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
174 codeToGID
= (Gushort
*)gmallocn(n
, sizeof(Gushort
));
175 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
176 n
* sizeof(Gushort
));
182 if (!(ff
= FoFiTrueType::load(fileName
->getCString()))) {
183 error(-1, "failed to load truetype font\n");
186 /* This might be set already for the CIDType2 case */
187 if (fontType
== fontTrueType
) {
188 codeToGID
= ((Gfx8BitFont
*)gfxFont
)->getCodeToGIDMap(ff
);
191 if (!openTempFile(&tmpFileName2
, &tmpFile
, "wb", NULL
)) {
193 error(-1, "failed to open truetype tempfile\n");
196 ff
->writeTTF(&fileWrite
, tmpFile
);
200 if (FT_New_Face(lib
, tmpFileName2
->getCString(), 0, &face
)) {
201 error(-1, "could not create truetype face\n");
204 unlink (tmpFileName2
->getCString());
216 if ((ff1c
= FoFiType1C::load(fileName
->getCString()))) {
217 codeToGID
= ff1c
->getCIDToGIDMap(&codeToGIDLen
);
222 if (FT_New_Face(lib
, fileName
->getCString(), 0, &face
)) {
225 error(-1, "could not create cid face\n");
231 printf ("font type not handled\n");
236 // delete the (temporary) font file -- with Unix hard link
237 // semantics, this will remove the last link; otherwise it will
238 // return an error, leaving the file to be deleted later
239 if (fileName
== tmpFileName
) {
240 unlink (fileName
->getCString());
244 cairo_font_face
= cairo_ft_font_face_create_for_ft_face (face
,
247 if (cairo_font_face
== NULL
) {
248 error(-1, "could not create cairo font\n");
249 goto err2
; /* this doesn't do anything, but it looks like we're
250 * handling the error */
252 CairoFont
*ret
= new CairoFont(ref
, cairo_font_face
, face
, codeToGID
, codeToGIDLen
);
253 cairo_font_face_set_user_data (cairo_font_face
,
254 &cairo_font_face_key
,
256 cairo_font_face_destroy
);
262 printf ("some font thing failed\n");
266 CairoFont::CairoFont(Ref ref
, cairo_font_face_t
*cairo_font_face
, FT_Face face
,
267 Gushort
*codeToGID
, int codeToGIDLen
) : ref(ref
), cairo_font_face(cairo_font_face
),
268 face(face
), codeToGID(codeToGID
),
269 codeToGIDLen(codeToGIDLen
) { }
271 CairoFont::~CairoFont() {
277 CairoFont::matches(Ref
&other
) {
278 return (other
.num
== ref
.num
&& other
.gen
== ref
.gen
);
282 CairoFont::getFontFace(void) {
283 return cairo_font_face
;
287 CairoFont::getGlyph(CharCode code
,
288 Unicode
*u
, int uLen
) {
291 if (codeToGID
&& code
< codeToGIDLen
) {
292 gid
= (FT_UInt
)codeToGID
[code
];
299 //------------------------------------------------------------------------
301 //------------------------------------------------------------------------
303 CairoFontEngine::CairoFontEngine(FT_Library libA
) {
307 for (i
= 0; i
< cairoFontCacheSize
; ++i
) {
311 FT_Int major
, minor
, patch
;
312 // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
313 FT_Library_Version(lib
, &major
, &minor
, &patch
);
314 useCIDs
= major
> 2 ||
315 (major
== 2 && (minor
> 1 || (minor
== 1 && patch
> 7)));
318 CairoFontEngine::~CairoFontEngine() {
321 for (i
= 0; i
< cairoFontCacheSize
; ++i
) {
328 CairoFontEngine::getFont(GfxFont
*gfxFont
, XRef
*xref
) {
332 GfxFontType fontType
;
334 fontType
= gfxFont
->getType();
335 if (fontType
== fontType3
) {
336 /* Need to figure this out later */
340 ref
= *gfxFont
->getID();
342 for (i
= 0; i
< cairoFontCacheSize
; ++i
) {
344 if (font
&& font
->matches(ref
)) {
345 for (j
= i
; j
> 0; --j
) {
346 fontCache
[j
] = fontCache
[j
-1];
353 font
= CairoFont::create (gfxFont
, xref
, lib
, useCIDs
);
354 //XXX: if font is null should we still insert it into the cache?
355 if (fontCache
[cairoFontCacheSize
- 1]) {
356 delete fontCache
[cairoFontCacheSize
- 1];
358 for (j
= cairoFontCacheSize
- 1; j
> 0; --j
) {
359 fontCache
[j
] = fontCache
[j
-1];