xref: /plan9/sys/src/cmd/gs/src/gsptype2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gsptype2.c,v 1.19 2005/05/25 15:57:58 igor Exp $ */
18 /* PatternType 2 implementation */
19 #include "gx.h"
20 #include "gserrors.h"
21 #include "gscspace.h"
22 #include "gsshade.h"
23 #include "gsmatrix.h"           /* for gspcolor.h */
24 #include "gsstate.h"            /* for set/currentfilladjust */
25 #include "gxcolor2.h"
26 #include "gxdcolor.h"
27 #include "gsptype2.h"
28 #include "gxpcolor.h"
29 #include "gxstate.h"            /* for gs_state_memory */
30 #include "gzpath.h"
31 #include "gzstate.h"
32 
33 /* GC descriptors */
34 private_st_pattern2_template();
35 private_st_pattern2_instance();
36 
37 /* GC procedures */
ENUM_PTRS_BEGIN(pattern2_instance_enum_ptrs)38 private ENUM_PTRS_BEGIN(pattern2_instance_enum_ptrs) {
39     if (index < st_pattern2_template_max_ptrs) {
40         gs_ptr_type_t ptype =
41             ENUM_SUPER_ELT(gs_pattern2_instance_t, st_pattern2_template,
42                            template, 0);
43 
44         if (ptype)
45             return ptype;
46         return ENUM_OBJ(NULL);  /* don't stop early */
47     }
48     ENUM_PREFIX(st_pattern_instance, st_pattern2_template_max_ptrs);
49 }
50 ENUM_PTRS_END
RELOC_PTRS_BEGIN(pattern2_instance_reloc_ptrs)51 private RELOC_PTRS_BEGIN(pattern2_instance_reloc_ptrs) {
52     RELOC_PREFIX(st_pattern_instance);
53     RELOC_SUPER(gs_pattern2_instance_t, st_pattern2_template, template);
54 } RELOC_PTRS_END
55 
56 /* Define a PatternType 2 pattern. */
57 private pattern_proc_uses_base_space(gs_pattern2_uses_base_space);
58 private pattern_proc_make_pattern(gs_pattern2_make_pattern);
59 private pattern_proc_get_pattern(gs_pattern2_get_pattern);
60 private pattern_proc_remap_color(gs_pattern2_remap_color);
61 private pattern_proc_set_color(gs_pattern2_set_color);
62 private const gs_pattern_type_t gs_pattern2_type = {
63     2, {
64         gs_pattern2_uses_base_space, gs_pattern2_make_pattern,
65         gs_pattern2_get_pattern, gs_pattern2_remap_color,
66         gs_pattern2_set_color,
67     }
68 };
69 
70 /* Initialize a PatternType 2 pattern. */
71 void
gs_pattern2_init(gs_pattern2_template_t * ppat)72 gs_pattern2_init(gs_pattern2_template_t * ppat)
73 {
74     gs_pattern_common_init((gs_pattern_template_t *)ppat, &gs_pattern2_type);
75 }
76 
77 /* Test whether a PatternType 2 pattern uses a base space. */
78 private bool
gs_pattern2_uses_base_space(const gs_pattern_template_t * ptemp)79 gs_pattern2_uses_base_space(const gs_pattern_template_t *ptemp)
80 {
81     return false;
82 }
83 
84 /* Make an instance of a PatternType 2 pattern. */
85 private int
gs_pattern2_make_pattern(gs_client_color * pcc,const gs_pattern_template_t * pcp,const gs_matrix * pmat,gs_state * pgs,gs_memory_t * mem)86 gs_pattern2_make_pattern(gs_client_color * pcc,
87                          const gs_pattern_template_t * pcp,
88                          const gs_matrix * pmat, gs_state * pgs,
89                          gs_memory_t * mem)
90 {
91     const gs_pattern2_template_t *ptemp =
92         (const gs_pattern2_template_t *)pcp;
93     int code = gs_make_pattern_common(pcc, pcp, pmat, pgs, mem,
94                                       &st_pattern2_instance);
95     gs_pattern2_instance_t *pinst;
96 
97     if (code < 0)
98         return code;
99     pinst = (gs_pattern2_instance_t *)pcc->pattern;
100     pinst->template = *ptemp;
101     pinst->shfill = false;
102     return 0;
103 }
104 
105 /* Get the template of a PatternType 2 pattern instance. */
106 private const gs_pattern_template_t *
gs_pattern2_get_pattern(const gs_pattern_instance_t * pinst)107 gs_pattern2_get_pattern(const gs_pattern_instance_t *pinst)
108 {
109     return (const gs_pattern_template_t *)
110         &((const gs_pattern2_instance_t *)pinst)->template;
111 }
112 
113 /* Set the 'shfill' flag to a PatternType 2 pattern instance. */
114 int
gs_pattern2_set_shfill(gs_client_color * pcc)115 gs_pattern2_set_shfill(gs_client_color * pcc)
116 {
117     gs_pattern2_instance_t *pinst;
118 
119     if (pcc->pattern->type != &gs_pattern2_type)
120 	return_error(gs_error_unregistered); /* Must not happen. */
121     pinst = (gs_pattern2_instance_t *)pcc->pattern;
122     pinst->shfill = true;
123     return 0;
124 }
125 
126 
127 /* ---------------- Rendering ---------------- */
128 
129 /* GC descriptor */
130 gs_private_st_ptrs_add0(st_dc_pattern2, gx_device_color, "dc_pattern2",
131                         dc_pattern2_enum_ptrs, dc_pattern2_reloc_ptrs,
132                         st_client_color, ccolor);
133 
134 private dev_color_proc_get_dev_halftone(gx_dc_pattern2_get_dev_halftone);
135 private dev_color_proc_load(gx_dc_pattern2_load);
136 private dev_color_proc_fill_rectangle(gx_dc_pattern2_fill_rectangle);
137 private dev_color_proc_equal(gx_dc_pattern2_equal);
138 private dev_color_proc_save_dc(gx_dc_pattern2_save_dc);
139 /*
140  * Define the PatternType 2 Pattern device color type.  This is public only
141  * for testing when writing PDF or PostScript.
142  */
143 const gx_device_color_type_t gx_dc_pattern2 = {
144     &st_dc_pattern2,
145     gx_dc_pattern2_save_dc, gx_dc_pattern2_get_dev_halftone,
146     gx_dc_ht_get_phase,
147     gx_dc_pattern2_load, gx_dc_pattern2_fill_rectangle,
148     gx_dc_default_fill_masked, gx_dc_pattern2_equal,
149     gx_dc_pattern_write, gx_dc_pattern_read,
150     gx_dc_pattern_get_nonzero_comps
151 };
152 
153 /* Check device color for Pattern Type 2. */
154 bool
gx_dc_is_pattern2_color(const gx_device_color * pdevc)155 gx_dc_is_pattern2_color(const gx_device_color *pdevc)
156 {
157     return pdevc->type == &gx_dc_pattern2;
158 }
159 
160 /*
161  * The device halftone used by a PatternType 2 patter is that current in
162  * the graphic state at the time of the makepattern call.
163  */
164 private const gx_device_halftone *
gx_dc_pattern2_get_dev_halftone(const gx_device_color * pdevc)165 gx_dc_pattern2_get_dev_halftone(const gx_device_color * pdevc)
166 {
167     return ((gs_pattern2_instance_t *)pdevc->ccolor.pattern)->saved->dev_ht;
168 }
169 
170 /* Load a PatternType 2 color into the cache.  (No effect.) */
171 private int
gx_dc_pattern2_load(gx_device_color * pdevc,const gs_imager_state * ignore_pis,gx_device * ignore_dev,gs_color_select_t ignore_select)172 gx_dc_pattern2_load(gx_device_color *pdevc, const gs_imager_state *ignore_pis,
173                     gx_device *ignore_dev, gs_color_select_t ignore_select)
174 {
175     return 0;
176 }
177 
178 /* Remap a PatternType 2 color. */
179 private int
gs_pattern2_remap_color(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)180 gs_pattern2_remap_color(const gs_client_color * pc, const gs_color_space * pcs,
181                         gx_device_color * pdc, const gs_imager_state * pis,
182                         gx_device * dev, gs_color_select_t select)
183 {
184     /* We don't do any actual color mapping now. */
185     pdc->type = &gx_dc_pattern2;
186     pdc->ccolor = *pc;
187     pdc->ccolor_valid = true;
188     return 0;
189 }
190 
191 /*
192  * Perform actions required at set_color time. Since PatternType 2
193  * patterns specify a color space, we must update the overprint
194  * information as required by that color space. We temporarily disable
195  * overprint_mode, as it is never applicable when using shading patterns.
196  */
197 private int
gs_pattern2_set_color(const gs_client_color * pcc,gs_state * pgs)198 gs_pattern2_set_color(const gs_client_color * pcc, gs_state * pgs)
199 {
200     gs_pattern2_instance_t * pinst = (gs_pattern2_instance_t *)pcc->pattern;
201     gs_color_space * pcs = pinst->template.Shading->params.ColorSpace;
202     int code, save_overprint_mode = pgs->overprint_mode;
203 
204     pgs->overprint_mode = 0;
205     code = pcs->type->set_overprint(pcs, pgs);
206     pgs->overprint_mode = save_overprint_mode;
207     return code;
208 }
209 
210 /* Fill path or rect, and with a PatternType 2 color. */
211 int
gx_dc_pattern2_fill_path(const gx_device_color * pdevc,gx_path * ppath,gs_fixed_rect * rect,gx_device * dev)212 gx_dc_pattern2_fill_path(const gx_device_color * pdevc,
213                               gx_path * ppath, gs_fixed_rect * rect,
214                               gx_device * dev)
215 {
216     gs_pattern2_instance_t *pinst =
217         (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
218 
219     return gs_shading_fill_path_adjusted(pinst->template.Shading, ppath, rect, dev,
220                                 (gs_imager_state *)pinst->saved, !pinst->shfill);
221 }
222 
223 /* Fill a rectangle with a PatternType 2 color. */
224 private int
gx_dc_pattern2_fill_rectangle(const gx_device_color * pdevc,int x,int y,int w,int h,gx_device * dev,gs_logical_operation_t lop,const gx_rop_source_t * source)225 gx_dc_pattern2_fill_rectangle(const gx_device_color * pdevc, int x, int y,
226                               int w, int h, gx_device * dev,
227                               gs_logical_operation_t lop,
228                               const gx_rop_source_t * source)
229 {
230     gs_fixed_rect rect;
231     rect.p.x = int2fixed(x);
232     rect.p.y = int2fixed(y);
233     rect.q.x = int2fixed(x + w);
234     rect.q.y = int2fixed(y + h);
235     return gx_dc_pattern2_fill_path(pdevc, NULL, &rect,  dev);
236 }
237 
238 /* Compare two PatternType 2 colors for equality. */
239 private bool
gx_dc_pattern2_equal(const gx_device_color * pdevc1,const gx_device_color * pdevc2)240 gx_dc_pattern2_equal(const gx_device_color * pdevc1,
241                      const gx_device_color * pdevc2)
242 {
243     return pdevc2->type == pdevc1->type &&
244         pdevc1->ccolor.pattern == pdevc2->ccolor.pattern;
245 }
246 
247 /*
248  * Currently patterns cannot be passed through the command list,
249  * however vector devices need to save a color for comparing
250  * it with another color, which appears later.
251  * We provide a minimal support, which is necessary
252  * for the current implementation of pdfwrite.
253  * It is not sufficient for restoring the pattern from the saved color.
254  */
255 private void
gx_dc_pattern2_save_dc(const gx_device_color * pdevc,gx_device_color_saved * psdc)256 gx_dc_pattern2_save_dc(
257     const gx_device_color * pdevc,
258     gx_device_color_saved * psdc )
259 {
260     gs_pattern2_instance_t * pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
261 
262     psdc->type = pdevc->type;
263     psdc->colors.pattern2.id = pinst->pattern_id;
264 }
265 
266 /* Transform a shading bounding box into device space. */
267 /* This is just a bridge to an old code. */
268 int
gx_dc_pattern2_shade_bbox_transform2fixed(const gs_rect * rect,const gs_imager_state * pis,gs_fixed_rect * rfixed)269 gx_dc_pattern2_shade_bbox_transform2fixed(const gs_rect * rect, const gs_imager_state * pis,
270 			   gs_fixed_rect * rfixed)
271 {
272     gs_rect dev_rect;
273     int code = gs_bbox_transform(rect, &ctm_only(pis), &dev_rect);
274 
275     if (code >= 0) {
276 	rfixed->p.x = float2fixed(dev_rect.p.x);
277 	rfixed->p.y = float2fixed(dev_rect.p.y);
278 	rfixed->q.x = float2fixed(dev_rect.q.x);
279 	rfixed->q.y = float2fixed(dev_rect.q.y);
280     }
281     return code;
282 }
283 
284 /* Get a shading bbox. Returns 1 on success. */
285 int
gx_dc_pattern2_get_bbox(const gx_device_color * pdevc,gs_fixed_rect * bbox)286 gx_dc_pattern2_get_bbox(const gx_device_color * pdevc, gs_fixed_rect *bbox)
287 {
288     gs_pattern2_instance_t *pinst =
289         (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
290     int code;
291 
292     if (!pinst->template.Shading->params.have_BBox)
293 	return 0;
294     code = gx_dc_pattern2_shade_bbox_transform2fixed(
295 		&pinst->template.Shading->params.BBox, (gs_imager_state *)pinst->saved, bbox);
296     if (code < 0)
297 	return code;
298     return 1;
299 }
300 
301 /* Check device color for a possibly self-overlapping shading. */
302 bool
gx_dc_pattern2_can_overlap(const gx_device_color * pdevc)303 gx_dc_pattern2_can_overlap(const gx_device_color *pdevc)
304 {
305     gs_pattern2_instance_t * pinst;
306 
307     if (pdevc->type != &gx_dc_pattern2)
308 	return false;
309     pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
310     switch (pinst->template.Shading->head.type) {
311 	case 3: case 6: case 7:
312 	    return true;
313 	default:
314 	    return false;
315     }
316 }
317 
318 /* Check whether a pattern color has a background. */
gx_dc_pattern2_has_background(const gx_device_color * pdevc)319 bool gx_dc_pattern2_has_background(const gx_device_color *pdevc)
320 {
321     gs_pattern2_instance_t * pinst;
322     const gs_shading_t *Shading;
323 
324     if (pdevc->type != &gx_dc_pattern2)
325 	return false;
326     pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
327     Shading = pinst->template.Shading;
328     return !pinst->shfill && Shading->params.Background != NULL;
329 }
330