Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/cairo/src/cairo-matrix.c
Line
Count
Source (jump to first uncovered line)
1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2002 University of Southern California
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * The Original Code is the cairo graphics library.
29
 *
30
 * The Initial Developer of the Original Code is University of Southern
31
 * California.
32
 *
33
 * Contributor(s):
34
 *  Carl D. Worth <cworth@cworth.org>
35
 */
36
37
#include "cairoint.h"
38
#include "cairo-error-private.h"
39
#include <float.h>
40
41
1.52M
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
42
43
/**
44
 * SECTION:cairo-matrix
45
 * @Title: cairo_matrix_t
46
 * @Short_Description: Generic matrix operations
47
 * @See_Also: #cairo_t
48
 *
49
 * #cairo_matrix_t is used throughout cairo to convert between different
50
 * coordinate spaces.  A #cairo_matrix_t holds an affine transformation,
51
 * such as a scale, rotation, shear, or a combination of these.
52
 * The transformation of a point (<literal>x</literal>,<literal>y</literal>)
53
 * is given by:
54
 *
55
 * <programlisting>
56
 * x_new = xx * x + xy * y + x0;
57
 * y_new = yx * x + yy * y + y0;
58
 * </programlisting>
59
 *
60
 * The current transformation matrix of a #cairo_t, represented as a
61
 * #cairo_matrix_t, defines the transformation from user-space
62
 * coordinates to device-space coordinates. See cairo_get_matrix() and
63
 * cairo_set_matrix().
64
 **/
65
66
static void
67
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
68
69
static void
70
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
71
72
/**
73
 * cairo_matrix_init_identity:
74
 * @matrix: a #cairo_matrix_t
75
 *
76
 * Modifies @matrix to be an identity transformation.
77
 *
78
 * Since: 1.0
79
 **/
80
void
81
cairo_matrix_init_identity (cairo_matrix_t *matrix)
82
18.9M
{
83
18.9M
    cairo_matrix_init (matrix,
84
18.9M
           1, 0,
85
18.9M
           0, 1,
86
18.9M
           0, 0);
87
18.9M
}
88
slim_hidden_def(cairo_matrix_init_identity);
89
90
/**
91
 * cairo_matrix_init:
92
 * @matrix: a #cairo_matrix_t
93
 * @xx: xx component of the affine transformation
94
 * @yx: yx component of the affine transformation
95
 * @xy: xy component of the affine transformation
96
 * @yy: yy component of the affine transformation
97
 * @x0: X translation component of the affine transformation
98
 * @y0: Y translation component of the affine transformation
99
 *
100
 * Sets @matrix to be the affine transformation given by
101
 * @xx, @yx, @xy, @yy, @x0, @y0. The transformation is given
102
 * by:
103
 * <programlisting>
104
 *  x_new = xx * x + xy * y + x0;
105
 *  y_new = yx * x + yy * y + y0;
106
 * </programlisting>
107
 *
108
 * Since: 1.0
109
 **/
110
void
111
cairo_matrix_init (cairo_matrix_t *matrix,
112
       double xx, double yx,
113
114
       double xy, double yy,
115
       double x0, double y0)
116
37.9M
{
117
37.9M
    matrix->xx = xx; matrix->yx = yx;
118
37.9M
    matrix->xy = xy; matrix->yy = yy;
119
37.9M
    matrix->x0 = x0; matrix->y0 = y0;
120
37.9M
}
121
slim_hidden_def(cairo_matrix_init);
122
123
/**
124
 * _cairo_matrix_get_affine:
125
 * @matrix: a #cairo_matrix_t
126
 * @xx: location to store xx component of matrix
127
 * @yx: location to store yx component of matrix
128
 * @xy: location to store xy component of matrix
129
 * @yy: location to store yy component of matrix
130
 * @x0: location to store x0 (X-translation component) of matrix, or %NULL
131
 * @y0: location to store y0 (Y-translation component) of matrix, or %NULL
132
 *
133
 * Gets the matrix values for the affine transformation that @matrix represents.
134
 * See cairo_matrix_init().
135
 *
136
 *
137
 * This function is a leftover from the old public API, but is still
138
 * mildly useful as an internal means for getting at the matrix
139
 * members in a positional way. For example, when reassigning to some
140
 * external matrix type, or when renaming members to more meaningful
141
 * names (such as a,b,c,d,e,f) for particular manipulations.
142
 **/
143
void
144
_cairo_matrix_get_affine (const cairo_matrix_t *matrix,
145
        double *xx, double *yx,
146
        double *xy, double *yy,
147
        double *x0, double *y0)
148
5.01k
{
149
5.01k
    *xx  = matrix->xx;
150
5.01k
    *yx  = matrix->yx;
151
152
5.01k
    *xy  = matrix->xy;
153
5.01k
    *yy  = matrix->yy;
154
155
5.01k
    if (x0)
156
139
  *x0 = matrix->x0;
157
5.01k
    if (y0)
158
139
  *y0 = matrix->y0;
159
5.01k
}
160
161
/**
162
 * cairo_matrix_init_translate:
163
 * @matrix: a #cairo_matrix_t
164
 * @tx: amount to translate in the X direction
165
 * @ty: amount to translate in the Y direction
166
 *
167
 * Initializes @matrix to a transformation that translates by @tx and
168
 * @ty in the X and Y dimensions, respectively.
169
 *
170
 * Since: 1.0
171
 **/
172
void
173
cairo_matrix_init_translate (cairo_matrix_t *matrix,
174
           double tx, double ty)
