1 /* Copyright (C) 1989, 1995, 1997, 1998, 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: gdevmem.c,v 1.9 2005/03/14 18:08:36 dan Exp $ */
18 /* Generic "memory" (stored bitmap) device */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsrect.h"
23 #include "gsstruct.h"
24 #include "gxarith.h"
25 #include "gxdevice.h"
26 #include "gxgetbit.h"
27 #include "gxdevmem.h" /* semi-public definitions */
28 #include "gdevmem.h" /* private definitions */
29 #include "gstrans.h"
30
31 /* Structure descriptor */
32 public_st_device_memory();
33
34 /* GC procedures */
35 private
ENUM_PTRS_WITH(device_memory_enum_ptrs,gx_device_memory * mptr)36 ENUM_PTRS_WITH(device_memory_enum_ptrs, gx_device_memory *mptr)
37 {
38 return ENUM_USING(st_device_forward, vptr, sizeof(gx_device_forward), index - 3);
39 }
40 case 0: ENUM_RETURN((mptr->foreign_bits ? NULL : (void *)mptr->base));
41 case 1: ENUM_RETURN((mptr->foreign_line_pointers ? NULL : (void *)mptr->line_ptrs));
42 ENUM_STRING_PTR(2, gx_device_memory, palette);
43 ENUM_PTRS_END
44 private
RELOC_PTRS_WITH(device_memory_reloc_ptrs,gx_device_memory * mptr)45 RELOC_PTRS_WITH(device_memory_reloc_ptrs, gx_device_memory *mptr)
46 {
47 if (!mptr->foreign_bits) {
48 byte *base_old = mptr->base;
49 long reloc;
50 int y;
51
52 RELOC_PTR(gx_device_memory, base);
53 reloc = base_old - mptr->base;
54 for (y = 0; y < mptr->height; y++)
55 mptr->line_ptrs[y] -= reloc;
56 /* Relocate line_ptrs, which also points into the data area. */
57 mptr->line_ptrs = (byte **) ((byte *) mptr->line_ptrs - reloc);
58 } else if (!mptr->foreign_line_pointers) {
59 RELOC_PTR(gx_device_memory, line_ptrs);
60 }
61 RELOC_CONST_STRING_PTR(gx_device_memory, palette);
62 RELOC_USING(st_device_forward, vptr, sizeof(gx_device_forward));
63 }
64 RELOC_PTRS_END
65
66 /* Define the palettes for monobit devices. */
67 private const byte b_w_palette_string[6] = {
68 0xff, 0xff, 0xff, 0, 0, 0
69 };
70 const gs_const_string mem_mono_b_w_palette = {
71 b_w_palette_string, 6
72 };
73 private const byte w_b_palette_string[6] = {
74 0, 0, 0, 0xff, 0xff, 0xff
75 };
76 const gs_const_string mem_mono_w_b_palette = {
77 w_b_palette_string, 6
78 };
79
80 /* ------ Generic code ------ */
81
82 /* Return the appropriate memory device for a given */
83 /* number of bits per pixel (0 if none suitable). */
84 private const gx_device_memory *const mem_devices[65] = {
85 0, &mem_mono_device, &mem_mapped2_device, 0, &mem_mapped4_device,
86 0, 0, 0, &mem_mapped8_device,
87 0, 0, 0, 0, 0, 0, 0, &mem_true16_device,
88 0, 0, 0, 0, 0, 0, 0, &mem_true24_device,
89 0, 0, 0, 0, 0, 0, 0, &mem_true32_device,
90 0, 0, 0, 0, 0, 0, 0, &mem_true40_device,
91 0, 0, 0, 0, 0, 0, 0, &mem_true48_device,
92 0, 0, 0, 0, 0, 0, 0, &mem_true56_device,
93 0, 0, 0, 0, 0, 0, 0, &mem_true64_device
94 };
95 const gx_device_memory *
gdev_mem_device_for_bits(int bits_per_pixel)96 gdev_mem_device_for_bits(int bits_per_pixel)
97 {
98 return ((uint)bits_per_pixel > 64 ? (const gx_device_memory *)0 :
99 mem_devices[bits_per_pixel]);
100 }
101 /* Do the same for a word-oriented device. */
102 private const gx_device_memory *const mem_word_devices[65] = {
103 0, &mem_mono_device, &mem_mapped2_word_device, 0, &mem_mapped4_word_device,
104 0, 0, 0, &mem_mapped8_word_device,
105 0, 0, 0, 0, 0, 0, 0, 0 /*no 16-bit word device*/,
106 0, 0, 0, 0, 0, 0, 0, &mem_true24_word_device,
107 0, 0, 0, 0, 0, 0, 0, &mem_true32_word_device,
108 0, 0, 0, 0, 0, 0, 0, &mem_true40_word_device,
109 0, 0, 0, 0, 0, 0, 0, &mem_true48_word_device,
110 0, 0, 0, 0, 0, 0, 0, &mem_true56_word_device,
111 0, 0, 0, 0, 0, 0, 0, &mem_true64_word_device
112 };
113 const gx_device_memory *
gdev_mem_word_device_for_bits(int bits_per_pixel)114 gdev_mem_word_device_for_bits(int bits_per_pixel)
115 {
116 return ((uint)bits_per_pixel > 64 ? (const gx_device_memory *)0 :
117 mem_word_devices[bits_per_pixel]);
118 }
119
120 /* Test whether a device is a memory device */
121 bool
gs_device_is_memory(const gx_device * dev)122 gs_device_is_memory(const gx_device * dev)
123 {
124 /*
125 * We use the draw_thin_line procedure to mark memory devices.
126 * See gdevmem.h.
127 */
128 int bits_per_pixel = dev->color_info.depth;
129 const gx_device_memory *mdproto;
130
131 if ((uint)bits_per_pixel > 64)
132 return false;
133 mdproto = mem_devices[bits_per_pixel];
134 if (mdproto != 0 && dev_proc(dev, draw_thin_line) == dev_proc(mdproto, draw_thin_line))
135 return true;
136 mdproto = mem_word_devices[bits_per_pixel];
137 return (mdproto != 0 && dev_proc(dev, draw_thin_line) == dev_proc(mdproto, draw_thin_line));
138 }
139
140 /* Make a memory device. */
141 /* Note that the default for monobit devices is white = 0, black = 1. */
142 void
gs_make_mem_device(gx_device_memory * dev,const gx_device_memory * mdproto,gs_memory_t * mem,int page_device,gx_device * target)143 gs_make_mem_device(gx_device_memory * dev, const gx_device_memory * mdproto,
144 gs_memory_t * mem, int page_device, gx_device * target)
145 {
146 gx_device_init((gx_device *) dev, (const gx_device *)mdproto,
147 mem, true);
148 dev->stype = &st_device_memory;
149 switch (page_device) {
150 case -1:
151 set_dev_proc(dev, get_page_device, gx_default_get_page_device);
152 break;
153 case 1:
154 set_dev_proc(dev, get_page_device, gx_page_device_get_page_device);
155 break;
156 }
157 /* Preload the black and white cache. */
158 if (target == 0) {
159 if (dev->color_info.depth == 1) {
160 /* The default for black-and-white devices is inverted. */
161 dev->cached_colors.black = 1;
162 dev->cached_colors.white = 0;
163 } else {
164 dev->cached_colors.black = 0;
165 dev->cached_colors.white = (1 << dev->color_info.depth) - 1;
166 }
167 } else {
168 gx_device_set_target((gx_device_forward *)dev, target);
169 /* Forward the color mapping operations to the target. */
170 gx_device_forward_color_procs((gx_device_forward *) dev);
171 gx_device_copy_color_procs((gx_device *)dev, target);
172 dev->cached_colors = target->cached_colors;
173 }
174 if (dev->color_info.depth == 1) {
175 gdev_mem_mono_set_inverted(dev,
176 (target == 0 ||
177 dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE));
178 }
179 check_device_separable((gx_device *)dev);
180 gx_device_fill_in_procs((gx_device *)dev);
181 }
182 /* Make a monobit memory device. This is never a page device. */
183 /* Note that white=0, black=1. */
184 void
gs_make_mem_mono_device(gx_device_memory * dev,gs_memory_t * mem,gx_device * target)185 gs_make_mem_mono_device(gx_device_memory * dev, gs_memory_t * mem,
186 gx_device * target)
187 {
188 gx_device_init((gx_device *)dev, (const gx_device *)&mem_mono_device,
189 mem, true);
190 set_dev_proc(dev, get_page_device, gx_default_get_page_device);
191 gx_device_set_target((gx_device_forward *)dev, target);
192 gdev_mem_mono_set_inverted(dev, true);
193 check_device_separable((gx_device *)dev);
194 gx_device_fill_in_procs((gx_device *)dev);
195 }
196
197 /* Define whether a monobit memory device is inverted (black=1). */
198 void
gdev_mem_mono_set_inverted(gx_device_memory * dev,bool black_is_1)199 gdev_mem_mono_set_inverted(gx_device_memory * dev, bool black_is_1)
200 {
201 if (black_is_1)
202 dev->palette = mem_mono_b_w_palette;
203 else
204 dev->palette = mem_mono_w_b_palette;
205 }
206
207 /*
208 * Compute the size of the bitmap storage, including the space for the scan
209 * line pointer table. Note that scan lines are padded to a multiple of
210 * align_bitmap_mod bytes, and additional padding may be needed if the
211 * pointer table must be aligned to an even larger modulus.
212 *
213 * The computation for planar devices is a little messier. Each plane
214 * must pad its scan lines, and then we must pad again for the pointer
215 * tables (one table per plane).
216 */
217 ulong
gdev_mem_bits_size(const gx_device_memory * dev,int width,int height)218 gdev_mem_bits_size(const gx_device_memory * dev, int width, int height)
219 {
220 int num_planes = dev->num_planes;
221 gx_render_plane_t plane1;
222 const gx_render_plane_t *planes;
223 ulong size;
224 int pi;
225
226 if (num_planes)
227 planes = dev->planes;
228 else
229 planes = &plane1, plane1.depth = dev->color_info.depth, num_planes = 1;
230 for (size = 0, pi = 0; pi < num_planes; ++pi)
231 size += bitmap_raster(width * planes[pi].depth);
232 return ROUND_UP(size * height, ARCH_ALIGN_PTR_MOD);
233 }
234 ulong
gdev_mem_line_ptrs_size(const gx_device_memory * dev,int width,int height)235 gdev_mem_line_ptrs_size(const gx_device_memory * dev, int width, int height)
236 {
237 return (ulong)height * sizeof(byte *) * max(dev->num_planes, 1);
238 }
239 ulong
gdev_mem_data_size(const gx_device_memory * dev,int width,int height)240 gdev_mem_data_size(const gx_device_memory * dev, int width, int height)
241 {
242 return gdev_mem_bits_size(dev, width, height) +
243 gdev_mem_line_ptrs_size(dev, width, height);
244 }
245 /*
246 * Do the inverse computation: given a width (in pixels) and a buffer size,
247 * compute the maximum height.
248 */
249 int
gdev_mem_max_height(const gx_device_memory * dev,int width,ulong size,bool page_uses_transparency)250 gdev_mem_max_height(const gx_device_memory * dev, int width, ulong size,
251 bool page_uses_transparency)
252 {
253 int height;
254 ulong max_height;
255
256 if (page_uses_transparency) {
257 /*
258 * If the device is using PDF 1.4 transparency then we will need to
259 * also allocate image buffers for doing the blending operations.
260 * We can only estimate the space requirements. However since it
261 * is only an estimate, we may exceed our desired buffer space while
262 * processing the file.
263 */
264 max_height = size / (bitmap_raster(width
265 * dev->color_info.depth + ESTIMATED_PDF14_ROW_SPACE(width))
266 + sizeof(byte *) * max(dev->num_planes, 1));
267 height = (int)min(max_height, max_int);
268 } else {
269 /* For non PDF 1.4 transparency, we can do an exact calculation */
270 max_height = size /
271 (bitmap_raster(width * dev->color_info.depth) +
272 sizeof(byte *) * max(dev->num_planes, 1));
273 height = (int)min(max_height, max_int);
274 /*
275 * Because of alignment rounding, the just-computed height might
276 * be too large by a small amount. Adjust it the easy way.
277 */
278 while (gdev_mem_data_size(dev, width, height) > size)
279 --height;
280 }
281 return height;
282 }
283
284 /* Open a memory device, allocating the data area if appropriate, */
285 /* and create the scan line table. */
286 int
mem_open(gx_device * dev)287 mem_open(gx_device * dev)
288 {
289 gx_device_memory *const mdev = (gx_device_memory *)dev;
290
291 /* Check that we aren't trying to open a planar device as chunky. */
292 if (mdev->num_planes)
293 return_error(gs_error_rangecheck);
294 return gdev_mem_open_scan_lines(mdev, dev->height);
295 }
296 int
gdev_mem_open_scan_lines(gx_device_memory * mdev,int setup_height)297 gdev_mem_open_scan_lines(gx_device_memory *mdev, int setup_height)
298 {
299 bool line_pointers_adjacent = true;
300
301 if (setup_height < 0 || setup_height > mdev->height)
302 return_error(gs_error_rangecheck);
303 if (mdev->bitmap_memory != 0) {
304 /* Allocate the data now. */
305 ulong size = gdev_mem_bitmap_size(mdev);
306
307 if ((uint) size != size)
308 return_error(gs_error_limitcheck);
309 mdev->base = gs_alloc_bytes(mdev->bitmap_memory, (uint)size,
310 "mem_open");
311 if (mdev->base == 0)
312 return_error(gs_error_VMerror);
313 mdev->foreign_bits = false;
314 } else if (mdev->line_pointer_memory != 0) {
315 /* Allocate the line pointers now. */
316
317 mdev->line_ptrs = (byte **)
318 gs_alloc_byte_array(mdev->line_pointer_memory, mdev->height,
319 sizeof(byte *) * max(mdev->num_planes, 1),
320 "gdev_mem_open_scan_lines");
321 if (mdev->line_ptrs == 0)
322 return_error(gs_error_VMerror);
323 mdev->foreign_line_pointers = false;
324 line_pointers_adjacent = false;
325 }
326 if (line_pointers_adjacent)
327 mdev->line_ptrs = (byte **)
328 (mdev->base + gdev_mem_bits_size(mdev, mdev->width, mdev->height));
329 mdev->raster = gdev_mem_raster(mdev);
330 return gdev_mem_set_line_ptrs(mdev, NULL, 0, NULL, setup_height);
331 }
332 /*
333 * Set up the scan line pointers of a memory device.
334 * See gxdevmem.h for the detailed specification.
335 * Sets or uses line_ptrs, base, raster; uses width, color_info.depth,
336 * num_planes, plane_depths, plane_depth.
337 */
338 int
gdev_mem_set_line_ptrs(gx_device_memory * mdev,byte * base,int raster,byte ** line_ptrs,int setup_height)339 gdev_mem_set_line_ptrs(gx_device_memory * mdev, byte * base, int raster,
340 byte **line_ptrs, int setup_height)
341 {
342 int num_planes = mdev->num_planes;
343 gx_render_plane_t plane1;
344 const gx_render_plane_t *planes;
345 byte **pline =
346 (line_ptrs ? (mdev->line_ptrs = line_ptrs) : mdev->line_ptrs);
347 byte *data =
348 (base ? (mdev->raster = raster, mdev->base = base) :
349 (raster = mdev->raster, mdev->base));
350 int pi;
351
352 if (num_planes) {
353 if (base && !mdev->plane_depth)
354 return_error(gs_error_rangecheck);
355 planes = mdev->planes;
356 } else {
357 planes = &plane1;
358 plane1.depth = mdev->color_info.depth;
359 num_planes = 1;
360 }
361
362 for (pi = 0; pi < num_planes; ++pi) {
363 int raster = bitmap_raster(mdev->width * planes[pi].depth);
364 byte **pptr = pline;
365 byte **pend = pptr + setup_height;
366 byte *scan_line = data;
367
368 while (pptr < pend) {
369 *pptr++ = scan_line;
370 scan_line += raster;
371 }
372 data += raster * mdev->height;
373 pline += setup_height; /* not mdev->height, see gxdevmem.h */
374 }
375
376 return 0;
377 }
378
379 /* Return the initial transformation matrix */
380 void
mem_get_initial_matrix(gx_device * dev,gs_matrix * pmat)381 mem_get_initial_matrix(gx_device * dev, gs_matrix * pmat)
382 {
383 gx_device_memory * const mdev = (gx_device_memory *)dev;
384
385 pmat->xx = mdev->initial_matrix.xx;
386 pmat->xy = mdev->initial_matrix.xy;
387 pmat->yx = mdev->initial_matrix.yx;
388 pmat->yy = mdev->initial_matrix.yy;
389 pmat->tx = mdev->initial_matrix.tx;
390 pmat->ty = mdev->initial_matrix.ty;
391 }
392
393 /* Close a memory device, freeing the data area if appropriate. */
394 int
mem_close(gx_device * dev)395 mem_close(gx_device * dev)
396 {
397 gx_device_memory * const mdev = (gx_device_memory *)dev;
398
399 if (mdev->bitmap_memory != 0) {
400 gs_free_object(mdev->bitmap_memory, mdev->base, "mem_close");
401 /*
402 * The following assignment is strictly for the benefit of one
403 * client that is sloppy about using is_open properly.
404 */
405 mdev->base = 0;
406 } else if (mdev->line_pointer_memory != 0) {
407 gs_free_object(mdev->line_pointer_memory, mdev->line_ptrs,
408 "mem_close");
409 mdev->line_ptrs = 0; /* ibid. */
410 }
411 return 0;
412 }
413
414 /* Copy bits to a client. */
415 #undef chunk
416 #define chunk byte
417 int
mem_get_bits_rectangle(gx_device * dev,const gs_int_rect * prect,gs_get_bits_params_t * params,gs_int_rect ** unread)418 mem_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
419 gs_get_bits_params_t * params, gs_int_rect ** unread)
420 {
421 gx_device_memory * const mdev = (gx_device_memory *)dev;
422 gs_get_bits_options_t options = params->options;
423 int x = prect->p.x, w = prect->q.x - x, y = prect->p.y, h = prect->q.y - y;
424
425 if (options == 0) {
426 params->options =
427 (GB_ALIGN_STANDARD | GB_ALIGN_ANY) |
428 (GB_RETURN_COPY | GB_RETURN_POINTER) |
429 (GB_OFFSET_0 | GB_OFFSET_SPECIFIED | GB_OFFSET_ANY) |
430 (GB_RASTER_STANDARD | GB_RASTER_SPECIFIED | GB_RASTER_ANY) |
431 GB_PACKING_CHUNKY | GB_COLORS_NATIVE | GB_ALPHA_NONE;
432 return_error(gs_error_rangecheck);
433 }
434 if ((w <= 0) | (h <= 0)) {
435 if ((w | h) < 0)
436 return_error(gs_error_rangecheck);
437 return 0;
438 }
439 if (x < 0 || w > dev->width - x ||
440 y < 0 || h > dev->height - y
441 )
442 return_error(gs_error_rangecheck);
443 {
444 gs_get_bits_params_t copy_params;
445 byte *base = scan_line_base(mdev, y);
446 int code;
447
448 copy_params.options =
449 GB_COLORS_NATIVE | GB_PACKING_CHUNKY | GB_ALPHA_NONE |
450 (mdev->raster ==
451 bitmap_raster(mdev->width * mdev->color_info.depth) ?
452 GB_RASTER_STANDARD : GB_RASTER_SPECIFIED);
453 copy_params.raster = mdev->raster;
454 code = gx_get_bits_return_pointer(dev, x, h, params,
455 ©_params, base);
456 if (code >= 0)
457 return code;
458 return gx_get_bits_copy(dev, x, w, h, params, ©_params, base,
459 gx_device_raster(dev, true));
460 }
461 }
462
463 #if !arch_is_big_endian
464
465 /*
466 * Swap byte order in a rectangular subset of a bitmap. If store = true,
467 * assume the rectangle will be overwritten, so don't swap any bytes where
468 * it doesn't matter. The caller has already done a fit_fill or fit_copy.
469 * Note that the coordinates are specified in bits, not in terms of the
470 * actual device depth.
471 */
472 void
mem_swap_byte_rect(byte * base,uint raster,int x,int w,int h,bool store)473 mem_swap_byte_rect(byte * base, uint raster, int x, int w, int h, bool store)
474 {
475 int xbit = x & 31;
476
477 if (store) {
478 if (xbit + w > 64) { /* Operation spans multiple words. */
479 /* Just swap the words at the left and right edges. */
480 if (xbit != 0)
481 mem_swap_byte_rect(base, raster, x, 1, h, false);
482 x += w - 1;
483 xbit = x & 31;
484 if (xbit == 31)
485 return;
486 w = 1;
487 }
488 }
489 /* Swap the entire rectangle (or what's left of it). */
490 {
491 byte *row = base + ((x >> 5) << 2);
492 int nw = (xbit + w + 31) >> 5;
493 int ny;
494
495 for (ny = h; ny > 0; row += raster, --ny) {
496 int nx = nw;
497 bits32 *pw = (bits32 *) row;
498
499 do {
500 bits32 w = *pw;
501
502 *pw++ = (w >> 24) + ((w >> 8) & 0xff00) +
503 ((w & 0xff00) << 8) + (w << 24);
504 }
505 while (--nx);
506 }
507 }
508 }
509
510 /* Copy a word-oriented rectangle to the client, swapping bytes as needed. */
511 int
mem_word_get_bits_rectangle(gx_device * dev,const gs_int_rect * prect,gs_get_bits_params_t * params,gs_int_rect ** unread)512 mem_word_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
513 gs_get_bits_params_t * params, gs_int_rect ** unread)
514 {
515 gx_device_memory * const mdev = (gx_device_memory *)dev;
516 byte *src;
517 uint dev_raster = gx_device_raster(dev, 1);
518 int x = prect->p.x;
519 int w = prect->q.x - x;
520 int y = prect->p.y;
521 int h = prect->q.y - y;
522 int bit_x, bit_w;
523 int code;
524
525 fit_fill_xywh(dev, x, y, w, h);
526 if (w <= 0 || h <= 0) {
527 /*
528 * It's easiest to just keep going with an empty rectangle.
529 * We pass the original rectangle to mem_get_bits_rectangle,
530 * so unread will be filled in correctly.
531 */
532 x = y = w = h = 0;
533 }
534 bit_x = x * dev->color_info.depth;
535 bit_w = w * dev->color_info.depth;
536 src = scan_line_base(mdev, y);
537 mem_swap_byte_rect(src, dev_raster, bit_x, bit_w, h, false);
538 code = mem_get_bits_rectangle(dev, prect, params, unread);
539 mem_swap_byte_rect(src, dev_raster, bit_x, bit_w, h, false);
540 return code;
541 }
542
543 #endif /* !arch_is_big_endian */
544
545 /* Map a r-g-b color to a color index for a mapped color memory device */
546 /* (2, 4, or 8 bits per pixel.) */
547 /* This requires searching the palette. */
548 gx_color_index
mem_mapped_map_rgb_color(gx_device * dev,const gx_color_value cv[])549 mem_mapped_map_rgb_color(gx_device * dev, const gx_color_value cv[])
550 {
551 gx_device_memory * const mdev = (gx_device_memory *)dev;
552 byte br = gx_color_value_to_byte(cv[0]);
553
554 register const byte *pptr = mdev->palette.data;
555 int cnt = mdev->palette.size;
556 const byte *which = 0; /* initialized only to pacify gcc */
557 int best = 256 * 3;
558
559 if (mdev->color_info.num_components != 1) {
560 /* not 1 component, assume three */
561 /* The comparison is rather simplistic, treating differences in */
562 /* all components as equal. Better choices would be 'distance' */
563 /* in HLS space or other, but these would be much slower. */
564 /* At least exact matches will be found. */
565 byte bg = gx_color_value_to_byte(cv[1]);
566 byte bb = gx_color_value_to_byte(cv[2]);
567
568 while ((cnt -= 3) >= 0) {
569 register int diff = *pptr - br;
570
571 if (diff < 0)
572 diff = -diff;
573 if (diff < best) { /* quick rejection */
574 int dg = pptr[1] - bg;
575
576 if (dg < 0)
577 dg = -dg;
578 if ((diff += dg) < best) { /* quick rejection */
579 int db = pptr[2] - bb;
580
581 if (db < 0)
582 db = -db;
583 if ((diff += db) < best)
584 which = pptr, best = diff;
585 }
586 }
587 if (diff == 0) /* can't get any better than 0 diff */
588 break;
589 pptr += 3;
590 }
591 } else {
592 /* Gray scale conversion. The palette is made of three equal */
593 /* components, so this case is simpler. */
594 while ((cnt -= 3) >= 0) {
595 register int diff = *pptr - br;
596
597 if (diff < 0)
598 diff = -diff;
599 if (diff < best) { /* quick rejection */
600 which = pptr, best = diff;
601 }
602 if (diff == 0)
603 break;
604 pptr += 3;
605 }
606 }
607 return (gx_color_index) ((which - mdev->palette.data) / 3);
608 }
609
610 /* Map a color index to a r-g-b color for a mapped color memory device. */
611 int
mem_mapped_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])612 mem_mapped_map_color_rgb(gx_device * dev, gx_color_index color,
613 gx_color_value prgb[3])
614 {
615 gx_device_memory * const mdev = (gx_device_memory *)dev;
616 const byte *pptr = mdev->palette.data + (int)color * 3;
617
618 prgb[0] = gx_color_value_from_byte(pptr[0]);
619 prgb[1] = gx_color_value_from_byte(pptr[1]);
620 prgb[2] = gx_color_value_from_byte(pptr[2]);
621 return 0;
622 }
623
624 /*
625 * Implement draw_thin_line using a distinguished procedure that serves
626 * as the common marker for all memory devices.
627 */
628 int
mem_draw_thin_line(gx_device * dev,fixed fx0,fixed fy0,fixed fx1,fixed fy1,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)629 mem_draw_thin_line(gx_device *dev, fixed fx0, fixed fy0, fixed fx1, fixed fy1,
630 const gx_drawing_color *pdcolor,
631 gs_logical_operation_t lop)
632 {
633 return gx_default_draw_thin_line(dev, fx0, fy0, fx1, fy1, pdcolor, lop);
634 }
635