summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2004-05-28 22:53:24 +0000
committerOwen Taylor <otaylor@src.gnome.org>2004-05-28 22:53:24 +0000
commit31e0850c421fcc777c452121eb5c68fcf2ce3cda (patch)
tree3ff00cfd6e238df998bcf3c1b95fc059582ab1ce
parent3ef5e7edc246615f45accafca5d83739b14ca66b (diff)
downloadpango-31e0850c421fcc777c452121eb5c68fcf2ce3cda.tar.gz
Add PangoMatrix type for affine transforms.
Fri May 28 11:39:39 2004 Owen Taylor <otaylor@redhat.com> * pango/pango-types.h pango/pango-utils.c: Add PangoMatrix type for affine transforms. * configure.in pango.pc.in pango/Makefile.am: Add a -lm dependency for PangoMatrix operations. * pango/pango-context.[ch]: Add pango_context_set/get_matrix(). * pango/pangoft2-render.c pango/pangoft2-private.h: Add code for drawing antialiased transformed rectangles and squiggly error underlines. * pango/pangoft2.[ch]: Add pango_ft2_render_transformed(), pango_ft2_render_layout_subpixel(), pango_ft2_render_layout_line_subpixel(), implement transformed rendering. * pango/pangofc-font.c: Pass any transformation matrix on to fontconfig when creating the pattern for a PangoFcFont.
-rw-r--r--ChangeLog22
-rw-r--r--ChangeLog.pre-1-1022
-rw-r--r--ChangeLog.pre-1-622
-rw-r--r--ChangeLog.pre-1-822
-rw-r--r--examples/pangoft2topgm.c122
-rw-r--r--examples/renderdemo.c122
-rw-r--r--pango/Makefile.am3
-rw-r--r--pango/pango-context.c49
-rw-r--r--pango/pango-context.h4
-rw-r--r--pango/pango-types.h57
-rw-r--r--pango/pango-utils.c136
-rw-r--r--pango/pangofc-fontmap.c87
-rw-r--r--pango/pangoft2-private.h13
-rw-r--r--pango/pangoft2-render.c459
-rw-r--r--pango/pangoft2.c359
-rw-r--r--pango/pangoft2.h41
16 files changed, 1338 insertions, 202 deletions
diff --git a/ChangeLog b/ChangeLog
index 68ce7055..4abf1ade 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+Fri May 28 11:39:39 2004 Owen Taylor <otaylor@redhat.com>
+
+ * pango/pango-types.h pango/pango-utils.c: Add PangoMatrix
+ type for affine transforms.
+
+ * configure.in pango.pc.in pango/Makefile.am: Add a -lm
+ dependency for PangoMatrix operations.
+
+ * pango/pango-context.[ch]: Add pango_context_set/get_matrix().
+
+ * pango/pangoft2-render.c pango/pangoft2-private.h: Add
+ code for drawing antialiased transformed rectangles and
+ squiggly error underlines.
+
+ * pango/pangoft2.[ch]: Add pango_ft2_render_transformed(),
+ pango_ft2_render_layout_subpixel(),
+ pango_ft2_render_layout_line_subpixel(), implement transformed
+ rendering.
+
+ * pango/pangofc-font.c: Pass any transformation matrix on to
+ fontconfig when creating the pattern for a PangoFcFont.
+
Fri May 28 2004 Theppitak Karoonboonyanan <thep@linux.thai.net>
* pango/opentype/pango-ot-buffer.c (apply_gpos_ltr): Negate y offset
diff --git a/ChangeLog.pre-1-10 b/ChangeLog.pre-1-10
index 68ce7055..4abf1ade 100644
--- a/ChangeLog.pre-1-10
+++ b/ChangeLog.pre-1-10
@@ -1,3 +1,25 @@
+Fri May 28 11:39:39 2004 Owen Taylor <otaylor@redhat.com>
+
+ * pango/pango-types.h pango/pango-utils.c: Add PangoMatrix
+ type for affine transforms.
+
+ * configure.in pango.pc.in pango/Makefile.am: Add a -lm
+ dependency for PangoMatrix operations.
+
+ * pango/pango-context.[ch]: Add pango_context_set/get_matrix().
+
+ * pango/pangoft2-render.c pango/pangoft2-private.h: Add
+ code for drawing antialiased transformed rectangles and
+ squiggly error underlines.
+
+ * pango/pangoft2.[ch]: Add pango_ft2_render_transformed(),
+ pango_ft2_render_layout_subpixel(),
+ pango_ft2_render_layout_line_subpixel(), implement transformed
+ rendering.
+
+ * pango/pangofc-font.c: Pass any transformation matrix on to
+ fontconfig when creating the pattern for a PangoFcFont.
+
Fri May 28 2004 Theppitak Karoonboonyanan <thep@linux.thai.net>
* pango/opentype/pango-ot-buffer.c (apply_gpos_ltr): Negate y offset
diff --git a/ChangeLog.pre-1-6 b/ChangeLog.pre-1-6
index 68ce7055..4abf1ade 100644
--- a/ChangeLog.pre-1-6
+++ b/ChangeLog.pre-1-6
@@ -1,3 +1,25 @@
+Fri May 28 11:39:39 2004 Owen Taylor <otaylor@redhat.com>
+
+ * pango/pango-types.h pango/pango-utils.c: Add PangoMatrix
+ type for affine transforms.
+
+ * configure.in pango.pc.in pango/Makefile.am: Add a -lm
+ dependency for PangoMatrix operations.
+
+ * pango/pango-context.[ch]: Add pango_context_set/get_matrix().
+
+ * pango/pangoft2-render.c pango/pangoft2-private.h: Add
+ code for drawing antialiased transformed rectangles and
+ squiggly error underlines.
+
+ * pango/pangoft2.[ch]: Add pango_ft2_render_transformed(),
+ pango_ft2_render_layout_subpixel(),
+ pango_ft2_render_layout_line_subpixel(), implement transformed
+ rendering.
+
+ * pango/pangofc-font.c: Pass any transformation matrix on to
+ fontconfig when creating the pattern for a PangoFcFont.
+
Fri May 28 2004 Theppitak Karoonboonyanan <thep@linux.thai.net>
* pango/opentype/pango-ot-buffer.c (apply_gpos_ltr): Negate y offset
diff --git a/ChangeLog.pre-1-8 b/ChangeLog.pre-1-8
index 68ce7055..4abf1ade 100644
--- a/ChangeLog.pre-1-8
+++ b/ChangeLog.pre-1-8
@@ -1,3 +1,25 @@
+Fri May 28 11:39:39 2004 Owen Taylor <otaylor@redhat.com>
+
+ * pango/pango-types.h pango/pango-utils.c: Add PangoMatrix
+ type for affine transforms.
+
+ * configure.in pango.pc.in pango/Makefile.am: Add a -lm
+ dependency for PangoMatrix operations.
+
+ * pango/pango-context.[ch]: Add pango_context_set/get_matrix().
+
+ * pango/pangoft2-render.c pango/pangoft2-private.h: Add
+ code for drawing antialiased transformed rectangles and
+ squiggly error underlines.
+
+ * pango/pangoft2.[ch]: Add pango_ft2_render_transformed(),
+ pango_ft2_render_layout_subpixel(),
+ pango_ft2_render_layout_line_subpixel(), implement transformed
+ rendering.
+
+ * pango/pangofc-font.c: Pass any transformation matrix on to
+ fontconfig when creating the pattern for a PangoFcFont.
+
Fri May 28 2004 Theppitak Karoonboonyanan <thep@linux.thai.net>
* pango/opentype/pango-ot-buffer.c (apply_gpos_ltr): Negate y offset
diff --git a/examples/pangoft2topgm.c b/examples/pangoft2topgm.c
index 277dec51..106f9c8a 100644
--- a/examples/pangoft2topgm.c
+++ b/examples/pangoft2topgm.c
@@ -27,6 +27,7 @@
#define DEFAULT_FONT_SIZE 18
#include <errno.h>
+#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
@@ -54,6 +55,7 @@ static char *opt_output = NULL;
static int opt_margin = 10;
static int opt_markup = FALSE;
static gboolean opt_rtl = FALSE;
+static int opt_rotate = 0;
static gboolean opt_auto_dir = TRUE;
static char *opt_text = NULL;
static gboolean opt_waterfall = FALSE;
@@ -149,6 +151,65 @@ get_options_string (void)
}
static void
+transform_point (PangoMatrix *matrix,
+ double x_in,
+ double y_in,
+ double *x_out,
+ double *y_out)
+{
+ *x_out = x_in * matrix->xx + y_in * matrix->xy + matrix->x0;
+ *y_out = x_in * matrix->yx + y_in * matrix->yy + matrix->y0;
+}
+
+static void
+output_body (PangoContext *context,
+ const char *text,
+ FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ int *width,
+ int *height)
+{
+ PangoLayout *layout;
+ PangoRectangle logical_rect;
+ int size, start_size, end_size, increment;
+ int dy;
+
+ if (opt_waterfall)
+ {
+ start_size = 8;
+ end_size = 48;
+ increment = 4;
+ }
+ else
+ {
+ start_size = end_size = -1;
+ increment = 1;
+ }
+
+ *width = 0;
+ *height = 0;
+ dy = 0;
+
+ for (size = start_size; size <= end_size; size += increment)
+ {
+ pango_context_set_matrix (context, matrix);
+
+ layout = make_layout (context, text, size);
+ pango_layout_get_extents (layout, NULL, &logical_rect);
+
+ *width = MAX (*width, PANGO_PIXELS (logical_rect.width));
+ *height += PANGO_PIXELS (logical_rect.height);
+
+ if (bitmap)
+ pango_ft2_render_layout (bitmap, layout, 0, dy);
+
+ dy += PANGO_PIXELS (logical_rect.height);
+
+ g_object_unref (layout);
+ }
+}
+
+static void
do_output (PangoContext *context,
const char *text,
FT_Bitmap *bitmap,
@@ -157,9 +218,16 @@ do_output (PangoContext *context,
{
PangoLayout *layout;
PangoRectangle logical_rect;
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+ int rotated_width, rotated_height;
int x = opt_margin;
int y = opt_margin;
- int size, start_size, end_size, increment;
+ double p1x, p1y;
+ double p2x, p2y;
+ double p3x, p3y;
+ double p4x, p4y;
+ double minx, miny;
+ double maxx, maxy;
*width = 0;
*height = 0;
@@ -181,35 +249,31 @@ do_output (PangoContext *context,
g_object_unref (layout);
g_free (options_string);
}
-
- if (opt_waterfall)
- {
- start_size = 8;
- end_size = 48;
- increment = 4;
- }
- else
- {
- start_size = end_size = -1;
- increment = 1;
- }
- for (size = start_size; size <= end_size; size += increment)
- {
- layout = make_layout (context, text, size);
- pango_layout_get_extents (layout, NULL, &logical_rect);
-
- *width = MAX (*width, PANGO_PIXELS (logical_rect.width));
- *height += PANGO_PIXELS (logical_rect.height);
-
- if (bitmap)
- pango_ft2_render_layout (bitmap, layout, x, y);
-
- y += PANGO_PIXELS (logical_rect.height);
+ output_body (context, text, NULL, NULL, &rotated_width, &rotated_height);
- g_object_unref (layout);
- }
+ pango_matrix_rotate (&matrix, opt_rotate);
+ transform_point (&matrix, 0, 0, &p1x, &p1y);
+ transform_point (&matrix, rotated_width, 0, &p2x, &p2y);
+ transform_point (&matrix, rotated_width, rotated_height, &p3x, &p3y);
+ transform_point (&matrix, 0, rotated_height, &p4x, &p4y);
+
+ minx = MIN (MIN (p1x, p2x), MIN (p3x, p4x));
+ miny = MIN (MIN (p1y, p2y), MIN (p3y, p4y));
+
+ maxx = MAX (MAX (p1x, p2x), MAX (p3x, p4x));
+ maxy = MAX (MAX (p1y, p2y), MAX (p3y, p4y));
+
+ matrix.x0 = x - minx;
+ matrix.y0 = y - miny;
+
+ if (bitmap)
+ output_body (context, text, bitmap, &matrix, &rotated_width, &rotated_height);
+
+ *width = MAX (*width, maxx - minx);
+ *height += maxy - miny;
+
*width += 2 * opt_margin;
*height += 2 * opt_margin;
}
@@ -263,6 +327,8 @@ int main(int argc, char *argv[])
ARG_STRING, &opt_output },
{ "rtl", "Set base dir to RTL",
ARG_BOOL, &opt_rtl },
+ { "rotate", "Angle at which to rotate results",
+ ARG_INT, &opt_rotate },
{ "text", "Text to display (instead of a file)",
ARG_STRING, &opt_text },
{ "waterfall", "Create a waterfall display",
@@ -390,7 +456,7 @@ int main(int argc, char *argv[])
memset (buf, 0x00, bitmap.pitch * bitmap.rows);
do_output (context, text, &bitmap, &width, &height);
-
+
/* Invert bitmap to get black text on white background */
{
int pix_idx;
diff --git a/examples/renderdemo.c b/examples/renderdemo.c
index 277dec51..106f9c8a 100644
--- a/examples/renderdemo.c
+++ b/examples/renderdemo.c
@@ -27,6 +27,7 @@
#define DEFAULT_FONT_SIZE 18
#include <errno.h>
+#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
@@ -54,6 +55,7 @@ static char *opt_output = NULL;
static int opt_margin = 10;
static int opt_markup = FALSE;
static gboolean opt_rtl = FALSE;
+static int opt_rotate = 0;
static gboolean opt_auto_dir = TRUE;
static char *opt_text = NULL;
static gboolean opt_waterfall = FALSE;
@@ -149,6 +151,65 @@ get_options_string (void)
}
static void
+transform_point (PangoMatrix *matrix,
+ double x_in,
+ double y_in,
+ double *x_out,
+ double *y_out)
+{
+ *x_out = x_in * matrix->xx + y_in * matrix->xy + matrix->x0;
+ *y_out = x_in * matrix->yx + y_in * matrix->yy + matrix->y0;
+}
+
+static void
+output_body (PangoContext *context,
+ const char *text,
+ FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ int *width,
+ int *height)
+{
+ PangoLayout *layout;
+ PangoRectangle logical_rect;
+ int size, start_size, end_size, increment;
+ int dy;
+
+ if (opt_waterfall)
+ {
+ start_size = 8;
+ end_size = 48;
+ increment = 4;
+ }
+ else
+ {
+ start_size = end_size = -1;
+ increment = 1;
+ }
+
+ *width = 0;
+ *height = 0;
+ dy = 0;
+
+ for (size = start_size; size <= end_size; size += increment)
+ {
+ pango_context_set_matrix (context, matrix);
+
+ layout = make_layout (context, text, size);
+ pango_layout_get_extents (layout, NULL, &logical_rect);
+
+ *width = MAX (*width, PANGO_PIXELS (logical_rect.width));
+ *height += PANGO_PIXELS (logical_rect.height);
+
+ if (bitmap)
+ pango_ft2_render_layout (bitmap, layout, 0, dy);
+
+ dy += PANGO_PIXELS (logical_rect.height);
+
+ g_object_unref (layout);
+ }
+}
+
+static void
do_output (PangoContext *context,
const char *text,
FT_Bitmap *bitmap,
@@ -157,9 +218,16 @@ do_output (PangoContext *context,
{
PangoLayout *layout;
PangoRectangle logical_rect;
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+ int rotated_width, rotated_height;
int x = opt_margin;
int y = opt_margin;
- int size, start_size, end_size, increment;
+ double p1x, p1y;
+ double p2x, p2y;
+ double p3x, p3y;
+ double p4x, p4y;
+ double minx, miny;
+ double maxx, maxy;
*width = 0;
*height = 0;
@@ -181,35 +249,31 @@ do_output (PangoContext *context,
g_object_unref (layout);
g_free (options_string);
}
-
- if (opt_waterfall)
- {
- start_size = 8;
- end_size = 48;
- increment = 4;
- }
- else
- {
- start_size = end_size = -1;
- increment = 1;
- }
- for (size = start_size; size <= end_size; size += increment)
- {
- layout = make_layout (context, text, size);
- pango_layout_get_extents (layout, NULL, &logical_rect);
-
- *width = MAX (*width, PANGO_PIXELS (logical_rect.width));
- *height += PANGO_PIXELS (logical_rect.height);
-
- if (bitmap)
- pango_ft2_render_layout (bitmap, layout, x, y);
-
- y += PANGO_PIXELS (logical_rect.height);
+ output_body (context, text, NULL, NULL, &rotated_width, &rotated_height);
- g_object_unref (layout);
- }
+ pango_matrix_rotate (&matrix, opt_rotate);
+ transform_point (&matrix, 0, 0, &p1x, &p1y);
+ transform_point (&matrix, rotated_width, 0, &p2x, &p2y);
+ transform_point (&matrix, rotated_width, rotated_height, &p3x, &p3y);
+ transform_point (&matrix, 0, rotated_height, &p4x, &p4y);
+
+ minx = MIN (MIN (p1x, p2x), MIN (p3x, p4x));
+ miny = MIN (MIN (p1y, p2y), MIN (p3y, p4y));
+
+ maxx = MAX (MAX (p1x, p2x), MAX (p3x, p4x));
+ maxy = MAX (MAX (p1y, p2y), MAX (p3y, p4y));
+
+ matrix.x0 = x - minx;
+ matrix.y0 = y - miny;
+
+ if (bitmap)
+ output_body (context, text, bitmap, &matrix, &rotated_width, &rotated_height);
+
+ *width = MAX (*width, maxx - minx);
+ *height += maxy - miny;
+
*width += 2 * opt_margin;
*height += 2 * opt_margin;
}
@@ -263,6 +327,8 @@ int main(int argc, char *argv[])
ARG_STRING, &opt_output },
{ "rtl", "Set base dir to RTL",
ARG_BOOL, &opt_rtl },
+ { "rotate", "Angle at which to rotate results",
+ ARG_INT, &opt_rotate },
{ "text", "Text to display (instead of a file)",
ARG_STRING, &opt_text },
{ "waterfall", "Create a waterfall display",
@@ -390,7 +456,7 @@ int main(int argc, char *argv[])
memset (buf, 0x00, bitmap.pitch * bitmap.rows);
do_output (context, text, &bitmap, &width, &height);
-
+
/* Invert bitmap to get black text on white background */
{
int pix_idx;
diff --git a/pango/Makefile.am b/pango/Makefile.am
index 5782a14b..14b3e039 100644
--- a/pango/Makefile.am
+++ b/pango/Makefile.am
@@ -40,7 +40,7 @@ endif
lib_LTLIBRARIES = libpango-1.0.la
libpango_1_0_la_LDFLAGS = -version-info $(LT_VERSION_INFO) $(no_undefined)
-libpango_1_0_la_LIBADD = $(GLIB_LIBS) mini-fribidi/libmini-fribidi.la
+libpango_1_0_la_LIBADD = $(GLIB_LIBS) mini-fribidi/libmini-fribidi.la -lm
libpango_1_0_la_DEPENDENCIES = mini-fribidi/libmini-fribidi.la
if OS_WIN32
@@ -189,6 +189,7 @@ libpangoft2_1_0_la_SOURCES = \
pangoft2.c \
pangoft2-private.h \
pangoft2-fontmap.c \
+ pangoft2-render.c \
module-defs-fc.c
if OS_WIN32
diff --git a/pango/pango-context.c b/pango/pango-context.c
index 316245dd..9ebde1e1 100644
--- a/pango/pango-context.c
+++ b/pango/pango-context.c
@@ -37,6 +37,8 @@ struct _PangoContext
PangoDirection base_dir;
PangoFontDescription *font_desc;
+ PangoMatrix *matrix;
+
PangoFontMap *font_map;
};
@@ -117,6 +119,8 @@ pango_context_finalize (GObject *object)
g_object_unref (context->font_map);
pango_font_description_free (context->font_desc);
+ if (context->matrix)
+ pango_matrix_free (context->matrix);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -152,6 +156,51 @@ pango_context_new (void)
}
/**
+ * pango_context_set_matrix:
+ * @context: a #PangoContext
+ * @matrix: a #PangoMatrix, or %NULL to unset any existing matrix.
+ * (No matrix set is the same as setting the identity matrix.)
+ *
+ * Sets the transformation matrix that will be applied when rendering
+ * with this context. Note that reported metrics are in the user space
+ * coordinates before the application of the matrix, not device-space
+ * coordiantes after the application of the matrix. So, they don't scale
+ * with the matrix, though they may change slightly for different
+ * matrices, depending on how the text is fit to the pixel grid.
+ **/
+void
+pango_context_set_matrix (PangoContext *context,
+ PangoMatrix *matrix)
+{
+ g_return_if_fail (PANGO_IS_CONTEXT (context));
+
+ if (context->matrix)
+ pango_matrix_free (context->matrix);
+ if (matrix)
+ context->matrix = pango_matrix_copy (matrix);
+}
+
+/**
+ * pango_context_get_matrix:
+ * @context: a #PangoContext
+ *
+ * Gets the transformation matrix that will be applied when
+ * rendering with this context. See pango_context_set_matrix().
+ *
+ * Returns: the matrix, or %NULL if no matrix has been set
+ * (which is the same as the identity matrix). The returned
+ * matrix is owned by Pango and must not be modified or
+ * freed.
+ **/
+PangoMatrix *
+pango_context_get_matrix (PangoContext *context)
+{
+ g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL);
+
+ return context->matrix;
+}
+
+/**
* pango_context_set_font_map:
* @context: a #PangoContext
* @font_map: the #PangoFontMap to set.
diff --git a/pango/pango-context.h b/pango/pango-context.h
index 878c3c28..6a6d28c8 100644
--- a/pango/pango-context.h
+++ b/pango/pango-context.h
@@ -78,6 +78,10 @@ void pango_context_set_base_dir (PangoContext
PangoDirection direction);
PangoDirection pango_context_get_base_dir (PangoContext *context);
+void pango_context_set_matrix (PangoContext *context,
+ PangoMatrix *matrix);
+PangoMatrix *pango_context_get_matrix (PangoContext *context);
+
/* Break a string of Unicode characters into segments with
* consistent shaping/language engine and bidrectional level.
* Returns a GList of PangoItem's
diff --git a/pango/pango-types.h b/pango/pango-types.h
index 6f515ead..55283fbd 100644
--- a/pango/pango-types.h
+++ b/pango/pango-types.h
@@ -33,6 +33,8 @@ typedef struct _PangoEngineLang PangoEngineLang;
typedef struct _PangoEngineShape PangoEngineShape;
typedef struct _PangoFont PangoFont;
+
+typedef struct _PangoMatrix PangoMatrix;
typedef struct _PangoRectangle PangoRectangle;
/* Dummy typedef - internally it's a 'const char *' */
@@ -53,6 +55,61 @@ struct _PangoRectangle
int height;
};
+/**
+ * PangoMatrix:
+ * @xx: 1st component of the transformation matrix
+ * @xy: 2nd component of the transformation matrix
+ * @yx: 3rd component of the transformation matrix
+ * @yy: 4th component of the transformation matrix
+ * @x0: x translation
+ * @y0: y translation
+ *
+ * A structure specifying a transformation between user-space
+ * coordinates and device coordinates. The transformation
+ * is given by
+ *
+ * <programlisting>
+ * x_device = x_user * matrix->xx + y_user * matrix->xy + matrix->x0;
+ * y_device = x_user * matrix->yx + y_user * matrix->yy + matrix->y0;
+ * </programlisting>
+ **/
+struct _PangoMatrix
+{
+ double xx;
+ double xy;
+ double yx;
+ double yy;
+ double x0;
+ double y0;
+};
+
+/**
+ * PANGO_MATRIX_INIT
+ *
+ * Constant that can be used to initialize a PangoMatrix to
+ * the identity transform.
+ *
+ * <informalexample><programlisting>
+ * PangoMatrix matrix = PANGO_MATRIX_INIT;
+ * pango_matrix_rotate (&amp;matrix, 45.);
+ * </programlisting></informalexample>
+ **/
+#define PANGO_MATRIX_INIT { 1., 0., 0., 1., 0., 0. };
+
+PangoMatrix *pango_matrix_copy (PangoMatrix *matrix);
+void pango_matrix_free (PangoMatrix *matrix);
+
+void pango_matrix_translate (PangoMatrix *matrix,
+ double tx,
+ double ty);
+void pango_matrix_scale (PangoMatrix *matrix,
+ double scale_x,
+ double scale_y);
+void pango_matrix_rotate (PangoMatrix *matrix,
+ double degrees);
+void pango_matrix_concat (PangoMatrix *matrix,
+ PangoMatrix *new);
+
#define PANGO_SCALE 1024
#define PANGO_PIXELS(d) (((d) >= 0) ? \
((d) + PANGO_SCALE / 2) / PANGO_SCALE : \
diff --git a/pango/pango-utils.c b/pango/pango-utils.c
index 68267772..6c75a3bf 100644
--- a/pango/pango-utils.c
+++ b/pango/pango-utils.c
@@ -20,6 +20,7 @@
*/
#include <errno.h>
+#include <math.h>
#include <string.h>
#include <stdlib.h>
@@ -986,6 +987,141 @@ pango_parse_stretch (const char *str,
return FALSE;
}
+/**
+ * pango_matrix_copy:
+ * @matrix: a #PangoMatrix
+ *
+ * Copies a #PangoMatrix.
+ *
+ * Return value: a copy of @matrix. The result must be freed with
+ * pango_matrix_free().
+ **/
+PangoMatrix *
+pango_matrix_copy (PangoMatrix *matrix)
+{
+ g_return_val_if_fail (matrix != NULL, NULL);
+
+ return g_memdup (matrix, sizeof (PangoMatrix));
+}
+
+/**
+ * pango_matrix_free:
+ * @matrix: a #PangoMatrix
+ *
+ * Free a #PangoMatrix created with pango_matrix_copy().
+ **/
+void
+pango_matrix_free (PangoMatrix *matrix)
+{
+ g_return_if_fail (matrix != NULL);
+
+ g_free (matrix);
+}
+
+/**
+ * pango_matrix_translate:
+ * @matrix: a #PangoMatrix
+ * @tx: amount to translate in the X direction
+ * @ty: amount to translate in the Y direction
+ *
+ * Changes the transformation represented by @matrix to be the
+ * transformation given by first translating by (@tx, @ty)
+ * then applying the original transformation.
+ **/
+void
+pango_matrix_translate (PangoMatrix *matrix,
+ double tx,
+ double ty)
+{
+ g_return_if_fail (matrix != NULL);
+
+ matrix->x0 = matrix->xx * tx + matrix->xy * ty + matrix->x0;
+ matrix->y0 = matrix->yx * tx + matrix->yy * ty + matrix->y0;
+}
+
+/**
+ * pango_matrix_scale:
+ * @matrix: a #PangoMatrix
+ * @scale_x: amount to scale by in X direction
+ * @scale_y: amount to scale by in Y direction
+ *
+ * Changes the transformation represented by @matrix to be the
+ * transformation given by first scaling by @sx in the X direction
+ * and @sy in the Y direction then applying the original
+ * transformation.
+ **/
+void
+pango_matrix_scale (PangoMatrix *matrix,
+ double scale_x,
+ double scale_y)
+{
+ g_return_if_fail (matrix != NULL);
+
+ matrix->xx *= scale_x;
+ matrix->xy *= scale_y;
+ matrix->yx *= scale_x;
+ matrix->yy *= scale_y;
+}
+
+/**
+ * pango_matrix_rotate:
+ * @matrix: a #PangoMatrix
+ * @degrees: degrees to rotate counter-clockwise
+ *
+ * Changes the transformation represented by @matrix to be the
+ * transformation given by first rotating by @degrees degrees
+ * counter-clokwise then applying the original transformation.
+ **/
+void
+pango_matrix_rotate (PangoMatrix *matrix,
+ double degrees)
+{
+ PangoMatrix tmp;
+ gdouble r, s, c;
+
+ g_return_if_fail (matrix != NULL);
+
+ r = degrees * (G_PI / 180.);
+ s = sin (r);
+ c = cos (r);
+
+ tmp.xx = c;
+ tmp.xy = s;
+ tmp.yx = -s;
+ tmp.yy = c;
+ tmp.x0 = 0;
+ tmp.y0 = 0;
+
+ pango_matrix_concat (matrix, &tmp);
+}
+
+/**
+ * pango_matrix_concat:
+ * @matrix: a #PangoMatrix
+ * @new: a #PangoMatrix
+ *
+ * Changes the transformation represented by @matrix to be the
+ * transformation given by first applying transformation
+ * given by @new then applying the original transformation.
+ **/
+void
+pango_matrix_concat (PangoMatrix *matrix,
+ PangoMatrix *new)
+{
+ PangoMatrix tmp;
+
+ g_return_if_fail (matrix != NULL);
+
+ tmp = *matrix;
+
+ matrix->xx = tmp.xx * new->xx + tmp.xy * new->yx;
+ matrix->xy = tmp.xx * new->xy + tmp.xy * new->yy;
+ matrix->yx = tmp.yx * new->xx + tmp.yy * new->yx;
+ matrix->yy = tmp.yx * new->xy + tmp.yy * new->yy;
+ matrix->x0 = tmp.xx * new->x0 + tmp.xy * new->y0 + tmp.x0;
+ matrix->y0 = tmp.yx * new->y0 + tmp.yy * new->y0 + tmp.y0;
+}
+
static const char canon_map[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c
index 26129836..5321e587 100644
--- a/pango/pangofc-fontmap.c
+++ b/pango/pangofc-fontmap.c
@@ -359,7 +359,6 @@ pango_fc_font_map_add (PangoFcFontMap *fcfontmap,
g_assert (fcfont->fontmap == NULL);
- fcfont->fontmap = g_object_ref (fcfontmap);
g_hash_table_insert (priv->fonts,
fcfont->font_pattern,
fcfont);
@@ -588,10 +587,12 @@ pango_fc_make_pattern (const PangoFontDescription *description)
static PangoFont *
pango_fc_font_map_new_font (PangoFontMap *fontmap,
- FcPattern *match)
+ PangoMatrix *pango_matrix,
+ FcPattern *match)
{
PangoFcFontMap *fcfontmap = (PangoFcFontMap *)fontmap;
PangoFcFontMapPrivate *priv = fcfontmap->priv;
+ FcPattern *pattern;
PangoFcFont *fcfont;
/* Returning NULL here actually violates a contract
@@ -604,14 +605,40 @@ pango_fc_font_map_new_font (PangoFontMap *fontmap,
return NULL;
/* Look up cache */
- fcfont = g_hash_table_lookup (priv->fonts, match);
+ if (!pango_matrix)
+ {
+ fcfont = g_hash_table_lookup (priv->fonts, match);
- if (fcfont)
- return g_object_ref (fcfont);
+ if (fcfont)
+ return g_object_ref (fcfont);
+ }
+
+ if (pango_matrix)
+ {
+ FcMatrix fc_matrix;
+
+ /* FontConfig has the Y axis pointing up, Pango, down.
+ */
+ fc_matrix.xx = pango_matrix->xx;
+ fc_matrix.xy = - pango_matrix->xy;
+ fc_matrix.yx = - pango_matrix->yx;
+ fc_matrix.yy = pango_matrix->yy;
+
+ pattern = FcPatternDuplicate (match);
+ FcPatternAddMatrix (pattern, FC_MATRIX, &fc_matrix);
+ }
+ else
+ pattern = match;
+
+ fcfont = PANGO_FC_FONT_MAP_GET_CLASS (fontmap)->new_font (fcfontmap, pattern);
- fcfont = PANGO_FC_FONT_MAP_GET_CLASS (fontmap)->new_font (fcfontmap, match);
+ if (!pango_matrix)
+ pango_fc_font_map_add (fcfontmap, fcfont);
- pango_fc_font_map_add (fcfontmap, fcfont);
+ if (pango_matrix)
+ FcPatternDestroy (pattern);
+
+ fcfont->fontmap = g_object_ref (fcfontmap);
return (PangoFont *)fcfont;
}
@@ -736,15 +763,19 @@ pango_fc_font_map_get_patterns (PangoFontMap *fontmap,
static PangoFont *
pango_fc_font_map_load_font (PangoFontMap *fontmap,
- PangoContext *context,
- const PangoFontDescription *description)
+ PangoContext *context,
+ const PangoFontDescription *description)
{
PangoFcPatternSet *patterns = pango_fc_font_map_get_patterns (fontmap, context, description, NULL);
if (!patterns)
return NULL;
if (patterns->n_patterns > 0)
- return pango_fc_font_map_new_font (fontmap, patterns->patterns[0]);
+ {
+ return pango_fc_font_map_new_font (fontmap,
+ context ? pango_context_get_matrix (context) : NULL,
+ patterns->patterns[0]);
+ }
return NULL;
}
@@ -809,35 +840,51 @@ pango_fc_font_map_load_fontset (PangoFontMap *fontmap,
PangoFcPatternSet *patterns = pango_fc_font_map_get_patterns (fontmap, context, desc, language);
PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (fontmap);
PangoFcFontMapPrivate *priv = fcfontmap->priv;
+ PangoFontset *result;
+ PangoMatrix *matrix;
int i;
if (!patterns)
return NULL;
- if (!patterns->fontset)
+ if (context)
+ matrix = pango_context_get_matrix (context);
+ else
+ matrix = NULL;
+
+ /* We never cache fontsets when a transformation is in place
+ */
+ if (!patterns->fontset || matrix)
{
PangoFontsetSimple *simple;
simple = pango_fontset_simple_new (language);
+ result = PANGO_FONTSET (simple);
for (i = 0; i < patterns->n_patterns; i++)
{
- PangoFont *font = pango_fc_font_map_new_font (fontmap, patterns->patterns[i]);
+ PangoFont *font;
+
+ font = pango_fc_font_map_new_font (fontmap, matrix, patterns->patterns[i]);
if (font)
pango_fontset_simple_append (simple, font);
}
-
- patterns->fontset = PANGO_FONTSET (simple);
- g_object_add_weak_pointer (G_OBJECT (patterns->fontset),
- (gpointer *)&patterns->fontset);
+
+ if (!matrix)
+ {
+ patterns->fontset = PANGO_FONTSET (simple);
+ g_object_add_weak_pointer (G_OBJECT (patterns->fontset),
+ (gpointer *)&patterns->fontset);
+ }
}
else
- g_object_ref (patterns->fontset);
+ result = g_object_ref (patterns->fontset);
- if (!patterns->cache_link ||
- patterns->cache_link != priv->fontset_cache->head)
+ if (!matrix &&
+ (!patterns->cache_link ||
+ patterns->cache_link != priv->fontset_cache->head))
pango_fc_font_map_cache_fontset (fcfontmap, patterns);
- return patterns->fontset;
+ return result;
}
static void
diff --git a/pango/pangoft2-private.h b/pango/pangoft2-private.h
index 8caa28b7..29ab5b50 100644
--- a/pango/pangoft2-private.h
+++ b/pango/pangoft2-private.h
@@ -92,4 +92,17 @@ void pango_ft2_font_set_cache_glyph_data (PangoFont *font,
void pango_ft2_font_set_glyph_cache_destroy (PangoFont *font,
GDestroyNotify destroy_notify);
+void _pango_ft2_draw_rect (FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ int x,
+ int y,
+ int width,
+ int height);
+void _pango_ft2_draw_error_underline (FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ int x,
+ int y,
+ int width,
+ int height);
+
#endif /* __PANGOFT2_PRIVATE_H__ */
diff --git a/pango/pangoft2-render.c b/pango/pangoft2-render.c
new file mode 100644
index 00000000..2b809fb7
--- /dev/null
+++ b/pango/pangoft2-render.c
@@ -0,0 +1,459 @@
+/* Pango
+ * pangoft2-render.c: Rendering routines to FT_Bitmap objects
+ *
+ * Copyright (C) 2004 Red Hat Software
+ * Copyright (C) 2000 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+
+#include "pangoft2-private.h"
+
+typedef struct {
+ double y;
+ double x1;
+ double x2;
+} Position;
+
+static void
+draw_simple_trap (FT_Bitmap *bitmap,
+ Position *t,
+ Position *b)
+{
+ int iy = floor (t->y);
+ int x1, x2, x;
+ double dy = b->y - t->y;
+ guchar *dest;
+
+ if (iy < 0 || iy >= bitmap->rows)
+ return;
+ dest = bitmap->buffer + iy * bitmap->pitch;
+
+ if (t->x1 < b->x1)
+ x1 = floor (t->x1);
+ else
+ x1 = floor (b->x1);
+
+ if (t->x2 > b->x2)
+ x2 = ceil (t->x2);
+ else
+ x2 = ceil (b->x2);
+
+ x1 = CLAMP (x1, 0, bitmap->width);
+ x2 = CLAMP (x2, 0, bitmap->width);
+
+ for (x = x1; x < x2; x++)
+ {
+ double top_left = MAX (t->x1, x);
+ double top_right = MIN (t->x2, x + 1);
+ double bottom_left = MAX (b->x1, x);
+ double bottom_right = MIN (b->x2, x + 1);
+ double c = 0.5 * dy * ((top_right - top_left) + (bottom_right - bottom_left));
+
+ /* When converting to [0,255], we round up. This is intended
+ * to prevent the problem of pixels that get divided into
+ * multiple slices not being fully black.
+ */
+ int ic = c * 256;
+
+ dest[x] = MIN (dest[x] + ic, 255);
+ }
+}
+
+static void
+interpolate_position (Position *result,
+ Position *top,
+ Position *bottom,
+ double val,
+ double val1,
+ double val2)
+{
+ result->y = (top->y * (val2 - val) + bottom->y * (val - val1)) / (val2 - val1);
+ result->x1 = (top->x1 * (val2 - val) + bottom->x1 * (val - val1)) / (val2 - val1);
+ result->x2 = (top->x2 * (val2 - val) + bottom->x2 * (val - val1)) / (val2 - val1);
+}
+
+/* This draws a trapezoid with the parallel sides aligned with
+ * the X axis. We do this by subdividing the trapezoid vertically
+ * into thin slices (themselves trapezoids) where two edge sides are each
+ * contained within a single pixel and then rasterizing each
+ * slice. There are frequently multiple slices within a single
+ * line so we have to accumulate to get the final result.
+ */
+static void
+draw_trap (FT_Bitmap *bitmap,
+ double y1,
+ double x11,
+ double x21,
+ double y2,
+ double x12,
+ double x22)
+{
+ Position pos;
+ Position t;
+ Position b;
+ gboolean done = FALSE;
+
+ if (y1 == y2)
+ return;
+
+ pos.y = t.y = y1;
+ pos.x1 = t.x1 = x11;
+ pos.x2 = t.x2 = x21;
+ b.y = y2;
+ b.x1 = x12;
+ b.x2 = x22;
+
+ while (!done)
+ {
+ Position pos_next;
+ double y_next, x1_next, x2_next;
+ double ix1, ix2;
+
+ /* The algorithm here is written to emphasize simplicity and
+ * numerical stability as opposed to speed.
+ *
+ * While the end result is slicing up the polygon vertically,
+ * conceptually we aren't walking in the X direction, rather we
+ * are walking along the edges. When we compute crossing of
+ * horizontal pixel boundaries, we use the X coordinate as the
+ * interpolating variable, when we compute crossing for vertical
+ * pixel boundaries, we use the Y coordinate.
+ *
+ * This allows us to handle almost exactly horizontal edges without
+ * running into difficulties. (Almost exactly horizontal edges
+ * come up frequently due to inexactness in computing, say,
+ * a 90 degree rotation transformation)
+ */
+
+ pos_next = b;
+ done = TRUE;
+
+ /* Check for crossing vertical pixel boundaries */
+ y_next = floor (pos.y) + 1;
+ if (y_next < pos_next.y)
+ {
+ interpolate_position (&pos_next, &t, &b,
+ y_next, t.y, b.y);
+ pos_next.y = y_next;
+ done = FALSE;
+ }
+
+ /* Check left side for crossing horizontal pixel boundaries */
+ ix1 = floor (pos.x1);
+
+ if (b.x1 < t.x1)
+ {
+ if (ix1 == pos.x1)
+ x1_next = ix1 - 1;
+ else
+ x1_next = ix1;
+
+ if (x1_next > pos_next.x1)
+ {
+ interpolate_position (&pos_next, &t, &b,
+ x1_next, t.x1, b.x1);
+ pos_next.x1 = x1_next;
+ done = FALSE;
+ }
+ }
+ else if (b.x1 > t.x1)
+ {
+ x1_next = ix1 + 1;
+
+ if (x1_next < pos_next.x1)
+ {
+ interpolate_position (&pos_next, &t, &b,
+ x1_next, t.x1, b.x1);
+ pos_next.x1 = x1_next;
+ done = FALSE;
+ }
+ }
+
+ /* Check right side for crossing horizontal pixel boundaries */
+ ix2 = floor (pos.x2);
+
+ if (b.x2 < t.x2)
+ {
+ if (ix2 == pos.x2)
+ x2_next = ix2 - 1;
+ else
+ x2_next = ix2;
+
+ if (x2_next > pos_next.x2)
+ {
+ interpolate_position (&pos_next, &t, &b,
+ x2_next, t.x2, b.x2);
+ pos_next.x2 = x2_next;
+ done = FALSE;
+ }
+ }
+ else if (x22 > x21)
+ {
+ x2_next = ix2 + 1;
+
+ if (x2_next < pos_next.x2)
+ {
+ interpolate_position (&pos_next, &t, &b,
+ x2_next, t.x2, b.x2);
+ pos_next.x2 = x2_next;
+ done = FALSE;
+ }
+ }
+
+ draw_simple_trap (bitmap, &pos, &pos_next);
+ pos = pos_next;
+ }
+}
+
+typedef struct
+{
+ double x, y;
+} Point;
+
+static void
+to_device (PangoMatrix *matrix,
+ double x,
+ double y,
+ Point *result)
+{
+ result->x = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
+ result->y = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
+}
+
+int
+compare_points (const void *a,
+ const void *b)
+{
+ const Point *pa = a;
+ const Point *pb = b;
+
+ if (pa->y < pb->y)
+ return -1;
+ else if (pa->y > pb->y)
+ return 1;
+ else if (pa->x < pb->x)
+ return -1;
+ else if (pa->x > pb->x)
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * _pango_ft2_draw_rect:
+ * @bitmap: a #FT_Bitmap
+ * @matrix: a #PangoMatrix giving the user to device transformation
+ * @x_offset: X offset in device coordinates to add onto transformation result
+ * @y_offset: Y offset in device coordinates to add onto transformation result
+ * @x: X coordinate of rectangle, in Pango units in user coordinate system
+ * @y: Y coordinate of rectangle, in Pango units in user coordinate system
+ * @width: width of rectangle, in Pango units in user coordinate system
+ * @height: height of rectangle, in Pango units in user coordinate system
+ *
+ * Render an axis aligned rectangle in user coordinates onto
+ * a bitmap after transformation by the given matrix. Rendering
+ * is done anti-aliased.
+ **/
+void
+_pango_ft2_draw_rect (FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ Point points[4];
+
+ /* Convert the points to device coordinates, and sort
+ * in ascending Y order. (Ordering by X for ties)
+ */
+ to_device (matrix, x, y, &points[0]);
+ to_device (matrix, x + width, y, &points[1]);
+ to_device (matrix, x, y + height, &points[2]);
+ to_device (matrix, x + width, y + height, &points[3]);
+
+ qsort (points, 4, sizeof (Point), compare_points);
+
+ /* There are essentially three cases. (There is a fourth
+ * case where trapezoid B is degenerate and we just have
+ * two triangles, but we don't need to handle it separately.)
+ *
+ * 1 2 3
+ *
+ * ______ /\ /\
+ * / / /A \ /A \
+ * / B / /____\ /____\
+ * /_____/ / B / \ B \
+ * /_____/ \_____\
+ * \ C / \ C /
+ * \ / \ /
+ * \/ \/
+ */
+ if (points[0].y == points[1].y)
+ {
+ /* Case 1 (pure shear) */
+ draw_trap (bitmap, /* B */
+ points[0].y, points[0].x, points[1].x,
+ points[2].y, points[2].x, points[3].x);
+ }
+ else if (points[1].x < points[2].x)
+ {
+ /* Case 2 */
+ double tmp_width = ((points[2].x - points[0].x) * (points[1].y - points[0].y)) / (points[2].y - points[0].y);
+ double base_width = tmp_width + points[0].x - points[1].x;
+
+ draw_trap (bitmap, /* A */
+ points[0].y, points[0].x, points[0].x,
+ points[1].y, points[1].x, points[1].x + base_width);
+ draw_trap (bitmap,
+ points[1].y, points[1].x, points[1].x + base_width, /* B */
+ points[2].y, points[2].x - base_width, points[2].x);
+ draw_trap (bitmap,
+ points[2].y, points[2].x - base_width, points[2].x, /* C */
+ points[3].y, points[3].x, points[3].x);
+ }
+ else
+ {
+ /* case 3 */
+ double tmp_width = ((points[0].x - points[2].x) * (points[1].y - points[0].y)) / (points[2].y - points[0].y);
+ double base_width = tmp_width + points[1].x - points[0].x;
+
+ draw_trap (bitmap, /* A */
+ points[0].y, points[0].x, points[0].x,
+ points[1].y, points[1].x - base_width, points[1].x);
+ draw_trap (bitmap,
+ points[1].y, points[1].x - base_width, points[1].x, /* B */
+ points[2].y, points[2].x, points[2].x + base_width);
+ draw_trap (bitmap,
+ points[2].y, points[2].x, points[2].x + base_width, /* C */
+ points[3].y, points[3].x, points[3].x);
+ }
+}
+
+/* We are drawing an error underline that looks like one of:
+ *
+ * /\ /\ /\ /\ /\ -
+ * / \ / \ / \ / \ / \ |
+ * \ \ /\ \ / / \ \ /\ \ |
+ * \ \/B \ \/ C / \ \/B \ \ | height = HEIGHT_SQUARES * square
+ * \ A \ /\ A \ / \ A \ /\ A \ |
+ * \ \/ \ \/ \ \/ \ \ |
+ * \ / \ / \ / \ / |
+ * \/ \/ \/ \/ -
+ *
+ * |----|
+ * unit_width = (HEIGHT_SQUARES - 1) * square
+ *
+ * To do this conveniently, we work in a coordinate system where A,B,C
+ * are axis aligned rectangles. (If fonts were square, the diagrams
+ * would be clearer)
+ *
+ * (0,0)
+ * /\ /\
+ * / \ / \
+ * /\ /\ /\ /
+ * / \/ \/ \/
+ * / \ /\ /
+ * Y axis \/ \/
+ * \ /\
+ * \/ \
+ * \ X axis
+ *
+ * Note that the long side in this coordinate system is HEIGHT_SQUARES + 1
+ * units long
+ *
+ * The diagrams above are shown with HEIGHT_SQUARES an integer, but
+ * that is actually incidental; the value 2.5 below seems better than
+ * either HEIGHT_SQUARES=3 (a little long and skinny) or
+ * HEIGHT_SQUARES=2 (a bit short and stubby)
+ */
+
+#define HEIGHT_SQUARES 2.5
+
+static void
+get_total_matrix (PangoMatrix *total,
+ PangoMatrix *global,
+ int x,
+ int y,
+ int square)
+{
+ PangoMatrix local;
+ gdouble scale = 0.5 * square;
+
+ /* The local matrix translates from the axis aligned coordinate system
+ * to the original user space coordinate system.
+ */
+ local.xx = scale;
+ local.xy = - scale;
+ local.yx = scale;
+ local.yy = scale;
+ local.x0 = 0;
+ local.y0 = 0;
+
+ *total = *global;
+ pango_matrix_concat (total, &local);
+
+ total->x0 = (global->xx * x + global->xy * y) / PANGO_SCALE + global->x0;
+ total->y0 = (global->yx * x + global->yy * y) / PANGO_SCALE + global->y0;
+}
+
+void
+_pango_ft2_draw_error_underline (FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+
+ int square = height / HEIGHT_SQUARES;
+ int unit_width = (HEIGHT_SQUARES - 1) * square;
+ int width_units = (width + unit_width / 2) / unit_width;
+
+ x += (width - width_units * unit_width) / 2;
+ width = width_units * unit_width;
+
+ while (TRUE)
+ {
+ PangoMatrix total;
+ get_total_matrix (&total, matrix, x, y, square);
+
+ _pango_ft2_draw_rect (bitmap, &total, /* A */
+ 0, 0,
+ HEIGHT_SQUARES * 2 - 1, 1);
+
+ if (width_units > 2)
+ {
+ _pango_ft2_draw_rect (bitmap, &total,
+ HEIGHT_SQUARES * 2 - 2, - (HEIGHT_SQUARES * 2 - 3),
+ 1, HEIGHT_SQUARES * 2 - 3); /* B */
+ width_units -= 2;
+ x += unit_width * 2;
+ }
+ else if (width_units == 2)
+ {
+ _pango_ft2_draw_rect (bitmap, &total,
+ HEIGHT_SQUARES * 2 - 2, - (HEIGHT_SQUARES * 2 - 2),
+ 1, HEIGHT_SQUARES * 2 - 2); /* C */
+ break;
+ }
+ else
+ break;
+ }
+}
diff --git a/pango/pangoft2.c b/pango/pangoft2.c
index 4693a9f3..5de9ca7e 100644
--- a/pango/pangoft2.c
+++ b/pango/pangoft2.c
@@ -158,6 +158,25 @@ load_fallback_face (PangoFT2Font *ft2font,
FcPatternDestroy (matched);
}
+static void
+set_transform (PangoFT2Font *ft2font)
+{
+ PangoFcFont *fcfont = (PangoFcFont *)ft2font;
+ FcMatrix *fc_matrix;
+
+ if (FcPatternGetMatrix (fcfont->font_pattern, FC_MATRIX, 0, &fc_matrix) == FcResultMatch)
+ {
+ FT_Matrix ft_matrix;
+
+ ft_matrix.xx = 0x10000L * fc_matrix->xx;
+ ft_matrix.yy = 0x10000L * fc_matrix->yy;
+ ft_matrix.xy = 0x10000L * fc_matrix->xy;
+ ft_matrix.yx = 0x10000L * fc_matrix->yx;
+
+ FT_Set_Transform (ft2font->face, &ft_matrix, NULL);
+ }
+}
+
/**
* pango_ft2_font_get_face:
* @font: a #PangoFont
@@ -228,6 +247,8 @@ pango_ft2_font_get_face (PangoFont *font)
g_assert (ft2font->face);
+ set_transform (ft2font);
+
error = FT_Set_Char_Size (ft2font->face,
PANGO_PIXELS_26_6 (ft2font->size),
PANGO_PIXELS_26_6 (ft2font->size),
@@ -337,23 +358,45 @@ pango_ft2_font_render_glyph (PangoFont *font,
return rendered;
}
+static void
+transform_point (PangoMatrix *matrix,
+ int x,
+ int y,
+ int *x_out_pixels,
+ int *y_out_pixels)
+{
+ double x_out = (matrix->xx * x + matrix->xy * y) / PANGO_SCALE + matrix->x0;
+ double y_out = (matrix->yx * x + matrix->yy * y) / PANGO_SCALE + matrix->y0;
+
+ *x_out_pixels = floor (x_out + 0.5);
+ *y_out_pixels = floor (y_out + 0.5);
+}
/**
- * pango_ft2_render:
+ * pango_ft2_render_transformed:
* @bitmap: the FreeType2 bitmap onto which to draw the string
* @font: the font in which to draw the string
+ * @matrix: a #PangoMatrix, or %NULL to use an identity transformation
* @glyphs: the glyph string to draw
- * @x: the x position of the start of the string (in pixels)
- * @y: the y position of the baseline (in pixels)
+ * @x: the x position of the start of the string (in Pango
+ * units in user space coordinates)
+ * @y: the y position of the baseline (in Pango units
+ * in user space coordinates)
*
- * Renders a PangoGlyphString onto a FreeType2 bitmap.
+ * Renders a #PangoGlyphString onto a FreeType2 bitmap, possibly
+ * transforming the layed-out coordinates through a transformation
+ * matrix. Note that the transformation matrix for @font is not
+ * changed, so to produce correct rendering results, the @font
+ * must have been loaded using a #PangoContext with an identical
+ * transformation matrix to that passed in to this function.
**/
void
-pango_ft2_render (FT_Bitmap *bitmap,
- PangoFont *font,
- PangoGlyphString *glyphs,
- int x,
- int y)
+pango_ft2_render_transformed (FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ int x,
+ int y)
{
FT_UInt glyph_index;
int i;
@@ -384,9 +427,19 @@ pango_ft2_render (FT_Bitmap *bitmap,
rendered_glyph = pango_ft2_font_render_glyph (font, glyph_index);
add_glyph_to_cache = TRUE;
}
-
- ixoff = x + PANGO_PIXELS (x_position + gi->geometry.x_offset);
- iyoff = y + PANGO_PIXELS (gi->geometry.y_offset);
+
+ if (matrix)
+ {
+ transform_point (matrix,
+ x + x_position + gi->geometry.x_offset,
+ y + gi->geometry.y_offset,
+ &ixoff, &iyoff);
+ }
+ else
+ {
+ ixoff = PANGO_PIXELS (x + x_position + gi->geometry.x_offset);
+ iyoff = PANGO_PIXELS (y + gi->geometry.y_offset);
+ }
x_start = MAX (0, - (ixoff + rendered_glyph->bitmap_left));
x_limit = MIN (rendered_glyph->bitmap.width,
@@ -483,6 +536,26 @@ pango_ft2_render (FT_Bitmap *bitmap,
}
}
+/**
+ * pango_ft2_render:
+ * @bitmap: the FreeType2 bitmap onto which to draw the string
+ * @font: the font in which to draw the string
+ * @glyphs: the glyph string to draw
+ * @x: the x position of the start of the string (in pixels)
+ * @y: the y position of the baseline (in pixels)
+ *
+ * Renders a #PangoGlyphString onto a FreeType2 bitmap.
+ **/
+void
+pango_ft2_render (FT_Bitmap *bitmap,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ int x,
+ int y)
+{
+ pango_ft2_render_transformed (bitmap, NULL, font, glyphs, x * PANGO_SCALE, y * PANGO_SCALE);
+}
+
static FT_Glyph_Metrics *
pango_ft2_get_per_char (PangoFont *font,
guint32 glyph_index)
@@ -715,59 +788,113 @@ pango_ft2_get_unknown_glyph (PangoFont *font)
return 0;
}
-
static void
-pango_ft2_draw_hline (FT_Bitmap *bitmap,
- int y,
- int start,
- int end)
+draw_underline (FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ PangoFontMetrics *metrics,
+ PangoUnderline uline,
+ int x,
+ int width,
+ int base_y,
+ int descent)
{
- unsigned char *p;
- int ix;
+ int underline_thickness = pango_font_metrics_get_underline_thickness (metrics);
+ int underline_position = pango_font_metrics_get_underline_position (metrics);
+ int y_off = 0; /* Quiet GCC */
- if (y < 0 || y >= bitmap->rows)
- return;
+ switch (uline)
+ {
+ case PANGO_UNDERLINE_NONE:
+ g_assert_not_reached();
+ break;
+ case PANGO_UNDERLINE_SINGLE:
+ y_off = - underline_position;
+ break;
+ case PANGO_UNDERLINE_DOUBLE:
+ y_off = - underline_position;
+ break;
+ case PANGO_UNDERLINE_LOW:
+ y_off = underline_thickness + descent;
+ break;
+ case PANGO_UNDERLINE_ERROR:
+ {
+ _pango_ft2_draw_error_underline (bitmap, matrix,
+ x,
+ base_y - underline_position,
+ width,
+ 3 * underline_thickness);
+ return;
+ }
+ }
- if (end <= 0 || start >= bitmap->width)
- return;
-
- if (start < 0)
- start = 0;
+ _pango_ft2_draw_rect (bitmap, matrix,
+ x,
+ base_y + y_off,
+ width,
+ underline_thickness);
- if (end >= bitmap->width)
- end = bitmap->width;
+ if (uline == PANGO_UNDERLINE_DOUBLE)
+ {
+ y_off += 2 * underline_thickness;
+
+ _pango_ft2_draw_rect (bitmap, matrix,
+ x,
+ base_y + y_off,
+ width,
+ underline_thickness);
+ }
+}
- p = bitmap->buffer + y * bitmap->pitch + start;
-
- for (ix = 0; ix < end - start; ix++)
- *p++ = 0xff;
+static void
+draw_strikethrough (FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ PangoFontMetrics *metrics,
+ int x,
+ int width,
+ int base_y)
+{
+ int strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness (metrics);
+ int strikethrough_position = pango_font_metrics_get_strikethrough_position (metrics);
+
+ _pango_ft2_draw_rect (bitmap, matrix,
+ x,
+ base_y - strikethrough_position,
+ width,
+ strikethrough_thickness);
}
/**
- * pango_ft2_render_layout_line:
+ * pango_ft2_render_layout_line_subpixel:
* @bitmap: a FT_Bitmap to render the line onto
* @line: a #PangoLayoutLine
- * @x: the x position of start of string (in pixels)
- * @y: the y position of baseline (in pixels)
+ * @x: the x position of start of string (in pango units)
+ * @y: the y position of baseline (in pango units)
*
- * Render a #PangoLayoutLine onto a FreeType2 bitmap
+ * Render a #PangoLayoutLine onto a FreeType2 bitmap, with he
+ * location specified in fixed-point pango units rather than
+ * pixels. (Using this will avoid extra inaccuracies from
+ * rounding to integer pixels multiple times, even if the
+ * final glyph positions are integers.)
*/
void
-pango_ft2_render_layout_line (FT_Bitmap *bitmap,
- PangoLayoutLine *line,
- int x,
- int y)
+pango_ft2_render_layout_line_subpixel (FT_Bitmap *bitmap,
+ PangoLayoutLine *line,
+ int x,
+ int y)
{
GSList *tmp_list = line->runs;
PangoRectangle logical_rect;
PangoRectangle ink_rect;
int x_off = 0;
+ PangoMatrix *matrix;
+
+ matrix = pango_context_get_matrix (pango_layout_get_context (line->layout));
while (tmp_list)
{
PangoUnderline uline = PANGO_UNDERLINE_NONE;
gboolean strike, shape_set;
- gint rise, risen_y;
+ gint rise;
PangoLayoutRun *run = tmp_list->data;
tmp_list = tmp_list->next;
@@ -776,92 +903,84 @@ pango_ft2_render_layout_line (FT_Bitmap *bitmap,
&uline, &strike, &rise,
&shape_set, &ink_rect, &logical_rect);
- risen_y = y - PANGO_PIXELS (rise);
-
if (!shape_set)
{
- if (uline == PANGO_UNDERLINE_NONE)
+ if (uline == PANGO_UNDERLINE_NONE && !strike)
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
NULL, &logical_rect);
else
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
&ink_rect, &logical_rect);
+
+ pango_ft2_render_transformed (bitmap, matrix,
+ run->item->analysis.font, run->glyphs,
+ x + x_off, y - rise);
- pango_ft2_render (bitmap, run->item->analysis.font, run->glyphs,
- x + PANGO_PIXELS (x_off), risen_y);
- }
+ if (uline != PANGO_UNDERLINE_NONE || strike)
+ {
+ PangoFontMetrics *metrics = pango_font_get_metrics (run->item->analysis.font,
+ run->item->analysis.language);
+
+ if (uline != PANGO_UNDERLINE_NONE)
+ draw_underline (bitmap, matrix, metrics,
+ uline,
+ x_off + ink_rect.x,
+ ink_rect.width,
+ y - rise,
+ ink_rect.y + ink_rect.height);
+
+ if (strike)
+ draw_strikethrough (bitmap, matrix, metrics,
+ x_off + ink_rect.x,
+ ink_rect.width,
+ y - rise);
- switch (uline)
- {
- case PANGO_UNDERLINE_NONE:
- break;
- case PANGO_UNDERLINE_DOUBLE:
- pango_ft2_draw_hline (bitmap,
- risen_y + 4,
- x + PANGO_PIXELS (x_off + ink_rect.x),
- x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
- /* Fall through */
- case PANGO_UNDERLINE_SINGLE:
- pango_ft2_draw_hline (bitmap,
- risen_y + 2,
- x + PANGO_PIXELS (x_off + ink_rect.x),
- x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
- break;
- case PANGO_UNDERLINE_ERROR:
- {
- int point_x;
- int counter = 0;
- int end_x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
-
- for (point_x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
- point_x <= end_x;
- point_x += 2)
- {
- if (counter)
- pango_ft2_draw_hline (bitmap,
- risen_y + 2,
- point_x, MIN (point_x + 1, end_x));
- else
- pango_ft2_draw_hline (bitmap,
- risen_y + 3,
- point_x, MIN (point_x + 1, end_x));
-
- counter = (counter + 1) % 2;
- }
- }
- break;
- case PANGO_UNDERLINE_LOW:
- pango_ft2_draw_hline (bitmap,
- risen_y + PANGO_PIXELS (ink_rect.y + ink_rect.height),
- x + PANGO_PIXELS (x_off + ink_rect.x),
- x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
- break;
+ pango_font_metrics_unref (metrics);
+ }
}
- if (strike)
- pango_ft2_draw_hline (bitmap,
- risen_y + PANGO_PIXELS (logical_rect.y + logical_rect.height / 2),
- x + PANGO_PIXELS (x_off + logical_rect.x),
- x + PANGO_PIXELS (x_off + logical_rect.x + logical_rect.width));
-
x_off += logical_rect.width;
}
}
+
/**
- * pango_ft2_render_layout:
+ * pango_ft2_render_layout_line:
+ * @bitmap: a FT_Bitmap to render the line onto
+ * @line: a #PangoLayoutLine
+ * @x: the x position of start of string (in pixels)
+ * @y: the y position of baseline (in pixels)
+ *
+ * Render a #PangoLayoutLine onto a FreeType2 bitmap
+ */
+void
+pango_ft2_render_layout_line (FT_Bitmap *bitmap,
+ PangoLayoutLine *line,
+ int x,
+ int y)
+{
+ pango_ft2_render_layout_line_subpixel (bitmap, line, x * PANGO_SCALE, y * PANGO_SCALE);
+}
+
+
+/**
+ * pango_ft2_render_layout_subpixel:
* @bitmap: a FT_Bitmap to render the layout onto
* @layout: a #PangoLayout
- * @x: the X position of the left of the layout (in pixels)
- * @y: the Y position of the top of the layout (in pixels)
+ * @x: the X position of the left of the layout (in Pango units)
+ * @y: the Y position of the top of the layout (in Pango units)
*
- * Render a #PangoLayout onto a FreeType2 bitmap
+ * Render a #PangoLayout onto a FreeType2 bitmap, with he
+ * location specified in fixed-point pango units rather than
+ * pixels. (Using this will avoid extra inaccuracies from
+ * rounding to integer pixels multiple times, even if the
+ * final glyph positions are integers.)
*/
void
-pango_ft2_render_layout (FT_Bitmap *bitmap,
- PangoLayout *layout,
- int x,
- int y)
+pango_ft2_render_layout_subpixel (FT_Bitmap *bitmap,
+ PangoLayout *layout,
+ int x,
+ int y)
{
PangoLayoutIter *iter;
@@ -880,17 +999,35 @@ pango_ft2_render_layout (FT_Bitmap *bitmap,
pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
baseline = pango_layout_iter_get_baseline (iter);
-
- pango_ft2_render_layout_line (bitmap,
- line,
- x + PANGO_PIXELS (logical_rect.x),
- y + PANGO_PIXELS (baseline));
+
+ pango_ft2_render_layout_line_subpixel (bitmap,
+ line,
+ x + logical_rect.x,
+ y + baseline);
}
while (pango_layout_iter_next_line (iter));
pango_layout_iter_free (iter);
}
+/**
+ * pango_ft2_render_layout:
+ * @bitmap: a FT_Bitmap to render the layout onto
+ * @layout: a #PangoLayout
+ * @x: the X position of the left of the layout (in pixels)
+ * @y: the Y position of the top of the layout (in pixels)
+ *
+ * Render a #PangoLayout onto a FreeType2 bitmap
+ */
+void
+pango_ft2_render_layout (FT_Bitmap *bitmap,
+ PangoLayout *layout,
+ int x,
+ int y)
+{
+ pango_ft2_render_layout_subpixel (bitmap, layout, x * PANGO_SCALE, y * PANGO_SCALE);
+}
+
/* This utility function is duplicated here and in pango-layout.c; should it be
* public? Trouble is - what is the appropriate set of properties?
*/
diff --git a/pango/pangoft2.h b/pango/pangoft2.h
index e8ba820f..16386c6d 100644
--- a/pango/pangoft2.h
+++ b/pango/pangoft2.h
@@ -45,20 +45,33 @@ typedef void (*PangoFT2SubstituteFunc) (FcPattern *pattern,
/* Calls for applications */
-
-void pango_ft2_render (FT_Bitmap *bitmap,
- PangoFont *font,
- PangoGlyphString *glyphs,
- gint x,
- gint y);
-void pango_ft2_render_layout_line (FT_Bitmap *bitmap,
- PangoLayoutLine *line,
- int x,
- int y);
-void pango_ft2_render_layout (FT_Bitmap *bitmap,
- PangoLayout *layout,
- int x,
- int y);
+void pango_ft2_render (FT_Bitmap *bitmap,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ gint x,
+ gint y);
+void pango_ft2_render_transformed (FT_Bitmap *bitmap,
+ PangoMatrix *matrix,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ int x,
+ int y);
+void pango_ft2_render_layout_line (FT_Bitmap *bitmap,
+ PangoLayoutLine *line,
+ int x,
+ int y);
+void pango_ft2_render_layout_line_subpixel (FT_Bitmap *bitmap,
+ PangoLayoutLine *line,
+ int x,
+ int y);
+void pango_ft2_render_layout (FT_Bitmap *bitmap,
+ PangoLayout *layout,
+ int x,
+ int y);
+void pango_ft2_render_layout_subpixel (FT_Bitmap *bitmap,
+ PangoLayout *layout,
+ int x,
+ int y);
GType pango_ft2_font_map_get_type (void);