175
1.41M
{
176
1.41M
    cairo_matrix_init (matrix,
177
1.41M
           1, 0,
178
1.41M
           0, 1,
179
1.41M
           tx, ty);
180
1.41M
}
181
slim_hidden_def(cairo_matrix_init_translate);
182
183
/**
184
 * cairo_matrix_translate:
185
 * @matrix: a #cairo_matrix_t
186
 * @tx: amount to translate in the X direction
187
 * @ty: amount to translate in the Y direction
188
 *
189
 * Applies a translation by @tx, @ty to the transformation in
190
 * @matrix. The effect of the new transformation is to first translate
191
 * the coordinates by @tx and @ty, then apply the original transformation
192
 * to the coordinates.
193
 *
194
 * Since: 1.0
195
 **/
196
void
197
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
198
3.07k
{
199
3.07k
    cairo_matrix_t tmp;
200
201
3.07k
    cairo_matrix_init_translate (&tmp, tx, ty);
202
203
3.07k
    cairo_matrix_multiply (matrix, &tmp, matrix);
204
3.07k
}
205
slim_hidden_def (cairo_matrix_translate);
206
207
/**
208
 * cairo_matrix_init_scale:
209
 * @matrix: a #cairo_matrix_t
210
 * @sx: scale factor in the X direction
211
 * @sy: scale factor in the Y direction
212
 *
213
 * Initializes @matrix to a transformation that scales by @sx and @sy
214
 * in the X and Y dimensions, respectively.
215
 *
216
 * Since: 1.0
217
 **/
218
void
219
cairo_matrix_init_scale (cairo_matrix_t *matrix,
220
       double sx, double sy)
221
13.2M
{
222
13.2M
    cairo_matrix_init (matrix,
223
13.2M
           sx,  0,
224
13.2M
           0, sy,
225
13.2M
           0, 0);
226
13.2M
}
227
slim_hidden_def(cairo_matrix_init_scale);
228
229
/**
230
 * cairo_matrix_scale:
231
 * @matrix: a #cairo_matrix_t
232
 * @sx: scale factor in the X direction
233
 * @sy: scale factor in the Y direction
234
 *
235
 * Applies scaling by @sx, @sy to the transformation in @matrix. The
236
 * effect of the new transformation is to first scale the coordinates
237
 * by @sx and @sy, then apply the original transformation to the coordinates.
238
 *
239
 * Since: 1.0
240
 **/
241
void
242
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
243
2.56M
{
244
2.56M
    cairo_matrix_t tmp;
245
246
2.56M
    cairo_matrix_init_scale (&tmp, sx, sy);
247
248
2.56M
    cairo_matrix_multiply (matrix, &tmp, matrix);
249
2.56M
}
250
slim_hidden_def(cairo_matrix_scale);
251
252
/**
253
 * cairo_matrix_init_rotate:
254
 * @matrix: a #cairo_matrix_t
255
 * @radians: angle of rotation, in radians. The direction of rotation
256
 * is defined such that positive angles rotate in the direction from
257
 * the positive X axis toward the positive Y axis. With the default
258
 * axis orientation of cairo, positive angles rotate in a clockwise
259
 * direction.
260
 *
261
 * Initialized @matrix to a transformation that rotates by @radians.
262
 *
263
 * Since: 1.0
264
 **/
265
void
266
cairo_matrix_init_rotate (cairo_matrix_t *matrix,
267
        double radians)
268
4.22M
{
269
4.22M
    double  s;
270
4.22M
    double  c;
271
272
4.22M
    s = sin (radians);
273
4.22M
    c = cos (radians);
274
275
4.22M
    cairo_matrix_init (matrix,
276
4.22M
           c, s,
277
4.22M
           -s, c,
278
4.22M
           0, 0);
279
4.22M
}
280
slim_hidden_def(cairo_matrix_init_rotate);
281
282
/**
283
 * cairo_matrix_rotate:
284
 * @matrix: a #cairo_matrix_t
285
 * @radians: angle of rotation, in radians. The direction of rotation
286
 * is defined such that positive angles rotate in the direction from
287
 * the positive X axis toward the positive Y axis. With the default
288
 * axis orientation of cairo, positive angles rotate in a clockwise
289
 * direction.
290
 *
291
 * Applies rotation by @radians to the transformation in
292
 * @matrix. The effect of the new transformation is to first rotate the
293
 * coordinates by @radians, then apply the original transformation
294
 * to the coordinates.
295
 *
296
 * Since: 1.0
297
 **/
298
void
299
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
300
4.22M
{
301
4.22M
    cairo_matrix_t tmp;
302
303
4.22M
    cairo_matrix_init_rotate (&tmp, radians);
304
305
4.22M
    cairo_matrix_multiply (matrix, &tmp, matrix);
306
4.22M
}
307
308
/**
309
 * cairo_matrix_multiply:
310
 * @result: a #cairo_matrix_t in which to store the result
311
 * @a: a #cairo_matrix_t
312
 * @b: a #cairo_matrix_t
313
 *
314
 * Multiplies the affine transformations in @a and @b together
315
 * and stores the result in @result. The effect of the resulting
316
 * transformation is to first apply the transformation in @a to the
317
 * coordinates and then apply the transformation in @b to the
318
 * coordinates.
319
 *
320
 * It is allowable for @result to be identical to either @a or @b.
321
 *
322
 * Since: 1.0
323
 **/
324
/*
325
 * XXX: The ordering of the arguments to this function corresponds
326
 *      to [row_vector]*A*B. If we want to use column vectors instead,
327
 *      then we need to switch the two arguments and fix up all
328
 *      uses.
329
 */
