Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/cmd/gs/src/gsmatrix.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 1995, 1996, 1998, 1999 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: gsmatrix.c,v 1.8 2004/08/31 13:23:16 igor Exp $ */
18
/* Matrix operators for Ghostscript library */
19
#include "math_.h"
20
#include "memory_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gxfarith.h"
24
#include "gxfixed.h"
25
#include "gxmatrix.h"
26
#include "stream.h"
27
 
28
/* The identity matrix */
29
private const gs_matrix gs_identity_matrix =
30
{identity_matrix_body};
31
 
32
/* ------ Matrix creation ------ */
33
 
34
/* Create an identity matrix */
35
void
36
gs_make_identity(gs_matrix * pmat)
37
{
38
    *pmat = gs_identity_matrix;
39
}
40
 
41
/* Create a translation matrix */
42
int
43
gs_make_translation(floatp dx, floatp dy, gs_matrix * pmat)
44
{
45
    *pmat = gs_identity_matrix;
46
    pmat->tx = dx;
47
    pmat->ty = dy;
48
    return 0;
49
}
50
 
51
/* Create a scaling matrix */
52
int
53
gs_make_scaling(floatp sx, floatp sy, gs_matrix * pmat)
54
{
55
    *pmat = gs_identity_matrix;
56
    pmat->xx = sx;
57
    pmat->yy = sy;
58
    return 0;
59
}
60
 
61
/* Create a rotation matrix. */
62
/* The angle is in degrees. */
63
int
64
gs_make_rotation(floatp ang, gs_matrix * pmat)
65
{
66
    gs_sincos_t sincos;
67
 
68
    gs_sincos_degrees(ang, &sincos);
69
    pmat->yy = pmat->xx = sincos.cos;
70
    pmat->xy = sincos.sin;
71
    pmat->yx = -sincos.sin;
72
    pmat->tx = pmat->ty = 0.0;
73
    return 0;
74
}
75
 
76
/* ------ Matrix arithmetic ------ */
77
 
78
/* Multiply two matrices.  We should check for floating exceptions, */
79
/* but for the moment it's just too awkward. */
80
/* Since this is used heavily, we check for shortcuts. */
81
int
82
gs_matrix_multiply(const gs_matrix * pm1, const gs_matrix * pm2, gs_matrix * pmr)
83
{
84
    double xx1 = pm1->xx, yy1 = pm1->yy;
85
    double tx1 = pm1->tx, ty1 = pm1->ty;
86
    double xx2 = pm2->xx, yy2 = pm2->yy;
87
    double xy2 = pm2->xy, yx2 = pm2->yx;
88
 
89
    if (is_xxyy(pm1)) {
90
	pmr->tx = tx1 * xx2 + pm2->tx;
91
	pmr->ty = ty1 * yy2 + pm2->ty;
92
	if (is_fzero(xy2))
93
	    pmr->xy = 0;
94
	else
95
	    pmr->xy = xx1 * xy2,
96
		pmr->ty += tx1 * xy2;
97
	pmr->xx = xx1 * xx2;
98
	if (is_fzero(yx2))
99
	    pmr->yx = 0;
100
	else
101
	    pmr->yx = yy1 * yx2,
102
		pmr->tx += ty1 * yx2;
103
	pmr->yy = yy1 * yy2;
104
    } else {
105
	double xy1 = pm1->xy, yx1 = pm1->yx;
106
 
107
	pmr->xx = xx1 * xx2 + xy1 * yx2;
108
	pmr->xy = xx1 * xy2 + xy1 * yy2;
109
	pmr->yy = yx1 * xy2 + yy1 * yy2;
110
	pmr->yx = yx1 * xx2 + yy1 * yx2;
111
	pmr->tx = tx1 * xx2 + ty1 * yx2 + pm2->tx;
112
	pmr->ty = tx1 * xy2 + ty1 * yy2 + pm2->ty;
113
    }
114
    return 0;
115
}
116
 
