summaryrefslogtreecommitdiff
path: root/trunk/pango/pango-matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/pango/pango-matrix.c')
-rw-r--r--trunk/pango/pango-matrix.c467
1 files changed, 467 insertions, 0 deletions
diff --git a/trunk/pango/pango-matrix.c b/trunk/pango/pango-matrix.c
new file mode 100644
index 00000000..828d4f90
--- /dev/null
+++ b/trunk/pango/pango-matrix.c
@@ -0,0 +1,467 @@
+/* Pango
+ * pango-matrix.c: Matrix manipulation routines
+ *
+ * Copyright (C) 2000, 2006 Red Hat Software
+ *
+ * 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 <config.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "pango-matrix.h"
+#include "pango-impl-utils.h"
+
+GType
+pango_matrix_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (G_UNLIKELY (our_type == 0))
+ our_type = g_boxed_type_register_static (I_("PangoMatrix"),
+ (GBoxedCopyFunc) pango_matrix_copy,
+ (GBoxedFreeFunc) pango_matrix_free);
+
+ return our_type;
+}
+
+/**
+ * pango_matrix_copy:
+ * @matrix: a #PangoMatrix, can be %NULL
+ *
+ * Copies a #PangoMatrix.
+ *
+ * Return value: the newly allocated #PangoMatrix, which should
+ * be freed with pango_matrix_free(), or %NULL if
+ * @matrix was %NULL.
+ *
+ * Since: 1.6
+ **/
+PangoMatrix *
+pango_matrix_copy (const PangoMatrix *matrix)
+{
+ PangoMatrix *new_matrix;
+
+ if (matrix)
+ {
+ new_matrix = g_slice_new (PangoMatrix);
+ *new_matrix = *matrix;
+ }
+ else
+ new_matrix = NULL;
+
+ return new_matrix;
+}
+
+/**
+ * pango_matrix_free:
+ * @matrix: a #PangoMatrix, or %NULL
+ *
+ * Free a #PangoMatrix created with pango_matrix_copy().
+ * Does nothing if @matrix is %NULL.
+ *
+ * Since: 1.6
+ **/
+void
+pango_matrix_free (PangoMatrix *matrix)
+{
+ if (matrix)
+ g_slice_free (PangoMatrix, 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.
+ *
+ * Since: 1.6
+ **/
+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.
+ *
+ * Since: 1.6
+ **/
+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-clockwise then applying the original transformation.
+ *
+ * Since: 1.6
+ **/
+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_matrix: a #PangoMatrix
+ *
+ * Changes the transformation represented by @matrix to be the
+ * transformation given by first applying transformation
+ * given by @new_matrix then applying the original transformation.
+ *
+ * Since: 1.6
+ **/
+void
+pango_matrix_concat (PangoMatrix *matrix,
+ const PangoMatrix *new_matrix)
+{
+ PangoMatrix tmp;
+
+ g_return_if_fail (matrix != NULL);
+
+ tmp = *matrix;
+
+ matrix->xx = tmp.xx * new_matrix->xx + tmp.xy * new_matrix->yx;
+ matrix->xy = tmp.xx * new_matrix->xy + tmp.xy * new_matrix->yy;
+ matrix->yx = tmp.yx * new_matrix->xx + tmp.yy * new_matrix->yx;
+ matrix->yy = tmp.yx * new_matrix->xy + tmp.yy * new_matrix->yy;
+ matrix->x0 = tmp.xx * new_matrix->x0 + tmp.xy * new_matrix->y0 + tmp.x0;
+ matrix->y0 = tmp.yx * new_matrix->y0 + tmp.yy * new_matrix->y0 + tmp.y0;
+}
+
+/**
+ * pango_matrix_get_font_scale_factor:
+ * @matrix: a #PangoMatrix, may be %NULL
+ *
+ * Returns the scale factor of a matrix on the height of the font.
+ * That is, the scale factor in the direction perpendicular to the
+ * vector that the X coordinate is mapped to.
+ *
+ * Return value: the scale factor of @matrix on the height of the font,
+ * or 1.0 if @matrix is %NULL.
+ *
+ * Since: 1.12
+ **/
+double
+pango_matrix_get_font_scale_factor (const PangoMatrix *matrix)
+{
+/*
+ * Based on cairo-matrix.c:_cairo_matrix_compute_scale_factors()
+ *
+ * Copyright 2005, Keith Packard
+ */
+ double det;
+
+ if (!matrix)
+ return 1.0;
+
+ det = matrix->xx * matrix->yy - matrix->yx * matrix->xy;
+
+ if (det == 0)
+ {
+ return 0.0;
+ }
+ else
+ {
+ double x = matrix->xx;
+ double y = matrix->yx;
+ double major, minor;
+
+ major = sqrt (x*x + y*y);
+
+ /*
+ * ignore mirroring
+ */
+ if (det < 0)
+ det = - det;
+
+ if (major)
+ minor = det / major;
+ else
+ minor = 0.0;
+
+ return minor;
+ }
+}
+
+/**
+ * pango_matrix_transform_distance:
+ * @matrix: a #PangoMatrix, or %NULL
+ * @dx: in/out X component of a distance vector
+ * @dy: yn/out Y component of a distance vector
+ *
+ * Transforms the distance vector (@dx,@dy) by @matrix. This is
+ * similar to pango_matrix_transform_point() except that the translation
+ * components of the transformation are ignored. The calculation of
+ * the returned vector is as follows:
+ *
+ * <programlisting>
+ * dx2 = dx1 * xx + dy1 * xy;
+ * dy2 = dx1 * yx + dy1 * yy;
+ * </programlisting>
+ *
+ * Affine transformations are position invariant, so the same vector
+ * always transforms to the same vector. If (@x1,@y1) transforms
+ * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
+ * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
+ *
+ * Since: 1.16
+ **/
+void
+pango_matrix_transform_distance (const PangoMatrix *matrix,
+ double *dx,
+ double *dy)
+{
+ if (matrix)
+ {
+ double new_x, new_y;
+
+ new_x = (matrix->xx * *dx + matrix->xy * *dy);
+ new_y = (matrix->yx * *dx + matrix->yy * *dy);
+
+ *dx = new_x;
+ *dy = new_y;
+ }
+}
+
+/**
+ * pango_matrix_transform_point:
+ * @matrix: a #PangoMatrix, or %NULL
+ * @x: in/out X position
+ * @y: in/out Y position
+ *
+ * Transforms the point (@x, @y) by @matrix.
+ *
+ * Since: 1.16
+ **/
+void
+pango_matrix_transform_point (const PangoMatrix *matrix,
+ double *x,
+ double *y)
+{
+ if (matrix)
+ {
+ pango_matrix_transform_distance (matrix, x, y);
+
+ *x += matrix->x0;
+ *y += matrix->y0;
+ }
+}
+
+/**
+ * pango_matrix_transform_rectangle:
+ * @matrix: a #PangoMatrix, or %NULL
+ * @rect: in/out bounding box in Pango units, or %NULL
+ *
+ * First transforms @rect using @matrix, then calculates the bounding box
+ * of the transformed rectangle. The rectangle should be in Pango units.
+ *
+ * This function is useful for example when you want to draw a rotated
+ * @PangoLayout to an image buffer, and want to know how large the image
+ * should be and how much you should shift the layout when rendering.
+ *
+ * If you have a rectangle in device units (pixels), use
+ * pango_matrix_transform_pixel_rectangle().
+ *
+ * If you have the rectangle in Pango units and want to convert to
+ * transformed pixel bounding box, it is more accurate to transform it first
+ * (using this function) and pass the result to pango_extents_to_pixels(),
+ * as @ink_rect. However, there is a reason that you may want to convert
+ * to pixels first and then transform, and that is when the transformed
+ * coordinates may overflow in Pango units (large matrix translation for
+ * example).
+ *
+ * Since: 1.16
+ **/
+void
+pango_matrix_transform_rectangle (const PangoMatrix *matrix,
+ PangoRectangle *rect)
+{
+ int i;
+ double quad_x[4], quad_y[4];
+ double dx1, dy1;
+ double dx2, dy2;
+ double min_x, max_x;
+ double min_y, max_y;
+
+ if (!rect || !matrix)
+ return;
+
+ quad_x[0] = pango_units_to_double (rect->x);
+ quad_y[0] = pango_units_to_double (rect->y);
+ pango_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
+
+ dx1 = pango_units_to_double (rect->width);
+ dy1 = 0;
+ pango_matrix_transform_distance (matrix, &dx1, &dy1);
+ quad_x[1] = quad_x[0] + dx1;
+ quad_y[1] = quad_y[0] + dy1;
+
+ dx2 = 0;
+ dy2 = pango_units_to_double (rect->height);
+ pango_matrix_transform_distance (matrix, &dx2, &dy2);
+ quad_x[2] = quad_x[0] + dx2;
+ quad_y[2] = quad_y[0] + dy2;
+
+ quad_x[3] = quad_x[0] + dx1 + dx2;
+ quad_y[3] = quad_y[0] + dy1 + dy2;
+
+ min_x = max_x = quad_x[0];
+ min_y = max_y = quad_y[0];
+
+ for (i=1; i < 4; i++) {
+ if (quad_x[i] < min_x)
+ min_x = quad_x[i];
+ else if (quad_x[i] > max_x)
+ max_x = quad_x[i];
+
+ if (quad_y[i] < min_y)
+ min_y = quad_y[i];
+ else if (quad_y[i] > max_y)
+ max_y = quad_y[i];
+ }
+
+ rect->x = pango_units_from_double (min_x);
+ rect->y = pango_units_from_double (min_y);
+ rect->width = pango_units_from_double (max_x) - rect->x;
+ rect->height = pango_units_from_double (max_y) - rect->y;
+}
+
+/**
+ * pango_matrix_transform_pixel_rectangle:
+ * @matrix: a #PangoMatrix, or %NULL
+ * @rect: in/out bounding box in device units, or %NULL
+ *
+ * First transforms the @rect using @matrix, then calculates the bounding box
+ * of the transformed rectangle. The rectangle should be in device units
+ * (pixels).
+ *
+ * This function is useful for example when you want to draw a rotated
+ * @PangoLayout to an image buffer, and want to know how large the image
+ * should be and how much you should shift the layout when rendering.
+ *
+ * For better accuracy, you should use pango_matrix_transform_rectangle() on
+ * original rectangle in Pango units and convert to pixels afterward
+ * using pango_extents_to_pixels() as @ink_rect.
+ *
+ * Since: 1.16
+ **/
+void
+pango_matrix_transform_pixel_rectangle (const PangoMatrix *matrix,
+ PangoRectangle *rect)
+{
+ int i;
+ double quad_x[4], quad_y[4];
+ double dx1, dy1;
+ double dx2, dy2;
+ double min_x, max_x;
+ double min_y, max_y;
+
+ if (!rect || !matrix)
+ return;
+
+ quad_x[0] = rect->x;
+ quad_y[0] = rect->y;
+ pango_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
+
+ dx1 = rect->width;
+ dy1 = 0;
+ pango_matrix_transform_distance (matrix, &dx1, &dy1);
+ quad_x[1] = quad_x[0] + dx1;
+ quad_y[1] = quad_y[0] + dy1;
+
+ dx2 = 0;
+ dy2 = rect->height;
+ pango_matrix_transform_distance (matrix, &dx2, &dy2);
+ quad_x[2] = quad_x[0] + dx2;
+ quad_y[2] = quad_y[0] + dy2;
+
+ quad_x[3] = quad_x[0] + dx1 + dx2;
+ quad_y[3] = quad_y[0] + dy1 + dy2;
+
+ min_x = max_x = quad_x[0];
+ min_y = max_y = quad_y[0];
+
+ for (i=1; i < 4; i++) {
+ if (quad_x[i] < min_x)
+ min_x = quad_x[i];
+ else if (quad_x[i] > max_x)
+ max_x = quad_x[i];
+
+ if (quad_y[i] < min_y)
+ min_y = quad_y[i];
+ else if (quad_y[i] > max_y)
+ max_y = quad_y[i];
+ }
+
+ rect->x = min_x;
+ rect->y = min_y;
+ rect->width = max_x - rect->x;
+ rect->height = max_y - rect->y;
+}