330
void
331
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
332
12.8M
{
333
12.8M
    cairo_matrix_t r;
334
335
12.8M
    r.xx = a->xx * b->xx + a->yx * b->xy;
336
12.8M
    r.yx = a->xx * b->yx + a->yx * b->yy;
337
338
12.8M
    r.xy = a->xy * b->xx + a->yy * b->xy;
339
12.8M
    r.yy = a->xy * b->yx + a->yy * b->yy;
340
341
12.8M
    r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0;
342
12.8M
    r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0;
343
344
12.8M
    *result = r;
345
12.8M
}
346
slim_hidden_def(cairo_matrix_multiply);
347
348
void
349
_cairo_matrix_multiply (cairo_matrix_t *r,
350
      const cairo_matrix_t *a,
351
      const cairo_matrix_t *b)
352
0
{
353
0
    r->xx = a->xx * b->xx + a->yx * b->xy;
354
0
    r->yx = a->xx * b->yx + a->yx * b->yy;
355
356
0
    r->xy = a->xy * b->xx + a->yy * b->xy;
357
0
    r->yy = a->xy * b->yx + a->yy * b->yy;
358
359
0
    r->x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0;
360
0
    r->y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0;
361
0
}
362
363
/**
364
 * cairo_matrix_transform_distance:
365
 * @matrix: a #cairo_matrix_t
366
 * @dx: X component of a distance vector. An in/out parameter
367
 * @dy: Y component of a distance vector. An in/out parameter
368
 *
369
 * Transforms the distance vector (@dx,@dy) by @matrix. This is
370
 * similar to cairo_matrix_transform_point() except that the translation
371
 * components of the transformation are ignored. The calculation of
372
 * the returned vector is as follows:
373
 *
374
 * <programlisting>
375
 * dx2 = dx1 * a + dy1 * c;
376
 * dy2 = dx1 * b + dy1 * d;
377
 * </programlisting>
378
 *
379
 * Affine transformations are position invariant, so the same vector
380
 * always transforms to the same vector. If (@x1,@y1) transforms
381
 * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
382
 * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
383
 *
384
 * Since: 1.0
385
 **/
386
void
387
cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy)
388
47.6M
{
389
47.6M
    double new_x, new_y;
390
391
47.6M
    new_x = (matrix->xx * *dx + matrix->xy * *dy);
392
47.6M
    new_y = (matrix->yx * *dx + matrix->yy * *dy);
393
394
47.6M
    *dx = new_x;
395
47.6M
    *dy = new_y;
396
47.6M
}
397
slim_hidden_def(cairo_matrix_transform_distance);
398
399
/**
400
 * cairo_matrix_transform_point:
401
 * @matrix: a #cairo_matrix_t
402
 * @x: X position. An in/out parameter
403
 * @y: Y position. An in/out parameter
404
 *
405
 * Transforms the point (@x, @y) by @matrix.
406
 *
407
 * Since: 1.0
408
 **/
409
void
410
cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y)
411
12.4M
{
412
12.4M
    cairo_matrix_transform_distance (matrix, x, y);
413
414
12.4M
    *x += matrix->x0;
415
12.4M
    *y += matrix->y0;
416
12.4M
}
417
slim_hidden_def(cairo_matrix_transform_point);
418
419
void
420
_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
421
              double *x1, double *y1,
422
              double *x2, double *y2,
423
              cairo_bool_t *is_tight)
424
2.19M
{
425
2.19M
    int i;
426
2.19M
    double quad_x[4], quad_y[4];
427
2.19M
    double min_x, max_x;
428
2.19M
    double min_y, max_y;
429
430
2.19M
    if (matrix->xy == 0. && matrix->yx == 0.) {
431
  /* non-rotation/skew matrix, just map the two extreme points */
432
433
2.19M
  if (matrix->xx != 1.) {
434
24.6k
      quad_x[0] = *x1 * matrix->xx;
435
24.6k
      quad_x[1] = *x2 * matrix->xx;
436
24.6k
      if (quad_x[0] < quad_x[1]) {
437
19.0k
    *x1 = quad_x[0];
438
19.0k
    *x2 = quad_x[1];
439
19.0k
      } else {
440
5.61k
    *x1 = quad_x[1];
441
5.61k
    *x2 = quad_x[0];
442
5.61k
      }
443
24.6k
  }
444
2.19M
  if (matrix->x0 != 0.) {
445
2.13M
      *x1 += matrix->x0;
446
2.13M
      *x2 += matrix->x0;
447
2.13M
  }
448
449
2.19M
  if (matrix->yy != 1.) {
450
23.9k
      quad_y[0] = *y1 * matrix->yy;
451
23.9k
      quad_y[1] = *y2 * matrix->yy;
452
23.9k
      if (quad_y[0] < quad_y[1]) {
453
20.4k
    *y1 = quad_y[0];
454
20.4k
    *y2 = quad_y[1];
455
20.4k
      } else {
456
3.46k
    *y1 = quad_y[1];
457
3.46k
    *y2 = quad_y[0];
458
3.46k
      }
459
23.9k
  }
460
2.19M
  if (matrix->y0 != 0.) {
461
2.13M
      *y1 += matrix->y0;
462
2.13M
      *y2 += matrix->y0;
463
2.13M
  }
464
465
2.19M
  if (is_tight)
466
0
      *is_tight = TRUE;
467
468
2.19M
  return;
469
2.19M
    }
470
471
    /* general matrix */
472
0
    quad_x[0] = *x1;
473
0
    quad_y[0] = *y1;
474
0
    cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
475
476
0
    quad_x[1] = *x2;
477
0
    quad_y[1] = *y1;
478
0
    cairo_matrix_transform_point (matrix, &quad_x[1], &quad_y[1]);
479
480
0
    quad_x[2] = *x1;
481
0
    quad_y[2] = *y2;
482
0
    cairo_matrix_transform_point (matrix, &quad_x[2], &quad_y[2]);
483
484
0
    quad_x[3] = *x2;
485
0
    quad_y[3] = *y2;
486
0
    cairo_matrix_transform_point (matrix, &quad_x[3], &quad_y[3]);
487
488
0
    min_x = max_x = quad_x[0];
489
0
    min_y = max_y = quad_y[0];
490
491
0
    for (i=1; i < 4; i++) {
492
0
  if (quad_x[i] < min_x)
493
0
      min_x = quad_x[i];
494
0
  if (quad_x[i] > max_x)
495
0
      max_x = quad_x[i];
496
497
0
  if (quad_y[i] < min_y)
498
0
      min_y = quad_y[i];
499
0
  if (quad_y[i] > max_y)
500
0
      max_y = quad_y[i];
501
0
    }
502
503
0
    *x1 = min_x;
504
0
    *y1 = min_y;
505
0
    *x2 = max_x;
506
0
    *y2 = max_y;
507
508
0
    if (is_tight) {
509
        /* it's tight if and only if the four corner points form an axis-aligned
510
           rectangle.
511
           And that's true if and only if we can derive corners 0 and 3 from
512
           corners 1 and 2 in one of two straightforward ways...
513
           We could use a tolerance here but for now we'll fall back to FALSE in the case
514
           of floating point error.
515
        */
516
0
        *is_tight =
517
0
            (quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] &&
518
0
             quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) ||
519
0
            (quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] &&
520
0
             quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]);
