1 /* Copyright (C) 2001-2019 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.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Mask clipping support */
18 #include "gx.h"
19 #include "gserrors.h"
20 #include "gxdevice.h"
21 #include "gxdevmem.h"
22 #include "gxmclip.h"
23 
24 /* Structure descriptor */
25 public_st_device_mask_clip();
26 
27 /* GC procedures */
ENUM_PTRS_WITH(device_mask_clip_enum_ptrs,gx_device_mask_clip * mcdev)28 static ENUM_PTRS_WITH(device_mask_clip_enum_ptrs, gx_device_mask_clip *mcdev)
29 {
30     if (index < st_gx_strip_bitmap_max_ptrs) {
31         return ENUM_USING(st_gx_strip_bitmap, &mcdev->tiles,
32                           sizeof(mcdev->tiles), index);
33     }
34     index -= st_gx_strip_bitmap_max_ptrs;
35     if (index < st_device_memory_max_ptrs) {
36         return ENUM_USING(st_device_memory, &mcdev->mdev,
37                           sizeof(mcdev->mdev), index);
38     }
39     ENUM_PREFIX(st_device_forward, st_device_memory_max_ptrs);
40 }
41 ENUM_PTRS_END
RELOC_PTRS_WITH(device_mask_clip_reloc_ptrs,gx_device_mask_clip * mcdev)42 static RELOC_PTRS_WITH(device_mask_clip_reloc_ptrs, gx_device_mask_clip *mcdev)
43 {
44     RELOC_PREFIX(st_device_forward);
45     RELOC_USING(st_gx_strip_bitmap, &mcdev->tiles, sizeof(mcdev->tiles));
46     RELOC_USING(st_device_memory, &mcdev->mdev, sizeof(mcdev->mdev));
47     if (mcdev->mdev.base != 0) {
48         /*
49          * Update the line pointers specially, since they point into the
50          * buffer that is part of the mask clipping device itself.
51          */
52         long diff = (char *)RELOC_OBJ(mcdev) - (char *)mcdev;
53         int i;
54 
55         for (i = 0; i < mcdev->mdev.height; ++i)
56             mcdev->mdev.line_ptrs[i] += diff;
57         mcdev->mdev.base = mcdev->mdev.line_ptrs[0];
58         mcdev->mdev.line_ptrs =
59             (void *)((char *)(mcdev->mdev.line_ptrs) + diff);
60     }
61 }
62 RELOC_PTRS_END
63 
64 /* Initialize a mask clipping device. */
65 int
gx_mask_clip_initialize(gx_device_mask_clip * cdev,const gx_device_mask_clip * proto,const gx_bitmap * bits,gx_device * tdev,int tx,int ty,gs_memory_t * mem)66 gx_mask_clip_initialize(gx_device_mask_clip * cdev,
67                         const gx_device_mask_clip * proto,
68                         const gx_bitmap * bits, gx_device * tdev,
69                         int tx, int ty, gs_memory_t *mem)
70 {
71     int buffer_width = bits->size.x;
72     int buffer_height =
73         tile_clip_buffer_size / (bits->raster + sizeof(byte *));
74 
75     if (mem == NULL)
76         gx_device_init_on_stack((gx_device *)cdev, (const gx_device *)proto,
77                                 tdev->memory);
78     else
79         gx_device_init((gx_device *)cdev, (const gx_device *)proto, mem, true);
80     cdev->width = tdev->width;
81     cdev->height = tdev->height;
82     cdev->color_info = tdev->color_info;
83     gx_device_set_target((gx_device_forward *)cdev, tdev);
84     cdev->phase.x = -tx;
85     cdev->phase.y = -ty;
86     if (buffer_height > bits->size.y)
87         buffer_height = bits->size.y;
88     gs_make_mem_mono_device(&cdev->mdev, 0, 0);
89     for (;;) {
90         ulong bitmap_size = max_ulong;
91 
92         /* Bug 702124: Allow for the case when size.y == 0 - then
93          * buffer_height will be zero, and it's not a VMerror. */
94         if (bits->size.y > 0 && buffer_height <= 0) {
95             /*
96              * The tile is too wide to buffer even one scan line.
97              * We could do copy_mono in chunks, but for now, we punt.
98              */
99             cdev->mdev.base = 0;
100             return_error(gs_error_VMerror);
101         }
102         cdev->mdev.width = buffer_width;
103         cdev->mdev.height = buffer_height;
104         gdev_mem_bitmap_size(&cdev->mdev, &bitmap_size);
105         if (bitmap_size <= tile_clip_buffer_size)
106             break;
107         buffer_height--;
108     }
109     cdev->mdev.base = cdev->buffer.bytes;
110     return (*dev_proc(&cdev->mdev, open_device))((gx_device *)&cdev->mdev);
111 }
112