зеркало из https://github.com/mozilla/pjs.git
Bug 288498 - Prevent SVG DOS with dasharray
This commit is contained in:
Родитель
84a42982ba
Коммит
79a8633670
|
@ -19,3 +19,5 @@ PATCHES:
|
|||
xlib.diff - include X11/xlib.h in cairo-xlib.h - needed for Solaris.
|
||||
|
||||
stroke-extent.diff - fix calculation of stroke extents.
|
||||
|
||||
dash-dos.diff - prevent DOS attack with dasharray.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,645 +0,0 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2002 University of Southern California
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it either under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation
|
||||
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
||||
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
||||
* notice, a recipient may use your version of this file under either
|
||||
* the MPL or the LGPL.
|
||||
*
|
||||
* You should have received a copy of the LGPL along with this library
|
||||
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* You should have received a copy of the MPL along with this library
|
||||
* in the file COPYING-MPL-1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
||||
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
||||
* the specific language governing rights and limitations.
|
||||
*
|
||||
* The Original Code is the cairo graphics library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is University of Southern
|
||||
* California.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Carl D. Worth <cworth@cworth.org>
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_matrix_t const CAIRO_MATRIX_IDENTITY = {
|
||||
{
|
||||
{1, 0},
|
||||
{0, 1},
|
||||
{0, 0}
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
|
||||
|
||||
static void
|
||||
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
|
||||
|
||||
/**
|
||||
* cairo_matrix_create:
|
||||
*
|
||||
* Creates a new identity matrix.
|
||||
*
|
||||
* Return value: a newly created matrix; free with cairo_matrix_destroy(),
|
||||
* or %NULL if memory couldn't be allocated.
|
||||
**/
|
||||
cairo_matrix_t *
|
||||
cairo_matrix_create (void)
|
||||
{
|
||||
cairo_matrix_t *matrix;
|
||||
|
||||
matrix = malloc (sizeof (cairo_matrix_t));
|
||||
if (matrix == NULL)
|
||||
return NULL;
|
||||
|
||||
_cairo_matrix_init (matrix);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_matrix_init (cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_set_identity (matrix);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_matrix_fini (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_matrix_destroy:
|
||||
* @matrix: a #cairo_matrix_t
|
||||
*
|
||||
* Frees a matrix created with cairo_matrix_create.
|
||||
**/
|
||||
void
|
||||
cairo_matrix_destroy (cairo_matrix_t *matrix)
|
||||
{
|
||||
_cairo_matrix_fini (matrix);
|
||||
free (matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_matrix_copy:
|
||||
* @matrix: a #cairo_matrix_t
|
||||
* @other: another #cairo_
|
||||
*
|
||||
* Modifies @matrix to be identical to @other.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
|
||||
{
|
||||
*matrix = *other;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
slim_hidden_def(cairo_matrix_copy);
|
||||
|
||||
/**
|
||||
* cairo_matrix_set_identity:
|
||||
* @matrix: a #cairo_matrix_t
|
||||
*
|
||||
* Modifies @matrix to be an identity transformation.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_set_identity (cairo_matrix_t *matrix)
|
||||
{
|
||||
*matrix = CAIRO_MATRIX_IDENTITY;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
slim_hidden_def(cairo_matrix_set_identity);
|
||||
|
||||
/**
|
||||
* cairo_matrix_set_affine:
|
||||
* @matrix: a cairo_matrix_t
|
||||
* @a: a component of the affine transformation
|
||||
* @b: b component of the affine transformation
|
||||
* @c: c component of the affine transformation
|
||||
* @d: d component of the affine transformation
|
||||
* @tx: X translation component of the affine transformation
|
||||
* @ty: Y translation component of the affine transformation
|
||||
*
|
||||
* Sets @matrix to be the affine transformation given by
|
||||
* @a, b, @c, @d, @tx, @ty. The transformation is given
|
||||
* by:
|
||||
* <programlisting>
|
||||
* x_new = x * a + y * c + tx;
|
||||
* y_new = x * b + y * d + ty;
|
||||
* </programlisting>
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_set_affine (cairo_matrix_t *matrix,
|
||||
double a, double b,
|
||||
double c, double d,
|
||||
double tx, double ty)
|
||||
{
|
||||
matrix->m[0][0] = a; matrix->m[0][1] = b;
|
||||
matrix->m[1][0] = c; matrix->m[1][1] = d;
|
||||
matrix->m[2][0] = tx; matrix->m[2][1] = ty;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
slim_hidden_def(cairo_matrix_set_affine);
|
||||
|
||||
/**
|
||||
* cairo_matrix_get_affine:
|
||||
* @matrix: a @cairo_matrix_t
|
||||
* @a: location to store a component of affine transformation, or %NULL
|
||||
* @b: location to store b component of affine transformation, or %NULL
|
||||
* @c: location to store c component of affine transformation, or %NULL
|
||||
* @d: location to store d component of affine transformation, or %NULL
|
||||
* @tx: location to store X-translation component of affine transformation, or %NULL
|
||||
* @ty: location to store Y-translation component of affine transformation, or %NULL
|
||||
*
|
||||
* Gets the matrix values for the affine tranformation that @matrix represents.
|
||||
* See cairo_matrix_set_affine().
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_get_affine (cairo_matrix_t *matrix,
|
||||
double *a, double *b,
|
||||
double *c, double *d,
|
||||
double *tx, double *ty)
|
||||
{
|
||||
if (a)
|
||||
*a = matrix->m[0][0];
|
||||
if (b)
|
||||
*b = matrix->m[0][1];
|
||||
|
||||
if (c)
|
||||
*c = matrix->m[1][0];
|
||||
if (d)
|
||||
*d = matrix->m[1][1];
|
||||
|
||||
if (tx)
|
||||
*tx = matrix->m[2][0];
|
||||
if (ty)
|
||||
*ty = matrix->m[2][1];
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
|
||||
double tx, double ty)
|
||||
{
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
1, 0,
|
||||
0, 1,
|
||||
tx, ty);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_matrix_translate:
|
||||
* @matrix: a cairo_matrix_t
|
||||
* @tx: amount to rotate in the X direction
|
||||
* @ty: amount to rotate in the Y direction
|
||||
*
|
||||
* Applies a translation by @tx, @ty to the transformation in
|
||||
* @matrix. The new transformation is given by first translating by
|
||||
* @tx, @ty then applying the original transformation
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_translate (&tmp, tx, ty);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
|
||||
double sx, double sy)
|
||||
{
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
sx, 0,
|
||||
0, sy,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_matrix_scale:
|
||||
* @matrix: a #cairo_matrix_t
|
||||
* @sx: Scale factor in the X direction
|
||||
* @sy: Scale factor in the Y direction
|
||||
*
|
||||
* Applies scaling by @tx, @ty to the transformation in
|
||||
* @matrix. The new transformation is given by first scaling by @sx
|
||||
* and @sy then applying the original transformation
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_scale (&tmp, sx, sy);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
slim_hidden_def(cairo_matrix_scale);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
|
||||
double radians)
|
||||
{
|
||||
double s;
|
||||
double c;
|
||||
#if HAVE_SINCOS
|
||||
sincos (radians, &s, &c);
|
||||
#else
|
||||
s = sin (radians);
|
||||
c = cos (radians);
|
||||
#endif
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
c, s,
|
||||
-s, c,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_matrix_rotate:
|
||||
* @matrix: a @cairo_matrix_t
|
||||
* @radians: angle of rotation, in radians. Angles are defined
|
||||
* so that an angle of 90 degrees (%M_PI radians) rotates the
|
||||
* positive X axis into the positive Y axis. With the default
|
||||
* Cairo choice of axis orientation, positive rotations are
|
||||
* clockwise.
|
||||
*
|
||||
* Applies rotation by @radians to the transformation in
|
||||
* @matrix. The new transformation is given by first rotating by
|
||||
* @radians then applying the original transformation
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_rotate (&tmp, radians);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_matrix_multiply:
|
||||
* @result: a @cairo_matrix_t in which to store the result
|
||||
* @a: a @cairo_matrix_t
|
||||
* @b: a @cairo_matrix_t
|
||||
*
|
||||
* Multiplies the affine transformations in @a and @b together
|
||||
* and stores the result in @result. The resulting transformation
|
||||
* is given by first applying the transformation in @b then
|
||||
* applying the transformation in @a.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
|
||||
{
|
||||
cairo_matrix_t r;
|
||||
int row, col, n;
|
||||
double t;
|
||||
|
||||
for (row = 0; row < 3; row++) {
|
||||
for (col = 0; col < 2; col++) {
|
||||
if (row == 2)
|
||||
t = b->m[2][col];
|
||||
else
|
||||
t = 0;
|
||||
for (n = 0; n < 2; n++) {
|
||||
t += a->m[row][n] * b->m[n][col];
|
||||
}
|
||||
r.m[row][col] = t;
|
||||
}
|
||||
}
|
||||
|
||||
*result = r;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
slim_hidden_def(cairo_matrix_multiply);
|
||||
|
||||
/**
|
||||
* cairo_matrix_transform_distance:
|
||||
* @matrix: a @cairo_matrix_t
|
||||
* @dx: a distance in the X direction. An in/out parameter
|
||||
* @dy: a distance in the Y direction. An in/out parameter
|
||||
*
|
||||
* Transforms the vector (@dx,@dy) by @matrix. Translation is
|
||||
* ignored. In terms of the components of the affine transformation:
|
||||
*
|
||||
* <programlisting>
|
||||
* dx2 = dx1 * a + dy1 * c;
|
||||
* dy2 = dx1 * b + dy1 * d;
|
||||
* </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.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
|
||||
{
|
||||
double new_x, new_y;
|
||||
|
||||
new_x = (matrix->m[0][0] * *dx
|
||||
+ matrix->m[1][0] * *dy);
|
||||
new_y = (matrix->m[0][1] * *dx
|
||||
+ matrix->m[1][1] * *dy);
|
||||
|
||||
*dx = new_x;
|
||||
*dy = new_y;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
slim_hidden_def(cairo_matrix_transform_distance);
|
||||
|
||||
/**
|
||||
* cairo_matrix_transform_point:
|
||||
* @matrix: a @cairo_matrix_t
|
||||
* @x: X position. An in/out parameter
|
||||
* @y: Y position. An in/out parameter
|
||||
*
|
||||
* Transforms the point (@x, @y) by @matrix.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS, always.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
|
||||
{
|
||||
cairo_matrix_transform_distance (matrix, x, y);
|
||||
|
||||
*x += matrix->m[2][0];
|
||||
*y += matrix->m[2][1];
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
slim_hidden_def(cairo_matrix_transform_point);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
|
||||
double *x, double *y,
|
||||
double *width, double *height)
|
||||
{
|
||||
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;
|
||||
|
||||
quad_x[0] = *x;
|
||||
quad_y[0] = *y;
|
||||
cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
|
||||
|
||||
dx1 = *width;
|
||||
dy1 = 0;
|
||||
cairo_matrix_transform_distance (matrix, &dx1, &dy1);
|
||||
quad_x[1] = quad_x[0] + dx1;
|
||||
quad_y[1] = quad_y[0] + dy1;
|
||||
|
||||
dx2 = 0;
|
||||
dy2 = *height;
|
||||
cairo_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];
|
||||
if (quad_x[i] > max_x)
|
||||
max_x = quad_x[i];
|
||||
|
||||
if (quad_y[i] < min_y)
|
||||
min_y = quad_y[i];
|
||||
if (quad_y[i] > max_y)
|
||||
max_y = quad_y[i];
|
||||
}
|
||||
|
||||
*x = min_x;
|
||||
*y = min_y;
|
||||
*width = max_x - min_x;
|
||||
*height = max_y - min_y;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
|
||||
{
|
||||
int row, col;
|
||||
|
||||
for (row = 0; row < 3; row++)
|
||||
for (col = 0; col < 2; col++)
|
||||
matrix->m[row][col] *= scalar;
|
||||
}
|
||||
|
||||
/* This function isn't a correct adjoint in that the implicit 1 in the
|
||||
homogeneous result should actually be ad-bc instead. But, since this
|
||||
adjoint is only used in the computation of the inverse, which
|
||||
divides by det (A)=ad-bc anyway, everything works out in the end. */
|
||||
static void
|
||||
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* adj (A) = transpose (C:cofactor (A,i,j)) */
|
||||
double a, b, c, d, tx, ty;
|
||||
|
||||
a = matrix->m[0][0]; b = matrix->m[0][1];
|
||||
c = matrix->m[1][0]; d = matrix->m[1][1];
|
||||
tx = matrix->m[2][0]; ty = matrix->m[2][1];
|
||||
|
||||
cairo_matrix_set_affine (matrix,
|
||||
d, -b,
|
||||
-c, a,
|
||||
c*ty - d*tx, b*tx - a*ty);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_matrix_invert:
|
||||
* @matrix: a @cairo_matrix_t
|
||||
*
|
||||
* Changes @matrix to be the inverse of it's original value. Not
|
||||
* all transformation matrices have inverses; if the matrix
|
||||
* collapses points together (it is <firstterm>degenerate</firstterm>),
|
||||
* then it has no inverse and this function will fail.
|
||||
*
|
||||
* Returns: If @matrix has an inverse, modifies @matrix to
|
||||
* be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
|
||||
* returns %CAIRO_STATUS_INVALID_MATRIX.
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_matrix_invert (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* inv (A) = 1/det (A) * adj (A) */
|
||||
double det;
|
||||
|
||||
_cairo_matrix_compute_determinant (matrix, &det);
|
||||
|
||||
if (det == 0)
|
||||
return CAIRO_STATUS_INVALID_MATRIX;
|
||||
|
||||
_cairo_matrix_compute_adjoint (matrix);
|
||||
_cairo_matrix_scalar_multiply (matrix, 1 / det);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
slim_hidden_def(cairo_matrix_invert);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det)
|
||||
{
|
||||
double a, b, c, d;
|
||||
|
||||
a = matrix->m[0][0]; b = matrix->m[0][1];
|
||||
c = matrix->m[1][0]; d = matrix->m[1][1];
|
||||
|
||||
*det = a*d - b*c;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2)
|
||||
{
|
||||
/* The eigenvalues of an NxN matrix M are found by solving the polynomial:
|
||||
|
||||
det (M - lI) = 0
|
||||
|
||||
The zeros in our homogeneous 3x3 matrix make this equation equal
|
||||
to that formed by the sub-matrix:
|
||||
|
||||
M = a b
|
||||
c d
|
||||
|
||||
by which:
|
||||
|
||||
l^2 - (a+d)l + (ad - bc) = 0
|
||||
|
||||
l = (a+d +/- sqrt (a^2 + 2ad + d^2 - 4 (ad-bc))) / 2;
|
||||
*/
|
||||
|
||||
double a, b, c, d, rad;
|
||||
|
||||
a = matrix->m[0][0];
|
||||
b = matrix->m[0][1];
|
||||
c = matrix->m[1][0];
|
||||
d = matrix->m[1][1];
|
||||
|
||||
rad = sqrt (a*a + 2*a*d + d*d - 4*(a*d - b*c));
|
||||
*lambda1 = (a + d + rad) / 2.0;
|
||||
*lambda2 = (a + d - rad) / 2.0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Compute the amount that each basis vector is scaled by. */
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major)
|
||||
{
|
||||
double det;
|
||||
|
||||
_cairo_matrix_compute_determinant (matrix, &det);
|
||||
|
||||
if (det == 0)
|
||||
*sx = *sy = 0;
|
||||
else
|
||||
{
|
||||
double x = x_major != 0;
|
||||
double y = x == 0;
|
||||
double major, minor;
|
||||
|
||||
cairo_matrix_transform_distance (matrix, &x, &y);
|
||||
major = sqrt(x*x + y*y);
|
||||
/*
|
||||
* ignore mirroring
|
||||
*/
|
||||
if (det < 0)
|
||||
det = -det;
|
||||
if (major)
|
||||
minor = det / major;
|
||||
else
|
||||
minor = 0.0;
|
||||
if (x_major)
|
||||
{
|
||||
*sx = major;
|
||||
*sy = minor;
|
||||
}
|
||||
else
|
||||
{
|
||||
*sx = minor;
|
||||
*sy = major;
|
||||
}
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
|
||||
int *itx, int *ity)
|
||||
{
|
||||
double a, b, c, d, tx, ty;
|
||||
int ttx, tty;
|
||||
int ok = 0;
|
||||
cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
|
||||
ttx = _cairo_fixed_from_double (tx);
|
||||
tty = _cairo_fixed_from_double (ty);
|
||||
ok = ((a == 1.0)
|
||||
&& (b == 0.0)
|
||||
&& (c == 0.0)
|
||||
&& (d == 1.0)
|
||||
&& (_cairo_fixed_is_integer(ttx))
|
||||
&& (_cairo_fixed_is_integer(tty)));
|
||||
if (ok) {
|
||||
*itx = _cairo_fixed_integer_part(ttx);
|
||||
*ity = _cairo_fixed_integer_part(tty);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
|
@ -1,587 +0,0 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2002 University of Southern California
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it either under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation
|
||||
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
||||
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
||||
* notice, a recipient may use your version of this file under either
|
||||
* the MPL or the LGPL.
|
||||
*
|
||||
* You should have received a copy of the LGPL along with this library
|
||||
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* You should have received a copy of the MPL along with this library
|
||||
* in the file COPYING-MPL-1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
||||
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
||||
* the specific language governing rights and limitations.
|
||||
*
|
||||
* The Original Code is the cairo graphics library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is University of Southern
|
||||
* California.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Carl D. Worth <cworth@cworth.org>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static int
|
||||
_cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix);
|
||||
|
||||
static void
|
||||
_cairo_pen_compute_slopes (cairo_pen_t *pen);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init_empty (cairo_pen_t *pen)
|
||||
{
|
||||
pen->radius = 0;
|
||||
pen->tolerance = 0;
|
||||
pen->vertices = NULL;
|
||||
pen->num_vertices = 0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
||||
{
|
||||
int i;
|
||||
int reflect;
|
||||
double det;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
/* XXX: It would be nice to notice that the pen is already properly constructed.
|
||||
However, this test would also have to account for possible changes in the transformation
|
||||
matrix.
|
||||
if (pen->radius == radius && pen->tolerance == tolerance)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
*/
|
||||
_cairo_pen_fini (pen);
|
||||
}
|
||||
|
||||
pen->radius = radius;
|
||||
pen->tolerance = gstate->tolerance;
|
||||
|
||||
_cairo_matrix_compute_determinant (&gstate->ctm, &det);
|
||||
if (det >= 0) {
|
||||
reflect = 0;
|
||||
} else {
|
||||
reflect = 1;
|
||||
}
|
||||
|
||||
pen->num_vertices = _cairo_pen_vertices_needed (gstate->tolerance,
|
||||
radius,
|
||||
&gstate->ctm);
|
||||
|
||||
pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertices == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute pen coordinates. To generate the right ellipse, compute points around
|
||||
* a circle in user space and transform them to device space. To get a consistent
|
||||
* orientation in device space, flip the pen if the transformation matrix
|
||||
* is reflecting
|
||||
*/
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
double theta = 2 * M_PI * i / (double) pen->num_vertices;
|
||||
double dx = radius * cos (reflect ? -theta : theta);
|
||||
double dy = radius * sin (reflect ? -theta : theta);
|
||||
cairo_pen_vertex_t *v = &pen->vertices[i];
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
v->point.x = _cairo_fixed_from_double (dx);
|
||||
v->point.y = _cairo_fixed_from_double (dy);
|
||||
}
|
||||
|
||||
_cairo_pen_compute_slopes (pen);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_pen_fini (cairo_pen_t *pen)
|
||||
{
|
||||
free (pen->vertices);
|
||||
pen->vertices = NULL;
|
||||
|
||||
_cairo_pen_init_empty (pen);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
|
||||
{
|
||||
*pen = *other;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertices == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
|
||||
{
|
||||
cairo_pen_vertex_t *vertices;
|
||||
int num_vertices;
|
||||
int i;
|
||||
|
||||
num_vertices = pen->num_vertices + num_points;
|
||||
vertices = realloc (pen->vertices, num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (vertices == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
pen->vertices = vertices;
|
||||
pen->num_vertices = num_vertices;
|
||||
|
||||
/* initialize new vertices */
|
||||
for (i=0; i < num_points; i++)
|
||||
pen->vertices[pen->num_vertices-num_points+i].point = point[i];
|
||||
|
||||
_cairo_hull_compute (pen->vertices, &pen->num_vertices);
|
||||
|
||||
_cairo_pen_compute_slopes (pen);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
The circular pen in user space is transformed into an ellipse in
|
||||
device space.
|
||||
|
||||
We construct the pen by computing points along the circumference
|
||||
using equally spaced angles.
|
||||
|
||||
We show below that this approximation to the ellipse has
|
||||
maximum error at the major axis of the ellipse.
|
||||
So, we need to compute the length of the major axis and then
|
||||
use that to compute the number of sides needed in our pen.
|
||||
|
||||
Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this
|
||||
derivation:
|
||||
|
||||
1. First some notation:
|
||||
|
||||
All capital letters represent vectors in two dimensions. A prime '
|
||||
represents a transformed coordinate. Matrices are written in underlined
|
||||
form, ie _R_. Lowercase letters represent scalar real values.
|
||||
|
||||
The letter t is used to represent the greek letter theta.
|
||||
|
||||
2. The question has been posed: What is the maximum expansion factor
|
||||
achieved by the linear transformation
|
||||
|
||||
X' = _R_ X
|
||||
|
||||
where _R_ is a real-valued 2x2 matrix with entries:
|
||||
|
||||
_R_ = [a b]
|
||||
[c d] .
|
||||
|
||||
In other words, what is the maximum radius, MAX[ |X'| ], reached for any
|
||||
X on the unit circle ( |X| = 1 ) ?
|
||||
|
||||
|
||||
3. Some useful formulae
|
||||
|
||||
(A) through (C) below are standard double-angle formulae. (D) is a lesser
|
||||
known result and is derived below:
|
||||
|
||||
(A) sin^2(t) = (1 - cos(2*t))/2
|
||||
(B) cos^2(t) = (1 + cos(2*t))/2
|
||||
(C) sin(t)*cos(t) = sin(2*t)/2
|
||||
(D) MAX[a*cos(t) + b*sin(t)] = sqrt(a^2 + b^2)
|
||||
|
||||
Proof of (D):
|
||||
|
||||
find the maximum of the function by setting the derivative to zero:
|
||||
|
||||
-a*sin(t)+b*cos(t) = 0
|
||||
|
||||
From this it follows that
|
||||
|
||||
tan(t) = b/a
|
||||
|
||||
and hence
|
||||
|
||||
sin(t) = b/sqrt(a^2 + b^2)
|
||||
|
||||
and
|
||||
|
||||
cos(t) = a/sqrt(a^2 + b^2)
|
||||
|
||||
Thus the maximum value is
|
||||
|
||||
MAX[a*cos(t) + b*sin(t)] = (a^2 + b^2)/sqrt(a^2 + b^2)
|
||||
= sqrt(a^2 + b^2)
|
||||
|
||||
|
||||
4. Derivation of maximum expansion
|
||||
|
||||
To find MAX[ |X'| ] we search brute force method using calculus. The unit
|
||||
circle on which X is constrained is to be parameterized by t:
|
||||
|
||||
X(t) = (cos(t), sin(t))
|
||||
|
||||
Thus
|
||||
|
||||
X'(t) = (a*cos(t) + b*sin(t), c*cos(t) + d*sin(t)) .
|
||||
|
||||
Define
|
||||
|
||||
r(t) = |X'(t)|
|
||||
|
||||
Thus
|
||||
|
||||
r^2(t) = (a*cos(t) + b*sin(t))^2 + (c*cos(t) + d*sin(t))^2
|
||||
= (a^2 + c^2)*cos^2(t) + (b^2 + d^2)*sin^2(t)
|
||||
+ 2*(a*b + c*d)*cos(t)*sin(t)
|
||||
|
||||
Now apply the double angle formulae (A) to (C) from above:
|
||||
|
||||
r^2(t) = (a^2 + b^2 + c^2 + d^2)/2
|
||||
+ (a^2 - b^2 + c^2 - d^2)*cos(2*t)/2
|
||||
+ (a*b + c*d)*sin(2*t)
|
||||
= f + g*cos(u) + h*sin(u)
|
||||
|
||||
Where
|
||||
|
||||
f = (a^2 + b^2 + c^2 + d^2)/2
|
||||
g = (a^2 - b^2 + c^2 - d^2)/2
|
||||
h = (a*b + c*d)
|
||||
u = 2*t
|
||||
|
||||
It is clear that MAX[ |X'| ] = sqrt(MAX[ r^2 ]). Here we determine MAX[ r^2 ]
|
||||
using (D) from above:
|
||||
|
||||
MAX[ r^2 ] = f + sqrt(g^2 + h^2)
|
||||
|
||||
And finally
|
||||
|
||||
MAX[ |X'| ] = sqrt( f + sqrt(g^2 + h^2) )
|
||||
|
||||
Which is the solution to this problem.
|
||||
|
||||
|
||||
Walter Brisken
|
||||
2004/10/08
|
||||
|
||||
(Note that the minor axis length is at the minimum of the above solution,
|
||||
which is just sqrt (f - sqrt (g^2 + h^2)) given the symmetry of (D)).
|
||||
|
||||
Now to compute how many sides to use for the pen formed by
|
||||
a regular polygon.
|
||||
|
||||
Set
|
||||
|
||||
M = major axis length (computed by above formula)
|
||||
m = minor axis length (computed by above formula)
|
||||
|
||||
Align 'M' along the X axis and 'm' along the Y axis and draw
|
||||
an ellipse parameterized by angle 't':
|
||||
|
||||
x = M cos t y = m sin t
|
||||
|
||||
Perturb t by ± d and compute two new points (x+,y+), (x-,y-).
|
||||
The distance from the average of these two points to (x,y) represents
|
||||
the maximum error in approximating the ellipse with a polygon formed
|
||||
from vertices 2∆ radians apart.
|
||||
|
||||
x+ = M cos (t+∆) y+ = m sin (t+∆)
|
||||
x- = M cos (t-∆) y- = m sin (t-∆)
|
||||
|
||||
Now compute the approximation error, E:
|
||||
|
||||
Ex = (x - (x+ + x-) / 2)
|
||||
Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2)
|
||||
= M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) +
|
||||
cos(t)cos(∆) - sin(t)sin(∆))/2)
|
||||
= M(cos(t) - cos(t)cos(∆))
|
||||
= M cos(t) (1 - cos(∆))
|
||||
|
||||
Ey = y - (y+ - y-) / 2
|
||||
= m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2
|
||||
= m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) +
|
||||
sin(t)cos(∆) - cos(t)sin(∆))/2)
|
||||
= m (sin(t) - sin(t)cos(∆))
|
||||
= m sin(t) (1 - cos(∆))
|
||||
|
||||
E² = Ex² + Ey²
|
||||
= (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))²
|
||||
= (1 - cos(∆))² (M² cos²(t) + m² sin²(t))
|
||||
= (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t))
|
||||
= (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m²
|
||||
|
||||
Find the extremum by differentiation wrt t and setting that to zero
|
||||
|
||||
∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t))
|
||||
|
||||
0 = 2 cos (t) sin (t)
|
||||
0 = sin (2t)
|
||||
t = nπ
|
||||
|
||||
Which is to say that the maximum and minimum errors occur on the
|
||||
axes of the ellipse at 0 and π radians:
|
||||
|
||||
E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m²
|
||||
= (1-cos(∆))² M²
|
||||
E²(π) = (1-cos(∆))² m²
|
||||
|
||||
maximum error = M (1-cos(∆))
|
||||
minimum error = m (1-cos(∆))
|
||||
|
||||
We must make maximum error ≤ tolerance, so compute the ∆ needed:
|
||||
|
||||
tolerance = M (1-cos(∆))
|
||||
tolerance / M = 1 - cos (∆)
|
||||
cos(∆) = 1 - tolerance/M
|
||||
∆ = acos (1 - tolerance / M);
|
||||
|
||||
Remembering that ∆ is half of our angle between vertices,
|
||||
the number of vertices is then
|
||||
|
||||
vertices = ceil(2π/2∆).
|
||||
= ceil(π/∆).
|
||||
|
||||
Note that this also equation works for M == m (a circle) as it
|
||||
doesn't matter where on the circle the error is computed.
|
||||
|
||||
*/
|
||||
|
||||
static int
|
||||
_cairo_pen_vertices_needed (double tolerance,
|
||||
double radius,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
double a = matrix->m[0][0], c = matrix->m[0][1];
|
||||
double b = matrix->m[1][0], d = matrix->m[1][1];
|
||||
|
||||
double i = a*a + c*c;
|
||||
double j = b*b + d*d;
|
||||
|
||||
double f = 0.5 * (i + j);
|
||||
double g = 0.5 * (i - j);
|
||||
double h = a*b + c*d;
|
||||
|
||||
/*
|
||||
* compute major and minor axes lengths for
|
||||
* a pen with the specified radius
|
||||
*/
|
||||
|
||||
double major_axis = radius * sqrt (f + sqrt (g*g+h*h));
|
||||
|
||||
/*
|
||||
* we don't need the minor axis length, which is
|
||||
* double min = radius * sqrt (f - sqrt (g*g+h*h));
|
||||
*/
|
||||
|
||||
/*
|
||||
* compute number of vertices needed
|
||||
*/
|
||||
int num_vertices;
|
||||
|
||||
/* Where tolerance / M is > 1, we use 4 points */
|
||||
if (tolerance >= major_axis) {
|
||||
num_vertices = 4;
|
||||
} else {
|
||||
double delta = acos (1 - tolerance / major_axis);
|
||||
num_vertices = ceil (M_PI / delta);
|
||||
|
||||
/* number of vertices must be even */
|
||||
if (num_vertices % 2)
|
||||
num_vertices++;
|
||||
}
|
||||
return num_vertices;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_pen_compute_slopes (cairo_pen_t *pen)
|
||||
{
|
||||
int i, i_prev;
|
||||
cairo_pen_vertex_t *prev, *v, *next;
|
||||
|
||||
for (i=0, i_prev = pen->num_vertices - 1;
|
||||
i < pen->num_vertices;
|
||||
i_prev = i++) {
|
||||
prev = &pen->vertices[i_prev];
|
||||
v = &pen->vertices[i];
|
||||
next = &pen->vertices[(i + 1) % pen->num_vertices];
|
||||
|
||||
_cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
|
||||
_cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Find active pen vertex for clockwise edge of stroke at the given slope.
|
||||
*
|
||||
* NOTE: The behavior of this function is sensitive to the sense of
|
||||
* the inequality within _cairo_slope_clockwise/_cairo_slope_counter_clockwise.
|
||||
*
|
||||
* The issue is that the slope_ccw member of one pen vertex will be
|
||||
* equivalent to the slope_cw member of the next pen vertex in a
|
||||
* counterclockwise order. However, for this function, we care
|
||||
* strongly about which vertex is returned.
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
|
||||
cairo_slope_t *slope,
|
||||
int *active)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
if (_cairo_slope_clockwise (slope, &pen->vertices[i].slope_ccw)
|
||||
&& _cairo_slope_counter_clockwise (slope, &pen->vertices[i].slope_cw))
|
||||
break;
|
||||
}
|
||||
|
||||
*active = i;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
|
||||
*
|
||||
* NOTE: The behavior of this function is sensitive to the sense of
|
||||
* the inequality within _cairo_slope_clockwise/_cairo_slope_counter_clockwise.
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
|
||||
cairo_slope_t *slope,
|
||||
int *active)
|
||||
{
|
||||
int i;
|
||||
cairo_slope_t slope_reverse;
|
||||
|
||||
slope_reverse = *slope;
|
||||
slope_reverse.dx = -slope_reverse.dx;
|
||||
slope_reverse.dy = -slope_reverse.dy;
|
||||
|
||||
for (i=pen->num_vertices-1; i >= 0; i--) {
|
||||
if (_cairo_slope_counter_clockwise (&pen->vertices[i].slope_ccw, &slope_reverse)
|
||||
&& _cairo_slope_clockwise (&pen->vertices[i].slope_cw, &slope_reverse))
|
||||
break;
|
||||
}
|
||||
|
||||
*active = i;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
|
||||
cairo_spline_t *spline,
|
||||
cairo_direction_t dir,
|
||||
cairo_polygon_t *polygon)
|
||||
{
|
||||
int i;
|
||||
cairo_status_t status;
|
||||
int start, stop, step;
|
||||
int active = 0;
|
||||
cairo_point_t hull_point;
|
||||
cairo_slope_t slope, initial_slope, final_slope;
|
||||
cairo_point_t *point = spline->points;
|
||||
int num_points = spline->num_points;
|
||||
|
||||
if (dir == CAIRO_DIRECTION_FORWARD) {
|
||||
start = 0;
|
||||
stop = num_points;
|
||||
step = 1;
|
||||
initial_slope = spline->initial_slope;
|
||||
final_slope = spline->final_slope;
|
||||
} else {
|
||||
start = num_points - 1;
|
||||
stop = -1;
|
||||
step = -1;
|
||||
initial_slope = spline->final_slope;
|
||||
initial_slope.dx = -initial_slope.dx;
|
||||
initial_slope.dy = -initial_slope.dy;
|
||||
final_slope = spline->initial_slope;
|
||||
final_slope.dx = -final_slope.dx;
|
||||
final_slope.dy = -final_slope.dy;
|
||||
}
|
||||
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &initial_slope, &active);
|
||||
|
||||
i = start;
|
||||
while (i != stop) {
|
||||
hull_point.x = point[i].x + pen->vertices[active].point.x;
|
||||
hull_point.y = point[i].y + pen->vertices[active].point.y;
|
||||
status = _cairo_polygon_line_to (polygon, &hull_point);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (i + step == stop)
|
||||
slope = final_slope;
|
||||
else
|
||||
_cairo_slope_init (&slope, &point[i], &point[i+step]);
|
||||
if (_cairo_slope_counter_clockwise (&slope, &pen->vertices[active].slope_ccw)) {
|
||||
if (++active == pen->num_vertices)
|
||||
active = 0;
|
||||
} else if (_cairo_slope_clockwise (&slope, &pen->vertices[active].slope_cw)) {
|
||||
if (--active == -1)
|
||||
active = pen->num_vertices - 1;
|
||||
} else {
|
||||
i += step;
|
||||
}
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Compute outline of a given spline using the pen.
|
||||
The trapezoids needed to fill that outline will be added to traps
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_stroke_spline (cairo_pen_t *pen,
|
||||
cairo_spline_t *spline,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_polygon_t polygon;
|
||||
|
||||
/* If the line width is so small that the pen is reduced to a
|
||||
single point, then we have nothing to do. */
|
||||
if (pen->num_vertices <= 1)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
|
||||
status = _cairo_spline_decompose (spline, tolerance);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_polygon_close (&polygon);
|
||||
_cairo_traps_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
|
@ -858,6 +858,8 @@ typedef struct _cairo_gstate {
|
|||
double *dash;
|
||||
int num_dashes;
|
||||
double dash_offset;
|
||||
double max_dash_length;
|
||||
double fraction_dash_lit;
|
||||
|
||||
char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */
|
||||
cairo_font_slant_t font_slant;
|
||||
|
@ -1645,6 +1647,9 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
|
|||
cairo_private cairo_status_t
|
||||
_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_matrix_compute_expansion_factors (cairo_matrix_t *matrix, double *min, double *max);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
|
||||
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
Index: cairo_gstate.c
|
||||
===================================================================
|
||||
RCS file: /cvsroot/mozilla/gfx/cairo/cairo/src/cairo_gstate.c,v
|
||||
retrieving revision 1.3
|
||||
diff -u -8 -p -r1.3 cairo_gstate.c
|
||||
--- cairo_gstate.c 30 Mar 2005 17:32:16 -0000 1.3
|
||||
+++ cairo_gstate.c 31 Mar 2005 19:53:08 -0000
|
||||
@@ -84,16 +84,18 @@ _cairo_gstate_init (cairo_gstate_t *gsta
|
||||
gstate->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT;
|
||||
gstate->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT;
|
||||
|
||||
gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
|
||||
|
||||
gstate->dash = NULL;
|
||||
gstate->num_dashes = 0;
|
||||
gstate->dash_offset = 0.0;
|
||||
+ gstate->max_dash_length = 0.0;
|
||||
+ gstate->fraction_dash_lit = 0.0;
|
||||
|
||||
gstate->font_family = NULL;
|
||||
gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT;
|
||||
gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT;
|
||||
|
||||
gstate->font = NULL;
|
||||
|
||||
gstate->surface = NULL;
|
||||
@@ -538,28 +540,41 @@ cairo_line_join_t
|
||||
_cairo_gstate_current_line_join (cairo_gstate_t *gstate)
|
||||
{
|
||||
return gstate->line_join;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset)
|
||||
{
|
||||
+ double length = 0.0, lit = 0.0;
|
||||
+ int i;
|
||||
+
|
||||
if (gstate->dash) {
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
}
|
||||
|
||||
gstate->num_dashes = num_dashes;
|
||||
if (gstate->num_dashes) {
|
||||
gstate->dash = malloc (gstate->num_dashes * sizeof (double));
|
||||
if (gstate->dash == NULL) {
|
||||
gstate->num_dashes = 0;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
+
|
||||
+ gstate->max_dash_length = 0.0;
|
||||
+ for (i = 0; i < num_dashes; i++) {
|
||||
+ gstate->max_dash_length = MAX(dash[i], gstate->max_dash_length);
|
||||
+
|
||||
+ if (!(i & 1))
|
||||
+ lit += dash[i];
|
||||
+ length += dash[i];
|
||||
+ }
|
||||
+ gstate->fraction_dash_lit = lit/length;
|
||||
}
|
||||
|
||||
memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double));
|
||||
gstate->dash_offset = offset;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1317,46 +1332,77 @@ _cairo_gstate_pattern_init_copy (cairo_g
|
||||
cairo_pattern_union_t *pattern,
|
||||
cairo_pattern_t *src)
|
||||
{
|
||||
_cairo_pattern_init_copy (&pattern->base, src);
|
||||
_cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse);
|
||||
_cairo_pattern_set_alpha (&pattern->base, gstate->alpha);
|
||||
}
|
||||
|
||||
+static cairo_bool_t
|
||||
+_dashes_invisible (cairo_gstate_t *gstate)
|
||||
+{
|
||||
+ if (gstate->dash) {
|
||||
+ double min, max;
|
||||
+
|
||||
+ _cairo_matrix_compute_expansion_factors (&gstate->ctm, &min, &max);
|
||||
+
|
||||
+ /* Quick and dirty applicaton of Nyquist sampling limit */
|
||||
+
|
||||
+ if (min * gstate->max_dash_length < 0.5f)
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
cairo_status_t
|
||||
_cairo_gstate_stroke (cairo_gstate_t *gstate)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_traps_t traps;
|
||||
+ double *dash = NULL;
|
||||
+ double alpha = 0.0;
|
||||
|
||||
if (gstate->line_width <= 0.0)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
+ if (_dashes_invisible(gstate)) {
|
||||
+ dash = gstate->dash;
|
||||
+ gstate->dash = NULL;
|
||||
+
|
||||
+ alpha = gstate->alpha;
|
||||
+ gstate->alpha *= gstate->fraction_dash_lit;
|
||||
+ }
|
||||
+
|
||||
_cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
|
||||
status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
|
||||
- if (status) {
|
||||
- _cairo_traps_fini (&traps);
|
||||
- return status;
|
||||
- }
|
||||
+ if (status)
|
||||
+ goto BAIL;
|
||||
|
||||
_cairo_gstate_clip_and_composite_trapezoids (gstate,
|
||||
gstate->pattern,
|
||||
gstate->operator,
|
||||
gstate->surface,
|
||||
&traps);
|
||||
|
||||
+ BAIL:
|
||||
_cairo_traps_fini (&traps);
|
||||
|
||||
_cairo_gstate_new_path (gstate);
|
||||
|
||||
- return CAIRO_STATUS_SUCCESS;
|
||||
+ if (dash) {
|
||||
+ gstate->dash = dash;
|
||||
+ gstate->alpha = alpha;
|
||||
+ }
|
||||
+
|
||||
+ return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
|
||||
double x,
|
||||
double y,
|
||||
cairo_bool_t *inside_ret)
|
||||
{
|
||||
@@ -1695,19 +1741,25 @@ _cairo_gstate_show_page (cairo_gstate_t
|
||||
cairo_status_t
|
||||
_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
|
||||
double *x1, double *y1,
|
||||
double *x2, double *y2)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_traps_t traps;
|
||||
cairo_box_t extents;
|
||||
+ double *dash = NULL;
|
||||
+
|
||||
+ if (_dashes_invisible(gstate)) {
|
||||
+ dash = gstate->dash;
|
||||
+ gstate->dash = NULL;
|
||||
+ }
|
||||
|
||||
_cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
|
||||
-
|
||||
+
|
||||
_cairo_traps_init (&traps);
|
||||
|
||||
status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
|
||||
if (status)
|
||||
goto BAIL;
|
||||
|
||||
_cairo_traps_extents (&traps, &extents);
|
||||
|
||||
@@ -1716,16 +1768,19 @@ _cairo_gstate_stroke_extents (cairo_gsta
|
||||
*x2 = _cairo_fixed_to_double (extents.p2.x);
|
||||
*y2 = _cairo_fixed_to_double (extents.p2.y);
|
||||
|
||||
cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
|
||||
cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
|
||||
|
||||
BAIL:
|
||||
_cairo_traps_fini (&traps);
|
||||
+
|
||||
+ if (dash)
|
||||
+ gstate->dash = dash;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
|
||||
double *x1, double *y1,
|
||||
double *x2, double *y2)
|
||||
Index: cairo_matrix.c
|
||||
===================================================================
|
||||
RCS file: /cvsroot/mozilla/gfx/cairo/cairo/src/cairo_matrix.c,v
|
||||
retrieving revision 1.2
|
||||
diff -u -8 -p -r1.2 cairo_matrix.c
|
||||
--- cairo_matrix.c 23 Mar 2005 19:53:39 -0000 1.2
|
||||
+++ cairo_matrix.c 31 Mar 2005 19:53:08 -0000
|
||||
@@ -615,16 +615,39 @@ _cairo_matrix_compute_scale_factors (cai
|
||||
*sx = minor;
|
||||
*sy = major;
|
||||
}
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
+/* Compute the min/max expansion factors. See the comment in
|
||||
+ * cairo-pen.c for the derivation */
|
||||
+cairo_status_t
|
||||
+_cairo_matrix_compute_expansion_factors (cairo_matrix_t *matrix,
|
||||
+ double *min, double *max)
|
||||
+{
|
||||
+ double a = matrix->m[0][0], c = matrix->m[0][1];
|
||||
+ double b = matrix->m[1][0], d = matrix->m[1][1];
|
||||
+
|
||||
+ double i = a*a + c*c;
|
||||
+ double j = b*b + d*d;
|
||||
+
|
||||
+ double f = 0.5 * (i + j);
|
||||
+ double g = 0.5 * (i - j);
|
||||
+ double h = a*b + c*d;
|
||||
+
|
||||
+ *max = sqrt (f + sqrt (g*g+h*h));
|
||||
+
|
||||
+ *min = sqrt (f - sqrt (g*g+h*h));
|
||||
+
|
||||
+ return CAIRO_STATUS_SUCCESS;
|
||||
+}
|
||||
+
|
||||
cairo_bool_t
|
||||
_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
|
||||
int *itx, int *ity)
|
||||
{
|
||||
double a, b, c, d, tx, ty;
|
||||
int ttx, tty;
|
||||
int ok = 0;
|
||||
cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
|
||||
Index: cairo_pen.c
|
||||
===================================================================
|
||||
RCS file: /cvsroot/mozilla/gfx/cairo/cairo/src/cairo_pen.c,v
|
||||
retrieving revision 1.2
|
||||
diff -u -8 -p -r1.2 cairo_pen.c
|
||||
--- cairo_pen.c 23 Mar 2005 19:53:39 -0000 1.2
|
||||
+++ cairo_pen.c 31 Mar 2005 19:53:08 -0000
|
||||
@@ -367,42 +367,24 @@ doesn't matter where on the circle the e
|
||||
|
||||
*/
|
||||
|
||||
static int
|
||||
_cairo_pen_vertices_needed (double tolerance,
|
||||
double radius,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
- double a = matrix->m[0][0], c = matrix->m[0][1];
|
||||
- double b = matrix->m[1][0], d = matrix->m[1][1];
|
||||
+ double min, max, major_axis;
|
||||
+ int num_vertices;
|
||||
|
||||
- double i = a*a + c*c;
|
||||
- double j = b*b + d*d;
|
||||
-
|
||||
- double f = 0.5 * (i + j);
|
||||
- double g = 0.5 * (i - j);
|
||||
- double h = a*b + c*d;
|
||||
-
|
||||
- /*
|
||||
- * compute major and minor axes lengths for
|
||||
- * a pen with the specified radius
|
||||
- */
|
||||
-
|
||||
- double major_axis = radius * sqrt (f + sqrt (g*g+h*h));
|
||||
-
|
||||
- /*
|
||||
- * we don't need the minor axis length, which is
|
||||
- * double min = radius * sqrt (f - sqrt (g*g+h*h));
|
||||
- */
|
||||
-
|
||||
+ _cairo_matrix_compute_expansion_factors (matrix, &min, &max);
|
||||
+ major_axis = radius * max;
|
||||
/*
|
||||
* compute number of vertices needed
|
||||
*/
|
||||
- int num_vertices;
|
||||
|
||||
/* Where tolerance / M is > 1, we use 4 points */
|
||||
if (tolerance >= major_axis) {
|
||||
num_vertices = 4;
|
||||
} else {
|
||||
double delta = acos (1 - tolerance / major_axis);
|
||||
num_vertices = ceil (M_PI / delta);
|
||||
|
||||
Index: cairoint.h
|
||||
===================================================================
|
||||
RCS file: /cvsroot/mozilla/gfx/cairo/cairo/src/cairoint.h,v
|
||||
retrieving revision 1.4
|
||||
diff -u -8 -p -r1.4 cairoint.h
|
||||
--- cairoint.h 29 Mar 2005 20:53:07 -0000 1.4
|
||||
+++ cairoint.h 31 Mar 2005 19:53:08 -0000
|
||||
@@ -853,16 +853,18 @@ typedef struct _cairo_gstate {
|
||||
cairo_line_join_t line_join;
|
||||
double miter_limit;
|
||||
|
||||
cairo_fill_rule_t fill_rule;
|
||||
|
||||
double *dash;
|
||||
int num_dashes;
|
||||
double dash_offset;
|
||||
+ double max_dash_length;
|
||||
+ double fraction_dash_lit;
|
||||
|
||||
char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */
|
||||
cairo_font_slant_t font_slant;
|
||||
cairo_font_weight_t font_weight;
|
||||
|
||||
cairo_font_t *font; /* Specific to the current CTM */
|
||||
|
||||
cairo_surface_t *surface;
|
||||
@@ -1640,16 +1642,19 @@ cairo_private cairo_status_t
|
||||
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major);
|
||||
|
||||
+cairo_private cairo_status_t
|
||||
+_cairo_matrix_compute_expansion_factors (cairo_matrix_t *matrix, double *min, double *max);
|
||||
+
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
|
||||
|
||||
/* cairo_traps.c */
|
||||
cairo_private void
|
||||
_cairo_traps_init (cairo_traps_t *traps);
|
||||
|
||||
cairo_private void
|
Загрузка…
Ссылка в новой задаче