[XeTeX] Patch: Add an entry for stemv

Yue Wang yuleopen at gmail.com
Wed Mar 4 04:44:42 CET 2009


Hi, Jonathan:

Last year we talked about fonts like simsun may get ugly result when
using the dvipdfmx driver. And Jin-Hwan kindly added a -v option to
dvipdfmx driver in order to specify stemv number. So in the
tex->dvipdfmx world, now we can apply fake embolden, fake slant, and
stemv modification to a given font.
Today I hacked xetex three hours and added a new entry for xetex, and
here is the patch.

Usage:
\font\a="foobar:stemv=30" at 10pt
\a  foobar font \bye


Index: texk/web2c/xetexdir/XeTeXLayoutInterface.cpp
===================================================================
--- texk/web2c/xetexdir/XeTeXLayoutInterface.cpp	(revision 899)
+++ texk/web2c/xetexdir/XeTeXLayoutInterface.cpp	(working copy)
@@ -69,6 +69,7 @@
 	float			extend;
 	float			slant;
 	float			embolden;
+	int			stemv;
 #ifdef XETEX_GRAPHITE
 	gr::Segment*		grSegment;
 	XeTeXGrFont*		grFont;
@@ -545,9 +546,14 @@
 	return engine->embolden;
 }

+int getStemVFactor(XeTeXLayoutEngine engine)
+{
+	return engine->stemv;
+}
+
 XeTeXLayoutEngine createLayoutEngine(PlatformFontRef fontRef,
XeTeXFont font, UInt32 scriptTag, UInt32 languageTag,
 										UInt32* addFeatures, SInt32* addParams, UInt32*
removeFeatures, UInt32 rgbValue,
-										float extend, float slant, float embolden)
+										float extend, float slant, float embolden, int stemv)
 {
 	LEErrorCode status = LE_NO_ERROR;
 	XeTeXLayoutEngine result = new XeTeXLayoutEngine_rec;
@@ -561,6 +567,7 @@
 	result->extend = extend;
 	result->slant = slant;
 	result->embolden = embolden;
+	result->stemv = stemv;

 #ifdef XETEX_GRAPHITE
 	result->grSegment = NULL;
@@ -912,7 +919,7 @@
 XeTeXLayoutEngine createGraphiteEngine(PlatformFontRef fontRef, XeTeXFont font,
 										const char* name,
 										UInt32 rgbValue, int rtl, UInt32 languageTag,
-										float extend, float slant, float embolden,
+										float extend, float slant, float embolden, int stemv,
 										int nFeatures, const int* featureIDs, const int* featureValues)
 {
 	// check if the font supports graphite, and return NULL if not
@@ -931,6 +938,7 @@
 	result->extend = extend;
 	result->slant = slant;
 	result->embolden = embolden;
+	result->stemv = stemv;
 	result->layoutEngine = NULL;

 	result->grFont = new XeTeXGrFont(result->font, name);
Index: texk/web2c/xetexdir/XeTeX_mac.c
===================================================================
--- texk/web2c/xetexdir/XeTeX_mac.c	(revision 899)
+++ texk/web2c/xetexdir/XeTeX_mac.c	(working copy)
@@ -799,7 +799,7 @@
 				
 				// didn't find feature or variation, try other options....
 	
-				i = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden,
&letterspace, &rgbValue);
+				i = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden,
&letterspace, &rgbValue, &stemv);
 				if (i == 1)
 					goto next_option;
 				else if (i == -1)
Index: texk/web2c/xetexdir/XeTeX_ext.c
===================================================================
--- texk/web2c/xetexdir/XeTeX_ext.c	(revision 899)
+++ texk/web2c/xetexdir/XeTeX_ext.c	(working copy)
@@ -730,6 +730,51 @@
 	return neg ? -val : val;
 }

+int
+read_integer(const char** s)
+{
+	int		neg = 0;
+	int	val = 0;
+	const char*	cp = *s;
+
+	while (*cp == ' '|| *cp == '\t')
+		++cp;
+	if (*cp == '-') {
+		neg = 1;
+		++cp;
+	}
+	else if (*cp == '+') {
+		++cp;
+	}
+
+	while (*cp >= '0' && *cp <= '9') {
+		val = val * 10 + *cp - '0';
+		++cp;
+	}
+	*s = cp;
+
+	return neg ? -val : val;
+}
+
+int
+read_unsigned_integer(const char** s)
+{
+	int	val = 0;
+	const char*	cp = *s;
+
+	while (*cp == ' '|| *cp == '\t')
+		++cp;
+
+	while (*cp >= '0' && *cp <= '9') {
+		val = val * 10 + *cp - '0';
+		++cp;
+	}
+	*s = cp;
+
+	return val;
+}
+
+
 static UInt32
 read_tag(const char* cp, char padChar)
 {
@@ -815,7 +860,7 @@
 }

 int
