Ejemplo n.º 1
0
int
i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) {
  char *name;
  int font_num = font->font_id;

  i_mutex_lock(mutex);

  T1_errno = 0;
  if (T1_LoadFont(font_num)) {
    t1_push_error();
    i_mutex_unlock(mutex);
    return 0;
  }
  name = T1_GetFontName(font_num);

  if (name) {
    size_t len = strlen(name);
    strncpy(name_buf, name, name_buf_size);
    name_buf[name_buf_size-1] = '\0';
    i_mutex_unlock(mutex);
    return len + 1;
  }
  else {
    t1_push_error();
    i_mutex_unlock(mutex);
    return 0;
  }
}
Ejemplo n.º 2
0
int
i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
               char *out) {
  int count = 0;
  int font_num = font->font_id;
  
  i_mutex_lock(mutex);

  mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %u, utf8 %d)\n", 
          font_num, text, (unsigned)len, utf8));

  i_clear_error();
  if (T1_LoadFont(font_num)) {
    t1_push_error();
    i_mutex_unlock(mutex);
    return 0;
  }

  while (len) {
    unsigned long c;
    if (utf8) {
      c = i_utf8_advance(&text, &len);
      if (c == ~0UL) {
        i_push_error(0, "invalid UTF8 character");
	i_mutex_unlock(mutex);
        return 0;
      }
    }
    else {
      c = (unsigned char)*text++;
      --len;
    }
    
    if (c >= 0x100) {
      /* limit of 256 characters for T1 */
      *out++ = 0;
    }
    else {
      char const * name = T1_GetCharName(font_num, (unsigned char)c);

      if (name) {
        *out++ = strcmp(name, ".notdef") != 0;
      }
      else {
        mm_log((2, "  No name found for character %lx\n", c));
        *out++ = 0;
      }
    }
    ++count;
  }

  i_mutex_unlock(mutex);

  return count;
}
Ejemplo n.º 3
0
i_t1_font_t
i_t1_new(char *pfb,char *afm) {
  int font_id;
  i_t1_font_t font;

  i_mutex_lock(mutex);

  i_clear_error();

  if (!t1_initialized && i_init_t1_low(0)) {
    i_mutex_unlock(mutex);
    return NULL;
  }

  mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
  font_id = T1_AddFont(pfb);
  if (font_id<0) {
    mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
    t1_push_error();
    i_mutex_unlock(mutex);
    return NULL;
  }
  
  if (afm != NULL) {
    mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
    if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
  }

  if (T1_LoadFont(font_id)) {
    mm_log((1, "i_t1_new() -> -1 - T1_LoadFont failed (%d)\n", T1_errno));
    t1_push_error();
    i_push_error(0, "loading font");
    T1_DeleteFont(font_id);
    i_mutex_unlock(mutex);
    return NULL;
  }

  ++t1_active_fonts;

  i_mutex_unlock(mutex);

  font = mymalloc(sizeof(*font));
  font->font_id = font_id;

  mm_log((1, "i_t1_new() -> %p (%d)\n", font, font_id));

  return font;
}
Ejemplo n.º 4
0
int
i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf, 
                 size_t name_buf_size) {
  char *name;
  int font_num = font->font_id;

  i_clear_error();
  if (ch > 0xFF) {
    return 0;
  }

  i_mutex_lock(mutex);

  if (T1_LoadFont(font_num)) {
    t1_push_error();
    i_mutex_unlock(mutex);
    return 0;
  }
  name = T1_GetCharName(font_num, (unsigned char)ch);
  if (name) {
    if (strcmp(name, ".notdef")) {
      size_t len = strlen(name);
      strncpy(name_buf, name, name_buf_size);
      name_buf[name_buf_size-1] = '\0';
      i_mutex_unlock(mutex);
      return len + 1;
    }
    else {
      i_mutex_unlock(mutex);
      return 0;
    }
  }
  else {
    t1_push_error();
    i_mutex_unlock(mutex);
    return 0;
  }
}
Ejemplo n.º 5
0
bool InitT1(struct font_entry * tfontp)
{
  if (libt1==NULL) {
    if ((libt1=T1_InitLib( NO_LOGFILE | IGNORE_CONFIGFILE
			   | IGNORE_FONTDATABASE | T1_NO_AFM)) == NULL) {
      Warning("an error occured during t1lib initialisation, disabling it"); 
      option_flags &= ~USE_LIBT1;
      return(false);
    }
# ifdef DEBUG
    else 
      DEBUG_PRINT(DEBUG_T1,("\n  T1LIB VERSION: %s", T1_GetLibIdent()));
# endif
  }

  DEBUG_PRINT((DEBUG_DVI|DEBUG_T1),("\n  OPEN T1 FONT:\t'%s'", tfontp->name));
  tfontp->T1id = T1_AddFont( tfontp->name );
  if (tfontp->T1id < 0) {
    Warning("t1lib could not open font file %s", tfontp->name);
    return(false);
  } 
  if (T1_LoadFont(tfontp->T1id)) {
    Warning("t1lib could not load font file %s", tfontp->name);
    return(false);
  } 
  Message(BE_VERBOSE,"<%s>", tfontp->name);
  if (tfontp->psfontmap!=NULL && tfontp->psfontmap->encoding != NULL) {
    DEBUG_PRINT(DEBUG_T1,("\n  USE ENCODING:\t'%s'", tfontp->psfontmap->encoding->name));
    if (T1_ReencodeFont(tfontp->T1id,tfontp->psfontmap->encoding->charname)) {
      Warning("unable to use font encoding '%s' for %s", 
	      tfontp->psfontmap->encoding->name,tfontp->name);
      return(false);
    }
  }
  tfontp->type = FONT_TYPE_T1;
  return(true);
}
Ejemplo n.º 6
0
/* T1_SetChar(...): Generate the bitmap for a character */
T1_OUTLINE *T1_GetCharOutline( int FontID, char charcode, float size,
			       T1_TMATRIX *transform)
{
  int i;
  int mode;
  T1_PATHSEGMENT *charpath;
  struct XYspace *Current_S;
  unsigned char ucharcode;
  
  
  FONTSIZEDEPS *font_ptr;
  FONTPRIVATE  *fontarrayP;
  
  /* We don't implement underlining for characters, but the rasterer
     implements it. Thus, we use a modflag of constant 0 */
  int modflag=0;

  
  /* We return to this if something goes wrong deep in the rasterizer */
  if ((i=setjmp( stck_state))!=0) {
    T1_errno=T1ERR_TYPE1_ABORT;
    sprintf( err_warn_msg_buf, "t1_abort: Reason: %s",
	     t1_get_abort_message( i));
    T1_PrintLog( "T1_GetCharOutline()", err_warn_msg_buf,
	       T1LOG_ERROR);
    return( NULL);
  }

  ucharcode=(unsigned char)charcode;

  
  /* First, check for a correct ID */
  i=CheckForFontID(FontID);
  if (i==-1){
    T1_errno=T1ERR_INVALID_FONTID;
    return(NULL);
  }
  /* if necessary load font into memory */
  if (i==0)
    if (T1_LoadFont(FontID))
      return(NULL);

  /* Check for valid size */
  if (size<=0.0){
    T1_errno=T1ERR_INVALID_PARAMETER;
    return(NULL);
  }

  fontarrayP=&(pFontBase->pFontArray[FontID]);
  
  /* font is now loaded into memory =>
     Check for size: */
  if ((font_ptr=QueryFontSize( FontID, size, NO_ANTIALIAS))==NULL){
    font_ptr=CreateNewFontSize( FontID, size, NO_ANTIALIAS);
    if (font_ptr==NULL){
      T1_errno=T1ERR_ALLOC_MEM;
      return(NULL);
    }
  }
  
  /* Setup an appropriate charspace matrix. Note that the rasterizer
     assumes vertical values with inverted sign! Transformation should
     create a copy of the local charspace matrix which then still has
     to be made permanent. */
  if (transform!=NULL) {
    Current_S=(struct XYspace *) 
      Permanent(Scale(Transform (font_ptr->pCharSpaceLocal,
				 transform->cxx, - transform->cxy,
				 transform->cyx, - transform->cyy),
		      DeviceSpecifics.scale_x, DeviceSpecifics.scale_y));
  }
  else{
    Current_S=(struct XYspace *)
      Permanent(Scale(Transform(font_ptr->pCharSpaceLocal,
				1.0, 0.0, 0.0, -1.0),
		      DeviceSpecifics.scale_x, DeviceSpecifics.scale_y));
  }

  
  /* fnt_ptr now points to the correct FontSizeDeps-struct =>
     lets now raster the character */
  mode=0;
  charpath=(T1_PATHSEGMENT *)fontfcnB( FontID, modflag, Current_S,
				       fontarrayP->pFontEnc,
				       ucharcode, &mode,
				       fontarrayP->pType1Data,
				       DO_NOT_RASTER);
  KillSpace (Current_S);

  return((T1_OUTLINE *)charpath);
}
Ejemplo n.º 7
0
/* T1_GetMoveOutline(...): Generate the "outline" for a movement
                           */