521
0
    }
522
0
}
523
524
cairo_private void
525
_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix,
526
              cairo_box_t          *bbox,
527
              cairo_bool_t *is_tight)
528
0
{
529
0
    double x1, y1, x2, y2;
530
531
0
    _cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2);
532
0
    _cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight);
533
0
    _cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2);
534
0
}
535
536
static void
537
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
538
139
{
539
139
    matrix->xx *= scalar;
540
139
    matrix->yx *= scalar;
541
542
139
    matrix->xy *= scalar;
543
139
    matrix->yy *= scalar;
544
545
139
    matrix->x0 *= scalar;
546
139
    matrix->y0 *= scalar;
547
139
}
548
549
/* This function isn't a correct adjoint in that the implicit 1 in the
550
   homogeneous result should actually be ad-bc instead. But, since this
551
   adjoint is only used in the computation of the inverse, which
552
   divides by det (A)=ad-bc anyway, everything works out in the end. */
553
static void
554
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
555
139
{
556
    /* adj (A) = transpose (C:cofactor (A,i,j)) */
557
139
    double a, b, c, d, tx, ty;
558
559
139
    _cairo_matrix_get_affine (matrix,
560
139
            &a,  &b,
561
139
            &c,  &d,
562
139
            &tx, &ty);
563
564
139
    cairo_matrix_init (matrix,
565
139
           d, -b,
566
139
           -c, a,
567
139
           c*ty - d*tx, b*tx - a*ty);
568
139
}
569
570
/**
571
 * cairo_matrix_invert:
572
 * @matrix: a #cairo_matrix_t
573
 *
574
 * Changes @matrix to be the inverse of its original value. Not
575
 * all transformation matrices have inverses; if the matrix
576
 * collapses points together (it is <firstterm>degenerate</firstterm>),
577
 * then it has no inverse and this function will fail.
578
 *
579
 * Returns: If @matrix has an inverse, modifies @matrix to
580
 *  be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
581
 *  returns %CAIRO_STATUS_INVALID_MATRIX.
582
 *
583
 * Since: 1.0
584
 **/
585
cairo_status_t
586
cairo_matrix_invert (cairo_matrix_t *matrix)
587
3.23M
{
588
3.23M
    double det;
589
590
    /* Simple scaling|translation matrices are quite common... */
591
3.23M
    if (matrix->xy == 0. && matrix->yx == 0.) {
592
3.23M
  matrix->x0 = -matrix->x0;
593
3.23M
  matrix->y0 = -matrix->y0;
594
595
3.23M
  if (matrix->xx != 1.) {
596
15.4k
      if (matrix->xx == 0.)
597
0
    return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
598
599
15.4k
      matrix->xx = 1. / matrix->xx;
600
15.4k
      matrix->x0 *= matrix->xx;
601
15.4k
  }
602
603
3.23M
  if (matrix->yy != 1.) {
604
15.0k
      if (matrix->yy == 0.)
605
0
    return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
606
607
15.0k
      matrix->yy = 1. / matrix->yy;
608
15.0k
      matrix->y0 *= matrix->yy;
609
15.0k
  }
610
611
3.23M
  return CAIRO_STATUS_SUCCESS;
612
3.23M
    }
613
614
    /* inv (A) = 1/det (A) * adj (A) */
615
139
    det = _cairo_matrix_compute_determinant (matrix);
616
617
139
    if (! ISFINITE (det))
618
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
619
620
139
    if (det == 0)
621
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
622
623
139
    _cairo_matrix_compute_adjoint (matrix);
624
139
    _cairo_matrix_scalar_multiply (matrix, 1 / det);
625
626
139
    return CAIRO_STATUS_SUCCESS;
627
139
}
628
slim_hidden_def(cairo_matrix_invert);
629
630
cairo_bool_t
631
_cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
632
889k
{
633
889k
    double det;
634
635
889k
    det = _cairo_matrix_compute_determinant (matrix);
636
637
889k
    return ISFINITE (det) && det != 0.;
638
889k
}
639
640
cairo_bool_t
641
_cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix)
642
0
{
643
0
    return matrix->xx == 0. &&
644
0
           matrix->xy == 0. &&
645
0
           matrix->yx == 0. &&
646
0
           matrix->yy == 0.;
647
0
}
648
649
double
650
_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix)
651
8.22M
{
652
8.22M
    double a, b, c, d;
653
654
8.22M
    a = matrix->xx; b = matrix->yx;
655
8.22M
    c = matrix->xy; d = matrix->yy;
656
657
8.22M
    return a*d - b*c;
658
8.22M
}
659
660
/**
661
 * _cairo_matrix_compute_basis_scale_factors:
662
 * @matrix: a matrix
663
 * @basis_scale: the scale factor in the direction of basis
664
 * @normal_scale: the scale factor in the direction normal to the basis
665
 * @x_basis: basis to use.  X basis if true, Y basis otherwise.
666
 *
667
 * Computes |Mv| and det(M)/|Mv| for v=[1,0] if x_basis is true, and v=[0,1]
668
 * otherwise, and M is @matrix.
669
 *
670
 * Return value: the scale factor of @matrix on the height of the font,
671
 * or 1.0 if @matrix is %NULL.
672
 **/
