2 |
- |
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: gsptype1.c,v 1.23 2005/06/15 18:40:07 igor Exp $ */
|
|
|
18 |
/* PatternType 1 pattern implementation */
|
|
|
19 |
#include "math_.h"
|
|
|
20 |
#include "gx.h"
|
|
|
21 |
#include "gserrors.h"
|
|
|
22 |
#include "gsrop.h"
|
|
|
23 |
#include "gsstruct.h"
|
|
|
24 |
#include "gsutil.h" /* for gs_next_ids */
|
|
|
25 |
#include "gxarith.h"
|
|
|
26 |
#include "gxfixed.h"
|
|
|
27 |
#include "gxmatrix.h"
|
|
|
28 |
#include "gxcoord.h" /* for gs_concat, gx_tr'_to_fixed */
|
|
|
29 |
#include "gxcspace.h" /* for gscolor2.h */
|
|
|
30 |
#include "gxcolor2.h"
|
|
|
31 |
#include "gxdcolor.h"
|
|
|
32 |
#include "gxdevice.h"
|
|
|
33 |
#include "gxdevmem.h"
|
|
|
34 |
#include "gxclip2.h"
|
|
|
35 |
#include "gspath.h"
|
|
|
36 |
#include "gxpath.h"
|
|
|
37 |
#include "gxpcolor.h"
|
|
|
38 |
#include "gxp1impl.h" /* requires gxpcolor.h */
|
|
|
39 |
#include "gzstate.h"
|
|
|
40 |
#include "gsimage.h"
|
|
|
41 |
#include "gsiparm4.h"
|
|
|
42 |
#include "gsovrc.h"
|
|
|
43 |
|
|
|
44 |
/* Temporary switches for experimanting with Adobe compatibility. */
|
|
|
45 |
#define ADJUST_SCALE_FOR_THIN_LINES 0 /* Old code = 0 */
|
|
|
46 |
#define ADJUST_SCALE_BY_GS_TRADITION 0 /* Old code = 1 */
|
|
|
47 |
#define ADJUST_AS_ADOBE 1 /* Old code = 0 *//* This one is closer to Adobe. */
|
|
|
48 |
|
|
|
49 |
/* GC descriptors */
|
|
|
50 |
private_st_pattern1_template();
|
|
|
51 |
private_st_pattern1_instance();
|
|
|
52 |
|
|
|
53 |
/* GC procedures */
|
|
|
54 |
private ENUM_PTRS_BEGIN(pattern1_instance_enum_ptrs) {
|
|
|
55 |
if (index < st_pattern1_template_max_ptrs) {
|
|
|
56 |
gs_ptr_type_t ptype =
|
|
|
57 |
ENUM_SUPER_ELT(gs_pattern1_instance_t, st_pattern1_template,
|
|
|
58 |
template, 0);
|
|
|
59 |
|
|
|
60 |
if (ptype)
|
|
|
61 |
return ptype;
|
|
|
62 |
return ENUM_OBJ(NULL); /* don't stop early */
|
|
|
63 |
}
|
|
|
64 |
ENUM_PREFIX(st_pattern_instance, st_pattern1_template_max_ptrs);
|
|
|
65 |
} ENUM_PTRS_END
|
|
|
66 |
private RELOC_PTRS_BEGIN(pattern1_instance_reloc_ptrs) {
|
|
|
67 |
RELOC_PREFIX(st_pattern_instance);
|
|
|
68 |
RELOC_SUPER(gs_pattern1_instance_t, st_pattern1_template, template);
|
|
|
69 |
} RELOC_PTRS_END
|
|
|
70 |
|
|
|
71 |
/* Define a PatternType 1 pattern. */
|
|
|
72 |
private pattern_proc_uses_base_space(gs_pattern1_uses_base_space);
|
|
|
73 |
private pattern_proc_make_pattern(gs_pattern1_make_pattern);
|
|
|
74 |
private pattern_proc_get_pattern(gs_pattern1_get_pattern);
|
|
|
75 |
private pattern_proc_set_color(gs_pattern1_set_color);
|
|
|
76 |
private const gs_pattern_type_t gs_pattern1_type = {
|
|
|
77 |
1, {
|
|
|
78 |
gs_pattern1_uses_base_space, gs_pattern1_make_pattern,
|
|
|
79 |
gs_pattern1_get_pattern, gs_pattern1_remap_color,
|
|
|
80 |
gs_pattern1_set_color
|
|
|
81 |
}
|
|
|
82 |
};
|
|
|
83 |
|
|
|
84 |
/*
|
|
|
85 |
* Build a PatternType 1 Pattern color space.
|
|
|
86 |
*/
|
|
|
87 |
int
|
|
|
88 |
gs_cspace_build_Pattern1(gs_color_space ** ppcspace,
|
|
|
89 |
const gs_color_space * pbase_cspace, gs_memory_t * pmem)
|
|
|
90 |
{
|
|
|
91 |
gs_color_space *pcspace = 0;
|
|
|
92 |
int code;
|
|
|
93 |
|
|
|
94 |
if (pbase_cspace != 0) {
|
|
|
95 |
if (gs_color_space_num_components(pcspace) < 0) /* Pattern space */
|
|
|
96 |
return_error(gs_error_rangecheck);
|
|
|
97 |
}
|
|
|
98 |
code = gs_cspace_alloc(&pcspace, &gs_color_space_type_Pattern, pmem);
|
|
|
99 |
if (code < 0)
|
|
|
100 |
return code;
|
|
|
101 |
if (pbase_cspace != 0) {
|
|
|
102 |
pcspace->params.pattern.has_base_space = true;
|
|
|
103 |
gs_cspace_init_from((gs_color_space *) & (pcspace->params.pattern.base_space),
|
|
|
104 |
pbase_cspace
|
|
|
105 |
);
|
|
|
106 |
} else
|
|
|
107 |
pcspace->params.pattern.has_base_space = false;
|
|
|
108 |
*ppcspace = pcspace;
|
|
|
109 |
return 0;
|
|
|
110 |
}
|
|
|
111 |
|
|
|
112 |
/* Initialize a PatternType 1 pattern template. */
|
|
|
113 |
void
|
|
|
114 |
gs_pattern1_init(gs_pattern1_template_t * ppat)
|
|
|
115 |
{
|
|
|
116 |
gs_pattern_common_init((gs_pattern_template_t *)ppat, &gs_pattern1_type);
|
|
|
117 |
}
|
|
|
118 |
|
|
|
119 |
/* Make an instance of a PatternType 1 pattern. */
|
|
|
120 |
private int compute_inst_matrix(gs_pattern1_instance_t * pinst,
|
|
|
121 |
const gs_state * saved, gs_rect * pbbox, int width, int height);
|
|
|
122 |
int
|
|
|
123 |
gs_makepattern(gs_client_color * pcc, const gs_pattern1_template_t * pcp,
|
|
|
124 |
const gs_matrix * pmat, gs_state * pgs, gs_memory_t * mem)
|
|
|
125 |
{
|
|
|
126 |
return gs_pattern1_make_pattern(pcc, (const gs_pattern_template_t *)pcp,
|
|
|
127 |
pmat, pgs, mem);
|
|
|
128 |
}
|
|
|
129 |
private int
|
|
|
130 |
gs_pattern1_make_pattern(gs_client_color * pcc,
|
|
|
131 |
const gs_pattern_template_t * ptemp,
|
|
|
132 |
const gs_matrix * pmat, gs_state * pgs,
|
|
|
133 |
gs_memory_t * mem)
|
|
|
134 |
{
|
|
|
135 |
const gs_pattern1_template_t *pcp = (const gs_pattern1_template_t *)ptemp;
|
|
|
136 |
gs_pattern1_instance_t inst;
|
|
|
137 |
gs_pattern1_instance_t *pinst;
|
|
|
138 |
gs_state *saved;
|
|
|
139 |
gs_rect bbox;
|
|
|
140 |
gs_fixed_rect cbox;
|
|
|
141 |
gx_device * pdev = pgs->device;
|
|
|
142 |
int dev_width = pdev->width;
|
|
|
143 |
int dev_height = pdev->height;
|
|
|
144 |
int code = gs_make_pattern_common(pcc, (const gs_pattern_template_t *)pcp,
|
|
|
145 |
pmat, pgs, mem,
|
|
|
146 |
&st_pattern1_instance);
|
|
|
147 |
|
|
|
148 |
if (code < 0)
|
|
|
149 |
return code;
|
|
|
150 |
if (mem == 0)
|
|
|
151 |
mem = gs_state_memory(pgs);
|
|
|
152 |
pinst = (gs_pattern1_instance_t *)pcc->pattern;
|
|
|
153 |
*(gs_pattern_instance_t *)&inst = *(gs_pattern_instance_t *)pinst;
|
|
|
154 |
saved = inst.saved;
|
|
|
155 |
switch (pcp->PaintType) {
|
|
|
156 |
case 1: /* colored */
|
|
|
157 |
gs_set_logical_op(saved, lop_default);
|
|
|
158 |
break;
|
|
|
159 |
case 2: /* uncolored */
|
|
|
160 |
gx_set_device_color_1(saved);
|
|
|
161 |
break;
|
|
|
162 |
default:
|
|
|
163 |
code = gs_note_error(gs_error_rangecheck);
|
|
|
164 |
goto fsaved;
|
|
|
165 |
}
|
|
|
166 |
inst.template = *pcp;
|
|
|
167 |
code = compute_inst_matrix(&inst, saved, &bbox, dev_width, dev_height);
|
|
|
168 |
if (code < 0)
|
|
|
169 |
goto fsaved;
|
|
|
170 |
|
|
|
171 |
#define mat inst.step_matrix
|
|
|
172 |
if_debug6('t', "[t]step_matrix=[%g %g %g %g %g %g]\n",
|
|
|
173 |
mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
|
|
|
174 |
if_debug4('t', "[t]bbox=(%g,%g),(%g,%g)\n",
|
|
|
175 |
bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
|
|
|
176 |
{
|
|
|
177 |
float bbw = bbox.q.x - bbox.p.x;
|
|
|
178 |
float bbh = bbox.q.y - bbox.p.y;
|
|
|
179 |
|
|
|
180 |
/* If the step and the size agree to within 1/2 pixel, */
|
|
|
181 |
/* make them the same. */
|
|
|
182 |
if (ADJUST_SCALE_BY_GS_TRADITION) {
|
|
|
183 |
inst.size.x = (int)(bbw + 0.8); /* 0.8 is arbitrary */
|
|
|
184 |
inst.size.y = (int)(bbh + 0.8);
|
|
|
185 |
} else {
|
|
|
186 |
inst.size.x = (int)ceil(bbw);
|
|
|
187 |
inst.size.y = (int)ceil(bbh);
|
|
|
188 |
}
|
|
|
189 |
|
|
|
190 |
if (inst.size.x == 0 || inst.size.y == 0) {
|
|
|
191 |
/*
|
|
|
192 |
* The pattern is empty: the stepping matrix doesn't matter.
|
|
|
193 |
*/
|
|
|
194 |
gs_make_identity(&mat);
|
|
|
195 |
bbox.p.x = bbox.p.y = bbox.q.x = bbox.q.y = 0;
|
|
|
196 |
} else {
|
|
|
197 |
/* Check for singular stepping matrix. */
|
|
|
198 |
if (fabs(mat.xx * mat.yy - mat.xy * mat.yx) < 1.0e-6) {
|
|
|
199 |
code = gs_note_error(gs_error_rangecheck);
|
|
|
200 |
goto fsaved;
|
|
|
201 |
}
|
|
|
202 |
if (ADJUST_SCALE_BY_GS_TRADITION &&
|
|
|
203 |
mat.xy == 0 && mat.yx == 0 &&
|
|
|
204 |
fabs(fabs(mat.xx) - bbw) < 0.5 &&
|
|
|
205 |
fabs(fabs(mat.yy) - bbh) < 0.5
|
|
|
206 |
) {
|
|
|
207 |
gs_scale(saved, fabs(inst.size.x / mat.xx),
|
|
|
208 |
fabs(inst.size.y / mat.yy));
|
|
|
209 |
code = compute_inst_matrix(&inst, saved, &bbox,
|
|
|
210 |
dev_width, dev_height);
|
|
|
211 |
if (code < 0)
|
|
|
212 |
goto fsaved;
|
|
|
213 |
if (ADJUST_SCALE_FOR_THIN_LINES) {
|
|
|
214 |
/* To allow thin lines at a cell boundary
|
|
|
215 |
to be painted inside the cell,
|
|
|
216 |
we adjust the scale so that
|
|
|
217 |
the scaled width is in fixed_1 smaller */
|
|
|
218 |
gs_scale(saved, (fabs(inst.size.x) - 1.0 / fixed_scale) / fabs(inst.size.x),
|
|
|
219 |
(fabs(inst.size.y) - 1.0 / fixed_scale) / fabs(inst.size.y));
|
|
|
220 |
}
|
|
|
221 |
if_debug2('t',
|
|
|
222 |
"[t]adjusted XStep & YStep to size=(%d,%d)\n",
|
|
|
223 |
inst.size.x, inst.size.y);
|
|
|
224 |
if_debug4('t', "[t]bbox=(%g,%g),(%g,%g)\n",
|
|
|
225 |
bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
|
|
|
226 |
} else if (ADJUST_AS_ADOBE) {
|
|
|
227 |
if (mat.xy == 0 && mat.yx == 0 &&
|
|
|
228 |
fabs(fabs(mat.xx) - bbw) < 0.5 &&
|
|
|
229 |
fabs(fabs(mat.yy) - bbh) < 0.5
|
|
|
230 |
) {
|
|
|
231 |
if (inst.step_matrix.xx <= 2) {
|
|
|
232 |
/* Prevent a degradation - see -r72 mspro.pdf */
|
|
|
233 |
gs_scale(saved, fabs(inst.size.x / mat.xx), 1);
|
|
|
234 |
inst.step_matrix.xx = (float)inst.size.x;
|
|
|
235 |
} else {
|
|
|
236 |
inst.step_matrix.xx = (float)floor(inst.step_matrix.xx + 0.5);
|
|
|
237 |
/* To allow thin lines at a cell boundary
|
|
|
238 |
to be painted inside the cell,
|
|
|
239 |
we adjust the scale so that
|
|
|
240 |
the scaled width is in fixed_1 smaller */
|
|
|
241 |
if (bbw >= inst.size.x - 1.0 / fixed_scale)
|
|
|
242 |
gs_scale(saved, (fabs(inst.size.x) - 1.0 / fixed_scale) / fabs(inst.size.x), 1);
|
|
|
243 |
}
|
|
|
244 |
if (inst.step_matrix.yy <= 2) {
|
|
|
245 |
gs_scale(saved, 1, fabs(inst.size.y / mat.yy));
|
|
|
246 |
inst.step_matrix.yy = (float)inst.size.y;
|
|
|
247 |
} else {
|
|
|
248 |
inst.step_matrix.yy = (float)floor(inst.step_matrix.yy + 0.5);
|
|
|
249 |
if (bbh >= inst.size.y - 1.0 / fixed_scale)
|
|
|
250 |
gs_scale(saved, 1, (fabs(inst.size.y) - 1.0 / fixed_scale) / fabs(inst.size.y));
|
|
|
251 |
}
|
|
|
252 |
code = gs_bbox_transform(&inst.template.BBox, &ctm_only(saved), &bbox);
|
|
|
253 |
if (code < 0)
|
|
|
254 |
goto fsaved;
|
|
|
255 |
}
|
|
|
256 |
}
|
|
|
257 |
}
|
|
|
258 |
}
|
|
|
259 |
if ((code = gs_bbox_transform_inverse(&bbox, &mat, &inst.bbox)) < 0)
|
|
|
260 |
goto fsaved;
|
|
|
261 |
if_debug4('t', "[t]ibbox=(%g,%g),(%g,%g)\n",
|
|
|
262 |
inst.bbox.p.x, inst.bbox.p.y, inst.bbox.q.x, inst.bbox.q.y);
|
|
|
263 |
inst.is_simple = (fabs(mat.xx) == inst.size.x && mat.xy == 0 &&
|
|
|
264 |
mat.yx == 0 && fabs(mat.yy) == inst.size.y);
|
|
|
265 |
if_debug6('t',
|
|
|
266 |
"[t]is_simple? xstep=(%g,%g) ystep=(%g,%g) size=(%d,%d)\n",
|
|
|
267 |
inst.step_matrix.xx, inst.step_matrix.xy,
|
|
|
268 |
inst.step_matrix.yx, inst.step_matrix.yy,
|
|
|
269 |
inst.size.x, inst.size.y);
|
|
|
270 |
/* Absent other information, instances always require a mask. */
|
|
|
271 |
inst.uses_mask = true;
|
|
|
272 |
gx_translate_to_fixed(saved, float2fixed_rounded(mat.tx - bbox.p.x),
|
|
|
273 |
float2fixed_rounded(mat.ty - bbox.p.y));
|
|
|
274 |
mat.tx = bbox.p.x;
|
|
|
275 |
mat.ty = bbox.p.y;
|
|
|
276 |
#undef mat
|
|
|
277 |
cbox.p.x = fixed_0;
|
|
|
278 |
cbox.p.y = fixed_0;
|
|
|
279 |
cbox.q.x = int2fixed(inst.size.x);
|
|
|
280 |
cbox.q.y = int2fixed(inst.size.y);
|
|
|
281 |
code = gx_clip_to_rectangle(saved, &cbox);
|
|
|
282 |
if (code < 0)
|
|
|
283 |
goto fsaved;
|
|
|
284 |
inst.id = gs_next_ids(mem, 1);
|
|
|
285 |
*pinst = inst;
|
|
|
286 |
return 0;
|
|
|
287 |
#undef mat
|
|
|
288 |
fsaved:gs_state_free(saved);
|
|
|
289 |
gs_free_object(mem, pinst, "gs_makepattern");
|
|
|
290 |
return code;
|
|
|
291 |
}
|
|
|
292 |
|
|
|
293 |
/*
|
|
|
294 |
* Clamp the bound box for a pattern to the region of the pattern that will
|
|
|
295 |
* actually be on our page. We need to do this becuase some applications
|
|
|
296 |
* create patterns which specify a bounding box which is much larger than
|
|
|
297 |
* the page. We allocate a buffer for holding the pattern. We need to
|
|
|
298 |
* prevent this buffer from getting too large.
|
|
|
299 |
*/
|
|
|
300 |
private int
|
|
|
301 |
clamp_pattern_bbox(gs_pattern1_instance_t * pinst, gs_rect * pbbox,
|
|
|
302 |
int width, int height, const gs_matrix * pmat)
|
|
|
303 |
{
|
|
|
304 |
double xstep = pinst->template.XStep;
|
|
|
305 |
double ystep = pinst->template.YStep;
|
|
|
306 |
double xmin = pbbox->q.x;
|
|
|
307 |
double xmax = pbbox->p.x;
|
|
|
308 |
double ymin = pbbox->q.y;
|
|
|
309 |
double ymax = pbbox->p.y;
|
|
|
310 |
int ixpat, iypat, iystart;
|
|
|
311 |
double xpat, ypat;
|
|
|
312 |
double xlower, xupper, ylower, yupper;
|
|
|
313 |
double xdev, ydev;
|
|
|
314 |
gs_rect dev_page, pat_page;
|
|
|
315 |
gs_point dev_pat_origin, dev_step;
|
|
|
316 |
int code;
|
|
|
317 |
|
|
|
318 |
/*
|
|
|
319 |
* Scan across the page. We determine the region to be scanned
|
|
|
320 |
* by working in the pattern coordinate space. This is logically
|
|
|
321 |
* simpler since XStep and YStep are on axis in the pattern space.
|
|
|
322 |
*/
|
|
|
323 |
/*
|
|
|
324 |
* Convert the page dimensions from device coordinates into the
|
|
|
325 |
* pattern coordinate frame.
|
|
|
326 |
*/
|
|
|
327 |
dev_page.p.x = dev_page.p.y = 0;
|
|
|
328 |
dev_page.q.x = width;
|
|
|
329 |
dev_page.q.y = height;
|
|
|
330 |
code = gs_bbox_transform_inverse(&dev_page, pmat, &pat_page);
|
|
|
331 |
if (code < 0)
|
|
|
332 |
return code;
|
|
|
333 |
/*
|
|
|
334 |
* Determine the location of the pattern origin in device coordinates.
|
|
|
335 |
*/
|
|
|
336 |
gs_point_transform(0.0, 0.0, pmat, &dev_pat_origin);
|
|
|
337 |
/*
|
|
|
338 |
* Determine our starting point. We start with a postion that puts the
|
|
|
339 |
* pattern below and to the left of the page (in pattern space) and scan
|
|
|
340 |
* until the pattern is above and right of the page.
|
|
|
341 |
*/
|
|
|
342 |
ixpat = (int) floor((pat_page.p.x - pinst->template.BBox.q.x) / xstep);
|
|
|
343 |
iystart = (int) floor((pat_page.p.y - pinst->template.BBox.q.y) / ystep);
|
|
|
344 |
|
|
|
345 |
/* Now do the scan */
|
|
|
346 |
for (; ; ixpat++) {
|
|
|
347 |
xpat = ixpat * xstep;
|
|
|
348 |
for (iypat = iystart; ; iypat++) {
|
|
|
349 |
ypat = iypat * ystep;
|
|
|
350 |
/*
|
|
|
351 |
* Calculate the shift in the pattern's location.
|
|
|
352 |
*/
|
|
|
353 |
gs_point_transform(xpat, ypat, pmat, &dev_step);
|
|
|
354 |
xdev = dev_step.x - dev_pat_origin.x;
|
|
|
355 |
ydev = dev_step.y - dev_pat_origin.y;
|
|
|
356 |
/*
|
|
|
357 |
* Check if the pattern bounding box intersects the page.
|
|
|
358 |
*/
|
|
|
359 |
xlower = (xdev + pbbox->p.x > 0) ? pbbox->p.x : -xdev;
|
|
|
360 |
xupper = (xdev + pbbox->q.x < width) ? pbbox->q.x : -xdev + width;
|
|
|
361 |
ylower = (ydev + pbbox->p.y > 0) ? pbbox->p.y : -ydev;
|
|
|
362 |
yupper = (ydev + pbbox->q.y < height) ? pbbox->q.y : -ydev + height;
|
|
|
363 |
if (xlower < xupper && ylower < yupper) {
|
|
|
364 |
/*
|
|
|
365 |
* The pattern intersects the page. Expand required area if
|
|
|
366 |
* needed.
|
|
|
367 |
*/
|
|
|
368 |
if (xlower < xmin)
|
|
|
369 |
xmin = xlower;
|
|
|
370 |
if (xupper > xmax)
|
|
|
371 |
xmax = xupper;
|
|
|
372 |
if (ylower < ymin)
|
|
|
373 |
ymin = ylower;
|
|
|
374 |
if (yupper > ymax)
|
|
|
375 |
ymax = yupper;
|
|
|
376 |
}
|
|
|
377 |
if (ypat > pat_page.q.y - pinst->template.BBox.p.y)
|
|
|
378 |
break;
|
|
|
379 |
}
|
|
|
380 |
if (xpat > pat_page.q.x - pinst->template.BBox.p.x)
|
|
|
381 |
break;
|
|
|
382 |
}
|
|
|
383 |
/* Update the bounding box. */
|
|
|
384 |
if (xmin < xmax && ymin < ymax) {
|
|
|
385 |
pbbox->p.x = xmin;
|
|
|
386 |
pbbox->q.x = xmax;
|
|
|
387 |
pbbox->p.y = ymin;
|
|
|
388 |
pbbox->q.y = ymax;
|
|
|
389 |
} else {
|
|
|
390 |
/* The pattern is never on the page. Set bbox = 1, 1 */
|
|
|
391 |
pbbox->p.x = pbbox->p.y = 0;
|
|
|
392 |
pbbox->q.x = pbbox->q.y = 1;
|
|
|
393 |
}
|
|
|
394 |
return 0;
|
|
|
395 |
}
|
|
|
396 |
|
|
|
397 |
/* Compute the stepping matrix and device space instance bounding box */
|
|
|
398 |
/* from the step values and the saved matrix. */
|
|
|
399 |
private int
|
|
|
400 |
compute_inst_matrix(gs_pattern1_instance_t * pinst, const gs_state * saved,
|
|
|
401 |
gs_rect * pbbox, int width, int height)
|
|
|
402 |
{
|
|
|
403 |
double xx = pinst->template.XStep * saved->ctm.xx;
|
|
|
404 |
double xy = pinst->template.XStep * saved->ctm.xy;
|
|
|
405 |
double yx = pinst->template.YStep * saved->ctm.yx;
|
|
|
406 |
double yy = pinst->template.YStep * saved->ctm.yy;
|
|
|
407 |
int code;
|
|
|
408 |
|
|
|
409 |
/* Adjust the stepping matrix so all coefficients are >= 0. */
|
|
|
410 |
if (xx == 0 || yy == 0) { /* We know that both xy and yx are non-zero. */
|
|
|
411 |
double temp;
|
|
|
412 |
|
|
|
413 |
temp = xx, xx = yx, yx = temp;
|
|
|
414 |
temp = xy, xy = yy, yy = temp;
|
|
|
415 |
}
|
|
|
416 |
if (xx < 0)
|
|
|
417 |
xx = -xx, xy = -xy;
|
|
|
418 |
if (yy < 0)
|
|
|
419 |
yx = -yx, yy = -yy;
|
|
|
420 |
/* Now xx > 0, yy > 0. */
|
|
|
421 |
pinst->step_matrix.xx = xx;
|
|
|
422 |
pinst->step_matrix.xy = xy;
|
|
|
423 |
pinst->step_matrix.yx = yx;
|
|
|
424 |
pinst->step_matrix.yy = yy;
|
|
|
425 |
pinst->step_matrix.tx = saved->ctm.tx;
|
|
|
426 |
pinst->step_matrix.ty = saved->ctm.ty;
|
|
|
427 |
code = gs_bbox_transform(&pinst->template.BBox, &ctm_only(saved), pbbox);
|
|
|
428 |
/*
|
|
|
429 |
* Some applications produce patterns that are larger than the page.
|
|
|
430 |
* If the bounding box for the pattern is larger than the page. clamp
|
|
|
431 |
* the pattern to the page size.
|
|
|
432 |
*/
|
|
|
433 |
if (code >= 0 &&
|
|
|
434 |
(pbbox->q.x - pbbox->p.x > width || pbbox->q.y - pbbox->p.y > height))
|
|
|
435 |
code = clamp_pattern_bbox(pinst, pbbox, width,
|
|
|
436 |
height, &ctm_only(saved));
|
|
|
437 |
|
|
|
438 |
return code;
|
|
|
439 |
}
|
|
|
440 |
|
|
|
441 |
/* Test whether a PatternType 1 pattern uses a base space. */
|
|
|
442 |
private bool
|
|
|
443 |
gs_pattern1_uses_base_space(const gs_pattern_template_t *ptemp)
|
|
|
444 |
{
|
|
|
445 |
return ((const gs_pattern1_template_t *)ptemp)->PaintType == 2;
|
|
|
446 |
}
|
|
|
447 |
|
|
|
448 |
/* getpattern for PatternType 1 */
|
|
|
449 |
/* This is only intended for the benefit of pattern PaintProcs. */
|
|
|
450 |
private const gs_pattern_template_t *
|
|
|
451 |
gs_pattern1_get_pattern(const gs_pattern_instance_t *pinst)
|
|
|
452 |
{
|
|
|
453 |
return (const gs_pattern_template_t *)
|
|
|
454 |
&((const gs_pattern1_instance_t *)pinst)->template;
|
|
|
455 |
}
|
|
|
456 |
|
|
|
457 |
/*
|
|
|
458 |
* Perform actions required at setcolor time. This procedure resets the
|
|
|
459 |
* overprint information (almost) as required by the pattern. The logic
|
|
|
460 |
* behind this operation is a bit convoluted:
|
|
|
461 |
*
|
|
|
462 |
* 1. Both PatternType 1 and 2 "colors" occur within the pattern color
|
|
|
463 |
* space.
|
|
|
464 |
*
|
|
|
465 |
* 2. Nominally, the set of drawn components is a property of the color
|
|
|
466 |
* space, and is set at the time setcolorspace is called. This is
|
|
|
467 |
* not the case for patterns, so overprint information must be set
|
|
|
468 |
* at setcolor time for them.
|
|
|
469 |
*
|
|
|
470 |
* 3. PatternType 2 color spaces incorporate their own color space, so
|
|
|
471 |
* the set of drawn components is determined by that color space.
|
|
|
472 |
* For PatternType 1 color spaces, the PaintType determines the
|
|
|
473 |
* appropriate color space to use. If PaintType is 2 (uncolored),
|
|
|
474 |
* the pattern makes use of the base color space of the current
|
|
|
475 |
* pattern color space, so overprint is set as appropriate for
|
|
|
476 |
* that color space.
|
|
|
477 |
*
|
|
|
478 |
* 4. For PatternType 1 color spaces with PaintType 1 (colored), the
|
|
|
479 |
* appropriate color space to use is determined by the pattern's
|
|
|
480 |
* PaintProc. This cannot be handled by the current graphic
|
|
|
481 |
* library mechanism, because color space information is lost when
|
|
|
482 |
* the pattern tile is cached (and the pattern tile is essentially
|
|
|
483 |
* always cached). We punt in this case and list all components
|
|
|
484 |
* as drawn components. (This feature could be support by retaining
|
|
|
485 |
* per-component pattern masks, but complete re-design of the
|
|
|
486 |
* pattern mechanism is probably more appropriate.)
|
|
|
487 |
*
|
|
|
488 |
* 5. Once overprint information has been set for a particular color,
|
|
|
489 |
* it must be reset to the proper value when that color is no
|
|
|
490 |
* longer in use. "Normal" (non-pattern) colors do not have a
|
|
|
491 |
* "set_color" action, both for performance and logical reasons.
|
|
|
492 |
* This does not, however, cause significant difficulty, as the
|
|
|
493 |
* change in color space required to set a normal color will
|
|
|
494 |
* reset the overprint information as required.
|
|
|
495 |
*/
|
|
|
496 |
private int
|
|
|
497 |
gs_pattern1_set_color(const gs_client_color * pcc, gs_state * pgs)
|
|
|
498 |
{
|
|
|
499 |
gs_pattern1_instance_t * pinst = (gs_pattern1_instance_t *)pcc->pattern;
|
|
|
500 |
gs_pattern1_template_t * ptmplt = &pinst->template;
|
|
|
501 |
|
|
|
502 |
if (ptmplt->PaintType == 2) {
|
|
|
503 |
const gs_color_space * pcs = pgs->color_space;
|
|
|
504 |
|
|
|
505 |
pcs = (const gs_color_space *)&(pcs->params.pattern.base_space);
|
|
|
506 |
return pcs->type->set_overprint(pcs, pgs);
|
|
|
507 |
} else {
|
|
|
508 |
gs_overprint_params_t params;
|
|
|
509 |
|
|
|
510 |
params.retain_any_comps = false;
|
|
|
511 |
pgs->effective_overprint_mode = 0;
|
|
|
512 |
return gs_state_update_overprint(pgs, ¶ms);
|
|
|
513 |
}
|
|
|
514 |
}
|
|
|
515 |
|
|
|
516 |
|
|
|
517 |
const gs_pattern1_template_t *
|
|
|
518 |
gs_getpattern(const gs_client_color * pcc)
|
|
|
519 |
{
|
|
|
520 |
const gs_pattern_instance_t *pinst = pcc->pattern;
|
|
|
521 |
|
|
|
522 |
return (pinst == 0 || pinst->type != &gs_pattern1_type ? 0 :
|
|
|
523 |
&((const gs_pattern1_instance_t *)pinst)->template);
|
|
|
524 |
}
|
|
|
525 |
|
|
|
526 |
/*
|
|
|
527 |
* Code for generating patterns from bitmaps and pixmaps.
|
|
|
528 |
*/
|
|
|
529 |
|
|
|
530 |
/*
|
|
|
531 |
* The following structures are realized here only because this is the
|
|
|
532 |
* first location in which they were needed. Otherwise, there is nothing
|
|
|
533 |
* about them that is specific to patterns.
|
|
|
534 |
*/
|
|
|
535 |
public_st_gs_bitmap();
|
|
|
536 |
public_st_gs_tile_bitmap();
|
|
|
537 |
public_st_gs_depth_bitmap();
|
|
|
538 |
public_st_gs_tile_depth_bitmap();
|
|
|
539 |
public_st_gx_strip_bitmap();
|
|
|
540 |
|
|
|
541 |
/*
|
|
|
542 |
* Structure for holding a gs_depth_bitmap and the corresponding depth and
|
|
|
543 |
* colorspace information.
|
|
|
544 |
*
|
|
|
545 |
* The free_proc pointer is needed to hold the original value of the pattern
|
|
|
546 |
* instance free structure. This pointer in the pattern instance will be
|
|
|
547 |
* overwritten with free_pixmap_pattern, which will free the pixmap info
|
|
|
548 |
* structure when it is freed.
|
|
|
549 |
*/
|
|
|
550 |
typedef struct pixmap_info_s {
|
|
|
551 |
gs_depth_bitmap bitmap; /* must be first */
|
|
|
552 |
const gs_color_space *pcspace;
|
|
|
553 |
uint white_index;
|
|
|
554 |
void (*free_proc)(gs_memory_t *, void *, client_name_t);
|
|
|
555 |
} pixmap_info;
|
|
|
556 |
|
|
|
557 |
gs_private_st_suffix_add1(st_pixmap_info,
|
|
|
558 |
pixmap_info,
|
|
|
559 |
"pixmap info. struct",
|
|
|
560 |
pixmap_enum_ptr,
|
|
|
561 |
pixmap_reloc_ptr,
|
|
|
562 |
st_gs_depth_bitmap,
|
|
|
563 |
pcspace
|
|
|
564 |
);
|
|
|
565 |
|
|
|
566 |
#define st_pixmap_info_max_ptrs (1 + st_tile_bitmap_max_ptrs)
|
|
|
567 |
|
|
|
568 |
/*
|
|
|
569 |
* Free routine for pattern instances created from pixmaps. This overwrites
|
|
|
570 |
* the free procedure originally stored in the pattern instance, and stores
|
|
|
571 |
* the pointer to that procedure in the pixmap_info structure. This procedure
|
|
|
572 |
* will call the original procedure, then free the pixmap_info structure.
|
|
|
573 |
*
|
|
|
574 |
* Note that this routine does NOT release the data in the original pixmap;
|
|
|
575 |
* that remains the responsibility of the client.
|
|
|
576 |
*/
|
|
|
577 |
private void
|
|
|
578 |
free_pixmap_pattern(
|
|
|
579 |
gs_memory_t * pmem,
|
|
|
580 |
void * pvpinst,
|
|
|
581 |
client_name_t cname
|
|
|
582 |
)
|
|
|
583 |
{
|
|
|
584 |
gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pvpinst;
|
|
|
585 |
pixmap_info *ppmap = pinst->template.client_data;
|
|
|
586 |
|
|
|
587 |
ppmap->free_proc(pmem, pvpinst, cname);
|
|
|
588 |
gs_free_object(pmem, ppmap, cname);
|
|
|
589 |
}
|
|
|
590 |
|
|
|
591 |
/*
|
|
|
592 |
* PaintProcs for bitmap and pixmap patterns.
|
|
|
593 |
*/
|
|
|
594 |
private int bitmap_paint(gs_image_enum * pen, gs_data_image_t * pim,
|
|
|
595 |
const gs_depth_bitmap * pbitmap, gs_state * pgs);
|
|
|
596 |
private int
|
|
|
597 |
mask_PaintProc(const gs_client_color * pcolor, gs_state * pgs)
|
|
|
598 |
{
|
|
|
599 |
const pixmap_info *ppmap = gs_getpattern(pcolor)->client_data;
|
|
|
600 |
const gs_depth_bitmap *pbitmap = &(ppmap->bitmap);
|
|
|
601 |
gs_image_enum *pen =
|
|
|
602 |
gs_image_enum_alloc(gs_state_memory(pgs), "mask_PaintProc");
|
|
|
603 |
gs_image1_t mask;
|
|
|
604 |
|
|
|
605 |
if (pen == 0)
|
|
|
606 |
return_error(gs_error_VMerror);
|
|
|
607 |
gs_image_t_init_mask(&mask, true);
|
|
|
608 |
mask.Width = pbitmap->size.x;
|
|
|
609 |
mask.Height = pbitmap->size.y;
|
|
|
610 |
gs_image_init(pen, &mask, false, pgs);
|
|
|
611 |
return bitmap_paint(pen, (gs_data_image_t *) & mask, pbitmap, pgs);
|
|
|
612 |
}
|
|
|
613 |
private int
|
|
|
614 |
image_PaintProc(const gs_client_color * pcolor, gs_state * pgs)
|
|
|
615 |
{
|
|
|
616 |
const pixmap_info *ppmap = gs_getpattern(pcolor)->client_data;
|
|
|
617 |
const gs_depth_bitmap *pbitmap = &(ppmap->bitmap);
|
|
|
618 |
gs_image_enum *pen =
|
|
|
619 |
gs_image_enum_alloc(gs_state_memory(pgs), "image_PaintProc");
|
|
|
620 |
gs_color_space cs;
|
|
|
621 |
const gs_color_space *pcspace;
|
|
|
622 |
gx_image_enum_common_t *pie;
|
|
|
623 |
/*
|
|
|
624 |
* If the image is transparent then we want to do image type4 processing.
|
|
|
625 |
* Otherwise we want to use image type 1 processing.
|
|
|
626 |
*/
|
|
|
627 |
int transparent = ppmap->white_index < (1 << (pbitmap->num_comps * pbitmap->pix_depth));
|
|
|
628 |
|
|
|
629 |
/*
|
|
|
630 |
* Note: gs_image1_t and gs_image4_t sre nearly identical structure
|
|
|
631 |
* definitions. From our point of view, the only significant difference
|
|
|
632 |
* is MaskColor in gs_image4_t. The fields are generally loaded using
|
|
|
633 |
* the gs_image1_t version of the union and then used for either type
|
|
|
634 |
* of image processing.
|
|
|
635 |
*/
|
|
|
636 |
union {
|
|
|
637 |
gs_image1_t i1;
|
|
|
638 |
gs_image4_t i4;
|
|
|
639 |
} image;
|
|
|
640 |
int code;
|
|
|
641 |
|
|
|
642 |
if (pen == 0)
|
|
|
643 |
return_error(gs_error_VMerror);
|
|
|
644 |
|
|
|
645 |
if (ppmap->pcspace == 0) {
|
|
|
646 |
gs_cspace_init_DeviceGray(pgs->memory, &cs);
|
|
|
647 |
pcspace = &cs;
|
|
|
648 |
} else
|
|
|
649 |
pcspace = ppmap->pcspace;
|
|
|
650 |
gs_gsave(pgs);
|
|
|
651 |
gs_setcolorspace(pgs, pcspace);
|
|
|
652 |
if (transparent)
|
|
|
653 |
gs_image4_t_init( (gs_image4_t *) &image, pcspace);
|
|
|
654 |
else
|
|
|
655 |
gs_image_t_init_adjust( (gs_image_t *) &image, pcspace, 0);
|
|
|
656 |
image.i1.Width = pbitmap->size.x;
|
|
|
657 |
image.i1.Height = pbitmap->size.y;
|
|
|
658 |
if (transparent) {
|
|
|
659 |
image.i4.MaskColor_is_range = false;
|
|
|
660 |
image.i4.MaskColor[0] = ppmap->white_index;
|
|
|
661 |
}
|
|
|
662 |
image.i1.Decode[0] = 0.0;
|
|
|
663 |
image.i1.Decode[1] = (float)((1 << pbitmap->pix_depth) - 1);
|
|
|
664 |
image.i1.BitsPerComponent = pbitmap->pix_depth;
|
|
|
665 |
/* backwards compatibility */
|
|
|
666 |
if (ppmap->pcspace == 0) {
|
|
|
667 |
image.i1.Decode[0] = 1.0;
|
|
|
668 |
image.i1.Decode[1] = 0.0;
|
|
|
669 |
}
|
|
|
670 |
|
|
|
671 |
if ( (code = gs_image_begin_typed( (const gs_image_common_t *)&image,
|
|
|
672 |
pgs,
|
|
|
673 |
false,
|
|
|
674 |
&pie )) >= 0 &&
|
|
|
675 |
(code = gs_image_enum_init( pen,
|
|
|
676 |
pie,
|
|
|
677 |
(gs_data_image_t *)&image,
|
|
|
678 |
pgs )) >= 0 )
|
|
|
679 |
code = bitmap_paint(pen, (gs_data_image_t *) & image, pbitmap, pgs);
|
|
|
680 |
gs_grestore(pgs);
|
|
|
681 |
return code;
|
|
|
682 |
}
|
|
|
683 |
/* Finish painting any kind of bitmap pattern. */
|
|
|
684 |
private int
|
|
|
685 |
bitmap_paint(gs_image_enum * pen, gs_data_image_t * pim,
|
|
|
686 |
const gs_depth_bitmap * pbitmap, gs_state * pgs)
|
|
|
687 |
{
|
|
|
688 |
uint raster = pbitmap->raster;
|
|
|
689 |
uint nbytes = (pim->Width * pbitmap->pix_depth + 7) >> 3;
|
|
|
690 |
uint used;
|
|
|
691 |
const byte *dp = pbitmap->data;
|
|
|
692 |
int n;
|
|
|
693 |
int code = 0, code1;
|
|
|
694 |
|
|
|
695 |
if (nbytes == raster)
|
|
|
696 |
code = gs_image_next(pen, dp, nbytes * pim->Height, &used);
|
|
|
697 |
else
|
|
|
698 |
for (n = pim->Height; n > 0 && code >= 0; dp += raster, --n)
|
|
|
699 |
code = gs_image_next(pen, dp, nbytes, &used);
|
|
|
700 |
code1 = gs_image_cleanup_and_free_enum(pen);
|
|
|
701 |
if (code >= 0 && code1 < 0)
|
|
|
702 |
code = code1;
|
|
|
703 |
return code;
|
|
|
704 |
}
|
|
|
705 |
|
|
|
706 |
/*
|
|
|
707 |
* Make a pattern from a bitmap or pixmap. The pattern may be colored or
|
|
|
708 |
* uncolored, as determined by the mask operand. This code is intended
|
|
|
709 |
* primarily for use by PCL.
|
|
|
710 |
*
|
|
|
711 |
* See the comment prior to the declaration of this function in gscolor2.h
|
|
|
712 |
* for further information.
|
|
|
713 |
*/
|
|
|
714 |
int
|
|
|
715 |
gs_makepixmappattern(
|
|
|
716 |
gs_client_color * pcc,
|
|
|
717 |
const gs_depth_bitmap * pbitmap,
|
|
|
718 |
bool mask,
|
|
|
719 |
const gs_matrix * pmat,
|
|
|
720 |
long id,
|
|
|
721 |
const gs_color_space * pcspace,
|
|
|
722 |
uint white_index,
|
|
|
723 |
gs_state * pgs,
|
|
|
724 |
gs_memory_t * mem
|
|
|
725 |
)
|
|
|
726 |
{
|
|
|
727 |
|
|
|
728 |
gs_pattern1_template_t pat;
|
|
|
729 |
pixmap_info *ppmap;
|
|
|
730 |
gs_matrix mat, smat;
|
|
|
731 |
int code;
|
|
|
732 |
|
|
|
733 |
/* check that the data is legitimate */
|
|
|
734 |
if ((mask) || (pcspace == 0)) {
|
|
|
735 |
if (pbitmap->pix_depth != 1)
|
|
|
736 |
return_error(gs_error_rangecheck);
|
|
|
737 |
pcspace = 0;
|
|
|
738 |
} else if (gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed)
|
|
|
739 |
return_error(gs_error_rangecheck);
|
|
|
740 |
if (pbitmap->num_comps != 1)
|
|
|
741 |
return_error(gs_error_rangecheck);
|
|
|
742 |
|
|
|
743 |
/* allocate and initialize a pixmap_info structure for the paint proc */
|
|
|
744 |
if (mem == 0)
|
|
|
745 |
mem = gs_state_memory(pgs);
|
|
|
746 |
ppmap = gs_alloc_struct(mem,
|
|
|
747 |
pixmap_info,
|
|
|
748 |
&st_pixmap_info,
|
|
|
749 |
"makepximappattern"
|
|
|
750 |
);
|
|
|
751 |
if (ppmap == 0)
|
|
|
752 |
return_error(gs_error_VMerror);
|
|
|
753 |
ppmap->bitmap = *pbitmap;
|
|
|
754 |
ppmap->pcspace = pcspace;
|
|
|
755 |
ppmap->white_index = white_index;
|
|
|
756 |
|
|
|
757 |
/* set up the client pattern structure */
|
|
|
758 |
gs_pattern1_init(&pat);
|
|
|
759 |
uid_set_UniqueID(&pat.uid, (id == no_UniqueID) ? gs_next_ids(mem, 1) : id);
|
|
|
760 |
pat.PaintType = (mask ? 2 : 1);
|
|
|
761 |
pat.TilingType = 1;
|
|
|
762 |
pat.BBox.p.x = 0;
|
|
|
763 |
pat.BBox.p.y = 0;
|
|
|
764 |
pat.BBox.q.x = pbitmap->size.x;
|
|
|
765 |
pat.BBox.q.y = pbitmap->size.y;
|
|
|
766 |
pat.XStep = (float)pbitmap->size.x;
|
|
|
767 |
pat.YStep = (float)pbitmap->size.y;
|
|
|
768 |
pat.PaintProc = (mask ? mask_PaintProc : image_PaintProc);
|
|
|
769 |
pat.client_data = ppmap;
|
|
|
770 |
|
|
|
771 |
/* set the ctm to be the identity */
|
|
|
772 |
gs_currentmatrix(pgs, &smat);
|
|
|
773 |
gs_make_identity(&mat);
|
|
|
774 |
gs_setmatrix(pgs, &mat);
|
|
|
775 |
|
|
|
776 |
/* build the pattern, restore the previous matrix */
|
|
|
777 |
if (pmat == NULL)
|
|
|
778 |
pmat = &mat;
|
|
|
779 |
if ((code = gs_makepattern(pcc, &pat, pmat, pgs, mem)) != 0)
|
|
|
780 |
gs_free_object(mem, ppmap, "makebitmappattern_xform");
|
|
|
781 |
else {
|
|
|
782 |
/*
|
|
|
783 |
* If this is not a masked pattern and if the white pixel index
|
|
|
784 |
* is outside of the representable range, we don't need to go to
|
|
|
785 |
* the trouble of accumulating a mask that will just be all 1s.
|
|
|
786 |
*/
|
|
|
787 |
gs_pattern1_instance_t *pinst =
|
|
|
788 |
(gs_pattern1_instance_t *)pcc->pattern;
|
|
|
789 |
|
|
|
790 |
if (!mask && (white_index >= (1 << pbitmap->pix_depth)))
|
|
|
791 |
pinst->uses_mask = false;
|
|
|
792 |
|
|
|
793 |
/* overwrite the free procedure for the pattern instance */
|
|
|
794 |
ppmap->free_proc = pinst->rc.free;
|
|
|
795 |
pinst->rc.free = free_pixmap_pattern;
|
|
|
796 |
|
|
|
797 |
/*
|
|
|
798 |
* Since the PaintProcs don't reference the saved color space or
|
|
|
799 |
* color, clear these so that there isn't an extra retained
|
|
|
800 |
* reference to the Pattern object.
|
|
|
801 |
*/
|
|
|
802 |
gs_setgray(pinst->saved, 0.0);
|
|
|
803 |
|
|
|
804 |
}
|
|
|
805 |
gs_setmatrix(pgs, &smat);
|
|
|
806 |
return code;
|
|
|
807 |
}
|
|
|
808 |
|
|
|
809 |
/*
|
|
|
810 |
* Backwards compatibility.
|
|
|
811 |
*/
|
|
|
812 |
int
|
|
|
813 |
gs_makebitmappattern_xform(
|
|
|
814 |
gs_client_color * pcc,
|
|
|
815 |
const gx_tile_bitmap * ptile,
|
|
|
816 |
bool mask,
|
|
|
817 |
const gs_matrix * pmat,
|
|
|
818 |
long id,
|
|
|
819 |
gs_state * pgs,
|
|
|
820 |
gs_memory_t * mem
|
|
|
821 |
)
|
|
|
822 |
{
|
|
|
823 |
gs_depth_bitmap bitmap;
|
|
|
824 |
|
|
|
825 |
/* build the bitmap the size of one repetition */
|
|
|
826 |
bitmap.data = ptile->data;
|
|
|
827 |
bitmap.raster = ptile->raster;
|
|
|
828 |
bitmap.size.x = ptile->rep_width;
|
|
|
829 |
bitmap.size.y = ptile->rep_height;
|
|
|
830 |
bitmap.id = ptile->id; /* shouldn't matter */
|
|
|
831 |
bitmap.pix_depth = 1;
|
|
|
832 |
bitmap.num_comps = 1;
|
|
|
833 |
|
|
|
834 |
return gs_makepixmappattern(pcc, &bitmap, mask, pmat, id, 0, 0, pgs, mem);
|
|
|
835 |
}
|
|
|
836 |
|
|
|
837 |
|
|
|
838 |
/* ------ Color space implementation ------ */
|
|
|
839 |
|
|
|
840 |
/*
|
|
|
841 |
* Defined the Pattern device color types. We need a masked analogue of
|
|
|
842 |
* each of the non-pattern types, to handle uncolored patterns. We use
|
|
|
843 |
* 'masked_fill_rect' instead of 'masked_fill_rectangle' in order to limit
|
|
|
844 |
* identifier lengths to 32 characters.
|
|
|
845 |
*/
|
|
|
846 |
private dev_color_proc_get_dev_halftone(gx_dc_pattern_get_dev_halftone);
|
|
|
847 |
private dev_color_proc_load(gx_dc_pattern_load);
|
|
|
848 |
/*dev_color_proc_fill_rectangle(gx_dc_pattern_fill_rectangle); *//*gxp1fill.h */
|
|
|
849 |
private dev_color_proc_equal(gx_dc_pattern_equal);
|
|
|
850 |
private dev_color_proc_load(gx_dc_pure_masked_load);
|
|
|
851 |
|
|
|
852 |
private dev_color_proc_get_dev_halftone(gx_dc_pure_masked_get_dev_halftone);
|
|
|
853 |
/*dev_color_proc_fill_rectangle(gx_dc_pure_masked_fill_rect); *//*gxp1fill.h */
|
|
|
854 |
private dev_color_proc_equal(gx_dc_pure_masked_equal);
|
|
|
855 |
private dev_color_proc_load(gx_dc_binary_masked_load);
|
|
|
856 |
|
|
|
857 |
private dev_color_proc_get_dev_halftone(gx_dc_binary_masked_get_dev_halftone);
|
|
|
858 |
/*dev_color_proc_fill_rectangle(gx_dc_binary_masked_fill_rect); *//*gxp1fill.h */
|
|
|
859 |
private dev_color_proc_equal(gx_dc_binary_masked_equal);
|
|
|
860 |
private dev_color_proc_load(gx_dc_colored_masked_load);
|
|
|
861 |
|
|
|
862 |
private dev_color_proc_get_dev_halftone(gx_dc_colored_masked_get_dev_halftone);
|
|
|
863 |
/*dev_color_proc_fill_rectangle(gx_dc_colored_masked_fill_rect); *//*gxp1fill.h */
|
|
|
864 |
private dev_color_proc_equal(gx_dc_colored_masked_equal);
|
|
|
865 |
|
|
|
866 |
/* The device color types are exported for gxpcmap.c. */
|
|
|
867 |
gs_private_st_composite(st_dc_pattern, gx_device_color, "dc_pattern",
|
|
|
868 |
dc_pattern_enum_ptrs, dc_pattern_reloc_ptrs);
|
|
|
869 |
const gx_device_color_type_t gx_dc_pattern = {
|
|
|
870 |
&st_dc_pattern,
|
|
|
871 |
gx_dc_pattern_save_dc, gx_dc_pattern_get_dev_halftone,
|
|
|
872 |
gx_dc_ht_get_phase,
|
|
|
873 |
gx_dc_pattern_load, gx_dc_pattern_fill_rectangle,
|
|
|
874 |
gx_dc_default_fill_masked, gx_dc_pattern_equal,
|
|
|
875 |
gx_dc_pattern_write, gx_dc_pattern_read,
|
|
|
876 |
gx_dc_pattern_get_nonzero_comps
|
|
|
877 |
};
|
|
|
878 |
|
|
|
879 |
extern_st(st_dc_ht_binary);
|
|
|
880 |
gs_private_st_composite(st_dc_pure_masked, gx_device_color, "dc_pure_masked",
|
|
|
881 |
dc_masked_enum_ptrs, dc_masked_reloc_ptrs);
|
|
|
882 |
const gx_device_color_type_t gx_dc_pure_masked = {
|
|
|
883 |
&st_dc_pure_masked,
|
|
|
884 |
gx_dc_pattern_save_dc, gx_dc_pure_masked_get_dev_halftone,
|
|
|
885 |
gx_dc_no_get_phase,
|
|
|
886 |
gx_dc_pure_masked_load, gx_dc_pure_masked_fill_rect,
|
|
|
887 |
gx_dc_default_fill_masked, gx_dc_pure_masked_equal,
|
|
|
888 |
gx_dc_pattern_write, gx_dc_pattern_read,
|
|
|
889 |
gx_dc_pure_get_nonzero_comps
|
|
|
890 |
};
|
|
|
891 |
|
|
|
892 |
gs_private_st_composite(st_dc_binary_masked, gx_device_color,
|
|
|
893 |
"dc_binary_masked", dc_binary_masked_enum_ptrs,
|
|
|
894 |
dc_binary_masked_reloc_ptrs);
|
|
|
895 |
const gx_device_color_type_t gx_dc_binary_masked = {
|
|
|
896 |
&st_dc_binary_masked,
|
|
|
897 |
gx_dc_pattern_save_dc, gx_dc_binary_masked_get_dev_halftone,
|
|
|
898 |
gx_dc_ht_get_phase,
|
|
|
899 |
gx_dc_binary_masked_load, gx_dc_binary_masked_fill_rect,
|
|
|
900 |
gx_dc_default_fill_masked, gx_dc_binary_masked_equal,
|
|
|
901 |
gx_dc_pattern_write, gx_dc_pattern_read,
|
|
|
902 |
gx_dc_ht_binary_get_nonzero_comps
|
|
|
903 |
};
|
|
|
904 |
|
|
|
905 |
gs_private_st_composite_only(st_dc_colored_masked, gx_device_color,
|
|
|
906 |
"dc_colored_masked",
|
|
|
907 |
dc_masked_enum_ptrs, dc_masked_reloc_ptrs);
|
|
|
908 |
const gx_device_color_type_t gx_dc_colored_masked = {
|
|
|
909 |
&st_dc_colored_masked,
|
|
|
910 |
gx_dc_pattern_save_dc, gx_dc_colored_masked_get_dev_halftone,
|
|
|
911 |
gx_dc_ht_get_phase,
|
|
|
912 |
gx_dc_colored_masked_load, gx_dc_colored_masked_fill_rect,
|
|
|
913 |
gx_dc_default_fill_masked, gx_dc_colored_masked_equal,
|
|
|
914 |
gx_dc_pattern_write, gx_dc_pattern_read,
|
|
|
915 |
gx_dc_ht_colored_get_nonzero_comps
|
|
|
916 |
};
|
|
|
917 |
|
|
|
918 |
#undef gx_dc_type_pattern
|
|
|
919 |
const gx_device_color_type_t *const gx_dc_type_pattern = &gx_dc_pattern;
|
|
|
920 |
#define gx_dc_type_pattern (&gx_dc_pattern)
|
|
|
921 |
|
|
|
922 |
/* GC procedures */
|
|
|
923 |
private
|
|
|
924 |
ENUM_PTRS_WITH(dc_pattern_enum_ptrs, gx_device_color *cptr)
|
|
|
925 |
{
|
|
|
926 |
return ENUM_USING(st_dc_pure_masked, vptr, size, index - 1);
|
|
|
927 |
}
|
|
|
928 |
case 0:
|
|
|
929 |
{
|
|
|
930 |
gx_color_tile *tile = cptr->colors.pattern.p_tile;
|
|
|
931 |
|
|
|
932 |
ENUM_RETURN((tile == 0 ? tile : tile - tile->index));
|
|
|
933 |
}
|
|
|
934 |
ENUM_PTRS_END
|
|
|
935 |
private RELOC_PTRS_WITH(dc_pattern_reloc_ptrs, gx_device_color *cptr)
|
|
|
936 |
{
|
|
|
937 |
gx_color_tile *tile = cptr->colors.pattern.p_tile;
|
|
|
938 |
|
|
|
939 |
if (tile != 0) {
|
|
|
940 |
uint index = tile->index;
|
|
|
941 |
|
|
|
942 |
RELOC_TYPED_OFFSET_PTR(gx_device_color, colors.pattern.p_tile, index);
|
|
|
943 |
}
|
|
|
944 |
RELOC_USING(st_dc_pure_masked, vptr, size);
|
|
|
945 |
}
|
|
|
946 |
RELOC_PTRS_END
|
|
|
947 |
private ENUM_PTRS_WITH(dc_masked_enum_ptrs, gx_device_color *cptr)
|
|
|
948 |
ENUM_SUPER(gx_device_color, st_client_color, ccolor, 1);
|
|
|
949 |
case 0:
|
|
|
950 |
{
|
|
|
951 |
gx_color_tile *mask = cptr->mask.m_tile;
|
|
|
952 |
|
|
|
953 |
ENUM_RETURN((mask == 0 ? mask : mask - mask->index));
|
|
|
954 |
}
|
|
|
955 |
ENUM_PTRS_END
|
|
|
956 |
private RELOC_PTRS_WITH(dc_masked_reloc_ptrs, gx_device_color *cptr)
|
|
|
957 |
{
|
|
|
958 |
gx_color_tile *mask = cptr->mask.m_tile;
|
|
|
959 |
|
|
|
960 |
RELOC_SUPER(gx_device_color, st_client_color, ccolor);
|
|
|
961 |
if (mask != 0) {
|
|
|
962 |
uint index = mask->index;
|
|
|
963 |
|
|
|
964 |
RELOC_TYPED_OFFSET_PTR(gx_device_color, mask.m_tile, index);
|
|
|
965 |
}
|
|
|
966 |
}
|
|
|
967 |
RELOC_PTRS_END
|
|
|
968 |
private ENUM_PTRS_BEGIN(dc_binary_masked_enum_ptrs)
|
|
|
969 |
{
|
|
|
970 |
return ENUM_USING(st_dc_ht_binary, vptr, size, index - 2);
|
|
|
971 |
}
|
|
|
972 |
case 0:
|
|
|
973 |
case 1:
|
|
|
974 |
return ENUM_USING(st_dc_pure_masked, vptr, size, index);
|
|
|
975 |
ENUM_PTRS_END
|
|
|
976 |
private RELOC_PTRS_BEGIN(dc_binary_masked_reloc_ptrs)
|
|
|
977 |
{
|
|
|
978 |
RELOC_USING(st_dc_pure_masked, vptr, size);
|
|
|
979 |
RELOC_USING(st_dc_ht_binary, vptr, size);
|
|
|
980 |
}
|
|
|
981 |
RELOC_PTRS_END
|
|
|
982 |
|
|
|
983 |
|
|
|
984 |
/*
|
|
|
985 |
* Currently patterns cannot be passed through the command list,
|
|
|
986 |
* however vector devices need to save a color for comparing
|
|
|
987 |
* it with another color, which appears later.
|
|
|
988 |
* We provide a minimal support, which is necessary
|
|
|
989 |
* for the current implementation of pdfwrite.
|
|
|
990 |
* It is not sufficient for restoring the pattern from the saved color.
|
|
|
991 |
*/
|
|
|
992 |
void
|
|
|
993 |
gx_dc_pattern_save_dc(
|
|
|
994 |
const gx_device_color * pdevc,
|
|
|
995 |
gx_device_color_saved * psdc )
|
|
|
996 |
{
|
|
|
997 |
psdc->type = pdevc->type;
|
|
|
998 |
if (pdevc->ccolor_valid) {
|
|
|
999 |
psdc->colors.pattern.id = pdevc->ccolor.pattern->pattern_id;
|
|
|
1000 |
psdc->colors.pattern.phase = pdevc->phase;
|
|
|
1001 |
} {
|
|
|
1002 |
/* The client color has been changed to a non-pattern color,
|
|
|
1003 |
but device color has not been created yet.
|
|
|
1004 |
*/
|
|
|
1005 |
psdc->colors.pattern.id = gs_no_id;
|
|
|
1006 |
psdc->colors.pattern.phase.x = psdc->colors.pattern.phase.y = 0;
|
|
|
1007 |
}
|
|
|
1008 |
}
|
|
|
1009 |
|
|
|
1010 |
/*
|
|
|
1011 |
* Colored Type 1 patterns cannot provide a halftone, as multiple
|
|
|
1012 |
* halftones may be used by the PaintProc procedure. Hence, we can only
|
|
|
1013 |
* hope this is a contone device.
|
|
|
1014 |
*/
|
|
|
1015 |
private const gx_device_halftone *
|
|
|
1016 |
gx_dc_pattern_get_dev_halftone(const gx_device_color * pdevc)
|
|
|
1017 |
{
|
|
|
1018 |
return 0;
|
|
|
1019 |
}
|
|
|
1020 |
|
|
|
1021 |
/*
|
|
|
1022 |
* Uncolored Type 1 halftones make use of the halftone impplied by their
|
|
|
1023 |
* base color. Ideally this would be returned via an inhereted method,
|
|
|
1024 |
* but the device color structure does not support such an arrangement.
|
|
|
1025 |
*/
|
|
|
1026 |
private const gx_device_halftone *
|
|
|
1027 |
gx_dc_pure_masked_get_dev_halftone(const gx_device_color * pdevc)
|
|
|
1028 |
{
|
|
|
1029 |
return 0;
|
|
|
1030 |
}
|
|
|
1031 |
|
|
|
1032 |
private const gx_device_halftone *
|
|
|
1033 |
gx_dc_binary_masked_get_dev_halftone(const gx_device_color * pdevc)
|
|
|
1034 |
{
|
|
|
1035 |
return pdevc->colors.binary.b_ht;
|
|
|
1036 |
}
|
|
|
1037 |
|
|
|
1038 |
private const gx_device_halftone *
|
|
|
1039 |
gx_dc_colored_masked_get_dev_halftone(const gx_device_color * pdevc)
|
|
|
1040 |
{
|
|
|
1041 |
return pdevc->colors.colored.c_ht;
|
|
|
1042 |
}
|
|
|
1043 |
|
|
|
1044 |
|
|
|
1045 |
/* Macros for pattern loading */
|
|
|
1046 |
#define FINISH_PATTERN_LOAD\
|
|
|
1047 |
while ( !gx_pattern_cache_lookup(pdevc, pis, dev, select) )\
|
|
|
1048 |
{ code = gx_pattern_load(pdevc, pis, dev, select);\
|
|
|
1049 |
if ( code < 0 ) break;\
|
|
|
1050 |
}\
|
|
|
1051 |
return code;
|
|
|
1052 |
|
|
|
1053 |
/* Ensure that a colored Pattern is loaded in the cache. */
|
|
|
1054 |
private int
|
|
|
1055 |
gx_dc_pattern_load(gx_device_color * pdevc, const gs_imager_state * pis,
|
|
|
1056 |
gx_device * dev, gs_color_select_t select)
|
|
|
1057 |
{
|
|
|
1058 |
int code = 0;
|
|
|
1059 |
|
|
|
1060 |
FINISH_PATTERN_LOAD
|
|
|
1061 |
}
|
|
|
1062 |
/* Ensure that an uncolored Pattern is loaded in the cache. */
|
|
|
1063 |
private int
|
|
|
1064 |
gx_dc_pure_masked_load(gx_device_color * pdevc, const gs_imager_state * pis,
|
|
|
1065 |
gx_device * dev, gs_color_select_t select)
|
|
|
1066 |
{
|
|
|
1067 |
int code = (*gx_dc_type_data_pure.load) (pdevc, pis, dev, select);
|
|
|
1068 |
|
|
|
1069 |
if (code < 0)
|
|
|
1070 |
return code;
|
|
|
1071 |
FINISH_PATTERN_LOAD
|
|
|
1072 |
}
|
|
|
1073 |
private int
|
|
|
1074 |
gx_dc_binary_masked_load(gx_device_color * pdevc, const gs_imager_state * pis,
|
|
|
1075 |
gx_device * dev, gs_color_select_t select)
|
|
|
1076 |
{
|
|
|
1077 |
int code = (*gx_dc_type_data_ht_binary.load) (pdevc, pis, dev, select);
|
|
|
1078 |
|
|
|
1079 |
if (code < 0)
|
|
|
1080 |
return code;
|
|
|
1081 |
FINISH_PATTERN_LOAD
|
|
|
1082 |
}
|
|
|
1083 |
private int
|
|
|
1084 |
gx_dc_colored_masked_load(gx_device_color * pdevc, const gs_imager_state * pis,
|
|
|
1085 |
gx_device * dev, gs_color_select_t select)
|
|
|
1086 |
{
|
|
|
1087 |
int code = (*gx_dc_type_data_ht_colored.load) (pdevc, pis, dev, select);
|
|
|
1088 |
|
|
|
1089 |
if (code < 0)
|
|
|
1090 |
return code;
|
|
|
1091 |
FINISH_PATTERN_LOAD
|
|
|
1092 |
}
|
|
|
1093 |
|
|
|
1094 |
/* Look up a pattern color in the cache. */
|
|
|
1095 |
bool
|
|
|
1096 |
gx_pattern_cache_lookup(gx_device_color * pdevc, const gs_imager_state * pis,
|
|
|
1097 |
gx_device * dev, gs_color_select_t select)
|
|
|
1098 |
{
|
|
|
1099 |
gx_pattern_cache *pcache = pis->pattern_cache;
|
|
|
1100 |
gx_bitmap_id id = pdevc->mask.id;
|
|
|
1101 |
|
|
|
1102 |
if (id == gx_no_bitmap_id) {
|
|
|
1103 |
color_set_null_pattern(pdevc);
|
|
|
1104 |
return true;
|
|
|
1105 |
}
|
|
|
1106 |
if (pcache != 0) {
|
|
|
1107 |
gx_color_tile *ctile = &pcache->tiles[id % pcache->num_tiles];
|
|
|
1108 |
bool internal_accum = true;
|
|
|
1109 |
if (pis->have_pattern_streams) {
|
|
|
1110 |
int code = dev_proc(dev, pattern_manage)(dev, id, NULL, pattern_manage__load);
|
|
|
1111 |
internal_accum = (code == 0);
|
|
|
1112 |
if (code < 0)
|
|
|
1113 |
return false;
|
|
|
1114 |
}
|
|
|
1115 |
if (ctile->id == id &&
|
|
|
1116 |
ctile->is_dummy == !internal_accum &&
|
|
|
1117 |
(pdevc->type != &gx_dc_pattern ||
|
|
|
1118 |
ctile->depth == dev->color_info.depth)
|
|
|
1119 |
) {
|
|
|
1120 |
int px = pis->screen_phase[select].x;
|
|
|
1121 |
int py = pis->screen_phase[select].y;
|
|
|
1122 |
|
|
|
1123 |
if (pdevc->type == &gx_dc_pattern) { /* colored */
|
|
|
1124 |
pdevc->colors.pattern.p_tile = ctile;
|
|
|
1125 |
color_set_phase_mod(pdevc, px, py,
|
|
|
1126 |
ctile->tbits.rep_width,
|
|
|
1127 |
ctile->tbits.rep_height);
|
|
|
1128 |
}
|
|
|
1129 |
pdevc->mask.m_tile =
|
|
|
1130 |
(ctile->tmask.data == 0 ? (gx_color_tile *) 0 :
|
|
|
1131 |
ctile);
|
|
|
1132 |
pdevc->mask.m_phase.x = -px;
|
|
|
1133 |
pdevc->mask.m_phase.y = -py;
|
|
|
1134 |
return true;
|
|
|
1135 |
}
|
|
|
1136 |
}
|
|
|
1137 |
return false;
|
|
|
1138 |
}
|
|
|
1139 |
|
|
|
1140 |
#undef FINISH_PATTERN_LOAD
|
|
|
1141 |
|
|
|
1142 |
/* Compare two Pattern colors for equality. */
|
|
|
1143 |
private bool
|
|
|
1144 |
gx_dc_pattern_equal(const gx_device_color * pdevc1,
|
|
|
1145 |
const gx_device_color * pdevc2)
|
|
|
1146 |
{
|
|
|
1147 |
return pdevc2->type == pdevc1->type &&
|
|
|
1148 |
pdevc1->phase.x == pdevc2->phase.x &&
|
|
|
1149 |
pdevc1->phase.y == pdevc2->phase.y &&
|
|
|
1150 |
pdevc1->mask.id == pdevc2->mask.id;
|
|
|
1151 |
}
|
|
|
1152 |
|
|
|
1153 |
/*
|
|
|
1154 |
* For shading and colored tiling patterns, it is not possible to say
|
|
|
1155 |
* which color components have non-zero values. The following routine
|
|
|
1156 |
* indicates this by just returning 1. The procedure is exported for
|
|
|
1157 |
* the benefit of gsptype2.c.
|
|
|
1158 |
*/
|
|
|
1159 |
int
|
|
|
1160 |
gx_dc_pattern_get_nonzero_comps(
|
|
|
1161 |
const gx_device_color * pdevc_ignored,
|
|
|
1162 |
const gx_device * dev_ignored,
|
|
|
1163 |
gx_color_index * pcomp_bits_ignored )
|
|
|
1164 |
{
|
|
|
1165 |
return 1;
|
|
|
1166 |
}
|
|
|
1167 |
|
|
|
1168 |
|
|
|
1169 |
private bool
|
|
|
1170 |
gx_dc_pure_masked_equal(const gx_device_color * pdevc1,
|
|
|
1171 |
const gx_device_color * pdevc2)
|
|
|
1172 |
{
|
|
|
1173 |
return (*gx_dc_type_pure->equal) (pdevc1, pdevc2) &&
|
|
|
1174 |
pdevc1->mask.id == pdevc2->mask.id;
|
|
|
1175 |
}
|
|
|
1176 |
private bool
|
|
|
1177 |
gx_dc_binary_masked_equal(const gx_device_color * pdevc1,
|
|
|
1178 |
const gx_device_color * pdevc2)
|
|
|
1179 |
{
|
|
|
1180 |
return (*gx_dc_type_ht_binary->equal) (pdevc1, pdevc2) &&
|
|
|
1181 |
pdevc1->mask.id == pdevc2->mask.id;
|
|
|
1182 |
}
|
|
|
1183 |
private bool
|
|
|
1184 |
gx_dc_colored_masked_equal(const gx_device_color * pdevc1,
|
|
|
1185 |
const gx_device_color * pdevc2)
|
|
|
1186 |
{
|
|
|
1187 |
return (*gx_dc_type_ht_colored->equal) (pdevc1, pdevc2) &&
|
|
|
1188 |
pdevc1->mask.id == pdevc2->mask.id;
|
|
|
1189 |
}
|
|
|
1190 |
|
|
|
1191 |
/* currently, patterns cannot be passed through the command list */
|
|
|
1192 |
int
|
|
|
1193 |
gx_dc_pattern_write(
|
|
|
1194 |
const gx_device_color * pdevc,
|
|
|
1195 |
const gx_device_color_saved * psdc,
|
|
|
1196 |
const gx_device * dev,
|
|
|
1197 |
byte * data,
|
|
|
1198 |
uint * psize )
|
|
|
1199 |
{
|
|
|
1200 |
return_error(gs_error_unknownerror);
|
|
|
1201 |
}
|
|
|
1202 |
|
|
|
1203 |
int
|
|
|
1204 |
gx_dc_pattern_read(
|
|
|
1205 |
gx_device_color * pdevc,
|
|
|
1206 |
const gs_imager_state * pis,
|
|
|
1207 |
const gx_device_color * prior_devc,
|
|
|
1208 |
const gx_device * dev,
|
|
|
1209 |
const byte * data,
|
|
|
1210 |
uint size,
|
|
|
1211 |
gs_memory_t * mem )
|
|
|
1212 |
{
|
|
|
1213 |
return_error(gs_error_unknownerror);
|
|
|
1214 |
}
|