1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gscoord.c 8250 2007-09-25 13:31:24Z giles $ */
15
/* Coordinate system operators for Ghostscript library */
19
#include "gsccode.h" /* for gxfont.h */
23
#include "gxfont.h" /* for char_tm */
24
#include "gxpath.h" /* for gx_path_translate */
26
#include "gxcoord.h" /* requires gsmatrix, gsstate */
29
/* Choose whether to enable the rounding code in update_ctm. */
30
#define ROUND_CTM_FIXED 0
32
/* Forward declarations */
34
#define trace_ctm(pgs) trace_matrix_fixed(&(pgs)->ctm)
35
static void trace_matrix_fixed(const gs_matrix_fixed *);
36
static void trace_matrix(const gs_matrix *);
40
/* Macro for ensuring ctm_inverse is valid */
42
# define print_inverse(pgs)\
43
if ( gs_debug_c('x') )\
44
dlprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
46
# define print_inverse(pgs) DO_NOTHING
48
#define ensure_inverse_valid(pgs)\
49
if ( !pgs->ctm_inverse_valid )\
50
{ int code = ctm_set_inverse(pgs);\
51
if ( code < 0 ) return code;\
55
ctm_set_inverse(gs_state * pgs)
57
int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
62
pgs->ctm_inverse_valid = true;
66
/* Machinery for updating fixed version of ctm. */
68
* We (conditionally) adjust the floating point translation
69
* so that it exactly matches the (rounded) fixed translation.
70
* This avoids certain unpleasant rounding anomalies, such as
71
* 0 0 moveto currentpoint not returning 0 0, and () stringwidth
75
# define update_t_fixed(mat, t, t_fixed, v)\
76
(set_float2fixed_vars((mat).t_fixed, v),\
77
set_fixed2float_var((mat).t, (mat).t_fixed))
78
#else /* !ROUND_CTM_FIXED */
79
# define update_t_fixed(mat, t, t_fixed, v)\
81
set_float2fixed_vars((mat).t_fixed, (mat).t))
82
#endif /* (!)ROUND_CTM_FIXED */
83
#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
84
#define update_matrix_fixed(mat, xt, yt)\
85
((mat).txy_fixed_valid = (f_fits_in_fixed(xt) && f_fits_in_fixed(yt) ?\
86
(update_t_fixed(mat, tx, tx_fixed, xt),\
87
update_t_fixed(mat, ty, ty_fixed, yt), true) :\
88
((mat).tx = (xt), (mat).ty = (yt), false)))
89
#define update_ctm(pgs, xt, yt)\
90
(pgs->ctm_inverse_valid = false,\
91
pgs->char_tm_valid = false,\
92
update_matrix_fixed(pgs->ctm, xt, yt))
94
/* ------ Coordinate system definition ------ */
97
gs_initmatrix(gs_state * pgs)
101
gs_defaultmatrix(pgs, &imat);
102
update_ctm(pgs, imat.tx, imat.ty);
103
set_ctm_only(pgs, imat);
106
dlprintf("[x]initmatrix:\n"), trace_ctm(pgs);
112
gs_defaultmatrix(const gs_state * pgs, gs_matrix * pmat)
116
if (pgs->ctm_default_set) { /* set after Install */
117
*pmat = pgs->ctm_default;
120
dev = gs_currentdevice_inline(pgs);
121
gs_deviceinitialmatrix(dev, pmat);
122
/* Add in the translation for the Margins. */
123
pmat->tx += dev->Margins[0] *
124
dev->HWResolution[0] / dev->MarginsHWResolution[0];
125
pmat->ty += dev->Margins[1] *
126
dev->HWResolution[1] / dev->MarginsHWResolution[1];
131
gs_setdefaultmatrix(gs_state * pgs, const gs_matrix * pmat)
134
pgs->ctm_default_set = false;
136
pgs->ctm_default = *pmat;
137
pgs->ctm_default_set = true;
143
gs_currentmatrix(const gs_state * pgs, gs_matrix * pmat)
145
*pmat = ctm_only(pgs);
149
/* Set the current transformation matrix for rendering text. */
150
/* Note that this may be based on a font other than the current font. */
152
gs_setcharmatrix(gs_state * pgs, const gs_matrix * pmat)
155
int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
159
update_matrix_fixed(pgs->char_tm, cmat.tx, cmat.ty);
160
char_tm_only(pgs) = cmat;
163
dlprintf("[x]setting char_tm:"), trace_matrix_fixed(&pgs->char_tm);
165
pgs->char_tm_valid = true;
169
/* Read (after possibly computing) the current transformation matrix */
170
/* for rendering text. If force=true, update char_tm if it is invalid; */
171
/* if force=false, don't update char_tm, and return an error code. */
173
gs_currentcharmatrix(gs_state * pgs, gs_matrix * ptm, bool force)
175
if (!pgs->char_tm_valid) {
179
return_error(gs_error_undefinedresult);
180
code = gs_setcharmatrix(pgs, &pgs->font->FontMatrix);
185
*ptm = char_tm_only(pgs);
190
gs_setmatrix(gs_state * pgs, const gs_matrix * pmat)
192
update_ctm(pgs, pmat->tx, pmat->ty);
193
set_ctm_only(pgs, *pmat);
196
dlprintf("[x]setmatrix:\n"), trace_ctm(pgs);
202
gs_imager_setmatrix(gs_imager_state * pis, const gs_matrix * pmat)
204
update_matrix_fixed(pis->ctm, pmat->tx, pmat->ty);
205
set_ctm_only(pis, *pmat);
208
dlprintf("[x]imager_setmatrix:\n"), trace_ctm(pis);
214
gs_settocharmatrix(gs_state * pgs)
216
if (pgs->char_tm_valid) {
217
pgs->ctm = pgs->char_tm;
218
pgs->ctm_inverse_valid = false;
221
return_error(gs_error_undefinedresult);
225
gs_translate(gs_state * pgs, floatp dx, floatp dy)
230
if ((code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0)
232
pt.x = (float)pt.x + pgs->ctm.tx;
233
pt.y = (float)pt.y + pgs->ctm.ty;
234
update_ctm(pgs, pt.x, pt.y);
237
dlprintf4("[x]translate: %f %f -> %f %f\n",
245
gs_scale(gs_state * pgs, floatp sx, floatp sy)
251
pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
254
dlprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
260
gs_rotate(gs_state * pgs, floatp ang)
262
int code = gs_matrix_rotate(&ctm_only(pgs), ang,
263
&ctm_only_writable(pgs));
265
pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
268
dlprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
274
gs_concat(gs_state * pgs, const gs_matrix * pmat)
277
int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
281
update_ctm(pgs, cmat.tx, cmat.ty);
282
set_ctm_only(pgs, cmat);
285
dlprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
290
/* ------ Coordinate transformation ------ */
292
#define is_skewed(pmat) (!(is_xxyy(pmat) || is_xyyx(pmat)))
295
gs_transform(gs_state * pgs, floatp x, floatp y, gs_point * pt)
297
return gs_point_transform(x, y, &ctm_only(pgs), pt);
301
gs_dtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
303
return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
307
gs_itransform(gs_state * pgs, floatp x, floatp y, gs_point * pt)
308
{ /* If the matrix isn't skewed, we get more accurate results */
309
/* by using transform_inverse than by using the inverse matrix. */
310
if (!is_skewed(&pgs->ctm)) {
311
return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
313
ensure_inverse_valid(pgs);
314
return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
319
gs_idtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
320
{ /* If the matrix isn't skewed, we get more accurate results */
321
/* by using transform_inverse than by using the inverse matrix. */
322
if (!is_skewed(&pgs->ctm)) {
323
return gs_distance_transform_inverse(dx, dy,
326
ensure_inverse_valid(pgs);
327
return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
332
gs_imager_idtransform(const gs_imager_state * pis, floatp dx, floatp dy,
335
return gs_distance_transform_inverse(dx, dy, &ctm_only(pis), pt);
338
/* ------ For internal use only ------ */
340
/* Set the translation to a fixed value, and translate any existing path. */
341
/* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
343
gx_translate_to_fixed(register gs_state * pgs, fixed px, fixed py)
345
double fpx = fixed2float(px);
346
double fdx = fpx - pgs->ctm.tx;
347
double fpy = fixed2float(py);
348
double fdy = fpy - pgs->ctm.ty;
352
if (pgs->ctm.txy_fixed_valid) {
353
dx = float2fixed(fdx);
354
dy = float2fixed(fdy);
355
code = gx_path_translate(pgs->path, dx, dy);
358
if (pgs->char_tm_valid && pgs->char_tm.txy_fixed_valid)
359
pgs->char_tm.tx_fixed += dx,
360
pgs->char_tm.ty_fixed += dy;
362
if (!gx_path_is_null(pgs->path))
363
return_error(gs_error_limitcheck);
366
pgs->ctm.tx_fixed = px;
368
pgs->ctm.ty_fixed = py;
369
pgs->ctm.txy_fixed_valid = true;
370
pgs->ctm_inverse_valid = false;
371
if (pgs->char_tm_valid) { /* Update char_tm now, leaving it valid. */
372
pgs->char_tm.tx += fdx;
373
pgs->char_tm.ty += fdy;
376
if (gs_debug_c('x')) {
377
dlprintf2("[x]translate_to_fixed %g, %g:\n",
378
fixed2float(px), fixed2float(py));
380
dlprintf("[x] char_tm:\n");
381
trace_matrix_fixed(&pgs->char_tm);
384
gx_setcurrentpoint(pgs, fixed2float(pgs->ctm.tx_fixed), fixed2float(pgs->ctm.ty_fixed));
385
pgs->current_point_valid = true;
389
/* Scale the CTM and character matrix for oversampling. */
391
gx_scale_char_matrix(register gs_state * pgs, int sx, int sy)
393
#define scale_cxy(s, vx, vy)\
397
pgs->ctm_inverse_valid = false;\
398
if ( pgs->char_tm_valid )\
399
{ pgs->char_tm.vx *= s;\
400
pgs->char_tm.vy *= s;\
403
scale_cxy(sx, xx, yx);
404
scale_cxy(sy, xy, yy);
406
if_debug2('x', "[x]char scale: %d %d\n", sx, sy);
410
/* Compute the coefficients for fast fixed-point distance transformations */
411
/* from a transformation matrix. */
412
/* We should cache the coefficients with the ctm.... */
414
gx_matrix_to_fixed_coeff(const gs_matrix * pmat, register fixed_coeff * pfc,
423
if (!is_fzero(ctm.xx)) {
424
discard(frexp(ctm.xx, &scale));
426
if (!is_fzero(ctm.xy)) {
427
discard(frexp(ctm.xy, &expt));
432
if (!is_fzero(ctm.yx)) {
433
discard(frexp(ctm.yx, &expt));
438
if (!is_fzero(ctm.yy)) {
439
discard(frexp(ctm.yy, &expt));
444
* There are two multiplications in fixed_coeff_mult: one involves a
445
* factor that may have max_bits significant bits, the other may have
446
* fixed_fraction_bits (_fixed_shift) bits. Ensure that neither one
449
if (max_bits < fixed_fraction_bits)
450
max_bits = fixed_fraction_bits;
451
scale = sizeof(long) * 8 - 1 - max_bits - scale;
453
shift = scale - _fixed_shift;
456
pfc->round = (fixed) 1 << (shift - 1);
463
if ( is_fzero(ctm.c) ) pfc->c = 0;\
464
else pfc->c = (long)ldexp(ctm.c, scale)
471
if (gs_debug_c('x')) {
472
dlprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n",
473
ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty);
474
dlprintf6(" scale=%d fc: [0x%lx 0x%lx 0x%lx 0x%lx] shift=%d\n",
475
scale, pfc->xx, pfc->xy, pfc->yx, pfc->yy,
479
pfc->max_bits = max_bits;
484
* Handle the case of a large value or a value with a fraction part.
485
* See gxmatrix.h for more details.
488
fixed_coeff_mult(fixed value, long coeff, const fixed_coeff *pfc, int maxb)
490
int shift = pfc->shift;
493
* Test if the value is too large for simple long math.
495
if ((value + (fixed_1 << (maxb - 1))) & (-fixed_1 << maxb)) {
496
/* The second argument of fixed_mult_quo must be non-negative. */
499
-fixed_mult_quo(value, -coeff, fixed_1 << shift) :
500
fixed_mult_quo(value, coeff, fixed_1 << shift));
503
* The construction above guarantees that the multiplications
504
* won't overflow the capacity of an int.
507
arith_rshift(fixed2int_var(value) * coeff
508
+ fixed2int(fixed_fraction(value) * coeff)
509
+ pfc->round, shift);
513
/* ------ Debugging printout ------ */
519
trace_matrix_fixed(const gs_matrix_fixed * pmat)
521
trace_matrix((const gs_matrix *)pmat);
522
if (pmat->txy_fixed_valid) {
523
dprintf2("\t\tt_fixed: [%6g %6g]\n",
524
fixed2float(pmat->tx_fixed),
525
fixed2float(pmat->ty_fixed));
527
dputs("\t\tt_fixed not valid\n");
531
trace_matrix(register const gs_matrix * pmat)
533
dlprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
534
pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);