673
cairo_status_t
674
_cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
675
             double *basis_scale, double *normal_scale,
676
             cairo_bool_t x_basis)
677
1.09k
{
678
1.09k
    double det;
679
680
1.09k
    det = _cairo_matrix_compute_determinant (matrix);
681
682
1.09k
    if (! ISFINITE (det))
683
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
684
685
1.09k
    if (det == 0)
686
0
    {
687
0
  *basis_scale = *normal_scale = 0;
688
0
    }
689
1.09k
    else
690
1.09k
    {
691
1.09k
  double x = x_basis != 0;
692
1.09k
  double y = x == 0;
693
1.09k
  double major, minor;
694
695
1.09k
  cairo_matrix_transform_distance (matrix, &x, &y);
696
1.09k
  major = hypot (x, y);
697
  /*
698
   * ignore mirroring
699
   */
700
1.09k
  if (det < 0)
701
0
      det = -det;
702
1.09k
  if (major)
703
1.09k
      minor = det / major;
704
0
  else
705
0
      minor = 0.0;
706
1.09k
  if (x_basis)
707
1.09k
  {
708
1.09k
      *basis_scale = major;
709
1.09k
      *normal_scale = minor;
710
1.09k
  }
711
0
  else
712
0
  {
713
0
      *basis_scale = minor;
714
0
      *normal_scale = major;
715
0
  }
716
1.09k
    }
717
718
1.09k
    return CAIRO_STATUS_SUCCESS;
719
1.09k
}
720
721
cairo_bool_t
722
_cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
723
              int *itx, int *ity)
724
539k
{
725
539k
    if (_cairo_matrix_is_translation (matrix))
726
539k
    {
727
539k
        cairo_fixed_t x0_fixed = _cairo_fixed_from_double (matrix->x0);
728
539k
        cairo_fixed_t y0_fixed = _cairo_fixed_from_double (matrix->y0);
729
730
539k
        if (_cairo_fixed_is_integer (x0_fixed) &&
731
539k
            _cairo_fixed_is_integer (y0_fixed))
732
539k
        {
733
539k
            if (itx)
734
539k
                *itx = _cairo_fixed_integer_part (x0_fixed);
735
539k
            if (ity)
736
539k
                *ity = _cairo_fixed_integer_part (y0_fixed);
737
738
539k
            return TRUE;
739
539k
        }
740
539k
    }
741
742
93
    return FALSE;
743
539k
}
744
745
8.84M
#define SCALING_EPSILON _cairo_fixed_to_double(1)
746
747
/* This only returns true if the matrix is 90 degree rotations or
748
 * flips. It appears calling code is relying on this. It will return
749
 * false for other rotations even if the scale is one. Approximations
750
 * are allowed to handle matricies filled in using trig functions
751
 * such as sin(M_PI_2).
752
 */
753
cairo_bool_t
754
_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix)
755
2.22M
{
756
    /* check that the determinant is near +/-1 */
757
2.22M
    double det = _cairo_matrix_compute_determinant (matrix);
758
2.22M
    if (fabs (det * det - 1.0) < SCALING_EPSILON) {
759
  /* check that one axis is close to zero */
760
2.20M
  if (fabs (matrix->xy) < SCALING_EPSILON  &&
761
2.20M
      fabs (matrix->yx) < SCALING_EPSILON)
762
2.20M
      return TRUE;
763
0
  if (fabs (matrix->xx) < SCALING_EPSILON  &&
764
0
      fabs (matrix->yy) < SCALING_EPSILON)
765
0
      return TRUE;
766
  /* If rotations are allowed then it must instead test for
767
   * orthogonality. This is xx*xy+yx*yy ~= 0.
768
   */
769
0
    }
770
10.5k
    return FALSE;
771
2.22M
}
772
773
/* By pixel exact here, we mean a matrix that is composed only of
774
 * 90 degree rotations, flips, and integer translations and produces a 1:1
775
 * mapping between source and destination pixels. If we transform an image
776
 * with a pixel-exact matrix, filtering is not useful.
777
 */
