1 /* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gscoord.c,v 1.9 2004/03/13 18:28:52 igor Exp $ */
18 /* Coordinate system operators for Ghostscript library */
19 #include "math_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsccode.h" /* for gxfont.h */
23 #include "gxfarith.h"
24 #include "gxfixed.h"
25 #include "gxmatrix.h"
26 #include "gxfont.h" /* for char_tm */
27 #include "gxpath.h" /* for gx_path_translate */
28 #include "gzstate.h"
29 #include "gxcoord.h" /* requires gsmatrix, gsstate */
30 #include "gxdevice.h"
31
32 /* Choose whether to enable the rounding code in update_ctm. */
33 #define ROUND_CTM_FIXED 1
34
35 /* Forward declarations */
36 #ifdef DEBUG
37 #define trace_ctm(pgs) trace_matrix_fixed(&(pgs)->ctm)
38 private void trace_matrix_fixed(const gs_matrix_fixed *);
39 private void trace_matrix(const gs_matrix *);
40
41 #endif
42
43 /* Macro for ensuring ctm_inverse is valid */
44 #ifdef DEBUG
45 # define print_inverse(pgs)\
46 if ( gs_debug_c('x') )\
47 dlprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
48 #else
49 # define print_inverse(pgs) DO_NOTHING
50 #endif
51 #define ensure_inverse_valid(pgs)\
52 if ( !pgs->ctm_inverse_valid )\
53 { int code = ctm_set_inverse(pgs);\
54 if ( code < 0 ) return code;\
55 }
56
57 private int
ctm_set_inverse(gs_state * pgs)58 ctm_set_inverse(gs_state * pgs)
59 {
60 int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
61
62 print_inverse(pgs);
63 if (code < 0)
64 return code;
65 pgs->ctm_inverse_valid = true;
66 return 0;
67 }
68
69 /* Machinery for updating fixed version of ctm. */
70 /*
71 * We (conditionally) adjust the floating point translation
72 * so that it exactly matches the (rounded) fixed translation.
73 * This avoids certain unpleasant rounding anomalies, such as
74 * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
75 * not returning 0 0.
76 */
77 #if ROUND_CTM_FIXED
78 # define update_t_fixed(mat, t, t_fixed, v)\
79 (set_float2fixed_vars((mat).t_fixed, v),\
80 set_fixed2float_var((mat).t, (mat).t_fixed))
81 #else /* !ROUND_CTM_FIXED */
82 # define update_t_fixed(mat, t, t_fixed, v)\
83 ((mat).t = (v),\
84 set_float2fixed_vars((mat).t_fixed, (mat).t))
85 #endif /* (!)ROUND_CTM_FIXED */
86 #define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
87 #define update_matrix_fixed(mat, xt, yt)\
88 ((mat).txy_fixed_valid = (f_fits_in_fixed(xt) && f_fits_in_fixed(yt) ?\
89 (update_t_fixed(mat, tx, tx_fixed, xt),\
90 update_t_fixed(mat, ty, ty_fixed, yt), true) :\
91 ((mat).tx = (xt), (mat).ty = (yt), false)))
92 #define update_ctm(pgs, xt, yt)\
93 (pgs->ctm_inverse_valid = false,\
94 pgs->char_tm_valid = false,\
95 update_matrix_fixed(pgs->ctm, xt, yt))
96
97 /* ------ Coordinate system definition ------ */
98
99 int
gs_initmatrix(gs_state * pgs)100 gs_initmatrix(gs_state * pgs)
101 {
102 gs_matrix imat;
103
104 gs_defaultmatrix(pgs, &imat);
105 update_ctm(pgs, imat.tx, imat.ty);
106 set_ctm_only(pgs, imat);
107 #ifdef DEBUG
108 if (gs_debug_c('x'))
109 dlprintf("[x]initmatrix:\n"), trace_ctm(pgs);
110 #endif
111 return 0;
112 }
113
114 int
gs_defaultmatrix(const gs_state * pgs,gs_matrix * pmat)115 gs_defaultmatrix(const gs_state * pgs, gs_matrix * pmat)
116 {
117 gx_device *dev;
118
119 if (pgs->ctm_default_set) { /* set after Install */
120 *pmat = pgs->ctm_default;
121 return 1;
122 }
123 dev = gs_currentdevice_inline(pgs);
124 gs_deviceinitialmatrix(dev, pmat);
125 /* Add in the translation for the Margins. */
126 pmat->tx += dev->Margins[0] *
127 dev->HWResolution[0] / dev->MarginsHWResolution[0];
128 pmat->ty += dev->Margins[1] *
129 dev->HWResolution[1] / dev->MarginsHWResolution[1];
130 return 0;
131 }
132
133 int
gs_setdefaultmatrix(gs_state * pgs,const gs_matrix * pmat)134 gs_setdefaultmatrix(gs_state * pgs, const gs_matrix * pmat)
135 {
136 if (pmat == NULL)
137 pgs->ctm_default_set = false;
138 else {
139 pgs->ctm_default = *pmat;
140 pgs->ctm_default_set = true;
141 }
142 return 0;
143 }
144
145 int
gs_currentmatrix(const gs_state * pgs,gs_matrix * pmat)146 gs_currentmatrix(const gs_state * pgs, gs_matrix * pmat)
147 {
148 *pmat = ctm_only(pgs);
149 return 0;
150 }
151
152 /* Set the current transformation matrix for rendering text. */
153 /* Note that this may be based on a font other than the current font. */
154 int
gs_setcharmatrix(gs_state * pgs,const gs_matrix * pmat)155 gs_setcharmatrix(gs_state * pgs, const gs_matrix * pmat)
156 {
157 gs_matrix cmat;
158 int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
159
160 if (code < 0)
161 return code;
162 update_matrix_fixed(pgs->char_tm, cmat.tx, cmat.ty);
163 char_tm_only(pgs) = cmat;
164 #ifdef DEBUG
165 if (gs_debug_c('x'))
166 dlprintf("[x]setting char_tm:"), trace_matrix_fixed(&pgs->char_tm);
167 #endif
168 pgs->char_tm_valid = true;
169 return 0;
170 }
171
172 /* Read (after possibly computing) the current transformation matrix */
173 /* for rendering text. If force=true, update char_tm if it is invalid; */
174 /* if force=false, don't update char_tm, and return an error code. */
175 int
gs_currentcharmatrix(gs_state * pgs,gs_matrix * ptm,bool force)176 gs_currentcharmatrix(gs_state * pgs, gs_matrix * ptm, bool force)
177 {
178 if (!pgs->char_tm_valid) {
179 int code;
180
181 if (!force)
182 return_error(gs_error_undefinedresult);
183 code = gs_setcharmatrix(pgs, &pgs->font->FontMatrix);
184 if (code < 0)
185 return code;
186 }
187 if (ptm != NULL)
188 *ptm = char_tm_only(pgs);
189 return 0;
190 }
191
192 int
gs_setmatrix(gs_state * pgs,const gs_matrix * pmat)193 gs_setmatrix(gs_state * pgs, const gs_matrix * pmat)
194 {
195 update_ctm(pgs, pmat->tx, pmat->ty);
196 set_ctm_only(pgs, *pmat);
197 #ifdef DEBUG
198 if (gs_debug_c('x'))
199 dlprintf("[x]setmatrix:\n"), trace_ctm(pgs);
200 #endif
201 return 0;
202 }
203
204 int
gs_imager_setmatrix(gs_imager_state * pis,const gs_matrix * pmat)205 gs_imager_setmatrix(gs_imager_state * pis, const gs_matrix * pmat)
206 {
207 update_matrix_fixed(pis->ctm, pmat->tx, pmat->ty);
208 set_ctm_only(pis, *pmat);
209 #ifdef DEBUG
210 if (gs_debug_c('x'))
211 dlprintf("[x]imager_setmatrix:\n"), trace_ctm(pis);
212 #endif
213 return 0;
214 }
215
216 int
gs_settocharmatrix(gs_state * pgs)217 gs_settocharmatrix(gs_state * pgs)
218 {
219 if (pgs->char_tm_valid) {
220 pgs->ctm = pgs->char_tm;
221 pgs->ctm_inverse_valid = false;
222 return 0;
223 } else
224 return_error(gs_error_undefinedresult);
225 }
226
227 int
gs_translate(gs_state * pgs,floatp dx,floatp dy)228 gs_translate(gs_state * pgs, floatp dx, floatp dy)
229 {
230 gs_point pt;
231 int code;
232
233 if ((code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0)
234 return code;
235 pt.x += pgs->ctm.tx;
236 pt.y += pgs->ctm.ty;
237 update_ctm(pgs, pt.x, pt.y);
238 #ifdef DEBUG
239 if (gs_debug_c('x'))
240 dlprintf4("[x]translate: %f %f -> %f %f\n",
241 dx, dy, pt.x, pt.y),
242 trace_ctm(pgs);
243 #endif
244 return 0;
245 }
246
247 int
gs_scale(gs_state * pgs,floatp sx,floatp sy)248 gs_scale(gs_state * pgs, floatp sx, floatp sy)
249 {
250 pgs->ctm.xx *= sx;
251 pgs->ctm.xy *= sx;
252 pgs->ctm.yx *= sy;
253 pgs->ctm.yy *= sy;
254 pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
255 #ifdef DEBUG
256 if (gs_debug_c('x'))
257 dlprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
258 #endif
259 return 0;
260 }
261
262 int
gs_rotate(gs_state * pgs,floatp ang)263 gs_rotate(gs_state * pgs, floatp ang)
264 {
265 int code = gs_matrix_rotate(&ctm_only(pgs), ang,
266 &ctm_only_writable(pgs));
267
268 pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
269 #ifdef DEBUG
270 if (gs_debug_c('x'))
271 dlprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
272 #endif
273 return code;
274 }
275
276 int
gs_concat(gs_state * pgs,const gs_matrix * pmat)277 gs_concat(gs_state * pgs, const gs_matrix * pmat)
278 {
279 gs_matrix cmat;
280 int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
281
282 if (code < 0)
283 return code;
284 update_ctm(pgs, cmat.tx, cmat.ty);
285 set_ctm_only(pgs, cmat);
286 #ifdef DEBUG
287 if (gs_debug_c('x'))
288 dlprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
289 #endif
290 return code;
291 }
292
293 /* ------ Coordinate transformation ------ */
294
295 #define is_skewed(pmat) (!(is_xxyy(pmat) || is_xyyx(pmat)))
296
297 int
gs_transform(gs_state * pgs,floatp x,floatp y,gs_point * pt)298 gs_transform(gs_state * pgs, floatp x, floatp y, gs_point * pt)
299 {
300 return gs_point_transform(x, y, &ctm_only(pgs), pt);
301 }
302
303 int
gs_dtransform(gs_state * pgs,floatp dx,floatp dy,gs_point * pt)304 gs_dtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
305 {
306 return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
307 }
308
309 int
gs_itransform(gs_state * pgs,floatp x,floatp y,gs_point * pt)310 gs_itransform(gs_state * pgs, floatp x, floatp y, gs_point * pt)
311 { /* If the matrix isn't skewed, we get more accurate results */
312 /* by using transform_inverse than by using the inverse matrix. */
313 if (!is_skewed(&pgs->ctm)) {
314 return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
315 } else {
316 ensure_inverse_valid(pgs);
317 return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
318 }
319 }
320
321 int
gs_idtransform(gs_state * pgs,floatp dx,floatp dy,gs_point * pt)322 gs_idtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
323 { /* If the matrix isn't skewed, we get more accurate results */
324 /* by using transform_inverse than by using the inverse matrix. */
325 if (!is_skewed(&pgs->ctm)) {
326 return gs_distance_transform_inverse(dx, dy,
327 &ctm_only(pgs), pt);
328 } else {
329 ensure_inverse_valid(pgs);
330 return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
331 }
332 }
333
334 int
gs_imager_idtransform(const gs_imager_state * pis,floatp dx,floatp dy,gs_point * pt)335 gs_imager_idtransform(const gs_imager_state * pis, floatp dx, floatp dy,
336 gs_point * pt)
337 {
338 return gs_distance_transform_inverse(dx, dy, &ctm_only(pis), pt);
339 }
340
341 /* ------ For internal use only ------ */
342
343 /* Set the translation to a fixed value, and translate any existing path. */
344 /* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
345 int
gx_translate_to_fixed(register gs_state * pgs,fixed px,fixed py)346 gx_translate_to_fixed(register gs_state * pgs, fixed px, fixed py)
347 {
348 double fpx = fixed2float(px);
349 double fdx = fpx - pgs->ctm.tx;
350 double fpy = fixed2float(py);
351 double fdy = fpy - pgs->ctm.ty;
352 fixed dx, dy;
353 int code;
354
355 if (pgs->ctm.txy_fixed_valid) {
356 dx = float2fixed(fdx);
357 dy = float2fixed(fdy);
358 code = gx_path_translate(pgs->path, dx, dy);
359 if (code < 0)
360 return code;
361 if (pgs->char_tm_valid && pgs->char_tm.txy_fixed_valid)
362 pgs->char_tm.tx_fixed += dx,
363 pgs->char_tm.ty_fixed += dy;
364 } else {
365 if (!gx_path_is_null(pgs->path))
366 return_error(gs_error_limitcheck);
367 }
368 pgs->ctm.tx = fpx;
369 pgs->ctm.tx_fixed = px;
370 pgs->ctm.ty = fpy;
371 pgs->ctm.ty_fixed = py;
372 pgs->ctm.txy_fixed_valid = true;
373 pgs->ctm_inverse_valid = false;
374 if (pgs->char_tm_valid) { /* Update char_tm now, leaving it valid. */
375 pgs->char_tm.tx += fdx;
376 pgs->char_tm.ty += fdy;
377 }
378 #ifdef DEBUG
379 if (gs_debug_c('x')) {
380 dlprintf2("[x]translate_to_fixed %g, %g:\n",
381 fixed2float(px), fixed2float(py));
382 trace_ctm(pgs);
383 dlprintf("[x] char_tm:\n");
384 trace_matrix_fixed(&pgs->char_tm);
385 }
386 #endif
387 gx_setcurrentpoint(pgs, fixed2float(pgs->ctm.tx_fixed), fixed2float(pgs->ctm.ty_fixed));
388 pgs->current_point_valid = true;
389 return 0;
390 }
391
392 /* Scale the CTM and character matrix for oversampling. */
393 int
gx_scale_char_matrix(register gs_state * pgs,int sx,int sy)394 gx_scale_char_matrix(register gs_state * pgs, int sx, int sy)
395 {
396 #define scale_cxy(s, vx, vy)\
397 if ( s != 1 )\
398 { pgs->ctm.vx *= s;\
399 pgs->ctm.vy *= s;\
400 pgs->ctm_inverse_valid = false;\
401 if ( pgs->char_tm_valid )\
402 { pgs->char_tm.vx *= s;\
403 pgs->char_tm.vy *= s;\
404 }\
405 }
406 scale_cxy(sx, xx, yx);
407 scale_cxy(sy, xy, yy);
408 #undef scale_cxy
409 if_debug2('x', "[x]char scale: %d %d\n", sx, sy);
410 return 0;
411 }
412
413 /* Compute the coefficients for fast fixed-point distance transformations */
414 /* from a transformation matrix. */
415 /* We should cache the coefficients with the ctm.... */
416 int
gx_matrix_to_fixed_coeff(const gs_matrix * pmat,register fixed_coeff * pfc,int max_bits)417 gx_matrix_to_fixed_coeff(const gs_matrix * pmat, register fixed_coeff * pfc,
418 int max_bits)
419 {
420 gs_matrix ctm;
421 int scale = -10000;
422 int expt, shift;
423
424 ctm = *pmat;
425 pfc->skewed = 0;
426 if (!is_fzero(ctm.xx)) {
427 discard(frexp(ctm.xx, &scale));
428 }
429 if (!is_fzero(ctm.xy)) {
430 discard(frexp(ctm.xy, &expt));
431 if (expt > scale)
432 scale = expt;
433 pfc->skewed = 1;
434 }
435 if (!is_fzero(ctm.yx)) {
436 discard(frexp(ctm.yx, &expt));
437 if (expt > scale)
438 scale = expt;
439 pfc->skewed = 1;
440 }
441 if (!is_fzero(ctm.yy)) {
442 discard(frexp(ctm.yy, &expt));
443 if (expt > scale)
444 scale = expt;
445 }
446 /*
447 * There are two multiplications in fixed_coeff_mult: one involves a
448 * factor that may have max_bits significant bits, the other may have
449 * fixed_fraction_bits (_fixed_shift) bits. Ensure that neither one
450 * will overflow.
451 */
452 if (max_bits < fixed_fraction_bits)
453 max_bits = fixed_fraction_bits;
454 scale = sizeof(long) * 8 - 1 - max_bits - scale;
455
456 shift = scale - _fixed_shift;
457 if (shift > 0) {
458 pfc->shift = shift;
459 pfc->round = (fixed) 1 << (shift - 1);
460 } else {
461 pfc->shift = 0;
462 pfc->round = 0;
463 scale -= shift;
464 }
465 #define SET_C(c)\
466 if ( is_fzero(ctm.c) ) pfc->c = 0;\
467 else pfc->c = (long)ldexp(ctm.c, scale)
468 SET_C(xx);
469 SET_C(xy);
470 SET_C(yx);
471 SET_C(yy);
472 #undef SET_C
473 #ifdef DEBUG
474 if (gs_debug_c('x')) {
475 dlprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n",
476 ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty);
477 dlprintf6(" scale=%d fc: [0x%lx 0x%lx 0x%lx 0x%lx] shift=%d\n",
478 scale, pfc->xx, pfc->xy, pfc->yx, pfc->yy,
479 pfc->shift);
480 }
481 #endif
482 pfc->max_bits = max_bits;
483 return 0;
484 }
485
486 /*
487 * Handle the case of a large value or a value with a fraction part.
488 * See gxmatrix.h for more details.
489 */
490 fixed
fixed_coeff_mult(fixed value,long coeff,const fixed_coeff * pfc,int maxb)491 fixed_coeff_mult(fixed value, long coeff, const fixed_coeff *pfc, int maxb)
492 {
493 int shift = pfc->shift;
494
495 /*
496 * Test if the value is too large for simple long math.
497 */
498 if ((value + (fixed_1 << (maxb - 1))) & (-fixed_1 << maxb)) {
499 /* The second argument of fixed_mult_quo must be non-negative. */
500 return
501 (coeff < 0 ?
502 -fixed_mult_quo(value, -coeff, fixed_1 << shift) :
503 fixed_mult_quo(value, coeff, fixed_1 << shift));
504 } else {
505 /*
506 * The construction above guarantees that the multiplications
507 * won't overflow the capacity of an int.
508 */
509 return (fixed)
510 arith_rshift(fixed2int_var(value) * coeff
511 + fixed2int(fixed_fraction(value) * coeff)
512 + pfc->round, shift);
513 }
514 }
515
516 /* ------ Debugging printout ------ */
517
518 #ifdef DEBUG
519
520 /* Print a matrix */
521 private void
trace_matrix_fixed(const gs_matrix_fixed * pmat)522 trace_matrix_fixed(const gs_matrix_fixed * pmat)
523 {
524 trace_matrix((const gs_matrix *)pmat);
525 if (pmat->txy_fixed_valid) {
526 dprintf2("\t\tt_fixed: [%6g %6g]\n",
527 fixed2float(pmat->tx_fixed),
528 fixed2float(pmat->ty_fixed));
529 } else {
530 dputs("\t\tt_fixed not valid\n");
531 }
532 }
533 private void
trace_matrix(register const gs_matrix * pmat)534 trace_matrix(register const gs_matrix * pmat)
535 {
536 dlprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
537 pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
538 }
539
540 #endif
541