117
/* Invert a matrix.  Return gs_error_undefinedresult if not invertible. */
118
int
119
gs_matrix_invert(const gs_matrix * pm, gs_matrix * pmr)
120
{				/* We have to be careful about fetch/store order, */
121
    /* because pm might be the same as pmr. */
122
    if (is_xxyy(pm)) {
123
	if (is_fzero(pm->xx) || is_fzero(pm->yy))
124
	    return_error(gs_error_undefinedresult);
125
	pmr->tx = -(pmr->xx = 1.0 / pm->xx) * pm->tx;
126
	pmr->xy = 0.0;
127
	pmr->yx = 0.0;
128
	pmr->ty = -(pmr->yy = 1.0 / pm->yy) * pm->ty;
129
    } else {
130
	double det = pm->xx * pm->yy - pm->xy * pm->yx;
131
	double mxx = pm->xx, mtx = pm->tx;
132
 
133
	if (det == 0)
134
	    return_error(gs_error_undefinedresult);
135
	pmr->xx = pm->yy / det;
136
	pmr->xy = -pm->xy / det;
137
	pmr->yx = -pm->yx / det;
138
	pmr->yy = mxx / det;	/* xx is already changed */
139
	pmr->tx = -(mtx * pmr->xx + pm->ty * pmr->yx);
140
	pmr->ty = -(mtx * pmr->xy + pm->ty * pmr->yy);	/* tx ditto */
141
    }
142
    return 0;
143
}
144
 
145
/* Translate a matrix, possibly in place. */
146
int
147
gs_matrix_translate(const gs_matrix * pm, floatp dx, floatp dy, gs_matrix * pmr)
148
{
149
    gs_point trans;
150
    int code = gs_distance_transform(dx, dy, pm, &trans);
151
 
152
    if (code < 0)
153
	return code;
154
    if (pmr != pm)
155
	*pmr = *pm;
156
    pmr->tx += trans.x;
157
    pmr->ty += trans.y;
158
    return 0;
159
}
160
 
161
/* Scale a matrix, possibly in place. */
162
int
163
gs_matrix_scale(const gs_matrix * pm, floatp sx, floatp sy, gs_matrix * pmr)
164
{
165
    pmr->xx = pm->xx * sx;
166
    pmr->xy = pm->xy * sx;
167
    pmr->yx = pm->yx * sy;
168
    pmr->yy = pm->yy * sy;
169
    if (pmr != pm) {
170
	pmr->tx = pm->tx;
171
	pmr->ty = pm->ty;
172
    }
173
    return 0;
174
}
175
 
176
/* Rotate a matrix, possibly in place.  The angle is in degrees. */
177
int
178
gs_matrix_rotate(const gs_matrix * pm, floatp ang, gs_matrix * pmr)
179
{
180
    double mxx, mxy;
181
    gs_sincos_t sincos;
182
 
183
    gs_sincos_degrees(ang, &sincos);
184
    mxx = pm->xx, mxy = pm->xy;
185
    pmr->xx = sincos.cos * mxx + sincos.sin * pm->yx;
186
    pmr->xy = sincos.cos * mxy + sincos.sin * pm->yy;
187
    pmr->yx = sincos.cos * pm->yx - sincos.sin * mxx;
188
    pmr->yy = sincos.cos * pm->yy - sincos.sin * mxy;
189
    if (pmr != pm) {
190
	pmr->tx = pm->tx;
191
	pmr->ty = pm->ty;
192
    }
193
    return 0;
194
}
195
 
196
/* ------ Coordinate transformations (floating point) ------ */
197
 
198
/* Note that all the transformation routines take separate */
199
/* x and y arguments, but return their result in a point. */
200
 
201
/* Transform a point. */
202
int
203
gs_point_transform(floatp x, floatp y, const gs_matrix * pmat,
204
		   gs_point * ppt)
205
{
206
    ppt->x = x * pmat->xx + pmat->tx;
207
    ppt->y = y * pmat->yy + pmat->ty;
208
    if (!is_fzero(pmat->yx))
209
	ppt->x += y * pmat->yx;
210
    if (!is_fzero(pmat->xy))
211
	ppt->y += x * pmat->xy;
212
    return 0;
213
}
214
 
215
/* Inverse-transform a point. */
216
/* Return gs_error_undefinedresult if the matrix is not invertible. */
217
int
218
gs_point_transform_inverse(floatp x, floatp y, const gs_matrix * pmat,
219
			   gs_point * ppt)
