2 |
- |
1 |
/* Copyright (C) 1989, 1995, 1996, 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: gxifast.c,v 1.9 2003/08/18 21:21:57 dan Exp $ */
|
|
|
18 |
/* Fast monochrome image rendering */
|
|
|
19 |
#include "gx.h"
|
|
|
20 |
#include "memory_.h"
|
|
|
21 |
#include "gpcheck.h"
|
|
|
22 |
#include "gsbittab.h"
|
|
|
23 |
#include "gserrors.h"
|
|
|
24 |
#include "gxfixed.h"
|
|
|
25 |
#include "gxarith.h"
|
|
|
26 |
#include "gxmatrix.h"
|
|
|
27 |
#include "gsccolor.h"
|
|
|
28 |
#include "gspaint.h"
|
|
|
29 |
#include "gsutil.h"
|
|
|
30 |
#include "gxdevice.h"
|
|
|
31 |
#include "gxcmap.h"
|
|
|
32 |
#include "gxdcolor.h"
|
|
|
33 |
#include "gxistate.h"
|
|
|
34 |
#include "gxdevmem.h"
|
|
|
35 |
#include "gdevmem.h" /* for mem_mono_device */
|
|
|
36 |
#include "gxcpath.h"
|
|
|
37 |
#include "gximage.h"
|
|
|
38 |
#include "gzht.h"
|
|
|
39 |
|
|
|
40 |
/* Conditionally include statistics code. */
|
|
|
41 |
#ifdef DEBUG
|
|
|
42 |
# define STATS
|
|
|
43 |
#endif
|
|
|
44 |
|
|
|
45 |
/* ------ Strategy procedure ------ */
|
|
|
46 |
|
|
|
47 |
/* Check the prototype. */
|
|
|
48 |
iclass_proc(gs_image_class_1_simple);
|
|
|
49 |
|
|
|
50 |
/* Use special fast logic for portrait or landscape black-and-white images. */
|
|
|
51 |
private irender_proc(image_render_skip);
|
|
|
52 |
private irender_proc(image_render_simple);
|
|
|
53 |
private irender_proc(image_render_landscape);
|
|
|
54 |
irender_proc_t
|
|
|
55 |
gs_image_class_1_simple(gx_image_enum * penum)
|
|
|
56 |
{
|
|
|
57 |
irender_proc_t rproc;
|
|
|
58 |
fixed ox = dda_current(penum->dda.pixel0.x);
|
|
|
59 |
fixed oy = dda_current(penum->dda.pixel0.y);
|
|
|
60 |
|
|
|
61 |
if (penum->use_rop || penum->spp != 1 || penum->bps != 1)
|
|
|
62 |
return 0;
|
|
|
63 |
switch (penum->posture) {
|
|
|
64 |
case image_portrait:
|
|
|
65 |
{ /* Use fast portrait algorithm. */
|
|
|
66 |
long dev_width =
|
|
|
67 |
fixed2long_pixround(ox + penum->x_extent.x) -
|
|
|
68 |
fixed2long_pixround(ox);
|
|
|
69 |
|
|
|
70 |
if (dev_width != penum->rect.w) {
|
|
|
71 |
/*
|
|
|
72 |
* Add an extra align_bitmap_mod of padding so that
|
|
|
73 |
* we can align scaled rows with the device.
|
|
|
74 |
*/
|
|
|
75 |
long line_size =
|
|
|
76 |
bitmap_raster(any_abs(dev_width)) + align_bitmap_mod;
|
|
|
77 |
|
|
|
78 |
if (penum->adjust != 0 || line_size > max_uint)
|
|
|
79 |
return 0;
|
|
|
80 |
/* Must buffer a scan line. */
|
|
|
81 |
penum->line_width = any_abs(dev_width);
|
|
|
82 |
penum->line_size = (uint) line_size;
|
|
|
83 |
penum->line = gs_alloc_bytes(penum->memory,
|
|
|
84 |
penum->line_size, "image line");
|
|
|
85 |
if (penum->line == 0) {
|
|
|
86 |
gx_default_end_image(penum->dev,
|
|
|
87 |
(gx_image_enum_common_t *)penum,
|
|
|
88 |
false);
|
|
|
89 |
return 0;
|
|
|
90 |
}
|
|
|
91 |
}
|
|
|
92 |
if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n",
|
|
|
93 |
penum->rect.w, dev_width);
|
|
|
94 |
rproc = image_render_simple;
|
|
|
95 |
break;
|
|
|
96 |
}
|
|
|
97 |
case image_landscape:
|
|
|
98 |
{ /* Use fast landscape algorithm. */
|
|
|
99 |
long dev_width =
|
|
|
100 |
fixed2long_pixround(oy + penum->x_extent.y) -
|
|
|
101 |
fixed2long_pixround(oy);
|
|
|
102 |
long line_size =
|
|
|
103 |
(dev_width = any_abs(dev_width),
|
|
|
104 |
bitmap_raster(dev_width) * 8 +
|
|
|
105 |
ROUND_UP(dev_width, 8) * align_bitmap_mod);
|
|
|
106 |
|
|
|
107 |
if ((dev_width != penum->rect.w && penum->adjust != 0) ||
|
|
|
108 |
line_size > max_uint
|
|
|
109 |
)
|
|
|
110 |
return 0;
|
|
|
111 |
/* Must buffer a group of 8N scan lines. */
|
|
|
112 |
penum->line_width = dev_width;
|
|
|
113 |
penum->line_size = (uint) line_size;
|
|
|
114 |
penum->line = gs_alloc_bytes(penum->memory,
|
|
|
115 |
penum->line_size, "image line");
|
|
|
116 |
if (penum->line == 0) {
|
|
|
117 |
gx_default_end_image(penum->dev,
|
|
|
118 |
(gx_image_enum_common_t *) penum,
|
|
|
119 |
false);
|
|
|
120 |
return 0;
|
|
|
121 |
}
|
|
|
122 |
penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox);
|
|
|
123 |
if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n",
|
|
|
124 |
penum->rect.w, dev_width, line_size);
|
|
|
125 |
rproc = image_render_landscape;
|
|
|
126 |
/* Precompute values needed for rasterizing. */
|
|
|
127 |
penum->dxy =
|
|
|
128 |
float2fixed(penum->matrix.xy +
|
|
|
129 |
fixed2float(fixed_epsilon) / 2);
|
|
|
130 |
break;
|
|
|
131 |
}
|
|
|
132 |
default:
|
|
|
133 |
return 0;
|
|
|
134 |
}
|
|
|
135 |
/* Precompute values needed for rasterizing. */
|
|
|
136 |
penum->dxx =
|
|
|
137 |
float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
|
|
|
138 |
/*
|
|
|
139 |
* We don't want to spread the samples, but we have to reset unpack_bps
|
|
|
140 |
* to prevent the buffer pointer from being incremented by 8 bytes per
|
|
|
141 |
* input byte.
|
|
|
142 |
*/
|
|
|
143 |
penum->unpack = sample_unpack_copy;
|
|
|
144 |
penum->unpack_bps = 8;
|
|
|
145 |
if (penum->use_mask_color) {
|
|
|
146 |
/*
|
|
|
147 |
* Set the masked color as 'no_color' to make it transparent
|
|
|
148 |
* according to the mask color range and the decoding.
|
|
|
149 |
*/
|
|
|
150 |
penum->masked = true;
|
|
|
151 |
if (penum->mask_color.values[0] == 1) {
|
|
|
152 |
/* if v0 == 1, 1 is transparent since v1 must be == 1 to be a valid range */
|
|
|
153 |
set_nonclient_dev_color(penum->map[0].inverted ? &penum->icolor0 : &penum->icolor1,
|
|
|
154 |
gx_no_color_index);
|
|
|
155 |
} else if (penum->mask_color.values[1] == 0) {
|
|
|
156 |
/* if v1 == 0, 0 is transparent since v0 must be == 0 to be a valid range */
|
|
|
157 |
set_nonclient_dev_color(penum->map[0].inverted ? &penum->icolor1 : &penum->icolor0,
|
|
|
158 |
gx_no_color_index);
|
|
|
159 |
} else {
|
|
|
160 |
/*
|
|
|
161 |
* The only other possible in-range value is v0 = 0, v1 = 1.
|
|
|
162 |
* The image is completely transparent!
|
|
|
163 |
*/
|
|
|
164 |
rproc = image_render_skip;
|
|
|
165 |
}
|
|
|
166 |
penum->map[0].decoding = sd_none;
|
|
|
167 |
}
|
|
|
168 |
return rproc;
|
|
|
169 |
}
|
|
|
170 |
|
|
|
171 |
/* ------ Rendering procedures ------ */
|
|
|
172 |
|
|
|
173 |
#define DC_IS_NULL(pdc)\
|
|
|
174 |
(gx_dc_is_pure(pdc) && (pdc)->colors.pure == gx_no_color_index)
|
|
|
175 |
|
|
|
176 |
/* Skip over a completely transparent image. */
|
|
|
177 |
private int
|
|
|
178 |
image_render_skip(gx_image_enum * penum, const byte * buffer, int data_x,
|
|
|
179 |
uint w, int h, gx_device * dev)
|
|
|
180 |
{
|
|
|
181 |
return h;
|
|
|
182 |
}
|
|
|
183 |
|
|
|
184 |
/*
|
|
|
185 |
* Scale (and possibly reverse) one scan line of a monobit image.
|
|
|
186 |
* This is used for both portrait and landscape image processing.
|
|
|
187 |
* We pass in an x offset (0 <= line_x < align_bitmap_mod * 8) so that
|
|
|
188 |
* we can align the result with the eventual device X.
|
|
|
189 |
*
|
|
|
190 |
* To be precise, the input to this routine is the w bits starting at
|
|
|
191 |
* bit data_x in buffer. These w bits expand to abs(x_extent) bits,
|
|
|
192 |
* either inverted (zero = 0xff) or not (zero = 0), starting at bit
|
|
|
193 |
* line_x in line which corresponds to coordinate
|
|
|
194 |
* fixed2int_pixround(xcur + min(x_extent, 0)). Note that the entire
|
|
|
195 |
* bytes containing the first and last output bits are affected: the
|
|
|
196 |
* other bits in those bytes are set to zero (i.e., the value of the
|
|
|
197 |
* 'zero' argument).
|
|
|
198 |
*/
|
|
|
199 |
#ifdef STATS
|
|
|
200 |
struct stats_image_fast_s {
|
|
|
201 |
long
|
|
|
202 |
calls, all0s, all1s, runs, lbit0, byte00, byte01, byte02, byte03,
|
|
|
203 |
byte04, rbit0, lbit1, byte1, rbit1, thin, thin2, nwide, bwide,
|
|
|
204 |
nfill, bfill;
|
|
|
205 |
} stats_image_fast;
|
|
|
206 |
# define INCS(stat) ++stats_image_fast.stat
|
|
|
207 |
# define ADDS(stat, n) stats_image_fast.stat += n
|
|
|
208 |
#else
|
|
|
209 |
# define INCS(stat) DO_NOTHING
|
|
|
210 |
# define ADDS(stat, n) DO_NOTHING
|
|
|
211 |
#endif
|
|
|
212 |
inline private void
|
|
|
213 |
fill_row(byte *line, int line_x, uint raster, int value)
|
|
|
214 |
{
|
|
|
215 |
memset(line + (line_x >> 3), value, raster - (line_x >> 3));
|
|
|
216 |
}
|
|
|
217 |
private void
|
|
|
218 |
image_simple_expand(byte * line, int line_x, uint raster,
|
|
|
219 |
const byte * buffer, int data_x, uint w,
|
|
|
220 |
fixed xcur, fixed x_extent, byte zero /* 0 or 0xff */ )
|
|
|
221 |
{
|
|
|
222 |
int dbitx = data_x & 7;
|
|
|
223 |
byte sbit = 0x80 >> dbitx;
|
|
|
224 |
byte sbitmask = 0xff >> dbitx;
|
|
|
225 |
uint wx = dbitx + w;
|
|
|
226 |
gx_dda_fixed xl;
|
|
|
227 |
gx_dda_step_fixed dxx4, dxx8, dxx16, dxx24, dxx32;
|
|
|
228 |
register const byte *psrc = buffer + (data_x >> 3);
|
|
|
229 |
|
|
|
230 |
/*
|
|
|
231 |
* The following 3 variables define the end of the input data row.
|
|
|
232 |
* We would put them in a struct, except that no compiler that we
|
|
|
233 |
* know of will optimize individual struct members as though they
|
|
|
234 |
* were simple variables (e.g., by putting them in registers).
|
|
|
235 |
*
|
|
|
236 |
* endp points to the byte that contains the bit just beyond the
|
|
|
237 |
* end of the row. endx gives the bit number of this bit within
|
|
|
238 |
* the byte, with 0 being the *least* significant bit. endbit is
|
|
|
239 |
* a mask for this bit.
|
|
|
240 |
*/
|
|
|
241 |
const byte *endp = psrc + (wx >> 3);
|
|
|
242 |
int endx = ~wx & 7;
|
|
|
243 |
byte endbit = 1 << endx;
|
|
|
244 |
|
|
|
245 |
/*
|
|
|
246 |
* The following 3 variables do the same for start of the last run
|
|
|
247 |
* of the input row (think of it as a pointer to just beyond the
|
|
|
248 |
* end of the next-to-last run).
|
|
|
249 |
*/
|
|
|
250 |
const byte *stop = endp;
|
|
|
251 |
int stopx;
|
|
|
252 |
byte stopbit = endbit;
|
|
|
253 |
byte data;
|
|
|
254 |
byte one = ~zero;
|
|
|
255 |
fixed xl0;
|
|
|
256 |
|
|
|
257 |
if (w == 0)
|
|
|
258 |
return;
|
|
|
259 |
INCS(calls);
|
|
|
260 |
|
|
|
261 |
/* Scan backward for the last transition. */
|
|
|
262 |
if (stopbit == 0x80)
|
|
|
263 |
--stop, stopbit = 1;
|
|
|
264 |
else
|
|
|
265 |
stopbit <<= 1;
|
|
|
266 |
/* Now (stop, stopbit) give the last bit of the row. */
|
|
|
267 |
{
|
|
|
268 |
byte stopmask = -stopbit << 1;
|
|
|
269 |
byte last = *stop;
|
|
|
270 |
|
|
|
271 |
if (stop == psrc) /* only 1 input byte */
|
|
|
272 |
stopmask &= sbitmask;
|
|
|
273 |
if (last & stopbit) {
|
|
|
274 |
/* The last bit is a 1: look for a 0-to-1 transition. */
|
|
|
275 |
if (~last & stopmask) { /* Transition in last byte. */
|
|
|
276 |
last |= stopbit - 1;
|
|
|
277 |
} else { /* No transition in the last byte. */
|
|
|
278 |
while (stop > psrc && stop[-1] == 0xff)
|
|
|
279 |
--stop;
|
|
|
280 |
if (stop == psrc ||
|
|
|
281 |
(stop == psrc + 1 && !(~*psrc & sbitmask))
|
|
|
282 |
) {
|
|
|
283 |
/* The input is all 1s. Clear the row and exit. */
|
|
|
284 |
INCS(all1s);
|
|
|
285 |
fill_row(line, line_x, raster, one);
|
|
|
286 |
return;
|
|
|
287 |
}
|
|
|
288 |
last = *--stop;
|
|
|
289 |
}
|
|
|
290 |
stopx = byte_bit_run_length_0[byte_reverse_bits[last]] - 1;
|
|
|
291 |
} else {
|
|
|
292 |
/* The last bit is a 0: look for a 1-to-0 transition. */
|
|
|
293 |
if (last & stopmask) { /* Transition in last byte. */
|
|
|
294 |
last &= -stopbit;
|
|
|
295 |
} else { /* No transition in the last byte. */
|
|
|
296 |
while (stop > psrc && stop[-1] == 0)
|
|
|
297 |
--stop;
|
|
|
298 |
if (stop == psrc ||
|
|
|
299 |
(stop == psrc + 1 && !(*psrc & sbitmask))
|
|
|
300 |
) {
|
|
|
301 |
/* The input is all 0s. Clear the row and exit. */
|
|
|
302 |
INCS(all0s);
|
|
|
303 |
fill_row(line, line_x, raster, zero);
|
|
|
304 |
return;
|
|
|
305 |
}
|
|
|
306 |
last = *--stop;
|
|
|
307 |
}
|
|
|
308 |
stopx = byte_bit_run_length_0[byte_reverse_bits[last ^ 0xff]] - 1;
|
|
|
309 |
}
|
|
|
310 |
if (stopx < 0)
|
|
|
311 |
stopx = 7, ++stop;
|
|
|
312 |
stopbit = 1 << stopx;
|
|
|
313 |
}
|
|
|
314 |
|
|
|
315 |
/* Pre-clear the row. */
|
|
|
316 |
fill_row(line, line_x, raster, zero);
|
|
|
317 |
|
|
|
318 |
/* Set up the DDAs. */
|
|
|
319 |
xl0 =
|
|
|
320 |
(x_extent >= 0 ?
|
|
|
321 |
fixed_fraction(fixed_pre_pixround(xcur)) :
|
|
|
322 |
fixed_fraction(fixed_pre_pixround(xcur + x_extent)) - x_extent);
|
|
|
323 |
xl0 += int2fixed(line_x);
|
|
|
324 |
dda_init(xl, xl0, x_extent, w);
|
|
|
325 |
dxx4 = xl.step;
|
|
|
326 |
dda_step_add(dxx4, xl.step);
|
|
|
327 |
/* egcc - 2.91.66 generates incorrect code for
|
|
|
328 |
* dda_step_add(dxx4, dxx4);
|
|
|
329 |
* Using the temp variable.
|
|
|
330 |
*/
|
|
|
331 |
dxx8 = dxx4;
|
|
|
332 |
dda_step_add(dxx4, dxx8);
|
|
|
333 |
dxx8 = dxx4;
|
|
|
334 |
dda_step_add(dxx8, dxx4);
|
|
|
335 |
dxx16 = dxx8;
|
|
|
336 |
dda_step_add(dxx16, dxx8);
|
|
|
337 |
dxx24 = dxx16;
|
|
|
338 |
dda_step_add(dxx24, dxx8);
|
|
|
339 |
dxx32 = dxx24;
|
|
|
340 |
dda_step_add(dxx32, dxx8);
|
|
|
341 |
|
|
|
342 |
/*
|
|
|
343 |
* Loop invariants:
|
|
|
344 |
* data = *psrc;
|
|
|
345 |
* sbit = 1 << n, 0<=n<=7.
|
|
|
346 |
*/
|
|
|
347 |
for (data = *psrc;;) {
|
|
|
348 |
int x0, n, bit;
|
|
|
349 |
byte *bp;
|
|
|
350 |
static const byte lmasks[9] = {
|
|
|
351 |
0xff, 0x7f, 0x3f, 0x1f, 0xf, 7, 3, 1, 0
|
|
|
352 |
};
|
|
|
353 |
static const byte rmasks[9] = {
|
|
|
354 |
0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
|
|
|
355 |
};
|
|
|
356 |
|
|
|
357 |
INCS(runs);
|
|
|
358 |
|
|
|
359 |
/* Scan a run of zeros. */
|
|
|
360 |
data ^= 0xff; /* invert */
|
|
|
361 |
while (data & sbit) {
|
|
|
362 |
dda_next(xl);
|
|
|
363 |
sbit >>= 1;
|
|
|
364 |
INCS(lbit0);
|
|
|
365 |
}
|
|
|
366 |
if (!sbit) { /* Scan a run of zero bytes. */
|
|
|
367 |
sw: if ((data = psrc[1]) != 0) {
|
|
|
368 |
psrc++;
|
|
|
369 |
INCS(byte00);
|
|
|
370 |
} else if ((data = psrc[2]) != 0) {
|
|
|
371 |
dda_state_next(xl.state, dxx8);
|
|
|
372 |
psrc += 2;
|
|
|
373 |
INCS(byte01);
|
|
|
374 |
} else if ((data = psrc[3]) != 0) {
|
|
|
375 |
dda_state_next(xl.state, dxx16);
|
|
|
376 |
psrc += 3;
|
|
|
377 |
INCS(byte02);
|
|
|
378 |
} else if ((data = psrc[4]) != 0) {
|
|
|
379 |
dda_state_next(xl.state, dxx24);
|
|
|
380 |
psrc += 4;
|
|
|
381 |
INCS(byte03);
|
|
|
382 |
} else {
|
|
|
383 |
dda_state_next(xl.state, dxx32);
|
|
|
384 |
psrc += 4;
|
|
|
385 |
INCS(byte04);
|
|
|
386 |
goto sw;
|
|
|
387 |
}
|
|
|
388 |
if (data > 0xf)
|
|
|
389 |
sbit = 0x80;
|
|
|
390 |
else {
|
|
|
391 |
sbit = 0x08;
|
|
|
392 |
dda_state_next(xl.state, dxx4);
|
|
|
393 |
}
|
|
|
394 |
data ^= 0xff; /* invert */
|
|
|
395 |
while (data & sbit) {
|
|
|
396 |
dda_next(xl);
|
|
|
397 |
sbit >>= 1;
|
|
|
398 |
INCS(rbit0);
|
|
|
399 |
}
|
|
|
400 |
}
|
|
|
401 |
x0 = dda_current_fixed2int(xl);
|
|
|
402 |
if (psrc >= stop && sbit == stopbit) {
|
|
|
403 |
/*
|
|
|
404 |
* We've scanned the last run of 0s.
|
|
|
405 |
* Prepare to fill the final run of 1s.
|
|
|
406 |
*/
|
|
|
407 |
n = fixed2int(xl0 + x_extent) - x0;
|
|
|
408 |
} else { /* Scan a run of ones. */
|
|
|
409 |
/* We know the current bit is a one. */
|
|
|
410 |
data ^= 0xff; /* un-invert */
|
|
|
411 |
do {
|
|
|
412 |
dda_next(xl);
|
|
|
413 |
sbit >>= 1;
|
|
|
414 |
INCS(lbit1);
|
|
|
415 |
}
|
|
|
416 |
while (data & sbit);
|
|
|
417 |
if (!sbit) { /* Scan a run of 0xff bytes. */
|
|
|
418 |
while ((data = *++psrc) == 0xff) {
|
|
|
419 |
dda_state_next(xl.state, dxx8);
|
|
|
420 |
INCS(byte1);
|
|
|
421 |
}
|
|
|
422 |
if (data < 0xf0)
|
|
|
423 |
sbit = 0x80;
|
|
|
424 |
else {
|
|
|
425 |
sbit = 0x08;
|
|
|
426 |
dda_state_next(xl.state, dxx4);
|
|
|
427 |
}
|
|
|
428 |
while (data & sbit) {
|
|
|
429 |
dda_next(xl);
|
|
|
430 |
sbit >>= 1;
|
|
|
431 |
INCS(rbit1);
|
|
|
432 |
}
|
|
|
433 |
}
|
|
|
434 |
n = dda_current_fixed2int(xl) - x0;
|
|
|
435 |
}
|
|
|
436 |
|
|
|
437 |
/* Fill the run in the scan line. */
|
|
|
438 |
if (n < 0)
|
|
|
439 |
x0 += n, n = -n;
|
|
|
440 |
bp = line + (x0 >> 3);
|
|
|
441 |
bit = x0 & 7;
|
|
|
442 |
if ((n += bit) <= 8) {
|
|
|
443 |
*bp ^= lmasks[bit] - lmasks[n];
|
|
|
444 |
INCS(thin);
|
|
|
445 |
} else if ((n -= 8) <= 8) {
|
|
|
446 |
*bp ^= lmasks[bit];
|
|
|
447 |
bp[1] ^= rmasks[n];
|
|
|
448 |
INCS(thin2);
|
|
|
449 |
} else {
|
|
|
450 |
*bp++ ^= lmasks[bit];
|
|
|
451 |
if (n >= 56) {
|
|
|
452 |
int nb = n >> 3;
|
|
|
453 |
|
|
|
454 |
memset(bp, one, nb);
|
|
|
455 |
bp += nb;
|
|
|
456 |
INCS(nwide);
|
|
|
457 |
ADDS(bwide, nb);
|
|
|
458 |
} else {
|
|
|
459 |
ADDS(bfill, n >> 3);
|
|
|
460 |
while ((n -= 8) >= 0)
|
|
|
461 |
*bp++ = one;
|
|
|
462 |
INCS(nfill);
|
|
|
463 |
}
|
|
|
464 |
*bp ^= rmasks[n & 7];
|
|
|
465 |
}
|
|
|
466 |
if (psrc >= stop && sbit == stopbit)
|
|
|
467 |
break;
|
|
|
468 |
}
|
|
|
469 |
}
|
|
|
470 |
|
|
|
471 |
/* Copy one rendered scan line to the device. */
|
|
|
472 |
private int
|
|
|
473 |
copy_portrait(gx_image_enum * penum, const byte * data, int dx, int raster,
|
|
|
474 |
int x, int y, int w, int h, gx_device * dev)
|
|
|
475 |
{
|
|
|
476 |
const gx_device_color *pdc0;
|
|
|
477 |
const gx_device_color *pdc1;
|
|
|
478 |
uint align = ALIGNMENT_MOD(data, align_bitmap_mod);
|
|
|
479 |
|
|
|
480 |
/*
|
|
|
481 |
* We know that the lookup table maps 1 bit to 1 bit,
|
|
|
482 |
* so it can only have 2 states: straight-through or invert.
|
|
|
483 |
*/
|
|
|
484 |
if (penum->map[0].table.lookup4x1to32[0])
|
|
|
485 |
pdc0 = &penum->icolor1, pdc1 = &penum->icolor0;
|
|
|
486 |
else
|
|
|
487 |
pdc0 = &penum->icolor0, pdc1 = &penum->icolor1;
|
|
|
488 |
data -= align;
|
|
|
489 |
dx += align << 3;
|
|
|
490 |
if (gx_dc_is_pure(pdc0) && gx_dc_is_pure(pdc1)) {
|
|
|
491 |
/* Just use copy_mono. */
|
|
|
492 |
dev_proc_copy_mono((*copy_mono)) =
|
|
|
493 |
(h == 1 || (raster & (align_bitmap_mod - 1)) == 0 ?
|
|
|
494 |
dev_proc(dev, copy_mono) : gx_copy_mono_unaligned);
|
|
|
495 |
return (*copy_mono)
|
|
|
496 |
(dev, data, dx, raster, gx_no_bitmap_id,
|
|
|
497 |
x, y, w, h, pdc0->colors.pure, pdc1->colors.pure);
|
|
|
498 |
}
|
|
|
499 |
/*
|
|
|
500 |
* At least one color isn't pure: if the other one is transparent, use
|
|
|
501 |
* the opaque color's fill_masked procedure. Note that we use a
|
|
|
502 |
* slightly unusual representation for transparent here (per
|
|
|
503 |
* gx_begin_image1): a pure color with pixel value gx_no_color_index.
|
|
|
504 |
*/
|
|
|
505 |
{
|
|
|
506 |
const gx_device_color *pdc;
|
|
|
507 |
bool invert;
|
|
|
508 |
|
|
|
509 |
if (DC_IS_NULL(pdc1)) {
|
|
|
510 |
pdc = pdc0;
|
|
|
511 |
invert = true;
|
|
|
512 |
} else {
|
|
|
513 |
if (!DC_IS_NULL(pdc0)) {
|
|
|
514 |
int code = gx_device_color_fill_rectangle
|
|
|
515 |
(pdc0, x, y, w, h, dev, lop_default, NULL);
|
|
|
516 |
|
|
|
517 |
if (code < 0)
|
|
|
518 |
return code;
|
|
|
519 |
}
|
|
|
520 |
pdc = pdc1;
|
|
|
521 |
invert = false;
|
|
|
522 |
}
|
|
|
523 |
return (*pdc->type->fill_masked)
|
|
|
524 |
(pdc, data, dx, raster, gx_no_bitmap_id, x, y, w, h,
|
|
|
525 |
dev, lop_default, invert);
|
|
|
526 |
|
|
|
527 |
}
|
|
|
528 |
}
|
|
|
529 |
|
|
|
530 |
/* Rendering procedure for a monobit image with no */
|
|
|
531 |
/* skew or rotation and pure colors. */
|
|
|
532 |
private int
|
|
|
533 |
image_render_simple(gx_image_enum * penum, const byte * buffer, int data_x,
|
|
|
534 |
uint w, int h, gx_device * dev)
|
|
|
535 |
{
|
|
|
536 |
dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
|
|
|
537 |
const fixed dxx = penum->dxx;
|
|
|
538 |
const byte *line;
|
|
|
539 |
uint line_width, line_size;
|
|
|
540 |
int line_x;
|
|
|
541 |
fixed xcur = dda_current(penum->dda.pixel0.x);
|
|
|
542 |
int ix = fixed2int_pixround(xcur);
|
|
|
543 |
int ixr;
|
|
|
544 |
const int iy = penum->yci, ih = penum->hci;
|
|
|
545 |
gx_device_color * const pdc0 = &penum->icolor0;
|
|
|
546 |
gx_device_color * const pdc1 = &penum->icolor1;
|
|
|
547 |
int dy;
|
|
|
548 |
int code;
|
|
|
549 |
|
|
|
550 |
if (h == 0)
|
|
|
551 |
return 0;
|
|
|
552 |
if ((!DC_IS_NULL(pdc0) &&
|
|
|
553 |
(code = gx_color_load(pdc0, penum->pis, dev)) < 0) ||
|
|
|
554 |
(!DC_IS_NULL(pdc1) &&
|
|
|
555 |
(code = gx_color_load(pdc1, penum->pis, dev)) < 0)
|
|
|
556 |
)
|
|
|
557 |
return code;
|
|
|
558 |
if (penum->line == 0) { /* A direct BitBlt is possible. */
|
|
|
559 |
line = buffer;
|
|
|
560 |
line_size = (w + 7) >> 3;
|
|
|
561 |
line_width = w;
|
|
|
562 |
line_x = 0;
|
|
|
563 |
} else if (copy_mono == dev_proc(&mem_mono_device, copy_mono) &&
|
|
|
564 |
dxx > 0 && gx_dc_is_pure(pdc1) && gx_dc_is_pure(pdc0) &&
|
|
|
565 |
/* We know the colors must be (0,1) or (1,0). */
|
|
|
566 |
(pdc0->colors.pure ^ pdc1->colors.pure) == 1 &&
|
|
|
567 |
!penum->clip_image &&
|
|
|
568 |
/*
|
|
|
569 |
* Even if clip_image is false, the clipping rectangle
|
|
|
570 |
* might lie partly outside the device coordinate space
|
|
|
571 |
* if the Margins values are non-zero.
|
|
|
572 |
*/
|
|
|
573 |
ix >= 0 &&
|
|
|
574 |
(ixr = fixed2int_pixround(xcur + penum->x_extent.x) - 1) <
|
|
|
575 |
dev->width &&
|
|
|
576 |
iy >= 0 && iy + ih <= dev->height
|
|
|
577 |
) {
|
|
|
578 |
/* Do the operation directly into the memory device bitmap. */
|
|
|
579 |
int line_ix;
|
|
|
580 |
int ib_left = ix >> 3, ib_right = ixr >> 3;
|
|
|
581 |
byte *scan_line = scan_line_base((gx_device_memory *) dev, iy);
|
|
|
582 |
byte save_left, save_right, mask;
|
|
|
583 |
|
|
|
584 |
line_x = ix & (align_bitmap_mod * 8 - 1);
|
|
|
585 |
line_ix = ix - line_x;
|
|
|
586 |
line_size = (ixr >> 3) + 1 - (line_ix >> 3);
|
|
|
587 |
line_width = ixr + 1 - ix;
|
|
|
588 |
/* We must save and restore any unmodified bits in */
|
|
|
589 |
/* the two edge bytes. */
|
|
|
590 |
save_left = scan_line[ib_left];
|
|
|
591 |
save_right = scan_line[ib_right];
|
|
|
592 |
image_simple_expand(scan_line + (line_ix >> 3), line_x,
|
|
|
593 |
line_size, buffer, data_x, w, xcur,
|
|
|
594 |
penum->x_extent.x,
|
|
|
595 |
(byte)((pdc0->colors.pure == 0) !=
|
|
|
596 |
(penum->map[0].table.lookup4x1to32[0] == 0) ?
|
|
|
597 |
0xff : 0));
|
|
|
598 |
if (ix & 7)
|
|
|
599 |
mask = (byte) (0xff00 >> (ix & 7)),
|
|
|
600 |
scan_line[ib_left] =
|
|
|
601 |
(save_left & mask) + (scan_line[ib_left] & ~mask);
|
|
|
602 |
if ((ixr + 1) & 7)
|
|
|
603 |
mask = (byte) (0xff00 >> ((ixr + 1) & 7)),
|
|
|
604 |
scan_line[ib_right] =
|
|
|
605 |
(scan_line[ib_right] & mask) + (save_right & ~mask);
|
|
|
606 |
if (ih <= 1)
|
|
|
607 |
return 1;
|
|
|
608 |
/****** MAY BE UNALIGNED ******/
|
|
|
609 |
line = scan_line + (line_ix >> 3);
|
|
|
610 |
if (dxx < 0)
|
|
|
611 |
ix -= line_width;
|
|
|
612 |
for (dy = 1; dy < ih; dy++) {
|
|
|
613 |
int code = (*copy_mono)
|
|
|
614 |
(dev, line, line_x, line_size, gx_no_bitmap_id,
|
|
|
615 |
ix, iy + dy, line_width, 1,
|
|
|
616 |
(gx_color_index)0, (gx_color_index)1);
|
|
|
617 |
|
|
|
618 |
if (code < 0)
|
|
|
619 |
return code;
|
|
|
620 |
}
|
|
|
621 |
return 0;
|
|
|
622 |
} else {
|
|
|
623 |
line = penum->line;
|
|
|
624 |
line_size = penum->line_size;
|
|
|
625 |
line_width = penum->line_width;
|
|
|
626 |
line_x = ix & (align_bitmap_mod * 8 - 1);
|
|
|
627 |
image_simple_expand(penum->line, line_x, line_size,
|
|
|
628 |
buffer, data_x, w, xcur,
|
|
|
629 |
penum->x_extent.x, 0);
|
|
|
630 |
}
|
|
|
631 |
|
|
|
632 |
/* Finally, transfer the scan line to the device. */
|
|
|
633 |
if (dxx < 0)
|
|
|
634 |
ix -= line_width;
|
|
|
635 |
for (dy = 0; dy < ih; dy++) {
|
|
|
636 |
int code = copy_portrait(penum, line, line_x, line_size,
|
|
|
637 |
ix, iy + dy, line_width, 1, dev);
|
|
|
638 |
|
|
|
639 |
if (code < 0)
|
|
|
640 |
return code;
|
|
|
641 |
}
|
|
|
642 |
|
|
|
643 |
return 1;
|
|
|
644 |
}
|
|
|
645 |
|
|
|
646 |
/* Rendering procedure for a 90 degree rotated monobit image */
|
|
|
647 |
/* with pure colors. We buffer and then flip 8 scan lines at a time. */
|
|
|
648 |
private int copy_landscape(gx_image_enum *, int, int, bool, gx_device *);
|
|
|
649 |
private int
|
|
|
650 |
image_render_landscape(gx_image_enum * penum, const byte * buffer, int data_x,
|
|
|
651 |
uint w, int h, gx_device * dev)
|
|
|
652 |
{
|
|
|
653 |
byte *line = penum->line;
|
|
|
654 |
uint raster = bitmap_raster(penum->line_width);
|
|
|
655 |
int ix = penum->xci, iw = penum->wci;
|
|
|
656 |
int xinc, xmod;
|
|
|
657 |
byte *row;
|
|
|
658 |
const byte *orig_row = 0;
|
|
|
659 |
bool y_neg = penum->dxy < 0;
|
|
|
660 |
|
|
|
661 |
if (is_fneg(penum->matrix.yx))
|
|
|
662 |
ix += iw, iw = -iw, xinc = -1;
|
|
|
663 |
else
|
|
|
664 |
xinc = 1;
|
|
|
665 |
/*
|
|
|
666 |
* Because of clipping, there may be discontinuous jumps in the values
|
|
|
667 |
* of ix (xci). If this happens, or if we are at the end of the data or
|
|
|
668 |
* a client has requested flushing, flush the flipping buffer.
|
|
|
669 |
*/
|
|
|
670 |
if (ix != penum->xi_next || h == 0) {
|
|
|
671 |
int xi = penum->xi_next;
|
|
|
672 |
int code =
|
|
|
673 |
(xinc > 0 ?
|
|
|
674 |
copy_landscape(penum, penum->line_xy, xi, y_neg, dev) :
|
|
|
675 |
copy_landscape(penum, xi, penum->line_xy, y_neg, dev));
|
|
|
676 |
|
|
|
677 |
if (code < 0)
|
|
|
678 |
return code;
|
|
|
679 |
penum->line_xy = penum->xi_next = ix;
|
|
|
680 |
if (h == 0)
|
|
|
681 |
return code;
|
|
|
682 |
}
|
|
|
683 |
for (; iw != 0; iw -= xinc) {
|
|
|
684 |
if (xinc < 0)
|
|
|
685 |
--ix;
|
|
|
686 |
xmod = ix & 7;
|
|
|
687 |
row = line + xmod * raster;
|
|
|
688 |
if (orig_row == 0) {
|
|
|
689 |
image_simple_expand(row, 0, raster,
|
|
|
690 |
buffer, data_x, w,
|
|
|
691 |
dda_current(penum->dda.pixel0.y),
|
|
|
692 |
penum->x_extent.y, 0);
|
|
|
693 |
orig_row = row;
|
|
|
694 |
} else
|
|
|
695 |
memcpy(row, orig_row, raster);
|
|
|
696 |
if (xinc > 0) {
|
|
|
697 |
++ix;
|
|
|
698 |
if (xmod == 7) {
|
|
|
699 |
int code =
|
|
|
700 |
copy_landscape(penum, penum->line_xy, ix, y_neg, dev);
|
|
|
701 |
|
|
|
702 |
if (code < 0)
|
|
|
703 |
return code;
|
|
|
704 |
orig_row = 0;
|
|
|
705 |
penum->line_xy = ix;
|
|
|
706 |
}
|
|
|
707 |
} else {
|
|
|
708 |
if (xmod == 0) {
|
|
|
709 |
int code =
|
|
|
710 |
copy_landscape(penum, ix, penum->line_xy, y_neg, dev);
|
|
|
711 |
|
|
|
712 |
if (code < 0)
|
|
|
713 |
return code;
|
|
|
714 |
orig_row = 0;
|
|
|
715 |
penum->line_xy = ix;
|
|
|
716 |
}
|
|
|
717 |
}
|
|
|
718 |
}
|
|
|
719 |
penum->xi_next = ix;
|
|
|
720 |
return 0;
|
|
|
721 |
}
|
|
|
722 |
|
|
|
723 |
/* Flip and copy one group of scan lines. */
|
|
|
724 |
private int
|
|
|
725 |
copy_landscape(gx_image_enum * penum, int x0, int x1, bool y_neg,
|
|
|
726 |
gx_device * dev)
|
|
|
727 |
{
|
|
|
728 |
byte *line = penum->line;
|
|
|
729 |
uint line_width = penum->line_width;
|
|
|
730 |
uint raster = bitmap_raster(line_width);
|
|
|
731 |
byte *flipped = line + raster * 8;
|
|
|
732 |
int w = x1 - x0;
|
|
|
733 |
int y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
|
|
|
734 |
|
|
|
735 |
if (w == 0 || line_width == 0)
|
|
|
736 |
return 0;
|
|
|
737 |
/* Flip the buffered data from raster x 8 to align_bitmap_mod x */
|
|
|
738 |
/* line_width. */
|
|
|
739 |
if (line_width > 0) {
|
|
|
740 |
int i;
|
|
|
741 |
|
|
|
742 |
for (i = (line_width - 1) >> 3; i >= 0; --i)
|
|
|
743 |
memflip8x8(line + i, raster,
|
|
|
744 |
flipped + (i << (log2_align_bitmap_mod + 3)),
|
|
|
745 |
align_bitmap_mod);
|
|
|
746 |
}
|
|
|
747 |
/* Transfer the scan lines to the device. */
|
|
|
748 |
if (w < 0)
|
|
|
749 |
x0 = x1, w = -w;
|
|
|
750 |
if (y_neg)
|
|
|
751 |
y -= line_width;
|
|
|
752 |
return copy_portrait(penum, flipped, x0 & 7, align_bitmap_mod,
|
|
|
753 |
x0, y, w, line_width, dev);
|
|
|
754 |
}
|