[gs-cvs] rev 9131 - in trunk/gs: Resource/Init base psi

leonardo at ghostscript.com leonardo at ghostscript.com
Wed Oct 8 00:43:52 PDT 2008


Author: leonardo
Date: 2008-10-08 00:43:52 -0700 (Wed, 08 Oct 2008)
New Revision: 9131

Modified:
   trunk/gs/Resource/Init/gs_ttf.ps
   trunk/gs/base/gstype42.c
   trunk/gs/base/gxfont42.h
   trunk/gs/psi/zchar42.c
Log:
TT fonts : An initial implementation of GSUB.

DETAILS :

This is a partial fix for bug 689304  
"improper handling of vertical japanese text".
It works for brackets and punctuation signs orientation
when a vertical CJK text is painted with an 
Open Type font that defines a GSUB table.

The curent implementation always chooses a Format 1 
substitution table that substitutes single glyphs to single glyphs.
It doesn't account LangSys and feature tables.
Such logic is owned from the CJK patch attached to the bug 689304.
It may need further improvements.

Opposite to CJK group we implement it in C to allow
to it to work for other interpreters besides Postscript.

Interpreters may need to add an explicit call to 
the new function gs_type42_substitute_glyph_index_vertical
to involve the new functionality. This happens due to
a compatibility to PS interpreter that needs to call
the new function from the interpreter code rather than from
the graphics library.

See comments in code for more details.

EXPECTED DIFFERENCES :

None.


Modified: trunk/gs/Resource/Init/gs_ttf.ps
===================================================================
--- trunk/gs/Resource/Init/gs_ttf.ps	2008-10-08 05:56:27 UTC (rev 9130)
+++ trunk/gs/Resource/Init/gs_ttf.ps	2008-10-08 07:43:52 UTC (rev 9131)
@@ -711,7 +711,8 @@
   (vhea) //call.readtable
 	% Big tables
   (cmap) //call.readbigtable
-  (glyf) 1 index
+  (GSUB) //call.readbigtable
+  (glyf) //call.readbigtable
   (loca) 1 index
   (hmtx) 1 index
   (vmtx) 1 index

Modified: trunk/gs/base/gstype42.c
===================================================================
--- trunk/gs/base/gstype42.c	2008-10-08 05:56:27 UTC (rev 9130)
+++ trunk/gs/base/gstype42.c	2008-10-08 07:43:52 UTC (rev 9131)
@@ -14,6 +14,7 @@
 /* $Id$ */
 /* Type 42 (TrueType) font library routines */
 #include "memory_.h"
+#include "stdint_.h"
 #include "gx.h"
 #include "gserrors.h"
 #include "gsstruct.h"
@@ -191,6 +192,15 @@
 	else if (!memcmp(tab, "glyf", 4)) {
 	    pfont->data.glyf = offset;
 	    glyph_size = (uint)u32(tab + 12);
+	} else if (!memcmp(tab, "GSUB", 4)) {
+	    pfont->data.gsub_size = u32(tab + 12);
+	    pfont->data.gsub = gs_alloc_byte_array(pfont->memory, pfont->data.gsub_size, 1,
+							"gs_type42_font_init(GSUB)");
+	    if (pfont->data.gsub == 0)
+		return_error(gs_error_VMerror);
+	    code = gs_type42_read_data(pfont, offset, pfont->data.gsub_size, pfont->data.gsub);
+	    if ( code < 0 )
+		return code;
 	} else if (!memcmp(tab, "head", 4)) {
 	    byte head[54];
 
@@ -293,7 +303,7 @@
     } else {
 	/* Now build the len_glyphs array since 'loca' may not be properly sorted */
 	pfont->data.len_glyphs = (uint *)gs_alloc_byte_array(pfont->memory, loca_size, sizeof(uint),
-							"gs_type42_font");
+							"gs_type42_font_init");
 	if (pfont->data.len_glyphs == 0)
 	    return_error(gs_error_VMerror);
 	gs_font_notify_register((gs_font *)pfont, gs_len_glyphs_release, (void *)pfont);
@@ -640,6 +650,178 @@
     return 0;
 }
 
