/src/ghostpdl/base/gdevmem.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2021 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 | | /* Generic "memory" (stored bitmap) device */ |
17 | | #include "memory_.h" |
18 | | #include "gx.h" |
19 | | #include "gsdevice.h" |
20 | | #include "gserrors.h" |
21 | | #include "gsrect.h" |
22 | | #include "gsstruct.h" |
23 | | #include "gxarith.h" |
24 | | #include "gxdevice.h" |
25 | | #include "gxgetbit.h" |
26 | | #include "gxdevmem.h" /* semi-public definitions */ |
27 | | #include "gdevmem.h" /* private definitions */ |
28 | | #include "gstrans.h" |
29 | | |
30 | | /* Structure descriptor */ |
31 | | public_st_device_memory(); |
32 | | |
33 | | /* GC procedures */ |
34 | | static |
35 | 0 | ENUM_PTRS_WITH(device_memory_enum_ptrs, gx_device_memory *mptr) |
36 | 0 | { |
37 | 0 | return ENUM_USING(st_device_forward, vptr, sizeof(gx_device_forward), index - 3); |
38 | 0 | } |
39 | 0 | case 0: ENUM_RETURN((mptr->foreign_bits ? NULL : (void *)mptr->base)); |
40 | 0 | case 1: ENUM_RETURN((mptr->foreign_line_pointers ? NULL : (void *)mptr->line_ptrs)); |
41 | 0 | ENUM_STRING_PTR(2, gx_device_memory, palette); |
42 | 0 | ENUM_PTRS_END |
43 | | static |
44 | 0 | RELOC_PTRS_WITH(device_memory_reloc_ptrs, gx_device_memory *mptr) |
45 | 0 | { |
46 | 0 | if (!mptr->foreign_bits) { |
47 | 0 | byte *base_old = mptr->base; |
48 | 0 | long reloc; |
49 | 0 | int y; |
50 | 0 | int h = mptr->height; |
51 | |
|
52 | 0 | if (mptr->is_planar) |
53 | 0 | h *= mptr->color_info.num_components; |
54 | |
|
55 | 0 | RELOC_PTR(gx_device_memory, base); |
56 | 0 | reloc = base_old - mptr->base; |
57 | 0 | for (y = 0; y < h; y++) |
58 | 0 | mptr->line_ptrs[y] -= reloc; |
59 | | /* Relocate line_ptrs, which also points into the data area. */ |
60 | 0 | mptr->line_ptrs = (byte **) ((byte *) mptr->line_ptrs - reloc); |
61 | 0 | } else if (!mptr->foreign_line_pointers) { |
62 | 0 | RELOC_PTR(gx_device_memory, line_ptrs); |
63 | 0 | } |
64 | 0 | RELOC_CONST_STRING_PTR(gx_device_memory, palette); |
65 | 0 | RELOC_USING(st_device_forward, vptr, sizeof(gx_device_forward)); |
66 | 0 | } |
67 | 0 | RELOC_PTRS_END |
68 | | |
69 | | /* Define the palettes for monobit devices. */ |
70 | | static const byte b_w_palette_string[6] = { |
71 | | 0xff, 0xff, 0xff, 0, 0, 0 |
72 | | }; |
73 | | const gs_const_string mem_mono_b_w_palette = { |
74 | | b_w_palette_string, 6 |
75 | | }; |
76 | | static const byte w_b_palette_string[6] = { |
77 | | 0, 0, 0, 0xff, 0xff, 0xff |
78 | | }; |
79 | | const gs_const_string mem_mono_w_b_palette = { |
80 | | w_b_palette_string, 6 |
81 | | }; |
82 | | |
83 | | /* ------ Generic code ------ */ |
84 | | |
85 | | /* Return the appropriate memory device for a given */ |
86 | | /* number of bits per pixel (0 if none suitable). |
87 | | Greater than 64 occurs for the planar case |
88 | | which we will then return a mem_x_device */ |
89 | | static const gx_device_memory *const mem_devices[65] = { |
90 | | 0, &mem_mono_device, &mem_mapped2_device, 0, &mem_mapped4_device, |
91 | | 0, 0, 0, &mem_mapped8_device, |
92 | | 0, 0, 0, 0, 0, 0, 0, &mem_true16_device, |
93 | | 0, 0, 0, 0, 0, 0, 0, &mem_true24_device, |
94 | | 0, 0, 0, 0, 0, 0, 0, &mem_true32_device, |
95 | | 0, 0, 0, 0, 0, 0, 0, &mem_true40_device, |
96 | | 0, 0, 0, 0, 0, 0, 0, &mem_true48_device, |
97 | | 0, 0, 0, 0, 0, 0, 0, &mem_true56_device, |
98 | | 0, 0, 0, 0, 0, 0, 0, &mem_true64_device |
99 | | }; |
100 | | const gx_device_memory * |
101 | | gdev_mem_device_for_bits(int bits_per_pixel) |
102 | 2.59M | { |
103 | 2.59M | return ((uint)bits_per_pixel > 64 ? &mem_x_device : |
104 | 2.59M | mem_devices[bits_per_pixel]); |
105 | 2.59M | } |
106 | | /* Do the same for a word-oriented device. */ |
107 | | static const gx_device_memory *const mem_word_devices[65] = { |
108 | | 0, &mem_mono_device, &mem_mapped2_word_device, 0, &mem_mapped4_word_device, |
109 | | 0, 0, 0, &mem_mapped8_word_device, |
110 | | 0, 0, 0, 0, 0, 0, 0, 0 /*no 16-bit word device*/, |
111 | | 0, 0, 0, 0, 0, 0, 0, &mem_true24_word_device, |
112 | | 0, 0, 0, 0, 0, 0, 0, &mem_true32_word_device, |
113 | | 0, 0, 0, 0, 0, 0, 0, &mem_true40_word_device, |
114 | | 0, 0, 0, 0, 0, 0, 0, &mem_true48_word_device, |
115 | | 0, 0, 0, 0, 0, 0, 0, &mem_true56_word_device, |
116 | | 0, 0, 0, 0, 0, 0, 0, &mem_true64_word_device |
117 | | }; |
118 | | const gx_device_memory * |
119 | | gdev_mem_word_device_for_bits(int bits_per_pixel) |
120 | 0 | { |
121 | 0 | return ((uint)bits_per_pixel > 64 ? (const gx_device_memory *)0 : |
122 | 0 | mem_word_devices[bits_per_pixel]); |
123 | 0 | } |
124 | | |
125 | | static const gdev_mem_functions *mem_fns[65] = { |
126 | | NULL, &gdev_mem_fns_1, &gdev_mem_fns_2, NULL, |
127 | | &gdev_mem_fns_4, NULL, NULL, NULL, |
128 | | &gdev_mem_fns_8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
129 | | &gdev_mem_fns_16, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
130 | | &gdev_mem_fns_24, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
131 | | &gdev_mem_fns_32, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
132 | | &gdev_mem_fns_40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
133 | | &gdev_mem_fns_48, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
134 | | &gdev_mem_fns_56, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
135 | | &gdev_mem_fns_64 |
136 | | }; |
137 | | |
138 | | const gdev_mem_functions * |
139 | | gdev_mem_functions_for_bits(int bits_per_pixel) |
140 | 2.81M | { |
141 | 2.81M | return ((uint)bits_per_pixel > 64 ? NULL : mem_fns[bits_per_pixel]); |
142 | 2.81M | } |
143 | | |
144 | | static const gdev_mem_functions *mem_word_fns[65] = { |
145 | | NULL, &gdev_mem_fns_1, &gdev_mem_fns_2w, NULL, |
146 | | &gdev_mem_fns_4w, NULL, NULL, NULL, |
147 | | &gdev_mem_fns_8w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
148 | | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
149 | | &gdev_mem_fns_24w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
150 | | &gdev_mem_fns_32w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
151 | | &gdev_mem_fns_40w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
152 | | &gdev_mem_fns_48w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
153 | | &gdev_mem_fns_56w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
154 | | &gdev_mem_fns_64w |
155 | | }; |
156 | | |
157 | | const gdev_mem_functions * |
158 | | gdev_mem_word_functions_for_bits(int bits_per_pixel) |
159 | 0 | { |
160 | 0 | return ((uint)bits_per_pixel > 64 ? NULL : mem_word_fns[bits_per_pixel]); |
161 | 0 | } |
162 | | |
163 | | /* Test whether a device is a memory device */ |
164 | | bool |
165 | | gs_device_is_memory(const gx_device * dev) |
166 | 8.59M | { |
167 | | /* |
168 | | * We use the draw_thin_line procedure to mark memory devices. |
169 | | * See gdevmem.h. |
170 | | */ |
171 | 8.59M | return (dev_proc(dev, draw_thin_line) == mem_draw_thin_line); |
172 | 8.59M | } |
173 | | |
174 | | /* Make a memory device. */ |
175 | | /* Note that the default for monobit devices is white = 0, black = 1. */ |
176 | | void |
177 | | gs_make_mem_device(gx_device_memory * dev, const gx_device_memory * mdproto, |
178 | | gs_memory_t * mem, int page_device, gx_device * target) |
179 | 2.59M | { |
180 | | /* Can never fail */ |
181 | 2.59M | (void)gx_device_init((gx_device *) dev, (const gx_device *)mdproto, |
182 | 2.59M | mem, true); |
183 | 2.59M | dev->stype = &st_device_memory; |
184 | 2.59M | switch (page_device) { |
185 | 11 | case -1: |
186 | 11 | set_dev_proc(dev, get_page_device, gx_default_get_page_device); |
187 | 11 | break; |
188 | 14.7k | case 1: |
189 | 14.7k | set_dev_proc(dev, get_page_device, gx_page_device_get_page_device); |
190 | 14.7k | break; |
191 | 2.59M | } |
192 | | /* Preload the black and white cache. */ |
193 | 2.59M | if (target == NULL) { |
194 | 0 | if (dev->color_info.depth == 1) { |
195 | | /* The default for black-and-white devices is inverted. */ |
196 | 0 | dev->cached_colors.black = 1; |
197 | 0 | dev->cached_colors.white = 0; |
198 | 0 | } else { |
199 | 0 | dev->cached_colors.black = 0; |
200 | 0 | dev->cached_colors.white = (1 << dev->color_info.depth) - 1; |
201 | 0 | } |
202 | 0 | dev->graphics_type_tag = GS_UNKNOWN_TAG; |
203 | 2.59M | } else { |
204 | 2.59M | gx_device_set_target((gx_device_forward *)dev, target); |
205 | | /* Forward the color mapping operations to the target. */ |
206 | 2.59M | gx_device_forward_color_procs((gx_device_forward *) dev); |
207 | 2.59M | gx_device_copy_color_procs((gx_device *)dev, target); |
208 | 2.59M | dev->color_info.separable_and_linear = target->color_info.separable_and_linear; |
209 | 2.59M | dev->cached_colors = target->cached_colors; |
210 | 2.59M | dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */ |
211 | | |
212 | 2.59M | set_dev_proc(dev, put_image, gx_forward_put_image); |
213 | 2.59M | set_dev_proc(dev, dev_spec_op, gx_default_dev_spec_op); |
214 | 2.59M | } |
215 | 2.59M | if (dev->color_info.depth == 1) { |
216 | 0 | gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS]; |
217 | 0 | uchar k; |
218 | |
|
219 | 0 | if (target != 0) { |
220 | 0 | for (k = 0; k < target->color_info.num_components; k++) { |
221 | 0 | cv[k] = 0; |
222 | 0 | } |
223 | 0 | } |
224 | 0 | gdev_mem_mono_set_inverted(dev, (target == NULL || |
225 | 0 | (*dev_proc(dev, encode_color))((gx_device *)dev, cv) != 0)); |
226 | 0 | } |
227 | 2.59M | check_device_separable((gx_device *)dev); |
228 | 2.59M | gx_device_fill_in_procs((gx_device *)dev); |
229 | 2.59M | dev->band_y = 0; |
230 | 2.59M | } |
231 | | |
232 | | /* Make a memory device using copydevice, this should replace gs_make_mem_device. */ |
233 | | /* Note that the default for monobit devices is white = 0, black = 1. */ |
234 | | int |
235 | | gs_make_mem_device_with_copydevice(gx_device_memory ** ppdev, |
236 | | const gx_device_memory * mdproto, |
237 | | gs_memory_t * mem, |
238 | | int page_device, |
239 | | gx_device * target) |
240 | 0 | { |
241 | 0 | int code; |
242 | 0 | gx_device_memory *pdev; |
243 | |
|
244 | 0 | if (mem == NULL) |
245 | 0 | return -1; |
246 | | |
247 | 0 | code = gs_copydevice((gx_device **)&pdev, |
248 | 0 | (const gx_device *)mdproto, |
249 | 0 | mem); |
250 | 0 | if (code < 0) |
251 | 0 | return code; |
252 | | |
253 | 0 | switch (page_device) { |
254 | 0 | case -1: |
255 | 0 | set_dev_proc(pdev, get_page_device, gx_default_get_page_device); |
256 | 0 | break; |
257 | 0 | case 1: |
258 | 0 | set_dev_proc(pdev, get_page_device, gx_page_device_get_page_device); |
259 | 0 | break; |
260 | 0 | } |
261 | | /* Preload the black and white cache. */ |
262 | 0 | if (target == NULL) { |
263 | 0 | if (pdev->color_info.depth == 1) { |
264 | | /* The default for black-and-white devices is inverted. */ |
265 | 0 | pdev->cached_colors.black = 1; |
266 | 0 | pdev->cached_colors.white = 0; |
267 | 0 | } else { |
268 | 0 | pdev->cached_colors.black = 0; |
269 | 0 | pdev->cached_colors.white = (1 << pdev->color_info.depth) - 1; |
270 | 0 | } |
271 | 0 | pdev->graphics_type_tag = GS_UNKNOWN_TAG; |
272 | 0 | } else { |
273 | 0 | gx_device_set_target((gx_device_forward *)pdev, target); |
274 | | /* Forward the color mapping operations to the target. */ |
275 | 0 | gx_device_forward_color_procs((gx_device_forward *) pdev); |
276 | 0 | gx_device_copy_color_procs((gx_device *)pdev, target); |
277 | 0 | pdev->cached_colors = target->cached_colors; |
278 | 0 | pdev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */ |
279 | 0 | } |
280 | 0 | if (pdev->color_info.depth == 1) { |
281 | 0 | gx_color_value cv[3]; |
282 | |
|
283 | 0 | cv[0] = cv[1] = cv[2] = 0; |
284 | 0 | gdev_mem_mono_set_inverted(pdev, (target == NULL || |
285 | 0 | (*dev_proc(pdev, encode_color))((gx_device *)pdev, cv) != 0)); |
286 | 0 | } |
287 | 0 | check_device_separable((gx_device *)pdev); |
288 | 0 | gx_device_fill_in_procs((gx_device *)pdev); |
289 | 0 | pdev->band_y = 0; |
290 | 0 | *ppdev = pdev; |
291 | 0 | return 0; |
292 | 0 | } |
293 | | |
294 | | /* Make a monobit memory device using copydevice */ |
295 | | int |
296 | | gs_make_mem_mono_device_with_copydevice(gx_device_memory ** ppdev, gs_memory_t * mem, |
297 | | gx_device * target) |
298 | 0 | { |
299 | 0 | int code; |
300 | 0 | gx_device_memory *pdev; |
301 | |
|
302 | 0 | if (mem == NULL) |
303 | 0 | return -1; |
304 | | |
305 | 0 | code = gs_copydevice((gx_device **)&pdev, |
306 | 0 | (const gx_device *)&mem_mono_device, |
307 | 0 | mem); |
308 | 0 | if (code < 0) |
309 | 0 | return code; |
310 | | |
311 | 0 | set_dev_proc(pdev, get_page_device, gx_default_get_page_device); |
312 | 0 | gx_device_set_target((gx_device_forward *)pdev, target); |
313 | | /* Should this be forwarding, monochrome profile, or not set? MJV. */ |
314 | 0 | set_dev_proc(pdev, get_profile, gx_forward_get_profile); |
315 | |
|
316 | 0 | gdev_mem_mono_set_inverted(pdev, true); |
317 | 0 | check_device_separable((gx_device *)pdev); |
318 | 0 | gx_device_fill_in_procs((gx_device *)pdev); |
319 | 0 | *ppdev = pdev; |
320 | 0 | return 0; |
321 | 0 | } |
322 | | |
323 | | /* Make a monobit memory device. This is never a page device. */ |
324 | | /* Note that white=0, black=1. */ |
325 | | void |
326 | | gs_make_mem_mono_device(gx_device_memory * dev, gs_memory_t * mem, |
327 | | gx_device * target) |
328 | 222k | { |
329 | | /* Can never fail */ |
330 | 222k | (void)gx_device_init((gx_device *)dev, |
331 | 222k | (const gx_device *)&mem_mono_device, |
332 | 222k | mem, true); |
333 | 222k | set_dev_proc(dev, get_page_device, gx_default_get_page_device); |
334 | 222k | gx_device_set_target((gx_device_forward *)dev, target); |
335 | 222k | dev->raster = gx_device_raster((gx_device *)dev, 1); |
336 | 222k | gdev_mem_mono_set_inverted(dev, true); |
337 | 222k | check_device_separable((gx_device *)dev); |
338 | 222k | gx_device_fill_in_procs((gx_device *)dev); |
339 | | /* Should this be forwarding, monochrome profile, or not set? MJV */ |
340 | 222k | set_dev_proc(dev, get_profile, gx_forward_get_profile); |
341 | 222k | set_dev_proc(dev, set_graphics_type_tag, gx_forward_set_graphics_type_tag); |
342 | 222k | set_dev_proc(dev, dev_spec_op, gx_default_dev_spec_op); |
343 | | /* initialize to same tag as target */ |
344 | 222k | dev->graphics_type_tag = target ? target->graphics_type_tag : GS_UNKNOWN_TAG; |
345 | 222k | } |
346 | | |
347 | | /* Define whether a monobit memory device is inverted (black=1). */ |
348 | | void |
349 | | gdev_mem_mono_set_inverted(gx_device_memory * dev, bool black_is_1) |
350 | 222k | { |
351 | 222k | if (black_is_1) |
352 | 222k | dev->palette = mem_mono_b_w_palette; |
353 | 0 | else |
354 | 0 | dev->palette = mem_mono_w_b_palette; |
355 | 222k | } |
356 | | |
357 | | /* |
358 | | * Compute the size of the bitmap storage, including the space for the scan |
359 | | * line pointer table. Note that scan lines are padded to a multiple of |
360 | | * align_bitmap_mod bytes, and additional padding may be needed if the |
361 | | * pointer table must be aligned to an even larger modulus. |
362 | | * |
363 | | * The computation for planar devices is a little messier. Each plane |
364 | | * must pad its scan lines, and then we must pad again for the pointer |
365 | | * tables (one table per plane). |
366 | | * |
367 | | * Return VMerror if the size exceeds max ulong |
368 | | */ |
369 | | int |
370 | | gdev_mem_bits_size(const gx_device_memory * dev, int width, int height, ulong *psize) |
371 | 449k | { |
372 | 449k | int num_planes; |
373 | 449k | gx_render_plane_t plane1; |
374 | 449k | const gx_render_plane_t *planes; |
375 | 449k | ulong size; |
376 | 449k | int pi; |
377 | | |
378 | 449k | if (dev->is_planar) { |
379 | 0 | num_planes = dev->color_info.num_components; |
380 | 0 | planes = dev->planes; |
381 | 0 | } else |
382 | 449k | planes = &plane1, plane1.depth = dev->color_info.depth, num_planes = 1; |
383 | 899k | for (size = 0, pi = 0; pi < num_planes; ++pi) |
384 | 449k | size += bitmap_raster_pad_align(width * planes[pi].depth, dev->pad, dev->log2_align_mod); |
385 | 449k | if (height != 0) |
386 | 449k | if (size > (max_ulong - ARCH_ALIGN_PTR_MOD) / (ulong)height) |
387 | 0 | return_error(gs_error_VMerror); |
388 | 449k | size = ROUND_UP(size * height, ARCH_ALIGN_PTR_MOD); |
389 | 449k | if (dev->log2_align_mod > log2_align_bitmap_mod) |
390 | 0 | size += 1<<dev->log2_align_mod; |
391 | 449k | *psize = size; |
392 | 449k | return 0; |
393 | 449k | } |
394 | | ulong |
395 | | gdev_mem_line_ptrs_size(const gx_device_memory * dev, int width, int height) |
396 | 300k | { |
397 | 300k | int num_planes = 1; |
398 | 300k | if (dev->is_planar) |
399 | 0 | num_planes = dev->color_info.num_components; |
400 | 300k | return (ulong)height * sizeof(byte *) * num_planes; |
401 | 300k | } |
402 | | int |
403 | | gdev_mem_data_size(const gx_device_memory * dev, int width, int height, ulong *psize) |
404 | 296k | { |
405 | 296k | ulong bits_size; |
406 | 296k | ulong line_ptrs_size = gdev_mem_line_ptrs_size(dev, width, height); |
407 | | |
408 | 296k | if (gdev_mem_bits_size(dev, width, height, &bits_size) < 0 || |
409 | 296k | bits_size > max_ulong - line_ptrs_size) |
410 | 0 | return_error(gs_error_VMerror); |
411 | 296k | *psize = bits_size + line_ptrs_size; |
412 | 296k | return 0; |
413 | 296k | } |
414 | | /* |
415 | | * Do the inverse computation: given a width (in pixels) and a buffer size, |
416 | | * compute the maximum height. |
417 | | */ |
418 | | int |
419 | | gdev_mem_max_height(const gx_device_memory * dev, int width, ulong size, |
420 | | bool page_uses_transparency) |
421 | 14.7k | { |
422 | 14.7k | int height; |
423 | 14.7k | ulong max_height; |
424 | 14.7k | ulong data_size; |
425 | 14.7k | bool deep = device_is_deep((const gx_device *)dev); |
426 | | |
427 | 14.7k | if (page_uses_transparency) { |
428 | | /* |
429 | | * If the device is using PDF 1.4 transparency then we will need to |
430 | | * also allocate image buffers for doing the blending operations. |
431 | | * We can only estimate the space requirements. However since it |
432 | | * is only an estimate, we may exceed our desired buffer space while |
433 | | * processing the file. |
434 | | */ |
435 | 3.30k | max_height = size / (bitmap_raster_pad_align(width |
436 | 3.30k | * dev->color_info.depth + ESTIMATED_PDF14_ROW_SPACE(width, dev->color_info.num_components, deep ? 16 : 8), |
437 | 3.30k | dev->pad, dev->log2_align_mod) + sizeof(byte *) * (dev->is_planar ? dev->color_info.num_components : 1)); |
438 | 3.30k | height = (int)min(max_height, max_int); |
439 | 11.4k | } else { |
440 | | /* For non PDF 1.4 transparency, we can do an exact calculation */ |
441 | 11.4k | max_height = size / |
442 | 11.4k | (bitmap_raster_pad_align(width * dev->color_info.depth, dev->pad, dev->log2_align_mod) + |
443 | 11.4k | sizeof(byte *) * (dev->is_planar ? dev->color_info.num_components : 1)); |
444 | 11.4k | height = (int)min(max_height, max_int); |
445 | | /* |
446 | | * Because of alignment rounding, the just-computed height might |
447 | | * be too large by a small amount. Adjust it the easy way. |
448 | | */ |
449 | 11.4k | do { |
450 | 11.4k | gdev_mem_data_size(dev, width, height, &data_size); |
451 | 11.4k | if (data_size <= size) |
452 | 11.4k | break; |
453 | 0 | --height; |
454 | 0 | } while (data_size > size); |
455 | 11.4k | } |
456 | 0 | return height; |
457 | 14.7k | } |
458 | | |
459 | | /* Open a memory device, allocating the data area if appropriate, */ |
460 | | /* and create the scan line table. */ |
461 | | int |
462 | | mem_open(gx_device * dev) |
463 | 135k | { |
464 | 135k | gx_device_memory *const mdev = (gx_device_memory *)dev; |
465 | | |
466 | | /* Check that we aren't trying to open a planar device as chunky. */ |
467 | 135k | if (mdev->is_planar) |
468 | 0 | return_error(gs_error_rangecheck); |
469 | 135k | return gdev_mem_open_scan_lines(mdev, dev->height); |
470 | 135k | } |
471 | | int |
472 | | gdev_mem_open_scan_lines(gx_device_memory *mdev, int setup_height) |
473 | 135k | { |
474 | 135k | return gdev_mem_open_scan_lines_interleaved(mdev, setup_height, 0); |
475 | 135k | } |
476 | | int |
477 | | gdev_mem_open_scan_lines_interleaved(gx_device_memory *mdev, |
478 | | int setup_height, |
479 | | int interleaved) |
480 | 135k | { |
481 | 135k | bool line_pointers_adjacent = true; |
482 | 135k | ulong size; |
483 | | |
484 | 135k | if (setup_height < 0 || setup_height > mdev->height) |
485 | 0 | return_error(gs_error_rangecheck); |
486 | 135k | if (mdev->bitmap_memory != NULL) { |
487 | 726 | int align; |
488 | | /* Allocate the data now. */ |
489 | 726 | if (gdev_mem_bitmap_size(mdev, &size) < 0) |
490 | 0 | return_error(gs_error_VMerror); |
491 | | |
492 | 726 | if ((uint) size != size) /* ulong may be bigger than uint */ |
493 | 0 | return_error(gs_error_limitcheck); |
494 | 726 | mdev->base = gs_alloc_bytes(mdev->bitmap_memory, (uint)size, |
495 | 726 | "mem_open"); |
496 | 726 | if (mdev->base == NULL) |
497 | 0 | return_error(gs_error_VMerror); |
498 | 726 | #ifdef PACIFY_VALGRIND |
499 | | /* If we end up writing the bitmap to the clist, we can get valgrind errors |
500 | | * because we write and read the padding at the end of each raster line. |
501 | | * Easiest to set the entire block. |
502 | | */ |
503 | 726 | memset(mdev->base, 0x00, size); |
504 | 726 | #endif |
505 | 726 | align = 1<<mdev->log2_align_mod; |
506 | 726 | mdev->base += (-(int)(intptr_t)mdev->base) & (align-1); |
507 | 726 | mdev->foreign_bits = false; |
508 | 134k | } else if (mdev->line_pointer_memory != NULL) { |
509 | | /* Allocate the line pointers now. */ |
510 | |
|
511 | 0 | mdev->line_ptrs = (byte **) |
512 | 0 | gs_alloc_byte_array(mdev->line_pointer_memory, mdev->height, |
513 | 0 | sizeof(byte *) * (mdev->is_planar ? mdev->color_info.num_components : 1), |
514 | 0 | "gdev_mem_open_scan_lines"); |
515 | 0 | if (mdev->line_ptrs == NULL) |
516 | 0 | return_error(gs_error_VMerror); |
517 | 0 | mdev->foreign_line_pointers = false; |
518 | 0 | line_pointers_adjacent = false; |
519 | 0 | } |
520 | 135k | if (line_pointers_adjacent) { |
521 | 135k | int code; |
522 | | |
523 | 135k | if (mdev->base == NULL) |
524 | 0 | return_error(gs_error_rangecheck); |
525 | | |
526 | 135k | code = gdev_mem_bits_size(mdev, mdev->width, mdev->height, &size); |
527 | 135k | if (code < 0) |
528 | 0 | return code; |
529 | | |
530 | 135k | mdev->line_ptrs = (byte **)(mdev->base + size); |
531 | 135k | } |
532 | 135k | mdev->raster = gx_device_raster((gx_device *)mdev, 1); |
533 | 135k | return gdev_mem_set_line_ptrs_interleaved(mdev, NULL, 0, NULL, |
534 | 135k | setup_height, |
535 | 135k | interleaved); |
536 | 135k | } |
537 | | /* |
538 | | * Set up the scan line pointers of a memory device. |
539 | | * See gxdevmem.h for the detailed specification. |
540 | | * Sets or uses line_ptrs, base, raster; uses width, color_info.depth, |
541 | | * num_planes, plane_depths, plane_depth. |
542 | | */ |
543 | | int |
544 | | gdev_mem_set_line_ptrs(gx_device_memory *mdev, byte *base, int raster, |
545 | | byte **line_ptrs, int setup_height) |
546 | 2.63M | { |
547 | 2.63M | return gdev_mem_set_line_ptrs_interleaved(mdev, base, raster, line_ptrs, setup_height, 0); |
548 | 2.63M | } |
549 | | int |
550 | | gdev_mem_set_line_ptrs_interleaved(gx_device_memory * mdev, byte * base, |
551 | | int raster, byte **line_ptrs, |
552 | | int setup_height, int interleaved) |
553 | 2.77M | { |
554 | 2.77M | int num_planes = (mdev->is_planar ? mdev->color_info.num_components : 0); |
555 | 2.77M | byte **pline; |
556 | 2.77M | byte *data; |
557 | 2.77M | int pi; |
558 | 2.77M | int plane_raster; |
559 | | |
560 | | /* If we are supplied with line_ptrs, then assume that we don't have |
561 | | * any already, and take them on. */ |
562 | 2.77M | if (line_ptrs) |
563 | 2.63M | mdev->line_ptrs = line_ptrs; |
564 | 2.77M | pline = mdev->line_ptrs; |
565 | | |
566 | | /* If we are supplied a base, then we are supplied a raster. Assume that |
567 | | * we don't have any buffer already, and take these on. Assume that the |
568 | | * base has been allocated with sufficient padding to allow for any |
569 | | * alignment required. */ |
570 | 2.77M | if (base == NULL) { |
571 | 135k | base = mdev->base; |
572 | 135k | raster = mdev->raster; |
573 | 2.63M | } else { |
574 | 2.63M | mdev->base = base; |
575 | 2.63M | mdev->raster = raster; |
576 | 2.63M | } |
577 | | |
578 | | /* Now, pad and align as required. */ |
579 | 2.77M | if (mdev->log2_align_mod > log2_align_bitmap_mod) { |
580 | 0 | int align = 1<<mdev->log2_align_mod; |
581 | 0 | align = (-(int)(intptr_t)base) & (align-1); |
582 | 0 | data = base + align; |
583 | 2.77M | } else { |
584 | 2.77M | data = mdev->base; |
585 | 2.77M | } |
586 | | |
587 | 2.77M | if (num_planes) { |
588 | 0 | if (base && !mdev->plane_depth) |
589 | 0 | return_error(gs_error_rangecheck); |
590 | 2.77M | } else { |
591 | 2.77M | num_planes = 1; |
592 | 2.77M | } |
593 | | |
594 | 2.77M | if (interleaved) |
595 | 0 | plane_raster = raster, raster *= num_planes; |
596 | 2.77M | else |
597 | 2.77M | plane_raster = raster * mdev->height; |
598 | 5.54M | for (pi = 0; pi < num_planes; ++pi) { |
599 | 2.77M | byte **pptr = pline; |
600 | 2.77M | byte **pend = pptr + setup_height; |
601 | 2.77M | byte *scan_line = data; |
602 | | |
603 | 11.9M | while (pptr < pend) { |
604 | 9.13M | *pptr++ = scan_line; |
605 | 9.13M | scan_line += raster; |
606 | 9.13M | } |
607 | 2.77M | data += plane_raster; |
608 | 2.77M | pline += setup_height; /* not mdev->height, see gxdevmem.h */ |
609 | 2.77M | } |
610 | | |
611 | 2.77M | return 0; |
612 | 2.77M | } |
613 | | |
614 | | /* Return the initial transformation matrix */ |
615 | | void |
616 | | mem_get_initial_matrix(gx_device * dev, gs_matrix * pmat) |
617 | 95.5k | { |
618 | 95.5k | gx_device_memory * const mdev = (gx_device_memory *)dev; |
619 | | |
620 | 95.5k | pmat->xx = mdev->initial_matrix.xx; |
621 | 95.5k | pmat->xy = mdev->initial_matrix.xy; |
622 | 95.5k | pmat->yx = mdev->initial_matrix.yx; |
623 | 95.5k | pmat->yy = mdev->initial_matrix.yy; |
624 | 95.5k | pmat->tx = mdev->initial_matrix.tx; |
625 | 95.5k | pmat->ty = mdev->initial_matrix.ty; |
626 | 95.5k | } |
627 | | |
628 | | /* Close a memory device, freeing the data area if appropriate. */ |
629 | | int |
630 | | mem_close(gx_device * dev) |
631 | 2.71M | { |
632 | 2.71M | gx_device_memory * const mdev = (gx_device_memory *)dev; |
633 | | |
634 | 2.71M | if (mdev->bitmap_memory != 0) { |
635 | 2 | gs_free_object(mdev->bitmap_memory, mdev->base, "mem_close"); |
636 | | /* |
637 | | * The following assignment is strictly for the benefit of one |
638 | | * client that is sloppy about using is_open properly. |
639 | | */ |
640 | 2 | mdev->base = 0; |
641 | 2.71M | } else if (mdev->line_pointer_memory != 0) { |
642 | 0 | gs_free_object(mdev->line_pointer_memory, mdev->line_ptrs, |
643 | 0 | "mem_close"); |
644 | 0 | mdev->line_ptrs = 0; /* ibid. */ |
645 | 0 | } |
646 | 2.71M | return 0; |
647 | 2.71M | } |
648 | | |
649 | | /* Copy bits to a client. */ |
650 | | #undef chunk |
651 | | #define chunk byte |
652 | | int |
653 | | mem_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, |
654 | | gs_get_bits_params_t * params) |
655 | 2.57M | { |
656 | 2.57M | gx_device_memory * const mdev = (gx_device_memory *)dev; |
657 | 2.57M | gs_get_bits_options_t options = params->options; |
658 | 2.57M | int x = prect->p.x, w = prect->q.x - x, y = prect->p.y, h = prect->q.y - y; |
659 | | |
660 | 2.57M | if (options == 0) { |
661 | 0 | params->options = |
662 | 0 | (GB_ALIGN_STANDARD | GB_ALIGN_ANY) | |
663 | 0 | (GB_RETURN_COPY | GB_RETURN_POINTER) | |
664 | 0 | (GB_OFFSET_0 | GB_OFFSET_SPECIFIED | GB_OFFSET_ANY) | |
665 | 0 | (GB_RASTER_STANDARD | GB_RASTER_SPECIFIED | GB_RASTER_ANY) | |
666 | 0 | GB_PACKING_CHUNKY | GB_COLORS_NATIVE | GB_ALPHA_NONE; |
667 | 0 | return_error(gs_error_rangecheck); |
668 | 0 | } |
669 | 2.57M | if (mdev->line_ptrs == NULL) |
670 | 0 | return_error(gs_error_rangecheck); |
671 | 2.57M | if ((w <= 0) | (h <= 0)) { |
672 | 0 | if ((w | h) < 0) |
673 | 0 | return_error(gs_error_rangecheck); |
674 | 0 | return 0; |
675 | 0 | } |
676 | 2.57M | if (x < 0 || w > dev->width - x || |
677 | 2.57M | y < 0 || h > dev->height - y |
678 | 2.57M | ) |
679 | 0 | return_error(gs_error_rangecheck); |
680 | 2.57M | { |
681 | 2.57M | gs_get_bits_params_t copy_params; |
682 | 2.57M | byte **base = &scan_line_base(mdev, y); |
683 | 2.57M | int code; |
684 | | |
685 | 2.57M | copy_params.options = |
686 | 2.57M | GB_COLORS_NATIVE | GB_PACKING_CHUNKY | GB_ALPHA_NONE | |
687 | 2.57M | (mdev->raster == |
688 | 2.57M | bitmap_raster(mdev->width * mdev->color_info.depth) ? |
689 | 2.57M | GB_RASTER_STANDARD : GB_RASTER_SPECIFIED); |
690 | 2.57M | copy_params.raster = mdev->raster; |
691 | 2.57M | code = gx_get_bits_return_pointer(dev, x, h, params, |
692 | 2.57M | ©_params, base); |
693 | 2.57M | if (code >= 0) |
694 | 2.57M | return code; |
695 | 0 | return gx_get_bits_copy(dev, x, w, h, params, ©_params, *base, |
696 | 0 | gx_device_raster(dev, true)); |
697 | 2.57M | } |
698 | 2.57M | } |
699 | | |
700 | | #if !ARCH_IS_BIG_ENDIAN |
701 | | |
702 | | /* |
703 | | * Swap byte order in a rectangular subset of a bitmap. If store = true, |
704 | | * assume the rectangle will be overwritten, so don't swap any bytes where |
705 | | * it doesn't matter. The caller has already done a fit_fill or fit_copy. |
706 | | * Note that the coordinates are specified in bits, not in terms of the |
707 | | * actual device depth. |
708 | | */ |
709 | | void |
710 | | mem_swap_byte_rect(byte * base, uint raster, int x, int w, int h, bool store) |
711 | 0 | { |
712 | 0 | int xbit = x & 31; |
713 | |
|
714 | 0 | if (store) { |
715 | 0 | if (xbit + w > 64) { /* Operation spans multiple words. */ |
716 | | /* Just swap the words at the left and right edges. */ |
717 | 0 | if (xbit != 0) |
718 | 0 | mem_swap_byte_rect(base, raster, x, 1, h, false); |
719 | 0 | x += w - 1; |
720 | 0 | xbit = x & 31; |
721 | 0 | if (xbit == 31) |
722 | 0 | return; |
723 | 0 | w = 1; |
724 | 0 | } |
725 | 0 | } |
726 | | /* Swap the entire rectangle (or what's left of it). */ |
727 | 0 | { |
728 | 0 | byte *row = base + ((x >> 5) << 2); |
729 | 0 | int nw = (xbit + w + 31) >> 5; |
730 | 0 | int ny; |
731 | |
|
732 | 0 | for (ny = h; ny > 0; row += raster, --ny) { |
733 | 0 | int nx = nw; |
734 | 0 | bits32 *pw = (bits32 *) row; |
735 | |
|
736 | 0 | do { |
737 | 0 | bits32 v = *pw; |
738 | |
|
739 | 0 | *pw++ = (v >> 24) + ((v >> 8) & 0xff00) + |
740 | 0 | ((v & 0xff00) << 8) + (v << 24); |
741 | 0 | } |
742 | 0 | while (--nx); |
743 | 0 | } |
744 | 0 | } |
745 | 0 | } |
746 | | |
747 | | /* Copy a word-oriented rectangle to the client, swapping bytes as needed. */ |
748 | | int |
749 | | mem_word_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, |
750 | | gs_get_bits_params_t * params) |
751 | 0 | { |
752 | 0 | gx_device_memory * const mdev = (gx_device_memory *)dev; |
753 | 0 | byte *src; |
754 | 0 | uint dev_raster = gx_device_raster(dev, 1); |
755 | 0 | int x = prect->p.x; |
756 | 0 | int w = prect->q.x - x; |
757 | 0 | int y = prect->p.y; |
758 | 0 | int h = prect->q.y - y; |
759 | 0 | int bit_x, bit_w; |
760 | 0 | int code; |
761 | |
|
762 | 0 | fit_fill_xywh(dev, x, y, w, h); |
763 | 0 | if (w <= 0 || h <= 0) { |
764 | | /* |
765 | | * It's easiest to just keep going with an empty rectangle. |
766 | | * We pass the original rectangle to mem_get_bits_rectangle. |
767 | | */ |
768 | 0 | x = y = w = h = 0; |
769 | 0 | } |
770 | 0 | bit_x = x * dev->color_info.depth; |
771 | 0 | bit_w = w * dev->color_info.depth; |
772 | |
|
773 | 0 | if(mdev->line_ptrs == NULL) |
774 | 0 | return_error(gs_error_rangecheck); |
775 | | |
776 | 0 | src = scan_line_base(mdev, y); |
777 | 0 | mem_swap_byte_rect(src, dev_raster, bit_x, bit_w, h, false); |
778 | 0 | code = mem_get_bits_rectangle(dev, prect, params); |
779 | 0 | mem_swap_byte_rect(src, dev_raster, bit_x, bit_w, h, false); |
780 | 0 | return code; |
781 | 0 | } |
782 | | |
783 | | #endif /* !ARCH_IS_BIG_ENDIAN */ |
784 | | |
785 | | /* Map a r-g-b color to a color index for a mapped color memory device */ |
786 | | /* (2, 4, or 8 bits per pixel.) */ |
787 | | /* This requires searching the palette. */ |
788 | | gx_color_index |
789 | | mem_mapped_map_rgb_color(gx_device * dev, const gx_color_value cv[]) |
790 | 0 | { |
791 | 0 | gx_device_memory * const mdev = (gx_device_memory *)dev; |
792 | 0 | byte br = gx_color_value_to_byte(cv[0]); |
793 | |
|
794 | 0 | register const byte *pptr = mdev->palette.data; |
795 | 0 | int cnt = mdev->palette.size; |
796 | 0 | const byte *which = 0; /* initialized only to pacify gcc */ |
797 | 0 | int best = 256 * 3; |
798 | |
|
799 | 0 | if (mdev->color_info.num_components != 1) { |
800 | | /* not 1 component, assume three */ |
801 | | /* The comparison is rather simplistic, treating differences in */ |
802 | | /* all components as equal. Better choices would be 'distance' */ |
803 | | /* in HLS space or other, but these would be much slower. */ |
804 | | /* At least exact matches will be found. */ |
805 | 0 | byte bg = gx_color_value_to_byte(cv[1]); |
806 | 0 | byte bb = gx_color_value_to_byte(cv[2]); |
807 | |
|
808 | 0 | while ((cnt -= 3) >= 0) { |
809 | 0 | register int diff = *pptr - br; |
810 | |
|
811 | 0 | if (diff < 0) |
812 | 0 | diff = -diff; |
813 | 0 | if (diff < best) { /* quick rejection */ |
814 | 0 | int dg = pptr[1] - bg; |
815 | |
|
816 | 0 | if (dg < 0) |
817 | 0 | dg = -dg; |
818 | 0 | if ((diff += dg) < best) { /* quick rejection */ |
819 | 0 | int db = pptr[2] - bb; |
820 | |
|
821 | 0 | if (db < 0) |
822 | 0 | db = -db; |
823 | 0 | if ((diff += db) < best) |
824 | 0 | which = pptr, best = diff; |
825 | 0 | } |
826 | 0 | } |
827 | 0 | if (diff == 0) /* can't get any better than 0 diff */ |
828 | 0 | break; |
829 | 0 | pptr += 3; |
830 | 0 | } |
831 | 0 | } else { |
832 | | /* Gray scale conversion. The palette is made of three equal */ |
833 | | /* components, so this case is simpler. */ |
834 | 0 | while ((cnt -= 3) >= 0) { |
835 | 0 | register int diff = *pptr - br; |
836 | |
|
837 | 0 | if (diff < 0) |
838 | 0 | diff = -diff; |
839 | 0 | if (diff < best) { /* quick rejection */ |
840 | 0 | which = pptr, best = diff; |
841 | 0 | } |
842 | 0 | if (diff == 0) |
843 | 0 | break; |
844 | 0 | pptr += 3; |
845 | 0 | } |
846 | 0 | } |
847 | 0 | return (gx_color_index) ((which - mdev->palette.data) / 3); |
848 | 0 | } |
849 | | |
850 | | /* Map a color index to a r-g-b color for a mapped color memory device. */ |
851 | | int |
852 | | mem_mapped_map_color_rgb(gx_device * dev, gx_color_index color, |
853 | | gx_color_value prgb[3]) |
854 | 0 | { |
855 | 0 | gx_device_memory * const mdev = (gx_device_memory *)dev; |
856 | 0 | const byte *pptr = mdev->palette.data; |
857 | |
|
858 | 0 | if (pptr == NULL) { |
859 | 0 | color = color * gx_max_color_value / ((1<<mdev->color_info.depth)-1); |
860 | 0 | prgb[0] = color; |
861 | 0 | prgb[1] = color; |
862 | 0 | prgb[2] = color; |
863 | 0 | } else { |
864 | 0 | pptr += (int)color * 3; |
865 | |
|
866 | 0 | prgb[0] = gx_color_value_from_byte(pptr[0]); |
867 | 0 | prgb[1] = gx_color_value_from_byte(pptr[1]); |
868 | 0 | prgb[2] = gx_color_value_from_byte(pptr[2]); |
869 | 0 | } |
870 | 0 | return 0; |
871 | 0 | } |
872 | | |
873 | | /* |
874 | | * Implement draw_thin_line using a distinguished procedure that serves |
875 | | * as the common marker for all memory devices. |
876 | | */ |
877 | | int |
878 | | mem_draw_thin_line(gx_device *dev, fixed fx0, fixed fy0, fixed fx1, fixed fy1, |
879 | | const gx_drawing_color *pdcolor, |
880 | | gs_logical_operation_t lop, |
881 | | fixed adjustx, fixed adjusty) |
882 | 76.4k | { |
883 | 76.4k | return gx_default_draw_thin_line(dev, fx0, fy0, fx1, fy1, pdcolor, lop, |
884 | 76.4k | adjustx, adjusty); |
885 | 76.4k | } |
886 | | |
887 | | void mem_initialize_device_procs(gx_device *dev) |
888 | 2.81M | { |
889 | 2.81M | set_dev_proc(dev, get_initial_matrix, mem_get_initial_matrix); |
890 | 2.81M | set_dev_proc(dev, sync_output, gx_default_sync_output); |
891 | 2.81M | set_dev_proc(dev, output_page, gx_default_output_page); |
892 | 2.81M | set_dev_proc(dev, close_device, mem_close); |
893 | 2.81M | set_dev_proc(dev, get_params, gx_default_get_params); |
894 | 2.81M | set_dev_proc(dev, put_params, gx_default_put_params); |
895 | 2.81M | set_dev_proc(dev, get_page_device, gx_forward_get_page_device); |
896 | 2.81M | set_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits); |
897 | 2.81M | set_dev_proc(dev, fill_path, gx_default_fill_path); |
898 | 2.81M | set_dev_proc(dev, stroke_path, gx_default_stroke_path); |
899 | 2.81M | set_dev_proc(dev, fill_mask, gx_default_fill_mask); |
900 | 2.81M | set_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid); |
901 | 2.81M | set_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram); |
902 | 2.81M | set_dev_proc(dev, fill_triangle, gx_default_fill_triangle); |
903 | 2.81M | set_dev_proc(dev, draw_thin_line, mem_draw_thin_line); |
904 | 2.81M | set_dev_proc(dev, get_clipping_box, gx_default_get_clipping_box); |
905 | 2.81M | set_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image); |
906 | 2.81M | set_dev_proc(dev, composite, gx_default_composite); |
907 | 2.81M | set_dev_proc(dev, get_hardware_params, gx_default_get_hardware_params); |
908 | 2.81M | set_dev_proc(dev, text_begin, gx_default_text_begin); |
909 | 2.81M | set_dev_proc(dev, transform_pixel_region, mem_transform_pixel_region); |
910 | | |
911 | | /* Defaults that may well get overridden. */ |
912 | 2.81M | set_dev_proc(dev, open_device, mem_open); |
913 | 2.81M | set_dev_proc(dev, copy_alpha, gx_default_copy_alpha); |
914 | 2.81M | set_dev_proc(dev, map_cmyk_color, gx_default_map_cmyk_color); |
915 | 2.81M | set_dev_proc(dev, strip_tile_rectangle, gx_default_strip_tile_rectangle); |
916 | 2.81M | set_dev_proc(dev, get_bits_rectangle, mem_get_bits_rectangle); |
917 | 2.81M | } |
918 | | |
919 | | void mem_dev_initialize_device_procs(gx_device *dev) |
920 | 2.81M | { |
921 | 2.81M | int depth = dev->color_info.depth; |
922 | 2.81M | const gdev_mem_functions *fns; |
923 | | |
924 | 2.81M | if (dev->is_planar) |
925 | 0 | depth /= dev->color_info.num_components; |
926 | 2.81M | fns = gdev_mem_functions_for_bits(depth); |
927 | | |
928 | 2.81M | mem_initialize_device_procs(dev); |
929 | | |
930 | 2.81M | set_dev_proc(dev, map_rgb_color, fns->map_rgb_color); |
931 | 2.81M | set_dev_proc(dev, map_color_rgb, fns->map_color_rgb); |
932 | 2.81M | set_dev_proc(dev, fill_rectangle, fns->fill_rectangle); |
933 | 2.81M | set_dev_proc(dev, copy_mono, fns->copy_mono); |
934 | 2.81M | set_dev_proc(dev, copy_color, fns->copy_color); |
935 | 2.81M | set_dev_proc(dev, copy_alpha, fns->copy_alpha); |
936 | 2.81M | set_dev_proc(dev, strip_copy_rop2, fns->strip_copy_rop2); |
937 | 2.81M | set_dev_proc(dev, strip_tile_rectangle, fns->strip_tile_rectangle); |
938 | 2.81M | } |
939 | | |
940 | | void mem_word_dev_initialize_device_procs(gx_device *dev) |
941 | 0 | { |
942 | 0 | const gdev_mem_functions *fns = |
943 | 0 | gdev_mem_word_functions_for_bits(dev->color_info.depth); |
944 | |
|
945 | 0 | mem_initialize_device_procs(dev); |
946 | |
|
947 | 0 | set_dev_proc(dev, map_rgb_color, fns->map_rgb_color); |
948 | 0 | set_dev_proc(dev, map_color_rgb, fns->map_color_rgb); |
949 | 0 | set_dev_proc(dev, fill_rectangle, fns->fill_rectangle); |
950 | 0 | set_dev_proc(dev, copy_mono, fns->copy_mono); |
951 | 0 | set_dev_proc(dev, copy_color, fns->copy_color); |
952 | 0 | set_dev_proc(dev, copy_alpha, fns->copy_alpha); |
953 | 0 | set_dev_proc(dev, strip_copy_rop2, fns->strip_copy_rop2); |
954 | 0 | set_dev_proc(dev, strip_tile_rectangle, fns->strip_tile_rectangle); |
955 | 0 | } |