220
{
221
    if (is_xxyy(pmat)) {
222
	if (is_fzero(pmat->xx) || is_fzero(pmat->yy))
223
	    return_error(gs_error_undefinedresult);
224
	ppt->x = (x - pmat->tx) / pmat->xx;
225
	ppt->y = (y - pmat->ty) / pmat->yy;
226
	return 0;
227
    } else if (is_xyyx(pmat)) {
228
	if (is_fzero(pmat->xy) || is_fzero(pmat->yx))
229
	    return_error(gs_error_undefinedresult);
230
	ppt->x = (y - pmat->ty) / pmat->xy;
231
	ppt->y = (x - pmat->tx) / pmat->yx;
232
	return 0;
233
    } else {			/* There are faster ways to do this, */
234
	/* but we won't implement one unless we have to. */
235
	gs_matrix imat;
236
	int code = gs_matrix_invert(pmat, &imat);
237
 
238
	if (code < 0)
239
	    return code;
240
	return gs_point_transform(x, y, &imat, ppt);
241
    }
242
}
243
 
244
/* Transform a distance. */
245
int
246
gs_distance_transform(floatp dx, floatp dy, const gs_matrix * pmat,
247
		      gs_point * pdpt)
248
{
249
    pdpt->x = dx * pmat->xx;
250
    pdpt->y = dy * pmat->yy;
251
    if (!is_fzero(pmat->yx))
252
	pdpt->x += dy * pmat->yx;
253
    if (!is_fzero(pmat->xy))
254
	pdpt->y += dx * pmat->xy;
255
    return 0;
256
}
257
 
258
/* Inverse-transform a distance. */
259
/* Return gs_error_undefinedresult if the matrix is not invertible. */
260
int
261
gs_distance_transform_inverse(floatp dx, floatp dy,
262
			      const gs_matrix * pmat, gs_point * pdpt)
263
{
264
    if (is_xxyy(pmat)) {
265
	if (is_fzero(pmat->xx) || is_fzero(pmat->yy))
266
	    return_error(gs_error_undefinedresult);
267
	pdpt->x = dx / pmat->xx;
268
	pdpt->y = dy / pmat->yy;
269
    } else if (is_xyyx(pmat)) {
270
	if (is_fzero(pmat->xy) || is_fzero(pmat->yx))
271
	    return_error(gs_error_undefinedresult);
272
	pdpt->x = dy / pmat->xy;
273
	pdpt->y = dx / pmat->yx;
274
    } else {
275
	double det = pmat->xx * pmat->yy - pmat->xy * pmat->yx;
276
 
277
	if (det == 0)
278
	    return_error(gs_error_undefinedresult);
279
	pdpt->x = (dx * pmat->yy - dy * pmat->yx) / det;
280
	pdpt->y = (dy * pmat->xx - dx * pmat->xy) / det;
281
    }
282
    return 0;
283
}
284
 
285
/* Compute the bounding box of 4 points. */
286
int
287
gs_points_bbox(const gs_point pts[4], gs_rect * pbox)
288
{
289
#define assign_min_max(vmin, vmax, v0, v1)\
290
  if ( v0 < v1 ) vmin = v0, vmax = v1; else vmin = v1, vmax = v0
291
#define assign_min_max_4(vmin, vmax, v0, v1, v2, v3)\
292
  { double min01, max01, min23, max23;\
293
    assign_min_max(min01, max01, v0, v1);\
294
    assign_min_max(min23, max23, v2, v3);\
295
    vmin = min(min01, min23);\
296
    vmax = max(max01, max23);\
297
  }
298
    assign_min_max_4(pbox->p.x, pbox->q.x,
299
		     pts[0].x, pts[1].x, pts[2].x, pts[3].x);
300
    assign_min_max_4(pbox->p.y, pbox->q.y,
301
		     pts[0].y, pts[1].y, pts[2].y, pts[3].y);
302
#undef assign_min_max
303
#undef assign_min_max_4
304
    return 0;
305
}
306
 
307
/* Transform or inverse-transform a bounding box. */
308
/* Return gs_error_undefinedresult if the matrix is not invertible. */
309
private int
310
bbox_transform_either_only(const gs_rect * pbox_in, const gs_matrix * pmat,
311
			   gs_point pts[4],
312
     int (*point_xform) (floatp, floatp, const gs_matrix *, gs_point *))
