1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
|
/* Copyright (C) 2001-2012 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
implied.
This software is distributed under license and may not be copied,
modified or distributed except as expressly authorized under the terms
of the license contained in the file LICENSE in this distribution.
Refer to licensing information at http://www.artifex.com or contact
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
CA 94903, U.S.A., +1(415)492-9861, for further information.
*/
/* PatternType 2 implementation */
#include "gx.h"
#include "gserrors.h"
#include "gscspace.h"
#include "gsshade.h"
#include "gsmatrix.h" /* for gspcolor.h */
#include "gsstate.h" /* for set/currentfilladjust */
#include "gxcolor2.h"
#include "gxdcolor.h"
#include "gsptype2.h"
#include "gxpcolor.h"
#include "gxstate.h" /* for gs_state_memory */
#include "gzpath.h"
#include "gzcpath.h"
#include "gzstate.h"
#include "gxdevsop.h"
/* GC descriptors */
private_st_pattern2_template();
private_st_pattern2_instance();
/* GC procedures */
static ENUM_PTRS_BEGIN(pattern2_instance_enum_ptrs) {
if (index < st_pattern2_template_max_ptrs) {
gs_ptr_type_t ptype =
ENUM_SUPER_ELT(gs_pattern2_instance_t, st_pattern2_template,
templat, 0);
if (ptype)
return ptype;
return ENUM_OBJ(NULL); /* don't stop early */
}
ENUM_PREFIX(st_pattern_instance, st_pattern2_template_max_ptrs);
}
ENUM_PTRS_END
static RELOC_PTRS_BEGIN(pattern2_instance_reloc_ptrs) {
RELOC_PREFIX(st_pattern_instance);
RELOC_SUPER(gs_pattern2_instance_t, st_pattern2_template, templat);
} RELOC_PTRS_END
/* Define a PatternType 2 pattern. */
static pattern_proc_uses_base_space(gs_pattern2_uses_base_space);
static pattern_proc_make_pattern(gs_pattern2_make_pattern);
static pattern_proc_get_pattern(gs_pattern2_get_pattern);
static pattern_proc_remap_color(gs_pattern2_remap_color);
static pattern_proc_set_color(gs_pattern2_set_color);
static const gs_pattern_type_t gs_pattern2_type = {
2, {
gs_pattern2_uses_base_space, gs_pattern2_make_pattern,
gs_pattern2_get_pattern, gs_pattern2_remap_color,
gs_pattern2_set_color,
}
};
/* Initialize a PatternType 2 pattern. */
void
gs_pattern2_init(gs_pattern2_template_t * ppat)
{
gs_pattern_common_init((gs_pattern_template_t *)ppat, &gs_pattern2_type);
}
/* Test whether a PatternType 2 pattern uses a base space. */
static bool
gs_pattern2_uses_base_space(const gs_pattern_template_t *ptemp)
{
return false;
}
/* Make an instance of a PatternType 2 pattern. */
static 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)
{
const gs_pattern2_template_t *ptemp =
(const gs_pattern2_template_t *)pcp;
int code = gs_make_pattern_common(pcc, pcp, pmat, pgs, mem,
&st_pattern2_instance);
gs_pattern2_instance_t *pinst;
if (code < 0)
return code;
pinst = (gs_pattern2_instance_t *)pcc->pattern;
pinst->templat = *ptemp;
pinst->shfill = false;
return 0;
}
/* Get the template of a PatternType 2 pattern instance. */
static const gs_pattern_template_t *
gs_pattern2_get_pattern(const gs_pattern_instance_t *pinst)
{
return (const gs_pattern_template_t *)
&((const gs_pattern2_instance_t *)pinst)->templat;
}
/* Set the 'shfill' flag to a PatternType 2 pattern instance. */
int
gs_pattern2_set_shfill(gs_client_color * pcc)
{
gs_pattern2_instance_t *pinst;
if (pcc->pattern->type != &gs_pattern2_type)
return_error(gs_error_unregistered); /* Must not happen. */
pinst = (gs_pattern2_instance_t *)pcc->pattern;
pinst->shfill = true;
return 0;
}
/* ---------------- Rendering ---------------- */
/* GC descriptor */
gs_private_st_ptrs_add0(st_dc_pattern2, gx_device_color, "dc_pattern2",
dc_pattern2_enum_ptrs, dc_pattern2_reloc_ptrs,
st_client_color, ccolor);
static dev_color_proc_get_dev_halftone(gx_dc_pattern2_get_dev_halftone);
static dev_color_proc_load(gx_dc_pattern2_load);
static dev_color_proc_fill_rectangle(gx_dc_pattern2_fill_rectangle);
static dev_color_proc_equal(gx_dc_pattern2_equal);
static dev_color_proc_save_dc(gx_dc_pattern2_save_dc);
/*
* Define the PatternType 2 Pattern device color type. This is public only
* for testing when writing PDF or PostScript.
*/
const gx_device_color_type_t gx_dc_pattern2 = {
&st_dc_pattern2,
gx_dc_pattern2_save_dc, gx_dc_pattern2_get_dev_halftone,
gx_dc_ht_get_phase,
gx_dc_pattern2_load, gx_dc_pattern2_fill_rectangle,
gx_dc_default_fill_masked, gx_dc_pattern2_equal,
gx_dc_cannot_write, gx_dc_cannot_read,
gx_dc_pattern_get_nonzero_comps
};
/* Check device color for Pattern Type 2. */
bool
gx_dc_is_pattern2_color(const gx_device_color *pdevc)
{
return pdevc->type == &gx_dc_pattern2;
}
/*
* The device halftone used by a PatternType 2 patter is that current in
* the graphic state at the time of the makepattern call.
*/
static const gx_device_halftone *
gx_dc_pattern2_get_dev_halftone(const gx_device_color * pdevc)
{
return ((gs_pattern2_instance_t *)pdevc->ccolor.pattern)->saved->dev_ht;
}
/* Load a PatternType 2 color into the cache. (No effect.) */
static 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)
{
return 0;
}
/* Remap a PatternType 2 color. */
static 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)
{
/* We don't do any actual color mapping now. */
pdc->type = &gx_dc_pattern2;
pdc->ccolor = *pc;
pdc->ccolor_valid = true;
return 0;
}
/*
* Perform actions required at set_color time. Since PatternType 2
* patterns specify a color space, we must update the overprint
* information as required by that color space. We temporarily disable
* overprint_mode, as it is never applicable when using shading patterns.
*/
static int
gs_pattern2_set_color(const gs_client_color * pcc, gs_state * pgs)
{
gs_pattern2_instance_t * pinst = (gs_pattern2_instance_t *)pcc->pattern;
gs_color_space * pcs = pinst->templat.Shading->params.ColorSpace;
int code, save_overprint_mode = pgs->overprint_mode;
pgs->overprint_mode = 0;
code = pcs->type->set_overprint(pcs, pgs);
pgs->overprint_mode = save_overprint_mode;
return code;
}
/* Fill a rectangle with a PatternType 2 color. */
/* WARNING: This function doesn't account the shading BBox
to allow the clipent to optimize the clipping
with changing the order of clip paths and rects.
The client must clip with the shading BBox before calling this function. */
static 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)
{
if (dev_proc(dev, dev_spec_op)(dev, gxdso_pattern_is_cpath_accum, NULL, 0)) {
/* Performing a conversion of imagemask into a clipping path.
Fall back to the device procedure. */
return dev_proc(dev, fill_rectangle)(dev, x, y, w, h, (gx_color_index)0/*any*/);
} else {
gs_fixed_rect rect;
gs_pattern2_instance_t *pinst =
(gs_pattern2_instance_t *)pdevc->ccolor.pattern;
rect.p.x = int2fixed(x);
rect.p.y = int2fixed(y);
rect.q.x = int2fixed(x + w);
rect.q.y = int2fixed(y + h);
return gs_shading_do_fill_rectangle(pinst->templat.Shading, &rect, dev,
(gs_imager_state *)pinst->saved, !pinst->shfill);
}
}
/* Compare two PatternType 2 colors for equality. */
static bool
gx_dc_pattern2_equal(const gx_device_color * pdevc1,
const gx_device_color * pdevc2)
{
return pdevc2->type == pdevc1->type &&
pdevc1->ccolor.pattern == pdevc2->ccolor.pattern;
}
/*
* Currently patterns cannot be passed through the command list,
* however vector devices need to save a color for comparing
* it with another color, which appears later.
* We provide a minimal support, which is necessary
* for the current implementation of pdfwrite.
* It is not sufficient for restoring the pattern from the saved color.
*/
static void
gx_dc_pattern2_save_dc(
const gx_device_color * pdevc,
gx_device_color_saved * psdc )
{
gs_pattern2_instance_t * pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
psdc->type = pdevc->type;
psdc->colors.pattern2.id = pinst->pattern_id;
psdc->colors.pattern2.shfill = pinst->shfill;
}
/* Transform a shading bounding box into device space. */
/* This is just a bridge to an old code. */
int
gx_dc_pattern2_shade_bbox_transform2fixed(const gs_rect * rect, const gs_imager_state * pis,
gs_fixed_rect * rfixed)
{
gs_rect dev_rect;
int code = gs_bbox_transform(rect, &ctm_only(pis), &dev_rect);
if (code >= 0) {
rfixed->p.x = float2fixed(dev_rect.p.x);
rfixed->p.y = float2fixed(dev_rect.p.y);
rfixed->q.x = float2fixed(dev_rect.q.x);
rfixed->q.y = float2fixed(dev_rect.q.y);
}
return code;
}
/* Get a shading bbox. Returns 1 on success. */
int
gx_dc_pattern2_get_bbox(const gx_device_color * pdevc, gs_fixed_rect *bbox)
{
gs_pattern2_instance_t *pinst =
(gs_pattern2_instance_t *)pdevc->ccolor.pattern;
int code;
if (!pinst->templat.Shading->params.have_BBox)
return 0;
code = gx_dc_pattern2_shade_bbox_transform2fixed(
&pinst->templat.Shading->params.BBox, (gs_imager_state *)pinst->saved, bbox);
if (code < 0)
return code;
return 1;
}
int
gx_dc_pattern2_color_has_bbox(const gx_device_color * pdevc)
{
gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
const gs_shading_t *psh = pinst->templat.Shading;
return psh->params.have_BBox;
}
/* Create a path from a PatternType 2 shading BBox to a path. */
static int
gx_dc_shading_path_add_box(gx_path *ppath, const gx_device_color * pdevc)
{
gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
const gs_shading_t *psh = pinst->templat.Shading;
if (!psh->params.have_BBox)
return_error(gs_error_unregistered); /* Do not call in this case. */
else {
gs_state *pis = pinst->saved;
return gs_shading_path_add_box(ppath, &psh->params.BBox, &pis->ctm);
}
}
/* Intersect a clipping path a shading BBox. */
int
gx_dc_pattern2_clip_with_bbox(const gx_device_color * pdevc, gx_device * pdev,
gx_clip_path *cpath_local, const gx_clip_path **ppcpath1)
{
if (gx_dc_is_pattern2_color(pdevc) && gx_dc_pattern2_color_has_bbox(pdevc) &&
(*dev_proc(pdev, dev_spec_op))(pdev, gxdso_pattern_shading_area, NULL, 0) == 0) {
gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
gx_path box_path;
gs_memory_t *mem = (*ppcpath1 != NULL ? (*ppcpath1)->path.memory : pdev->memory);
int code;
gx_path_init_local(&box_path, mem);
code = gx_dc_shading_path_add_box(&box_path, pdevc);
if (code == gs_error_limitcheck) {
/* Ignore huge BBox - bug 689027. */
code = 0;
} else {
if (code >= 0) {
gx_cpath_init_local_shared(cpath_local, *ppcpath1, mem);
code = gx_cpath_intersect(cpath_local, &box_path, gx_rule_winding_number, (gs_imager_state *)pinst->saved);
*ppcpath1 = cpath_local;
}
}
gx_path_free(&box_path, "gx_default_fill_path(path_bbox)");
}
return 0;
}
/* Intersect a clipping path a shading BBox. */
int
gx_dc_pattern2_clip_with_bbox_simple(const gx_device_color * pdevc, gx_device * pdev,
gx_clip_path *cpath_local)
{
int code = 0;
if (gx_dc_is_pattern2_color(pdevc) && gx_dc_pattern2_color_has_bbox(pdevc) &&
(*dev_proc(pdev, dev_spec_op))(pdev, gxdso_pattern_shading_area, NULL, 0) == 0) {
gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
gx_path box_path;
gs_memory_t *mem = cpath_local->path.memory;
gx_path_init_local(&box_path, mem);
code = gx_dc_shading_path_add_box(&box_path, pdevc);
if (code == gs_error_limitcheck) {
/* Ignore huge BBox - bug 689027. */
code = 0;
} else if (code >= 0) {
code = gx_cpath_intersect(cpath_local, &box_path, gx_rule_winding_number, (gs_imager_state *)pinst->saved);
}
gx_path_free(&box_path, "gx_default_fill_path(path_bbox)");
}
return code;
}
/* Check whether color is a shading with BBox. */
int
gx_dc_pattern2_is_rectangular_cell(const gx_device_color * pdevc, gx_device * pdev, gs_fixed_rect *rect)
{
if (gx_dc_is_pattern2_color(pdevc) && gx_dc_pattern2_color_has_bbox(pdevc) &&
(*dev_proc(pdev, dev_spec_op))(pdev, gxdso_pattern_shading_area, NULL, 0) == 0) {
gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
const gs_shading_t *psh = pinst->templat.Shading;
gs_fixed_point p, q;
if (is_xxyy(&ctm_only(pinst->saved)))
if (psh->params.have_BBox) {
int code = gs_point_transform2fixed(&pinst->saved->ctm,
psh->params.BBox.p.x, psh->params.BBox.p.y, &p);
if (code < 0)
return code;
code = gs_point_transform2fixed(&pinst->saved->ctm,
psh->params.BBox.q.x, psh->params.BBox.q.y, &q);
if (code < 0)
return code;
if (p.x > q.x) {
p.x ^= q.x; q.x ^= p.x; p.x ^= q.x;
}
if (p.y > q.y) {
p.y ^= q.y; q.y ^= p.y; p.y ^= q.y;
}
rect->p = p;
rect->q = q;
return 1;
}
}
return 0;
}
/* Get a shading color space. */
const gs_color_space *
gx_dc_pattern2_get_color_space(const gx_device_color * pdevc)
{
gs_pattern2_instance_t *pinst =
(gs_pattern2_instance_t *)pdevc->ccolor.pattern;
const gs_shading_t *psh = pinst->templat.Shading;
return psh->params.ColorSpace;
}
/* Check device color for a possibly self-overlapping shading. */
bool
gx_dc_pattern2_can_overlap(const gx_device_color *pdevc)
{
gs_pattern2_instance_t * pinst;
if (pdevc->type != &gx_dc_pattern2)
return false;
pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
switch (pinst->templat.Shading->head.type) {
case 3: case 6: case 7:
return true;
default:
return false;
}
}
/* Check whether a pattern color has a background. */
bool gx_dc_pattern2_has_background(const gx_device_color *pdevc)
{
gs_pattern2_instance_t * pinst;
const gs_shading_t *Shading;
if (pdevc->type != &gx_dc_pattern2)
return false;
pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
Shading = pinst->templat.Shading;
return !pinst->shfill && Shading->params.Background != NULL;
}
|