/* Copyright (C) 1993, 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: gspcolor.c,v 1.4.6.1.2.1 2003/01/17 00:49:03 giles Exp $ */ /* Pattern color operators and procedures for Ghostscript library */ #include "math_.h" #include "gx.h" #include "gserrors.h" #include "gsrop.h" #include "gsstruct.h" #include "gsutil.h" /* for gs_next_ids */ #include "gxarith.h" #include "gxfixed.h" #include "gxmatrix.h" #include "gxcoord.h" /* for gs_concat, gx_tr'_to_fixed */ #include "gxcspace.h" /* for gscolor2.h */ #include "gxcolor2.h" #include "gxdcolor.h" #include "gxdevice.h" #include "gxdevmem.h" #include "gxclip2.h" #include "gspath.h" #include "gxpath.h" #include "gxpcolor.h" #include "gzstate.h" #include "gsimage.h" #include "gsiparm4.h" /* GC descriptors */ public_st_pattern_template(); public_st_pattern_instance(); /* Define the Pattern color space. */ gs_private_st_composite(st_color_space_Pattern, gs_paint_color_space, "gs_color_space_Pattern", cs_Pattern_enum_ptrs, cs_Pattern_reloc_ptrs); private cs_proc_num_components(gx_num_components_Pattern); private cs_proc_base_space(gx_base_space_Pattern); private cs_proc_remap_color(gx_remap_Pattern); private cs_proc_init_color(gx_init_Pattern); private cs_proc_restrict_color(gx_restrict_Pattern); private cs_proc_install_cspace(gx_install_Pattern); private cs_proc_adjust_cspace_count(gx_adjust_cspace_Pattern); private cs_proc_adjust_color_count(gx_adjust_color_Pattern); const gs_color_space_type gs_color_space_type_Pattern = { gs_color_space_index_Pattern, false, false, &st_color_space_Pattern, gx_num_components_Pattern, gx_base_space_Pattern, gx_cspace_not_equal, gx_init_Pattern, gx_restrict_Pattern, gx_no_concrete_space, gx_no_concretize_color, NULL, gx_remap_Pattern, gx_install_Pattern, gx_adjust_cspace_Pattern, gx_adjust_color_Pattern }; /* Initialize a generic pattern template. */ void gs_pattern_common_init(gs_pattern_template_t * ppat, const gs_pattern_type_t *type) { ppat->type = type; ppat->PatternType = type->PatternType; uid_set_invalid(&ppat->uid); ppat->client_data = 0; /* for GC */ } /* Generic makepattern */ int gs_make_pattern(gs_client_color * pcc, const gs_pattern_template_t * pcp, const gs_matrix * pmat, gs_state * pgs, gs_memory_t * mem) { return pcp->type->procs.make_pattern(pcc, pcp, pmat, pgs, mem); } /* * Do the generic work for makepattern: allocate the instance and the * saved graphics state, and fill in the common members. */ int gs_make_pattern_common(gs_client_color *pcc, const gs_pattern_template_t *ptemp, const gs_matrix *pmat, gs_state *pgs, gs_memory_t *mem, gs_memory_type_ptr_t pstype) { gs_pattern_instance_t *pinst; gs_state *saved; if (mem == 0) mem = gs_state_memory(pgs); rc_alloc_struct_1(pinst, gs_pattern_instance_t, pstype, mem, return_error(gs_error_VMerror), "gs_make_pattern_common"); pinst->rc.free = rc_free_pattern_instance; pinst->type = ptemp->type; saved = gs_state_copy(pgs, mem); if (saved == 0) { gs_free_object(mem, pinst, "gs_make_pattern_common"); return_error(gs_error_VMerror); } gs_concat(saved, pmat); gs_newpath(saved); pinst->saved = saved; pcc->pattern = pinst; return 0; } /* Free the saved gstate when freeing a Pattern instance. */ void rc_free_pattern_instance(gs_memory_t * mem, void *pinst_void, client_name_t cname) { gs_pattern_instance_t *pinst = pinst_void; gs_state_free(pinst->saved); rc_free_struct_only(mem, pinst_void, cname); } /* setpattern */ int gs_setpattern(gs_state * pgs, const gs_client_color * pcc) { int code = gs_setpatternspace(pgs); if (code < 0) return code; return gs_setcolor(pgs, pcc); } /* setpatternspace */ /* This does all the work of setpattern except for the final setcolor. */ int gs_setpatternspace(gs_state * pgs) { int code = 0; if (pgs->in_cachedevice) return_error(gs_error_undefined); if (pgs->color_space->type->index != gs_color_space_index_Pattern) { gs_color_space cs; gs_cspace_init(&cs, &gs_color_space_type_Pattern, NULL); /**************** base_space SETTING IS WRONG ****************/ cs.params.pattern.base_space = *(gs_paint_color_space *) pgs->color_space; cs.params.pattern.has_base_space = true; *pgs->color_space = cs; /* Don't change orig_base_cspace_index. */ pgs->orig_cspace_index = gs_color_space_index_Pattern; cs_full_init_color(pgs->ccolor, &cs); gx_unset_dev_color(pgs); } return code; } /* * Adjust the reference count of a pattern. This is intended to support * applications (such as PCL) which maintain client colors outside of the * graphic state. Since the pattern instance structure is opaque to these * applications, they need some way to release or retain the instances as * needed. */ void gs_pattern_reference(gs_client_color * pcc, int delta) { if (pcc->pattern != 0) rc_adjust(pcc->pattern, delta, "gs_pattern_reference"); } /* getpattern */ /* This is only intended for the benefit of pattern PaintProcs. */ const gs_pattern_template_t * gs_get_pattern(const gs_client_color * pcc) { const gs_pattern_instance_t *pinst = pcc->pattern; return (pinst == 0 ? 0 : pinst->type->procs.get_pattern(pinst)); } /* * Get the number of components in a Pattern color. * For backward compatibility, and to distinguish Pattern color spaces * from all others, we negate the result. */ private int gx_num_components_Pattern(const gs_color_space * pcs) { return (pcs->params.pattern.has_base_space ? -1 - cs_num_components((const gs_color_space *) &(pcs->params.pattern.base_space)) : -1 /* Pattern dictionary only */ ); } /* Get the base space of a Pattern color space. */ private const gs_color_space * gx_base_space_Pattern(const gs_color_space * pcs) { return (pcs->params.pattern.has_base_space ? (const gs_color_space *)&(pcs->params.pattern.base_space) : NULL); } /* Remap a Pattern color. */ private int gx_remap_Pattern(const gs_client_color * pc, const gs_color_space * pcs, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { if (pc->pattern == 0) { color_set_null_pattern(pdc); return 0; } return pc->pattern->type->procs.remap_color(pc, pcs, pdc, pis, dev, select); } /* Initialize a Pattern color. */ private void gx_init_Pattern(gs_client_color * pcc, const gs_color_space * pcs) { if (pcs->params.pattern.has_base_space) { const gs_color_space *pbcs = (const gs_color_space *)&pcs->params.pattern.base_space; cs_init_color(pcc, pbcs); } /*pcc->pattern = 0; *//* cs_full_init_color handles this */ } /* Force a Pattern color into legal range. */ /* Note that if the pattern is uncolored (PaintType = 2), */ /* the color space must have a base space: we check this here only */ /* to prevent accessing uninitialized data, but if there is no base space, */ /* it is an error that we count on being detected elsewhere. */ private void gx_restrict_Pattern(gs_client_color * pcc, const gs_color_space * pcs) { /* We need a special check for the null pattern. */ if (pcc->pattern && pcc->pattern->type->procs.uses_base_space(gs_get_pattern(pcc)) && pcs->params.pattern.has_base_space ) { const gs_color_space *pbcs = (const gs_color_space *)&pcs->params.pattern.base_space; (*pbcs->type->restrict_color) (pcc, pbcs); } } /* Install a Pattern color space. */ private int gx_install_Pattern(const gs_color_space * pcs, gs_state * pgs) { if (!pcs->params.pattern.has_base_space) return 0; return (*pcs->params.pattern.base_space.type->install_cspace) ((const gs_color_space *) & pcs->params.pattern.base_space, pgs); } /* Adjust the reference counts for Pattern color spaces or colors. */ private void gx_adjust_cspace_Pattern(const gs_color_space * pcs, int delta) { if (pcs->params.pattern.has_base_space) (*pcs->params.pattern.base_space.type->adjust_cspace_count) ((const gs_color_space *)&pcs->params.pattern.base_space, delta); } private void gx_adjust_color_Pattern(const gs_client_color * pcc, const gs_color_space * pcs, int delta) { gs_pattern_instance_t *pinst = pcc->pattern; rc_adjust_only(pinst, delta, "gx_adjust_color_Pattern"); if (pcs && pcs->params.pattern.has_base_space) (*pcs->params.pattern.base_space.type->adjust_color_count) (pcc, (const gs_color_space *)&pcs->params.pattern.base_space, delta); } /* GC procedures */ private ENUM_PTRS_BEGIN_PROC(cs_Pattern_enum_ptrs) { EV_CONST gs_color_space *const pcs = vptr; if (!pcs->params.pattern.has_base_space) return 0; return ENUM_USING(*pcs->params.pattern.base_space.type->stype, &pcs->params.pattern.base_space, sizeof(pcs->params.pattern.base_space), index); } ENUM_PTRS_END_PROC private RELOC_PTRS_WITH(cs_Pattern_reloc_ptrs, gs_color_space *pcs) { if (!pcs->params.pattern.has_base_space) return; RELOC_USING(*pcs->params.pattern.base_space.type->stype, &pcs->params.pattern.base_space, sizeof(gs_paint_color_space)); } RELOC_PTRS_END