CairoFontEngine.cc 7.37 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
//========================================================================
//
// CairoFontEngine.cc
//
// Copyright 2003 Glyph & Cog, LLC
// Copyright 2004 Red Hat, Inc
//
//========================================================================

#include <config.h>

#include "config.h"
#include <string.h>
#include "CairoFontEngine.h"
#include "GlobalParams.h"
#include <fofi/FoFiTrueType.h>
#include <fofi/FoFiType1C.h>
#include "goo/gfile.h"
#include "Error.h"

#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif

static void fileWrite(void *stream, char *data, int len) {
  fwrite(data, 1, len, (FILE *)stream);
}

//------------------------------------------------------------------------
// CairoFont
//------------------------------------------------------------------------

33
static void cairo_font_face_destroy (void *data)
34 35 36 37 38 39
{
  CairoFont *font = (CairoFont *) data;

  delete font;
}

40
CairoFont::CairoFont(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
41 42 43 44 45 46 47 48 49 50 51
  Ref embRef;
  Object refObj, strObj;
  GooString *tmpFileName, *fileName, *substName,*tmpFileName2;
  DisplayFontParam *dfp;
  FILE *tmpFile;
  int c, i, n;
  GfxFontType fontType;
  char **enc;
  char *name;
  FoFiTrueType *ff;
  FoFiType1C *ff1c;
52
  static cairo_user_data_key_t cairo_font_face_key;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
53 54 55
  
  codeToGID = NULL;
  codeToGIDLen = 0;
56
  cairo_font_face = NULL;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
57 58 59 60 61
  
  ref = *gfxFont->getID();
  fontType = gfxFont->getType();

  tmpFileName = NULL;
62

Kristian Høgsberg's avatar
Kristian Høgsberg committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  if (gfxFont->getEmbeddedFontID(&embRef)) {
    if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
      error(-1, "Couldn't create temporary font file");
      goto err2;
    }
    
    refObj.initRef(embRef.num, embRef.gen);
    refObj.fetch(xref, &strObj);
    refObj.free();
    strObj.streamReset();
    while ((c = strObj.streamGetChar()) != EOF) {
      fputc(c, tmpFile);
    }
    strObj.streamClose();
    strObj.free();
    fclose(tmpFile);
    fileName = tmpFileName;
    
  } else if (!(fileName = gfxFont->getExtFontFile())) {
    // look for a display font mapping or a substitute font
    dfp = NULL;
84 85
    if (gfxFont->getName()) {
      dfp = globalParams->getDisplayFont(gfxFont);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    }
    if (!dfp) {
      error(-1, "Couldn't find a font for '%s'",
	    gfxFont->getName() ? gfxFont->getName()->getCString()
	    : "(unnamed)");
      goto err2;
    }
    switch (dfp->kind) {
    case displayFontT1:
      fileName = dfp->t1.fileName;
      fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
      break;
    case displayFontTT:
      fileName = dfp->tt.fileName;
      fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
      break;
    }
  }

  switch (fontType) {
  case fontType1:
  case fontType1C:
    if (FT_New_Face(lib, fileName->getCString(), 0, &face)) {
109
      error(-1, "could not create type1 face");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
110 111 112 113 114
      goto err2;
    }
    
    enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
    
115
    codeToGID = (Gushort *)gmallocn(256, sizeof(int));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
116 117 118 119 120 121 122 123 124 125 126 127
    codeToGIDLen = 256;
    for (i = 0; i < 256; ++i) {
      codeToGID[i] = 0;
      if ((name = enc[i])) {
	codeToGID[i] = (Gushort)FT_Get_Name_Index(face, name);
      }
    }
    break;
    
  case fontCIDType2:
    n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
    codeToGIDLen = n;
128
    codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
129 130 131 132 133
    memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
	   n * sizeof(Gushort));
    /* Fall through */
  case fontTrueType:
    if (!(ff = FoFiTrueType::load(fileName->getCString()))) {
134
      error(-1, "failed to load truetype font\n");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
135 136 137
      goto err2;
    }
    /* This might be set already for the CIDType2 case */
138
    if (fontType == fontTrueType) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
139 140 141 142 143
      codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
      codeToGIDLen = 256;
    }
    if (!openTempFile(&tmpFileName2, &tmpFile, "wb", NULL)) {
      delete ff;
144
      error(-1, "failed to open truetype tempfile\n");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
145 146 147 148 149 150 151
      goto err2;
    }
    ff->writeTTF(&fileWrite, tmpFile);
    fclose(tmpFile);
    delete ff;

    if (FT_New_Face(lib, tmpFileName2->getCString(), 0, &face)) {
152
      error(-1, "could not create truetype face\n");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
153 154 155 156 157 158 159 160
      goto err2;
    }
    unlink (tmpFileName2->getCString());
    delete tmpFileName2;
    break;
    
  case fontCIDType0:
  case fontCIDType0C:
