Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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