diff options
author | Behdad Esfahbod <behdad@gnome.org> | 2007-01-04 19:35:56 +0000 |
---|---|---|
committer | Behdad Esfahbod <behdad@src.gnome.org> | 2007-01-04 19:35:56 +0000 |
commit | 143def0d70b166251c5971eabb61c901343502c9 (patch) | |
tree | c1402594c509e908efcc7225710af3e53a66fd21 /pango/pango-matrix.c | |
parent | cbf5f1e8a747ce6b9d6a0b03a7febd6c6c55b0ca (diff) | |
download | pango-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.c | 216 |
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; +} |