-readCommonFeatures(const char* feat, const char* end, float* extend,
float* slant, float* embolden, float* letterspace, UInt32* rgbValue)
+readCommonFeatures(const char* feat, const char* end, float* extend,
float* slant, float* embolden, float* letterspace, UInt32* rgbValue,
int* stemv)
 	// returns 1 to go to next_option, -1 for bad_option, 0 to continue
 {
 	const char* sep;
@@ -878,6 +923,16 @@
 		return 1;
 	}

+	if (strncmp(feat, "stemv", 5) == 0) {
+		sep = feat + 5;
+		if (*sep != '=')
+			return -1;
+		++sep;
+		*stemv = read_unsigned_integer(&sep);
+		return 1;
+	}
+
+
 	return 0;
 }

@@ -906,6 +961,7 @@
 	float	slant = 0.0;
 	float	embolden = 0.0;
 	float	letterspace = 0.0;
+	int	stemv = -1;
 	
 	int i;

@@ -939,7 +995,7 @@
 				goto next_option;
 			}
 			
-			i = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden,
&letterspace, &rgbValue);
+			i = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden,
&letterspace, &rgbValue, &stemv);
 			if (i == 1)
 				goto next_option;
 			else if (i == -1)
@@ -1010,6 +1066,9 @@
 	if (letterspace != 0.0)
 		loadedfontletterspace = (letterspace / 100.0) * scaled_size;

+	if (stemv != -1)
+		stemv = stemv;
+
 	if ((loadedfontflags & FONT_FLAGS_COLORED) == 0)
 		rgbValue = 0x000000FF;

@@ -1018,7 +1077,7 @@

 	engine = createLayoutEngine(fontRef, font, scriptTag, languageTag,
 					addFeatures, addParams, removeFeatures, rgbValue,
-					extend, slant, embolden);
+					extend, slant, embolden, stemv);
 	if (engine == 0) {
 		// only free these if creation failed, otherwise the engine now owns them
 		if (addFeatures)
@@ -1077,6 +1136,7 @@
 	float	slant = 0.0;
 	float	embolden = 0.0;
 	float	letterspace = 0.0;
+	int	stemv = -1;
 	int		rtl = 0;

 	int		featureIDs[MAX_GRAPHITE_FEATURES];	
@@ -1089,7 +1149,7 @@
 	/* create a default engine so we can query the font for Graphite features;
 	   because of font caching, it's cheap to discard this and create
the real one later */
 	engine = createGraphiteEngine(fontRef, font, faceName, rgbValue,
rtl, languageTag,
-									extend, slant, embolden, 0, NULL, NULL);
+									extend, slant, embolden, stemv, 0, NULL, NULL);
 	if (engine == NULL)
 		return NULL;

@@ -1115,7 +1175,7 @@
 				goto next_option;
 			}
 			
-			i = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden,
&letterspace, &rgbValue);
+			i = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden,
&letterspace, &rgbValue, &stemv);
 			if (i == 1)
 				goto next_option;
 			else if (i == -1)
@@ -1176,6 +1236,9 @@
 	if (letterspace != 0.0)
 		loadedfontletterspace = (letterspace / 100.0) * scaled_size;

+	if (stemv != -1)
+		stemv = stemv;
+
 	if ((loadedfontflags & FONT_FLAGS_COLORED) == 0)
 		rgbValue = 0x000000FF;

@@ -1184,7 +1247,7 @@

 //	deleteLayoutEngine(engine);
 	engine = createGraphiteEngine(fontRef, font, faceName, rgbValue,
rtl, languageTag,
-					extend, slant, embolden, nFeatures, &featureIDs[0], &featureValues[0]);
+					extend, slant, embolden, stemv, nFeatures, &featureIDs[0],
&featureValues[0]);
 	if (engine != NULL)
 		nativefonttypeflag = OTGR_FONT_FLAG;

@@ -1614,6 +1677,7 @@
 #define XDV_FLAG_EXTEND			0x1000
 #define XDV_FLAG_SLANT			0x2000
 #define XDV_FLAG_EMBOLDEN		0x4000
+#define XDV_FLAG_STEMV			0x8000

 #ifdef XETEX_MAC
 static UInt32