+uint
+gs_type42_substitute_glyph_index_vertical(gs_font_type42 *pfont, uint glyph_index)
+{   /* A rough trial implementation, possibly needs improvements or optimization. */
+    /* Fixme: optimize : Initialize subtable_ptr when the font is defined. */
+    byte *gsub_ptr = pfont->data.gsub;
+    ulong gsub_size = pfont->data.gsub_size;
+    typedef struct GSUB_s {
+	uint32_t Version;
+	uint16_t ScriptList;
+	uint16_t FeatureList;
+	uint16_t LookupList;
+    } GSUB;
+#if 0 /* Currently unused, but maybe useful for future. */
+    typedef struct ScriptRecord_s {
+	byte Tag[4];
+	uint16_t Offset; /* Offset to Script table from beginning of ScriptList */
+    } ScriptRecord;
+    typedef struct ScriptList_s {
+	uint16_t ScriptCount;
+	ScriptRecord records[1 /* ScriptCount */];
+    } ScriptList;
+    typedef struct LangSysRecord_s {
+	byte Tag[4];
+	uint16_t Offset;  /* Offset to LangSys table from beginning of Script table */
+    } LangSysRecord;
+    typedef struct ScriptTable_s {
+	uint16_t DefaultLangSys;
+	uint16_t LangSysCount;
+	LangSysRecord records[1/* LangSysCount */];
+    } ScriptTable;
+    typedef struct LangSysTable_s {
+	uint16_t LookupOrder;
+	uint16_t ReqFeatureIndex;
+	uint16_t FeatureCount;
+	uint16_t FeatureIndex[1/* FeatureCount */];
+    } LangSysTable;
+    typedef struct FeatureRecord_s {
+	byte Tag[4];
+	uint16_t Feature; /* Offset to Feature table from beginning of FeatureList */
+    } FeatureRecord;
+    typedef struct FeatureListTable_s {
+	uint16_t FeatureCount;
+	FeatureRecord records[1/* FeatureCount */];
+    } FeatureListTable;
+#endif
+    typedef struct LookupListTable_s {
+	uint16_t LookupCount;
+	uint16_t Lookup[1/* LookupCount */]; /* offsets to Lookup tables-from beginning of LookupList */
+    } LookupListTable;
+    typedef struct LookupTable_s {
+	uint16_t LookupType;
+	uint16_t LookupFlag;
+	uint16_t SubTableCount;
+	uint16_t SubTable[1/* SubTableCount */]; /* offsets to Lookup tables-from beginning of LookupList */
+    } LookupTable;
+    typedef struct SingleSubstFormat1_s {
+	uint16_t SubstFormat; /* ==1 */
+	uint16_t Coverage; /* Offset to Coverage table-from beginning of Substitution table */
+	uint16_t DeltaGlyphId;
+    } SingleSubstFormat1;
+    typedef uint16_t GlyphID;
+    typedef struct SingleSubstFormat2_s {
+	uint16_t SubstFormat; /* ==2 */
+	uint16_t Coverage; /* Offset to Coverage table-from beginning of Substitution table */
+	uint16_t GlyphCount;
+	GlyphID Substitute[1/* GlyphCount */]; 
+    } SingleSubstFormat2;
+    typedef struct CoverageFormat1_s {
+	uint16_t CoverageFormat; /* ==1 */
+	uint16_t GlyphCount;
+	GlyphID GlyphArray[1/*GlyphCount*/]; /* Array of GlyphIDs-in numerical order */
+    } CoverageFormat1;
+    typedef struct RangeRecord_s {
+	GlyphID Start; /* First GlyphID in the range */
+	GlyphID End; /* Last GlyphID in the range */
+	uint16_t StartCoverageIndex; /* Coverage Index of first GlyphID in range */
+    } RangeRecord;
+    typedef struct CoverageFormat2_s {
+	uint16_t CoverageFormat; /* ==2 */
+	uint16_t RangeCount;
+	GlyphID RangeRecord[1/*RangeCount*/]; /* Array of GlyphIDs-in numerical order */
+    } CoverageFormat2;
+    int i, j;
+    GSUB gsub;
+    LookupListTable lookup_list_table;
+    byte *lookup_list_ptr;
+
+    /* GSUB header */
+    gsub.Version = u32(gsub_ptr + offset_of(GSUB, Version));
+    gsub.ScriptList = U16(gsub_ptr + offset_of(GSUB, ScriptList));
+    gsub.FeatureList = U16(gsub_ptr + offset_of(GSUB, FeatureList));
+    gsub.LookupList = U16(gsub_ptr + offset_of(GSUB, LookupList));
+    /* LookupList table */
+    lookup_list_ptr = gsub_ptr + gsub.LookupList;
+    lookup_list_table.LookupCount = U16(lookup_list_ptr + offset_of(LookupListTable, LookupCount));
+    for (i = 0; i < lookup_list_table.LookupCount; i++) {
+	byte *lookup_table_offset_ptr = lookup_list_ptr + offset_of(LookupListTable, Lookup) 
+			       + i * sizeof(uint16_t);
+	byte *lookup_table_ptr = lookup_list_ptr + U16(lookup_table_offset_ptr);
+	LookupTable lookup_table;
+
+	lookup_table.LookupType = U16(lookup_table_ptr + offset_of(LookupTable, LookupType));
+	lookup_table.LookupFlag = U16(lookup_table_ptr + offset_of(LookupTable, LookupFlag));
+	lookup_table.SubTableCount = U16(lookup_table_ptr + offset_of(LookupTable, SubTableCount));
+
+	if (lookup_table.LookupType == 1) {
+	    /* Currently we're interesting in Format 1 only, which is only useful 
+	       for single glyph substitution for vertical fonts. 
+	       We copied the logic of this choice from the CJK patch attached to bug 689304,
+	       and we think that it may need a further improvement. */
+	    byte *subtable_offset_ptr = lookup_table_ptr + offset_of(LookupTable, SubTable);
+	    for (j = 0; j < lookup_table.SubTableCount; j++) {
+		byte *subtable_ptr = lookup_table_ptr + U16(subtable_offset_ptr + j * sizeof(uint16_t));
+		uint16_t format = U16(subtable_ptr);
+
+		if (format == 1) {
+		    SingleSubstFormat1 subst;
+
+		    subst.SubstFormat = format; /* Debug purpose. */
+		    subst.Coverage = U16(subtable_ptr + offset_of(SingleSubstFormat1, Coverage));
+		    subst.DeltaGlyphId = U16(subtable_ptr + offset_of(SingleSubstFormat1, DeltaGlyphId));
+		} else {
+		    SingleSubstFormat2 subst;
+		    byte *coverage_ptr;
+		    uint16_t coverage_format;
+
+		    subst.SubstFormat = format; /* Debug purpose. */
+		    subst.Coverage = U16(subtable_ptr + offset_of(SingleSubstFormat2, Coverage));
+		    subst.GlyphCount = U16(subtable_ptr + offset_of(SingleSubstFormat2, GlyphCount));
+		    coverage_ptr = subtable_ptr + subst.Coverage;
+		    coverage_format = U16(coverage_ptr);
+		    if (coverage_format == 1) {
+			CoverageFormat1 cov;
+
+			cov.CoverageFormat = coverage_format; /* Debug purpose only. */
+			cov.GlyphCount = U16(coverage_ptr + offset_of(CoverageFormat1, GlyphCount));
+			{   /* Binary search. */
+			    int k0 = 0, k1 = subst.GlyphCount;
+
+			    for (;;) {
+				int k = (k0 + k1) / 2;
+				GlyphID glyph = U16(coverage_ptr + offset_of(CoverageFormat1, GlyphArray)
+							 + sizeof(GlyphID) * k);
+				if (glyph_index == glyph) {
+				    /* Found. */
+				    if (k >= subst.GlyphCount)
+					break; /* Wrong data ? (not sure). */
+				    else {
+					GlyphID new_glyph = U16(subtable_ptr + offset_of(SingleSubstFormat2, Substitute)
+							    + sizeof(GlyphID) * k);
+
+					return new_glyph;
+				    }
+				} else if (k0 >= k1 - 1) {
+				    k += 0; /* A place for breakpoint. */
+				    break; /* Not found. */
+				} else if (glyph_index < glyph)
+				    k1 = k;
+				else
+				    k0 = k + 1;
+			    }			
+			}
+		    } else {
+			/* Not implemented yet. */
+		    }
+		}
+	    }
+	}
+    }
+    return glyph_index;
+}
+
 /* Parse a glyph into pieces, if any. */
 static int
 parse_pieces(gs_font_type42 *pfont, gs_glyph glyph, gs_glyph *pieces,
@@ -681,9 +863,7 @@
 			gx_path *ppath, double sbw[4])
 {
     gs_font_type42 *const pfont = (gs_font_type42 *)font;
-    uint glyph_index = (glyph >= GS_MIN_GLYPH_INDEX 
-		? glyph - GS_MIN_GLYPH_INDEX 
-		: pfont->data.get_glyph_index(pfont, glyph));
+    uint glyph_index;
     gs_fixed_point origin;
     int code;
     gs_glyph_info_t info;
@@ -697,8 +877,15 @@
        We apply design grid here.
      */
     cached_fm_pair *pair;
+ 
+    if (glyph >= GS_MIN_GLYPH_INDEX) 
+	glyph_index = glyph - GS_MIN_GLYPH_INDEX;
+    else {
+	glyph_index = pfont->data.get_glyph_index(pfont, glyph);
+	if (WMode && pfont->data.gsub_size)
+	    glyph_index = gs_type42_substitute_glyph_index_vertical(pfont, glyph_index);
+    }
     code = gx_lookup_fm_pair(font, pmat, &log2_scale, design_grid, &pair);
-
     if (code < 0)
 	return code;
     if (pmat == 0)
@@ -791,6 +978,8 @@
 	glyph_index = pfont->data.get_glyph_index(pfont, glyph);
 	if (glyph_index == GS_NO_GLYPH)
 	    return_error(gs_error_undefined);
+	if ((members & (GLYPH_INFO_WIDTH1 | GLYPH_INFO_VVECTOR1)) && pfont->data.gsub_size)
+	    glyph_index = gs_type42_substitute_glyph_index_vertical(pfont, glyph_index);
     }
     return gs_type42_glyph_info_by_gid(font, glyph, pmat, members, info, glyph_index);
 