313
{
314
    int code;
315
 
316
    if ((code = (*point_xform) (pbox_in->p.x, pbox_in->p.y, pmat, &pts[0])) < 0 ||
317
	(code = (*point_xform) (pbox_in->p.x, pbox_in->q.y, pmat, &pts[1])) < 0 ||
318
	(code = (*point_xform) (pbox_in->q.x, pbox_in->p.y, pmat, &pts[2])) < 0 ||
319
     (code = (*point_xform) (pbox_in->q.x, pbox_in->q.y, pmat, &pts[3])) < 0
320
	)
321
	DO_NOTHING;
322
    return code;
323
}
324
 
325
private int
326
bbox_transform_either(const gs_rect * pbox_in, const gs_matrix * pmat,
327
		      gs_rect * pbox_out,
328
     int (*point_xform) (floatp, floatp, const gs_matrix *, gs_point *))
329
{
330
    int code;
331
 
332
    /*
333
     * In principle, we could transform only one point and two
334
     * distance vectors; however, because of rounding, we will only
335
     * get fully consistent results if we transform all 4 points.
336
     * We must compute the max and min after transforming,
337
     * since a rotation may be involved.
338
     */
339
    gs_point pts[4];
340
 
341
    if ((code = bbox_transform_either_only(pbox_in, pmat, pts, point_xform)) < 0)
342
	return code;
343
    return gs_points_bbox(pts, pbox_out);
344
}
345
int
346
gs_bbox_transform(const gs_rect * pbox_in, const gs_matrix * pmat,
347
		  gs_rect * pbox_out)
348
{
349
    return bbox_transform_either(pbox_in, pmat, pbox_out,
350
				 gs_point_transform);
351
}
352
int
353
gs_bbox_transform_only(const gs_rect * pbox_in, const gs_matrix * pmat,
354
		       gs_point points[4])
355
{
356
    return bbox_transform_either_only(pbox_in, pmat, points,
357
				      gs_point_transform);
358
}
359
int
360
gs_bbox_transform_inverse(const gs_rect * pbox_in, const gs_matrix * pmat,
361
			  gs_rect * pbox_out)
362
{
363
    return bbox_transform_either(pbox_in, pmat, pbox_out,
364
				 gs_point_transform_inverse);
365
}
366
 
367
/* ------ Coordinate transformations (to fixed point) ------ */
368
 
369
#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
370
 
371
/* Make a gs_matrix_fixed from a gs_matrix. */
372
int
373
gs_matrix_fixed_from_matrix(gs_matrix_fixed *pfmat, const gs_matrix *pmat)
374
{
375
    *(gs_matrix *)pfmat = *pmat;
376
    if (f_fits_in_fixed(pmat->tx) && f_fits_in_fixed(pmat->ty)) {
377
	pfmat->tx = fixed2float(pfmat->tx_fixed = float2fixed(pmat->tx));
378
	pfmat->ty = fixed2float(pfmat->ty_fixed = float2fixed(pmat->ty));
379
	pfmat->txy_fixed_valid = true;
380
    } else {
381
	pfmat->txy_fixed_valid = false;
382
    }
383
    return 0;
384
}
385
 
386
/* Transform a point with a fixed-point result. */
387
int
388
gs_point_transform2fixed(const gs_matrix_fixed * pmat,
389
			 floatp x, floatp y, gs_fixed_point * ppt)
