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