[cairo-commit] 9 commits - src/cairo-font-face-twin.c util/Makefile.am util/waterfall

Behdad Esfahbod behdad at kemper.freedesktop.org
Fri Dec 26 13:38:38 PST 2008


 src/cairo-font-face-twin.c |  429 +++++++++++++++++++++++++++------------------
 util/Makefile.am           |    3 
 util/waterfall             |   97 ++++++++++
 3 files changed, 358 insertions(+), 171 deletions(-)

New commits:
commit 9332c0a8eaf266e99555df9ad7769f8b5804cbfd
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 16:38:04 2008 -0500

    [util] Add waterfall

diff --git a/util/Makefile.am b/util/Makefile.am
index db40f17..895c516 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -28,4 +28,5 @@ EXTRA_DIST += \
 	COPYING \
 	xr2cairo \
 	cairo-api-update \
-	cairo-view
+	cairo-view \
+	waterfall
diff --git a/util/waterfall b/util/waterfall
new file mode 100755
index 0000000..5a683c5
--- /dev/null
+++ b/util/waterfall
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+
+import sys
+import cairo
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gtk.gdk
+import pango
+import gobject
+
+class CairoView(gtk.Window):
+    def __init__(self, family="", slant=0, weight=0, size=18, text="the quick brown fox jumps over the lazy dog! THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG?"):
+        gtk.Widget.__init__ (self)
+
+	self.family = family
+	if slant == "italic":
+	    self.slant = cairo.FONT_SLANT_ITALIC
+	elif slant == "oblique":
+	    self.slant = cairo.FONT_SLANT_OBLIQUE
+	else:
+	    self.slant = cairo.FONT_SLANT_NORMAL
+	if weight == "bold":
+	    self.weight = cairo.FONT_WEIGHT_BOLD
+	else:
+	    self.weight = cairo.FONT_WEIGHT_NORMAL
+	self.size = float (size)
+	self.text = text
+
+    def do_realize(self):
+        self.set_flags(self.flags() | gtk.REALIZED)
+
+        self.window = gtk.gdk.Window(
+            self.get_parent_window(),
+            width=self.allocation.width,
+            height=self.allocation.height,
+            window_type=gtk.gdk.WINDOW_CHILD,
+            wclass=gtk.gdk.INPUT_OUTPUT,
+            event_mask=self.get_events() | gtk.gdk.EXPOSURE_MASK)
+
+        self.window.set_user_data(self)
+
+        self.style.attach(self.window)
+
+        self.style.set_background(self.window, gtk.STATE_NORMAL)
+
+        self.window.move_resize(0, 0, 1000, 1000)
+
+    def do_unrealize(self):
+        self.window.destroy()
+
+    def do_expose_event(self, event):
+    	self.draw (event)
+
+        return False
+
+    def draw(self, event = None):
+
+        cr = self.window.cairo_create()
+	if event:
+		cr.rectangle(event.area.x, event.area.y,
+			     event.area.width, event.area.height)
+		cr.clip()
+
+    	cr.set_source_rgb (1, 1, 1)
+	cr.paint ()
+    	cr.set_source_rgb (0, 0, 0)
+
+	cr.select_font_face (self.family, self.slant, self.weight)
+
+	for size in range (1, 60):
+		cr.set_font_size (size)
+		extents = cr.text_extents (self.text)
+		cr.move_to (-extents[0], -extents[1])
+		cr.show_text (self.text)
+		cr.translate (0, extents[3])
+
+    def run(self):
+
+	self.props.allow_shrink = True
+        self.connect("destroy", gtk.main_quit)
+        self.show()
+
+        gtk.main()
+
+gobject.type_register(CairoView)
+
+def main(args):
+
+    if len (args) == 1:
+	print "usage: cairo-view family [slant [weight [size [text]]]]"
+	sys.exit (1)
+    cv= CairoView (*args[1:])
+    cv.run()
+
+if __name__ == "__main__":
+    main(sys.argv)
commit ab1febbf22a641feb2fda4b21156b2bd45df039b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 16:35:33 2008 -0500

    [twin] Resnap margin under monospace

diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index cd5357d..5d5bfb0 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -449,6 +449,7 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 			       cairo_text_extents_t *metrics)
 {
     double x1, y1, x2, y2, x3, y3;
+    double marginl;
     twin_scaled_properties_t *props;
     twin_snap_info_t info;
     const int8_t *b;
@@ -467,6 +468,7 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     /* small-caps */
     if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
 	glyph += 'A' - 'a';
+	/* 28 and 42 are small and capital letter heights of the glyph data */
 	cairo_scale (cr, 1, 28. / 42);
     }
 
@@ -482,15 +484,25 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     w = twin_glyph_right(b);
     gw = F(w);
 
+    marginl = props->marginl;
+
     /* monospace */
     if (props->face_props->monospace) {
 	double monow = F(24);
 	double extra =  props->penx + props->marginl + props->marginr;
 	cairo_scale (cr, (monow + extra) / (gw + extra), 1);
 	gw = monow;
+
+	/* resnap margin for new transform */
+	{
+	    double x, y, x_scale, x_scale_inv;
+	    x = 1; y = 0;
+	    compute_hinting_scale (cr, x, y, &x_scale, &x_scale_inv);
+	    marginl = SNAPXI (marginl);
+	}
     }
 
