2 * pango-matrix.c: Matrix manipulation routines
4 * Copyright (C) 2000, 2006 Red Hat Software
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
26 #include "pango-matrix.h"
27 #include "pango-impl-utils.h"
30 pango_matrix_get_type (void)
32 static GType our_type = 0;
34 if (G_UNLIKELY (our_type == 0))
35 our_type = g_boxed_type_register_static (I_("PangoMatrix"),
36 (GBoxedCopyFunc) pango_matrix_copy,
37 (GBoxedFreeFunc) pango_matrix_free);
44 * @matrix: a #PangoMatrix, may be %NULL
46 * Copies a #PangoMatrix.
48 * Return value: the newly allocated #PangoMatrix, which should
49 * be freed with pango_matrix_free(), or %NULL if
55 pango_matrix_copy (const PangoMatrix *matrix)
57 PangoMatrix *new_matrix;
62 new_matrix = g_slice_new (PangoMatrix);
64 *new_matrix = *matrix;
71 * @matrix: a #PangoMatrix, may be %NULL
73 * Free a #PangoMatrix created with pango_matrix_copy().
78 pango_matrix_free (PangoMatrix *matrix)
83 g_slice_free (PangoMatrix, matrix);
87 * pango_matrix_translate:
88 * @matrix: a #PangoMatrix
89 * @tx: amount to translate in the X direction
90 * @ty: amount to translate in the Y direction
92 * Changes the transformation represented by @matrix to be the
93 * transformation given by first translating by (@tx, @ty)
94 * then applying the original transformation.
99 pango_matrix_translate (PangoMatrix *matrix,
103 g_return_if_fail (matrix != NULL);
105 matrix->x0 = matrix->xx * tx + matrix->xy * ty + matrix->x0;
106 matrix->y0 = matrix->yx * tx + matrix->yy * ty + matrix->y0;
110 * pango_matrix_scale:
111 * @matrix: a #PangoMatrix
112 * @scale_x: amount to scale by in X direction
113 * @scale_y: amount to scale by in Y direction
115 * Changes the transformation represented by @matrix to be the
116 * transformation given by first scaling by @sx in the X direction
117 * and @sy in the Y direction then applying the original
123 pango_matrix_scale (PangoMatrix *matrix,
127 g_return_if_fail (matrix != NULL);
129 matrix->xx *= scale_x;
130 matrix->xy *= scale_y;
131 matrix->yx *= scale_x;
132 matrix->yy *= scale_y;
136 * pango_matrix_rotate:
137 * @matrix: a #PangoMatrix
138 * @degrees: degrees to rotate counter-clockwise
140 * Changes the transformation represented by @matrix to be the
141 * transformation given by first rotating by @degrees degrees
142 * counter-clockwise then applying the original transformation.
147 pango_matrix_rotate (PangoMatrix *matrix,
153 g_return_if_fail (matrix != NULL);
155 r = degrees * (G_PI / 180.);
166 pango_matrix_concat (matrix, &tmp);
170 * pango_matrix_concat:
171 * @matrix: a #PangoMatrix
172 * @new_matrix: a #PangoMatrix
174 * Changes the transformation represented by @matrix to be the
175 * transformation given by first applying transformation
176 * given by @new_matrix then applying the original transformation.
181 pango_matrix_concat (PangoMatrix *matrix,
182 const PangoMatrix *new_matrix)
186 g_return_if_fail (matrix != NULL);
190 matrix->xx = tmp.xx * new_matrix->xx + tmp.xy * new_matrix->yx;
191 matrix->xy = tmp.xx * new_matrix->xy + tmp.xy * new_matrix->yy;
192 matrix->yx = tmp.yx * new_matrix->xx + tmp.yy * new_matrix->yx;
193 matrix->yy = tmp.yx * new_matrix->xy + tmp.yy * new_matrix->yy;
194 matrix->x0 = tmp.xx * new_matrix->x0 + tmp.xy * new_matrix->y0 + tmp.x0;
195 matrix->y0 = tmp.yx * new_matrix->x0 + tmp.yy * new_matrix->y0 + tmp.y0;
199 * pango_matrix_get_font_scale_factor:
200 * @matrix: a #PangoMatrix, may be %NULL
202 * Returns the scale factor of a matrix on the height of the font.
203 * That is, the scale factor in the direction perpendicular to the
204 * vector that the X coordinate is mapped to.
206 * Return value: the scale factor of @matrix on the height of the font,
207 * or 1.0 if @matrix is %NULL.
212 pango_matrix_get_font_scale_factor (const PangoMatrix *matrix)
215 * Based on cairo-matrix.c:_cairo_matrix_compute_scale_factors()
217 * Copyright 2005, Keith Packard
224 det = matrix->xx * matrix->yy - matrix->yx * matrix->xy;
232 double x = matrix->xx;
233 double y = matrix->yx;
236 major = sqrt (x*x + y*y);
254 * pango_matrix_transform_distance:
255 * @matrix: a #PangoMatrix, or %NULL
256 * @dx: in/out X component of a distance vector
257 * @dy: yn/out Y component of a distance vector
259 * Transforms the distance vector (@dx,@dy) by @matrix. This is
260 * similar to pango_matrix_transform_point() except that the translation
261 * components of the transformation are ignored. The calculation of
262 * the returned vector is as follows:
265 * dx2 = dx1 * xx + dy1 * xy;
266 * dy2 = dx1 * yx + dy1 * yy;
269 * Affine transformations are position invariant, so the same vector
270 * always transforms to the same vector. If (@x1,@y1) transforms
271 * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
272 * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
277 pango_matrix_transform_distance (const PangoMatrix *matrix,
285 new_x = (matrix->xx * *dx + matrix->xy * *dy);
286 new_y = (matrix->yx * *dx + matrix->yy * *dy);
294 * pango_matrix_transform_point:
295 * @matrix: a #PangoMatrix, or %NULL
296 * @x: in/out X position
297 * @y: in/out Y position
299 * Transforms the point (@x, @y) by @matrix.
304 pango_matrix_transform_point (const PangoMatrix *matrix,
310 pango_matrix_transform_distance (matrix, x, y);
318 * pango_matrix_transform_rectangle:
319 * @matrix: a #PangoMatrix, or %NULL
320 * @rect: in/out bounding box in Pango units, or %NULL
322 * First transforms @rect using @matrix, then calculates the bounding box
323 * of the transformed rectangle. The rectangle should be in Pango units.
325 * This function is useful for example when you want to draw a rotated
326 * @PangoLayout to an image buffer, and want to know how large the image
327 * should be and how much you should shift the layout when rendering.
329 * If you have a rectangle in device units (pixels), use
330 * pango_matrix_transform_pixel_rectangle().
332 * If you have the rectangle in Pango units and want to convert to
333 * transformed pixel bounding box, it is more accurate to transform it first
334 * (using this function) and pass the result to pango_extents_to_pixels(),
335 * first argument, for an inclusive rounded rectangle.
336 * However, there are valid reasons that you may want to convert
337 * to pixels first and then transform, for example when the transformed
338 * coordinates may overflow in Pango units (large matrix translation for
344 pango_matrix_transform_rectangle (const PangoMatrix *matrix,
345 PangoRectangle *rect)
348 double quad_x[4], quad_y[4];
354 if (!rect || !matrix)
357 quad_x[0] = pango_units_to_double (rect->x);
358 quad_y[0] = pango_units_to_double (rect->y);
359 pango_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
361 dx1 = pango_units_to_double (rect->width);
363 pango_matrix_transform_distance (matrix, &dx1, &dy1);
364 quad_x[1] = quad_x[0] + dx1;
365 quad_y[1] = quad_y[0] + dy1;
368 dy2 = pango_units_to_double (rect->height);
369 pango_matrix_transform_distance (matrix, &dx2, &dy2);
370 quad_x[2] = quad_x[0] + dx2;
371 quad_y[2] = quad_y[0] + dy2;
373 quad_x[3] = quad_x[0] + dx1 + dx2;
374 quad_y[3] = quad_y[0] + dy1 + dy2;
376 min_x = max_x = quad_x[0];
377 min_y = max_y = quad_y[0];
379 for (i=1; i < 4; i++) {
380 if (quad_x[i] < min_x)
382 else if (quad_x[i] > max_x)
385 if (quad_y[i] < min_y)
387 else if (quad_y[i] > max_y)
391 rect->x = pango_units_from_double (min_x);
392 rect->y = pango_units_from_double (min_y);
393 rect->width = pango_units_from_double (max_x) - rect->x;
394 rect->height = pango_units_from_double (max_y) - rect->y;
398 * pango_matrix_transform_pixel_rectangle:
399 * @matrix: a #PangoMatrix, or %NULL
400 * @rect: in/out bounding box in device units, or %NULL
402 * First transforms the @rect using @matrix, then calculates the bounding box
403 * of the transformed rectangle. The rectangle should be in device units
406 * This function is useful for example when you want to draw a rotated
407 * @PangoLayout to an image buffer, and want to know how large the image
408 * should be and how much you should shift the layout when rendering.
410 * For better accuracy, you should use pango_matrix_transform_rectangle() on
411 * original rectangle in Pango units and convert to pixels afterward
412 * using pango_extents_to_pixels()'s first argument.
417 pango_matrix_transform_pixel_rectangle (const PangoMatrix *matrix,
418 PangoRectangle *rect)
421 double quad_x[4], quad_y[4];
427 if (!rect || !matrix)
432 pango_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
436 pango_matrix_transform_distance (matrix, &dx1, &dy1);
437 quad_x[1] = quad_x[0] + dx1;
438 quad_y[1] = quad_y[0] + dy1;
442 pango_matrix_transform_distance (matrix, &dx2, &dy2);
443 quad_x[2] = quad_x[0] + dx2;
444 quad_y[2] = quad_y[0] + dy2;
446 quad_x[3] = quad_x[0] + dx1 + dx2;
447 quad_y[3] = quad_y[0] + dy1 + dy2;
449 min_x = max_x = quad_x[0];
450 min_y = max_y = quad_y[0];
452 for (i=1; i < 4; i++) {
453 if (quad_x[i] < min_x)
455 else if (quad_x[i] > max_x)
458 if (quad_y[i] < min_y)
460 else if (quad_y[i] > max_y)
464 rect->x = floor (min_x);
465 rect->y = floor (min_y);
466 rect->width = ceil (max_x - rect->x);
467 rect->height = ceil (max_y - rect->y);