/* Copyright (C) 2001 artofcode LLC. 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. Author: Raph Levien */ /*$Id: gsdfilt.c,v 1.3.2.1.2.1 2003/01/17 00:49:02 giles Exp $ */ /* Functions for managing the device filter stack */ #include "ctype_.h" #include "memory_.h" /* for memchr, memcpy */ #include "string_.h" #include "gx.h" #include "gp.h" #include "gscdefs.h" /* for gs_lib_device_list */ #include "gserrors.h" #include "gsfname.h" #include "gsstruct.h" #include "gspath.h" /* gs_initclip prototype */ #include "gspaint.h" /* gs_erasepage prototype */ #include "gsmatrix.h" /* for gscoord.h */ #include "gscoord.h" /* for gs_initmatrix */ #include "gzstate.h" #include "gxcmap.h" #include "gxdevice.h" #include "gxdevmem.h" #include "gxiodev.h" #include "gsdfilt.h" struct gs_device_filter_stack_s { gs_device_filter_stack_t *next; gs_device_filter_t *df; gx_device *next_device; }; gs_private_st_ptrs3(st_gs_device_filter_stack, gs_device_filter_stack_t, "gs_device_filter_stack", gs_device_filter_stack_enum_ptrs, gs_device_filter_stack_reloc_ptrs, next, df, next_device); gs_public_st_simple(st_gs_device_filter, gs_device_filter_t, "gs_device_filter"); #ifdef DFILTER_TEST /* The test device filter installs a simple forwarding device which changes the behavior of map_rgb_color to "bleach" colors. It is only here for testing purposes, and isn't necessary to be compiled in production code. */ private gx_color_index gs_test_device_filter_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g, gx_color_value b) { gx_device_forward * const fdev = (gx_device_forward *)dev; gx_device *tdev = fdev->target; r += (gx_max_color_value - r) >> 1; g += (gx_max_color_value - g) >> 1; b += (gx_max_color_value - b) >> 1; return dev_proc(tdev, map_rgb_color)(tdev, r, g, b); } private const gx_device_forward gs_test_device_filter_device = {std_device_std_body_open(gx_device_forward, 0, "Device filter test device", 0, 0, 1, 1), {NULL, /* open_device */ NULL, /* get_initial_matrix */ NULL, /* sync_output */ NULL, /* output_page */ NULL, /* close_device */ gs_test_device_filter_map_rgb_color } }; private int gs_test_device_filter_push(gs_device_filter_t *self, gs_memory_t *mem, gx_device **pdev, gx_device *target) { gx_device_forward *fdev; fdev = gs_alloc_struct_immovable(mem, gx_device_forward, &st_device_forward, "gs_test_device_filter_push"); if (fdev == 0) return_error(gs_error_VMerror); gx_device_init((gx_device *)fdev, (const gx_device *)&gs_test_device_filter_device, mem, false); gx_device_forward_fill_in_procs(fdev); gx_device_copy_params((gx_device *)fdev, target); gx_device_set_target(fdev, target); *pdev = (gx_device *)fdev; return 0; } private int gs_test_device_filter_pop(gs_device_filter_t *self, gs_memory_t *mem, gs_state *pgs, gx_device *dev) { gx_device_set_target((gx_device_forward *)dev, NULL); gs_free_object(mem, self, "gs_test_device_filter_pop"); return 0; } int gs_test_device_filter(gs_device_filter_t **pdf, gs_memory_t *mem) { gs_device_filter_t *df; df = gs_alloc_struct(mem, gs_device_filter_t, &st_gs_device_filter, "gs_test_device_filter"); if (df == 0) return_error(gs_error_VMerror); df->push = gs_test_device_filter_push; df->pop = gs_test_device_filter_pop; *pdf = df; return 0; } #endif int gs_push_device_filter(gs_memory_t *mem, gs_state *pgs, gs_device_filter_t *df) { gs_device_filter_stack_t *dfs; gx_device *new_dev = NULL; int code; dfs = gs_alloc_struct(mem, gs_device_filter_stack_t, &st_gs_device_filter_stack, "gs_push_device_filter"); if (dfs == NULL) return_error(gs_error_VMerror); rc_increment(pgs->device); dfs->next_device = pgs->device; code = df->push(df, mem, &new_dev, pgs->device); if (code < 0) { return code; gs_free_object(mem, dfs, "gs_push_device_filter"); } dfs->next = pgs->dfilter_stack; pgs->dfilter_stack = dfs; dfs->df = df; gs_setdevice_no_init(pgs, new_dev); rc_decrement_only(new_dev, "gs_push_device_filter"); return code; } int gs_pop_device_filter(gs_memory_t *mem, gs_state *pgs) { gs_device_filter_stack_t *dfs_tos = pgs->dfilter_stack; gs_device_filter_t *df; int code; if (dfs_tos == NULL) return_error(gs_error_rangecheck); df = dfs_tos->df; code = df->pop(df, mem, pgs, pgs->device); pgs->dfilter_stack = dfs_tos->next; gs_setdevice_no_init(pgs, dfs_tos->next_device); rc_decrement_only(dfs_tos->next_device, "gs_pop_device_filter"); gs_free_object(mem, dfs_tos, "gs_pop_device_filter"); return code; } int gs_clear_device_filters(gs_memory_t *mem, gs_state *pgs) { int code; while (pgs->dfilter_stack != NULL) { if ((code = gs_pop_device_filter(mem, pgs)) < 0) return code; } return 0; }