390
{
391
    fixed px, py, t;
392
    double xtemp, ytemp;
393
    int code;
394
 
395
    if (!pmat->txy_fixed_valid) {	/* The translation is out of range.  Do the */
396
	/* computation in floating point, and convert to */
397
	/* fixed at the end. */
398
	gs_point fpt;
399
 
400
	gs_point_transform(x, y, (const gs_matrix *)pmat, &fpt);
401
	if (!(f_fits_in_fixed(fpt.x) && f_fits_in_fixed(fpt.y)))
402
	    return_error(gs_error_limitcheck);
403
	ppt->x = float2fixed(fpt.x);
404
	ppt->y = float2fixed(fpt.y);
405
	return 0;
406
    }
407
    if (!is_fzero(pmat->xy)) {	/* Hope for 90 degree rotation */
408
	if ((code = CHECK_DFMUL2FIXED_VARS(px, y, pmat->yx, xtemp)) < 0 ||
409
	    (code = CHECK_DFMUL2FIXED_VARS(py, x, pmat->xy, ytemp)) < 0
410
	    )
411
	    return code;
412
	FINISH_DFMUL2FIXED_VARS(px, xtemp);
413
	FINISH_DFMUL2FIXED_VARS(py, ytemp);
414
	if (!is_fzero(pmat->xx)) {
415
	    if ((code = CHECK_DFMUL2FIXED_VARS(t, x, pmat->xx, xtemp)) < 0)
416
		return code;
417
	    FINISH_DFMUL2FIXED_VARS(t, xtemp);
418
	    if ((code = CHECK_SET_FIXED_SUM(px, px, t)) < 0)
419
	        return code;
420
	}
421
	if (!is_fzero(pmat->yy)) {
422
	    if ((code = CHECK_DFMUL2FIXED_VARS(t, y, pmat->yy, ytemp)) < 0)
423
		return code;
424
	    FINISH_DFMUL2FIXED_VARS(t, ytemp);
425
	    if ((code = CHECK_SET_FIXED_SUM(py, py, t)) < 0)
426
	        return code;
427
	}
428
    } else {
429
	if ((code = CHECK_DFMUL2FIXED_VARS(px, x, pmat->xx, xtemp)) < 0 ||
430
	    (code = CHECK_DFMUL2FIXED_VARS(py, y, pmat->yy, ytemp)) < 0
431
	    )
432
	    return code;
433
	FINISH_DFMUL2FIXED_VARS(px, xtemp);
434
	FINISH_DFMUL2FIXED_VARS(py, ytemp);
435
	if (!is_fzero(pmat->yx)) {
436
	    if ((code = CHECK_DFMUL2FIXED_VARS(t, y, pmat->yx, ytemp)) < 0)
437
		return code;
438
	    FINISH_DFMUL2FIXED_VARS(t, ytemp);
439
	    if ((code = CHECK_SET_FIXED_SUM(px, px, t)) < 0)
440
	        return code;
441
	}
442
    }
443
    if (((code = CHECK_SET_FIXED_SUM(ppt->x, px, pmat->tx_fixed)) < 0) ||
444
        ((code = CHECK_SET_FIXED_SUM(ppt->y, py, pmat->ty_fixed)) < 0) )
445
        return code;
446
    return 0;
447
}
448
 
449
#if PRECISE_CURRENTPOINT
450
/* Transform a point with a fixed-point result. */
451
/* Used for the best precision of the current point,
452
   see comment in clamp_point_aux. */
453
int
454
gs_point_transform2fixed_rounding(const gs_matrix_fixed * pmat,
455
			 floatp x, floatp y, gs_fixed_point * ppt)
456
{
457
    gs_point fpt;
458
 
459
    gs_point_transform(x, y, (const gs_matrix *)pmat, &fpt);
460
    if (!(f_fits_in_fixed(fpt.x) && f_fits_in_fixed(fpt.y)))
461
	return_error(gs_error_limitcheck);
462
    ppt->x = float2fixed_rounded(fpt.x);
463
    ppt->y = float2fixed_rounded(fpt.y);
464
    return 0;
465
}
466
#endif
467
 
468
/* Transform a distance with a fixed-point result. */
469
int
470
gs_distance_transform2fixed(const gs_matrix_fixed * pmat,
471
			    floatp dx, floatp dy, gs_fixed_point * ppt)
472
{
473
    fixed px, py, t;
474
    double xtemp, ytemp;
475
    int code;
476
 
477
    if ((code = CHECK_DFMUL2FIXED_VARS(px, dx, pmat->xx, xtemp)) < 0 ||
478
	(code = CHECK_DFMUL2FIXED_VARS(py, dy, pmat->yy, ytemp)) < 0
479
	)
480
	return code;
481
    FINISH_DFMUL2FIXED_VARS(px, xtemp);
482
    FINISH_DFMUL2FIXED_VARS(py, ytemp);
483
    if (!is_fzero(pmat->yx)) {
484
	if ((code = CHECK_DFMUL2FIXED_VARS(t, dy, pmat->yx, ytemp)) < 0)
485
	    return code;
486
	FINISH_DFMUL2FIXED_VARS(t, ytemp);
487
	if ((code = CHECK_SET_FIXED_SUM(px, px, t)) < 0)
488
	    return code;
489
    }
490
    if (!is_fzero(pmat->xy)) {
491
	if ((code = CHECK_DFMUL2FIXED_VARS(t, dx, pmat->xy, xtemp)) < 0)
492
	    return code;
493
	FINISH_DFMUL2FIXED_VARS(t, xtemp);
494
	if ((code = CHECK_SET_FIXED_SUM(py, py, t)) < 0)
495
	    return code;
496
    }
497
    ppt->x = px;
498
    ppt->y = py;
499
    return 0;
500
}
501
 