-    cairo_translate (cr, props->marginl, 0); /* XXX if monospace, we need to snap again */
+    cairo_translate (cr, marginl, 0);
 
     /* stretch */
     cairo_scale (cr, props->stretch, 1);
commit 3c91d9f5a2a290653a56242eed6acae4f16e99e3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 16:30:01 2008 -0500

    [twin] Adjust margins

diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index 2a8be3b..cd5357d 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -224,33 +224,71 @@ typedef struct _twin_scaled_properties {
 
 	double weight; /* unhinted pen width */
 	double penx, peny; /* hinted pen width */
+	double marginl, marginr; /* hinted side margins */
 
 	double stretch; /* stretch factor */
 } twin_scaled_properties_t;
 
 static void
-twin_compute_pen (cairo_t *cr,
-		  double width,
-		  double *penx, double *peny)
+compute_hinting_scale (cairo_t *cr,
+		       double x, double y,
+		       double *scale, double *inv)
+{
+    cairo_user_to_device_distance (cr, &x, &y);
+    *scale = sqrt (x*x + y*y);
+    *inv = 1 / *scale;
+}
+
+static void
+compute_hinting_scales (cairo_t *cr,
+			double *x_scale, double *x_scale_inv,
+			double *y_scale, double *y_scale_inv)
 {
     double x, y;
-    double scale, inv;
 
     x = 1; y = 0;
-    cairo_user_to_device_distance (cr, &x, &y);
-    scale = sqrt (x*x + y*y);
-    inv = 1 / scale;
-    *penx = round (width * scale) * inv;
-    if (*penx < inv)
-	*penx = inv;
+    compute_hinting_scale (cr, x, y, x_scale, x_scale_inv);
 
     x = 0; y = 1;
-    cairo_user_to_device_distance (cr, &x, &y);
-    scale = sqrt (x*x + y*y);
-    inv = 1 / scale;
-    *peny = round (width * scale) * inv;
-    if (*peny < inv)
-	*peny = inv;
+    compute_hinting_scale (cr, x, y, y_scale, y_scale_inv);
+}
+
+#define SNAPXI(p)	(round ((p) * x_scale) * x_scale_inv)
+#define SNAPYI(p)	(round ((p) * y_scale) * y_scale_inv)
+
+/* This controls the global font size */
+#define F(g)		((g) / 72.)
+
+static void
+twin_hint_pen_and_margins(cairo_t *cr,
+			  double *penx, double *peny,
+			  double *marginl, double *marginr)
+{
+    double x_scale, x_scale_inv;
+    double y_scale, y_scale_inv;
+    double margin;
+
+    compute_hinting_scales (cr,
+			    &x_scale, &x_scale_inv,
+			    &y_scale, &y_scale_inv);
+
+    *penx = SNAPXI (*penx);
+    if (*penx < x_scale_inv)
+	*penx = x_scale_inv;
+
+    *peny = SNAPYI (*peny);
+    if (*peny < y_scale_inv)
+	*peny = y_scale_inv;
+
+    margin = *marginl + *marginr;
+    *marginl = SNAPXI (*marginl);
+    if (*marginl < x_scale_inv)
+	*marginl = x_scale_inv;
+
+    *marginr = margin - *marginl;
+    if (*marginr < 0)
+	*marginr = 0;
+    *marginr = SNAPXI (*marginr);
 }
 
 static cairo_status_t
@@ -271,13 +309,15 @@ twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font,
     props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
 
     /* weight */
-    props->weight = props->face_props->weight * (4. / 64 / TWIN_WEIGHT_NORMAL);
+    props->weight = props->face_props->weight * (F (4) / TWIN_WEIGHT_NORMAL);
 
-    /* pen */
+    /* pen & margins */
+    props->penx = props->peny = props->weight;
+    props->marginl = props->marginr = F (4);
     if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT)
-	twin_compute_pen (cr, props->weight, &props->penx, &props->peny);
-    else
-	props->penx = props->peny = props->weight;
+	twin_hint_pen_and_margins(cr,
+				  &props->penx, &props->peny,
+				  &props->marginl, &props->marginr);
 
     /* stretch */
     props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
@@ -302,9 +342,6 @@ FREE_PROPS:
  * User-font implementation
  */
 
-/* This controls the global font size */
-#define F(g)		((g) / 72.)
-
 static cairo_status_t
 twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
 		       cairo_t              *cr,