@@ -1718,6 +1782,7 @@
 	float	extend = 1.0;
 	float	slant = 0.0;
 	float	embolden = 0.0;
+	int	stemv = -1;

 #ifdef XETEX_MAC
 	ATSUStyle	style = NULL;
@@ -1777,6 +1842,7 @@
 		extend = getExtendFactor(engine);
 		slant = getSlantFactor(engine);
 		embolden = getEmboldenFactor(engine);
+		stemv = getStemVFactor(engine);

 		size = X2Fix(getPointSize(engine));
 	}
@@ -1835,6 +1901,11 @@
 		flags |= XDV_FLAG_EMBOLDEN;
 	}

+	if (stemv != -1) {
+		fontDefLength += 2;
+		flags |= XDV_FLAG_STEMV;
+	}
+
 	if (fontDefLength > xdvBufSize) {
 		if (xdvbuffer != NULL)
 			free(xdvbuffer);
@@ -1905,6 +1976,11 @@
 		cp += 4;
 	}
 	
+	if (flags & XDV_FLAG_STEMV) {
+		*(UInt16*)(cp) = SWAP16(stemv);
+		cp += 2;
+	}
+	
 	return fontDefLength;
 }

Index: texk/web2c/xetexdir/XeTeXLayoutInterface.h
===================================================================
--- texk/web2c/xetexdir/XeTeXLayoutInterface.h	(revision 899)
+++ texk/web2c/xetexdir/XeTeXLayoutInterface.h	(working copy)
@@ -95,7 +95,7 @@

 XeTeXLayoutEngine createLayoutEngine(PlatformFontRef fontRef,
XeTeXFont font, UInt32 scriptTag, UInt32 languageTag,
 						UInt32* addFeatures, SInt32* addParams, UInt32* removeFeatures,
UInt32 rgbValue,
-						float extend, float slant, float embolden);
+						float extend, float slant, float embolden, int stemv);

 void deleteLayoutEngine(XeTeXLayoutEngine engine);

@@ -105,6 +105,7 @@
 float getExtendFactor(XeTeXLayoutEngine engine);
 float getSlantFactor(XeTeXLayoutEngine engine);
 float getEmboldenFactor(XeTeXLayoutEngine engine);
+int getStemVFactor(XeTeXLayoutEngine engine);

 SInt32 layoutChars(XeTeXLayoutEngine engine, UInt16* chars, SInt32
offset, SInt32 count, SInt32 max,
 						char rightToLeft, float x, float y, SInt32* status);
@@ -155,7 +156,7 @@
 XeTeXLayoutEngine createGraphiteEngine(PlatformFontRef fontRef, XeTeXFont font,
 										const char* name,
 										UInt32 rgbValue, int rtl, UInt32 languageTag,
-										float extend, float slant, float embolden,
+										float extend, float slant, float embolden, int stemv,
 										int nFeatures, const int* featureIDs, const int* featureValues);
 int makeGraphiteSegment(XeTeXLayoutEngine engine, const UniChar*
txtPtr, int txtLen);
 void getGraphiteGlyphInfo(XeTeXLayoutEngine engine, int index,
UInt16* glyphID, float* x, float* y);
Index: texk/web2c/xetexdir/XeTeX_ext.h
===================================================================
--- texk/web2c/xetexdir/XeTeX_ext.h	(revision 899)
+++ texk/web2c/xetexdir/XeTeX_ext.h	(working copy)
@@ -228,7 +228,7 @@
 	void* load_mapping_file(const char* s, const char* e, char byteMapping);
 	void* findnativefont(unsigned char* name, integer scaled_size);
 	void releasefontengine(void* engine, int type_flag);
-	int readCommonFeatures(const char* feat, const char* end, float*
extend, float* slant, float* embolden, float* letterspace, UInt32*
rgbValue);
+	int readCommonFeatures(const char* feat, const char* end, float*
extend, float* slant, float* embolden, float* letterspace, UInt32*
rgbValue, int* stemv);

 	/* the metrics params here are really TeX 'scaled' values, but that
typedef isn't available every place this is included */
 	void otgetfontmetrics(void* engine, integer* ascent, integer*
descent, integer* xheight, integer* capheight, integer* slant);
Index: texk/xdvipdfmx/src/dvi.c
===================================================================
--- texk/xdvipdfmx/src/dvi.c	(revision 899)
+++ texk/xdvipdfmx/src/dvi.c	(working copy)
@@ -131,6 +131,7 @@
   float extend;
   float slant;
   float embolden;