778
cairo_bool_t
779
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
780
543k
{
781
543k
    cairo_fixed_t x0_fixed, y0_fixed;
782
783
543k
    if (! _cairo_matrix_has_unity_scale (matrix))
784
253
  return FALSE;
785
786
543k
    x0_fixed = _cairo_fixed_from_double (matrix->x0);
787
543k
    y0_fixed = _cairo_fixed_from_double (matrix->y0);
788
789
543k
    return _cairo_fixed_is_integer (x0_fixed) && _cairo_fixed_is_integer (y0_fixed);
790
543k
}
791
792
/*
793
  A circle in user space is transformed into an ellipse in device space.
794
795
  The following is a derivation of a formula to calculate the length of the
796
  major axis for this ellipse; this is useful for error bounds calculations.
797
798
  Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this derivation:
799
800
  1.  First some notation:
801
802
  All capital letters represent vectors in two dimensions.  A prime '
803
  represents a transformed coordinate.  Matrices are written in underlined
804
  form, ie _R_.  Lowercase letters represent scalar real values.
805
806
  2.  The question has been posed:  What is the maximum expansion factor
807
  achieved by the linear transformation
808
809
  X' = X _R_
810
811
  where _R_ is a real-valued 2x2 matrix with entries:
812
813
  _R_ = [a b]
814
        [c d]  .
815
816
  In other words, what is the maximum radius, MAX[ |X'| ], reached for any
817
  X on the unit circle ( |X| = 1 ) ?
818
819
  3.  Some useful formulae
820
821
  (A) through (C) below are standard double-angle formulae.  (D) is a lesser
822
  known result and is derived below:
823
824
  (A)  sin²(θ) = (1 - cos(2*θ))/2
825
  (B)  cos²(θ) = (1 + cos(2*θ))/2
826
  (C)  sin(θ)*cos(θ) = sin(2*θ)/2
827
  (D)  MAX[a*cos(θ) + b*sin(θ)] = sqrt(a² + b²)
828
829
  Proof of (D):
830
831
  find the maximum of the function by setting the derivative to zero:
832
833
       -a*sin(θ)+b*cos(θ) = 0
834
835
  From this it follows that
836
837
       tan(θ) = b/a
838
839
  and hence
840
841
       sin(θ) = b/sqrt(a² + b²)
842
843
  and
844
845
       cos(θ) = a/sqrt(a² + b²)
846
847
  Thus the maximum value is
848
849
       MAX[a*cos(θ) + b*sin(θ)] = (a² + b²)/sqrt(a² + b²)
850
                                   = sqrt(a² + b²)
851
852
  4.  Derivation of maximum expansion
853
854
  To find MAX[ |X'| ] we search brute force method using calculus.  The unit
855
  circle on which X is constrained is to be parameterized by t:
856
857
       X(θ) = (cos(θ), sin(θ))
858
859
  Thus
860
861
       X'(θ) = X(θ) * _R_ = (cos(θ), sin(θ)) * [a b]
862
                                               [c d]
863
             = (a*cos(θ) + c*sin(θ), b*cos(θ) + d*sin(θ)).
864
865
  Define
866
867
       r(θ) = |X'(θ)|
868
869
  Thus
870
871
       r²(θ) = (a*cos(θ) + c*sin(θ))² + (b*cos(θ) + d*sin(θ))²
872
             = (a² + b²)*cos²(θ) + (c² + d²)*sin²(θ)
873
                 + 2*(a*c + b*d)*cos(θ)*sin(θ)
874
875
  Now apply the double angle formulae (A) to (C) from above:
876
877
       r²(θ) = (a² + b² + c² + d²)/2
878
       + (a² + b² - c² - d²)*cos(2*θ)/2
879
         + (a*c + b*d)*sin(2*θ)
880
             = f + g*cos(φ) + h*sin(φ)
881
882
  Where
883
884
       f = (a² + b² + c² + d²)/2
885
       g = (a² + b² - c² - d²)/2
886
       h = (a*c + d*d)
887
       φ = 2*θ
888
889
  It is clear that MAX[ |X'| ] = sqrt(MAX[ r² ]).  Here we determine MAX[ r² ]
890
  using (D) from above:
891
892
       MAX[ r² ] = f + sqrt(g² + h²)
893
894
  And finally
895
896
       MAX[ |X'| ] = sqrt( f + sqrt(g² + h²) )
897
898
  Which is the solution to this problem.
899
900
  Walter Brisken
901
  2004/10/08
902
903
  (Note that the minor axis length is at the minimum of the above solution,
904
  which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
905
906
907
  For another derivation of the same result, using Singular Value Decomposition,
908
  see doc/tutorial/src/singular.c.
909
*/
910
911
/* determine the length of the major axis of a circle of the given radius
912
   after applying the transformation matrix. */
913
double
914
_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
915
               double radius)
916
834k
{
917
834k
    double  a, b, c, d, f, g, h, i, j;
918
919
834k
    if (_cairo_matrix_has_unity_scale (matrix))
920
830k
  return radius;
921
922
3.98k
    _cairo_matrix_get_affine (matrix,
923
3.98k
                              &a, &b,
924
3.98k
                              &c, &d,
925
3.98k
                              NULL, NULL);
926
927
3.98k
    i = a*a + b*b;
928
3.98k
    j = c*c + d*d;
929
930
3.98k
    f = 0.5 * (i + j);
931
3.98k
    g = 0.5 * (i - j);
932
3.98k
    h = a*c + b*d;
933
934
3.98k
    return radius * sqrt (f + hypot (g, h));
935
936
    /*
937
     * we don't need the minor axis length, which is
938
     * double min = radius * sqrt (f - sqrt (g*g+h*h));
939
     */
940
834k
}
941
942
static const pixman_transform_t pixman_identity_transform = {{
943
        {1 << 16,        0,       0},
944
        {       0, 1 << 16,       0},
945
        {       0,       0, 1 << 16}
946
    }};
947
948
static cairo_status_t
949
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t  *matrix,
950
        pixman_transform_t  *pixman_transform,
951
        double xc,
952
        double yc)
