1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Transparency operators */
18 #include "string_.h"
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gscspace.h"		/* for gscolor2.h */
23 #include "gscolor2.h"
24 #include "gsipar3x.h"
25 #include "gstrans.h"
26 #include "gxiparam.h"		/* for image enumerator */
27 #include "gxcspace.h"
28 #include "idict.h"
29 #include "idparam.h"
30 #include "ifunc.h"
31 #include "igstate.h"
32 #include "iimage.h"
33 #include "iname.h"
34 #include "store.h"
35 #include "gsdfilt.h"
36 #include "gdevdevn.h"
37 #include "gxblend.h"
38 #include "gdevp14.h"
39 
40 /* ------ Utilities ------ */
41 
42 static int
set_float_value(i_ctx_t * i_ctx_p,int (* set_value)(gs_state *,floatp))43 set_float_value(i_ctx_t *i_ctx_p, int (*set_value)(gs_state *, floatp))
44 {
45     os_ptr op = osp;
46     double value;
47     int code;
48 
49     if (real_param(op, &value) < 0)
50         return_op_typecheck(op);
51     if ((code = set_value(igs, value)) < 0)
52         return code;
53     pop(1);
54     return 0;
55 }
56 
57 static int
current_float_value(i_ctx_t * i_ctx_p,float (* current_value)(const gs_state *))58 current_float_value(i_ctx_t *i_ctx_p,
59                     float (*current_value)(const gs_state *))
60 {
61     os_ptr op = osp;
62 
63     push(1);
64     make_real(op, current_value(igs));
65     return 0;
66 }
67 
68 static int
enum_param(const gs_memory_t * mem,const ref * pnref,const char * const names[])69 enum_param(const gs_memory_t *mem, const ref *pnref,
70            const char *const names[])
71 {
72     const char *const *p;
73     ref nsref;
74 
75     name_string_ref(mem, pnref, &nsref);
76     for (p = names; *p; ++p)
77         if (r_size(&nsref) == strlen(*p) &&
78             !memcmp(*p, nsref.value.const_bytes, r_size(&nsref))
79             )
80             return p - names;
81     return_error(e_rangecheck);
82 }
83 
84 /* ------ Graphics state operators ------ */
85 
86 static const char *const blend_mode_names[] = {
87     GS_BLEND_MODE_NAMES, 0
88 };
89 
90 /* <modename> .setblendmode - */
91 static int
zsetblendmode(i_ctx_t * i_ctx_p)92 zsetblendmode(i_ctx_t *i_ctx_p)
93 {
94     os_ptr op = osp;
95     int code;
96 
97     check_type(*op, t_name);
98     if ((code = enum_param(imemory, op, blend_mode_names)) < 0 ||
99         (code = gs_setblendmode(igs, code)) < 0
100         )
101         return code;
102     pop(1);
103     return 0;
104 }
105 
106 /* - .currentblendmode <modename> */
107 static int
zcurrentblendmode(i_ctx_t * i_ctx_p)108 zcurrentblendmode(i_ctx_t *i_ctx_p)
109 {
110     os_ptr op = osp;
111     const char *mode_name = blend_mode_names[gs_currentblendmode(igs)];
112     ref nref;
113     int code = name_enter_string(imemory, mode_name, &nref);
114 
115     if (code < 0)
116         return code;
117     push(1);
118     *op = nref;
119     return 0;
120 }
121 
122 /* <0..1> .setopacityalpha - */
123 static int
zsetopacityalpha(i_ctx_t * i_ctx_p)124 zsetopacityalpha(i_ctx_t *i_ctx_p)
125 {
126     return set_float_value(i_ctx_p, gs_setopacityalpha);
127 }
128 
129 /* - .currentopacityalpha <0..1> */
130 static int
zcurrentopacityalpha(i_ctx_t * i_ctx_p)131 zcurrentopacityalpha(i_ctx_t *i_ctx_p)
132 {
133     return current_float_value(i_ctx_p, gs_currentopacityalpha);
134 }
135 
136 /* <0..1> .setshapealpha - */
137 static int
zsetshapealpha(i_ctx_t * i_ctx_p)138 zsetshapealpha(i_ctx_t *i_ctx_p)
139 {
140     return set_float_value(i_ctx_p, gs_setshapealpha);
141 }
142 
143 /* - .currentshapealpha <0..1> */
144 static int
zcurrentshapealpha(i_ctx_t * i_ctx_p)145 zcurrentshapealpha(i_ctx_t *i_ctx_p)
146 {
147     return current_float_value(i_ctx_p, gs_currentshapealpha);
148 }
149 
150 /* <bool> .settextknockout - */
151 static int
zsettextknockout(i_ctx_t * i_ctx_p)152 zsettextknockout(i_ctx_t *i_ctx_p)
153 {
154     os_ptr op = osp;
155 
156     check_type(*op, t_boolean);
157     gs_settextknockout(igs, op->value.boolval);
158     pop(1);
159     return 0;
160 }
161 
162 /* - .currenttextknockout <bool> */
163 static int
zcurrenttextknockout(i_ctx_t * i_ctx_p)164 zcurrenttextknockout(i_ctx_t *i_ctx_p)
165 {
166     os_ptr op = osp;
167 
168     push(1);
169     make_bool(op, gs_currenttextknockout(igs));
170     return 0;
171 }
172 
173 /* ------ Rendering stack operators ------ */
174 
175 static int
rect_param(gs_rect * prect,os_ptr op)176 rect_param(gs_rect *prect, os_ptr op)
177 {
178     double coords[4];
179     int code = num_params(op, 4, coords);
180 
181     if (code < 0)
182         return code;
183     prect->p.x = coords[0], prect->p.y = coords[1];
184     prect->q.x = coords[2], prect->q.y = coords[3];
185     return 0;
186 }
187 
188 static int
mask_op(i_ctx_t * i_ctx_p,int (* mask_proc)(gs_state *,gs_transparency_channel_selector_t))189 mask_op(i_ctx_t *i_ctx_p,
190         int (*mask_proc)(gs_state *, gs_transparency_channel_selector_t))
191 {
192     int csel;
193     int code = int_param(osp, 1, &csel);
194 
195     if (code < 0)
196         return code;
197     code = mask_proc(igs, csel);
198     if (code >= 0)
199         pop(1);
200     return code;
201 
202 }
203 
204 /* <paramdict> <llx> <lly> <urx> <ury> .begintransparencygroup - */
205 static int
zbegintransparencygroup(i_ctx_t * i_ctx_p)206 zbegintransparencygroup(i_ctx_t *i_ctx_p)
207 {
208     os_ptr op = osp;
209     os_ptr dop = op - 4;
210     gs_transparency_group_params_t params;
211     gs_rect bbox;
212     ref *dummy;
213     int code;
214 
215     check_type(*dop, t_dictionary);
216     check_dict_read(*dop);
217     gs_trans_group_params_init(&params);
218     if ((code = dict_bool_param(dop, "Isolated", false, &params.Isolated)) < 0 ||
219         (code = dict_bool_param(dop, "Knockout", false, &params.Knockout)) < 0 ||
220         (code = dict_bool_param(dop, ".image_with_SMask", false, &params.image_with_SMask)) < 0
221         )
222         return code;
223     code = rect_param(&bbox, op);
224     if (code < 0)
225         return code;
226     /* If the CS is not given in the transparency group dict, set to NULL   */
227     /* so that the transparency code knows to inherit from the parent layer */
228     if (dict_find_string(dop, "CS", &dummy) <= 0) {
229         params.ColorSpace = NULL;
230     } else {
231         /* the PDF interpreter set the colorspace, so use it */
232         params.ColorSpace = gs_currentcolorspace(igs);
233     }
234     code = gs_begin_transparency_group(igs, &params, &bbox);
235     if (code < 0)
236         return code;
237     pop(5);
238     return code;
239 }
240 
241 /* - .discardtransparencygroup - */
242 static int
zdiscardtransparencygroup(i_ctx_t * i_ctx_p)243 zdiscardtransparencygroup(i_ctx_t *i_ctx_p)
244 {
245     if (gs_current_transparency_type(igs) != TRANSPARENCY_STATE_Group)
246         return_error(e_rangecheck);
247     return gs_discard_transparency_layer(igs);
248 }
249 
250 /* - .endtransparencygroup - */
251 static int
zendtransparencygroup(i_ctx_t * i_ctx_p)252 zendtransparencygroup(i_ctx_t *i_ctx_p)
253 {
254     return gs_end_transparency_group(igs);
255 }
256 
257 /* <cs_set?> <paramdict> <llx> <lly> <urx> <ury> .begintransparencymaskgroup -	*/
258 /*             cs_set == false if we are inheriting the colorspace		*/
259 static int tf_using_function(floatp, float *, void *);
260 static int
zbegintransparencymaskgroup(i_ctx_t * i_ctx_p)261 zbegintransparencymaskgroup(i_ctx_t *i_ctx_p)
262 {
263     os_ptr op = osp;
264     os_ptr dop = op - 4;
265     gs_transparency_mask_params_t params;
266     ref *pparam;
267     gs_rect bbox;
268     int code;
269     static const char *const subtype_names[] = {
270         GS_TRANSPARENCY_MASK_SUBTYPE_NAMES, 0
271     };
272 
273     check_type(*dop, t_dictionary);
274     check_dict_read(*dop);
275     if (dict_find_string(dop, "Subtype", &pparam) <= 0)
276         return_error(e_rangecheck);
277     if ((code = enum_param(imemory, pparam, subtype_names)) < 0)
278         return code;
279     gs_trans_mask_params_init(&params, code);
280     params.replacing = true;
281     if ((code = dict_floats_param(imemory, dop, "Background",
282                     cs_num_components(gs_currentcolorspace(i_ctx_p->pgs)),
283                                   params.Background, NULL)) < 0)
284         return code;
285     else if (code > 0)
286         params.Background_components = code;
287     if ((code = dict_floats_param(imemory, dop, "GrayBackground",
288                     1, &params.GrayBackground, NULL)) < 0)
289         return code;
290     if (dict_find_string(dop, "TransferFunction", &pparam) > 0) {
291         gs_function_t *pfn = ref_function(pparam);
292 
293         if (pfn == 0 || pfn->params.m != 1 || pfn->params.n != 1)
294             return_error(e_rangecheck);
295         params.TransferFunction = tf_using_function;
296         params.TransferFunction_data = pfn;
297     }
298     code = rect_param(&bbox, op);
299     if (code < 0)
300         return code;
301     /* Is the colorspace set for this mask ? */
302     if (op[-5].value.boolval) {
303                 params.ColorSpace = gs_currentcolorspace(igs);
304     } else {
305         params.ColorSpace = NULL;
306     }
307     code = gs_begin_transparency_mask(igs, &params, &bbox, false);
308     if (code < 0)
309         return code;
310     pop(6);
311     return code;
312 }
313 
314 /* - .begintransparencymaskimage - */
315 static int
zbegintransparencymaskimage(i_ctx_t * i_ctx_p)316 zbegintransparencymaskimage(i_ctx_t *i_ctx_p)
317 {
318     gs_transparency_mask_params_t params;
319     gs_rect bbox = { { 0, 0} , { 1, 1} };
320     int code;
321     gs_color_space *gray_cs = gs_cspace_new_DeviceGray(imemory);
322 
323     if (!gray_cs)
324         return_error(e_VMerror);
325     gs_trans_mask_params_init(&params, TRANSPARENCY_MASK_Luminosity);
326     code = gs_begin_transparency_mask(igs, &params, &bbox, true);
327     if (code < 0)
328         return code;
329     rc_decrement_cs(gray_cs, "zbegintransparencymaskimage");
330     return code;
331 }
332 
333 /* Implement the TransferFunction using a Function. */
334 static int
tf_using_function(floatp in_val,float * out,void * proc_data)335 tf_using_function(floatp in_val, float *out, void *proc_data)
336 {
337     float in = in_val;
338     gs_function_t *const pfn = proc_data;
339 
340     return gs_function_evaluate(pfn, &in, out);
341 }
342 
343 /* - .discardtransparencymask - */
344 static int
zdiscardtransparencymask(i_ctx_t * i_ctx_p)345 zdiscardtransparencymask(i_ctx_t *i_ctx_p)
346 {
347     if (gs_current_transparency_type(igs) != TRANSPARENCY_STATE_Mask)
348         return_error(e_rangecheck);
349     return gs_discard_transparency_layer(igs);
350 }
351 
352 /* <mask#> .endtransparencymask - */
353 static int
zendtransparencymask(i_ctx_t * i_ctx_p)354 zendtransparencymask(i_ctx_t *i_ctx_p)
355 {
356     return mask_op(i_ctx_p, gs_end_transparency_mask);
357 }
358 
359 /* ------ Soft-mask images ------ */
360 
361 /* <dict> .image3x - */
362 static int mask_dict_param(const gs_memory_t *mem, os_ptr,
363                             image_params *, const char *, int,
364                             gs_image3x_mask_t *);
365 static int
zimage3x(i_ctx_t * i_ctx_p)366 zimage3x(i_ctx_t *i_ctx_p)
367 {
368     os_ptr op = osp;
369     gs_image3x_t image;
370     ref *pDataDict;
371     image_params ip_data;
372     int num_components =
373         gs_color_space_num_components(gs_currentcolorspace(igs));
374     int ignored;
375     int code;
376 
377     check_type(*op, t_dictionary);
378     check_dict_read(*op);
379     memset(&image, 0, sizeof(gs_image3x_t));
380     gs_image3x_t_init(&image, NULL);
381     if (dict_find_string(op, "DataDict", &pDataDict) <= 0)
382         return_error(e_rangecheck);
383     if ((code = pixel_image_params(i_ctx_p, pDataDict,
384                    (gs_pixel_image_t *)&image, &ip_data,
385                    16, false, gs_currentcolorspace(igs))) < 0 ||
386         (code = dict_int_param(pDataDict, "ImageType", 1, 1, 0, &ignored)) < 0
387         )
388         return code;
389     /*
390      * We have to process the masks in the reverse order, because they
391      * insert their DataSource before the one(s) for the DataDict.
392      */
393     if ((code = mask_dict_param(imemory, op, &ip_data,
394                                 "ShapeMaskDict", num_components,
395                                 &image.Shape)) < 0 ||
396         (code = mask_dict_param(imemory, op, &ip_data,
397                                 "OpacityMaskDict", num_components,
398                                 &image.Opacity)) < 0
399         )
400         return code;
401     return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image,
402                         &ip_data.DataSource[0],
403                         image.CombineWithColor, 1);
404 }
405 
406 /* Get one soft-mask dictionary parameter. */
407 static int
mask_dict_param(const gs_memory_t * mem,os_ptr op,image_params * pip_data,const char * dict_name,int num_components,gs_image3x_mask_t * pixm)408 mask_dict_param(const gs_memory_t *mem, os_ptr op,
409 image_params *pip_data, const char *dict_name,
410                 int num_components, gs_image3x_mask_t *pixm)
411 {
412     ref *pMaskDict;
413     image_params ip_mask;
414     int ignored;
415     int code, mcode;
416 
417     if (dict_find_string(op, dict_name, &pMaskDict) <= 0)
418         return 1;
419     if ((mcode = code = data_image_params(mem, pMaskDict, &pixm->MaskDict,
420                                           &ip_mask, false, 1, 16, false, false)) < 0 ||
421         (code = dict_int_param(pMaskDict, "ImageType", 1, 1, 0, &ignored)) < 0 ||
422         (code = dict_int_param(pMaskDict, "InterleaveType", 1, 3, -1,
423                                &pixm->InterleaveType)) < 0 ||
424         (code = dict_floats_param(mem, op, "Matte", num_components,
425                                   pixm->Matte, NULL)) < 0
426         )
427         return code;
428     pixm->has_Matte = code > 0;
429     /*
430      * The MaskDict must have a DataSource iff InterleaveType == 3.
431      */
432     if ((pip_data->MultipleDataSources && pixm->InterleaveType != 3) ||
433         ip_mask.MultipleDataSources ||
434         mcode != (pixm->InterleaveType != 3)
435         )
436         return_error(e_rangecheck);
437     if (pixm->InterleaveType == 3) {
438         /* Insert the mask DataSource before the data DataSources. */
439         memmove(&pip_data->DataSource[1], &pip_data->DataSource[0],
440                 (countof(pip_data->DataSource) - 1) *
441                 sizeof(pip_data->DataSource[0]));
442         pip_data->DataSource[0] = ip_mask.DataSource[0];
443     }
444     return 0;
445 }
446 
447 /* depth .pushpdf14devicefilter - */
448 /* this is a filter operator, but we include it here to maintain
449    modularity of the pdf14 transparency support */
450 static int
zpushpdf14devicefilter(i_ctx_t * i_ctx_p)451 zpushpdf14devicefilter(i_ctx_t *i_ctx_p)
452 {
453     int code;
454     os_ptr op = osp;
455 
456     check_type(*op, t_integer);
457     code = gs_push_pdf14trans_device(igs, false);
458     if (code < 0)
459         return code;
460     pop(1);
461     return 0;
462 }
463 
464 /* this is a filter operator, but we include it here to maintain
465    modularity of the pdf14 transparency support */
466 static int
zpoppdf14devicefilter(i_ctx_t * i_ctx_p)467 zpoppdf14devicefilter(i_ctx_t *i_ctx_p)
468 {
469     return gs_pop_pdf14trans_device(igs, false);
470 }
471 
472 /* This is used to communicate to the transparency compositor
473    when a q (save extended graphic state) occurs.  Since
474    the softmask is part of the graphic state we need to know
475    this to handle clist processing properly */
476 
477 static int
zpushextendedgstate(i_ctx_t * i_ctx_p)478 zpushextendedgstate(i_ctx_t *i_ctx_p)
479 {
480     int code;
481     code = gs_push_transparency_state(igs);
482     return(code);
483 }
484 
485 /* This is used to communicate to the transparency compositor
486    when a Q (restore extended graphic state) occurs.  Since
487    the softmask is part of the graphic state we need to know
488    this to handle clist processing properly */
489 
490 static int
zpopextendedgstate(i_ctx_t * i_ctx_p)491 zpopextendedgstate(i_ctx_t *i_ctx_p)
492 {
493     int code;
494     code = gs_pop_transparency_state(igs, false);
495     return(code);
496 }
497 
498 /* ------ Initialization procedure ------ */
499 
500 /* We need to split the table because of the 16-element limit. */
501 const op_def ztrans1_op_defs[] = {
502     {"1.setblendmode", zsetblendmode},
503     {"0.currentblendmode", zcurrentblendmode},
504     {"1.setopacityalpha", zsetopacityalpha},
505     {"0.currentopacityalpha", zcurrentopacityalpha},
506     {"1.setshapealpha", zsetshapealpha},
507     {"0.currentshapealpha", zcurrentshapealpha},
508     {"1.settextknockout", zsettextknockout},
509     {"0.currenttextknockout", zcurrenttextknockout},
510     {"0.pushextendedgstate", zpushextendedgstate},
511     {"0.popextendedgstate", zpopextendedgstate},
512     op_def_end(0)
513 };
514 const op_def ztrans2_op_defs[] = {
515     {"5.begintransparencygroup", zbegintransparencygroup},
516     {"0.discardtransparencygroup", zdiscardtransparencygroup},
517     {"0.endtransparencygroup", zendtransparencygroup},
518     {"5.begintransparencymaskgroup", zbegintransparencymaskgroup},
519     {"5.begintransparencymaskimage", zbegintransparencymaskimage},
520     {"0.discardtransparencymask", zdiscardtransparencymask},
521     {"1.endtransparencymask", zendtransparencymask},
522     {"1.image3x", zimage3x},
523     {"1.pushpdf14devicefilter", zpushpdf14devicefilter},
524     {"0.poppdf14devicefilter", zpoppdf14devicefilter},
525     op_def_end(0)
526 };
527