/* Copyright (C) 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevtrac.c,v 1.2.6.1.2.1 2003/01/17 00:49:01 giles Exp $ */ /* Tracing device (including sample high-level implementation) */ #include "gx.h" #include "gserrors.h" #include "gscspace.h" #include "gxdevice.h" #include "gxtmap.h" /* for gxdht.h */ #include "gxdht.h" #include "gxfont.h" #include "gxiparam.h" #include "gxistate.h" #include "gxpaint.h" #include "gzpath.h" #include "gzcpath.h" /* Define the default resolution. */ #ifndef X_DPI # define X_DPI 720 #endif #ifndef Y_DPI # define Y_DPI 720 #endif extern_st(st_gs_text_enum); extern_st(st_gx_image_enum_common); /* ---------------- Internal utilities ---------------- */ private void trace_drawing_color(const char *prefix, const gx_drawing_color *pdcolor) { dprintf1("%scolor=", prefix); if (pdcolor->type == gx_dc_type_none) dputs("none"); else if (pdcolor->type == gx_dc_type_null) dputs("null"); else if (pdcolor->type == gx_dc_type_pure) dprintf1("0x%lx", (ulong)pdcolor->colors.pure); else if (pdcolor->type == gx_dc_type_ht_binary) { int ci = pdcolor->colors.binary.b_index; dprintf5("binary(0x%lx, 0x%lx, %d/%d, index=%d)", (ulong)pdcolor->colors.binary.color[0], (ulong)pdcolor->colors.binary.color[1], pdcolor->colors.binary.b_level, (ci < 0 ? pdcolor->colors.binary.b_ht->order.num_bits : pdcolor->colors.binary.b_ht->components[ci].corder.num_bits), ci); } else if (pdcolor->type == gx_dc_type_ht_colored) { ulong plane_mask = pdcolor->colors.colored.plane_mask; int ci; dprintf1("colored(mask=%lu", plane_mask); for (ci = 0; plane_mask != 0; ++ci, plane_mask >>= 1) if (plane_mask & 1) { dprintf2(", (base=%u, level=%u)", pdcolor->colors.colored.c_base[ci], pdcolor->colors.colored.c_level[ci]); } else dputs(", -"); } else { dputs("**unknown**"); } } private void trace_lop(gs_logical_operation_t lop) { dprintf1(", lop=0x%x", (uint)lop); } private void trace_path(const gx_path *path) { gs_path_enum penum; gx_path_enum_init(&penum, path); for (;;) { gs_fixed_point pts[3]; switch (gx_path_enum_next(&penum, pts)) { case gs_pe_moveto: dprintf2(" %g %g moveto\n", fixed2float(pts[0].x), fixed2float(pts[0].y)); continue; case gs_pe_lineto: dprintf2(" %g %g lineto\n", fixed2float(pts[0].x), fixed2float(pts[0].y)); continue; case gs_pe_curveto: dprintf6(" %g %g %g %g %g %g curveto\n", fixed2float(pts[0].x), fixed2float(pts[0].y), fixed2float(pts[1].x), fixed2float(pts[1].y), fixed2float(pts[2].x), fixed2float(pts[2].y)); continue; case gs_pe_closepath: dputs(" closepath\n"); continue; default: break; } break; } } private void trace_clip(gx_device *dev, const gx_clip_path *pcpath) { if (pcpath == 0) return; if (gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0, int2fixed(dev->width), int2fixed(dev->height)) ) return; dputs(", clip={"); if (pcpath->path_valid) trace_path(&pcpath->path); else dputs("NO PATH"); dputs("}"); } /* ---------------- Low-level driver procedures ---------------- */ private int trace_fill_rectangle(gx_device * dev, int x, int y, int w, int h, gx_color_index color) { dprintf5("fill_rectangle(%d, %d, %d, %d, 0x%lx)\n", x, y, w, h, (ulong)color); return 0; } 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) { dprintf7("copy_mono(x=%d, y=%d, w=%d, h=%d, dx=%d, raster=%d, id=0x%lx,\n", x, y, w, h, dx, raster, (ulong)id); dprintf2(" colors=(0x%lx,0x%lx))\n", (ulong)zero, (ulong)one); return 0; } 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) { dprintf7("copy_color(x=%d, y=%d, w=%d, h=%d, dx=%d, raster=%d, id=0x%lx)\n", x, y, w, h, dx, raster, (ulong)id); return 0; } 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) { dprintf7("copy_alpha(x=%d, y=%d, w=%d, h=%d, dx=%d, raster=%d, id=0x%lx,\n", x, y, w, h, dx, raster, (ulong)id); dprintf2(" color=0x%lx, depth=%d)\n", (ulong)color, depth); return 0; } 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) { dprintf7("fill_mask(x=%d, y=%d, w=%d, h=%d, dx=%d, raster=%d, id=0x%lx,\n", x, y, w, h, dx, raster, (ulong)id); trace_drawing_color(" ", pdcolor); dprintf1(", depth=%d", depth); trace_lop(lop); trace_clip(dev, pcpath); dputs(")\n"); return 0; } 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) { dputs("**fill_trapezoid**\n"); return 0; } 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) { dprintf6("fill_parallelogram((%g,%g), (%g,%g), (%g,%g)", fixed2float(px), fixed2float(py), fixed2float(ax), fixed2float(ay), fixed2float(bx), fixed2float(by)); trace_drawing_color(", ", pdcolor); trace_lop(lop); dputs(")\n"); return 0; } 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) { dprintf6("fill_triangle((%g,%g), (%g,%g), (%g,%g)", fixed2float(px), fixed2float(py), fixed2float(ax), fixed2float(ay), fixed2float(bx), fixed2float(by)); trace_drawing_color(", ", pdcolor); trace_lop(lop); dputs(")\n"); return 0; } 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) { dprintf4("draw_thin_line((%g,%g), (%g,%g)", fixed2float(fx0), fixed2float(fy0), fixed2float(fx1), fixed2float(fy1)); trace_drawing_color(", ", pdcolor); trace_lop(lop); dputs(")\n"); return 0; } 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) { dprintf6("strip_tile_rectangle(x=%d, y=%d, w=%d, h=%d, colors=(0x%lx,0x%lx),\n", x, y, w, h, (ulong)color0, (ulong)color1); dprintf8(" size=(%d,%d) shift %u, rep=(%u,%u) shift %u, phase=(%d,%d))\n", tiles->size.x, tiles->size.y, tiles->shift, tiles->rep_width, tiles->rep_height, tiles->rep_shift, px, py); return 0; } 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) { dputs("**strip_copy_rop**\n"); return 0; } /* ---------------- High-level driver procedures ---------------- */ 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) { dputs("fill_path({\n"); trace_path(ppath); trace_drawing_color("}, ", pdcolor); dprintf5(", rule=%d, adjust=(%g,%g), flatness=%g, fill_zero_width=%s", params->rule, fixed2float(params->adjust.x), fixed2float(params->adjust.y), params->flatness, (params->fill_zero_width ? "true" : "false")); trace_clip(dev, pcpath); /****** pis ******/ dputs(")\n"); return 0; } 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) { dputs("stroke_path({\n"); trace_path(ppath); trace_drawing_color("}, ", pdcolor); dprintf1(", flatness=%g", params->flatness); trace_clip(dev, pcpath); /****** pis ******/ dputs(")\n"); return 0; } typedef struct trace_image_enum_s { gx_image_enum_common; gs_memory_t *memory; int rows_left; } trace_image_enum_t; gs_private_st_suffix_add0(st_trace_image_enum, trace_image_enum_t, "trace_image_enum_t", trace_image_enum_enum_ptrs, trace_image_enum_reloc_ptrs, st_gx_image_enum_common); private int trace_plane_data(gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height, int *rows_used) { trace_image_enum_t *pie = (trace_image_enum_t *)info; int i; dprintf1("image_plane_data(height=%d", height); for (i = 0; i < pie->num_planes; ++i) { if (planes[i].data) dprintf4(", {depth=%d, width=%d, dx=%d, raster=%u}", pie->plane_depths[i], pie->plane_widths[i], planes[i].data_x, planes[i].raster); else dputs(", -"); } dputs(")\n"); *rows_used = height; return (pie->rows_left -= height) <= 0; } private int trace_end_image(gx_image_enum_common_t * info, bool draw_last) { trace_image_enum_t *pie = (trace_image_enum_t *)info; gs_free_object(pie->memory, pie, "trace_end_image"); return 0; } private const gx_image_enum_procs_t trace_image_enum_procs = { trace_plane_data, trace_end_image }; 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) { trace_image_enum_t *pie; const gs_pixel_image_t *ppi = (const gs_pixel_image_t *)pim; int ncomp; dprintf7("begin_typed_image(type=%d, ImageMatrix=[%g %g %g %g %g %g]", pim->type->index, pim->ImageMatrix.xx, pim->ImageMatrix.xy, pim->ImageMatrix.yx, pim->ImageMatrix.yy, pim->ImageMatrix.tx, pim->ImageMatrix.ty); switch (pim->type->index) { case 1: if (((const gs_image1_t *)ppi)->ImageMask) { ncomp = 1; break; } /* falls through */ case 4: ncomp = gs_color_space_num_components(ppi->ColorSpace); break; case 3: ncomp = gs_color_space_num_components(ppi->ColorSpace) + 1; break; case 2: /* no data */ dputs(")\n"); return 1; default: goto dflt; } pie = gs_alloc_struct(memory, trace_image_enum_t, &st_trace_image_enum, "trace_begin_typed_image"); if (pie == 0) goto dflt; if (gx_image_enum_common_init((gx_image_enum_common_t *)pie, (const gs_data_image_t *)pim, &trace_image_enum_procs, dev, ncomp, ppi->format) < 0 ) goto dflt; dprintf4("\n Width=%d, Height=%d, BPC=%d, num_components=%d)\n", ppi->Width, ppi->Height, ppi->BitsPerComponent, ncomp); pie->memory = memory; pie->rows_left = ppi->Height; *pinfo = (gx_image_enum_common_t *)pie; return 0; dflt: dputs(") DEFAULTED\n"); return gx_default_begin_typed_image(dev, pis, pmat, pim, prect, pdcolor, pcpath, memory, pinfo); } private int trace_text_process(gs_text_enum_t *pte) { return 0; } private const gs_text_enum_procs_t trace_text_procs = { NULL, trace_text_process, NULL, NULL, NULL, NULL, gx_default_text_release }; 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) { static const char *const tags[sizeof(text->operation) * 8] = { "FROM_STRING", "FROM_BYTES", "FROM_CHARS", "FROM_GLYPHS", "FROM_SINGLE_CHAR", "FROM_SINGLE_GLYPH", "ADD_TO_ALL_WIDTHS", "ADD_TO_SPACE_WIDTH", "REPLACE_WIDTHS", "DO_NONE", "DO_DRAW", "DO_CHARWIDTH", "DO_FALSE_CHARPATH", "DO_TRUE_CHARPATH", "DO_FALSE_CHARBOXPATH", "DO_TRUE_CHARBOXPATH", "INTERVENE", "RETURN_WIDTH" }; int i; gs_text_enum_t *pte; int code; dputs("text_begin("); for (i = 0; i < countof(tags); ++i) if (text->operation & (1 << i)) { if (tags[i]) dprintf1("%s ", tags[i]); else dprintf1("%d? ", i); } dprintf1("font=%s\n text=(", font->font_name.chars); if (text->operation & TEXT_FROM_SINGLE_CHAR) dprintf1("0x%lx", (ulong)text->data.d_char); else if (text->operation & TEXT_FROM_SINGLE_GLYPH) dprintf1("0x%lx", (ulong)text->data.d_glyph); else for (i = 0; i < text->size; ++i) { if (text->operation & TEXT_FROM_STRING) dputc(text->data.bytes[i]); else dprintf1("0x%lx ", (text->operation & TEXT_FROM_GLYPHS ? (ulong)text->data.glyphs[i] : (ulong)text->data.chars[i])); } dprintf1(")\n size=%u", text->size); if (text->operation & TEXT_ADD_TO_ALL_WIDTHS) dprintf2(", delta_all=(%g,%g)", text->delta_all.x, text->delta_all.y); if (text->operation & TEXT_ADD_TO_SPACE_WIDTH) { dprintf3(", space=0x%lx, delta_space=(%g,%g)", (text->operation & TEXT_FROM_GLYPHS ? (ulong)text->space.s_glyph : (ulong)text->space.s_char), text->delta_space.x, text->delta_space.y); } if (text->operation & TEXT_REPLACE_WIDTHS) { dputs("\n widths="); for (i = 0; i < text->widths_size; ++i) { if (text->x_widths) dprintf1("(%g,", text->x_widths[i]); else dputs("(,"); if (text->y_widths) dprintf1("%g)", (text->y_widths == text->x_widths ? text->y_widths[++i] : text->y_widths[i])); else dputs(")"); } } if (text->operation & TEXT_DO_DRAW) trace_drawing_color(", ", pdcolor); /* * We can't do it if CHAR*PATH or INTERVENE, or if (RETURN_WIDTH and not * REPLACE_WIDTHS and we can't get the widths from the font). */ if (text->operation & (TEXT_DO_FALSE_CHARPATH | TEXT_DO_TRUE_CHARPATH | TEXT_DO_FALSE_CHARBOXPATH | TEXT_DO_TRUE_CHARBOXPATH | TEXT_INTERVENE) ) goto dflt; rc_alloc_struct_1(pte, gs_text_enum_t, &st_gs_text_enum, memory, goto dflt, "trace_text_begin"); code = gs_text_enum_init(pte, &trace_text_procs, dev, pis, text, font, path, pdcolor, pcpath, memory); if (code < 0) goto dfree; if ((text->operation & (TEXT_DO_CHARWIDTH | TEXT_RETURN_WIDTH)) && !(text->operation & TEXT_REPLACE_WIDTHS) ) { /* * Get the widths from the font. This code is mostly copied from * the pdfwrite driver, and should probably be shared with it. * ****** WRONG IF Type 0 FONT ****** */ int i; gs_point w; double scale = (font->FontType == ft_TrueType ? 0.001 : 1.0); gs_fixed_point origin; gs_point dpt; int num_spaces = 0; if (!(text->operation & TEXT_FROM_STRING)) goto dfree; /* can't handle yet */ if (gx_path_current_point(path, &origin) < 0) goto dfree; w.x = 0, w.y = 0; for (i = 0; i < text->size; ++i) { gs_char ch = text->data.bytes[i]; int wmode = font->WMode; gs_glyph glyph = ((gs_font_base *)font)->procs.encode_char(font, ch, GLYPH_SPACE_INDEX); gs_glyph_info_t info; if (glyph != gs_no_glyph && (code = font->procs.glyph_info(font, glyph, NULL, GLYPH_INFO_WIDTH0 << wmode, &info)) >= 0 ) { w.x += info.width[wmode].x; w.y += info.width[wmode].y; } else goto dfree; if (ch == text->space.s_char) ++num_spaces; } gs_distance_transform(w.x * scale, w.y * scale, &font->FontMatrix, &dpt); if (text->operation & TEXT_ADD_TO_ALL_WIDTHS) { int num_chars = text->size; dpt.x += text->delta_all.x * num_chars; dpt.y += text->delta_all.y * num_chars; } if (text->operation & TEXT_ADD_TO_SPACE_WIDTH) { dpt.x += text->delta_space.x * num_spaces; dpt.y += text->delta_space.y * num_spaces; } pte->returned.total_width = dpt; gs_distance_transform(dpt.x, dpt.y, &ctm_only(pis), &dpt); code = gx_path_add_point(path, origin.x + float2fixed(dpt.x), origin.y + float2fixed(dpt.y)); if (code < 0) goto dfree; } dputs(")\n"); *ppenum = pte; return 0; dfree: gs_free_object(memory, pte, "trace_text_begin"); dflt: dputs(") DEFAULTED\n"); return gx_default_text_begin(dev, pis, text, font, path, pdcolor, pcpath, memory, ppenum); } /* ---------------- The device definition ---------------- */ #define TRACE_DEVICE_BODY(dname, ncomp, depth, map_rgb_color, map_color_rgb, map_cmyk_color, map_rgb_alpha_color)\ std_device_dci_body(gx_device, 0, dname,\ DEFAULT_WIDTH_10THS * X_DPI / 10,\ DEFAULT_HEIGHT_10THS * Y_DPI / 10,\ X_DPI, Y_DPI, ncomp, depth,\ (1 << (depth / ncomp)) - 1,\ (ncomp > 1 ? (1 << (depth / ncomp)) - 1 : 0),\ 1 << (depth / ncomp),\ (ncomp > 1 ? 1 << (depth / ncomp) : 1)),\ {\ NULL, /* open_device */\ NULL, /* get_initial_matrix */\ NULL, /* sync_output */\ NULL, /* output_page */\ NULL, /* close_device */\ map_rgb_color, /* differs */\ map_color_rgb, /* differs */\ trace_fill_rectangle,\ NULL, /* tile_rectangle */\ trace_copy_mono,\ trace_copy_color,\ NULL, /* draw_line */\ NULL, /* get_bits */\ NULL, /* get_params */\ NULL, /* put_params */\ map_cmyk_color, /* differs */\ NULL, /* get_xfont_procs */\ NULL, /* get_xfont_device */\ map_rgb_alpha_color, /* differs */\ gx_page_device_get_page_device,\ NULL, /* get_alpha_bits */\ trace_copy_alpha,\ NULL, /* get_band */\ NULL, /* copy_rop */\ trace_fill_path,\ trace_stroke_path,\ trace_fill_mask,\ trace_fill_trapezoid,\ trace_fill_parallelogram,\ trace_fill_triangle,\ trace_draw_thin_line,\ NULL, /* begin_image */\ NULL, /* image_data */\ NULL, /* end_image */\ trace_strip_tile_rectangle,\ trace_strip_copy_rop,\ NULL, /* get_clipping_box */\ trace_begin_typed_image,\ NULL, /* get_bits_rectangle */\ NULL, /* map_color_rgb_alpha */\ NULL, /* create_compositor */\ NULL, /* get_hardware_params */\ trace_text_begin,\ NULL /* finish_copydevice */\ } const gx_device gs_tr_mono_device = { TRACE_DEVICE_BODY("tr_mono", 1, 1, gx_default_b_w_map_rgb_color, gx_default_b_w_map_color_rgb, NULL, NULL) }; const gx_device gs_tr_rgb_device = { TRACE_DEVICE_BODY("tr_rgb", 3, 24, gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb, NULL, NULL) }; const gx_device gs_tr_cmyk_device = { TRACE_DEVICE_BODY("tr_cmyk", 4, 4, NULL, cmyk_1bit_map_color_rgb, cmyk_1bit_map_cmyk_color, NULL) };