953
2.72k
{
954
2.72k
    cairo_matrix_t inv;
955
2.72k
    unsigned max_iterations;
956
957
2.72k
    pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
958
2.72k
    pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
959
2.72k
    pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
960
961
2.72k
    pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
962
2.72k
    pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
963
2.72k
    pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
964
965
2.72k
    pixman_transform->matrix[2][0] = 0;
966
2.72k
    pixman_transform->matrix[2][1] = 0;
967
2.72k
    pixman_transform->matrix[2][2] = 1 << 16;
968
969
    /* The conversion above breaks cairo's translation invariance:
970
     * a translation of (a, b) in device space translates to
971
     * a translation of (xx * a + xy * b, yx * a + yy * b)
972
     * for cairo, while pixman uses rounded versions of xx ... yy.
973
     * This error increases as a and b get larger.
974
     *
975
     * To compensate for this, we fix the point (xc, yc) in pattern
976
     * space and adjust pixman's transform to agree with cairo's at
977
     * that point.
978
     */
979
980
2.72k
    if (_cairo_matrix_has_unity_scale (matrix))
981
223
  return CAIRO_STATUS_SUCCESS;
982
983
2.50k
    if (unlikely (fabs (matrix->xx) > PIXMAN_MAX_INT ||
984
2.50k
      fabs (matrix->xy) > PIXMAN_MAX_INT ||
985
2.50k
      fabs (matrix->x0) > PIXMAN_MAX_INT ||
986
2.50k
      fabs (matrix->yx) > PIXMAN_MAX_INT ||
987
2.50k
      fabs (matrix->yy) > PIXMAN_MAX_INT ||
988
2.50k
      fabs (matrix->y0) > PIXMAN_MAX_INT))
989
29
    {
990
29
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
991
29
    }
992
993
    /* Note: If we can't invert the transformation, skip the adjustment. */
994
2.47k
    inv = *matrix;
995
2.47k
    if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
996
0
  return CAIRO_STATUS_SUCCESS;
997
998
    /* find the pattern space coordinate that maps to (xc, yc) */
999
2.47k
    max_iterations = 5;
1000
3.35k
    do {
1001
3.35k
  double x,y;
1002
3.35k
  pixman_vector_t vector;
1003
3.35k
  cairo_fixed_16_16_t dx, dy;
1004
1005
3.35k
  vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
1006
3.35k
  vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
1007
3.35k
  vector.vector[2] = 1 << 16;
1008
1009
  /* If we can't transform the reference point, skip the adjustment. */
1010
3.35k
  if (! pixman_transform_point_3d (pixman_transform, &vector))
1011
0
      return CAIRO_STATUS_SUCCESS;
1012
1013
3.35k
  x = pixman_fixed_to_double (vector.vector[0]);
1014
3.35k
  y = pixman_fixed_to_double (vector.vector[1]);
1015
3.35k
  cairo_matrix_transform_point (&inv, &x, &y);
1016
1017
  /* Ideally, the vector should now be (xc, yc).
1018
   * We can now compensate for the resulting error.
1019
   */
1020
3.35k
  x -= xc;
1021
3.35k
  y -= yc;
1022
3.35k
  cairo_matrix_transform_distance (matrix, &x, &y);
1023
3.35k
  dx = _cairo_fixed_16_16_from_double (x);
1024
3.35k
  dy = _cairo_fixed_16_16_from_double (y);
1025
3.35k
  pixman_transform->matrix[0][2] -= dx;
1026
3.35k
  pixman_transform->matrix[1][2] -= dy;
1027
1028
3.35k
  if (dx == 0 && dy == 0)
1029
2.47k
      return CAIRO_STATUS_SUCCESS;
1030
3.35k
    } while (--max_iterations);
1031
1032
    /* We didn't find an exact match between cairo and pixman, but
1033
     * the matrix should be mostly correct */
1034
0
    return CAIRO_STATUS_SUCCESS;
1035
2.47k
}
1036
1037
static inline double
1038
_pixman_nearest_sample (double d)
1039
1.01M
{
1040
1.01M
    return ceil (d - .5);
1041
1.01M
}
1042
1043
/**
1044
 * _cairo_matrix_is_pixman_translation:
1045
 * @matrix: a matrix
1046
 * @filter: the filter to be used on the pattern transformed by @matrix
1047
 * @x_offset: the translation in the X direction
1048
 * @y_offset: the translation in the Y direction
1049
 *
1050
 * Checks if @matrix translated by (x_offset, y_offset) can be
1051
 * represented using just an offset (within the range pixman can
1052
 * accept) and an identity matrix.
1053
 *
1054
 * Passing a non-zero value in x_offset/y_offset has the same effect
1055
 * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and
1056
 * setting x_offset and y_offset to 0.
1057
 *
1058
 * Upon return x_offset and y_offset contain the translation vector if
1059
 * the return value is %TRUE. If the return value is %FALSE, they will
1060
 * not be modified.
1061
 *
1062
 * Return value: %TRUE if @matrix can be represented as a pixman
1063
 * translation, %FALSE otherwise.
1064
 **/
1065
cairo_bool_t
1066
_cairo_matrix_is_pixman_translation (const cairo_matrix_t     *matrix,
1067
             cairo_filter_t            filter,
1068
             int                      *x_offset,
1069
             int                      *y_offset)
1070
547k
{
1071
547k
    double tx, ty;
1072
1073
547k
    if (!_cairo_matrix_is_translation (matrix))
1074
2.75k
  return FALSE;
1075
1076
544k
    if (matrix->x0 == 0. && matrix->y0 == 0.)
1077
36.8k
  return TRUE;
1078
1079
507k
    tx = matrix->x0 + *x_offset;
1080
507k
    ty = matrix->y0 + *y_offset;
1081
1082
507k
    if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
1083
507k
  tx = _pixman_nearest_sample (tx);
1084
507k
  ty = _pixman_nearest_sample (ty);
1085
507k
    } else if (tx != floor (tx) || ty != floor (ty)) {
1086
0
  return FALSE;
1087
0
    }