T1_OUTLINE *T1_GetMoveOutline( int FontID, int deltax, int deltay, int modflag,
			       float size, T1_TMATRIX *transform)
{
  int i;
  FONTSIZEDEPS *font_ptr;
  struct segment *path, *tmppath;
  struct XYspace *Current_S;
  psfont *FontP;
  float length;
  

  /* We return to this if something goes wrong deep in the rasterizer */
  if ((i=setjmp( stck_state))!=0) {
    T1_errno=T1ERR_TYPE1_ABORT;
    sprintf( err_warn_msg_buf, "t1_abort: Reason: %s",
	     t1_get_abort_message( i));
    T1_PrintLog( "T1_GetMoveOutline()", err_warn_msg_buf,
	       T1LOG_ERROR);
    return( NULL);
  }


  /* First, check for a correct ID */
  i=CheckForFontID(FontID);
  if (i==-1){
    T1_errno=T1ERR_INVALID_FONTID;
    return(NULL);
  }
  /* if necessary load font into memory */
  if (i==0)
    if (T1_LoadFont(FontID))
      return(NULL);

  /* Check for valid size */
  if (size<=0.0){
    T1_errno=T1ERR_INVALID_PARAMETER;
    return(NULL);
  }

  FontP=pFontBase->pFontArray[i].pType1Data;
  
  /* font is now loaded into memory =>
     Check for size: */
  if ((font_ptr=QueryFontSize( FontID, size, NO_ANTIALIAS))==NULL){
    font_ptr=CreateNewFontSize( FontID, size, NO_ANTIALIAS);
    if (font_ptr==NULL){
      T1_errno=T1ERR_ALLOC_MEM;
      return(NULL);
    }
  }

  /* Setup an appropriate charspace matrix. Note that the rasterizer
     assumes vertical values with inverted sign! Transformation should
     create a copy of the local charspace matrix which then still has
     to be made permanent. */
  if (transform!=NULL){
    Current_S=(struct XYspace *) 
      Permanent(Scale(Transform (font_ptr->pCharSpaceLocal,
				 transform->cxx, - transform->cxy,
				 transform->cyx, - transform->cyy),
		      DeviceSpecifics.scale_x, DeviceSpecifics.scale_y));
  }
  else{
    Current_S=(struct XYspace *)
      Permanent(Scale(Transform(font_ptr->pCharSpaceLocal,
				1.0, 0.0, 0.0, -1.0),
		      DeviceSpecifics.scale_x, DeviceSpecifics.scale_y));
  }
  
  
  path=(struct segment *)ILoc( Current_S, deltax, deltay); 

  /* Take care for underlining and such */
  length=(float) deltax;
  if (modflag & T1_UNDERLINE){
    tmppath=(struct segment *)Type1Line(FontP,Current_S,
					pFontBase->pFontArray[FontID].UndrLnPos,
					pFontBase->pFontArray[FontID].UndrLnThick,
					length);
    path=(struct segment *)Join(path,tmppath);
  }
  if (modflag & T1_OVERLINE){
    tmppath=(struct segment *)Type1Line(FontP,Current_S,
					pFontBase->pFontArray[FontID].OvrLnPos,
					pFontBase->pFontArray[FontID].OvrLnThick,
					length);
    path=(struct segment *)Join(path,tmppath);
  }
  if (modflag & T1_OVERSTRIKE){
    tmppath=(struct segment *)Type1Line(FontP,Current_S,
					pFontBase->pFontArray[FontID].OvrStrkPos,
					pFontBase->pFontArray[FontID].OvrStrkThick,
					length);
    path=(struct segment *)Join(path,tmppath);
  }
      
  KillSpace( Current_S);
  
  return( (T1_OUTLINE *)path);
  
}
Ejemplo n.º 8
0
/* T1_GetStringOutline(...): Generate the outline for a string of
                             characters */