161 162 163 164

    codeToGID = NULL;
    codeToGIDLen = 0;

165 166 167 168 169 170
    if (useCIDs)
    {
      if ((ff1c = FoFiType1C::load(fileName->getCString()))) {
        codeToGID = ff1c->getCIDToGIDMap(&codeToGIDLen);
        delete ff1c;
      }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
171
    }
172 173

    if (FT_New_Face(lib, fileName->getCString(), 0, &face)) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
174
      gfree(codeToGID);
Albert Astals Cid's avatar
Albert Astals Cid committed
175
      codeToGID = NULL;
176
      error(-1, "could not create cid face\n");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
      goto err2;
    }
    break;
    
  default:
    printf ("font type not handled\n");
    goto err2;
    break;
  }

  // delete the (temporary) font file -- with Unix hard link
  // semantics, this will remove the last link; otherwise it will
  // return an error, leaving the file to be deleted later
  if (fileName == tmpFileName) {
    unlink (fileName->getCString());
192
    delete tmpFileName;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
193 194
  }

195 196 197 198
  cairo_font_face = cairo_ft_font_face_create_for_ft_face (face,
							   FT_LOAD_NO_HINTING |
							   FT_LOAD_NO_BITMAP);
  if (cairo_font_face == NULL) {
199
    error(-1, "could not create cairo font\n");
200 201
    goto err2; /* this doesn't do anything, but it looks like we're
		* handling the error */
202
  }
203

204 205 206 207 208
  cairo_font_face_set_user_data (cairo_font_face, 
				 &cairo_font_face_key,
				 this,
				 cairo_font_face_destroy);

Kristian Høgsberg's avatar
Kristian Høgsberg committed
209 210 211 212 213 214 215
  return;
 err2:
  /* hmm? */
  printf ("some font thing failed\n");
}

CairoFont::~CairoFont() {
216
  FT_Done_Face (face);
Albert Astals Cid's avatar
Albert Astals Cid committed
217
  gfree(codeToGID);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
218 219 220
}

GBool
221 222
CairoFont::matches(Ref &other) {
  return (other.num == ref.num && other.gen == ref.gen);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
223 224
}

225 226 227
cairo_font_face_t *
CairoFont::getFontFace(void) {
  return cairo_font_face;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
}

unsigned long
CairoFont::getGlyph(CharCode code,
		    Unicode *u, int uLen) {
  FT_UInt gid;

  if (codeToGID && code < codeToGIDLen) {
    gid = (FT_UInt)codeToGID[code];
  } else {
    gid = (FT_UInt)code;
  }
  return gid;
}

//------------------------------------------------------------------------
// CairoFontEngine
//------------------------------------------------------------------------

CairoFontEngine::CairoFontEngine(FT_Library libA) {
  int i;

  lib = libA;
  for (i = 0; i < cairoFontCacheSize; ++i) {
    fontCache[i] = NULL;
  }
254 255 256 257 258 259
  
  FT_Int major, minor, patch;
  // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
  FT_Library_Version(lib, &major, &minor, &patch);
  useCIDs = major > 2 ||
            (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
260 261 262 263 264 265 266 267 268 269 270 271
}

CairoFontEngine::~CairoFontEngine() {
  int i;
  
  for (i = 0; i < cairoFontCacheSize; ++i) {
    if (fontCache[i])
      delete fontCache[i];
  }
}

CairoFont *
272
CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
273 274 275 276 277 278 279 280 281 282 283 284 285
  int i, j;
  Ref ref;
  CairoFont *font;
  GfxFontType fontType;
  
  fontType = gfxFont->getType();
  if (fontType == fontType3) {
    /* Need to figure this out later */
    //    return NULL;
  }

  ref = *gfxFont->getID();

286
  for (i = 0; i < cairoFontCacheSize; ++i) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
287
    font = fontCache[i];
288
    if (font && font->matches(ref)) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
289 290 291 292 293 294 295 296
      for (j = i; j > 0; --j) {
	fontCache[j] = fontCache[j-1];
      }
      fontCache[0] = font;
      return font;
    }
  }
  
297
  font = new CairoFont (gfxFont, xref, lib, useCIDs);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
298 299 300 301 302 303 304 305 306 307
  if (fontCache[cairoFontCacheSize - 1]) {
    delete fontCache[cairoFontCacheSize - 1];
  }
  for (j = cairoFontCacheSize - 1; j > 0; --j) {
    fontCache[j] = fontCache[j-1];
  }
  fontCache[0] = font;
  return font;
}