Modified: trunk/gs/base/gxfont42.h
===================================================================
--- trunk/gs/base/gxfont42.h	2008-10-08 05:56:27 UTC (rev 9130)
+++ trunk/gs/base/gxfont42.h	2008-10-08 07:43:52 UTC (rev 9131)
@@ -104,6 +104,8 @@
     gs_glyph_cache *gdcache;
     bool warning_patented;
     bool warning_bad_instruction;
+    byte *gsub;			/* GSUB */
+    ulong gsub_size;
 };
 #define gs_font_type42_common\
     gs_font_base_common;\
@@ -114,10 +116,10 @@
 
 extern_st(st_gs_font_type42);
 #define public_st_gs_font_type42()	/* in gstype42.c */\
-  gs_public_st_suffix_add3_final(st_gs_font_type42, gs_font_type42,\
+  gs_public_st_suffix_add4_final(st_gs_font_type42, gs_font_type42,\
     "gs_font_type42", font_type42_enum_ptrs, font_type42_reloc_ptrs,\
     gs_font_finalize, st_gs_font_base, data.proc_data, data.len_glyphs, \
-    data.gdcache)
+    data.gdcache, data.gsub)
 
 /*
  * Because a Type 42 font contains so many cached values,
@@ -170,4 +172,6 @@
 int gs_truetype_font_info(gs_font *font, const gs_point *pscale, int members,
 	   gs_font_info_t *info);
 
+uint gs_type42_substitute_glyph_index_vertical(gs_font_type42 *pfont, uint glyph_index);
+
 #endif /* gxfont42_INCLUDED */