1088
1089
507k
    if (fabs (tx) > PIXMAN_MAX_INT || fabs (ty) > PIXMAN_MAX_INT)
1090
1.03k
  return FALSE;
1091
1092
506k
    *x_offset = _cairo_lround (tx);
1093
506k
    *y_offset = _cairo_lround (ty);
1094
506k
    return TRUE;
1095
507k
}
1096
1097
/**
1098
 * _cairo_matrix_to_pixman_matrix_offset:
1099
 * @matrix: a matrix
1100
 * @filter: the filter to be used on the pattern transformed by @matrix
1101
 * @xc: the X coordinate of the point to fix in pattern space
1102
 * @yc: the Y coordinate of the point to fix in pattern space
1103
 * @out_transform: the transformation which best approximates @matrix
1104
 * @x_offset: the translation in the X direction
1105
 * @y_offset: the translation in the Y direction
1106
 *
1107
 * This function tries to represent @matrix translated by (x_offset,
1108
 * y_offset) as a %pixman_transform_t and an translation.
1109
 *
1110
 * Passing a non-zero value in x_offset/y_offset has the same effect
1111
 * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and
1112
 * setting x_offset and y_offset to 0.
1113
 *
1114
 * If it is possible to represent the matrix with an identity
1115
 * %pixman_transform_t and a translation within the valid range for
1116
 * pixman, this function will set @out_transform to be the identity,
1117
 * @x_offset and @y_offset to be the translation vector and will
1118
 * return %CAIRO_INT_STATUS_NOTHING_TO_DO. Otherwise it will try to
1119
 * evenly divide the translational component of @matrix between
1120
 * @out_transform and (@x_offset, @y_offset).
1121
 *
1122
 * Upon return x_offset and y_offset contain the translation vector.
1123
 *
1124
 * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the out_transform
1125
 * is the identity, %CAIRO_STATUS_INVALID_MATRIX if it was not
1126
 * possible to represent @matrix as a pixman_transform_t without
1127
 * overflows, %CAIRO_STATUS_SUCCESS otherwise.
1128
 **/
1129
cairo_status_t
1130
_cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t *matrix,
1131
               cairo_filter_t            filter,
1132
               double                    xc,
1133
               double                    yc,
1134
               pixman_transform_t *out_transform,
1135
               int                      *x_offset,
1136
               int                      *y_offset)
1137
3.53k
{
1138
3.53k
    cairo_bool_t is_pixman_translation;
1139
1140
3.53k
    is_pixman_translation = _cairo_matrix_is_pixman_translation (matrix,
1141
3.53k
                 filter,
1142
3.53k
                 x_offset,
1143
3.53k
                 y_offset);
1144
1145
3.53k
    if (is_pixman_translation) {
1146
808
  *out_transform = pixman_identity_transform;
1147
808
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
1148
2.72k
    } else {
1149
2.72k
  cairo_matrix_t m;
1150
1151
2.72k
  m = *matrix;
1152
2.72k
  cairo_matrix_translate (&m, *x_offset, *y_offset);
1153
2.72k
  if (m.x0 != 0.0 || m.y0 != 0.0) {
1154
350
      double tx, ty, norm;
1155
350
      int i, j;
1156
1157
      /* pixman also limits the [xy]_offset to 16 bits so evenly
1158
       * spread the bits between the two.
1159
       *
1160
       * To do this, find the solutions of:
1161
       *   |x| = |x*m.xx + y*m.xy + m.x0|
1162
       *   |y| = |x*m.yx + y*m.yy + m.y0|
1163
       *
1164
       * and select the one whose maximum norm is smallest.
1165
       */
1166
350
      tx = m.x0;
1167
350
      ty = m.y0;
1168
350
      norm = MAX (fabs (tx), fabs (ty));
1169
1170
1.05k
      for (i = -1; i < 2; i+=2) {
1171
2.10k
    for (j = -1; j < 2; j+=2) {
1172
1.40k
        double x, y, den, new_norm;
1173
1174
1.40k
        den = (m.xx + i) * (m.yy + j) - m.xy * m.yx;
1175
1.40k
        if (fabs (den) < DBL_EPSILON)
1176
689
      continue;
1177
1178
711
        x = m.y0 * m.xy - m.x0 * (m.yy + j);
1179
711
        y = m.x0 * m.yx - m.y0 * (m.xx + i);
1180
1181
711
        den = 1 / den;
1182
711
        x *= den;
1183
711
        y *= den;
1184
1185
711
        new_norm = MAX (fabs (x), fabs (y));
1186
711
        if (norm > new_norm) {
1187
350
      norm = new_norm;
1188
350
      tx = x;
1189
350
      ty = y;
1190
350
        }
1191
711
    }
1192
700
      }
1193
1194
350
      tx = floor (tx);
1195
350
      ty = floor (ty);
1196
350
      *x_offset = -tx;
1197
350
      *y_offset = -ty;
1198
350
      cairo_matrix_translate (&m, tx, ty);
1199
2.37k
  } else {
1200
2.37k
      *x_offset = 0;
1201
2.37k
      *y_offset = 0;
1202
2.37k
  }
1203
1204
2.72k
  return _cairo_matrix_to_pixman_matrix (&m, out_transform, xc, yc);
1205
2.72k
    }
1206
3.53k
}