@@ -320,9 +357,6 @@ twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
 #define TWIN_GLYPH_MAX_SNAP_Y 7
 
 typedef struct {
-    double x_scale, x_scale_inv;
-    double y_scale, y_scale_inv;
-
     int n_snap_x;
     int8_t snap_x[TWIN_GLYPH_MAX_SNAP_X];
     double snapped_x[TWIN_GLYPH_MAX_SNAP_X];
@@ -349,20 +383,12 @@ twin_compute_snap (cairo_t             *cr,
 {
     int			s, n;
     const signed char	*snap;
-    double x, y;
-
-    x = 1; y = 0;
-    cairo_user_to_device_distance (cr, &x, &y);
-    info->x_scale = sqrt (x*x + y*y);
-    info->x_scale_inv = 1 / info->x_scale;
-
-    x = 0; y = 1;
-    cairo_user_to_device_distance (cr, &x, &y);
-    info->y_scale = sqrt (x*x + y*y);
-    info->y_scale_inv = 1 / info->y_scale;
+    double x_scale, x_scale_inv;
+    double y_scale, y_scale_inv;
 
-#define SNAPXI(p)	(round ((p) * info->x_scale) * info->x_scale_inv)
-#define SNAPYI(p)	(round ((p) * info->y_scale) * info->y_scale_inv)
+    compute_hinting_scales (cr,
+			    &x_scale, &x_scale_inv,
+			    &y_scale, &y_scale_inv);
 
     snap = twin_glyph_snap_x (b);
     n = twin_glyph_n_snap_x (b);
@@ -459,12 +485,12 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     /* monospace */
     if (props->face_props->monospace) {
 	double monow = F(24);
-	cairo_scale (cr, (monow+3*props->penx) / (gw+3*props->penx), 1);
+	double extra =  props->penx + props->marginl + props->marginr;
+	cairo_scale (cr, (monow + extra) / (gw + extra), 1);
 	gw = monow;
     }
 
-    /* left margin */
-    cairo_translate (cr, props->penx, 0); /* XXX if monospace, we need to snap again */
+    cairo_translate (cr, props->marginl, 0); /* XXX if monospace, we need to snap again */
 
     /* stretch */
     cairo_scale (cr, props->stretch, 1);
@@ -475,7 +501,7 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 	info.n_snap_x = info.n_snap_y = 0;
 
     /* advance width */
-    metrics->x_advance = gw * props->stretch + props->penx * 3; /* pen width + margin */
+    metrics->x_advance = gw * props->stretch + props->penx + props->marginl + props->marginr;
 
     /* glyph shape */
     for (;;) {
commit 0b5c60bae1fb0924bbd43daab38932052e10b3be
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 15:48:46 2008 -0500

    [twin] Clean up hinting

diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index 991951e..2a8be3b 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -316,42 +316,10 @@ twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
   return twin_scaled_font_compute_properties (scaled_font, cr);
 }
 
-static double
-_twin_snap (int8_t v, cairo_bool_t do_snap, int8_t *snap, double *snapped, int n)
-{
-    int	s;
-
-    if (!do_snap || !n)
-	return F(v);
-
-    if (snap[0] == v)
-	return snapped[0];
-
-    for (s = 0; s < n - 1; s++)
-    {
-	if (snap[s+1] == v)
-	    return snapped[s+1];
-
-	if (snap[s] <= v && v <= snap[s+1])
-	{
-	    int before = snap[s];
-	    int after = snap[s+1];
-	    int dist = after - before;
-	    double snap_before = snapped[s];
-	    double snap_after = snapped[s+1];
-	    double dist_before = v - before;
-	    return snap_before + (snap_after - snap_before) * dist_before / dist;
-	}
-    }
-    return F(v);
-}
-
 #define TWIN_GLYPH_MAX_SNAP_X 4
 #define TWIN_GLYPH_MAX_SNAP_Y 7
 
 typedef struct {
-    cairo_bool_t snap;
-
     double x_scale, x_scale_inv;
     double y_scale, y_scale_inv;
 
@@ -363,9 +331,6 @@ typedef struct {
     double snapped_y[TWIN_GLYPH_MAX_SNAP_Y];
 } twin_snap_info_t;
 
-#define SNAPXI(p)	(round ((p) * info->x_scale) * info->x_scale_inv)
-#define SNAPYI(p)	(round ((p) * info->y_scale) * info->y_scale_inv)
-
 #define twin_glyph_left(g)      ((g)[0])
 #define twin_glyph_right(g)     ((g)[1])
 #define twin_glyph_ascent(g)    ((g)[2])
@@ -378,19 +343,14 @@ typedef struct {
 #define twin_glyph_draw(g)      (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
 
 static void
-_twin_compute_snap (cairo_t             *cr,
-		    cairo_scaled_font_t *scaled_font,
-		    twin_snap_info_t    *info,
-		    const signed char   *b)
+twin_compute_snap (cairo_t             *cr,
+		   twin_snap_info_t    *info,
+		   const signed char   *b)
 {
     int			s, n;
     const signed char	*snap;
     double x, y;
 
-    info->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
-    if (!info->snap)
-	return;
-
     x = 1; y = 0;
     cairo_user_to_device_distance (cr, &x, &y);
     info->x_scale = sqrt (x*x + y*y);
@@ -401,6 +361,8 @@ _twin_compute_snap (cairo_t             *cr,
     info->y_scale = sqrt (x*x + y*y);
     info->y_scale_inv = 1 / info->y_scale;
 
+#define SNAPXI(p)	(round ((p) * info->x_scale) * info->x_scale_inv)
+#define SNAPYI(p)	(round ((p) * info->y_scale) * info->y_scale_inv)
 
     snap = twin_glyph_snap_x (b);
     n = twin_glyph_n_snap_x (b);
@@ -421,8 +383,38 @@ _twin_compute_snap (cairo_t             *cr,
     }
 }
 
-#define SNAPX(p)	_twin_snap (p, info.snap, info.snap_x, info.snapped_x, info.n_snap_x)
-#define SNAPY(p)	_twin_snap (p, info.snap, info.snap_y, info.snapped_y, info.n_snap_y)
+static double
+twin_snap (int8_t v, int n, int8_t *snap, double *snapped)
+{
+    int	s;
+
+    if (!n)
+	return F(v);
+
+    if (snap[0] == v)
+	return snapped[0];
+
+    for (s = 0; s < n - 1; s++)
+    {
+	if (snap[s+1] == v)
+	    return snapped[s+1];
+
+	if (snap[s] <= v && v <= snap[s+1])
+	{
+	    int before = snap[s];
+	    int after = snap[s+1];
+	    int dist = after - before;
+	    double snap_before = snapped[s];
+	    double snap_after = snapped[s+1];
+	    double dist_before = v - before;
+	    return snap_before + (snap_after - snap_before) * dist_before / dist;
+	}
+    }
+    return F(v);
+}
+
+#define SNAPX(p)	twin_snap (p, info.n_snap_x, info.snap_x, info.snapped_x)
+#define SNAPY(p)	twin_snap (p, info.n_snap_y, info.snap_y, info.snapped_y)
 
 static cairo_status_t
 twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
@@ -472,12 +464,15 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     }
 
     /* left margin */
-    cairo_translate (cr, props->penx, 0);
+    cairo_translate (cr, props->penx, 0); /* XXX if monospace, we need to snap again */
 
     /* stretch */
     cairo_scale (cr, props->stretch, 1);
 
-    _twin_compute_snap (cr, scaled_font, &info, b);
+    if (props->snap)
+	twin_compute_snap (cr, &info, b);
+    else
+	info.n_snap_x = info.n_snap_y = 0;
 
     /* advance width */
     metrics->x_advance = gw * props->stretch + props->penx * 3; /* pen width + margin */
commit 6e7a2c4ce32ddfb0e58a74fcba8c4e46e46d32a4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 15:34:50 2008 -0500

    [twin] Fix monospace for narrow glyphs

diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index 3b9f969..991951e 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -443,10 +443,14 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     /* Save glyph space, we need it when stroking */
     cairo_save (cr);
 
-    /* left margin + pen width, pen width */
-    cairo_translate (cr, props->penx * 1.5, -props->peny * .5);
+    /* center the pen */
+    cairo_translate (cr, props->penx * .5, -props->peny * .5);
 
-    cairo_scale (cr, props->stretch, 1);
+    /* small-caps */
+    if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
+	glyph += 'A' - 'a';
+	cairo_scale (cr, 1, 28. / 42);
+    }
 
     /* slant */
     if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) {
@@ -454,11 +458,6 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 	cairo_transform (cr, &shear);
     }
 
-    if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
-	glyph += 'A' - 'a';
-	cairo_scale (cr, 1, 28. / 42);
-    }
-
     b = _cairo_twin_outlines +
 	_cairo_twin_charmap[unlikely (glyph >= ARRAY_LENGTH (_cairo_twin_charmap)) ? 0 : glyph];
     g = twin_glyph_draw(b);
@@ -468,10 +467,16 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     /* monospace */
     if (props->face_props->monospace) {
 	double monow = F(24);
-	cairo_scale (cr, (monow+props->penx) / (gw+props->penx), 1);
+	cairo_scale (cr, (monow+3*props->penx) / (gw+3*props->penx), 1);
 	gw = monow;
     }
 
+    /* left margin */
+    cairo_translate (cr, props->penx, 0);
+
+    /* stretch */
+    cairo_scale (cr, props->stretch, 1);
+
     _twin_compute_snap (cr, scaled_font, &info, b);
 
     /* advance width */
commit e8e6ae1294f11addcbc8a95db471bb48a50b0b1a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 15:15:15 2008 -0500

    [twin] Cache pen and other properties on the scaled font

diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index 7c446c9..3b9f969 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -159,7 +159,7 @@ parse_field (twin_face_properties_t *props,
 }
 
 static void
-props_parse (twin_face_properties_t *props,
+face_props_parse (twin_face_properties_t *props,
 	     const char *s)
 {
     const char *start, *end;
@@ -180,8 +180,8 @@ props_parse (twin_face_properties_t *props,
 }
 
 static cairo_status_t
-twin_set_face_properties_from_toy (cairo_font_face_t *twin_face,
-				   cairo_toy_font_face_t *toy_face)
+twin_font_face_set_properties_from_toy (cairo_font_face_t *twin_face,
+					cairo_toy_font_face_t *toy_face)
 {
     cairo_status_t status;
     twin_face_properties_t *props;
@@ -197,7 +197,7 @@ twin_set_face_properties_from_toy (cairo_font_face_t *twin_face,
     props->slant = toy_face->slant;
     props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ?
 		    TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD;
-    props_parse (props, toy_face->family);
+    face_props_parse (props, toy_face->family);
 
     status = cairo_font_face_set_user_data (twin_face,
 					    &twin_properties_key,
@@ -218,10 +218,85 @@ FREE_PROPS:
  */
 
 typedef struct _twin_scaled_properties {
-	cairo_bool_t snap;
-	double penx, peny;
+	twin_face_properties_t *face_props;
+
+	cairo_bool_t snap; /* hint outlines */
+
+	double weight; /* unhinted pen width */
+	double penx, peny; /* hinted pen width */
+
+	double stretch; /* stretch factor */
 } twin_scaled_properties_t;
 
+static void
+twin_compute_pen (cairo_t *cr,
+		  double width,
+		  double *penx, double *peny)
+{
+    double x, y;
+    double scale, inv;
+
+    x = 1; y = 0;
+    cairo_user_to_device_distance (cr, &x, &y);
+    scale = sqrt (x*x + y*y);
+    inv = 1 / scale;
+    *penx = round (width * scale) * inv;
+    if (*penx < inv)
+	*penx = inv;
+
+    x = 0; y = 1;
+    cairo_user_to_device_distance (cr, &x, &y);
+    scale = sqrt (x*x + y*y);
+    inv = 1 / scale;
+    *peny = round (width * scale) * inv;
+    if (*peny < inv)
+	*peny = inv;
+}
+
+static cairo_status_t
+twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font,
+				     cairo_t           *cr)
+{
+    cairo_status_t status;
+    twin_scaled_properties_t *props;
+
+    props = malloc (sizeof (twin_scaled_properties_t));
+    if (unlikely (props == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+
+    props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+						       &twin_properties_key);
+
+    props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
+
+    /* weight */
+    props->weight = props->face_props->weight * (4. / 64 / TWIN_WEIGHT_NORMAL);
+
+    /* pen */
+    if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT)
+	twin_compute_pen (cr, props->weight, &props->penx, &props->peny);
+    else
+	props->penx = props->peny = props->weight;
+
+    /* stretch */
+    props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
+
+
+    /* Save it */
+    status = cairo_scaled_font_set_user_data (scaled_font,
+					      &twin_properties_key,
+					      props, free);
+    if (unlikely (status))
+	goto FREE_PROPS;
+
+    return CAIRO_STATUS_SUCCESS;
+
+FREE_PROPS:
+    free (props);
+    return status;
+}
+
 
 /*
  * User-font implementation
@@ -238,7 +313,7 @@ twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
   metrics->ascent  = F (54);
   metrics->descent = 1 - metrics->ascent;
 
-  return CAIRO_STATUS_SUCCESS;
+  return twin_scaled_font_compute_properties (scaled_font, cr);
 }
 
 static double
@@ -346,39 +421,6 @@ _twin_compute_snap (cairo_t             *cr,
     }
 }
 
-static void
-_twin_compute_pen (cairo_t             *cr,
-		   cairo_scaled_font_t *scaled_font,
-		   double width,
-		   double *penx, double *peny)
-{
-    double x, y;
-    double scale, inv;
-    cairo_bool_t hint;
-
-    hint = scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT;
-    if (!hint) {
-	*penx = *peny = width;
-	return;
-    }
-
-    x = 1; y = 0;
-    cairo_user_to_device_distance (cr, &x, &y);
-    scale = sqrt (x*x + y*y);
-    inv = 1 / scale;
-    *penx = round (width * scale) * inv;
-    if (*penx < inv)
-	*penx = inv;
-
-    x = 0; y = 1;
-    cairo_user_to_device_distance (cr, &x, &y);
-    scale = sqrt (x*x + y*y);
-    inv = 1 / scale;
-    *peny = round (width * scale) * inv;
-    if (*peny < inv)
-	*peny = inv;
-}
-
 #define SNAPX(p)	_twin_snap (p, info.snap, info.snap_x, info.snapped_x, info.n_snap_x)
 #define SNAPY(p)	_twin_snap (p, info.snap, info.snap_y, info.snapped_y, info.n_snap_y)
 
@@ -389,45 +431,30 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 			       cairo_text_extents_t *metrics)
 {
     double x1, y1, x2, y2, x3, y3;
-    twin_face_properties_t *props;
+    twin_scaled_properties_t *props;
     twin_snap_info_t info;
     const int8_t *b;
     const int8_t *g;
     int8_t w;
     double gw;
-    double weight, stretch;
-    double penx, peny;
-
-    cairo_set_tolerance (cr, 0.01);
-    cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
-    cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
 
-    /* Prepare face */
+    props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key);
 
-    props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
-					   &twin_properties_key);
-
-    /* weight */
-    weight = props->weight * (4. / 64 / TWIN_WEIGHT_NORMAL);
-
-    /* lock pen matrix */
-    _twin_compute_pen (cr, scaled_font, weight, &penx, &peny);
+    /* Save glyph space, we need it when stroking */
     cairo_save (cr);
 
     /* left margin + pen width, pen width */
-    cairo_translate (cr, penx * 1.5, -peny * .5);
+    cairo_translate (cr, props->penx * 1.5, -props->peny * .5);
 
-    /* stretch */
-    stretch = 1 + .1 * ((int) props->stretch - (int) TWIN_STRETCH_NORMAL);
-    cairo_scale (cr, stretch, 1);
+    cairo_scale (cr, props->stretch, 1);
 
     /* slant */
-    if (props->slant != CAIRO_FONT_SLANT_NORMAL) {
+    if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) {
 	cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0};
 	cairo_transform (cr, &shear);
     }
 
-    if (props->smallcaps && glyph >= 'a' && glyph <= 'z') {
+    if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
 	glyph += 'A' - 'a';
 	cairo_scale (cr, 1, 28. / 42);
     }
@@ -439,16 +466,16 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     gw = F(w);
 
     /* monospace */
-    if (props->monospace) {
+    if (props->face_props->monospace) {
 	double monow = F(24);
-	cairo_scale (cr, (monow+penx) / (gw+penx), 1);
+	cairo_scale (cr, (monow+props->penx) / (gw+props->penx), 1);
 	gw = monow;
     }
 
     _twin_compute_snap (cr, scaled_font, &info, b);
 
     /* advance width */
-    metrics->x_advance = gw * stretch + penx * 3; /* pen width + margin */
+    metrics->x_advance = gw * props->stretch + props->penx * 3; /* pen width + margin */
 
     /* glyph shape */
     for (;;) {
@@ -485,9 +512,12 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 	    cairo_close_path (cr);
 	    /* fall through */
 	case 'e':
-	    cairo_restore (cr);
-	    cairo_scale (cr, penx, peny);
+	    cairo_restore (cr); /* restore glyph space */
+	    cairo_set_tolerance (cr, 0.01);
+	    cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+	    cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
 	    cairo_set_line_width (cr, 1);
+	    cairo_scale (cr, props->penx, props->peny);
 	    cairo_stroke (cr);
 	    break;
 	case 'X':
@@ -534,9 +564,11 @@ _cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t   *toy_face,
     cairo_user_font_face_set_init_func             (twin_font_face, twin_scaled_font_init);
     cairo_user_font_face_set_render_glyph_func     (twin_font_face, twin_scaled_font_render_glyph);
     cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
-    status = twin_set_face_properties_from_toy (twin_font_face, toy_face);
-    if (status)
+    status = twin_font_face_set_properties_from_toy (twin_font_face, toy_face);
+    if (status) {
+	cairo_font_face_destroy (twin_font_face);
 	return status;
+    }
 
     *font_face = twin_font_face;
 
commit e133cc14469e8ebb8311bf8db206147f6b07786d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 14:56:32 2008 -0500

    [twin] Don't stretch pen

diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index 5dc7102..7c446c9 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -410,10 +410,6 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     /* weight */
     weight = props->weight * (4. / 64 / TWIN_WEIGHT_NORMAL);
 
-    /* stretch */
-    stretch = 1 + .05 * ((int) props->stretch - (int) TWIN_STRETCH_NORMAL);
-    cairo_scale (cr, stretch, 1);
-
     /* lock pen matrix */
     _twin_compute_pen (cr, scaled_font, weight, &penx, &peny);
     cairo_save (cr);
@@ -421,6 +417,10 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     /* left margin + pen width, pen width */
     cairo_translate (cr, penx * 1.5, -peny * .5);
 
+    /* stretch */
+    stretch = 1 + .1 * ((int) props->stretch - (int) TWIN_STRETCH_NORMAL);
+    cairo_scale (cr, stretch, 1);
+
     /* slant */
     if (props->slant != CAIRO_FONT_SLANT_NORMAL) {
 	cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0};
@@ -448,8 +448,7 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     _twin_compute_snap (cr, scaled_font, &info, b);
 
     /* advance width */
-    metrics->x_advance = gw + penx * 3; /* pen width + margin */
-    metrics->x_advance *= stretch;
+    metrics->x_advance = gw * stretch + penx * 3; /* pen width + margin */
 
     /* glyph shape */
     for (;;) {
commit dec4d791f4cc626d1fa52d68518f787210240812
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 14:24:08 2008 -0500

    [twin] Minor shuffling

diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index 8164063..5dc7102 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -38,8 +38,6 @@
 #include <math.h>
 #include "cairoint.h"
 
-#include <ctype.h>
-
 /*
  * This file implements a user-font rendering the decendant of the Hershey
  * font coded by Keith Packard for use in the Twin window system.
@@ -50,6 +48,9 @@
 
 
 
+cairo_user_data_key_t twin_properties_key;
+
+
 /*
  * Face properties
  */
@@ -66,7 +67,7 @@ typedef enum {
   TWIN_WEIGHT_BOLD = 700,
   TWIN_WEIGHT_ULTRABOLD = 800,
   TWIN_WEIGHT_HEAVY = 900
-} twin_face_wight;
+} twin_face_weight_t;
 
 /* CSS stretch */
 typedef enum {
@@ -79,24 +80,19 @@ typedef enum {
   TWIN_STRETCH_EXPANDED,
   TWIN_STRETCH_EXTRA_EXPANDED,
   TWIN_STRETCH_ULTRA_EXPANDED
-} twin_face_stretch;
+} twin_face_stretch_t;
 
 
 typedef struct _twin_face_properties {
-    cairo_font_slant_t slant;
-    twin_face_wight    weight;
-    twin_face_stretch  stretch;
+    cairo_font_slant_t  slant;
+    twin_face_weight_t  weight;
+    twin_face_stretch_t stretch;
 
     /* lets have some fun */
     cairo_bool_t monospace;
     cairo_bool_t smallcaps;
 } twin_face_properties_t;
 
-cairo_user_data_key_t twin_face_properties_key;
-
-#define TOLOWER(c) \
-   (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
-
 static cairo_bool_t
 field_matches (const char *s1,
                const char *s2,
@@ -106,6 +102,9 @@ field_matches (const char *s1,
 
   while (len && *s1 && *s2)
     {
+#define TOLOWER(c) \
+   (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
+
       c1 = TOLOWER (*s1);
       c2 = TOLOWER (*s2);
       if (c1 != c2) {
@@ -131,11 +130,11 @@ parse_field (twin_face_properties_t *props,
 #define MATCH(s1, var, value) \
 	if (field_matches (s1, s, len)) var = value
 
+    if (0) ;
 
-         MATCH ("oblique",    props->slant, CAIRO_FONT_SLANT_OBLIQUE);
+    else MATCH ("oblique",    props->slant, CAIRO_FONT_SLANT_OBLIQUE);
     else MATCH ("italic",     props->slant, CAIRO_FONT_SLANT_ITALIC);
 
-
     else MATCH ("ultra-light", props->weight, TWIN_WEIGHT_ULTRALIGHT);
     else MATCH ("light",       props->weight, TWIN_WEIGHT_LIGHT);
     else MATCH ("medium",      props->weight, TWIN_WEIGHT_NORMAL);
@@ -153,10 +152,10 @@ parse_field (twin_face_properties_t *props,
     else MATCH ("extra-expanded",  props->stretch, TWIN_STRETCH_EXTRA_EXPANDED);
     else MATCH ("ultra-expanded",  props->stretch, TWIN_STRETCH_ULTRA_EXPANDED);
 
-    else MATCH ("small-caps", props->smallcaps, TRUE);
-
     else MATCH ("mono",       props->monospace, TRUE);
     else MATCH ("monospace",  props->monospace, TRUE);
+
+    else MATCH ("small-caps", props->smallcaps, TRUE);
 }
 
 static void
@@ -165,8 +164,11 @@ props_parse (twin_face_properties_t *props,
 {
     const char *start, *end;
 
+#define ISALPHA(c) \
+   (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
+
     for (start = end = s; *end; end++) {
-	if (isalpha (*end) || *end == '-')
+	if (ISALPHA (*end) || *end == '-')
 	    continue;
 
 	if (start < end)
@@ -192,16 +194,15 @@ twin_set_face_properties_from_toy (cairo_font_face_t *twin_face,
     props->monospace = FALSE;
     props->smallcaps = FALSE;
 
-    /* fill in props */
     props->slant = toy_face->slant;
     props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ?
 		    TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD;
     props_parse (props, toy_face->family);
 
     status = cairo_font_face_set_user_data (twin_face,
-					    &twin_face_properties_key,
+					    &twin_properties_key,
 					    props, free);
-    if (status)
+    if (unlikely (status))
 	goto FREE_PROPS;
 
     return CAIRO_STATUS_SUCCESS;
@@ -212,19 +213,22 @@ FREE_PROPS:
 }
 
 
-#define twin_glyph_left(g)      ((g)[0])
-#define twin_glyph_right(g)     ((g)[1])
-#define twin_glyph_ascent(g)    ((g)[2])
-#define twin_glyph_descent(g)   ((g)[3])
+/*
+ * Scaled properties
+ */
 
-#define twin_glyph_n_snap_x(g)  ((g)[4])
-#define twin_glyph_n_snap_y(g)  ((g)[5])
-#define twin_glyph_snap_x(g)    (&g[6])
-#define twin_glyph_snap_y(g)    (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
-#define twin_glyph_draw(g)      (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
+typedef struct _twin_scaled_properties {
+	cairo_bool_t snap;
+	double penx, peny;
+} twin_scaled_properties_t;
 
-#define F(g)		((g) / 72.)
 
+/*
+ * User-font implementation
+ */
+
+/* This controls the global font size */
+#define F(g)		((g) / 72.)
 
 static cairo_status_t
 twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
@@ -233,42 +237,16 @@ twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
 {
   metrics->ascent  = F (54);
   metrics->descent = 1 - metrics->ascent;
-  return CAIRO_STATUS_SUCCESS;
-}
 
-static cairo_status_t
-twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
-				   unsigned long        unicode,
-				   unsigned long       *glyph)
-{
-    /* We use an identity charmap.  Which means we could live
-     * with no unicode_to_glyph method too.  But we define this
-     * to map all unknown chars to a single unknown glyph to
-     * reduce pressure on cache. */
-
-    if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
-	*glyph = unicode;
-    else
-	*glyph = 0;
-
-    return CAIRO_STATUS_SUCCESS;
+  return CAIRO_STATUS_SUCCESS;
 }
 
-#define SNAPX(p)	_twin_snap (p, info.snap, info.snap_x, info.snapped_x, info.n_snap_x)
-#define SNAPY(p)	_twin_snap (p, info.snap, info.snap_y, info.snapped_y, info.n_snap_y)
-
-#define TWIN_GLYPH_MAX_SNAP_X 4
-#define TWIN_GLYPH_MAX_SNAP_Y 7
-
-#define SNAPXI(p)	(round ((p) * info->x_scale) * info->x_scale_inv)
-#define SNAPYI(p)	(round ((p) * info->y_scale) * info->y_scale_inv)
-
 static double
 _twin_snap (int8_t v, cairo_bool_t do_snap, int8_t *snap, double *snapped, int n)
 {
     int	s;
 
-    if (!do_snap)
+    if (!do_snap || !n)
 	return F(v);
 
     if (snap[0] == v)
@@ -293,11 +271,14 @@ _twin_snap (int8_t v, cairo_bool_t do_snap, int8_t *snap, double *snapped, int n
     return F(v);
 }
 
+#define TWIN_GLYPH_MAX_SNAP_X 4
+#define TWIN_GLYPH_MAX_SNAP_Y 7
+
 typedef struct {
     cairo_bool_t snap;
 
-    double x_scale, x_scale_inv, x_off;
-    double y_scale, y_scale_inv, y_off;
+    double x_scale, x_scale_inv;
+    double y_scale, y_scale_inv;
 
     int n_snap_x;
     int8_t snap_x[TWIN_GLYPH_MAX_SNAP_X];
@@ -307,6 +288,20 @@ typedef struct {
     double snapped_y[TWIN_GLYPH_MAX_SNAP_Y];
 } twin_snap_info_t;
 
+#define SNAPXI(p)	(round ((p) * info->x_scale) * info->x_scale_inv)
+#define SNAPYI(p)	(round ((p) * info->y_scale) * info->y_scale_inv)
+
+#define twin_glyph_left(g)      ((g)[0])
+#define twin_glyph_right(g)     ((g)[1])
+#define twin_glyph_ascent(g)    ((g)[2])
+#define twin_glyph_descent(g)   ((g)[3])
+
+#define twin_glyph_n_snap_x(g)  ((g)[4])
+#define twin_glyph_n_snap_y(g)  ((g)[5])
+#define twin_glyph_snap_x(g)    (&g[6])
+#define twin_glyph_snap_y(g)    (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
+#define twin_glyph_draw(g)      (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
+
 static void
 _twin_compute_snap (cairo_t             *cr,
 		    cairo_scaled_font_t *scaled_font,
@@ -384,6 +379,8 @@ _twin_compute_pen (cairo_t             *cr,
 	*peny = inv;
 }
 
+#define SNAPX(p)	_twin_snap (p, info.snap, info.snap_x, info.snapped_x, info.n_snap_x)
+#define SNAPY(p)	_twin_snap (p, info.snap, info.snap_y, info.snapped_y, info.n_snap_y)
 
 static cairo_status_t
 twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
@@ -408,7 +405,7 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     /* Prepare face */
 
     props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
-					   &twin_face_properties_key);
+					   &twin_properties_key);
 
     /* weight */
     weight = props->weight * (4. / 64 / TWIN_WEIGHT_NORMAL);
@@ -504,6 +501,29 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
+				   unsigned long        unicode,
+				   unsigned long       *glyph)
+{
+    /* We use an identity charmap.  Which means we could live
+     * with no unicode_to_glyph method too.  But we define this
+     * to map all unknown chars to a single unknown glyph to
+     * reduce pressure on cache. */
+
+    if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
+	*glyph = unicode;
+    else
+	*glyph = 0;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+
+/*
+ * Face constructor
+ */
+
 cairo_status_t
 _cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t   *toy_face,
 				      cairo_font_face_t      **font_face)
commit c3de08ee2fcfb0e092f0299e249b0f5fe56b87bf
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Dec 26 14:11:52 2008 -0500

    [twin] Further reduce weight

diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index b61e79e..8164063 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -411,7 +411,7 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 					   &twin_face_properties_key);
 
     /* weight */
-    weight = props->weight * (5. / 64 / TWIN_WEIGHT_NORMAL);
+    weight = props->weight * (4. / 64 / TWIN_WEIGHT_NORMAL);
 
     /* stretch */
     stretch = 1 + .05 * ((int) props->stretch - (int) TWIN_STRETCH_NORMAL);


More information about the cairo-commit mailing list