T1_OUTLINE *T1_GetStringOutline( int FontID, char *string, int len, 
				 long spaceoff, int modflag, float size,
				 T1_TMATRIX *transform)
{
  int i;
  int mode;
  /* initialize this to NULL just to be on the safe side */
  T1_PATHSEGMENT *charpath = NULL;
  struct XYspace *Current_S;
  int *kern_pairs;       /* use for accessing the kern pairs if kerning is
			    requested */
  int no_chars=0;        /* The number of characters in the string */
  static int lastno_chars=0;
  long spacewidth;       /* This is given to fontfcnb_string() */
  
  
  FONTSIZEDEPS *font_ptr;
  FONTPRIVATE  *fontarrayP;
  
  static int *pixel_h_anchor_corr=NULL;
  static int *flags=NULL;

  unsigned char *ustring;


  /* We return to this if something goes wrong deep in the rasterizer */
  if ((i=setjmp( stck_state))!=0) {
    T1_errno=T1ERR_TYPE1_ABORT;
    sprintf( err_warn_msg_buf, "t1_abort: Reason: %s",
	     t1_get_abort_message( i));
    T1_PrintLog( "T1_GetStringOutline()", err_warn_msg_buf,
	       T1LOG_ERROR);
    return( NULL);
  }

  /* force string elements into unsigned */
  ustring=(unsigned char*)string;
  
  /* First, check for a correct ID */
  i=CheckForFontID(FontID);
  if (i==-1){
    T1_errno=T1ERR_INVALID_FONTID;
    return(NULL);
  }
  /* if necessary load font into memory */
  if (i==0)
    if (T1_LoadFont(FontID))
      return(NULL);

  /* If no AFM info is present, we return an error */
  if (pFontBase->pFontArray[FontID].pAFMData==NULL) {
    T1_errno=T1ERR_NO_AFM_DATA;
    return(NULL);
  }

  /* Check for valid size */
  if (size<=0.0){
    T1_errno=T1ERR_INVALID_PARAMETER;
    return(NULL);
  }

  fontarrayP=&(pFontBase->pFontArray[FontID]);
  
  /* font is now loaded into memory =>
     Check for size: */
  if ((font_ptr=QueryFontSize( FontID, size, NO_ANTIALIAS))==NULL){
    font_ptr=CreateNewFontSize( FontID, size, NO_ANTIALIAS);
    if (font_ptr==NULL){
      T1_errno=T1ERR_ALLOC_MEM;
      return(NULL);
    }
  }
  
  /* Now comes string specific stuff: Get length of string and create an
     array of integers where to store the bitmap positioning dimens: */
  if (len<0){  /* invalid length */
    T1_errno=T1ERR_INVALID_PARAMETER;
    return(NULL);
  }
  
  if (len==0) /* should be computed assuming "normal" 0-terminated string */
    no_chars=strlen(string);
  else        /* use value given on command line */
    no_chars=len;

  /* If necessary, allocate memory */
  if (no_chars>lastno_chars){
    if (pixel_h_anchor_corr!=NULL){
      free(pixel_h_anchor_corr);
    }
    if (flags!=NULL){
      free(flags);
    }
    
    pixel_h_anchor_corr=(int *)calloc(no_chars, sizeof(int));
    flags=(int *)calloc(no_chars, sizeof(int));
    lastno_chars=no_chars;
  }
  else{
    /* Reset flags  and position array */
    for (i=0; i<no_chars; i++){
      flags[i]=0;
      pixel_h_anchor_corr[i]=0;
    }
  }
  
  /* Setup an appropriate charspace matrix. Note that the rasterizer
     assumes vertical values with inverted sign! Transformation should
     create a copy of the local charspace matrix which then still has
     to be made permanent. */
  if (transform!=NULL){
    Current_S=(struct XYspace *) 
      Permanent(Scale(Transform (font_ptr->pCharSpaceLocal,
				 transform->cxx, - transform->cxy,
				 transform->cyx, - transform->cyy),
		      DeviceSpecifics.scale_x, DeviceSpecifics.scale_y));
  }
  else{
    Current_S=(struct XYspace *)
      Permanent(Scale(Transform(font_ptr->pCharSpaceLocal,
				1.0, 0.0, 0.0, -1.0),
		      DeviceSpecifics.scale_x, DeviceSpecifics.scale_y));
  }
  
  /* Compute the correct spacewidth value (in charspace units). The
     value supplied by the user is interpreted as an offset in
     char space units:
     */
  spacewidth=T1_GetCharWidth(FontID,fontarrayP->space_position)+spaceoff;
  
  mode=0;
  kern_pairs=(int *)calloc(no_chars, sizeof(int));
  if ((modflag & T1_KERNING))
    for (i=0; i<no_chars -1; i++)
      kern_pairs[i]=T1_GetKerning( FontID, ustring[i], ustring[i+1]);
  charpath=(T1_PATHSEGMENT *) fontfcnB_string( FontID, modflag, Current_S,
					       fontarrayP->pFontEnc,
					       (unsigned char *)string,
					       no_chars, &mode,
					       fontarrayP->pType1Data,
					       kern_pairs, spacewidth,
					       DO_NOT_RASTER);
  KillSpace (Current_S);
  
  /* In all cases, free memory for kerning pairs */
  free(kern_pairs);
  
  /* fill the string_glyph-structure */
  if (mode != 0) {
    sprintf( err_warn_msg_buf, "fontfcnB_string() set mode=%d", mode);
    T1_PrintLog( "T1_GetStringOutline()", err_warn_msg_buf, T1LOG_WARNING);
    T1_errno=mode;
    /* make sure to get rid of path if it's there */
    if (charpath){
      KillRegion (charpath);
    }
    return(NULL);
  }
  if (charpath == NULL){
    T1_PrintLog( "T1_GetStringOutline()", "path=NULL returned by fontfcnB_string()", T1LOG_WARNING);
    T1_errno=mode;
    return(NULL);
  }
  
  return( (T1_OUTLINE *)charpath);
}
Ejemplo n.º 9
0
SWFFONT* swf_LoadT1Font(const char*filename)
{
    SWFFONT * font;
    int nr;
    float angle,underline;
    char*fontname,*fullname,*familyname;
    BBox bbox;
    int s,num;
    char**charnames;
    char**charname;
    char*encoding[256];
    int c;
    int t;

    if(!t1lib_initialized) {
	T1_SetBitmapPad(16);
	if ((T1_InitLib(NO_LOGFILE)==NULL)){
	    fprintf(stderr, "Initialization of t1lib failed\n");
	    return 0;
	}
	t1lib_initialized = 1;
    }
    nr = T1_AddFont(filename);
    T1_LoadFont(nr);

    charnames = T1_GetAllCharNames(nr);
    if(!charnames) {
	fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
	return 0;
    }

    angle = T1_GetItalicAngle(nr);
    fontname = T1_GetFontName(nr);
    fullname = T1_GetFullName(nr);
    familyname = T1_GetFamilyName(nr);
    underline = T1_GetUnderlinePosition(nr);
    bbox = T1_GetFontBBox(nr);

    font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));

    font->version = 2;
    if(fontname) 
	font->name = (U8*)strdup(fontname);
    else 
	font->name = 0;
    font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));

    num = 0;
    charname = charnames;
    while(*charname) {
	charname++;
	if(num<256) {
	    if(*charname) encoding[num] = strdup(*charname);
	    else          encoding[num] = strdup(".notdef");
	}
	num++;
    }
    for(t=num;t<256;t++)
	encoding[t] = strdup(".notdef");
    
    //T1_ReencodeFont(nr, encoding);

    font->maxascii = num;
    font->numchars = num;
    
    font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);

    font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
    font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
    font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
    font->layout->ascent = (U16)(underline - bbox.lly);
    font->layout->descent = (U16)(bbox.ury - underline);
    font->layout->leading = (U16)(font->layout->ascent - 
	                     font->layout->descent -
			     (bbox.lly - bbox.ury));
    font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
    font->layout->kerningcount = 0;
    font->layout->kerning = 0;
    font->glyphnames = rfx_calloc(num*sizeof(char*));
  
    num = 0;

    charname = charnames;
    for(c=0;c<font->numchars;c++) {
	drawer_t draw;
	SRECT bbox;
	T1_OUTLINE * outline;
	FPOINT pos,last;
	int firstx;
	
	outline = T1_GetCharOutline(nr, c, 100.0, 0);
	firstx = outline->dest.x/0xffff;

	pos.x = 0;
	pos.y = 0;
	last = pos;
	
	font->glyphnames[c] = strdup(*charname);

	if(c<font->maxascii)
	    font->ascii2glyph[c] = c;
	font->glyph2ascii[c] = c;
	
	swf_Shape01DrawerInit(&draw, 0);

	while(outline) {
	    pos.x += (outline->dest.x/(float)0xffff);
	    pos.y += (outline->dest.y/(float)0xffff);

	    if(outline->type == T1_PATHTYPE_MOVE) {
		draw.moveTo(&draw,&pos);
	    } else if(outline->type == T1_PATHTYPE_LINE) {
		draw.lineTo(&draw,&pos);
	    } else if(outline->type == T1_PATHTYPE_BEZIER) {
		T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
		FPOINT b,c;
		b.x = o2->B.x/(float)0xffff+last.x;
		b.y = o2->B.y/(float)0xffff+last.y;
		c.x = o2->C.x/(float)0xffff+last.x;
		c.y = o2->C.y/(float)0xffff+last.y;
		draw_cubicTo(&draw,&b,&c,&pos);
	    } else {
		fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
	    }
	    last = pos;
	    outline = outline->link;
	}
	
	draw.finish(&draw);

	font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
	bbox = swf_ShapeDrawerGetBBox(&draw);
	draw.dealloc(&draw);
	    
	font->layout->bounds[c] = bbox;
	font->glyph[c].advance = bbox.xmax;
	if(!font->glyph[c].advance) {
	    font->glyph[c].advance = firstx;
	}
	charname++;
    }
    T1_DeleteFont(nr);

    for(t=0;t<256;t++)
	rfx_free(encoding[t]);
    return font;
}
Ejemplo n.º 10
0
int
i_t1_bbox(i_t1_font_t font, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
  BBox bbox;
  BBox gbbox;
  int mod_flags = t1_get_flags(flags);
  i_img_dim advance;
  int fontnum = font->font_id;
  int space_position;

  i_clear_error();

  i_mutex_lock(mutex);

  space_position = T1_GetEncodingIndex(fontnum, "space");
  
  mm_log((1,"i_t1_bbox(font %p (%d),points %.2f,str '%.*s', len %u)\n",
	  font, fontnum,points,(int)len,str,(unsigned)len));
  if (T1_LoadFont(fontnum) == -1) {
    t1_push_error();
    i_mutex_unlock(mutex);
    return 0;
  }

  if (len == 0) {
    /* len == 0 has special meaning to T1lib, but it means there's
       nothing to draw, so return that */
    bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
    advance = 0;
  }
  else {
    if (utf8) {
      int worklen;
      char *work = t1_from_utf8(str, len, &worklen);
      if (!work) {
	i_mutex_unlock(mutex);
	return 0;
      }
      advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags);
      bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
      t1_fix_bbox(&bbox, work, worklen, advance, space_position);
      myfree(work);
    }
    else {
      advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
      bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
      t1_fix_bbox(&bbox, str, len, advance, space_position);
    }
  }
  gbbox = T1_GetFontBBox(fontnum);
  
  mm_log((1,"bbox: (%d, %d, %d, %d, %d, %d)\n",
	  (int)(bbox.llx*points/1000),
	  (int)(gbbox.lly*points/1000),
	  (int)(bbox.urx*points/1000),
	  (int)(gbbox.ury*points/1000),
	  (int)(bbox.lly*points/1000),
	  (int)(bbox.ury*points/1000) ));


  cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
  cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;

  cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
  cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;

  cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
  cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;

  cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
  cords[BBOX_RIGHT_BEARING] = 
    cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];

  i_mutex_unlock(mutex);

  return BBOX_RIGHT_BEARING+1;
}