xref: /plan9/sys/src/cmd/gs/src/gdevtrac.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 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: gdevtrac.c,v 1.5 2003/06/06 17:50:27 igor Exp $ */
18 /* Tracing device (including sample high-level implementation) */
19 #include "gx.h"
20 #include "gserrors.h"
21 #include "gscspace.h"
22 #include "gxdevice.h"
23 #include "gxtmap.h"		/* for gxdht.h */
24 #include "gxdht.h"
25 #include "gxfont.h"
26 #include "gxiparam.h"
27 #include "gxistate.h"
28 #include "gxpaint.h"
29 #include "gzpath.h"
30 #include "gzcpath.h"
31 
32 /* Define the default resolution. */
33 #ifndef X_DPI
34 #  define X_DPI 720
35 #endif
36 #ifndef Y_DPI
37 #  define Y_DPI 720
38 #endif
39 
40 extern_st(st_gs_text_enum);
41 extern_st(st_gx_image_enum_common);
42 
43 /* ---------------- Internal utilities ---------------- */
44 
45 private void
trace_drawing_color(const char * prefix,const gx_drawing_color * pdcolor)46 trace_drawing_color(const char *prefix, const gx_drawing_color *pdcolor)
47 {
48     dprintf1("%scolor=", prefix);
49     if (pdcolor->type == gx_dc_type_none)
50 	dputs("none");
51     else if (pdcolor->type == gx_dc_type_null)
52 	dputs("null");
53     else if (pdcolor->type == gx_dc_type_pure)
54 	dprintf1("0x%lx", (ulong)pdcolor->colors.pure);
55     else if (pdcolor->type == gx_dc_type_ht_binary) {
56 	int ci = pdcolor->colors.binary.b_index;
57 
58 	dprintf5("binary(0x%lx, 0x%lx, %d/%d, index=%d)",
59 		 (ulong)pdcolor->colors.binary.color[0],
60 		 (ulong)pdcolor->colors.binary.color[1],
61 		 pdcolor->colors.binary.b_level,
62 		 (ci < 0 ? pdcolor->colors.binary.b_ht->order.num_bits :
63 		  pdcolor->colors.binary.b_ht->components[ci].corder.num_bits),
64 		 ci);
65     } else if (pdcolor->type == gx_dc_type_ht_colored) {
66 	ulong plane_mask = pdcolor->colors.colored.plane_mask;
67 	int ci;
68 
69 	dprintf1("colored(mask=%lu", plane_mask);
70 	for (ci = 0; plane_mask != 0; ++ci, plane_mask >>= 1)
71 	    if (plane_mask & 1) {
72 		dprintf2(", (base=%u, level=%u)",
73 			 pdcolor->colors.colored.c_base[ci],
74 			 pdcolor->colors.colored.c_level[ci]);
75 	    } else
76 		dputs(", -");
77     } else {
78 	dputs("**unknown**");
79     }
80 }
81 
82 private void
trace_lop(gs_logical_operation_t lop)83 trace_lop(gs_logical_operation_t lop)
84 {
85     dprintf1(", lop=0x%x", (uint)lop);
86 }
87 
88 private void
trace_path(const gx_path * path)89 trace_path(const gx_path *path)
90 {
91     gs_path_enum penum;
92 
93     gx_path_enum_init(&penum, path);
94     for (;;) {
95 	gs_fixed_point pts[3];
96 
97 	switch (gx_path_enum_next(&penum, pts)) {
98 	case gs_pe_moveto:
99 	    dprintf2("    %g %g moveto\n", fixed2float(pts[0].x),
100 		     fixed2float(pts[0].y));
101 	    continue;
102 	case gs_pe_lineto:
103 	    dprintf2("    %g %g lineto\n", fixed2float(pts[0].x),
104 		     fixed2float(pts[0].y));
105 	    continue;
106 	case gs_pe_curveto:
107 	    dprintf6("    %g %g %g %g %g %g curveto\n", fixed2float(pts[0].x),
108 		     fixed2float(pts[0].y), fixed2float(pts[1].x),
109 		     fixed2float(pts[1].y), fixed2float(pts[2].x),
110 		     fixed2float(pts[2].y));
111 	    continue;
112 	case gs_pe_closepath:
113 	    dputs("    closepath\n");
114 	    continue;
115 	default:
116 	    break;
117 	}
118 	break;
119     }
120 }
121 
122 private void
trace_clip(gx_device * dev,const gx_clip_path * pcpath)123 trace_clip(gx_device *dev, const gx_clip_path *pcpath)
124 {
125     if (pcpath == 0)
126 	return;
127     if (gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
128 				    int2fixed(dev->width),
129 				    int2fixed(dev->height))
130 	)
131 	return;
132     dputs(", clip={");
133     if (pcpath->path_valid)
134 	trace_path(&pcpath->path);
135     else
136 	dputs("NO PATH");
137     dputs("}");
138 }
139 
140 /* ---------------- Low-level driver procedures ---------------- */
141 
142 private int
trace_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)143 trace_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
144 		     gx_color_index color)
145 {
146     dprintf5("fill_rectangle(%d, %d, %d, %d, 0x%lx)\n",
147 	     x, y, w, h, (ulong)color);
148     return 0;
149 }
150 
151 private int
trace_copy_mono(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)152 trace_copy_mono(gx_device * dev, const byte * data,
153 		int dx, int raster, gx_bitmap_id id,
154 		int x, int y, int w, int h,
155 		gx_color_index zero, gx_color_index one)
156 {
157     dprintf7("copy_mono(x=%d, y=%d, w=%d, h=%d, dx=%d, raster=%d, id=0x%lx,\n",
158 	     x, y, w, h, dx, raster, (ulong)id);
159     dprintf2("    colors=(0x%lx,0x%lx))\n", (ulong)zero, (ulong)one);
160     return 0;
161 }
162 
163 private int
trace_copy_color(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h)164 trace_copy_color(gx_device * dev, const byte * data,
165 		 int dx, int raster, gx_bitmap_id id,
166 		 int x, int y, int w, int h)
167 {
168     dprintf7("copy_color(x=%d, y=%d, w=%d, h=%d, dx=%d, raster=%d, id=0x%lx)\n",
169 	     x, y, w, h, dx, raster, (ulong)id);
170     return 0;
171 }
172 
173 private int
trace_copy_alpha(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color,int depth)174 trace_copy_alpha(gx_device * dev, const byte * data, int dx, int raster,
175 		 gx_bitmap_id id, int x, int y, int w, int h,
176 		 gx_color_index color, int depth)
177 {
178     dprintf7("copy_alpha(x=%d, y=%d, w=%d, h=%d, dx=%d, raster=%d, id=0x%lx,\n",
179 	     x, y, w, h, dx, raster, (ulong)id);
180     dprintf2("    color=0x%lx, depth=%d)\n", (ulong)color, depth);
181     return 0;
182 }
183 
184 private int
trace_fill_mask(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)185 trace_fill_mask(gx_device * dev,
186 		const byte * data, int dx, int raster, gx_bitmap_id id,
187 		int x, int y, int w, int h,
188 		const gx_drawing_color * pdcolor, int depth,
189 		gs_logical_operation_t lop, const gx_clip_path * pcpath)
190 {
191     dprintf7("fill_mask(x=%d, y=%d, w=%d, h=%d, dx=%d, raster=%d, id=0x%lx,\n",
192 	     x, y, w, h, dx, raster, (ulong)id);
193     trace_drawing_color("    ", pdcolor);
194     dprintf1(", depth=%d", depth);
195     trace_lop(lop);
196     trace_clip(dev, pcpath);
197     dputs(")\n");
198     return 0;
199 }
200 
201 private int
trace_fill_trapezoid(gx_device * dev,const gs_fixed_edge * left,const gs_fixed_edge * right,fixed ybot,fixed ytop,bool swap_axes,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)202 trace_fill_trapezoid(gx_device * dev,
203 		     const gs_fixed_edge * left,
204 		     const gs_fixed_edge * right,
205 		     fixed ybot, fixed ytop, bool swap_axes,
206 		     const gx_drawing_color * pdcolor,
207 		     gs_logical_operation_t lop)
208 {
209     dputs("**fill_trapezoid**\n");
210     return 0;
211 }
212 
213 private int
trace_fill_parallelogram(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)214 trace_fill_parallelogram(gx_device * dev,
215 			 fixed px, fixed py, fixed ax, fixed ay,
216 			 fixed bx, fixed by, const gx_drawing_color * pdcolor,
217 			 gs_logical_operation_t lop)
218 {
219     dprintf6("fill_parallelogram((%g,%g), (%g,%g), (%g,%g)",
220 	     fixed2float(px), fixed2float(py), fixed2float(ax),
221 	     fixed2float(ay), fixed2float(bx), fixed2float(by));
222     trace_drawing_color(", ", pdcolor);
223     trace_lop(lop);
224     dputs(")\n");
225     return 0;
226 }
227 
228 private int
trace_fill_triangle(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)229 trace_fill_triangle(gx_device * dev,
230 		    fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
231 		    const gx_drawing_color * pdcolor,
232 		    gs_logical_operation_t lop)
233 {
234     dprintf6("fill_triangle((%g,%g), (%g,%g), (%g,%g)",
235 	     fixed2float(px), fixed2float(py), fixed2float(ax),
236 	     fixed2float(ay), fixed2float(bx), fixed2float(by));
237     trace_drawing_color(", ", pdcolor);
238     trace_lop(lop);
239     dputs(")\n");
240     return 0;
241 }
242 
243 private int
trace_draw_thin_line(gx_device * dev,fixed fx0,fixed fy0,fixed fx1,fixed fy1,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)244 trace_draw_thin_line(gx_device * dev,
245 		     fixed fx0, fixed fy0, fixed fx1, fixed fy1,
246 		     const gx_drawing_color * pdcolor,
247 		     gs_logical_operation_t lop)
248 {
249     dprintf4("draw_thin_line((%g,%g), (%g,%g)",
250 	     fixed2float(fx0), fixed2float(fy0), fixed2float(fx1),
251 	     fixed2float(fy1));
252     trace_drawing_color(", ", pdcolor);
253     trace_lop(lop);
254     dputs(")\n");
255     return 0;
256 }
257 
258 private int
trace_strip_tile_rectangle(gx_device * dev,const gx_strip_bitmap * tiles,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1,int px,int py)259 trace_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
260 			   int x, int y, int w, int h,
261 			   gx_color_index color0, gx_color_index color1,
262 			   int px, int py)
263 {
264     dprintf6("strip_tile_rectangle(x=%d, y=%d, w=%d, h=%d, colors=(0x%lx,0x%lx),\n",
265 	     x, y, w, h, (ulong)color0, (ulong)color1);
266     dprintf8("    size=(%d,%d) shift %u, rep=(%u,%u) shift %u, phase=(%d,%d))\n",
267 	     tiles->size.x, tiles->size.y, tiles->shift,
268 	     tiles->rep_width, tiles->rep_height, tiles->rep_shift, px, py);
269     return 0;
270 }
271 
272 private int
trace_strip_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int width,int height,int phase_x,int phase_y,gs_logical_operation_t lop)273 trace_strip_copy_rop(gx_device * dev, const byte * sdata, int sourcex,
274 		     uint sraster, gx_bitmap_id id,
275 		     const gx_color_index * scolors,
276 		     const gx_strip_bitmap * textures,
277 		     const gx_color_index * tcolors,
278 		     int x, int y, int width, int height,
279 		     int phase_x, int phase_y, gs_logical_operation_t lop)
280 {
281     dputs("**strip_copy_rop**\n");
282     return 0;
283 }
284 
285 /* ---------------- High-level driver procedures ---------------- */
286 
287 private int
trace_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)288 trace_fill_path(gx_device * dev, const gs_imager_state * pis,
289 		gx_path * ppath, const gx_fill_params * params,
290 		const gx_drawing_color * pdcolor,
291 		const gx_clip_path * pcpath)
292 {
293     dputs("fill_path({\n");
294     trace_path(ppath);
295     trace_drawing_color("}, ", pdcolor);
296     dprintf5(", rule=%d, adjust=(%g,%g), flatness=%g, fill_zero_width=%s",
297 	     params->rule, fixed2float(params->adjust.x),
298 	     fixed2float(params->adjust.y), params->flatness,
299 	     (params->fill_zero_width ? "true" : "false"));
300     trace_clip(dev, pcpath);
301     /****** pis ******/
302     dputs(")\n");
303     return 0;
304 }
305 
306 private int
trace_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)307 trace_stroke_path(gx_device * dev, const gs_imager_state * pis,
308 		  gx_path * ppath, const gx_stroke_params * params,
309 		  const gx_drawing_color * pdcolor,
310 		  const gx_clip_path * pcpath)
311 {
312     dputs("stroke_path({\n");
313     trace_path(ppath);
314     trace_drawing_color("}, ", pdcolor);
315     dprintf1(", flatness=%g", params->flatness);
316     trace_clip(dev, pcpath);
317     /****** pis ******/
318     dputs(")\n");
319     return 0;
320 }
321 
322 typedef struct trace_image_enum_s {
323     gx_image_enum_common;
324     gs_memory_t *memory;
325     int rows_left;
326 } trace_image_enum_t;
327 gs_private_st_suffix_add0(st_trace_image_enum, trace_image_enum_t,
328 			  "trace_image_enum_t", trace_image_enum_enum_ptrs,
329 			  trace_image_enum_reloc_ptrs,
330 			  st_gx_image_enum_common);
331 private int
trace_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)332 trace_plane_data(gx_image_enum_common_t * info,
333 		 const gx_image_plane_t * planes, int height,
334 		 int *rows_used)
335 {
336     trace_image_enum_t *pie = (trace_image_enum_t *)info;
337     int i;
338 
339     dprintf1("image_plane_data(height=%d", height);
340     for (i = 0; i < pie->num_planes; ++i) {
341 	if (planes[i].data)
342 	    dprintf4(", {depth=%d, width=%d, dx=%d, raster=%u}",
343 		     pie->plane_depths[i], pie->plane_widths[i],
344 		     planes[i].data_x, planes[i].raster);
345 	else
346 	    dputs(", -");
347     }
348     dputs(")\n");
349     *rows_used = height;
350     return (pie->rows_left -= height) <= 0;
351 }
352 private int
trace_end_image(gx_image_enum_common_t * info,bool draw_last)353 trace_end_image(gx_image_enum_common_t * info, bool draw_last)
354 {
355     trace_image_enum_t *pie = (trace_image_enum_t *)info;
356 
357     gs_free_object(pie->memory, pie, "trace_end_image");
358     return 0;
359 }
360 private const gx_image_enum_procs_t trace_image_enum_procs = {
361     trace_plane_data, trace_end_image
362 };
363 private int
trace_begin_typed_image(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pim,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gx_image_enum_common_t ** pinfo)364 trace_begin_typed_image(gx_device * dev, const gs_imager_state * pis,
365 			const gs_matrix * pmat,
366 			const gs_image_common_t * pim,
367 			const gs_int_rect * prect,
368 			const gx_drawing_color * pdcolor,
369 			const gx_clip_path * pcpath,
370 			gs_memory_t * memory,
371 			gx_image_enum_common_t ** pinfo)
372 {
373     trace_image_enum_t *pie;
374     const gs_pixel_image_t *ppi = (const gs_pixel_image_t *)pim;
375     int ncomp;
376 
377     dprintf7("begin_typed_image(type=%d, ImageMatrix=[%g %g %g %g %g %g]",
378 	     pim->type->index, pim->ImageMatrix.xx, pim->ImageMatrix.xy,
379 	     pim->ImageMatrix.yx, pim->ImageMatrix.yy,
380 	     pim->ImageMatrix.tx, pim->ImageMatrix.ty);
381     switch (pim->type->index) {
382     case 1:
383 	if (((const gs_image1_t *)ppi)->ImageMask) {
384 	    ncomp = 1;
385 	    break;
386 	}
387 	/* falls through */
388     case 4:
389 	ncomp = gs_color_space_num_components(ppi->ColorSpace);
390 	break;
391     case 3:
392 	ncomp = gs_color_space_num_components(ppi->ColorSpace) + 1;
393 	break;
394     case 2:			/* no data */
395 	dputs(")\n");
396 	return 1;
397     default:
398 	goto dflt;
399     }
400     pie = gs_alloc_struct(memory, trace_image_enum_t, &st_trace_image_enum,
401 			  "trace_begin_typed_image");
402     if (pie == 0)
403 	goto dflt;
404     if (gx_image_enum_common_init((gx_image_enum_common_t *)pie,
405 				  (const gs_data_image_t *)pim,
406 				  &trace_image_enum_procs, dev, ncomp,
407 				  ppi->format) < 0
408 	)
409 	goto dflt;
410     dprintf4("\n    Width=%d, Height=%d, BPC=%d, num_components=%d)\n",
411 	     ppi->Width, ppi->Height, ppi->BitsPerComponent, ncomp);
412     pie->memory = memory;
413     pie->rows_left = ppi->Height;
414     *pinfo = (gx_image_enum_common_t *)pie;
415     return 0;
416  dflt:
417     dputs(") DEFAULTED\n");
418     return gx_default_begin_typed_image(dev, pis, pmat, pim, prect, pdcolor,
419 					pcpath, memory, pinfo);
420 }
421 
422 private int
trace_text_process(gs_text_enum_t * pte)423 trace_text_process(gs_text_enum_t *pte)
424 {
425     return 0;
426 }
427 private const gs_text_enum_procs_t trace_text_procs = {
428     NULL, trace_text_process, NULL, NULL, NULL, NULL,
429     gx_default_text_release
430 };
431 private int
trace_text_begin(gx_device * dev,gs_imager_state * pis,const gs_text_params_t * text,gs_font * font,gx_path * path,const gx_device_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gs_text_enum_t ** ppenum)432 trace_text_begin(gx_device * dev, gs_imager_state * pis,
433 		 const gs_text_params_t * text, gs_font * font,
434 		 gx_path * path, const gx_device_color * pdcolor,
435 		 const gx_clip_path * pcpath, gs_memory_t * memory,
436 		 gs_text_enum_t ** ppenum)
437 {
438     static const char *const tags[sizeof(text->operation) * 8] = {
439 	"FROM_STRING", "FROM_BYTES", "FROM_CHARS", "FROM_GLYPHS",
440 	"FROM_SINGLE_CHAR", "FROM_SINGLE_GLYPH",
441 	"ADD_TO_ALL_WIDTHS", "ADD_TO_SPACE_WIDTH",
442 	"REPLACE_WIDTHS", "DO_NONE", "DO_DRAW", "DO_CHARWIDTH",
443 	"DO_FALSE_CHARPATH", "DO_TRUE_CHARPATH",
444 	"DO_FALSE_CHARBOXPATH", "DO_TRUE_CHARBOXPATH",
445 	"INTERVENE", "RETURN_WIDTH"
446     };
447     int i;
448     gs_text_enum_t *pte;
449     int code;
450 
451     dputs("text_begin(");
452     for (i = 0; i < countof(tags); ++i)
453 	if (text->operation & (1 << i)) {
454 	    if (tags[i])
455 		dprintf1("%s ", tags[i]);
456 	    else
457 		dprintf1("%d? ", i);
458 	}
459     dprintf1("font=%s\n           text=(", font->font_name.chars);
460     if (text->operation & TEXT_FROM_SINGLE_CHAR)
461 	dprintf1("0x%lx", (ulong)text->data.d_char);
462     else if (text->operation & TEXT_FROM_SINGLE_GLYPH)
463 	dprintf1("0x%lx", (ulong)text->data.d_glyph);
464     else
465 	for (i = 0; i < text->size; ++i) {
466 	    if (text->operation & TEXT_FROM_STRING)
467 		dputc(text->data.bytes[i]);
468 	    else
469 		dprintf1("0x%lx ",
470 			 (text->operation & TEXT_FROM_GLYPHS ?
471 			  (ulong)text->data.glyphs[i] :
472 			  (ulong)text->data.chars[i]));
473     }
474     dprintf1(")\n           size=%u", text->size);
475     if (text->operation & TEXT_ADD_TO_ALL_WIDTHS)
476 	dprintf2(", delta_all=(%g,%g)", text->delta_all.x, text->delta_all.y);
477     if (text->operation & TEXT_ADD_TO_SPACE_WIDTH) {
478 	dprintf3(", space=0x%lx, delta_space=(%g,%g)",
479 		 (text->operation & TEXT_FROM_GLYPHS ?
480 		  (ulong)text->space.s_glyph : (ulong)text->space.s_char),
481 		 text->delta_space.x, text->delta_space.y);
482     }
483     if (text->operation & TEXT_REPLACE_WIDTHS) {
484 	dputs("\n           widths=");
485 	for (i = 0; i < text->widths_size; ++i) {
486 	    if (text->x_widths)
487 		dprintf1("(%g,", text->x_widths[i]);
488 	    else
489 		dputs("(,");
490 	    if (text->y_widths)
491 		dprintf1("%g)",
492 			 (text->y_widths == text->x_widths ?
493 			  text->y_widths[++i] : text->y_widths[i]));
494 	    else
495 		dputs(")");
496 	}
497     }
498     if (text->operation & TEXT_DO_DRAW)
499 	trace_drawing_color(", ", pdcolor);
500     /*
501      * We can't do it if CHAR*PATH or INTERVENE, or if (RETURN_WIDTH and not
502      * REPLACE_WIDTHS and we can't get the widths from the font).
503      */
504     if (text->operation &
505 	(TEXT_DO_FALSE_CHARPATH | TEXT_DO_TRUE_CHARPATH |
506 	 TEXT_DO_FALSE_CHARBOXPATH | TEXT_DO_TRUE_CHARBOXPATH |
507 	 TEXT_INTERVENE)
508 	)
509 	goto dflt;
510     rc_alloc_struct_1(pte, gs_text_enum_t, &st_gs_text_enum, memory,
511 		      goto dflt, "trace_text_begin");
512     code = gs_text_enum_init(pte, &trace_text_procs, dev, pis, text, font,
513 			     path, pdcolor, pcpath, memory);
514     if (code < 0)
515 	goto dfree;
516     if ((text->operation & (TEXT_DO_CHARWIDTH | TEXT_RETURN_WIDTH)) &&
517 	!(text->operation & TEXT_REPLACE_WIDTHS)
518 	) {
519 	/*
520 	 * Get the widths from the font.  This code is mostly copied from
521 	 * the pdfwrite driver, and should probably be shared with it.
522 	 * ****** WRONG IF Type 0 FONT ******
523 	 */
524 	int i;
525 	gs_point w;
526 	double scale = (font->FontType == ft_TrueType ? 0.001 : 1.0);
527 	gs_fixed_point origin;
528 	gs_point dpt;
529 	int num_spaces = 0;
530 
531 	if (!(text->operation & TEXT_FROM_STRING))
532 	    goto dfree;		/* can't handle yet */
533 	if (gx_path_current_point(path, &origin) < 0)
534 	    goto dfree;
535 	w.x = 0, w.y = 0;
536 	for (i = 0; i < text->size; ++i) {
537 	    gs_char ch = text->data.bytes[i];
538 	    int wmode = font->WMode;
539 	    gs_glyph glyph =
540 		((gs_font_base *)font)->procs.encode_char(font, ch,
541 							  GLYPH_SPACE_NAME);
542 	    gs_glyph_info_t info;
543 
544 	    if (glyph != gs_no_glyph &&
545 		(code = font->procs.glyph_info(font, glyph, NULL,
546 					       GLYPH_INFO_WIDTH0 << wmode,
547 					       &info)) >= 0
548 	    ) {
549 		w.x += info.width[wmode].x;
550 		w.y += info.width[wmode].y;
551 	    } else
552 		goto dfree;
553 	    if (ch == text->space.s_char)
554 		++num_spaces;
555 	}
556 	gs_distance_transform(w.x * scale, w.y * scale,
557 			      &font->FontMatrix, &dpt);
558 	if (text->operation & TEXT_ADD_TO_ALL_WIDTHS) {
559 	    int num_chars = text->size;
560 
561 	    dpt.x += text->delta_all.x * num_chars;
562 	    dpt.y += text->delta_all.y * num_chars;
563 	}
564 	if (text->operation & TEXT_ADD_TO_SPACE_WIDTH) {
565 	    dpt.x += text->delta_space.x * num_spaces;
566 	    dpt.y += text->delta_space.y * num_spaces;
567 	}
568 	pte->returned.total_width = dpt;
569 	gs_distance_transform(dpt.x, dpt.y, &ctm_only(pis), &dpt);
570 	code = gx_path_add_point(path,
571 				 origin.x + float2fixed(dpt.x),
572 				 origin.y + float2fixed(dpt.y));
573 	if (code < 0)
574 	    goto dfree;
575     }
576     dputs(")\n");
577     *ppenum = pte;
578     return 0;
579  dfree:
580     gs_free_object(memory, pte, "trace_text_begin");
581  dflt:
582     dputs(") DEFAULTED\n");
583     return gx_default_text_begin(dev, pis, text, font, path, pdcolor,
584 				 pcpath, memory, ppenum);
585 }
586 
587 /* ---------------- The device definition ---------------- */
588 
589 #define TRACE_DEVICE_BODY(dname, ncomp, depth, map_rgb_color, map_color_rgb, map_cmyk_color, map_rgb_alpha_color)\
590     std_device_dci_body(gx_device, 0, dname,\
591 			DEFAULT_WIDTH_10THS * X_DPI / 10,\
592 			DEFAULT_HEIGHT_10THS * Y_DPI / 10,\
593 			X_DPI, Y_DPI, ncomp, depth,\
594 			(1 << (depth / ncomp)) - 1,\
595 			(ncomp > 1 ? (1 << (depth / ncomp)) - 1 : 0),\
596 			1 << (depth / ncomp),\
597 			(ncomp > 1 ? 1 << (depth / ncomp) : 1)),\
598 {\
599      NULL,			/* open_device */\
600      NULL,			/* get_initial_matrix */\
601      NULL,			/* sync_output */\
602      NULL,			/* output_page */\
603      NULL,			/* close_device */\
604      map_rgb_color,		/* differs */\
605      map_color_rgb,		/* differs */\
606      trace_fill_rectangle,\
607      NULL,			/* tile_rectangle */\
608      trace_copy_mono,\
609      trace_copy_color,\
610      NULL,			/* draw_line */\
611      NULL,			/* get_bits */\
612      NULL,			/* get_params */\
613      NULL,			/* put_params */\
614      map_cmyk_color,		/* differs */\
615      NULL,			/* get_xfont_procs */\
616      NULL,			/* get_xfont_device */\
617      map_rgb_alpha_color,	/* differs */\
618      gx_page_device_get_page_device,\
619      NULL,			/* get_alpha_bits */\
620      trace_copy_alpha,\
621      NULL,			/* get_band */\
622      NULL,			/* copy_rop */\
623      trace_fill_path,\
624      trace_stroke_path,\
625      trace_fill_mask,\
626      trace_fill_trapezoid,\
627      trace_fill_parallelogram,\
628      trace_fill_triangle,\
629      trace_draw_thin_line,\
630      NULL,			/* begin_image */\
631      NULL,			/* image_data */\
632      NULL,			/* end_image */\
633      trace_strip_tile_rectangle,\
634      trace_strip_copy_rop,\
635      NULL,			/* get_clipping_box */\
636      trace_begin_typed_image,\
637      NULL,			/* get_bits_rectangle */\
638      NULL,			/* map_color_rgb_alpha */\
639      NULL,			/* create_compositor */\
640      NULL,			/* get_hardware_params */\
641      trace_text_begin,\
642      NULL			/* finish_copydevice */\
643 }
644 
645 const gx_device gs_tr_mono_device = {
646     TRACE_DEVICE_BODY("tr_mono", 1, 1,
647 		      gx_default_b_w_map_rgb_color,
648 		      gx_default_b_w_map_color_rgb, NULL, NULL)
649 };
650 
651 const gx_device gs_tr_rgb_device = {
652     TRACE_DEVICE_BODY("tr_rgb", 3, 24,
653 		      gx_default_rgb_map_rgb_color,
654 		      gx_default_rgb_map_color_rgb, NULL, NULL)
655 };
656 
657 const gx_device gs_tr_cmyk_device = {
658     TRACE_DEVICE_BODY("tr_cmyk", 4, 4,
659 		      NULL, cmyk_1bit_map_color_rgb,
660 		      cmyk_1bit_map_cmyk_color, NULL)
661 };
662