/* Copyright (C) 1997, 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: zshade.c,v 1.4.6.2.2.1 2003/01/17 00:49:06 giles Exp $ */ /* PostScript language interface to shading */ #include "memory_.h" #include "ghost.h" #include "oper.h" #include "gscolor3.h" #include "gscspace.h" #include "gscolor2.h" /* requires gscspace.h */ #include "gsfunc3.h" #include "gsptype2.h" #include "gsstruct.h" /* must precede gsshade.h */ #include "gsshade.h" #include "gsuid.h" #include "stream.h" /* for files.h */ #include "files.h" #include "ialloc.h" #include "idict.h" #include "idparam.h" #include "ifunc.h" #include "igstate.h" #include "ipcolor.h" #include "store.h" /* Forward references */ private int shading_param(P2(const_os_ptr op, const gs_shading_t ** ppsh)); /* ---------------- Standard operators ---------------- */ /* - currentsmoothness */ private int zcurrentsmoothness(i_ctx_t *i_ctx_p) { os_ptr op = osp; push(1); make_real(op, gs_currentsmoothness(igs)); return 0; } /* setsmoothness - */ private int zsetsmoothness(i_ctx_t *i_ctx_p) { os_ptr op = osp; double smoothness; int code; if (real_param(op, &smoothness) < 0) return_op_typecheck(op); if ((code = gs_setsmoothness(igs, smoothness)) < 0) return code; pop(1); return 0; } /* .shfill - */ private int zshfill(i_ctx_t *i_ctx_p) { os_ptr op = osp; const gs_shading_t *psh; int code = shading_param(op, &psh); if (code < 0 || (code = gs_shfill(igs, psh)) < 0) return code; pop(1); return 0; } /* ------ Non-standard operators ------ */ /* .buildshadingpattern */ private int zbuildshadingpattern(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr op2 = op - 2; gs_matrix mat; gs_pattern2_template_t template; int_pattern *pdata; gs_client_color cc_instance; int code; check_type(*op2, t_dictionary); check_dict_read(*op2); gs_pattern2_init(&template); if ((code = read_matrix(op - 1, &mat)) < 0 || (code = dict_uid_param(op2, &template.uid, 1, imemory, i_ctx_p)) != 1 || (code = shading_param(op, &template.Shading)) < 0 || (code = int_pattern_alloc(&pdata, op2, imemory)) < 0 ) return_error((code < 0 ? code : e_rangecheck)); template.client_data = pdata; code = gs_make_pattern(&cc_instance, (const gs_pattern_template_t *)&template, &mat, igs, imemory); if (code < 0) { ifree_object(pdata, "int_pattern"); return code; } make_istruct(op - 1, a_readonly, cc_instance.pattern); pop(1); return code; } /* ------ Internal procedures ------ */ /* Get a shading parameter. */ private int shading_param(const_os_ptr op, const gs_shading_t ** ppsh) { /* * Since shadings form a subclass hierarchy, we currently have * no way to check whether a structure is actually a shading. */ if (!r_is_struct(op) || r_has_masked_attrs(op, a_executable | a_execute, a_all) ) return_error(e_typecheck); *ppsh = (gs_shading_t *) op->value.pstruct; return 0; } /* ---------------- Shading dictionaries ---------------- */ /* ------ Common code ------ */ extern_st(st_color_space); typedef int (*build_shading_proc_t) (P5(i_ctx_t *i_ctx_p, const ref *op, const gs_shading_params_t *params, gs_shading_t **ppsh, gs_memory_t *mem)); /* Operators */ /* Common framework for building shadings. */ private int build_shading(i_ctx_t *i_ctx_p, build_shading_proc_t proc) { os_ptr op = osp; int code; float box[4]; gs_shading_params_t params; gs_shading_t *psh; ref *pvalue; check_type(*op, t_dictionary); params.ColorSpace = 0; params.Background = 0; /* Collect parameters common to all shading types. */ { const gs_color_space *pcs_orig = gs_currentcolorspace(igs); int num_comp = gs_color_space_num_components(pcs_orig); gs_color_space *pcs; if (num_comp < 0) /* Pattern color space */ return_error(e_rangecheck); pcs = ialloc_struct(gs_color_space, &st_color_space, "build_shading"); if (pcs == 0) return_error(e_VMerror); gs_cspace_init_from(pcs, pcs_orig); params.ColorSpace = pcs; if (dict_find_string(op, "Background", &pvalue) > 0) { gs_client_color *pcc = ialloc_struct(gs_client_color, &st_client_color, "build_shading"); if (pcc == 0) { code = gs_note_error(e_VMerror); goto fail; } pcc->pattern = 0; params.Background = pcc; code = dict_floats_param(op, "Background", gs_color_space_num_components(pcs), pcc->paint.values, NULL); if (code < 0) goto fail; } } if (dict_find_string(op, "BBox", &pvalue) <= 0) params.have_BBox = false; else if ((code = dict_floats_param(op, "BBox", 4, box, NULL)) == 4) { params.BBox.p.x = box[0]; params.BBox.p.y = box[1]; params.BBox.q.x = box[2]; params.BBox.q.y = box[3]; params.have_BBox = true; } else goto fail; code = dict_bool_param(op, "AntiAlias", false, ¶ms.AntiAlias); if (code < 0) goto fail; /* Finish building the shading. */ code = (*proc)(i_ctx_p, op, ¶ms, &psh, imemory); if (code < 0) goto fail; make_istruct_new(op, 0, psh); return code; fail: gs_free_object(imemory, params.Background, "Background"); if (params.ColorSpace) { gs_cspace_release(params.ColorSpace); gs_free_object(imemory, params.ColorSpace, "ColorSpace"); } return (code < 0 ? code : gs_note_error(e_rangecheck)); } /* Collect a Function value. */ private int build_shading_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn, int num_inputs, gs_memory_t *mem) { ref *pFunction; *ppfn = 0; if (dict_find_string(op, "Function", &pFunction) <= 0) return 0; if (r_is_array(pFunction)) { uint size = r_size(pFunction); gs_function_t **Functions; uint i; gs_function_AdOt_params_t params; int code; check_read(*pFunction); if (size == 0) return_error(e_rangecheck); code = alloc_function_array(size, &Functions, mem); if (code < 0) return code; for (i = 0; i < size; ++i) { ref rsubfn; array_get(pFunction, (long)i, &rsubfn); code = fn_build_function(i_ctx_p, &rsubfn, &Functions[i], mem); if (code < 0) break; } params.m = 1; params.Domain = 0; params.n = size; params.Range = 0; params.Functions = (const gs_function_t * const *)Functions; if (code >= 0) code = gs_function_AdOt_init(ppfn, ¶ms, mem); if (code < 0) gs_function_AdOt_free_params(¶ms, mem); return code; } else return fn_build_function(i_ctx_p, pFunction, ppfn, mem); } /* ------ Build shadings ------ */ /* Build a ShadingType 1 (Function-based) shading. */ private int build_shading_1(i_ctx_t *i_ctx_p, const ref * op, const gs_shading_params_t * pcommon, gs_shading_t ** ppsh, gs_memory_t *mem) { gs_shading_Fb_params_t params; int code; static const float default_Domain[4] = {0, 1, 0, 1}; *(gs_shading_params_t *)¶ms = *pcommon; gs_make_identity(¶ms.Matrix); params.Function = 0; if ((code = dict_floats_param(op, "Domain", 4, params.Domain, default_Domain)) < 0 || (code = dict_matrix_param(op, "Matrix", ¶ms.Matrix)) < 0 || (code = build_shading_function(i_ctx_p, op, ¶ms.Function, 2, mem)) < 0 || (code = gs_shading_Fb_init(ppsh, ¶ms, mem)) < 0 ) { gs_free_object(mem, params.Function, "Function"); return code; } return 0; } /* .buildshading1 */ private int zbuildshading1(i_ctx_t *i_ctx_p) { return build_shading(i_ctx_p, build_shading_1); } /* Collect parameters for an Axial or Radial shading. */ private int build_directional_shading(i_ctx_t *i_ctx_p, const ref * op, float *Coords, int num_Coords, float Domain[2], gs_function_t ** pFunction, bool Extend[2], gs_memory_t *mem) { int code = dict_floats_param(op, "Coords", num_Coords, Coords, NULL); static const float default_Domain[2] = {0, 1}; ref *pExtend; *pFunction = 0; if (code < 0 || (code = dict_floats_param(op, "Domain", 2, Domain, default_Domain)) < 0 || (code = build_shading_function(i_ctx_p, op, pFunction, 1, mem)) < 0 ) return code; if (dict_find_string(op, "Extend", &pExtend) <= 0) Extend[0] = Extend[1] = false; else { ref E0, E1; if (!r_is_array(pExtend)) return_error(e_typecheck); else if (r_size(pExtend) != 2) return_error(e_rangecheck); else if ((array_get(pExtend, 0L, &E0), !r_has_type(&E0, t_boolean)) || (array_get(pExtend, 1L, &E1), !r_has_type(&E1, t_boolean)) ) return_error(e_typecheck); Extend[0] = E0.value.boolval, Extend[1] = E1.value.boolval; } return 0; } /* Build a ShadingType 2 (Axial) shading. */ private int build_shading_2(i_ctx_t *i_ctx_p, const ref * op, const gs_shading_params_t * pcommon, gs_shading_t ** ppsh, gs_memory_t *mem) { gs_shading_A_params_t params; int code; *(gs_shading_params_t *)¶ms = *pcommon; if ((code = build_directional_shading(i_ctx_p, op, params.Coords, 4, params.Domain, ¶ms.Function, params.Extend, mem)) < 0 || (code = gs_shading_A_init(ppsh, ¶ms, mem)) < 0 ) { gs_free_object(mem, params.Function, "Function"); } return code; } /* .buildshading2 */ private int zbuildshading2(i_ctx_t *i_ctx_p) { return build_shading(i_ctx_p, build_shading_2); } /* Build a ShadingType 3 (Radial) shading. */ private int build_shading_3(i_ctx_t *i_ctx_p, const ref * op, const gs_shading_params_t * pcommon, gs_shading_t ** ppsh, gs_memory_t *mem) { gs_shading_R_params_t params; int code; *(gs_shading_params_t *)¶ms = *pcommon; if ((code = build_directional_shading(i_ctx_p, op, params.Coords, 6, params.Domain, ¶ms.Function, params.Extend, mem)) < 0 || (code = gs_shading_R_init(ppsh, ¶ms, mem)) < 0 ) { gs_free_object(mem, params.Function, "Function"); } return code; } /* .buildshading3 */ private int zbuildshading3(i_ctx_t *i_ctx_p) { return build_shading(i_ctx_p, build_shading_3); } /* Collect parameters for a mesh shading. */ private int build_mesh_shading(i_ctx_t *i_ctx_p, const ref * op, gs_shading_mesh_params_t * params, float **pDecode, gs_function_t ** pFunction, gs_memory_t *mem) { int code; ref *pDataSource; *pDecode = 0; *pFunction = 0; if (dict_find_string(op, "DataSource", &pDataSource) <= 0) return_error(e_rangecheck); if (r_is_array(pDataSource)) { uint size = r_size(pDataSource); float *data = (float *)gs_alloc_byte_array(mem, size, sizeof(float), "build_mesh_shading"); int code; if (data == 0) return_error(e_VMerror); code = float_params(pDataSource->value.refs + size - 1, size, data); if (code < 0) { gs_free_object(mem, data, "build_mesh_shading"); return code; } data_source_init_floats(¶ms->DataSource, data, size); } else switch (r_type(pDataSource)) { case t_file: { stream *s; check_read_file(s, pDataSource); data_source_init_stream(¶ms->DataSource, s); break; } case t_string: check_read(*pDataSource); data_source_init_string2(¶ms->DataSource, pDataSource->value.bytes, r_size(pDataSource)); break; default: return_error(e_typecheck); } if (data_source_is_array(params->DataSource)) { params->BitsPerCoordinate = 0; params->BitsPerComponent = 0; } else { int num_decode = 4 + gs_color_space_num_components(params->ColorSpace) * 2; /****** FREE FLOAT ARRAY DATA ON ERROR ******/ if ((code = dict_int_param(op, "BitsPerCoordinate", 1, 32, 0, ¶ms->BitsPerCoordinate)) < 0 || (code = dict_int_param(op, "BitsPerComponent", 1, 16, 0, ¶ms->BitsPerComponent)) < 0 ) return code; *pDecode = (float *) gs_alloc_byte_array(mem, num_decode, sizeof(float), "build_mesh_shading"); if (*pDecode == 0) return_error(e_VMerror); code = dict_floats_param(op, "Decode", num_decode, *pDecode, NULL); if (code < 0) { gs_free_object(mem, *pDecode, "build_mesh_shading"); *pDecode = 0; return code; } } code = build_shading_function(i_ctx_p, op, pFunction, 1, mem); if (code < 0) { gs_free_object(mem, *pDecode, "build_mesh_shading"); *pDecode = 0; } return code; } /* Collect the BitsPerFlag parameter, if relevant. */ private int flag_bits_param(const ref * op, const gs_shading_mesh_params_t * params, int *pBitsPerFlag) { if (data_source_is_array(params->DataSource)) { *pBitsPerFlag = 0; return 0; } else { return dict_int_param(op, "BitsPerFlag", 2, 8, 0, pBitsPerFlag); } } /* Build a ShadingType 4 (Free-form Gouraud triangle mesh) shading. */ private int build_shading_4(i_ctx_t *i_ctx_p, const ref * op, const gs_shading_params_t * pcommon, gs_shading_t ** ppsh, gs_memory_t *mem) { gs_shading_FfGt_params_t params; int code; *(gs_shading_params_t *)¶ms = *pcommon; if ((code = build_mesh_shading(i_ctx_p, op, (gs_shading_mesh_params_t *)¶ms, ¶ms.Decode, ¶ms.Function, mem)) < 0 || (code = flag_bits_param(op, (gs_shading_mesh_params_t *)¶ms, ¶ms.BitsPerFlag)) < 0 || (code = gs_shading_FfGt_init(ppsh, ¶ms, mem)) < 0 ) { gs_free_object(mem, params.Function, "Function"); gs_free_object(mem, params.Decode, "Decode"); } return code; } /* .buildshading4 */ private int zbuildshading4(i_ctx_t *i_ctx_p) { return build_shading(i_ctx_p, build_shading_4); } /* Build a ShadingType 5 (Lattice-form Gouraud triangle mesh) shading. */ private int build_shading_5(i_ctx_t *i_ctx_p, const ref * op, const gs_shading_params_t * pcommon, gs_shading_t ** ppsh, gs_memory_t *mem) { gs_shading_LfGt_params_t params; int code; *(gs_shading_params_t *)¶ms = *pcommon; if ((code = build_mesh_shading(i_ctx_p, op, (gs_shading_mesh_params_t *)¶ms, ¶ms.Decode, ¶ms.Function, mem)) < 0 || (code = dict_int_param(op, "VerticesPerRow", 2, max_int, 0, ¶ms.VerticesPerRow)) < 0 || (code = gs_shading_LfGt_init(ppsh, ¶ms, mem)) < 0 ) { gs_free_object(mem, params.Function, "Function"); gs_free_object(mem, params.Decode, "Decode"); } return code; } /* .buildshading5 */ private int zbuildshading5(i_ctx_t *i_ctx_p) { return build_shading(i_ctx_p, build_shading_5); } /* Build a ShadingType 6 (Coons patch mesh) shading. */ private int build_shading_6(i_ctx_t *i_ctx_p, const ref * op, const gs_shading_params_t * pcommon, gs_shading_t ** ppsh, gs_memory_t *mem) { gs_shading_Cp_params_t params; int code; *(gs_shading_params_t *)¶ms = *pcommon; if ((code = build_mesh_shading(i_ctx_p, op, (gs_shading_mesh_params_t *)¶ms, ¶ms.Decode, ¶ms.Function, mem)) < 0 || (code = flag_bits_param(op, (gs_shading_mesh_params_t *)¶ms, ¶ms.BitsPerFlag)) < 0 || (code = gs_shading_Cp_init(ppsh, ¶ms, mem)) < 0 ) { gs_free_object(mem, params.Function, "Function"); gs_free_object(mem, params.Decode, "Decode"); } return code; } /* .buildshading6 */ private int zbuildshading6(i_ctx_t *i_ctx_p) { return build_shading(i_ctx_p, build_shading_6); } /* Build a ShadingType 7 (Tensor product patch mesh) shading. */ private int build_shading_7(i_ctx_t *i_ctx_p, const ref * op, const gs_shading_params_t * pcommon, gs_shading_t ** ppsh, gs_memory_t *mem) { gs_shading_Tpp_params_t params; int code; *(gs_shading_params_t *)¶ms = *pcommon; if ((code = build_mesh_shading(i_ctx_p, op, (gs_shading_mesh_params_t *)¶ms, ¶ms.Decode, ¶ms.Function, mem)) < 0 || (code = flag_bits_param(op, (gs_shading_mesh_params_t *)¶ms, ¶ms.BitsPerFlag)) < 0 || (code = gs_shading_Tpp_init(ppsh, ¶ms, mem)) < 0 ) { gs_free_object(mem, params.Function, "Function"); gs_free_object(mem, params.Decode, "Decode"); } return code; } /* .buildshading7 */ private int zbuildshading7(i_ctx_t *i_ctx_p) { return build_shading(i_ctx_p, build_shading_7); } /* ------ Initialization procedure ------ */ const op_def zshade_op_defs[] = { op_def_begin_ll3(), {"0currentsmoothness", zcurrentsmoothness}, {"1setsmoothness", zsetsmoothness}, {"1.shfill", zshfill}, {"1.buildshading1", zbuildshading1}, {"1.buildshading2", zbuildshading2}, {"1.buildshading3", zbuildshading3}, {"1.buildshading4", zbuildshading4}, {"1.buildshading5", zbuildshading5}, {"1.buildshading6", zbuildshading6}, {"1.buildshading7", zbuildshading7}, {"3.buildshadingpattern", zbuildshadingpattern}, op_def_end(0) };