+  int stemv;
 #endif
 } *loaded_fonts = NULL;
 static int num_loaded_fonts = 0, max_loaded_fonts = 0;
@@ -159,6 +160,7 @@
   int    extend;
   int    slant;
   int    embolden;
+  int    stemv;
 #endif
 } *def_fonts = NULL;

@@ -172,6 +174,7 @@
 #define XDV_FLAG_EXTEND			0x1000
 #define XDV_FLAG_SLANT			0x2000
 #define XDV_FLAG_EMBOLDEN		0x4000
+#define XDV_FLAG_STEMV			0x8000
 #endif

 static int num_def_fonts = 0, max_def_fonts = 0;
@@ -618,6 +621,7 @@
   def_fonts[num_def_fonts].extend      = 0x00010000; /* 1.0 */
   def_fonts[num_def_fonts].slant       = 0;
   def_fonts[num_def_fonts].embolden    = 0;
+  def_fonts[num_def_fonts].stemv    = -1;
 #endif
   num_def_fonts++;

@@ -693,6 +697,10 @@
       def_fonts[num_def_fonts].embolden = get_signed_quad(dvi_file);
     else
       def_fonts[num_def_fonts].embolden = 0;
+    if (flags & XDV_FLAG_STEMV)
+      def_fonts[num_def_fonts].stemv = get_unsigned_pair(dvi_file);
+    else
+      def_fonts[num_def_fonts].stemv = -1;
     num_def_fonts++;
   } else {
     ERROR("Unknown native_font flags.");
@@ -1039,7 +1047,7 @@
 #ifdef XETEX
 static int
 dvi_locate_native_font (const char *ps_name, const char *fam_name,
-                        const char *sty_name, spt_t ptsize, int
layout_dir, int extend, int slant, int embolden)
+                        const char *sty_name, spt_t ptsize, int
layout_dir, int extend, int slant, int embolden, int stemv)
 {
   int           cur_id = -1;
   fontmap_rec  *mrec;
@@ -1053,10 +1061,10 @@

   cur_id = num_loaded_fonts++;

-  sprintf(fontmap_key, "%s/%c/%d/%d/%d", ps_name, layout_dir == 0 ?
'H' : 'V', extend, slant, embolden);
+  sprintf(fontmap_key, "%s/%c/%d/%d/%d/%d", ps_name, layout_dir == 0
? 'H' : 'V', extend, slant, embolden, stemv);
   mrec = pdf_lookup_fontmap_record(fontmap_key);
   if (mrec == NULL) {
-    if (pdf_load_native_font(ps_name, fam_name, sty_name, layout_dir,
extend, slant, embolden) == -1) {
+    if (pdf_load_native_font(ps_name, fam_name, sty_name, layout_dir,
extend, slant, embolden, stemv) == -1) {
     ERROR("Cannot proceed without the \"native\" font: %s (%s %s)...",
           ps_name, fam_name, sty_name);
     }
@@ -1082,6 +1090,7 @@
   loaded_fonts[cur_id].extend = mrec->opt.extend;
   loaded_fonts[cur_id].slant = mrec->opt.slant;
   loaded_fonts[cur_id].embolden = mrec->opt.bold;
+  loaded_fonts[cur_id].stemv = mrec->opt.stemv;

   if (verbose)
     MESG(">");
@@ -1720,7 +1729,8 @@
                                        def_fonts[i].layout_dir,
                                        def_fonts[i].extend,
                                        def_fonts[i].slant,
-                                       def_fonts[i].embolden);
+                                       def_fonts[i].embolden,
+				       def_fonts[i].stemv);
     } else {
       font_id = dvi_locate_font(def_fonts[i].font_name,
 	                        def_fonts[i].point_size);
Index: texk/xdvipdfmx/src/fontmap.c
===================================================================
--- texk/xdvipdfmx/src/fontmap.c	(revision 899)
+++ texk/xdvipdfmx/src/fontmap.c	(working copy)
@@ -1049,7 +1049,7 @@

 static int
 pdf_insert_native_fontmap_record (const char *name, const char *path,
int index, FT_Face face,
-                                  int layout_dir, int extend, int
slant, int embolden)
+                                  int layout_dir, int extend, int
slant, int embolden, int stemv)
 {
   char        *fontmap_key;
   fontmap_rec *mrec;
@@ -1058,7 +1058,7 @@
   ASSERT(path || face);

   fontmap_key = malloc(strlen(name) + 40);	// CHECK
-  sprintf(fontmap_key, "%s/%c/%d/%d/%d", name, layout_dir == 0 ? 'H'
: 'V', extend, slant, embolden);
+  sprintf(fontmap_key, "%s/%c/%d/%d/%d/%d", name, layout_dir == 0 ?
'H' : 'V', extend, slant, embolden, stemv);

   if (verbose)
     MESG("<NATIVE-FONTMAP:%s", fontmap_key);
@@ -1080,6 +1080,7 @@
   mrec->opt.extend = extend   / 65536.0;
   mrec->opt.slant  = slant    / 65536.0;
   mrec->opt.bold   = embolden / 65536.0;
+  mrec->opt.stemv  = stemv    ;

   pdf_insert_fontmap_record(mrec->map_name, mrec);
   pdf_clear_fontmap_record(mrec);
@@ -1094,7 +1095,7 @@
 static FT_Library ftLib;

 static int
-pdf_load_native_font_from_path(const char *ps_name, int layout_dir,
int extend, int slant, int embolden)
+pdf_load_native_font_from_path(const char *ps_name, int layout_dir,
int extend, int slant, int embolden, int stemv)
 {
   const char *p;
   char *filename = NEW(strlen(ps_name), char);
@@ -1134,7 +1135,7 @@

   if (error == 0)
     return pdf_insert_native_fontmap_record(ps_name, filename, index, face,
-                                           layout_dir, extend, slant,
embolden);
+                                           layout_dir, extend, slant,
embolden, stemv);
   else
     return error;
 }