502
/* ------ Serialization ------ */
503
 
504
/*
505
 * For maximum conciseness in band lists, we write a matrix as a control
506
 * byte followed by 0 to 6 values.  The control byte has the format
507
 * AABBCD00.  AA and BB control (xx,yy) and (xy,yx) as follows:
508
 *	00 = values are (0.0, 0.0)
509
 *	01 = values are (V, V) [1 value follows]
510
 *	10 = values are (V, -V) [1 value follows]
511
 *	11 = values are (U, V) [2 values follow]
512
 * C and D control tx and ty as follows:
513
 *	0 = value is 0.0
514
 *	1 = value follows
515
 * The following code is the only place that knows this representation.
516
 */
517
 
518
/* Put a matrix on a stream. */
519
int
520
sput_matrix(stream *s, const gs_matrix *pmat)
521
{
522
    byte buf[1 + 6 * sizeof(float)];
523
    byte *cp = buf + 1;
524
    byte b = 0;
525
    float coeff[6];
526
    int i;
527
    uint ignore;
528
 
529
    coeff[0] = pmat->xx;
530
    coeff[1] = pmat->xy;
531
    coeff[2] = pmat->yx;
532
    coeff[3] = pmat->yy;
533
    coeff[4] = pmat->tx;
534
    coeff[5] = pmat->ty;
535
    for (i = 0; i < 4; i += 2) {
536
	float u = coeff[i], v = coeff[i ^ 3];
537
 
538
	b <<= 2;
539
	if (u != 0 || v != 0) {
540
	    memcpy(cp, &u, sizeof(float));
541
	    cp += sizeof(float);
542
 
543
	    if (v == u)
544
		b += 1;
545
	    else if (v == -u)
546
		b += 2;
547
	    else {
548
		b += 3;
549
		memcpy(cp, &v, sizeof(float));
550
		cp += sizeof(float);
551
	    }
552
	}
553
    }
554
    for (; i < 6; ++i) {
555
	float v = coeff[i];
556
 
557
	b <<= 1;
558
	if (v != 0) {
559
	    ++b;
560
	    memcpy(cp, &v, sizeof(float));
561
	    cp += sizeof(float);
562
	}
563
    }
564
    buf[0] = b << 2;
565
    return sputs(s, buf, cp - buf, &ignore);
566
}
567
 
568
/* Get a matrix from a stream. */
569
int
570
sget_matrix(stream *s, gs_matrix *pmat)
571
{
572
    int b = sgetc(s);
573
    float coeff[6];
574
    int i;
575
    int status;
576
    uint nread;
577
 
578
    if (b < 0)
579
	return b;
580
    for (i = 0; i < 4; i += 2, b <<= 2)
581
	if (!(b & 0xc0))
582
	    coeff[i] = coeff[i ^ 3] = 0.0;
583
	else {
584
	    float value;
585
 
586
	    status = sgets(s, (byte *)&value, sizeof(value), &nread);
587
	    if (status < 0 && status != EOFC)
588
		return_error(gs_error_ioerror);
589
	    coeff[i] = value;
590
	    switch ((b >> 6) & 3) {
591
		case 1:
592
		    coeff[i ^ 3] = value;
593
		    break;
594
		case 2:
595
		    coeff[i ^ 3] = -value;
596
		    break;
597
		case 3:
598
		    status = sgets(s, (byte *)&coeff[i ^ 3],
599
				   sizeof(coeff[0]), &nread);
600
		    if (status < 0 && status != EOFC)
601
			return_error(gs_error_ioerror);
602
	    }
603
	}
604
    for (; i < 6; ++i, b <<= 1)
605
	if (b & 0x80) {
606
	    status = sgets(s, (byte *)&coeff[i], sizeof(coeff[0]), &nread);
607
	    if (status < 0 && status != EOFC)
608
		return_error(gs_error_ioerror);
609
	} else
610
	    coeff[i] = 0.0;
611
    pmat->xx = coeff[0];
612
    pmat->xy = coeff[1];
613
    pmat->yx = coeff[2];
614
    pmat->yy = coeff[3];
615
    pmat->tx = coeff[4];
616
    pmat->ty = coeff[5];
617
    return 0;
618
}