TTF/TTC to CIDFontType2 patch



Hi all,

I found that in gnome-print, large TTF/TTC fonts for CJK characters is
converted to Type1 font by ttf2pt1. This method has changed the font and it
looks not exactly the same as original TTF/TTC ones.

In order to subset large TTF/TTC font into PostScript, Adobe has developed
Type 2 CIDFont, it's a extension to Type 42 font.

I have write a patch to make gnome-print use CIDFontType2 when its too large
for Type 42 font. I have tested it using Chinese SimSun font and gs-gpl 8.0.
(In gs-esp 7, theirs some bug to deal metrics data saved in GlyphDirectory.)

The patch is in attachment and it should be applied to files in libgnomeprint
directory. File gp-tt-cid2.c and gp-tt-cid2.h should be put in that directory
too.

Index: gnome-font-face.c
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-font-face.c,v
retrieving revision 1.75
diff -r1.75 gnome-font-face.c
44a45
> #include <libgnomeprint/gp-tt-cid2.h>
849,852c850,853
<  		{
<  			found = charmap;
<  			break;
<  		}
---
> 			{
> 				found = charmap;
> 				break;
> 			}
1128d1128
< 
1335a1336,1338
> void sfnts_write_byte_array (GnomeFontPsObject *pso, GByteArray* array);
> void sfnts_write_tt_table (GnomeFontPsObject *pso, const guchar *buf, guint buf_len, struct tt_table *table);
> 
1344a1348,1349
> 	GHashTable *tables;
> 	GByteArray *head;
1350a1356,1357
> 	guchar *required[] = {"head", "prep", "cvt ", "hhea", "fpgm", "maxp", "vhea", "gdir", NULL};
> 	gint metrics_count, num_glyphs;
1427,1443d1433
< 	} else {
< 		guchar *afm;
< 		/* This is somewhat experimental - convert TTF to Type1 */
< 		afm = ttf2pfa (pso->face->ft_face, embeddedname, pso->glyphs);
< 		if (!afm) {
< 			gnome_print_buffer_munmap (&b);
< 			g_warning ("file %s: line %d: Cannot convert TTF %s to Type1", __FILE__, __LINE__, file_name);
< 			gnome_font_face_ps_embed_empty (pso);
< 			return;
< 		}
< 		/* We take over ownership of afm here (be careful) */
< 		pso->buf = afm;
< 		pso->bufsize = strlen (afm);
< 		pso->length = pso->bufsize;
< 	}
< 
< 	gnome_print_buffer_munmap (&b);
1445,1491c1435,1449
< 	/*
< 	 * We have font downloaded (hopefully)
< 	 *
< 	 * With CharStrings: .nodef _1 _2 _3
< 	 *
< 	 * Now we have to build usable 2-byte encoded font from it
< 	 *
< 	 */
< 
< 	/* fixme: That is crap. We should use CID */
< 	/* Bitch 'o' bitches (Lauris) ! */
< 	if (pso->face->num_glyphs < 256) {
< 		gint glyph;
< 		/* 8-bit vector */
< 		pso->encodedbytes = 1;
< 		gf_pso_sprintf (pso, "(%s) cvn findfont dup length dict begin\n", embeddedname);
< 		gf_pso_sprintf (pso, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
< 		gf_pso_sprintf (pso, "/Encoding [\n");
< 		for (glyph = 0; glyph < 256; glyph++) {
< 			guint g;
< 			g = (glyph < pso->face->num_glyphs) ? glyph : 0;
< 			if ((g == 0) || !PSO_GLYPH_MARKED (pso, glyph)) {
< 				gf_pso_sprintf (pso, ((glyph & 0xf) == 0xf) ? "/.notdef\n" : "/.notdef ", g);
< 			} else {
< 				gf_pso_sprintf (pso, ((glyph & 0xf) == 0xf) ? "/_%d\n" : "/_%d ", g);
< 			}
< 		}
< 		gf_pso_sprintf (pso, "] def currentdict end\n");
< 		gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
< 	} else {
< 		gint nfonts, nglyphs, i, j;
< 		/* 16-bit vector */
< 		pso->encodedbytes = 2;
< 		nglyphs = pso->face->num_glyphs;
< 		nfonts = (nglyphs + 255) >> 8;
< 
< 		gf_pso_sprintf (pso, "32 dict begin\n");
< 		/* Common entries */
< 		gf_pso_sprintf (pso, "/FontType 0 def\n");
< 		gf_pso_sprintf (pso, "/FontMatrix [1 0 0 1 0 0] def\n");
< 		gf_pso_sprintf (pso, "/FontName (%s-Glyph-Composite) cvn def\n", embeddedname);
< 		gf_pso_sprintf (pso, "/LanguageLevel 2 def\n");
< 		/* Type 0 entries */
< 		gf_pso_sprintf (pso, "/FMapType 2 def\n");
< 		/* Bitch 'o' bitches */
< 		gf_pso_sprintf (pso, "/FDepVector [\n");
< 		for (i = 0; i < nfonts; i++) {
---
> 		/*
> 		 * We have font downloaded (hopefully)
> 		 *
> 		 * With CharStrings: .nodef _1 _2 _3
> 		 *
> 		 * Now we have to build usable 2-byte encoded font from it
> 		 *
> 		 */
> 		
> 		/* fixme: That is crap. We should use CID */
> 		/* Bitch 'o' bitches (Lauris) ! */
> 		if (pso->face->num_glyphs < 256) {
> 			gint glyph;
> 			/* 8-bit vector */
> 			pso->encodedbytes = 1;
1495,1501c1453,1457
< 			for (j = 0; j < 256; j++) {
< 				gint glyph;
< 				glyph = 256 * i + j;
< 				if (glyph >= nglyphs)
< 					glyph = 0;
< 				if ((glyph == 0) || !PSO_GLYPH_MARKED (pso, glyph)) {
< 					gf_pso_sprintf (pso, ((j & 0xf) == 0xf) ? "/.notdef\n" : "/.notdef ");
---
> 			for (glyph = 0; glyph < 256; glyph++) {
> 				guint g;
> 				g = (glyph < pso->face->num_glyphs) ? glyph : 0;
> 				if ((g == 0) || !PSO_GLYPH_MARKED (pso, glyph)) {
> 					gf_pso_sprintf (pso, ((glyph & 0xf) == 0xf) ? "/.notdef\n" : "/.notdef ", g);
1503c1459,1494
< 					gf_pso_sprintf (pso, ((j & 0xf) == 0xf) ? "/_%d\n" : "/_%d ", glyph);
---
> 					gf_pso_sprintf (pso, ((glyph & 0xf) == 0xf) ? "/_%d\n" : "/_%d ", g);
> 				}
> 			}
> 			gf_pso_sprintf (pso, "] def currentdict end\n");
> 			gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
> 		} else {
> 			gint nfonts, nglyphs, i, j;
> 			/* 16-bit vector */
> 			pso->encodedbytes = 2;
> 			nglyphs = pso->face->num_glyphs;
> 			nfonts = (nglyphs + 255) >> 8;
> 
> 			gf_pso_sprintf (pso, "32 dict begin\n");
> 			/* Common entries */
> 			gf_pso_sprintf (pso, "/FontType 0 def\n");
> 			gf_pso_sprintf (pso, "/FontMatrix [1 0 0 1 0 0] def\n");
> 			gf_pso_sprintf (pso, "/FontName (%s-Glyph-Composite) cvn def\n", embeddedname);
> 			gf_pso_sprintf (pso, "/LanguageLevel 2 def\n");
> 			/* Type 0 entries */
> 			gf_pso_sprintf (pso, "/FMapType 2 def\n");
> 			/* Bitch 'o' bitches */
> 			gf_pso_sprintf (pso, "/FDepVector [\n");
> 			for (i = 0; i < nfonts; i++) {
> 				gf_pso_sprintf (pso, "(%s) cvn findfont dup length dict begin\n", embeddedname);
> 				gf_pso_sprintf (pso, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
> 				gf_pso_sprintf (pso, "/Encoding [\n");
> 				for (j = 0; j < 256; j++) {
> 					gint glyph;
> 					glyph = 256 * i + j;
> 					if (glyph >= nglyphs)
> 						glyph = 0;
> 					if ((glyph == 0) || !PSO_GLYPH_MARKED (pso, glyph)) {
> 						gf_pso_sprintf (pso, ((j & 0xf) == 0xf) ? "/.notdef\n" : "/.notdef ");
> 					} else {
> 						gf_pso_sprintf (pso, ((j & 0xf) == 0xf) ? "/_%d\n" : "/_%d ", glyph);
> 					}
1504a1496,1497
> 				gf_pso_sprintf (pso, "] def\n");
> 				gf_pso_sprintf (pso, "currentdict end (%s-Glyph-Page-%d) cvn exch definefont\n", embeddedname, i);
1507c1500,1508
< 			gf_pso_sprintf (pso, "currentdict end (%s-Glyph-Page-%d) cvn exch definefont\n", embeddedname, i);
---
> 			gf_pso_sprintf (pso, "/Encoding [\n");
> 			for (i = 0; i < 256; i++) {
> 				gint fn;
> 				fn = (i < nfonts) ? i : 0;
> 				gf_pso_sprintf (pso, ((i & 0xf) == 0xf) ? "%d\n" : "%d  ", fn);
> 			}
> 			gf_pso_sprintf (pso, "] def\n");
> 			gf_pso_sprintf (pso, "currentdict end\n");
> 			gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
1508a1510,1547
> 
> 	} else {
> 		tables = gp_tt_get_tables (fbuf, b.buf_size, pso->face->entry->index);
> 		/* Relatively easy - just embed TTF into PS stream */
> 		/* Download master font */
> 		TTVersion = 1.0;
> 		MfrRevision = 1.0;
> 		gf_pso_sprintf (pso, "%%!PS-TrueTypeFont-");
> 		gf_pso_print_double (pso, "%g", TTVersion);
> 		gf_pso_sprintf (pso, "-");
> 		gf_pso_print_double (pso, "%g", MfrRevision);
> 		gf_pso_sprintf (pso, "\n");
> 
> 		gf_pso_sprintf (pso, "/CIDInit /ProcSet findresource begin\n\n");
> 		gf_pso_sprintf (pso, "20 dict begin\n");
> 		gf_pso_sprintf (pso, "/CIDFontName (%s) cvn def\n", embeddedname);
> 		gf_pso_sprintf (pso, "/CIDFontVersion 1 def\n");
> 		gf_pso_sprintf (pso, "/CIDFontType 2 def\n");
> 		gf_pso_sprintf (pso, "/FontType 42 def\n");
> 		gf_pso_sprintf (pso, "/CIDSystemInfo 3 dict dup begin\n");
> 		gf_pso_sprintf (pso, "  /Registry (Adobe) def\n");
> 		gf_pso_sprintf (pso, "  /Ordering (Identity) def\n");
> 		gf_pso_sprintf (pso, "  /Supplement 0 def\n");
> 		gf_pso_sprintf (pso, "  end def\n");
> 		gf_pso_sprintf (pso, "/CIDCount %d def\n", pso->face->num_glyphs);
> 		gf_pso_sprintf (pso, "/GDBytes 2 def\n");
> 		gf_pso_sprintf (pso, "/CIDMap 0 def\n");
> 		gf_pso_sprintf (pso, "/PaintType 0 def\n");
> 		gf_pso_sprintf (pso, "/FontMatrix [1 0 0 1 0 0] def\n");
> 		bbox = gnome_font_face_get_stdbbox (pso->face);
> 		gf_pso_sprintf (pso, "/FontBBox [");
> 		gf_pso_print_double (pso, "%g",  bbox->x0);
> 		gf_pso_sprintf (pso, " ");
> 		gf_pso_print_double (pso, "%g", bbox->y0);
> 		gf_pso_sprintf (pso, " ");
> 		gf_pso_print_double (pso, "%g",  bbox->x1);
> 		gf_pso_sprintf (pso, " ");
> 		gf_pso_print_double (pso, "%g",  bbox->y1);
1510,1514c1549,1562
< 		gf_pso_sprintf (pso, "/Encoding [\n");
< 		for (i = 0; i < 256; i++) {
< 			gint fn;
< 			fn = (i < nfonts) ? i : 0;
< 			gf_pso_sprintf (pso, ((i & 0xf) == 0xf) ? "%d\n" : "%d  ", fn);
---
> 		gf_pso_sprintf (pso, "/Encoding [] readonly def\n");
> 		gf_pso_sprintf (pso, "/CharStrings 1 dict dup begin\n");
> 		gf_pso_sprintf (pso, "  /.notdef 0 def\n");
> 		gf_pso_sprintf (pso, "  end readonly def\n");
> 		gf_pso_sprintf (pso, "/sfnts [\n");
> 		head = gp_tt_build_header (fbuf, b.buf_size, tables, required);
> 		sfnts_write_byte_array (pso, head);
> 		g_byte_array_free (head, TRUE);
> 		i = 0;
> 		for (i = 0; required[i] != NULL; i++) {
> 			struct tt_table *table;
> 			table = (struct tt_table *) g_hash_table_lookup (tables, (gpointer) required[i]);
> 			if (table == NULL) continue;
> 			sfnts_write_tt_table (pso, fbuf, b.buf_size, table);
1517,1518c1565,1629
< 		gf_pso_sprintf (pso, "currentdict end\n");
< 		gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
---
> 
> 		metrics_count = 0;
> 		if (g_hash_table_lookup (tables, "hmtx")) {
> 			metrics_count += 2;
> 			if (g_hash_table_lookup (tables, "vmtx")) {
> 				metrics_count += 2;
> 			}
> 		}
> 		gf_pso_sprintf (pso, "/MetricsCount %d def\n", metrics_count);
> 		num_glyphs = 1;
> 		for (i = 0; i < pso->face->num_glyphs; i++) {
> 			if (PSO_GLYPH_MARKED(pso, i)) num_glyphs++;
> 		}
> 		gf_pso_sprintf (pso, "/GlyphDirectory %d dict dup begin\n", num_glyphs);
> 		for (i = 0; i < pso->face->num_glyphs; i++) {
> 			GByteArray *glyph_desc;
> 			if (i != 0 && ! PSO_GLYPH_MARKED(pso, i)) continue;
> 			gf_pso_sprintf (pso, "  %d ", i);
> 			glyph_desc = gp_tt_get_glyph_desc(fbuf, b.buf_size, tables, i, metrics_count);
> 			sfnts_write_byte_array(pso, glyph_desc);
> 			g_byte_array_free (glyph_desc, TRUE);
> 			gf_pso_sprintf (pso, "    def\n");
> 		}
> 		gf_pso_sprintf (pso, "  end def\n");
> 		gf_pso_sprintf (pso, "CIDFontName currentdict end /CIDFont defineresource pop\n\n");
> 
> 		gf_pso_sprintf (pso, "(%s) cvn /Identity-H /CMap findresource[(%s) cvn /CIDFont findresource] composefont pop\n", pso->encodedname, embeddedname);
> 		g_hash_table_destroy (tables);
> 	}
> 	
> 	gnome_print_buffer_munmap (&b);
> }
> 
> void
> sfnts_write_byte_array (GnomeFontPsObject *pso, GByteArray* array)
> {
> 	guint i, j;
> 	guint8 *b;
> 
> 	gf_pso_sprintf (pso, "<");
> 	for (b = array->data, i = 0; i < array->len; i += 32) {
> 		for (j = 0; j < 32 && (i + j) < array->len; j++)
> 			gf_pso_sprintf(pso, "%02x", *b++);
> 		if (j == 32)
> 			gf_pso_sprintf(pso, "\n");
> 	}
> 	gf_pso_sprintf (pso, "00>\n");
> }
> 
> void
> sfnts_write_tt_table (GnomeFontPsObject *pso, const guchar *buf, guint buf_len, struct tt_table *table)
> {
> 	const guchar *b;
> 	guint32 i, j;
> 	
> 	gf_pso_sprintf (pso, "<");
> 	for (b = buf + table->offset, i = 0; i < table->length; i+=32) {
> 		for (j = 0; j < 32 && (i + j) < table->length; j++)
> 			gf_pso_sprintf(pso, "%02x", *b++);
> 		if (j == 32)
> 			gf_pso_sprintf(pso, "\n");
> 	}
> 	if (table->length % 4 != 0) {
> 		for (i = 0; i < (4 - table->length % 4); i++)
> 			gf_pso_sprintf(pso, "00");
1519a1631
> 	gf_pso_sprintf (pso, "00>\n");
Index: gnome-print-ps2.c
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-print-ps2.c,v
retrieving revision 1.79
diff -r1.79 gnome-print-ps2.c
47a48
> #define CMAP_IDENTITY "/CIDInit /ProcSet findresource begin\n10 dict begin\n  begincmap\n  /CMapType 1 def\n  /CMapName /Identity-H def\n  /CIDSystemInfo 3 dict dup begin\n    /Registry (Adobe) def\n    /Ordering (Identity) def\n    /Supplement 0 def\n  end def\n  1 begincodespacerange\n    <0000> <ffff>\n  endcodespacerange\n  0 usefont\n  1 begincidrange\n    <0000> <ffff> 0\n  endcidrange\n  endcmap\n  currentdict CMapName exch /CMap defineresource pop\nend\n10 dict begin\n  begincmap\n  /CMapType 1 def\n  /CMapName /Identity-V def\n  /CIDSystemInfo 3 dict dup begin\n    /Registry (Adobe) def\n    /Ordering (Identity) def\n    /Supplement 0 def\n  end def\n  /WMode 1 def\n  1 begincodespacerange\n    <0000> <ffff>\n  endcodespacerange\n  0 usefont\n  1 begincidrange\n    <0000> <ffff> 0\n  endcidrange\n  endcmap\n  currentdict CMapName exch /CMap defineresource pop\nend\nend\n"
768a770
> 	gboolean need_cmap_identity;
850a853,861
> 	need_cmap_identity = FALSE;
> 	for (font = ps2->fonts; font != NULL; font = font->next) {
> 		if (font->pso->face->entry->type == GP_FONT_ENTRY_TRUETYPE) {
> 			need_cmap_identity = TRUE;
> 			break;
> 		}
> 	}
> 	if (need_cmap_identity)
> 		gnome_print_transport_printf (pc->transport, CMAP_IDENTITY);
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/Makefile.am,v
retrieving revision 1.100
diff -r1.100 Makefile.am
17c17,18
< 	gp-tt-t1.c gp-tt-t1.h
---
> 	gp-tt-t1.c gp-tt-t1.h \
> 	gp-tt-cid2.c gp-tt-cid2.h
#include "gp-tt-cid2.h"

#include <glib.h>
#include <string.h>

#define GUINT32FROMPTR(p) ((*(guchar*)((p))<<24)|(*((guchar*)(p)+1)<<16)|(*((guchar*)(p)+2)<<8)|(*((guchar*)(p)+3)))
#define GUINT16FROMPTR(p) ((*(guchar*)((p))<<8)|(*((guchar*)(p)+1)))
#define GP_TT_IS_TTC(b) (!strncmp (b, "ttcf", 4))
#define GUINT16TOPTR(p,i) (*((guint8*)p)=(i>>8)&0xFF,*((guint8*)p+1)=i&0xFF)
#define GUINT32TOPTR(p,i) (*((guint8*)p)=(i>>24)&0xFF,*((guint8*)p+1)=(i>>16)&0xFF,*((guint8*)p+2)=(i>>8)&0xFF,*((guint8*)p+3)=i&0xFF)

struct tt_glyph_loca* gp_tt_loca_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph);
GByteArray* gp_tt_glyf_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph);
guint32 gp_tt_vmtx_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph);
guint32 gp_tt_hmtx_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph);

guint gp_tt_head_get_index_to_loc_format (const guchar *buf, guint buf_len, GHashTable *tables);

GHashTable *
gp_tt_get_tables (const guchar *buf, guint buf_len, guint face)
{
  const guchar *b;
  guint32 scaler_type;
  guint i, offset = 0, numTables;
  GHashTable *tt_tables;

  b = buf;
  
  if (GP_TT_IS_TTC (b)) {
    guint32 version, num_fonts;
    
    /* this file is TrueType Collection file */
    version = GUINT32FROMPTR (b + 4);
    if (version >= 0x00010000) {
      num_fonts = GUINT32FROMPTR (b + 8);
      if (face > num_fonts) {
        g_warning ("font doesn't have a face %d. number of face is %d.", face, num_fonts);
        return NULL;
      }
      offset = GUINT32FROMPTR (b + 12 + face * 4);
    } else {
      g_warning ("unknown TTC version %X", version);
      return NULL;
    }
  }

  scaler_type   = GUINT32FROMPTR (b + offset);
  numTables     = GUINT16FROMPTR (b + offset + 4);
  if ((scaler_type != 0x74727565) && (scaler_type != 0x00010000))
    return NULL;

  b = buf + offset + 12;
  tt_tables = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);

  for (i = 0; i < numTables; i++) {
    guint j;
    struct tt_table *table;

    table = (struct tt_table *) g_malloc (sizeof(struct tt_table));
    table->tag[4] = 0;
    for (j = 0; j < 4; j++)
      table->tag[j] = *(b + j);
    table->checksum = GUINT32FROMPTR (b + 4);
    table->offset = GUINT32FROMPTR (b + 8);
    table->length = GUINT32FROMPTR (b + 12);
    g_hash_table_insert (tt_tables, table->tag, table);
    b += 16;
  }

  return tt_tables;
}

GByteArray*
gp_tt_build_header (const guchar *buf, guint buf_len, GHashTable *tables, guchar **required)
{
  GByteArray *head;
  guchar *headbuf;
  guint8 *b;
  guchar **tag;
  guint num_tables, search_range, entry_selector, range_shift;
  guint i;
  guint32 len, offset;

  num_tables = 0;
  for (tag = required; *tag != NULL; tag++) {
    struct tt_table *table;
    table = g_hash_table_lookup (tables, *tag);
    if (table != NULL || !strcmp(*tag, "gdir"))
      num_tables++;
  }

  /* needs check */
  entry_selector = 1;
  while ((entry_selector << 1) <= num_tables)
    entry_selector <<= 1;
  search_range = entry_selector * 16;
  range_shift = num_tables * 16 - search_range;
  len = offset = 12 + 16 * num_tables;

  headbuf = g_malloc (sizeof(guchar[len]));
  headbuf[0] = 0;
  headbuf[1] = 1;
  headbuf[2] = 0;
  headbuf[3] = 0;
  GUINT16TOPTR (headbuf + 4, num_tables);
  GUINT16TOPTR (headbuf + 6, search_range);
  GUINT16TOPTR (headbuf + 8, entry_selector);
  GUINT16TOPTR (headbuf + 10, range_shift);

  for (b = headbuf + 12, tag = required; *tag != NULL; tag++) {
    struct tt_table *table;

    table = g_hash_table_lookup (tables, *tag);
    if (table == NULL && strcmp (*tag, "gdir"))
      continue;

    if (strcmp(*tag, "gdir") != 0) {
      for (i = 0; i < 4; i++) *(b+i) = *(table->tag+i);
      GUINT32TOPTR (b + 4, table->checksum);
      GUINT32TOPTR (b + 8, offset);
      GUINT32TOPTR (b + 12, table->length);
      offset += table->length;
    } else {
      *b = 'g', *(b+1) = 'd', *(b+2) = 'i', *(b+3) = 'r';
      GUINT32TOPTR (b + 4, 0);
      GUINT32TOPTR (b + 8, 0);
      GUINT32TOPTR (b + 12, 0);
    }

    if (offset % 4 != 0)
      offset += 4 - offset % 4;

    b += 16;
  }

  head = g_byte_array_sized_new (len);
  g_byte_array_append (head, headbuf, len);
  g_free (headbuf);

  return head;
}

GByteArray*
gp_tt_get_glyph_desc (const guchar * buf, guint buf_len, GHashTable *tables, guint glyph, guint metrics_count)
{
  GByteArray *glyf, *desc;
  guint32 hmtx, vmtx;

  glyf = gp_tt_glyf_get (buf, buf_len, tables, glyph);
  switch (metrics_count) {
  case 0:
    desc = glyf;
    break;
  case 2:
    desc = g_byte_array_sized_new (glyf->len + (metrics_count << 1));
    hmtx = gp_tt_hmtx_get (buf, buf_len, tables, glyph);
    GUINT32TOPTR (desc->data, hmtx);
    desc->len = 4;
    g_byte_array_append (desc, glyf->data, glyf->len);
    g_byte_array_free (glyf, TRUE);
    break;
  case 4:
    desc = g_byte_array_sized_new (glyf->len + (metrics_count << 1));
    hmtx = gp_tt_hmtx_get (buf, buf_len, tables, glyph);
    vmtx = gp_tt_vmtx_get (buf, buf_len, tables, glyph);
    GUINT32TOPTR (desc->data, vmtx);
    GUINT32TOPTR (desc->data + 4, hmtx);
    desc->len = 8;
    g_byte_array_append (desc, glyf->data, glyf->len);
    g_byte_array_free (glyf, TRUE);
    break;
  default:
    desc = NULL;
  }

  return desc;
}

GByteArray*
gp_tt_glyf_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph)
{
  struct tt_glyph_loca *loca;
  struct tt_table *glyf;
  GByteArray *desc;

  glyf = g_hash_table_lookup (tables, "glyf");
  loca = gp_tt_loca_get (buf, buf_len, tables, glyph);
  desc = g_byte_array_sized_new (loca->length);
  g_byte_array_append (desc, buf + glyf->offset + loca->offset, loca->length);
  g_free (loca);

  return desc;
}

struct tt_glyph_loca*
gp_tt_loca_get (const guchar *buf, guint buf_len, GHashTable *tables, guint index)
{
  guint format;
  struct tt_table *loca;
  struct tt_glyph_loca *result;
  const guchar * b;

  loca = g_hash_table_lookup (tables, "loca");
  format = gp_tt_head_get_index_to_loc_format (buf, buf_len, tables);
  
  result = (struct tt_glyph_loca *) g_malloc (sizeof(struct tt_glyph_loca));
  if (format == 0) {
    b = buf + loca->offset + index * 2;
    result->offset = GUINT16FROMPTR (b);
    result->length = GUINT16FROMPTR (b + 2) - result->offset;
    result->offset <<= 1;
    result->length <<= 1;
  } else if (format == 1) {
    b = buf + loca->offset + index * 4;
    result->offset = GUINT32FROMPTR (b);
    result->length = GUINT32FROMPTR (b + 4) - result->offset;
  } else {
    g_free (result);
    return NULL;
  }

  return result;
}

guint32
gp_tt_hmtx_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph)
{
  struct tt_table *hmtx;

  hmtx = g_hash_table_lookup (tables, "hmtx");
  return GUINT32FROMPTR (buf + hmtx->offset + glyph * 4);
}

guint32
gp_tt_vmtx_get (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph)
{
  struct tt_table *vmtx;

  vmtx = g_hash_table_lookup (tables, "vmtx");
  return GUINT32FROMPTR (buf + vmtx->offset + glyph * 4);
}

guint
gp_tt_head_get_index_to_loc_format (const guchar *buf, guint buf_len, GHashTable *tables)
{
  struct tt_table *head;

  head = (struct tt_table *) g_hash_table_lookup (tables, "head");
  return GUINT16FROMPTR (buf + head->offset + 50);
}
#ifndef __GP_TT_CID2_H__
#define __GP_TT_CID2_H__

#include <glib.h>

G_BEGIN_DECLS

struct tt_table {
  guchar tag[5];
  guint32 checksum;
  guint32 offset;
  guint32 length;
};

struct tt_glyph_loca {
  guint32 offset;
  guint32 length;
};

GHashTable* gp_tt_get_tables (const guchar *buf, guint buf_len, guint face);
GByteArray* gp_tt_build_header (const guchar *buf, guint buf_len, GHashTable *tables, guchar **required);
GByteArray* gp_tt_get_glyph_desc (const guchar *buf, guint buf_len, GHashTable *tables, guint glyph, guint metrics_count);

G_END_DECLS

#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]