@@ -1146,7 +1147,7 @@
 int
 pdf_load_native_font (const char *ps_name,
                       const char *fam_name, const char *sty_name,
-                      int layout_dir, int extend, int slant, int embolden)
+                      int layout_dir, int extend, int slant, int
embolden, int stemv)
 {
   static int        sInitialized = 0;
   int error = -1;
@@ -1163,7 +1164,7 @@
   }

   if (ps_name[0] == '[') {
-    error = pdf_load_native_font_from_path(ps_name, layout_dir,
extend, slant, embolden);
+    error = pdf_load_native_font_from_path(ps_name, layout_dir,
extend, slant, embolden, stemv);
   }
   else {
     CFStringRef theName = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
@@ -1185,7 +1186,7 @@
             ftErr = FT_New_Face(ftLib, (char*)path, index, &face);
             if (ftErr == 0) {
               error = pdf_insert_native_fontmap_record(ps_name, NULL, 0, face,
-                                                       layout_dir,
extend, slant, embolden);
+                                                       layout_dir,
extend, slant, embolden, stemv);
             }
           }
         }
@@ -1218,7 +1219,7 @@
   }

   if (ps_name[0] == '[') {
-    error = pdf_load_native_font_from_path(ps_name, layout_dir,
extend, slant, embolden);
+    error = pdf_load_native_font_from_path(ps_name, layout_dir,
extend, slant, embolden, stemv);
   }
   else {
     os = FcObjectSetBuild(FC_FILE, FC_INDEX, FC_FAMILY, FC_STYLE, NULL);
@@ -1242,7 +1243,7 @@
         name = (char *)FT_Get_Postscript_Name(face);
         if (!strcmp(name, ps_name)) {
           error = pdf_insert_native_fontmap_record(ps_name,
(char*)path, index, face,
-                                                   layout_dir,
extend, slant, embolden);
+                                                   layout_dir,
extend, slant, embolden, stemv);
           /* don't dispose of the FT_Face, as we'll be using it to
retrieve font data */
           break;
         }
Index: texk/xdvipdfmx/src/fontmap.h
===================================================================
--- texk/xdvipdfmx/src/fontmap.h	(revision 899)
+++ texk/xdvipdfmx/src/fontmap.h	(working copy)
@@ -103,7 +103,7 @@
 #ifdef XETEX
 extern int          pdf_load_native_font      (const char *ps_name,
                                                const char *fam_name,
const char *sty_name,
-                                               int layout_dir, int
extend, int slant, int embolden);
+                                               int layout_dir, int
extend, int slant, int embolden, int stemv);
 #endif

 #endif /* _FONTMAP_H_ */


Some limitations and bugs:

- I haven't touched Mac support yet. we should also modify xdv2pdf
driver in order to support the modification. but my Mac is broken last
week.... and I do not have time to reinstall the operating system.
- parse_integer and parse_unsigned_integer do not detect number
overflow. but since your parse_double doesn't do that too, I think it
is not urgent.
- It might have other bugs since it is a quick hack... but I have no
time to test.

I hope you can apply the patch to trunk. Thanks!


Yue Wang


More information about the XeTeX mailing list