summaryrefslogtreecommitdiff
path: root/pango/pango-matrix.c
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@gnome.org>2007-01-04 19:35:56 +0000
committerBehdad Esfahbod <behdad@src.gnome.org>2007-01-04 19:35:56 +0000
commit143def0d70b166251c5971eabb61c901343502c9 (patch)
treec1402594c509e908efcc7225710af3e53a66fd21 /pango/pango-matrix.c
parentcbf5f1e8a747ce6b9d6a0b03a7febd6c6c55b0ca (diff)
downloadpango-143def0d70b166251c5971eabb61c901343502c9.tar.gz
Part of Bug 332266 – gdk_draw_layout fails for coordinates >= 2^21
2007-01-04 Behdad Esfahbod <behdad@gnome.org> Part of Bug 332266 – gdk_draw_layout fails for coordinates >= 2^21 * pango/pango-types.h: * pango/pango-matrix.c: New public API: pango_matrix_transform_distance() pango_matrix_transform_point() pango_matrix_transform_rectangle() pango_matrix_transform_pixel_rectangle() * pango/pango-utils.h: * pango/pango-utils.c: New public API: pango_units_from_double() pango_units_to_double() pango_extents_to_pixels() * pango/pango-layout.c (pango_layout_get_pixel_extents), (pango_layout_line_get_pixel_extents): Use pango_extents_to_pixels(). * pango/pangocairo-fcfont.c: (pango_cairo_fc_font_glyph_extents_cache_init), (compute_glyph_extents): Use pango_units_from_double(). * examples/renderdemo.c (do_output): Use pango_matrix_transform_pixel_rectangle(); * pango/pango.def: * docs/pango-sections.txt: * docs/tmpl/glyphs.sgml: Update. svn path=/trunk/; revision=2126
Diffstat (limited to 'pango/pango-matrix.c')
-rw-r--r--pango/pango-matrix.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/pango/pango-matrix.c b/pango/pango-matrix.c
index e63ecab1..49c05f0b 100644
--- a/pango/pango-matrix.c
+++ b/pango/pango-matrix.c
@@ -282,3 +282,219 @@ pango_matrix_to_gravity (const PangoMatrix *matrix)
return gravity;
}
+
+/**
+ * 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 the @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 the 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 afterwards
+ * using pango_extents_to_pixels() as the 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;
+}