1 #include "mupdf/fitz.h"
2 
3 #include "color-imp.h"
4 
5 #include <assert.h>
6 #include <limits.h>
7 #include <string.h>
8 #include <math.h>
9 
10 fz_pixmap *
fz_keep_pixmap(fz_context * ctx,fz_pixmap * pix)11 fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix)
12 {
13 	return fz_keep_storable(ctx, &pix->storable);
14 }
15 
16 void
fz_drop_pixmap(fz_context * ctx,fz_pixmap * pix)17 fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix)
18 {
19 	fz_drop_storable(ctx, &pix->storable);
20 }
21 
22 void
fz_drop_pixmap_imp(fz_context * ctx,fz_storable * pix_)23 fz_drop_pixmap_imp(fz_context *ctx, fz_storable *pix_)
24 {
25 	fz_pixmap *pix = (fz_pixmap *)pix_;
26 
27 	fz_drop_colorspace(ctx, pix->colorspace);
28 	fz_drop_separations(ctx, pix->seps);
29 	if (pix->flags & FZ_PIXMAP_FLAG_FREE_SAMPLES)
30 		fz_free(ctx, pix->samples);
31 	fz_drop_pixmap(ctx, pix->underlying);
32 	fz_free(ctx, pix);
33 }
34 
35 fz_pixmap *
fz_new_pixmap_with_data(fz_context * ctx,fz_colorspace * colorspace,int w,int h,fz_separations * seps,int alpha,int stride,unsigned char * samples)36 fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha, int stride, unsigned char *samples)
37 {
38 	fz_pixmap *pix;
39 	int s = fz_count_active_separations(ctx, seps);
40 	int n;
41 
42 	if (w < 0 || h < 0)
43 		fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal dimensions for pixmap %d %d", w, h);
44 
45 	n = alpha + s + fz_colorspace_n(ctx, colorspace);
46 	if (stride < n*w && stride > -n*w)
47 		fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal stride for pixmap (n=%d w=%d, stride=%d)", n, w, stride);
48 	if (samples == NULL && stride < n*w)
49 		fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal -ve stride for pixmap without data");
50 	if (n > FZ_MAX_COLORS)
51 		fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal number of colorants");
52 
53 	pix = fz_malloc_struct(ctx, fz_pixmap);
54 	FZ_INIT_STORABLE(pix, 1, fz_drop_pixmap_imp);
55 	pix->x = 0;
56 	pix->y = 0;
57 	pix->w = w;
58 	pix->h = h;
59 	pix->alpha = alpha = !!alpha;
60 	pix->flags = FZ_PIXMAP_FLAG_INTERPOLATE;
61 	pix->xres = 96;
62 	pix->yres = 96;
63 	pix->colorspace = NULL;
64 	pix->n = n;
65 	pix->s = s;
66 	pix->seps = fz_keep_separations(ctx, seps);
67 	pix->stride = stride;
68 
69 	if (colorspace)
70 	{
71 		pix->colorspace = fz_keep_colorspace(ctx, colorspace);
72 	}
73 	else
74 	{
75 		assert(alpha || s);
76 	}
77 
78 	pix->samples = samples;
79 	if (!samples && pix->h > 0 && pix->w > 0)
80 	{
81 		fz_try(ctx)
82 		{
83 			if (pix->stride > INT_MAX / pix->h)
84 				fz_throw(ctx, FZ_ERROR_GENERIC, "Overly large image");
85 			pix->samples = Memento_label(fz_malloc(ctx, pix->h * pix->stride), "pixmap_data");
86 		}
87 		fz_catch(ctx)
88 		{
89 			fz_drop_separations(ctx, pix->seps);
90 			fz_drop_colorspace(ctx, pix->colorspace);
91 			fz_free(ctx, pix);
92 			fz_rethrow(ctx);
93 		}
94 		pix->flags |= FZ_PIXMAP_FLAG_FREE_SAMPLES;
95 	}
96 
97 	return pix;
98 }
99 
100 fz_pixmap *
fz_new_pixmap(fz_context * ctx,fz_colorspace * colorspace,int w,int h,fz_separations * seps,int alpha)101 fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha)
102 {
103 	int stride;
104 	int s = fz_count_active_separations(ctx, seps);
105 	int n;
106 	if (!colorspace && s == 0) alpha = 1;
107 	n = fz_colorspace_n(ctx, colorspace) + s + alpha;
108 	if (w > INT_MAX / n)
109 		fz_throw(ctx, FZ_ERROR_GENERIC, "Overly wide image");
110 	stride = n * w;
111 	return fz_new_pixmap_with_data(ctx, colorspace, w, h, seps, alpha, stride, NULL);
112 }
113 
114 fz_pixmap *
fz_new_pixmap_with_bbox(fz_context * ctx,fz_colorspace * colorspace,fz_irect bbox,fz_separations * seps,int alpha)115 fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha)
116 {
117 	fz_pixmap *pixmap;
118 	pixmap = fz_new_pixmap(ctx, colorspace, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0, seps, alpha);
119 	pixmap->x = bbox.x0;
120 	pixmap->y = bbox.y0;
121 	return pixmap;
122 }
123 
124 fz_pixmap *
fz_new_pixmap_with_bbox_and_data(fz_context * ctx,fz_colorspace * colorspace,fz_irect bbox,fz_separations * seps,int alpha,unsigned char * samples)125 fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha, unsigned char *samples)
126 {
127 	int w = bbox.x1 - bbox.x0;
128 	int stride;
129 	int s = fz_count_active_separations(ctx, seps);
130 	fz_pixmap *pixmap;
131 	if (!colorspace && s == 0) alpha = 1;
132 	stride = (fz_colorspace_n(ctx, colorspace) + s + alpha) * w;
133 	pixmap = fz_new_pixmap_with_data(ctx, colorspace, w, bbox.y1 - bbox.y0, seps, alpha, stride, samples);
134 	pixmap->x = bbox.x0;
135 	pixmap->y = bbox.y0;
136 	return pixmap;
137 }
138 
fz_new_pixmap_from_pixmap(fz_context * ctx,fz_pixmap * pixmap,const fz_irect * rect)139 fz_pixmap *fz_new_pixmap_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, const fz_irect *rect)
140 {
141 	fz_irect local_rect;
142 	fz_pixmap *subpix;
143 
144 	if (!pixmap)
145 		return NULL;
146 
147 	if (rect == NULL)
148 	{
149 		rect = &local_rect;
150 		local_rect.x0 = pixmap->x;
151 		local_rect.y0 = pixmap->y;
152 		local_rect.x1 = pixmap->x + pixmap->w;
153 		local_rect.y1 = pixmap->y + pixmap->h;
154 	}
155 	else if (rect->x0 < pixmap->x || rect->y0 < pixmap->y || rect->x1 > pixmap->x + pixmap->w || rect->y1 > pixmap->y + pixmap->h)
156 		fz_throw(ctx, FZ_ERROR_GENERIC, "Pixmap region is not a subarea");
157 
158 	subpix = fz_malloc_struct(ctx, fz_pixmap);
159 	*subpix = *pixmap;
160 	subpix->storable.refs = 1;
161 	subpix->x = rect->x0;
162 	subpix->y = rect->y0;
163 	subpix->w = rect->x1 - rect->x0;
164 	subpix->h = rect->y1 - rect->y0;
165 	subpix->samples += (rect->x0 - pixmap->x) + (rect->y0 - pixmap->y) * pixmap->stride;
166 	subpix->underlying = fz_keep_pixmap(ctx, pixmap);
167 	subpix->colorspace = fz_keep_colorspace(ctx, pixmap->colorspace);
168 	subpix->seps = fz_keep_separations(ctx, pixmap->seps);
169 	subpix->flags &= ~FZ_PIXMAP_FLAG_FREE_SAMPLES;
170 
171 	return subpix;
172 }
173 
fz_clone_pixmap(fz_context * ctx,const fz_pixmap * old)174 fz_pixmap *fz_clone_pixmap(fz_context *ctx, const fz_pixmap *old)
175 {
176 	fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, old->colorspace, fz_make_irect(old->x, old->y, old->w, old->h), old->seps, old->alpha);
177 	memcpy(pix->samples, old->samples, pix->stride * pix->h);
178 	return pix;
179 }
180 
181 fz_irect
fz_pixmap_bbox(fz_context * ctx,const fz_pixmap * pix)182 fz_pixmap_bbox(fz_context *ctx, const fz_pixmap *pix)
183 {
184 	fz_irect bbox;
185 	bbox.x0 = pix->x;
186 	bbox.y0 = pix->y;
187 	bbox.x1 = pix->x + pix->w;
188 	bbox.y1 = pix->y + pix->h;
189 	return bbox;
190 }
191 
192 fz_irect
fz_pixmap_bbox_no_ctx(const fz_pixmap * pix)193 fz_pixmap_bbox_no_ctx(const fz_pixmap *pix)
194 {
195 	fz_irect bbox;
196 	bbox.x0 = pix->x;
197 	bbox.y0 = pix->y;
198 	bbox.x1 = pix->x + pix->w;
199 	bbox.y1 = pix->y + pix->h;
200 	return bbox;
201 }
202 
203 fz_colorspace *
fz_pixmap_colorspace(fz_context * ctx,const fz_pixmap * pix)204 fz_pixmap_colorspace(fz_context *ctx, const fz_pixmap *pix)
205 {
206 	if (!pix)
207 		return NULL;
208 	return pix->colorspace;
209 }
210 
211 int
fz_pixmap_x(fz_context * ctx,const fz_pixmap * pix)212 fz_pixmap_x(fz_context *ctx, const fz_pixmap *pix)
213 {
214 	return pix->x;
215 }
216 
217 int
fz_pixmap_y(fz_context * ctx,const fz_pixmap * pix)218 fz_pixmap_y(fz_context *ctx, const fz_pixmap *pix)
219 {
220 	return pix->y;
221 }
222 
223 int
fz_pixmap_width(fz_context * ctx,const fz_pixmap * pix)224 fz_pixmap_width(fz_context *ctx, const fz_pixmap *pix)
225 {
226 	return pix->w;
227 }
228 
229 int
fz_pixmap_height(fz_context * ctx,const fz_pixmap * pix)230 fz_pixmap_height(fz_context *ctx, const fz_pixmap *pix)
231 {
232 	return pix->h;
233 }
234 
235 int
fz_pixmap_components(fz_context * ctx,const fz_pixmap * pix)236 fz_pixmap_components(fz_context *ctx, const fz_pixmap *pix)
237 {
238 	return pix->n;
239 }
240 
241 int
fz_pixmap_colorants(fz_context * ctx,const fz_pixmap * pix)242 fz_pixmap_colorants(fz_context *ctx, const fz_pixmap *pix)
243 {
244 	return pix->n - pix->alpha - pix->s;
245 }
246 
247 int
fz_pixmap_spots(fz_context * ctx,const fz_pixmap * pix)248 fz_pixmap_spots(fz_context *ctx, const fz_pixmap *pix)
249 {
250 	return pix->s;
251 }
252 
253 int
fz_pixmap_alpha(fz_context * ctx,const fz_pixmap * pix)254 fz_pixmap_alpha(fz_context *ctx, const fz_pixmap *pix)
255 {
256 	return pix->alpha;
257 }
258 
259 int
fz_pixmap_stride(fz_context * ctx,const fz_pixmap * pix)260 fz_pixmap_stride(fz_context *ctx, const fz_pixmap *pix)
261 {
262 	return pix->stride;
263 }
264 
265 unsigned char *
fz_pixmap_samples(fz_context * ctx,const fz_pixmap * pix)266 fz_pixmap_samples(fz_context *ctx, const fz_pixmap *pix)
267 {
268 	if (!pix)
269 		return NULL;
270 	return pix->samples;
271 }
272 
273 /*
274 	The slowest routine in most CMYK rendering profiles.
275 	We therefore spend some effort to improve it. Rather than
276 	writing bytes, we write uint32_t's.
277 */
278 #ifdef ARCH_ARM
279 static void
280 clear_cmyka_bitmap_ARM(uint32_t *samples, int c, int value)
281 __attribute__((naked));
282 
283 static void
clear_cmyka_bitmap_ARM(uint32_t * samples,int c,int value)284 clear_cmyka_bitmap_ARM(uint32_t *samples, int c, int value)
285 {
286 	asm volatile(
287 	ENTER_ARM
288 	"stmfd	r13!,{r4-r6,r14}					\n"
289 	"@ r0 = samples							\n"
290 	"@ r1 = c							\n"
291 	"@ r2 = value							\n"
292 	"mov	r3, #255						\n"
293 	"mov	r12,#0			@ r12= 0			\n"
294 	"subs	r1, r1, #3						\n"
295 	"ble	2f							\n"
296 	"str	r12,[r13,#-20]!						\n"
297 	"str	r12,[r13,#4]						\n"
298 	"str	r12,[r13,#8]						\n"
299 	"str	r12,[r13,#12]						\n"
300 	"str	r12,[r13,#16]						\n"
301 	"strb	r2, [r13,#3]						\n"
302 	"strb	r3, [r13,#4]						\n"
303 	"strb	r2, [r13,#8]						\n"
304 	"strb	r3, [r13,#9]						\n"
305 	"strb	r2, [r13,#13]						\n"
306 	"strb	r3, [r13,#14]						\n"
307 	"strb	r2, [r13,#18]						\n"
308 	"strb	r3, [r13,#19]						\n"
309 	"ldmfd	r13!,{r4,r5,r6,r12,r14}					\n"
310 	"1:								\n"
311 	"stmia	r0!,{r4,r5,r6,r12,r14}					\n"
312 	"subs	r1, r1, #4						\n"
313 	"bgt	1b							\n"
314 	"2:								\n"
315 	"adds	r1, r1, #3						\n"
316 	"ble	4f							\n"
317 	"3:								\n"
318 	"strb	r12,[r0], #1						\n"
319 	"strb	r12,[r0], #1						\n"
320 	"strb	r12,[r0], #1						\n"
321 	"strb	r2, [r0], #1						\n"
322 	"strb	r3, [r0], #1						\n"
323 	"subs	r1, r1, #1						\n"
324 	"bgt	3b							\n"
325 	"4:								\n"
326 	"ldmfd	r13!,{r4-r6,PC}						\n"
327 	ENTER_THUMB
328 	);
329 }
330 #endif
331 
332 static void
clear_cmyk_bitmap(unsigned char * samples,int w,int h,int spots,int stride,int value,int alpha)333 clear_cmyk_bitmap(unsigned char *samples, int w, int h, int spots, int stride, int value, int alpha)
334 {
335 	uint32_t *s = (uint32_t *)(void *)samples;
336 	uint8_t *t;
337 
338 	if (w < 0 || h < 0)
339 		return;
340 
341 	if (spots)
342 	{
343 		int x, i;
344 		spots += 4;
345 		stride -= w * (spots + alpha);
346 		for (; h > 0; h--)
347 		{
348 			for (x = w; x > 0; x--)
349 			{
350 				for (i = spots; i > 0; i--)
351 					*samples++ = value;
352 				if (alpha)
353 					*samples++ = 255;
354 			}
355 			samples += stride;
356 		}
357 		return;
358 	}
359 
360 	if (alpha)
361 	{
362 		int c = w;
363 		stride -= w*5;
364 		if (stride == 0)
365 		{
366 #ifdef ARCH_ARM
367 			clear_cmyka_bitmap_ARM(s, c, alpha);
368 			return;
369 #else
370 			/* We can do it all fast (except for maybe a few stragglers) */
371 			union
372 			{
373 				uint8_t bytes[20];
374 				uint32_t words[5];
375 			} d;
376 
377 			c *= h;
378 			h = 1;
379 
380 			d.words[0] = 0;
381 			d.words[1] = 0;
382 			d.words[2] = 0;
383 			d.words[3] = 0;
384 			d.words[4] = 0;
385 			d.bytes[3] = value;
386 			d.bytes[4] = 255;
387 			d.bytes[8] = value;
388 			d.bytes[9] = 255;
389 			d.bytes[13] = value;
390 			d.bytes[14] = 255;
391 			d.bytes[18] = value;
392 			d.bytes[19] = 255;
393 
394 			c -= 3;
395 			{
396 				const uint32_t a0 = d.words[0];
397 				const uint32_t a1 = d.words[1];
398 				const uint32_t a2 = d.words[2];
399 				const uint32_t a3 = d.words[3];
400 				const uint32_t a4 = d.words[4];
401 				while (c > 0)
402 				{
403 					*s++ = a0;
404 					*s++ = a1;
405 					*s++ = a2;
406 					*s++ = a3;
407 					*s++ = a4;
408 					c -= 4;
409 				}
410 			}
411 			c += 3;
412 #endif
413 		}
414 		t = (unsigned char *)s;
415 		w = c;
416 		while (h--)
417 		{
418 			c = w;
419 			while (c > 0)
420 			{
421 				*t++ = 0;
422 				*t++ = 0;
423 				*t++ = 0;
424 				*t++ = value;
425 				*t++ = 255;
426 				c--;
427 			}
428 			t += stride;
429 		}
430 	}
431 	else
432 	{
433 		stride -= w*4;
434 		if ((stride & 3) == 0)
435 		{
436 			size_t W = w;
437 			if (stride == 0)
438 			{
439 				W *= h;
440 				h = 1;
441 			}
442 			W *= 4;
443 			if (value == 0)
444 			{
445 				while (h--)
446 				{
447 					memset(s, 0, W);
448 					s += (stride>>2);
449 				}
450 			}
451 			else
452 			{
453 				/* We can do it all fast */
454 				union
455 				{
456 					uint8_t bytes[4];
457 					uint32_t word;
458 				} d;
459 
460 				d.word = 0;
461 				d.bytes[3] = value;
462 				{
463 					const uint32_t a0 = d.word;
464 					while (h--)
465 					{
466 						size_t WW = W >> 2;
467 						while (WW--)
468 						{
469 							*s++ = a0;
470 						}
471 						s += (stride>>2);
472 					}
473 				}
474 			}
475 		}
476 		else
477 		{
478 			t = (unsigned char *)s;
479 			while (h--)
480 			{
481 				int c = w;
482 				while (c > 0)
483 				{
484 					*t++ = 0;
485 					*t++ = 0;
486 					*t++ = 0;
487 					*t++ = value;
488 					c--;
489 				}
490 				t += stride;
491 			}
492 		}
493 	}
494 }
495 
496 void
fz_clear_pixmap(fz_context * ctx,fz_pixmap * pix)497 fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix)
498 {
499 	int stride = pix->w * pix->n;
500 	int h = pix->h;
501 	unsigned char *s = pix->samples;
502 	if (stride == pix->stride)
503 	{
504 		stride *= h;
505 		h = 1;
506 	}
507 	if (pix->alpha || fz_colorspace_is_subtractive(ctx, pix->colorspace))
508 	{
509 		while (h--)
510 		{
511 			memset(s, 0, (unsigned int)stride);
512 			s += pix->stride;
513 		}
514 	}
515 	else if (pix->s == 0)
516 	{
517 		while (h--)
518 		{
519 			memset(s, 0xff, (unsigned int)stride);
520 			s += pix->stride;
521 		}
522 	}
523 	else
524 	{
525 		/* Horrible, slow case: additive with spots */
526 		int w = stride/pix->n;
527 		int spots = pix->s;
528 		int colorants = pix->n - spots; /* We know there is no alpha */
529 		while (h--)
530 		{
531 			int w2 = w;
532 			while (w2--)
533 			{
534 				int i = colorants;
535 				do
536 				{
537 					*s++ = 0xff;
538 					i--;
539 				}
540 				while (i != 0);
541 
542 				i = spots;
543 				do
544 				{
545 					*s++ = 0;
546 					i--;
547 				}
548 				while (i != 0);
549 			}
550 		}
551 	}
552 }
553 
554 void
fz_clear_pixmap_with_value(fz_context * ctx,fz_pixmap * pix,int value)555 fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value)
556 {
557 	unsigned char *s;
558 	int w, h, n, stride, len;
559 	int alpha = pix->alpha;
560 
561 	w = pix->w;
562 	h = pix->h;
563 	if (w < 0 || h < 0)
564 		return;
565 
566 	/* CMYK needs special handling (and potentially any other subtractive colorspaces) */
567 	if (fz_colorspace_n(ctx, pix->colorspace) == 4)
568 	{
569 		clear_cmyk_bitmap(pix->samples, w, h, pix->s, pix->stride, 255-value, pix->alpha);
570 		return;
571 	}
572 
573 	n = pix->n;
574 	stride = pix->stride;
575 	len = w * n;
576 
577 	s = pix->samples;
578 	if (value == 255 || !alpha)
579 	{
580 		if (stride == len)
581 		{
582 			len *= h;
583 			h = 1;
584 		}
585 		while (h--)
586 		{
587 			memset(s, value, (unsigned int)len);
588 			s += stride;
589 		}
590 	}
591 	else
592 	{
593 		int k, x, y;
594 		stride -= len;
595 		for (y = 0; y < pix->h; y++)
596 		{
597 			for (x = 0; x < pix->w; x++)
598 			{
599 				for (k = 0; k < pix->n - 1; k++)
600 					*s++ = value;
601 				if (alpha)
602 					*s++ = 255;
603 			}
604 			s += stride;
605 		}
606 	}
607 }
608 
609 void
fz_fill_pixmap_with_color(fz_context * ctx,fz_pixmap * pix,fz_colorspace * colorspace,float * color,fz_color_params color_params)610 fz_fill_pixmap_with_color(fz_context *ctx, fz_pixmap *pix, fz_colorspace *colorspace, float *color, fz_color_params color_params)
611 {
612 	float colorfv[FZ_MAX_COLORS];
613 	unsigned char colorbv[FZ_MAX_COLORS];
614 	int i, n, a, s, x, y, w, h;
615 
616 	n = fz_colorspace_n(ctx, pix->colorspace);
617 	a = pix->alpha;
618 	s = pix->s;
619 	fz_convert_color(ctx, colorspace, color, pix->colorspace, colorfv, NULL, color_params);
620 	for (i = 0; i < n; ++i)
621 		colorbv[i] = colorfv[i] * 255;
622 
623 	w = pix->w;
624 	h = pix->h;
625 	for (y = 0; y < h; ++y)
626 	{
627 		unsigned char *p = pix->samples + y * pix->stride;
628 		for (x = 0; x < w; ++x)
629 		{
630 			for (i = 0; i < n; ++i)
631 				*p++ = colorbv[i];
632 			for (i = 0; i < s; ++i)
633 				*p++ = 0;
634 			if (a)
635 				*p++ = 255;
636 		}
637 	}
638 }
639 
640 void
fz_copy_pixmap_rect(fz_context * ctx,fz_pixmap * dest,fz_pixmap * src,fz_irect b,const fz_default_colorspaces * default_cs)641 fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_irect b, const fz_default_colorspaces *default_cs)
642 {
643 	unsigned char *srcp;
644 	unsigned char *destp;
645 	int y, w, destspan, srcspan;
646 
647 	b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));
648 	b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, src));
649 	w = b.x1 - b.x0;
650 	y = b.y1 - b.y0;
651 	if (w <= 0 || y <= 0)
652 		return;
653 
654 	srcspan = src->stride;
655 	srcp = src->samples + (unsigned int)(srcspan * (b.y0 - src->y) + src->n * (b.x0 - src->x));
656 	destspan = dest->stride;
657 	destp = dest->samples + (unsigned int)(destspan * (b.y0 - dest->y) + dest->n * (b.x0 - dest->x));
658 
659 	if (src->n == dest->n)
660 	{
661 		w *= src->n;
662 		do
663 		{
664 			memcpy(destp, srcp, w);
665 			srcp += srcspan;
666 			destp += destspan;
667 		}
668 		while (--y);
669 	}
670 	else
671 	{
672 		fz_pixmap fake_src = *src;
673 		fake_src.x = b.x0;
674 		fake_src.y = b.y0;
675 		fake_src.w = w;
676 		fake_src.h = y;
677 		fake_src.samples = srcp;
678 		fz_convert_pixmap_samples(ctx, dest, &fake_src, NULL, default_cs, fz_default_color_params, 0);
679 	}
680 }
681 
682 void
fz_clear_pixmap_rect_with_value(fz_context * ctx,fz_pixmap * dest,int value,fz_irect b)683 fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, fz_irect b)
684 {
685 	unsigned char *destp;
686 	int x, y, w, k, destspan;
687 
688 	b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));
689 	w = b.x1 - b.x0;
690 	y = b.y1 - b.y0;
691 	if (w <= 0 || y <= 0)
692 		return;
693 
694 	destspan = dest->stride;
695 	destp = dest->samples + (unsigned int)(destspan * (b.y0 - dest->y) + dest->n * (b.x0 - dest->x));
696 
697 	/* CMYK needs special handling (and potentially any other subtractive colorspaces) */
698 	if (fz_colorspace_n(ctx, dest->colorspace) == 4)
699 	{
700 		value = 255 - value;
701 		do
702 		{
703 			unsigned char *s = destp;
704 			for (x = 0; x < w; x++)
705 			{
706 				*s++ = 0;
707 				*s++ = 0;
708 				*s++ = 0;
709 				*s++ = value;
710 				*s++ = 255;
711 			}
712 			destp += destspan;
713 		}
714 		while (--y);
715 		return;
716 	}
717 
718 	if (value == 255)
719 	{
720 		do
721 		{
722 			memset(destp, 255, (unsigned int)(w * dest->n));
723 			destp += destspan;
724 		}
725 		while (--y);
726 	}
727 	else
728 	{
729 		do
730 		{
731 			unsigned char *s = destp;
732 			for (x = 0; x < w; x++)
733 			{
734 				for (k = 0; k < dest->n - 1; k++)
735 					*s++ = value;
736 				*s++ = 255;
737 			}
738 			destp += destspan;
739 		}
740 		while (--y);
741 	}
742 }
743 
744 void
fz_premultiply_pixmap(fz_context * ctx,fz_pixmap * pix)745 fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix)
746 {
747 	unsigned char *s = pix->samples;
748 	unsigned char a;
749 	int k, x, y;
750 	int stride = pix->stride - pix->w * pix->n;
751 
752 	if (!pix->alpha)
753 		return;
754 
755 	for (y = 0; y < pix->h; y++)
756 	{
757 		for (x = 0; x < pix->w; x++)
758 		{
759 			a = s[pix->n - 1];
760 			for (k = 0; k < pix->n - 1; k++)
761 				s[k] = fz_mul255(s[k], a);
762 			s += pix->n;
763 		}
764 		s += stride;
765 	}
766 }
767 
768 fz_pixmap *
fz_alpha_from_gray(fz_context * ctx,fz_pixmap * gray)769 fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray)
770 {
771 	fz_pixmap *alpha;
772 	unsigned char *sp, *dp;
773 	int w, h, sstride, dstride;
774 
775 	assert(gray->n == 1);
776 
777 	alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray), 0, 1);
778 	dp = alpha->samples;
779 	dstride = alpha->stride;
780 	sp = gray->samples;
781 	sstride = gray->stride;
782 
783 	h = gray->h;
784 	w = gray->w;
785 	while (h--)
786 	{
787 		memcpy(dp, sp, w);
788 		sp += sstride;
789 		dp += dstride;
790 	}
791 
792 	return alpha;
793 }
794 
795 void
fz_tint_pixmap(fz_context * ctx,fz_pixmap * pix,int black,int white)796 fz_tint_pixmap(fz_context *ctx, fz_pixmap *pix, int black, int white)
797 {
798 	unsigned char *s = pix->samples;
799 	int n = pix->n;
800 	int x, y, save;
801 	int rb = (black>>16)&255;
802 	int gb = (black>>8)&255;
803 	int bb = (black)&255;
804 	int rw = (white>>16)&255;
805 	int gw = (white>>8)&255;
806 	int bw = (white)&255;
807 	int rm = (rw - rb);
808 	int gm = (gw - gb);
809 	int bm = (bw - bb);
810 
811 	switch (fz_colorspace_type(ctx, pix->colorspace))
812 	{
813 	case FZ_COLORSPACE_GRAY:
814 		gw = (rw + gw + bw) / 3;
815 		gb = (rb + gb + bb) / 3;
816 		gm = gw - gb;
817 		for (y = 0; y < pix->h; y++)
818 		{
819 			for (x = 0; x < pix->w; x++)
820 			{
821 				*s = gb + fz_mul255(*s, gm);
822 				s += n;
823 			}
824 			s += pix->stride - pix->w * n;
825 		}
826 		break;
827 
828 	case FZ_COLORSPACE_BGR:
829 		save = rm; rm = bm; bm = save;
830 		save = rb; rb = bb; bb = save;
831 		/* fall through */
832 	case FZ_COLORSPACE_RGB:
833 		for (y = 0; y < pix->h; y++)
834 		{
835 			for (x = 0; x < pix->w; x++)
836 			{
837 				s[0] = rb + fz_mul255(s[0], rm);
838 				s[1] = gb + fz_mul255(s[1], gm);
839 				s[2] = bb + fz_mul255(s[2], bm);
840 				s += n;
841 			}
842 			s += pix->stride - pix->w * n;
843 		}
844 		break;
845 
846 	default:
847 		fz_throw(ctx, FZ_ERROR_GENERIC, "can only tint RGB, BGR and Gray pixmaps");
848 		break;
849 	}
850 }
851 
852 /* Invert luminance in RGB/BGR pixmap, but keep the colors as is. */
invert_luminance(int type,unsigned char * s)853 static inline void invert_luminance(int type, unsigned char *s)
854 {
855 	int r, g, b, y;
856 
857 	/* Convert to YUV */
858 	if (type == FZ_COLORSPACE_RGB)
859 	{
860 		r = s[0];
861 		g = s[1];
862 		b = s[2];
863 	}
864 	else
865 	{
866 		r = s[2];
867 		g = s[1];
868 		b = s[0];
869 	}
870 
871 	y = (39336 * r + 76884 * g + 14900 * b + 32768)>>16;
872 	y = 259-y;
873 	r += y;
874 	g += y;
875 	b += y;
876 
877 	if (type == FZ_COLORSPACE_RGB)
878 	{
879 		s[0] = r > 255 ? 255 : r < 0 ? 0 : r;
880 		s[1] = g > 255 ? 255 : g < 0 ? 0 : g;
881 		s[2] = b > 255 ? 255 : b < 0 ? 0 : b;
882 	}
883 	else
884 	{
885 		s[2] = r > 255 ? 255 : r < 0 ? 0 : r;
886 		s[1] = g > 255 ? 255 : g < 0 ? 0 : g;
887 		s[0] = b > 255 ? 255 : b < 0 ? 0 : b;
888 	}
889 }
890 
891 void
fz_invert_pixmap_luminance(fz_context * ctx,fz_pixmap * pix)892 fz_invert_pixmap_luminance(fz_context *ctx, fz_pixmap *pix)
893 {
894 	unsigned char *s = pix->samples;
895 	int x, y, n = pix->n;
896 	int type = pix->colorspace ? pix->colorspace->type : FZ_COLORSPACE_NONE;
897 
898 	if (type == FZ_COLORSPACE_GRAY)
899 	{
900 		fz_invert_pixmap(ctx, pix);
901 	}
902 	else if (type == FZ_COLORSPACE_RGB || type == FZ_COLORSPACE_BGR)
903 	{
904 		for (y = 0; y < pix->h; y++)
905 		{
906 			for (x = 0; x < pix->w; x++)
907 			{
908 				invert_luminance(type, s);
909 				s += n;
910 			}
911 			s += pix->stride - pix->w * n;
912 		}
913 	}
914 	else
915 	{
916 		fz_throw(ctx, FZ_ERROR_GENERIC, "can only invert luminance of Gray and RGB pixmaps");
917 	}
918 }
919 
920 void
fz_invert_pixmap(fz_context * ctx,fz_pixmap * pix)921 fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix)
922 {
923 	unsigned char *s = pix->samples;
924 	int k, x, y;
925 	int n1 = pix->n - pix->alpha;
926 	int n = pix->n;
927 
928 	for (y = 0; y < pix->h; y++)
929 	{
930 		for (x = 0; x < pix->w; x++)
931 		{
932 			for (k = 0; k < n1; k++)
933 				s[k] = 255 - s[k];
934 			s += n;
935 		}
936 		s += pix->stride - pix->w * n;
937 	}
938 }
939 
fz_invert_pixmap_rect(fz_context * ctx,fz_pixmap * image,fz_irect rect)940 void fz_invert_pixmap_rect(fz_context *ctx, fz_pixmap *image, fz_irect rect)
941 {
942 	unsigned char *p;
943 	int x, y, n;
944 
945 	int x0 = fz_clampi(rect.x0 - image->x, 0, image->w);
946 	int x1 = fz_clampi(rect.x1 - image->x, 0, image->w);
947 	int y0 = fz_clampi(rect.y0 - image->y, 0, image->h);
948 	int y1 = fz_clampi(rect.y1 - image->y, 0, image->h);
949 
950 	for (y = y0; y < y1; y++)
951 	{
952 		p = image->samples + (unsigned int)((y * image->stride) + (x0 * image->n));
953 		for (x = x0; x < x1; x++)
954 		{
955 			for (n = image->n; n > 1; n--, p++)
956 				*p = 255 - *p;
957 			p++;
958 		}
959 	}
960 }
961 
962 void
fz_gamma_pixmap(fz_context * ctx,fz_pixmap * pix,float gamma)963 fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma)
964 {
965 	unsigned char gamma_map[256];
966 	unsigned char *s = pix->samples;
967 	int n1 = pix->n - pix->alpha;
968 	int n = pix->n;
969 	int k, x, y;
970 
971 	for (k = 0; k < 256; k++)
972 		gamma_map[k] = pow(k / 255.0f, gamma) * 255;
973 
974 	for (y = 0; y < pix->h; y++)
975 	{
976 		for (x = 0; x < pix->w; x++)
977 		{
978 			for (k = 0; k < n1; k++)
979 				s[k] = gamma_map[s[k]];
980 			s += n;
981 		}
982 		s += pix->stride - pix->w * n;
983 	}
984 }
985 
986 size_t
fz_pixmap_size(fz_context * ctx,fz_pixmap * pix)987 fz_pixmap_size(fz_context *ctx, fz_pixmap * pix)
988 {
989 	if (pix == NULL)
990 		return 0;
991 	return sizeof(*pix) + (size_t)pix->n * pix->w * pix->h;
992 }
993 
994 fz_pixmap *
fz_convert_pixmap(fz_context * ctx,const fz_pixmap * pix,fz_colorspace * ds,fz_colorspace * prf,fz_default_colorspaces * default_cs,fz_color_params color_params,int keep_alpha)995 fz_convert_pixmap(fz_context *ctx, const fz_pixmap *pix, fz_colorspace *ds, fz_colorspace *prf, fz_default_colorspaces *default_cs, fz_color_params color_params, int keep_alpha)
996 {
997 	fz_pixmap *cvt;
998 
999 	if (!ds && !keep_alpha)
1000 		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot both throw away and keep alpha");
1001 
1002 	cvt = fz_new_pixmap(ctx, ds, pix->w, pix->h, pix->seps, keep_alpha && pix->alpha);
1003 
1004 	cvt->xres = pix->xres;
1005 	cvt->yres = pix->yres;
1006 	cvt->x = pix->x;
1007 	cvt->y = pix->y;
1008 	if (pix->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1009 		cvt->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1010 	else
1011 		cvt->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1012 
1013 	fz_try(ctx)
1014 	{
1015 		fz_convert_pixmap_samples(ctx, pix, cvt, prf, default_cs, color_params, 1);
1016 	}
1017 	fz_catch(ctx)
1018 	{
1019 		fz_drop_pixmap(ctx, cvt);
1020 		fz_rethrow(ctx);
1021 	}
1022 
1023 	return cvt;
1024 }
1025 
1026 fz_pixmap *
fz_new_pixmap_from_8bpp_data(fz_context * ctx,int x,int y,int w,int h,unsigned char * sp,int span)1027 fz_new_pixmap_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
1028 {
1029 	fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1);
1030 	int stride = pixmap->stride;
1031 	unsigned char *s = pixmap->samples;
1032 	pixmap->x = x;
1033 	pixmap->y = y;
1034 
1035 	for (y = 0; y < h; y++)
1036 	{
1037 		memcpy(s, sp + y * span, w);
1038 		s += stride;
1039 	}
1040 
1041 	return pixmap;
1042 }
1043 
1044 fz_pixmap *
fz_new_pixmap_from_1bpp_data(fz_context * ctx,int x,int y,int w,int h,unsigned char * sp,int span)1045 fz_new_pixmap_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
1046 {
1047 	fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1);
1048 	int stride = pixmap->stride - pixmap->w;
1049 	pixmap->x = x;
1050 	pixmap->y = y;
1051 
1052 	for (y = 0; y < h; y++)
1053 	{
1054 		unsigned char *out = pixmap->samples + y * w;
1055 		unsigned char *in = sp + y * span;
1056 		unsigned char bit = 0x80;
1057 		int ww = w;
1058 		while (ww--)
1059 		{
1060 			*out++ = (*in & bit) ? 255 : 0;
1061 			bit >>= 1;
1062 			if (bit == 0)
1063 				bit = 0x80, in++;
1064 		}
1065 		out += stride;
1066 	}
1067 
1068 	return pixmap;
1069 }
1070 
1071 int
fz_is_pixmap_monochrome(fz_context * ctx,fz_pixmap * pixmap)1072 fz_is_pixmap_monochrome(fz_context *ctx, fz_pixmap *pixmap)
1073 {
1074 	int n = pixmap->n;
1075 	int w = pixmap->w;
1076 	int h = pixmap->h;
1077 	unsigned char *s = pixmap->samples;
1078 	int x;
1079 
1080 	if (n != 1)
1081 		return 0;
1082 
1083 	while (h--)
1084 	{
1085 		for (x = 0; x < w; ++x)
1086 		{
1087 			unsigned char v = s[x];
1088 			if (v != 0 && v != 255)
1089 				return 0;
1090 		}
1091 		s += pixmap->stride;
1092 	}
1093 
1094 	return 1;
1095 }
1096 
1097 #ifdef ARCH_ARM
1098 static void
1099 fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,
1100 			int n, int fwd, int back, int back2, int fwd2,
1101 			int divX, int back4, int fwd4, int fwd3,
1102 			int divY, int back5, int divXY)
1103 __attribute__((naked));
1104 
1105 static void
fz_subsample_pixmap_ARM(unsigned char * ptr,int w,int h,int f,int factor,int n,int fwd,int back,int back2,int fwd2,int divX,int back4,int fwd4,int fwd3,int divY,int back5,int divXY)1106 fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,
1107 			int n, int fwd, int back, int back2, int fwd2,
1108 			int divX, int back4, int fwd4, int fwd3,
1109 			int divY, int back5, int divXY)
1110 {
1111 	asm volatile(
1112 	ENTER_ARM
1113 	"stmfd	r13!,{r1,r4-r11,r14}					\n"
1114 	"@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1115 	"@ r0 = src = ptr						\n"
1116 	"@ r1 = w							\n"
1117 	"@ r2 = h							\n"
1118 	"@ r3 = f							\n"
1119 	"mov	r9, r0			@ r9 = dst = ptr		\n"
1120 	"ldr	r6, [r13,#4*12]		@ r6 = fwd			\n"
1121 	"ldr	r7, [r13,#4*13]		@ r7 = back			\n"
1122 	"subs	r2, r2, r3		@ r2 = h -= f			\n"
1123 	"blt	11f			@ Skip if less than a full row	\n"
1124 	"1:				@ for (y = h; y > 0; y--) {	\n"
1125 	"ldr	r1, [r13]		@ r1 = w			\n"
1126 	"subs	r1, r1, r3		@ r1 = w -= f			\n"
1127 	"blt	6f			@ Skip if less than a full col	\n"
1128 	"ldr	r4, [r13,#4*10]		@ r4 = factor			\n"
1129 	"ldr	r8, [r13,#4*14]		@ r8 = back2			\n"
1130 	"ldr	r12,[r13,#4*15]		@ r12= fwd2			\n"
1131 	"2:				@ for (x = w; x > 0; x--) {	\n"
1132 	"ldr	r5, [r13,#4*11]		@ for (nn = n; nn > 0; n--) {	\n"
1133 	"3:				@				\n"
1134 	"mov	r14,#0			@ r14= v = 0			\n"
1135 	"sub	r5, r5, r3, LSL #8	@ for (xx = f; xx > 0; x--) {	\n"
1136 	"4:				@				\n"
1137 	"add	r5, r5, r3, LSL #16	@ for (yy = f; yy > 0; y--) {	\n"
1138 	"5:				@				\n"
1139 	"ldrb	r11,[r0], r6		@ r11= *src	src += fwd	\n"
1140 	"subs	r5, r5, #1<<16		@ xx--				\n"
1141 	"add	r14,r14,r11		@ v += r11			\n"
1142 	"bgt	5b			@ }				\n"
1143 	"sub	r0, r0, r7		@ src -= back			\n"
1144 	"adds	r5, r5, #1<<8		@ yy--				\n"
1145 	"blt	4b			@ }				\n"
1146 	"mov	r14,r14,LSR r4		@ r14 = v >>= factor		\n"
1147 	"strb	r14,[r9], #1		@ *d++ = r14			\n"
1148 	"sub	r0, r0, r8		@ s -= back2			\n"
1149 	"subs	r5, r5, #1		@ n--				\n"
1150 	"bgt	3b			@ }				\n"
1151 	"add	r0, r0, r12		@ s += fwd2			\n"
1152 	"subs	r1, r1, r3		@ x -= f			\n"
1153 	"bge	2b			@ }				\n"
1154 	"6:				@ Less than a full column left	\n"
1155 	"adds	r1, r1, r3		@ x += f			\n"
1156 	"beq	11f			@ if (x == 0) next row		\n"
1157 	"@ r0 = src							\n"
1158 	"@ r1 = x							\n"
1159 	"@ r2 = y							\n"
1160 	"@ r3 = f							\n"
1161 	"@ r4 = factor							\n"
1162 	"@ r6 = fwd							\n"
1163 	"@ r7 = back							\n"
1164 	"@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1165 	"ldr	r5, [r13,#4*11]		@ for (nn = n; nn > 0; n--) {	\n"
1166 	"ldr	r4, [r13,#4*16]		@ r4 = divX			\n"
1167 	"ldr	r8, [r13,#4*17]		@ r8 = back4			\n"
1168 	"ldr	r12,[r13,#4*18]		@ r12= fwd4			\n"
1169 	"8:				@				\n"
1170 	"mov	r14,#0			@ r14= v = 0			\n"
1171 	"sub	r5, r5, r1, LSL #8	@ for (xx = x; xx > 0; x--) {	\n"
1172 	"9:				@				\n"
1173 	"add	r5, r5, r3, LSL #16	@ for (yy = f; yy > 0; y--) {	\n"
1174 	"10:				@				\n"
1175 	"ldrb	r11,[r0], r6		@ r11= *src	src += fwd	\n"
1176 	"subs	r5, r5, #1<<16		@ xx--				\n"
1177 	"add	r14,r14,r11		@ v += r11			\n"
1178 	"bgt	10b			@ }				\n"
1179 	"sub	r0, r0, r7		@ src -= back			\n"
1180 	"adds	r5, r5, #1<<8		@ yy--				\n"
1181 	"blt	9b			@ }				\n"
1182 	"mul	r14,r4, r14		@ r14= v *= divX		\n"
1183 	"mov	r14,r14,LSR #16		@ r14= v >>= 16			\n"
1184 	"strb	r14,[r9], #1		@ *d++ = r14			\n"
1185 	"sub	r0, r0, r8		@ s -= back4			\n"
1186 	"subs	r5, r5, #1		@ n--				\n"
1187 	"bgt	8b			@ }				\n"
1188 	"add	r0, r0, r12		@ s += fwd4			\n"
1189 	"11:				@				\n"
1190 	"ldr	r14,[r13,#4*19]		@ r14 = fwd3			\n"
1191 	"subs	r2, r2, r3		@ h -= f			\n"
1192 	"add	r0, r0, r14		@ s += fwd3			\n"
1193 	"bge	1b			@ }				\n"
1194 	"adds	r2, r2, r3		@ h += f			\n"
1195 	"beq	21f			@ if no stray row, end		\n"
1196 	"@ So doing one last (partial) row				\n"
1197 	"@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1198 	"@ r0 = src = ptr						\n"
1199 	"@ r1 = w							\n"
1200 	"@ r2 = h							\n"
1201 	"@ r3 = f							\n"
1202 	"@ r4 = factor							\n"
1203 	"@ r5 = n							\n"
1204 	"@ r6 = fwd							\n"
1205 	"12:				@ for (y = h; y > 0; y--) {	\n"
1206 	"ldr	r1, [r13]		@ r1 = w			\n"
1207 	"ldr	r7, [r13,#4*21]		@ r7 = back5			\n"
1208 	"ldr	r8, [r13,#4*14]		@ r8 = back2			\n"
1209 	"subs	r1, r1, r3		@ r1 = w -= f			\n"
1210 	"blt	17f			@ Skip if less than a full col	\n"
1211 	"ldr	r4, [r13,#4*20]		@ r4 = divY			\n"
1212 	"ldr	r12,[r13,#4*15]		@ r12= fwd2			\n"
1213 	"13:				@ for (x = w; x > 0; x--) {	\n"
1214 	"ldr	r5, [r13,#4*11]		@ for (nn = n; nn > 0; n--) {	\n"
1215 	"14:				@				\n"
1216 	"mov	r14,#0			@ r14= v = 0			\n"
1217 	"sub	r5, r5, r3, LSL #8	@ for (xx = f; xx > 0; x--) {	\n"
1218 	"15:				@				\n"
1219 	"add	r5, r5, r2, LSL #16	@ for (yy = y; yy > 0; y--) {	\n"
1220 	"16:				@				\n"
1221 	"ldrb	r11,[r0], r6		@ r11= *src	src += fwd	\n"
1222 	"subs	r5, r5, #1<<16		@ xx--				\n"
1223 	"add	r14,r14,r11		@ v += r11			\n"
1224 	"bgt	16b			@ }				\n"
1225 	"sub	r0, r0, r7		@ src -= back5			\n"
1226 	"adds	r5, r5, #1<<8		@ yy--				\n"
1227 	"blt	15b			@ }				\n"
1228 	"mul	r14,r4, r14		@ r14 = x *= divY		\n"
1229 	"mov	r14,r14,LSR #16		@ r14 = v >>= 16		\n"
1230 	"strb	r14,[r9], #1		@ *d++ = r14			\n"
1231 	"sub	r0, r0, r8		@ s -= back2			\n"
1232 	"subs	r5, r5, #1		@ n--				\n"
1233 	"bgt	14b			@ }				\n"
1234 	"add	r0, r0, r12		@ s += fwd2			\n"
1235 	"subs	r1, r1, r3		@ x -= f			\n"
1236 	"bge	13b			@ }				\n"
1237 	"17:				@ Less than a full column left	\n"
1238 	"adds	r1, r1, r3		@ x += f			\n"
1239 	"beq	21f			@ if (x == 0) end		\n"
1240 	"@ r0 = src							\n"
1241 	"@ r1 = x							\n"
1242 	"@ r2 = y							\n"
1243 	"@ r3 = f							\n"
1244 	"@ r4 = factor							\n"
1245 	"@ r6 = fwd							\n"
1246 	"@ r7 = back5							\n"
1247 	"@ r8 = back2							\n"
1248 	"@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1249 	"ldr	r4, [r13,#4*22]		@ r4 = divXY			\n"
1250 	"ldr	r5, [r13,#4*11]		@ for (nn = n; nn > 0; n--) {	\n"
1251 	"ldr	r8, [r13,#4*17]		@ r8 = back4			\n"
1252 	"18:				@				\n"
1253 	"mov	r14,#0			@ r14= v = 0			\n"
1254 	"sub	r5, r5, r1, LSL #8	@ for (xx = x; xx > 0; x--) {	\n"
1255 	"19:				@				\n"
1256 	"add	r5, r5, r2, LSL #16	@ for (yy = y; yy > 0; y--) {	\n"
1257 	"20:				@				\n"
1258 	"ldrb	r11,[r0],r6		@ r11= *src	src += fwd	\n"
1259 	"subs	r5, r5, #1<<16		@ xx--				\n"
1260 	"add	r14,r14,r11		@ v += r11			\n"
1261 	"bgt	20b			@ }				\n"
1262 	"sub	r0, r0, r7		@ src -= back5			\n"
1263 	"adds	r5, r5, #1<<8		@ yy--				\n"
1264 	"blt	19b			@ }				\n"
1265 	"mul	r14,r4, r14		@ r14= v *= divX		\n"
1266 	"mov	r14,r14,LSR #16		@ r14= v >>= 16			\n"
1267 	"strb	r14,[r9], #1		@ *d++ = r14			\n"
1268 	"sub	r0, r0, r8		@ s -= back4			\n"
1269 	"subs	r5, r5, #1		@ n--				\n"
1270 	"bgt	18b			@ }				\n"
1271 	"21:				@				\n"
1272 	"ldmfd	r13!,{r1,r4-r11,PC}	@ pop, return to thumb		\n"
1273 	ENTER_THUMB
1274 	);
1275 }
1276 
1277 #endif
1278 
1279 void
fz_subsample_pixmap(fz_context * ctx,fz_pixmap * tile,int factor)1280 fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor)
1281 {
1282 	int dst_w, dst_h, w, h, fwd, fwd2, fwd3, back, back2, n, f;
1283 	unsigned char *s, *d;
1284 #ifndef ARCH_ARM
1285 	int x, y, xx, yy, nn;
1286 #endif
1287 
1288 	if (!tile)
1289 		return;
1290 
1291 	assert(tile->stride >= tile->w * tile->n);
1292 
1293 	s = d = tile->samples;
1294 	f = 1<<factor;
1295 	w = tile->w;
1296 	h = tile->h;
1297 	n = tile->n;
1298 	dst_w = (w + f-1)>>factor;
1299 	dst_h = (h + f-1)>>factor;
1300 	fwd = tile->stride;
1301 	back = f*fwd-n;
1302 	back2 = f*n-1;
1303 	fwd2 = (f-1)*n;
1304 	fwd3 = (f-1)*fwd + (int)tile->stride - w * n;
1305 	factor *= 2;
1306 #ifdef ARCH_ARM
1307 	{
1308 		int strayX = w%f;
1309 		int divX = (strayX ? 65536/(strayX*f) : 0);
1310 		int fwd4 = (strayX-1) * n;
1311 		int back4 = strayX*n-1;
1312 		int strayY = h%f;
1313 		int divY = (strayY ? 65536/(strayY*f) : 0);
1314 		int back5 = fwd * strayY - n;
1315 		int divXY = (strayY*strayX ? 65536/(strayX*strayY) : 0);
1316 		fz_subsample_pixmap_ARM(s, w, h, f, factor, n, fwd, back,
1317 					back2, fwd2, divX, back4, fwd4, fwd3,
1318 					divY, back5, divXY);
1319 	}
1320 #else
1321 	for (y = h - f; y >= 0; y -= f)
1322 	{
1323 		for (x = w - f; x >= 0; x -= f)
1324 		{
1325 			for (nn = n; nn > 0; nn--)
1326 			{
1327 				int v = 0;
1328 				for (xx = f; xx > 0; xx--)
1329 				{
1330 					for (yy = f; yy > 0; yy--)
1331 					{
1332 						v += *s;
1333 						s += fwd;
1334 					}
1335 					s -= back;
1336 				}
1337 				*d++ = v >> factor;
1338 				s -= back2;
1339 			}
1340 			s += fwd2;
1341 		}
1342 		/* Do any strays */
1343 		x += f;
1344 		if (x > 0)
1345 		{
1346 			int div = x * f;
1347 			int fwd4 = (x-1) * n;
1348 			int back4 = x*n-1;
1349 			for (nn = n; nn > 0; nn--)
1350 			{
1351 				int v = 0;
1352 				for (xx = x; xx > 0; xx--)
1353 				{
1354 					for (yy = f; yy > 0; yy--)
1355 					{
1356 						v += *s;
1357 						s += fwd;
1358 					}
1359 					s -= back;
1360 				}
1361 				*d++ = v / div;
1362 				s -= back4;
1363 			}
1364 			s += fwd4;
1365 		}
1366 		s += fwd3;
1367 	}
1368 	/* Do any stray line */
1369 	y += f;
1370 	if (y > 0)
1371 	{
1372 		int div = y * f;
1373 		int back5 = fwd * y - n;
1374 		for (x = w - f; x >= 0; x -= f)
1375 		{
1376 			for (nn = n; nn > 0; nn--)
1377 			{
1378 				int v = 0;
1379 				for (xx = f; xx > 0; xx--)
1380 				{
1381 					for (yy = y; yy > 0; yy--)
1382 					{
1383 						v += *s;
1384 						s += fwd;
1385 					}
1386 					s -= back5;
1387 				}
1388 				*d++ = v / div;
1389 				s -= back2;
1390 			}
1391 			s += fwd2;
1392 		}
1393 		/* Do any stray at the end of the stray line */
1394 		x += f;
1395 		if (x > 0)
1396 		{
1397 			int back4 = x * n - 1;
1398 			div = x * y;
1399 			for (nn = n; nn > 0; nn--)
1400 			{
1401 				int v = 0;
1402 				for (xx = x; xx > 0; xx--)
1403 				{
1404 					for (yy = y; yy > 0; yy--)
1405 					{
1406 						v += *s;
1407 						s += fwd;
1408 					}
1409 					s -= back5;
1410 				}
1411 				*d++ = v / div;
1412 				s -= back4;
1413 			}
1414 		}
1415 	}
1416 #endif
1417 	tile->w = dst_w;
1418 	tile->h = dst_h;
1419 	tile->stride = dst_w * n;
1420 	if (dst_h > INT_MAX / (dst_w * n))
1421 		fz_throw(ctx, FZ_ERROR_MEMORY, "pixmap too large");
1422 	tile->samples = fz_realloc(ctx, tile->samples, (size_t)dst_h * dst_w * n);
1423 }
1424 
1425 void
fz_set_pixmap_resolution(fz_context * ctx,fz_pixmap * pix,int xres,int yres)1426 fz_set_pixmap_resolution(fz_context *ctx, fz_pixmap *pix, int xres, int yres)
1427 {
1428 	pix->xres = xres;
1429 	pix->yres = yres;
1430 }
1431 
1432 /*
1433 	Return the md5 digest for a pixmap
1434 */
1435 void
fz_md5_pixmap(fz_context * ctx,fz_pixmap * pix,unsigned char digest[16])1436 fz_md5_pixmap(fz_context *ctx, fz_pixmap *pix, unsigned char digest[16])
1437 {
1438 	fz_md5 md5;
1439 
1440 	fz_md5_init(&md5);
1441 	if (pix)
1442 	{
1443 		unsigned char *s = pix->samples;
1444 		int h = pix->h;
1445 		int ss = pix->stride;
1446 		int len = pix->w * pix->n;
1447 		while (h--)
1448 		{
1449 			fz_md5_update(&md5, s, len);
1450 			s += ss;
1451 		}
1452 	}
1453 	fz_md5_final(&md5, digest);
1454 }
1455 
1456 #ifdef HAVE_VALGRIND
fz_valgrind_pixmap(const fz_pixmap * pix)1457 int fz_valgrind_pixmap(const fz_pixmap *pix)
1458 {
1459 	int w, h, n, total;
1460 	int ww, hh, nn;
1461 	int stride;
1462 	const unsigned char *p = pix->samples;
1463 
1464 	if (pix == NULL)
1465 		return 0;
1466 
1467 	total = 0;
1468 	ww = pix->w;
1469 	hh = pix->h;
1470 	nn = pix->n;
1471 	stride = pix->stride - ww*nn;
1472 	for (h = 0; h < hh; h++)
1473 	{
1474 		for (w = 0; w < ww; w++)
1475 			for (n = 0; n < nn; n++)
1476 				if (*p++) total ++;
1477 		p += stride;
1478 	}
1479 	return total;
1480 }
1481 #endif /* HAVE_VALGRIND */
1482 
1483 fz_pixmap *
fz_convert_indexed_pixmap_to_base(fz_context * ctx,const fz_pixmap * src)1484 fz_convert_indexed_pixmap_to_base(fz_context *ctx, const fz_pixmap *src)
1485 {
1486 	fz_pixmap *dst;
1487 	fz_colorspace *base;
1488 	const unsigned char *s;
1489 	unsigned char *d;
1490 	int y, x, k, n, high;
1491 	unsigned char *lookup;
1492 	int s_line_inc, d_line_inc;
1493 
1494 	if (src->colorspace->type != FZ_COLORSPACE_INDEXED)
1495 		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot convert non-indexed pixmap");
1496 	if (src->n != 1 + src->alpha)
1497 		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot convert indexed pixmap mis-matching components");
1498 
1499 	base = src->colorspace->u.indexed.base;
1500 	high = src->colorspace->u.indexed.high;
1501 	lookup = src->colorspace->u.indexed.lookup;
1502 	n = base->n;
1503 
1504 	dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha);
1505 	s = src->samples;
1506 	d = dst->samples;
1507 	s_line_inc = src->stride - src->w * src->n;
1508 	d_line_inc = dst->stride - dst->w * dst->n;
1509 
1510 	if (src->alpha)
1511 	{
1512 		for (y = 0; y < src->h; y++)
1513 		{
1514 			for (x = 0; x < src->w; x++)
1515 			{
1516 				int v = *s++;
1517 				int a = *s++;
1518 				int aa = a + (a>>7);
1519 				v = fz_mini(v, high);
1520 				for (k = 0; k < n; k++)
1521 					*d++ = (aa * lookup[v * n + k] + 128)>>8;
1522 				*d++ = a;
1523 			}
1524 			s += s_line_inc;
1525 			d += d_line_inc;
1526 		}
1527 	}
1528 	else
1529 	{
1530 		for (y = 0; y < src->h; y++)
1531 		{
1532 			for (x = 0; x < src->w; x++)
1533 			{
1534 				int v = *s++;
1535 				v = fz_mini(v, high);
1536 				for (k = 0; k < n; k++)
1537 					*d++ = lookup[v * n + k];
1538 			}
1539 			s += s_line_inc;
1540 			d += d_line_inc;
1541 		}
1542 	}
1543 
1544 	if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1545 		dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1546 	else
1547 		dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1548 
1549 	return dst;
1550 }
1551 
1552 fz_pixmap *
fz_convert_separation_pixmap_to_base(fz_context * ctx,const fz_pixmap * src)1553 fz_convert_separation_pixmap_to_base(fz_context *ctx, const fz_pixmap *src)
1554 {
1555 	fz_pixmap *dst;
1556 	fz_colorspace *ss, *base;
1557 	const unsigned char *s;
1558 	unsigned char *d;
1559 	int y, x, k, sn, bn, a;
1560 	float src_v[FZ_MAX_COLORS];
1561 	float base_v[FZ_MAX_COLORS];
1562 	int s_line_inc, d_line_inc;
1563 
1564 	ss = src->colorspace;
1565 
1566 	if (ss->type != FZ_COLORSPACE_SEPARATION)
1567 		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot expand non-separation pixmap");
1568 	if (src->n != ss->n + src->alpha)
1569 		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot expand separation pixmap mis-matching alpha channel");
1570 
1571 	base = ss->u.separation.base;
1572 	dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha);
1573 	fz_clear_pixmap(ctx, dst);
1574 	fz_try(ctx)
1575 	{
1576 		s = src->samples;
1577 		d = dst->samples;
1578 		s_line_inc = src->stride - src->w * src->n;
1579 		d_line_inc = dst->stride - dst->w * dst->n;
1580 		sn = ss->n;
1581 		bn = base->n;
1582 
1583 		if (base->type == FZ_COLORSPACE_LAB)
1584 		{
1585 			if (src->alpha)
1586 			{
1587 				for (y = 0; y < src->h; y++)
1588 				{
1589 					for (x = 0; x < src->w; x++)
1590 					{
1591 						for (k = 0; k < sn; ++k)
1592 							src_v[k] = *s++ / 255.0f;
1593 						a = *s++;
1594 						ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1595 						*d++ = (base_v[0] / 100) * 255.0f;
1596 						*d++ = base_v[1] + 128;
1597 						*d++ = base_v[2] + 128;
1598 						*d++ = a;
1599 					}
1600 					s += s_line_inc;
1601 					d += d_line_inc;
1602 				}
1603 			}
1604 			else
1605 			{
1606 				for (y = 0; y < src->h; y++)
1607 				{
1608 					for (x = 0; x < src->w; x++)
1609 					{
1610 						for (k = 0; k < sn; ++k)
1611 							src_v[k] = *s++ / 255.0f;
1612 						ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1613 						*d++ = (base_v[0] / 100) * 255.0f;
1614 						*d++ = base_v[1] + 128;
1615 						*d++ = base_v[2] + 128;
1616 					}
1617 					s += s_line_inc;
1618 					d += d_line_inc;
1619 				}
1620 			}
1621 		}
1622 		else
1623 		{
1624 			if (src->alpha)
1625 			{
1626 				for (y = 0; y < src->h; y++)
1627 				{
1628 					for (x = 0; x < src->w; x++)
1629 					{
1630 						for (k = 0; k < sn; ++k)
1631 							src_v[k] = *s++ / 255.0f;
1632 						a = *s++;
1633 						ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1634 						for (k = 0; k < bn; ++k)
1635 							*d++ = base_v[k] * 255.0f;
1636 						*d++ = a;
1637 					}
1638 					s += s_line_inc;
1639 					d += d_line_inc;
1640 				}
1641 			}
1642 			else
1643 			{
1644 				for (y = 0; y < src->h; y++)
1645 				{
1646 					for (x = 0; x < src->w; x++)
1647 					{
1648 						for (k = 0; k < sn; ++k)
1649 							src_v[k] = *s++ / 255.0f;
1650 						ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1651 						for (k = 0; k < bn; ++k)
1652 							*d++ = base_v[k] * 255.0f;
1653 					}
1654 					s += s_line_inc;
1655 					d += d_line_inc;
1656 				}
1657 			}
1658 		}
1659 
1660 		if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1661 			dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1662 		else
1663 			dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1664 	}
1665 	fz_catch(ctx)
1666 	{
1667 		fz_drop_pixmap(ctx, dst);
1668 		fz_rethrow(ctx);
1669 	}
1670 
1671 	return dst;
1672 }
1673