Modified: trunk/gs/psi/zchar42.c
===================================================================
--- trunk/gs/psi/zchar42.c	2008-10-08 05:56:27 UTC (rev 9130)
+++ trunk/gs/psi/zchar42.c	2008-10-08 07:43:52 UTC (rev 9131)
@@ -124,6 +124,7 @@
     gs_font *pfont;
     int code = font_param(op - 3, &pfont);
     gs_font_base *const pbfont = (gs_font_base *) pfont;
+    gs_font_type42 *const pfont42 = (gs_font_type42 *) pfont;
     gs_text_enum_t *penum = op_show_find(i_ctx_p);
     op_proc_t cont = (pbfont->PaintType == 0 ? type42_fill : type42_stroke), exec_cont = 0;
     ref *cnref;
@@ -163,6 +164,8 @@
 	return code;
     cnref = op - 1;
     glyph_index = (uint)op->value.intval;
+    if (gs_rootfont(igs)->WMode && pfont42->data.gsub_size)
+	glyph_index = gs_type42_substitute_glyph_index_vertical(pfont42, glyph_index);
     code = zchar42_set_cache(i_ctx_p, pbfont, cnref, glyph_index, cont, &exec_cont, true);
     if (code >= 0 && exec_cont != 0)
 	code = (*exec_cont)(i_ctx_p);
@@ -196,12 +199,14 @@
 {
     os_ptr op = osp;
     gs_font *pfont;
+    gs_font_type42 *pfont42;
     int code;
     gs_text_enum_t *penum = op_show_find(i_ctx_p);
     double sbxy[2];
     gs_point sbpt;
     gs_point *psbpt = 0;
     os_ptr opc = op;
+    uint glyph_index;
 
     if (!r_has_type(op - 3, t_dictionary)) {
 	check_op(6);
@@ -221,6 +226,7 @@
 		       pfont->FontType != ft_CID_TrueType)
 	)
 	return_error(e_undefined);
+    pfont42 = (gs_font_type42 *)pfont;
 
     if (!i_ctx_p->RenderTTNotdef) {
 	if (r_has_type(op - 1, t_name)) {
@@ -235,12 +241,15 @@
 	    }
 	}
     }
+    glyph_index = (uint)opc->value.intval;
+    if (gs_rootfont(igs)->WMode && pfont42->data.gsub_size)
+	glyph_index = gs_type42_substitute_glyph_index_vertical(pfont42, glyph_index);
     /*
      * We have to disregard penum->pis and penum->path, and render to
      * the current gstate and path.  This is a design bug that we will
      * have to address someday!
      */
-    code = gs_type42_append((uint)opc->value.intval, igs,
+    code = gs_type42_append(glyph_index, igs,
 			    igs->path, penum, pfont,
 			    (penum->text.operation & TEXT_DO_ANY_CHARPATH) != 0);
     if (code < 0)



More information about the gs-cvs mailing list