1 /* dip.c
2  * Digital Image Processing routines
3  * (c) 2000-2002 Karel 'Clock' Kulhavy
4  * This file is a part of the Links program, released under GPL.
5  * This does various utilities for digital image processing including font
6  * rendering.
7  */
8 
9 #include "cfg.h"
10 
11 #ifdef G
12 
13 #include "links.h"
14 
15 #ifdef HAVE_MATH_H
16 #include <math.h>
17 #endif /* HAVE_MATH_H */
18 
19 /* #define this if you want to report missing letters to stderr.
20  * Leave it commented up for normal operation and releases! */
21 /* #define REPORT_UNKNOWN 1 */
22 
23 unsigned aspect=65536; /* aspect=65536 for 320x240
24 			* aspect=157286 for 640x200 (tall pixels)
25 			* Defines aspect ratio of screen pixels.
26 			* aspect=(196608*xsize+ysize<<1)/(ysize<<1);
27 			* Default is 65536 because we assume square pixel
28 			* when not specified otherwise. Aspect is ratio of
29 			* the pixel height (in milimeters) to pixel width,
30 			* multiplied by 65536. */
31 
32 /* Limitation: No input image's dimension may exceed 2^(32-1-8) pixels.
33  */
34 
35 /* Each input byte represents 1 byte (gray). The question whether 0 is
36  * black or 255 is black doesn't matter.
37  */
38 
39 /* These constants represent contrast-enhancement and sharpen filter (which is one filter
40  * together) that is applied onto the letters to enhance their appearance at low height.
41  * They were determined by experiment for several values, interpolated, checked and tuned.
42  * If you change them, don't wonder if the letters start to look strange.
43  * The numers in the comments denote which height the line applies for.
44  */
45 static_const float fancy_constants[64]={
46 	(float)0,(float)3,	/*  1 */
47 	(float).1,(float)3,	/*  2 */
48 	(float).2,(float)3,	/*  3 */
49 	(float).3,(float)2.9,	/*  4 */
50 	(float).4,(float)2.7,	/*  5 */
51 	(float).4,(float)2.5,	/*  6 */
52 	(float).4,(float)2,	/*  7 */
53 	(float).5,(float)2,	/*  8 */
54 	(float).4,(float)2,	/*  9 */
55 	(float).38,(float)1.9,	/* 10 */
56 	(float).36,(float)1.8,	/* 11 */
57 	(float).33,(float)1.7,	/* 12 */
58 	(float).30,(float)1.6,	/* 13 */
59 	(float).25,(float)1.5,	/* 14 */
60 	(float).20,(float)1.5,	/* 15 */
61 	(float).15,(float)1.5,	/* 16 */
62 	(float).14,(float)1.5,	/* 17 */
63 	(float).13,(float)1.5,	/* 18 */
64 	(float).12,(float)1.5,	/* 19 */
65 	(float).12,(float)1.5,	/* 20 */
66 	(float).12,(float)1.5,	/* 21 */
67 	(float).12,(float)1.5,	/* 22 */
68 	(float).11,(float)1.5,	/* 23 */
69 	(float).10,(float)1.4,	/* 24 */
70 	(float).09,(float)1.3,	/* 25 */
71 	(float).08,(float)1.3,	/* 26 */
72 	(float).04,(float)1.2,	/* 27 */
73 	(float).04,(float)1.2,	/* 28 */
74 	(float).02,(float)1.1,	/* 29 */
75 	(float).02,(float)1.1,	/* 30 */
76 	(float).01,(float)1,	/* 31 */
77 	(float).01,(float)1	/* 32 */
78 };
79 
80 
81 /* This shall be hopefully reasonably fast and portable
82  * We assume ix is <65536. If not, the letters will be smaller in
83  * horizontal dimension (because of overflow) but this will not cause
84  * a segfault. 65536 pixels wide bitmaps are not normal and will anyway
85  * exhaust the memory.
86  */
compute_width(int ix,int iy,int required_height)87 int compute_width(int ix, int iy, int required_height)
88 {
89 	int width;
90 	unsigned long reg;
91 
92 	reg=(unsigned long)aspect*(unsigned long)required_height;
93 
94 	if (reg>=0x1000000UL) {
95 		/* It's big */
96 		reg=(reg+32768)>>16;
97 		width=(int)((reg*ix+(iy>>1))/iy);
98 	}else{
99 		/* It's small */
100 		reg=(reg+128)>>8;
101 		iy<<=8;
102 		width=(int)((reg*ix+(iy>>1))/iy);
103 	}
104 	if (width<1) width=1;
105 	return width;
106 }
107 
108 static struct lru font_cache;
109 			/* This is a cache for screen-ready colored bitmaps
110 			 * of lettrs and/or alpha channels for these (are the
111 			 * same size, only one byte per pixel and are used
112 			 * for letters with an image under them )
113 			 */
114 
115 #if defined(__i686__) || defined(__athlon__) || defined(__SSE2__) || defined(__x86_64__) || defined(__aarch64__) || defined(__alpha) || defined(__hppa)
116 /*
117  * On modern processors it is faster to do this in floating point.
118  * Do it only if we are sure that the coprocessor is present.
119  */
120 typedef double scale_t;
121 #define USE_FP_SCALE
122 #elif defined(HAVE_LONG_LONG)
123 typedef unsigned long long scale_t;
124 #else
125 /*
126  * This may overflow, but systems without long long are very old
127  * and we will rather accept overflow on big images (65536 pixels)
128  * than slowing down the process unacceptably with possibly emulated FPU.
129  */
130 typedef unsigned long scale_t;
131 #endif
132 
133 /* Each input byte represents 1 byte (gray). The question whether 0 is
134  * black or 255 is black doesn't matter.
135  */
136 
add_col_gray(unsigned * my_restrict col_buf,unsigned char * my_restrict ptr,size_t line_skip,size_t n,unsigned weight)137 static void add_col_gray(unsigned *my_restrict col_buf, unsigned char *my_restrict ptr, size_t line_skip, size_t n, unsigned weight)
138 {
139 	for (;n;n--) {
140 		*col_buf+=weight*(*ptr);
141 		ptr+=line_skip;
142 		col_buf++;
143 	}
144 }
145 
146  /* We assume unsigned short holds at least 16 bits. */
add_row_gray(unsigned * my_restrict row_buf,unsigned char * my_restrict ptr,size_t n,unsigned weight)147 static void add_row_gray(unsigned *my_restrict row_buf, unsigned char *my_restrict ptr, size_t n, unsigned weight)
148 {
149 	for (;n;n--) {
150 		*row_buf+=weight**ptr;
151 		ptr++;
152 		row_buf++;
153 	}
154 }
155 
156 /* line_skip is in pixels. The column contains the whole pixels (R G B)
157  * We assume unsigned short holds at least 16 bits. */
158 #if defined(__ICC) && defined(USE_FP_SCALE)
159 /* ICC misoptimizes this function when inlining it */
160 ATTR_NOINLINE
161 #endif
add_col_color(scale_t * my_restrict col_buf,volatile unsigned short * my_restrict ptr,size_t line_skip,size_t n,ulonglong weight)162 static void add_col_color(scale_t *my_restrict col_buf,
163 #if defined(__GNUC__) && __GNUC__ == 3
164 	volatile
165 #endif
166 	unsigned short *my_restrict ptr,
167 	size_t line_skip, size_t n, ulonglong weight)
168 {
169 	if (!weight) return;
170 #ifndef USE_FP_SCALE
171 	if (weight < 0x10000) {
172 		unsigned short weight_16 = (unsigned short)weight;
173 		for (;n;n--) {
174 			col_buf[0]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[0]);
175 			col_buf[1]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[1]);
176 			col_buf[2]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[2]);
177 			ptr+=line_skip;
178 			col_buf+=3;
179 		}
180 	} else
181 #endif
182 	{
183 		scale_t w = (scale_t)(longlong)weight;
184 		for (;n;n--) {
185 			col_buf[0]+=w*ptr[0];
186 			col_buf[1]+=w*ptr[1];
187 			col_buf[2]+=w*ptr[2];
188 			ptr+=line_skip;
189 			col_buf+=3;
190 		}
191 	}
192 }
193 
194 /* n is in pixels. pixel is 3 unsigned shorts in series */
195  /* We assume unsigned short holds at least 16 bits. */
add_row_color(scale_t * my_restrict row_buf,volatile unsigned short * my_restrict ptr,size_t n,ulonglong weight)196 static void add_row_color(scale_t *my_restrict row_buf,
197 #if defined(__GNUC__) && __GNUC__ == 3
198 	volatile
199 #endif
200 	unsigned short *my_restrict ptr,
201 	size_t n, ulonglong weight)
202 {
203 	if (!weight) return;
204 #ifndef USE_FP_SCALE
205 	if (weight < 0x10000) {
206 		unsigned short weight_16 = (unsigned short)weight;
207 		for (;n;n--) {
208 			row_buf[0]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[0]);
209 			row_buf[1]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[1]);
210 			row_buf[2]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[2]);
211 			ptr+=3;
212 			row_buf+=3;
213 		}
214 	} else
215 #endif
216 	{
217 		scale_t w = (scale_t)(longlong)weight;
218 		for (;n;n--) {
219 			row_buf[0]+=w*ptr[0];
220 			row_buf[1]+=w*ptr[1];
221 			row_buf[2]+=w*ptr[2];
222 			ptr+=3;
223 			row_buf+=3;
224 		}
225 	}
226 }
227 
228 /* We assume unsigned holds at least 32 bits */
emit_and_bias_col_gray(unsigned * my_restrict col_buf,unsigned char * my_restrict out,size_t line_skip,size_t n,unsigned weight)229 static void emit_and_bias_col_gray(unsigned *my_restrict col_buf, unsigned char *my_restrict out,
230 	size_t line_skip, size_t n, unsigned weight)
231 {
232 	unsigned half=weight>>1;
233 
234 	for (;n;n--) {
235 		*out=*col_buf/weight;
236 		out+=line_skip;
237 		*col_buf++=half;
238 	}
239 }
240 
241 /* We assume unsigned holds at least 32 bits */
emit_and_bias_row_gray(unsigned * my_restrict row_buf,unsigned char * my_restrict out,size_t n,unsigned weight)242 static void emit_and_bias_row_gray(unsigned *my_restrict row_buf, unsigned char *my_restrict out,
243 	size_t n, unsigned weight)
244 {
245 	unsigned half=weight>>1;
246 
247 	for (;n;n--) {
248 		*out++=*row_buf/weight;
249 		*row_buf++=half;
250 	}
251 }
252 
253 /* We assume unsigned holds at least 32 bits */
bias_buf_gray(unsigned * my_restrict col_buf,size_t n,unsigned half)254 static void bias_buf_gray(unsigned *my_restrict col_buf, size_t n, unsigned half)
255 {
256 	for (;n;n--) *col_buf++=half;
257 }
258 
259 /* We assume unsigned holds at least 32 bits */
bias_buf_color(scale_t * my_restrict col_buf,size_t n,scale_t half)260 static void bias_buf_color(scale_t *my_restrict col_buf, size_t n, scale_t half)
261 {
262 	for (;n;n--) {
263 		col_buf[0]=half;
264 		col_buf[1]=half;
265 		col_buf[2]=half;
266 		col_buf+=3;
267 	}
268 	/* System activated */
269 }
270 
271 #ifdef USE_FP_SCALE
272 #define	op(x)	((x) * inv_weight)
273 #else
274 #define op(x)	(sizeof(unsigned long) < sizeof(scale_t) && (x) == (unsigned long)(x) ? (unsigned long)(x) / weight : (x) / weight)
275 #endif
276 
277 /* line skip is in pixels. Pixel is 3*unsigned short */
278 /* We assume unsigned holds at least 32 bits */
279 /* We assume unsigned short holds at least 16 bits. */
emit_and_bias_col_color(scale_t * my_restrict col_buf,unsigned short * my_restrict out,size_t line_skip,size_t n,unsigned weight)280 static void emit_and_bias_col_color(scale_t *my_restrict col_buf,
281 	unsigned short *my_restrict out, size_t line_skip, size_t n, unsigned weight)
282 {
283 	scale_t half=(scale_t)weight / 2;
284 #ifdef USE_FP_SCALE
285 	scale_t inv_weight = (scale_t)1 / weight;
286 #endif
287 	for (;n;n--) {
288 		out[0]=(unsigned short)op(col_buf[0]);
289 		col_buf[0]=half;
290 		out[1]=(unsigned short)op(col_buf[1]);
291 		col_buf[1]=half;
292 		/* The following line is an enemy of the State and will be
293 		 * prosecuted according to the Constitution of The United States
294 		 * Cap. 20/3 ix. Sel. Bill 12/1920
295 		 * Moses 12/20 Erizea farizea 2:2:1:14
296 		 */
297 		out[2]=(unsigned short)op(col_buf[2]);
298 		col_buf[2]=half;
299 		out+=line_skip;
300 		col_buf+=3;
301 	}
302 }
303 
304 /* n is in pixels. pixel is 3 unsigned shorts in series. */
305 /* We assume unsigned holds at least 32 bits */
306 /* We assume unsigned short holds at least 16 bits. */
emit_and_bias_row_color(scale_t * my_restrict row_buf,unsigned short * my_restrict out,size_t n,unsigned weight)307 static void emit_and_bias_row_color(scale_t *my_restrict row_buf,
308 	unsigned short *my_restrict out, size_t n, unsigned weight)
309 {
310 	scale_t half=(scale_t)weight / 2;
311 #ifdef USE_FP_SCALE
312 	scale_t inv_weight = (scale_t)1 / weight;
313 #endif
314 	for (;n;n--) {
315 		out[0]=(unsigned short)op(row_buf[0]);
316 		row_buf[0]=half;
317 		out[1]=(unsigned short)op(row_buf[1]);
318 		row_buf[1]=half;
319 		out[2]=(unsigned short)op(row_buf[2]);
320 		row_buf[2]=half;
321 		out+=3;
322 		row_buf+=3;
323 	}
324 }
325 
326 #undef op
327 
328 /* For enlargement only -- does linear filtering.
329  * Allocates output and frees input.
330  * We assume unsigned holds at least 32 bits */
enlarge_gray_horizontal(unsigned char * in,size_t ix,size_t y,unsigned char ** out,size_t ox)331 static void enlarge_gray_horizontal(unsigned char *in, size_t ix, size_t y, unsigned char **out, size_t ox)
332 {
333 	unsigned *col_buf;
334 	size_t total;
335 	size_t out_pos,in_pos,in_begin,in_end;
336 	unsigned half = (unsigned)((ox - 1) >> 1);
337 	unsigned char *outptr;
338 	unsigned char *inptr;
339 
340 	if (ox && ox * y / ox != y) overalloc();
341 	if (ox * y > MAX_SIZE_T) overalloc();
342 	outptr=mem_alloc(ox * y);
343 	inptr=in;
344 	*out=outptr;
345 	if (ix==1) {
346 		/* Dull copying */
347 		for (;y;y--) {
348 			memset(outptr,*inptr,ox);
349 			outptr+=ox;
350 			inptr++;
351 		}
352 		mem_free(in);
353 	}else{
354 		total=(ix-1)*(ox-1);
355 		if (y > MAX_SIZE_T / sizeof(*col_buf)) overalloc();
356 		col_buf=mem_alloc(y * sizeof(*col_buf));
357 		bias_buf_gray(col_buf, y, half);
358 		out_pos=0;
359 		in_pos=0;
360 		again:
361 		in_begin=in_pos;
362 		in_end=in_pos+ox-1;
363 		add_col_gray(col_buf, inptr, ix, y, (unsigned)(in_end - out_pos));
364 		add_col_gray(col_buf, inptr + 1, ix, y, (unsigned)(out_pos - in_begin));
365 		emit_and_bias_col_gray(col_buf, outptr, ox, y, (unsigned)(ox - 1));
366 		outptr++;
367 		out_pos+=ix-1;
368 		if (out_pos>in_end) {
369 			in_pos=in_end;
370 			inptr++;
371 		}
372 		if (out_pos>total) {
373 			mem_free(in);
374 			mem_free(col_buf);
375 			return;
376 		}
377 		goto again;
378 	}
379 	/* Rohan, oh Rohan... */
380 	/* ztracena zeme :) */
381 }
382 
multiply_int(size_t a,size_t b)383 static inline longlong multiply_int(size_t a, size_t b)
384 {
385 #ifndef HAVE_LONG_LONG
386 	volatile
387 #endif
388 	longlong result = (ulonglong)a * (ulonglong)b;
389 #if !defined(__TINYC__) && !defined(HAVE_LONG_LONG)
390 	if (result / a != (longlong)b) {
391 		/*fprintf(stderr, "%lld, %lld, %d, %d\n", result / a, result, a, b);*/
392 		overflow();
393 	}
394 #endif
395 #ifndef HAVE_LONG_LONG
396 	if (result == result + 1 || result == result - 1)
397 		overflow();
398 #endif
399 	return result;
400 }
401 
402 /* For enlargement only -- does linear filtering
403  * Frees input and allocates output.
404  * We assume unsigned holds at least 32 bits
405  */
enlarge_color_horizontal(unsigned short * in,size_t ix,size_t y,unsigned short ** outa,size_t ox)406 static void enlarge_color_horizontal(unsigned short *in, size_t ix, size_t y,
407 	unsigned short **outa, size_t ox)
408 {
409 #ifdef HAVE_OPENMP
410 	int use_omp;
411 #endif
412 	int n_threads;
413 	size_t alloc_size;
414 	scale_t *col_buf;
415 	size_t a;
416 	size_t skip=3*ix;
417 	size_t oskip=3*ox;
418 	unsigned short *out;
419 
420 	if (!in) {
421 		*outa = NULL;
422 		return;
423 	}
424 
425 	if (ix==ox) {
426 		*outa=in;
427 		return;
428 	}
429 	if (ox && ox * y / ox != y) overalloc();
430 	if (ox * y > MAX_SIZE_T / 3 / sizeof(*out)) overalloc();
431 	out = mem_alloc_mayfail(sizeof(*out) * 3 * ox * y);
432 	*outa=out;
433 	if (!out) {
434 		mem_free(in);
435 		return;
436 	}
437 	if (ix==1) {
438 		unsigned short *inp = in;
439 		for (;y;y--,inp+=3) for (a=ox;a;a--,out+=3) {
440 			out[0]=inp[0];
441 			out[1]=inp[1];
442 			out[2]=inp[2];
443 		}
444 		mem_free(in);
445 		return;
446 	}
447 	multiply_int(ix-1,ox-1);
448 
449 	n_threads = omp_start();
450 #ifdef HAVE_OPENMP
451 	use_omp = !OPENMP_NONATOMIC & (n_threads > 1) & (ox >= 24);
452 	if (!use_omp)
453 		n_threads = 1;
454 #endif
455 	if (y > (MAX_SIZE_T - SMP_ALIGN + 1) / 3 / sizeof(*col_buf)) overalloc();
456 	alloc_size = y * 3 * sizeof(*col_buf);
457 	alloc_size = (alloc_size + SMP_ALIGN - 1) & ~(SMP_ALIGN - 1);
458 	if (alloc_size > MAX_SIZE_T / n_threads) overalloc();
459 	col_buf = mem_alloc_mayfail(alloc_size * n_threads);
460 	if (!col_buf) goto skip_omp;
461 #ifdef HAVE_OPENMP
462 #pragma omp parallel default(none) firstprivate(col_buf,alloc_size,in,out,ix,ox,y,skip,oskip) if (use_omp)
463 #endif
464 	{
465 		scale_t *thread_col_buf;
466 		ssize_t out_idx;
467 		thread_col_buf = (scale_t *)((char *)col_buf + alloc_size * omp_get_thread_num());
468 		bias_buf_color(thread_col_buf, y, (scale_t)(ox - 1) / 2);
469 #ifdef HAVE_OPENMP
470 #pragma omp for nowait
471 #endif
472 		for (out_idx = 0; out_idx <= (ssize_t)(ox - 1); out_idx++) {
473 			ulonglong out_pos, in_pos, in_end;
474 			size_t in_idx;
475 			out_pos = (ulonglong)out_idx * (ix - 1);
476 			if (out_idx)
477 				in_idx = (out_pos - 1) / (ox - 1);
478 			else
479 				in_idx = 0;
480 			in_pos = (ulonglong)in_idx * (ox - 1);
481 			in_end = in_pos + (ox - 1);
482 			add_col_color(thread_col_buf, in + in_idx * 3, skip, y,
483 				in_end - out_pos);
484 			add_col_color(thread_col_buf, in + (in_idx + 1) * 3, skip, y,
485 				out_pos - in_pos);
486 			emit_and_bias_col_color(thread_col_buf, out + out_idx * 3, oskip, y, (unsigned)(ox - 1));
487 		}
488 	}
489 skip_omp:
490 	omp_end();
491 
492 	mem_free(in);
493 	if (col_buf) mem_free(col_buf);
494 	else {
495 		mem_free(out);
496 		*outa = NULL;
497 	}
498 }
499 
500 /* Works for both enlarging and diminishing. Linear resample, no low pass.
501  * Automatically mem_frees the "in" and allocates "out". */
502 /* We assume unsigned holds at least 32 bits */
scale_gray_horizontal(unsigned char * in,size_t ix,size_t y,unsigned char ** out,size_t ox)503 static void scale_gray_horizontal(unsigned char *in, size_t ix, size_t y, unsigned char **out, size_t ox)
504 {
505 	unsigned *col_buf;
506 	size_t total=ix * ox;
507 	size_t out_pos, in_pos, in_begin, in_end, out_end;
508 	unsigned char *outptr;
509 	unsigned char *inptr;
510 
511 	if (ix<ox) {
512 		enlarge_gray_horizontal(in,ix,y,out,ox);
513 		return;
514 	}else if (ix==ox) {
515 		*out=in;
516 		return;
517 	}
518 	if (ox && ox * y / ox != y) overalloc();
519 	if (ox * y > MAX_SIZE_T) overalloc();
520 	outptr=mem_alloc(ox*y);
521 	inptr=in;
522 	*out=outptr;
523 	if (y > MAX_SIZE_T / sizeof(*col_buf)) overalloc();
524 	col_buf = mem_alloc(y * sizeof(*col_buf));
525 	bias_buf_gray(col_buf, y, (unsigned)(ix >> 1));
526 	out_pos=0;
527 	in_pos=0;
528 	again:
529 	in_begin=in_pos;
530 	in_end=in_pos+ox;
531 	out_end=out_pos+ix;
532 	if (in_begin<out_pos)in_begin=out_pos;
533 	if (in_end>out_end)in_end=out_end;
534 	add_col_gray(col_buf, inptr, ix, y, (unsigned)(in_end - in_begin));
535 	in_end=in_pos+ox;
536 	if (out_end>=in_end) {
537 		in_pos=in_end;
538 		inptr++;
539 	}
540 	if (out_end<=in_end) {
541 			emit_and_bias_col_gray(col_buf, outptr, ox, y, (unsigned)ix);
542 			out_pos=out_pos+ix;
543 			outptr++;
544 	}
545 	if (out_pos==total) {
546 		mem_free(in);
547 		mem_free(col_buf);
548 		return;
549 	}
550 	goto again;
551 }
552 
553 /* Works for both enlarging and diminishing. Linear resample, no low pass.
554  * Does only one color component.
555  * Frees ina and allocates outa.
556  * If ox*3<=ix, and display_optimize, performs optimization for LCD.
557  */
scale_color_horizontal(unsigned short * in,size_t ix,size_t y,unsigned short ** outa,size_t ox)558 static void scale_color_horizontal(unsigned short *in, size_t ix, size_t y, unsigned short **outa, size_t ox)
559 {
560 #ifdef HAVE_OPENMP
561 	int use_omp;
562 #endif
563 	int n_threads;
564 	size_t alloc_size;
565 	scale_t *col_buf;
566 	size_t skip = 3 * ix;
567 	size_t oskip = 3 * ox;
568 	unsigned short *out;
569 
570 	if (!in) {
571 		*outa = NULL;
572 		return;
573 	}
574 
575 	if (ix==ox) {
576 		*outa=in;
577 		return;
578 	}
579 	if (ix<ox) {
580 		enlarge_color_horizontal(in,ix,y,outa,ox);
581 		return;
582 	}
583 	multiply_int(ix,ox);
584 	if (ox && ox * y / ox != y) overalloc();
585 	if (ox * y > MAX_SIZE_T / 3 / sizeof(*out)) overalloc();
586 	out = mem_alloc_mayfail(sizeof(*out) * 3 * ox * y);
587 	*outa=out;
588 	if (!out) {
589 		mem_free(in);
590 		return;
591 	}
592 
593 	n_threads = omp_start();
594 #ifdef HAVE_OPENMP
595 	use_omp = !OPENMP_NONATOMIC & (n_threads > 1) & (ox >= 24);
596 	if (!use_omp)
597 		n_threads = 1;
598 #endif
599 	if (y > (MAX_SIZE_T - SMP_ALIGN + 1) / 3 / sizeof(*col_buf)) overalloc();
600 	alloc_size = y * 3 * sizeof(*col_buf);
601 	alloc_size = (alloc_size + SMP_ALIGN - 1) & ~(SMP_ALIGN - 1);
602 	if (alloc_size > MAX_SIZE_T / n_threads) overalloc();
603 	col_buf = mem_alloc_mayfail(alloc_size * n_threads);
604 	if (!col_buf) goto skip_omp;
605 #ifdef HAVE_OPENMP
606 #pragma omp parallel default(none) firstprivate(col_buf,alloc_size,in,out,ix,ox,y,skip,oskip) if (use_omp)
607 #endif
608 	{
609 		scale_t *thread_col_buf;
610 		ssize_t out_idx;
611 		thread_col_buf = (scale_t *)((char *)col_buf + alloc_size * omp_get_thread_num());
612 		bias_buf_color(thread_col_buf, y, (scale_t)ix / 2);
613 #ifdef HAVE_OPENMP
614 #pragma omp for nowait
615 #endif
616 		for (out_idx = 0; out_idx < (ssize_t)ox; out_idx++) {
617 			ulonglong out_pos, out_end, in_pos;
618 			size_t in_idx;
619 			out_pos = (ulonglong)out_idx * ix;
620 			out_end = out_pos + ix;
621 			in_idx = out_pos / ox;
622 			in_pos = (ulonglong)in_idx * ox;
623 			do {
624 				ulonglong in_begin, in_end;
625 				in_begin = in_pos;
626 				in_end = in_pos + ox;
627 				if (in_begin < out_pos) in_begin = out_pos;
628 				if (in_end > out_end) in_end = out_end;
629 				add_col_color(thread_col_buf, in + in_idx * 3, skip, y, in_end - in_begin);
630 				in_idx++;
631 				in_pos += ox;
632 			} while (in_pos < out_end);
633 			emit_and_bias_col_color(thread_col_buf, out + out_idx * 3, oskip, y, (unsigned)ix);
634 		}
635 	}
636 skip_omp:
637 	omp_end();
638 
639 	mem_free(in);
640 	if (col_buf) mem_free(col_buf);
641 	else {
642 		mem_free(out);
643 		*outa = NULL;
644 	}
645 }
646 
647 /* For magnification only. Does linear filtering. */
648 /* We assume unsigned holds at least 32 bits */
enlarge_gray_vertical(unsigned char * in,size_t x,size_t iy,unsigned char ** out,size_t oy)649 static void enlarge_gray_vertical(unsigned char *in, size_t x, size_t iy, unsigned char **out, size_t oy)
650 {
651 	unsigned *row_buf;
652 	size_t total;
653 	size_t out_pos,in_pos,in_begin,in_end;
654 	unsigned half = (unsigned)((oy - 1) >> 1);
655 	unsigned char *outptr;
656 	unsigned char *inptr;
657 
658 	if (iy==1) {
659 		if (x && x * oy / x != oy) overalloc();
660 		if (x * oy > MAX_SIZE_T) overalloc();
661 		outptr = mem_alloc(oy * x);
662 		*out=outptr;
663 		for(;oy;oy--,outptr+=x)
664 			memcpy(outptr,in,x);
665 		mem_free(in);
666 	}
667 	else if (iy==oy) {
668 		*out=in;
669 	}else{
670 		if (x && x * oy / x != oy) overalloc();
671 		if (x * oy > MAX_SIZE_T) overalloc();
672 		outptr = mem_alloc(oy * x);
673 		inptr=in;
674 		*out=outptr;
675 		total=(iy-1)*(oy-1);
676 		if (x > MAX_SIZE_T / sizeof(*row_buf)) overalloc();
677 		row_buf=mem_alloc(x * sizeof(*row_buf));
678 		bias_buf_gray(row_buf, x, half);
679 		out_pos=0;
680 		in_pos=0;
681 		again:
682 		in_begin=in_pos;
683 		in_end=in_pos+oy-1;
684 		add_row_gray(row_buf, inptr, x, (unsigned)(in_end - out_pos));
685 		add_row_gray(row_buf, inptr + x, x, (unsigned)(out_pos - in_begin));
686 		emit_and_bias_row_gray(row_buf, outptr, x, (unsigned)(oy - 1));
687 		outptr+=x;
688 		out_pos+=iy-1;
689 		if (out_pos>in_end) {
690 			in_pos=in_end;
691 			inptr+=x;
692 		}
693 		if (out_pos>total) {
694 			mem_free(in);
695 			mem_free(row_buf);
696 			return;
697 		}
698 		goto again;
699 	}
700 }
701 
702 /* For magnification only. Does linear filtering */
703 /* We assume unsigned holds at least 32 bits */
enlarge_color_vertical(unsigned short * in,size_t x,size_t iy,unsigned short ** outa,size_t oy)704 static void enlarge_color_vertical(unsigned short *in, size_t x, size_t iy, unsigned short **outa, size_t oy)
705 {
706 #ifdef HAVE_OPENMP
707 	int use_omp;
708 #endif
709 	int n_threads;
710 	size_t alloc_size;
711 	scale_t *row_buf;
712 	unsigned short *out;
713 
714 	if (!in) {
715 		*outa = NULL;
716 		return;
717 	}
718 
719 	if (iy==oy) {
720 		*outa=in;
721 		return;
722 	}
723 	/* Rivendell */
724 	if (x && x * oy / x != oy) overalloc();
725 	if (x * oy > MAX_SIZE_T / 3 / sizeof(*out)) overalloc();
726 	out = mem_alloc_mayfail(sizeof(*out) * 3 * oy * x);
727 	*outa=out;
728 	if (!out) {
729 		mem_free(in);
730 		return;
731 	}
732 	if (iy==1) {
733 		for (;oy;oy--) {
734 			memcpy(out,in,3*x*sizeof(*out));
735 			out+=3*x;
736 		}
737 		mem_free(in);
738 		return;
739 	}
740 	multiply_int(iy-1,oy-1);
741 
742 	n_threads = omp_start();
743 #ifdef HAVE_OPENMP
744 	use_omp = (!OPENMP_NONATOMIC | !(x & 3)) & (n_threads > 1) & (oy >= 24);
745 	if (!use_omp)
746 		n_threads = 1;
747 #endif
748 	if (x > (MAX_SIZE_T - SMP_ALIGN + 1) / 3 / sizeof(*row_buf)) overalloc();
749 	alloc_size = x * 3 * sizeof(*row_buf);
750 	alloc_size = (alloc_size + SMP_ALIGN - 1) & ~(SMP_ALIGN - 1);
751 	if (alloc_size > MAX_SIZE_T / n_threads) overalloc();
752 	row_buf = mem_alloc_mayfail(alloc_size * n_threads);
753 	if (!row_buf) goto skip_omp;
754 #ifdef HAVE_OPENMP
755 #pragma omp parallel default(none) firstprivate(row_buf,alloc_size,in,out,x,iy,oy) if (use_omp)
756 #endif
757 	{
758 		scale_t *thread_row_buf;
759 		ssize_t out_idx;
760 		thread_row_buf = (scale_t *)((char *)row_buf + alloc_size * omp_get_thread_num());
761 		bias_buf_color(thread_row_buf,x,(scale_t)(oy-1) / 2);
762 #ifdef HAVE_OPENMP
763 #pragma omp for nowait
764 #endif
765 		for (out_idx = 0; out_idx <= (ssize_t)(oy - 1); out_idx++) {
766 			ulonglong out_pos, in_pos, in_end;
767 			size_t in_idx;
768 			out_pos = (ulonglong)out_idx * (iy - 1);
769 			if (out_idx)
770 				in_idx = (out_pos - 1) / (oy - 1);
771 			else
772 				in_idx = 0;
773 			in_pos = (ulonglong)in_idx * (oy - 1);
774 			in_end = in_pos + oy - 1;
775 			add_row_color(thread_row_buf, in + in_idx * 3 * x, x,
776 				in_end - out_pos);
777 			add_row_color(thread_row_buf, in + (in_idx + 1) * 3 * x, x,
778 				out_pos - in_pos);
779 			emit_and_bias_row_color(thread_row_buf, out + out_idx * 3 * x, x, (unsigned)(oy - 1));
780 		}
781 	}
782 skip_omp:
783 	omp_end();
784 
785 	mem_free(in);
786 	if (row_buf) mem_free(row_buf);
787 	else {
788 		mem_free(out);
789 		*outa = NULL;
790 	}
791 }
792 
793 /* Both enlarges and diminishes. Linear filtering.
794  * Automatically allocates output and frees input.
795  * We assume unsigned holds at least 32 bits */
scale_gray_vertical(unsigned char * in,size_t x,size_t iy,unsigned char ** out,size_t oy)796 static void scale_gray_vertical(unsigned char *in, size_t x, size_t iy, unsigned char **out, size_t oy)
797 {
798 	unsigned *row_buf;
799 	size_t total=iy*oy;
800 	size_t out_pos, in_pos, in_begin, in_end, out_end;
801 	unsigned char *outptr;
802 	unsigned char *inptr;
803 
804 	/* Snow White, Snow White... */
805 	if (iy<oy) {
806 		enlarge_gray_vertical(in,x,iy,out,oy);
807 		return;
808 	}
809 	if (iy==oy) {
810 		*out=in;
811 		return;
812 	}
813 	if (x && x * oy / x != oy) overalloc();
814 	if (x * oy > MAX_SIZE_T) overalloc();
815 	outptr=mem_alloc(x*oy);
816 	inptr=in;
817 	*out=outptr;
818 	if (x > MAX_SIZE_T / sizeof(*row_buf)) overalloc();
819 	row_buf = mem_calloc(x * sizeof(*row_buf));
820 	bias_buf_gray(row_buf, x, (unsigned)(iy >> 1));
821 	out_pos=0;
822 	in_pos=0;
823 	again:
824 	in_begin=in_pos;
825 	in_end=in_pos+oy;
826 	out_end=out_pos+iy;
827 	if (in_begin<out_pos)in_begin=out_pos;
828 	if (in_end>out_end)in_end=out_end;
829 	add_row_gray(row_buf, inptr, x, (unsigned)(in_end - in_begin));
830 	in_end=in_pos+oy;
831 	if (out_end>=in_end) {
832 		in_pos=in_end;
833 		inptr+=x;
834 	}
835 	if (out_end<=in_end) {
836 			emit_and_bias_row_gray(row_buf, outptr, x, (unsigned)iy);
837 			out_pos=out_pos+iy;
838 			outptr+=x;
839 	}
840 	if (out_pos==total) {
841 		mem_free(in);
842 		mem_free(row_buf);
843 		return;
844 	}
845 	goto again;
846 }
847 
848 /* Both enlarges and diminishes. Linear filtering. Sizes are
849    in pixels. Sizes are not in bytes. 1 pixel=3 unsigned shorts.
850    We assume unsigned short can hold at least 16 bits.
851    We assume unsigned holds at least 32 bits.
852  */
scale_color_vertical(unsigned short * in,size_t x,size_t iy,unsigned short ** outa,size_t oy)853 static void scale_color_vertical(unsigned short *in, size_t x, size_t iy, unsigned short **outa, size_t oy)
854 {
855 #ifdef HAVE_OPENMP
856 	int use_omp;
857 #endif
858 	int n_threads;
859 	size_t alloc_size;
860 	scale_t *row_buf;
861 	unsigned short *out;
862 
863 	if (!in) {
864 		*outa = NULL;
865 		return;
866 	}
867 
868 	if (iy==oy) {
869 		*outa=in;
870 		return;
871 	}
872 	if (iy<oy) {
873 		enlarge_color_vertical(in,x,iy,outa,oy);
874 		return;
875 	}
876 	multiply_int(iy,oy);
877 	if (x && x * oy / x != oy) overalloc();
878 	if (x * oy > MAX_SIZE_T / 3 / sizeof(*out)) overalloc();
879 	out = mem_alloc_mayfail(sizeof(*out) * 3 * oy * x);
880 	*outa=out;
881 	if (!out) {
882 		mem_free(in);
883 		return;
884 	}
885 	n_threads = omp_start();
886 #ifdef HAVE_OPENMP
887 	use_omp = (!OPENMP_NONATOMIC | !(x & 3)) & (n_threads > 1) & (oy >= 24);
888 	if (!use_omp)
889 		n_threads = 1;
890 #endif
891 	if (x > (MAX_SIZE_T - SMP_ALIGN + 1) / 3 / sizeof(*row_buf)) overalloc();
892 	alloc_size = x * 3 * sizeof(*row_buf);
893 	alloc_size = (alloc_size + SMP_ALIGN - 1) & ~(SMP_ALIGN - 1);
894 	if (alloc_size > MAX_SIZE_T / n_threads) overalloc();
895 	row_buf = mem_alloc_mayfail(alloc_size * n_threads);
896 	if (!row_buf) goto skip_omp;
897 #ifdef HAVE_OPENMP
898 #pragma omp parallel default(none) firstprivate(row_buf,alloc_size,in,out,x,iy,oy) if (use_omp)
899 #endif
900 	{
901 		scale_t *thread_row_buf;
902 		ssize_t out_idx;
903 		thread_row_buf = (scale_t *)((char *)row_buf + alloc_size * omp_get_thread_num());
904 		bias_buf_color(thread_row_buf,x,(scale_t)iy / 2);
905 #ifdef HAVE_OPENMP
906 #pragma omp for nowait
907 #endif
908 		for (out_idx = 0; out_idx < (ssize_t)oy; out_idx++) {
909 			ulonglong out_pos, out_end, in_pos;
910 			size_t in_idx;
911 			out_pos = (ulonglong)out_idx * iy;
912 			out_end = out_pos + iy;
913 			in_idx = out_pos / oy;
914 			in_pos = (ulonglong)in_idx * oy;
915 			do {
916 				ulonglong in_begin, in_end;
917 				in_begin = in_pos;
918 				in_end = in_pos + oy;
919 				if (in_begin < out_pos) in_begin = out_pos;
920 				if (in_end > out_end) in_end = out_end;
921 				add_row_color(thread_row_buf, in + in_idx * 3 * x, x, in_end - in_begin);
922 				in_idx++;
923 				in_pos += oy;
924 			} while (in_pos < out_end);
925 			emit_and_bias_row_color(thread_row_buf, out + out_idx * 3 * x, x, (unsigned)iy);
926 		}
927 	}
928 skip_omp:
929 	omp_end();
930 
931 	mem_free(in);
932 	if (row_buf) mem_free(row_buf);
933 	else {
934 		mem_free(out);
935 		*outa = NULL;
936 	}
937 }
938 
939 
940 /* Scales grayscale 8-bit map. Both enlarges and diminishes. Uses either low
941  * pass or bilinear filtering. Automatically mem_frees the "in".
942  * Automatically allocates "out".
943  */
scale_gray(unsigned char * in,size_t ix,size_t iy,unsigned char ** out,size_t ox,size_t oy)944 static void scale_gray(unsigned char *in, size_t ix, size_t iy, unsigned char **out, size_t ox, size_t oy)
945 {
946 	unsigned char *intermediate_buffer;
947 
948 	if (!ix||!iy) {
949 		if (in) mem_free(in);
950 		if (ox && ox * oy / ox != oy) overalloc();
951 		if (ox * oy > MAX_SIZE_T) overalloc();
952 		*out = mem_calloc(ox * oy);
953 		return;
954 	}
955 	if (ix*oy<ox*iy) {
956 		scale_gray_vertical(in,ix,iy,&intermediate_buffer,oy);
957 		scale_gray_horizontal(intermediate_buffer,ix,oy,out,ox);
958 	}else{
959 		scale_gray_horizontal(in,ix,iy,&intermediate_buffer,ox);
960 		scale_gray_vertical(intermediate_buffer,ox,iy,out,oy);
961 	}
962 }
963 
964 /* To be called only when global variable display_optimize is 1 or 2.
965  * Performs a decimation according to this variable. Data shrink to 1/3
966  * and x is the smaller width.
967  * There must be 9*x*y unsigned shorts of data.
968  * x must be >=1.
969  * Performs realloc onto the buffer after decimation to save memory.
970  */
decimate_3(unsigned short ** data0,size_t x,size_t y)971 static void decimate_3(unsigned short **data0, size_t x, size_t y)
972 {
973 	unsigned short *data=*data0;
974 	unsigned short *ahead=data;
975 	size_t i, futuresize;
976 	if (!data)
977 		return;
978 	if (x && (size_t)x * (size_t)y / (size_t)x != (size_t)y) overalloc();
979 	if ((size_t)x * (size_t)y > MAX_SIZE_T / 3 / sizeof(**data0)) overalloc();
980 	futuresize = x * y * 3 * sizeof(**data0);
981 
982 #ifdef DEBUG
983 	if (!(x>0&&y>0)) internal_error("zero width or height in decimate_3");
984 #endif /* #Ifdef DEBUG */
985 	if (display_optimize==1) {
986 		if (x==1) {
987 			for (;y;y--,ahead+=9,data+=3) {
988 				data[0]=(ahead[0]+ahead[0]+ahead[3])/3;
989 				data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
990 				data[2]=(ahead[5]+ahead[8]+ahead[8])/3;
991 			}
992 		}else{
993 			for (;y;y--) {
994 				data[0]=(ahead[0]+ahead[0]+ahead[3])/3;
995 				data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
996 				data[2]=(ahead[5]+ahead[8]+ahead[11])/3;
997 				for (ahead+=9,data+=3,i=x-2;i;i--,ahead+=9,data+=3) {
998 					data[0]=(ahead[-3]+ahead[0]+ahead[3])/3;
999 					data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1000 					data[2]=(ahead[5]+ahead[8]+ahead[11])/3;
1001 				}
1002 				data[0]=(ahead[-3]+ahead[0]+ahead[3])/3;
1003 				data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1004 				data[2]=(ahead[5]+ahead[8]+ahead[8])/3;
1005 				ahead+=9,data+=3;
1006 			}
1007 		}
1008 	}else{
1009 		/* display_optimize==2 */
1010 		if (x==1) {
1011 			for (;y;y--,ahead+=9,data+=3) {
1012 				data[0]=(ahead[3]+ahead[6]+ahead[6])/3;
1013 				data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1014 				data[2]=(ahead[2]+ahead[2]+ahead[5])/3;
1015 			}
1016 		}else{
1017 			for (;y;y--) {
1018 				data[0]=(ahead[3]+ahead[6]+ahead[9])/3;
1019 				data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1020 				data[2]=(ahead[2]+ahead[2]+ahead[5])/3;
1021 				for (ahead+=9,data+=3,i=x-2;i;i--,ahead+=9,data+=3) {
1022 					data[0]=(ahead[3]+ahead[6]+ahead[9])/3;
1023 					data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1024 					data[2]=(ahead[-1]+ahead[2]+ahead[5])/3;
1025 				}
1026 				data[0]=(ahead[3]+ahead[6]+ahead[6])/3;
1027 				data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1028 				data[2]=(ahead[-1]+ahead[2]+ahead[5])/3;
1029 				ahead+=9,data+=3;
1030 			}
1031 		}
1032 	}
1033 	*data0=mem_realloc(*data0,futuresize);
1034 }
1035 
1036 /* Scales color 48-bits-per-pixel bitmap. Both enlarges and diminishes. Uses
1037  * either low pass or bilinear filtering. The memory organization for both
1038  * input and output are red, green, blue. All three of them are unsigned shorts 0-65535.
1039  * Allocates output and frees input
1040  * We assume unsigned short holds at least 16 bits.
1041  */
scale_color(unsigned short * in,size_t ix,size_t iy,unsigned short ** out,size_t ox,size_t oy)1042 void scale_color(unsigned short *in, size_t ix, size_t iy, unsigned short **out, size_t ox, size_t oy)
1043 {
1044 	unsigned short *intermediate_buffer;
1045 	int do_optimize;
1046 	size_t ox0 = ox;
1047 
1048 	if (!ix||!iy) {
1049 		if (in) mem_free(in);
1050 		if (ox && ox * oy / ox != oy) overalloc();
1051 		if (ox * oy > MAX_SIZE_T / 3 / sizeof(**out)) overalloc();
1052 		*out = mem_calloc_mayfail(ox * oy * sizeof(**out) * 3);
1053 		return;
1054 	}
1055 	if (display_optimize&&ox*3<=ix) {
1056 		do_optimize=1;
1057 		ox0=ox;
1058 		ox*=3;
1059 	}else do_optimize=0;
1060 	if (ix*oy<ox*iy) {
1061 		scale_color_vertical(in,ix,iy,&intermediate_buffer,oy);
1062 		scale_color_horizontal(intermediate_buffer,ix,oy,out,ox);
1063 	}else{
1064 		scale_color_horizontal(in,ix,iy,&intermediate_buffer,ox);
1065 		scale_color_vertical(intermediate_buffer,ox,iy,out,oy);
1066 	}
1067 	if (do_optimize) decimate_3(out, ox0, oy);
1068 }
1069 
1070 /* Fills a block with given color. length is number of pixels. pixel is a
1071  * tribyte. 24 bits per pixel.
1072  */
mix_one_color_24(unsigned char * my_restrict dest,size_t length,unsigned char r,unsigned char g,unsigned char b)1073 void mix_one_color_24(unsigned char *my_restrict dest, size_t length, unsigned char r, unsigned char g, unsigned char b)
1074 {
1075 	for (;length;length--) {
1076 		dest[0]=r;
1077 		dest[1]=g;
1078 		dest[2]=b;
1079 		dest+=3;
1080 	}
1081 }
1082 
1083 /* Fills a block with given color. length is number of pixels. pixel is a
1084  * tribyte. 48 bits per pixel.
1085  * We assume unsigned short holds at least 16 bits.
1086  */
mix_one_color_48(unsigned short * my_restrict dest,size_t length,unsigned short r,unsigned short g,unsigned short b)1087 void mix_one_color_48(unsigned short *my_restrict dest, size_t length, unsigned short r, unsigned short g, unsigned short b)
1088 {
1089 	for (;length;length--) {
1090 		dest[0]=r;
1091 		dest[1]=g;
1092 		dest[2]=b;
1093 		dest+=3;
1094 	}
1095 }
1096 
1097 /* Mixes ink and paper of a letter, using alpha as alpha mask.
1098  * Only mixing in photon space makes physical sense so that the input values
1099  * must always be equivalent to photons and not to electrons!
1100  * length is number of pixels. pixel is a tribyte
1101  * alpha is 8-bit, rgb are all 16-bit
1102  * We assume unsigned short holds at least 16 bits.
1103  */
mix_two_colors(unsigned short * my_restrict dest,unsigned char * my_restrict alpha,size_t length,unsigned short r0,unsigned short g0,unsigned short b0,unsigned short r255,unsigned short g255,unsigned short b255)1104 static void mix_two_colors(unsigned short *my_restrict dest, unsigned char *my_restrict alpha,
1105 	size_t length, unsigned short r0, unsigned short g0, unsigned short b0,
1106 	unsigned short r255, unsigned short g255, unsigned short b255)
1107 {
1108 	unsigned char mask, cmask;
1109 
1110 	for (;length;length--) {
1111 		mask=*alpha++;
1112 		if (((mask+1)&255)>=2) {
1113 			cmask=255-mask;
1114 			dest[0]=(mask*r255+cmask*r0+127)/255;
1115 			dest[1]=(mask*g255+cmask*g0+127)/255;
1116 			dest[2]=(mask*b255+cmask*b0+127)/255;
1117 		}else{
1118 			if (mask) {
1119 				dest[0]=r255;
1120 				dest[1]=g255;
1121 				dest[2]=b255;
1122 			}else{
1123 				dest[0]=r0;
1124 				dest[1]=g0;
1125 				dest[2]=b0;
1126 			}
1127 		}
1128 		dest+=3;
1129 	}
1130 }
1131 
1132 /* We assume unsigned short holds at least 16 bits. */
agx_and_uc_32_to_48_table(unsigned short * my_restrict dest,const unsigned char * my_restrict src,size_t length,unsigned short * my_restrict table,unsigned short rb,unsigned short gb,unsigned short bb)1133 void agx_and_uc_32_to_48_table(unsigned short *my_restrict dest,
1134 		const unsigned char *my_restrict src, size_t length,
1135 		unsigned short *my_restrict table,
1136 		unsigned short rb, unsigned short gb, unsigned short bb)
1137 {
1138 	unsigned char alpha, calpha;
1139 	unsigned short ri, gi, bi;
1140 
1141 	for (;length;length--)
1142 	{
1143 		ri=table[src[0]];
1144 		gi=table[src[1]+256];
1145 		bi=table[src[2]+512];
1146 		alpha=src[3];
1147 		src+=4;
1148 		if (((alpha+1)&255)>=2) {
1149 			calpha=255-alpha;
1150 			dest[0]=(ri*alpha+calpha*rb+127)/255;
1151 			dest[1]=(gi*alpha+calpha*gb+127)/255;
1152 			dest[2]=(bi*alpha+calpha*bb+127)/255;
1153 		} else {
1154 			if (alpha) {
1155 				dest[0]=ri;
1156 				dest[1]=gi;
1157 				dest[2]=bi;
1158 			} else {
1159 				dest[0]=rb;
1160 				dest[1]=gb;
1161 				dest[2]=bb;
1162 			}
1163 		}
1164 		dest+=3;
1165 	}
1166 }
1167 
1168 /* src is a block of four-bytes RGBA. All bytes are gamma corrected. length is
1169  * number of pixels. output is input powered to the given gamma, passed into
1170  * dest. src and dest may be identical and it will work. rb, gb, bb are 0-65535
1171  * in linear monitor output photon space
1172  */
1173 /* We assume unsigned short holds at least 16 bits. */
agx_and_uc_32_to_48(unsigned short * my_restrict dest,const unsigned char * my_restrict src,size_t length,float red_gamma,float green_gamma,float blue_gamma,unsigned short rb,unsigned short gb,unsigned short bb)1174 void agx_and_uc_32_to_48(unsigned short *my_restrict dest,
1175 		const unsigned char *my_restrict src, size_t length, float red_gamma,
1176 		float green_gamma, float blue_gamma, unsigned short rb,
1177 		unsigned short gb, unsigned short bb)
1178 {
1179 	float_double r,g,b;
1180 	unsigned char alpha, calpha;
1181 	unsigned short ri,gi,bi;
1182 	const float_double inv_255=(float_double)(1/255.);
1183 
1184 	for (;length;length--)
1185 	{
1186 		r=src[0];
1187 		g=src[1];
1188 		b=src[2];
1189 		alpha=src[3];
1190 		src+=4;
1191 		r*=inv_255;
1192 		g*=inv_255;
1193 		b*=inv_255;
1194 		r=fd_pow(r,red_gamma);
1195 		g=fd_pow(g,green_gamma);
1196 		b=fd_pow(b,blue_gamma);
1197 		ri=(unsigned)((r*65535)+(float_double)0.5);
1198 		gi=(unsigned)((g*65535)+(float_double)0.5);
1199 		bi=(unsigned)((b*65535)+(float_double)0.5);
1200 		cmd_limit_16(ri);
1201 		cmd_limit_16(gi);
1202 		cmd_limit_16(bi);
1203 		if (((alpha+1)&255)>=2) {
1204 			calpha=255-alpha;
1205 			dest[0]=(unsigned short)((ri*alpha+calpha*rb+127U)/255U);
1206 			dest[1]=(unsigned short)((gi*alpha+calpha*gb+127U)/255U);
1207 			dest[2]=(unsigned short)((bi*alpha+calpha*bb+127U)/255U);
1208 		}else{
1209 			if (alpha) {
1210 				dest[0]=ri;
1211 				dest[1]=gi;
1212 				dest[2]=bi;
1213 			}else{
1214 				dest[0]=rb;
1215 				dest[1]=gb;
1216 				dest[2]=bb;
1217 			}
1218 		}
1219 		dest+=3;
1220 	}
1221 }
1222 /* src is a block of four-bytes RGBA. All bytes are gamma corrected. length is
1223  * number of pixels. output is input powered to the given gamma, passed into
1224  * dest. src and dest may be identical and it will work. rb, gb, bb are 0-65535
1225  * in linear monitor output photon space. alpha 255 means full image no background.
1226  */
1227 /* We assume unsigned short holds at least 16 bits. */
agx_and_uc_64_to_48(unsigned short * my_restrict dest,const unsigned short * my_restrict src,size_t length,float red_gamma,float green_gamma,float blue_gamma,unsigned short rb,unsigned short gb,unsigned short bb)1228 void agx_and_uc_64_to_48(unsigned short *my_restrict dest,
1229 		const unsigned short *my_restrict src, size_t length, float red_gamma,
1230 		float green_gamma, float blue_gamma, unsigned short rb,
1231 		unsigned short gb, unsigned short bb)
1232 {
1233 	float_double r,g,b;
1234 	unsigned short alpha, calpha;
1235 	unsigned short ri,gi,bi;
1236 	const float_double inv_65535=(float_double)(1/65535.);
1237 
1238 	for (;length;length--)
1239 	{
1240 		r=src[0];
1241 		g=src[1];
1242 		b=src[2];
1243 		alpha=src[3];
1244 		src+=4;
1245 		r*=inv_65535;
1246 		g*=inv_65535;
1247 		b*=inv_65535;
1248 		r=fd_pow(r,red_gamma);
1249 		g=fd_pow(g,green_gamma);
1250 		b=fd_pow(b,blue_gamma);
1251 		ri=(unsigned short)(r*65535+(float_double)0.5);
1252 		gi=(unsigned short)(g*65535+(float_double)0.5);
1253 		bi=(unsigned short)(b*65535+(float_double)0.5);
1254 		cmd_limit_16(ri);
1255 		cmd_limit_16(gi);
1256 		cmd_limit_16(bi);
1257 		if (((alpha+1)&65535)>=2) {
1258 			calpha=65535-alpha;
1259 			dest[0]=(unsigned short)((ri*(unsigned)alpha+(unsigned)calpha*rb+32767U)/65535U);
1260 			dest[1]=(unsigned short)((gi*(unsigned)alpha+(unsigned)calpha*gb+32767U)/65535U);
1261 			dest[2]=(unsigned short)((bi*(unsigned)alpha+(unsigned)calpha*bb+32767U)/65535U);
1262 		}else{
1263 			if (alpha) {
1264 				dest[0]=ri;
1265 				dest[1]=gi;
1266 				dest[2]=bi;
1267 			}else{
1268 				dest[0]=rb;
1269 				dest[1]=gb;
1270 				dest[2]=bb;
1271 			}
1272 		}
1273 		dest+=3;
1274 	}
1275 }
1276 
1277 /* src is a block of four-bytes RGBA. All bytes are gamma corrected. length is
1278  * number of pixels. output is input powered to the given gamma, passed into
1279  * dest. src and dest may be identical and it will work. rb, gb, bb are 0-65535
1280  * in linear monitor output photon space. alpha 255 means full image no background.
1281  * We assume unsigned short holds at least 16 bits. */
agx_and_uc_64_to_48_table(unsigned short * my_restrict dest,const unsigned short * my_restrict src,size_t length,unsigned short * my_restrict gamma_table,unsigned short rb,unsigned short gb,unsigned short bb)1282 void agx_and_uc_64_to_48_table(unsigned short *my_restrict dest,
1283 		const unsigned short *my_restrict src, size_t length, unsigned short *my_restrict gamma_table,
1284 		unsigned short rb, unsigned short gb, unsigned short bb)
1285 {
1286 	unsigned short alpha, calpha;
1287 	unsigned short ri,gi,bi;
1288 
1289 	for (;length;length--)
1290 	{
1291 		ri=gamma_table[*src];
1292 		gi=gamma_table[src[1]+65536];
1293 		bi=gamma_table[src[2]+131072];
1294 		alpha=src[3];
1295 		src+=4;
1296 		if (((alpha+1)&65535)>=2) {
1297 			calpha=65535-alpha;
1298 			dest[0]=(ri*alpha+calpha*rb+32767)/65535;
1299 			dest[1]=(gi*alpha+calpha*gb+32767)/65535;
1300 			dest[2]=(bi*alpha+calpha*bb+32767)/65535;
1301 		}else{
1302 			if (alpha) {
1303 				dest[0]=ri;
1304 				dest[1]=gi;
1305 				dest[2]=bi;
1306 			}else{
1307 				dest[0]=rb;
1308 				dest[1]=gb;
1309 				dest[2]=bb;
1310 			}
1311 		}
1312 		dest+=3;
1313 	}
1314 }
1315 
1316 /* src is a block of three-bytes. All bytes are gamma corrected. length is
1317  * number of triplets. output is input powered to the given gamma, passed into
1318  * dest. src and dest may be identical and it will work.
1319  * We assume unsigned short holds at least 16 bits. */
agx_48_to_48(unsigned short * my_restrict dest,const unsigned short * my_restrict src,size_t length,float red_gamma,float green_gamma,float blue_gamma)1320 void agx_48_to_48(unsigned short *my_restrict dest,
1321 		const unsigned short *my_restrict src, size_t length, float red_gamma,
1322 		float green_gamma, float blue_gamma)
1323 {
1324 	float_double a;
1325 	const float_double inv_65535=(float_double)(1/65535.);
1326 
1327 	for (;length;length--,src+=3,dest+=3)
1328 	{
1329 		a=src[0];
1330 		a*=inv_65535;
1331 		a=fd_pow(a,red_gamma);
1332 		dest[0]=(unsigned short)((a*65535)+(float_double)0.5);
1333 		cmd_limit_16(dest[0]);
1334 		a=src[1];
1335 		a*=inv_65535;
1336 		a=fd_pow(a,green_gamma);
1337 		dest[1]=(unsigned short)((a*65535)+(float_double)0.5);
1338 		cmd_limit_16(dest[1]);
1339 		a=src[2];
1340 		a*=inv_65535;
1341 		a=fd_pow(a,blue_gamma);
1342 		dest[2]=(unsigned short)((a*65535)+(float_double)0.5);
1343 		cmd_limit_16(dest[2]);
1344 	}
1345 }
1346 
1347 /* src is a block of three-bytes. All bytes are gamma corrected. length is
1348  * number of triples. output is input powered to the given gamma, passed into
1349  * dest. src and dest may be identical and it will work.
1350  * We assume unsigned short holds at least 16 bits. */
agx_48_to_48_table(unsigned short * my_restrict dest,const unsigned short * my_restrict src,size_t length,unsigned short * my_restrict table)1351 void agx_48_to_48_table(unsigned short *my_restrict dest,
1352 		const unsigned short *my_restrict src, size_t length, unsigned short *my_restrict table)
1353 {
1354 	for (;length;length--,src+=3,dest+=3)
1355 	{
1356 		dest[0]=table[*src];
1357 		dest[1]=table[src[1]+65536];
1358 		dest[2]=table[src[2]+131072];
1359 	}
1360 }
1361 
1362 /* src is a block of three-bytes. All bytes are gamma corrected. length is
1363  * number of triples. output is input powered to the given gamma, passed into
1364  * dest. src and dest may be identical and it will work.
1365  * We assume unsigned short holds at least 16 bits. */
agx_24_to_48(unsigned short * my_restrict dest,const unsigned char * my_restrict src,size_t length,float red_gamma,float green_gamma,float blue_gamma)1366 void agx_24_to_48(unsigned short *my_restrict dest, const unsigned char *my_restrict src,
1367 			  size_t length, float red_gamma, float green_gamma, float
1368 			  blue_gamma)
1369 {
1370 	float_double a;
1371 	const float_double inv_255=(float_double)(1/255.);
1372 
1373 	for (;length;length--,src+=3,dest+=3)
1374 	{
1375 		a=*src;
1376 		a*=inv_255;
1377 		a=fd_pow(a,red_gamma);
1378 		dest[0]=(unsigned short)((a*65535)+(float_double)0.5);
1379 		cmd_limit_16(dest[0]);
1380 		a=src[1];
1381 		a*=inv_255;
1382 		a=fd_pow(a,green_gamma);
1383 		dest[1]=(unsigned short)((a*65535)+(float_double)0.5);
1384 		cmd_limit_16(dest[1]);
1385 		a=src[2];
1386 		a*=inv_255;
1387 		a=fd_pow(a,blue_gamma);
1388 		dest[2]=(unsigned short)((a*65535)+(float_double)0.5);
1389 		cmd_limit_16(dest[2]);
1390 	}
1391 }
1392 
1393 /* Allocates new gamma_table and fills it with mapping 8 bits ->
1394  * power to user_gamma/cimg->*_gamma -> 16 bits
1395  * We assume unsigned short holds at least 16 bits. */
make_gamma_table(struct cached_image * cimg)1396 void make_gamma_table(struct cached_image *cimg)
1397 {
1398 	float_double rg=(float_double)((float_double)(user_gamma tcc_hack) / cimg->red_gamma);
1399 	float_double gg=(float_double)((float_double)(user_gamma tcc_hack) / cimg->green_gamma);
1400 	float_double bg=(float_double)((float_double)(user_gamma tcc_hack) / cimg->blue_gamma);
1401 	int a;
1402 	unsigned short *ptr_16;
1403 	unsigned short last_val;
1404 	const float_double inv_255=(float_double)(1/255.);
1405 	const float_double inv_65535=(float_double)(1/65535.);
1406 
1407 	if (cimg->buffer_bytes_per_pixel<=4) {
1408 		/* 8-bit */
1409 		ptr_16=mem_alloc(768*sizeof(*(cimg->gamma_table)));
1410 		cimg->gamma_table=ptr_16;
1411 		for (a=0;a<256;a++,ptr_16++) {
1412 			last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_255,rg)+(float_double)0.5);
1413 			cmd_limit_16(last_val);
1414 			*ptr_16 = last_val;
1415 		}
1416 		for (a=0;a<256;a++,ptr_16++) {
1417 			last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_255,gg)+(float_double)0.5);
1418 			cmd_limit_16(last_val);
1419 			*ptr_16 = last_val;
1420 		}
1421 		for (a=0;a<256;a++,ptr_16++) {
1422 			last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_255,bg)+(float_double)0.5);
1423 			cmd_limit_16(last_val);
1424 			*ptr_16 = last_val;
1425 		}
1426 	}else{
1427 		int x_slow_fpu;
1428 		if (gamma_bits != 2) x_slow_fpu = !gamma_bits;
1429 		else x_slow_fpu = slow_fpu == 1;
1430 
1431 		last_val = 0;	/* against warning */
1432 
1433 		/* 16-bit */
1434 		ptr_16=mem_alloc(196608*sizeof(*(cimg->gamma_table)));
1435 		cimg->gamma_table=ptr_16;
1436 		for (a=0;a<0x10000;a++,ptr_16++) {
1437 			if (!x_slow_fpu || !(a & 0xff)) {
1438 				last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_65535,rg)+(float_double)0.5);
1439 				cmd_limit_16(last_val);
1440 			}
1441 			*ptr_16 = last_val;
1442 		}
1443 		for (a=0;a<0x10000;a++,ptr_16++) {
1444 			if (!x_slow_fpu || !(a & 0xff)) {
1445 				last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_65535,gg)+(float_double)0.5);
1446 				cmd_limit_16(last_val);
1447 			}
1448 			*ptr_16 = last_val;
1449 		}
1450 		for (a=0;a<0x10000;a++,ptr_16++) {
1451 			if (!x_slow_fpu || !(a & 0xff)) {
1452 				last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_65535,bg)+(float_double)0.5);
1453 				cmd_limit_16(last_val);
1454 			}
1455 			*ptr_16 = last_val;
1456 		}
1457 	}
1458 }
1459 
1460 /* We assume unsigned short holds at least 16 bits. */
agx_24_to_48_table(unsigned short * my_restrict dest,const unsigned char * my_restrict src,size_t length,unsigned short * my_restrict table)1461 void agx_24_to_48_table(unsigned short *my_restrict dest, const unsigned char *my_restrict src,
1462 			  size_t length, unsigned short *my_restrict table)
1463 {
1464 	for (;length;length--,src+=3,dest+=3)
1465 	{
1466 		dest[0]=table[src[0]];
1467 		dest[1]=table[src[1]+256];
1468 		dest[2]=table[src[2]+512];
1469 	}
1470 }
1471 
1472 #if 0
1473 /* Input is 0-255 (8-bit). Output is 0-255 (8-bit)*/
1474 unsigned char ags_8_to_8(unsigned char input, float gamma)
1475 {
1476 	const float_double inv_255=1/255.;
1477 	return 255*fd_pow((float_double)input*inv_255,gamma)+(float_double)0.5;
1478 }
1479 #endif
1480 
1481 /* Input is 0-255 (8-bit). Output is 0-65535 (16-bit)*/
1482 /* We assume unsigned short holds at least 16 bits. */
ags_8_to_16(unsigned char input,float gamma)1483 unsigned short ags_8_to_16(unsigned char input, float gamma)
1484 {
1485 	float_double a=input;
1486 	unsigned short retval;
1487 	const float_double inv_255=(float_double)(1/255.);
1488 
1489 	a*=inv_255;
1490 	a=fd_pow(a,gamma);
1491 	a*=65535;
1492 	retval = (unsigned short)(a+(float_double)0.5);
1493 	cmd_limit_16(retval);
1494 	return retval;
1495 }
1496 
1497 /* Input is 0-65535 (16-bit). Output is 0-255 (8-bit)*/
1498 /* We assume unsigned short holds at least 16 bits. */
ags_16_to_8(unsigned short input,float gamma)1499 unsigned char ags_16_to_8(unsigned short input, float gamma)
1500 {
1501 	const float_double inv_65535=(float_double)(1/65535.);
1502 	return (unsigned char)(fd_pow((float_double)input*inv_65535,gamma)*255+(float_double)0.5);
1503 }
1504 
1505 /* Input is 0-65535 (16-bit). Output is 0-255 (8-bit)*/
ags_16_to_16(unsigned short input,float gamma)1506 unsigned short ags_16_to_16(unsigned short input, float gamma)
1507 {
1508 	unsigned short retval;
1509 	const float_double inv_65535=(float_double)(1/65535.);
1510 
1511 	retval = (unsigned short)(65535*fd_pow((float_double)input*inv_65535,gamma)+(float_double)0.5);
1512 	cmd_limit_16(retval);
1513 	return retval;
1514 }
1515 
1516 #define FONT_NORMAL		1
1517 #define FONT_BOLD		2
1518 #define FONT_MONOSPACED		3
1519 
1520 /* Returns a pointer to a structure describing the letter found or NULL
1521  * if the letter is not found. Tries all possibilities in the style table
1522  * before returning NULL.
1523  */
find_stored_letter(struct style * style,int letter_number)1524 static struct letter *find_stored_letter(struct style *style, int letter_number)
1525 {
1526 	int tries[3];
1527 	int try;
1528 	if (style->flags & FF_MONOSPACED) {
1529 		tries[0] = FONT_MONOSPACED;
1530 		if (style->flags & FF_BOLD) {
1531 			tries[1] = FONT_BOLD;
1532 			tries[2] = FONT_NORMAL;
1533 		} else {
1534 			tries[1] = FONT_NORMAL;
1535 			tries[2] = FONT_BOLD;
1536 		}
1537 	} else {
1538 		if (style->flags & FF_BOLD) {
1539 			tries[0] = FONT_BOLD;
1540 			tries[1] = FONT_NORMAL;
1541 			tries[2] = FONT_MONOSPACED;
1542 		} else {
1543 			tries[0] = FONT_NORMAL;
1544 			tries[1] = FONT_MONOSPACED;
1545 			tries[2] = FONT_BOLD;
1546 		}
1547 	}
1548 	for (try = 0; try < 3; try++) {
1549 		struct font *font = &font_table[tries[try]];
1550 		int start = font->begin;
1551 		int result;
1552 #define EQ(v, key)	(letter_data[start + v].code == key)
1553 #define AB(v, key)	(letter_data[start + v].code > key)
1554 		BIN_SEARCH(font->length, EQ, AB, letter_number, result);
1555 		if (result >= 0)
1556 			return letter_data + start + result;
1557 	}
1558 	return letter_data + font_table[0].begin;
1559 }
1560 
1561 struct read_work {
1562 	const unsigned char *pointer;
1563 	int length;
1564 };
1565 
read_stored_data(png_structp png_ptr,png_bytep data,png_size_t length)1566 static void read_stored_data(png_structp png_ptr, png_bytep data, png_size_t length)
1567 {
1568 	struct read_work *work;
1569 
1570 	length=(png_uint_32)length;
1571 
1572 	work=png_get_io_ptr(png_ptr);
1573 	if (length>(png_uint_32)work->length) png_error(png_ptr,"Ran out of input data");
1574 	memcpy(data,work->pointer,length);
1575 	work->length-=(int)length;
1576 	work->pointer+=length;
1577 }
1578 
my_png_warning(png_structp a,png_const_charp b)1579 static void my_png_warning(png_structp a, png_const_charp b)
1580 {
1581 }
1582 
1583 static jmp_buf png_error_jump;
1584 static int png_error_jump_valid = 0;
1585 
my_png_error(png_structp a,png_const_charp error_string)1586 static void my_png_error(png_structp a, png_const_charp error_string)
1587 {
1588 	if (png_error_jump_valid)
1589 		longjmp(png_error_jump, 1);
1590 	error("Error when loading compiled-in font: %s.", error_string);
1591 }
1592 
1593 /* Loads width and height of the PNG (nothing is scaled). Style table is
1594  * already incremented.
1595  */
load_metric(struct style * style,int char_number,int * x,int * y)1596 static void load_metric(struct style *style, int char_number, int *x, int *y)
1597 {
1598 	struct letter *l;
1599 
1600 #ifdef HAVE_FREETYPE
1601 	if (style->ft_face) {
1602 		*y = style->height;
1603 		if (!freetype_load_metric_cached(style, char_number, x, *y))
1604 			return;
1605 	}
1606 #endif
1607 
1608 	l = find_stored_letter(style, char_number);
1609 	if (!l) {
1610 		*x = 0;
1611 		*y = 0;
1612 	} else {
1613 		*x = l->xsize;
1614 		*y = l->ysize;
1615 	}
1616 	return;
1617 }
1618 
1619 #ifdef PNG_USER_MEM_SUPPORTED
my_png_alloc(png_structp png_ptr,png_size_t size)1620 void *my_png_alloc(png_structp png_ptr, png_size_t size)
1621 {
1622 	void *ptr = mem_alloc_mayfail(size);
1623 	return ptr;
1624 }
my_png_free(png_structp png_ptr,void * ptr)1625 void my_png_free(png_structp png_ptr, void *ptr)
1626 {
1627 	if (ptr) mem_free(ptr);
1628 }
1629 #endif
1630 
dip_set_gamma(png_structp png_ptr,png_infop info_ptr)1631 static void dip_set_gamma(png_structp png_ptr, png_infop info_ptr)
1632 {
1633 	png_error_jump_valid = 1;
1634 	if (!setjmp(png_error_jump)) {
1635 		double gamma;
1636 		if (png_get_gAMA(png_ptr, info_ptr, &gamma))
1637 			png_set_gamma(png_ptr, 1.0, gamma);
1638 		else
1639 			png_set_gamma(png_ptr, 1.0, sRGB_gamma);
1640 	}
1641 	png_error_jump_valid = 0;
1642 }
1643 
1644 /* The data tha fall out of this function express this: 0 is paper. 255 is ink. 34
1645  * is 34/255ink+(255-34)paper. No gamma is involved in this formula, as you can see.
1646  * The multiplications and additions take place in photon space.
1647  */
load_char(unsigned char ** dest,int * x,int * y,const unsigned char * png_data,int png_length)1648 static void load_char(unsigned char **dest, int *x, int *y, const unsigned char *png_data, int png_length)
1649 {
1650 	png_structp png_ptr;
1651 	png_infop info_ptr;
1652 	int y1,number_of_passes;
1653 	unsigned char **ptrs;
1654 	struct read_work work;
1655 
1656 	work.pointer = png_data;
1657 	work.length = png_length;
1658 
1659 	retry1:
1660 #ifdef PNG_USER_MEM_SUPPORTED
1661 	png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
1662 			NULL, my_png_error, my_png_warning,
1663 			NULL, my_png_alloc, my_png_free);
1664 #else
1665 	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
1666 			NULL, my_png_error, my_png_warning);
1667 #endif
1668 	if (!png_ptr) {
1669 		if (out_of_memory(0, NULL, 0)) goto retry1;
1670 		fatal_exit("png_create_read_struct failed");
1671 	}
1672 	retry2:
1673 	info_ptr = png_create_info_struct(png_ptr);
1674 	if (!info_ptr) {
1675 		if (out_of_memory(0, NULL, 0)) goto retry2;
1676 		fatal_exit("png_create_info_struct failed");
1677 	}
1678 	png_set_read_fn(png_ptr, &work, (png_rw_ptr)read_stored_data);
1679 	png_read_info(png_ptr, info_ptr);
1680 	*x = (int)png_get_image_width(png_ptr, info_ptr);
1681 	*y = (int)png_get_image_height(png_ptr, info_ptr);
1682 	dip_set_gamma(png_ptr, info_ptr);
1683 	{
1684 		int bit_depth;
1685 		int color_type;
1686 
1687 		color_type = png_get_color_type(png_ptr, info_ptr);
1688 		bit_depth = png_get_bit_depth(png_ptr, info_ptr);
1689 		if (color_type == PNG_COLOR_TYPE_GRAY) {
1690 			if (bit_depth < 8) {
1691 				 png_set_expand(png_ptr);
1692 			}
1693 			if (bit_depth == 16) {
1694 				 png_set_strip_16(png_ptr);
1695 			}
1696 		}
1697 		if (color_type == PNG_COLOR_TYPE_PALETTE) {
1698 			png_set_expand(png_ptr);
1699 #ifdef HAVE_PNG_SET_RGB_TO_GRAY
1700 			png_set_rgb_to_gray(png_ptr, 1, -1, -1);
1701 #else
1702 			goto end;
1703 #endif
1704 		}
1705 		if (color_type & PNG_COLOR_MASK_ALPHA) {
1706 			png_set_strip_alpha(png_ptr);
1707 		}
1708 		if (color_type == PNG_COLOR_TYPE_RGB ||
1709 			color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
1710 #ifdef HAVE_PNG_SET_RGB_TO_GRAY
1711 			png_set_rgb_to_gray(png_ptr, 1, -1, -1);
1712 #else
1713 			goto end;
1714 #endif
1715 		}
1716 	}
1717 	/* If the depth is different from 8 bits/gray, make the libpng expand
1718 	 * it to 8 bit gray.
1719 	 */
1720 	number_of_passes = png_set_interlace_handling(png_ptr);
1721 	png_read_update_info(png_ptr, info_ptr);
1722 	if (*x && (unsigned)*x * (unsigned)*y / (unsigned)*x != (unsigned)*y) overalloc();
1723 	if ((unsigned)*x * (unsigned)*y > MAXINT) overalloc();
1724 	*dest = mem_alloc(*x * *y);
1725 	if ((unsigned)*y > MAXINT / sizeof(*ptrs)) overalloc();
1726 	ptrs = mem_alloc(*y * sizeof(*ptrs));
1727 	for (y1 = 0; y1 < *y; y1++) ptrs[y1] = *dest + *x * y1;
1728 	for (;number_of_passes; number_of_passes--) {
1729 		png_read_rows(png_ptr, ptrs, NULL, *y);
1730 	}
1731 	png_read_end(png_ptr, NULL);
1732 	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
1733 	mem_free(ptrs);
1734 	return;
1735 #ifndef HAVE_PNG_SET_RGB_TO_GRAY
1736 	end:
1737 	if (*x && (unsigned)*x * (unsigned)*y / (unsigned)*x != (unsigned)*y) overalloc();
1738 	if ((unsigned)*x * (unsigned)*y > MAXINT) overalloc();
1739 	*dest=mem_calloc(*x * *y));
1740 	return;
1741 #endif
1742 }
1743 
1744 /* Like load_char, but we dictate the y.
1745  */
load_scaled_char(unsigned char ** dest,int * x,int y,const unsigned char * png_data,int png_length,struct style * style)1746 static void load_scaled_char(unsigned char **dest, int *x, int y, const unsigned char *png_data, int png_length, struct style *style)
1747 {
1748 	unsigned char *interm;
1749 	unsigned char *interm2;
1750 	unsigned char *i2ptr, *dptr;
1751 	int ix, iy, y0, x0, c;
1752 	float conv0, conv1, sharpness,contrast;
1753 
1754 	load_char(&interm, &ix, &iy, png_data, png_length);
1755 	if (style->mono_space >= 0)
1756 		*x = compute_width(style->mono_space, style->mono_height, y);
1757 	else
1758 		*x = compute_width(ix, iy, y);
1759 	if (display_optimize) *x *= 3;
1760 	scale_gray(interm, ix, iy, dest, *x, y);
1761 	if (y > 32 || y <= 0) return; /* No convolution */
1762 	ix = *x + 2; /* There is one-pixel border around */
1763 	iy = y + 2;
1764 	if (ix && (unsigned)ix * (unsigned)iy / (unsigned)ix != (unsigned)iy) overalloc();
1765 	if ((unsigned)ix * (unsigned)iy > MAXINT) overalloc();
1766 	interm2 = mem_alloc(ix * iy);
1767 	i2ptr = interm2 + ix + 1;
1768 	dptr = *dest;
1769 	memset(interm2, 0, ix);
1770 	memset(interm2 + (iy - 1) * ix, 0, ix);
1771 	for (y0 = y; y0; y0--) {
1772 		i2ptr[-1] = 0;
1773 		memcpy(i2ptr, dptr, *x);
1774 		i2ptr[*x] = 0;
1775 		i2ptr += ix;
1776 		dptr += *x;
1777 	}
1778 	i2ptr = interm2 + ix + 1;
1779 	dptr = *dest;
1780 
1781 	/* Determine the sharpness and contrast */
1782 	sharpness = fancy_constants[2 * y - 2];
1783 	contrast = fancy_constants[2 * y - 1];
1784 
1785 	/* Compute the matrix constants from contrast and sharpness */
1786 	conv0 = (1 + sharpness) * contrast;
1787 	conv1 = (float)(-sharpness * (float)0.25 * contrast);
1788 
1789 	for (y0 = y; y0; y0--) {
1790 		for (x0 = *x; x0; x0--) {
1791 			/* Convolution */
1792 			c=(int)((*i2ptr * conv0) + i2ptr[-ix] * conv1 + i2ptr[-1] * conv1 + i2ptr[1] * conv1 + i2ptr[ix] * conv1 + (float)0.5);
1793 			if (c & ~255) c = c < 0 ? 0 : 255;
1794 			*dptr = (unsigned char)c;
1795 			dptr++;
1796 			i2ptr++;
1797 		}
1798 		i2ptr += 2;
1799 	}
1800 	mem_free(interm2);
1801 }
1802 
1803 static struct font_cache_entry *locked_color_entry = NULL;
1804 
1805 /* Adds required entry into font_cache and returns pointer to the entry.
1806  */
supply_color_cache_entry(struct style * style,struct letter * letter,int char_number)1807 ATTR_NOINLINE static struct font_cache_entry *supply_color_cache_entry(struct style *style, struct letter *letter, int char_number)
1808 {
1809 	int found_x, found_y;
1810 	unsigned char *found_data;
1811 	struct font_cache_entry *neww;
1812 	unsigned short *primary_data;
1813 	unsigned short red, green, blue;
1814 	unsigned bytes_consumed;
1815 
1816 	found_y = style->height;
1817 #ifdef HAVE_FREETYPE
1818 	if (!letter) {
1819 		if (freetype_type_character(style, char_number, &found_data, &found_x, found_y))
1820 			return NULL;
1821 	} else
1822 #endif
1823 	{
1824 		load_scaled_char(&found_data, &found_x, found_y, letter->begin, letter->length, style);
1825 	}
1826 
1827 	neww = mem_alloc(sizeof(struct font_cache_entry));
1828 	locked_color_entry = neww;
1829 	neww->bitmap.x = found_x;
1830 	neww->bitmap.y = found_y;
1831 	neww->r0 = style->r0;
1832 	neww->g0 = style->g0;
1833 	neww->b0 = style->b0;
1834 	neww->r1 = style->r1;
1835 	neww->g1 = style->g1;
1836 	neww->b1 = style->b1;
1837 	neww->flags = style->flags;
1838 	neww->char_number = char_number;
1839 	neww->mono_space = style->mono_space;
1840 	neww->mono_height = style->mono_height;
1841 #ifdef HAVE_FREETYPE
1842 	neww->font = freetype_get_allocated_font_name(style);
1843 #endif
1844 
1845 	if (neww->bitmap.x && (unsigned)neww->bitmap.x * (unsigned)neww->bitmap.y / (unsigned)neww->bitmap.x != (unsigned)neww->bitmap.y) overalloc();
1846 	if ((unsigned)neww->bitmap.x * (unsigned)neww->bitmap.y > MAXINT / 3 / sizeof(*primary_data)) overalloc();
1847 	primary_data = mem_alloc(3 * neww->bitmap.x * neww->bitmap.y * sizeof(*primary_data));
1848 
1849 	/* We assume the gamma of HTML styles is in sRGB space */
1850 	round_color_sRGB_to_48(&red, &green, &blue, (style->r0 << 16) | (style->g0 << 8) | style->b0);
1851 	mix_two_colors(primary_data, found_data,
1852 		found_x * found_y,
1853 		red, green, blue,
1854 		ags_8_to_16(style->r1, (float)((float)(user_gamma tcc_hack) / (float)sRGB_gamma)),
1855 		ags_8_to_16(style->g1, (float)((float)(user_gamma tcc_hack) / (float)sRGB_gamma)),
1856 		ags_8_to_16(style->b1, (float)((float)(user_gamma tcc_hack) / (float)sRGB_gamma))
1857 	);
1858 	if (display_optimize) {
1859 		/* A correction for LCD */
1860 		neww->bitmap.x /= 3;
1861 		decimate_3(&primary_data, neww->bitmap.x, neww->bitmap.y);
1862 	}
1863 	/* We have a buffer with photons */
1864 	if (drv->get_empty_bitmap(&neww->bitmap))
1865 		goto skip_dither;
1866 	if (dither_letters)
1867 		dither(primary_data, &neww->bitmap);
1868 	else
1869 		(*round_fn)(primary_data, &neww->bitmap);
1870 	skip_dither:
1871 	mem_free(primary_data);
1872 	drv->register_bitmap(&neww->bitmap);
1873 
1874 	mem_free(found_data);
1875 
1876 	bytes_consumed = neww->bitmap.x * neww->bitmap.y * (drv->depth&7);
1877 	/* Number of bytes per pixel in passed bitmaps */
1878 	bytes_consumed += (int)sizeof(*neww);
1879 	bytes_consumed += (int)sizeof(struct lru_entry);
1880 
1881 #ifdef HAVE_FREETYPE
1882 	if (!letter) {
1883 		lru_insert(&font_cache, neww, &freetype_cache[char_number & (sizeof_freetype_cache - 1)], bytes_consumed);
1884 	} else
1885 #endif
1886 	{
1887 		lru_insert(&font_cache, neww, &letter->color_list, bytes_consumed);
1888 	}
1889 
1890 	return neww;
1891 }
1892 
destroy_font_cache_bottom(void)1893 static int destroy_font_cache_bottom(void)
1894 {
1895 	struct font_cache_entry *bottom;
1896 	bottom = lru_get_bottom(&font_cache);
1897 	if (!bottom) return 0;
1898 	if (bottom == locked_color_entry) return 0;
1899 #ifdef HAVE_FREETYPE
1900 	if (bottom->font) mem_free(bottom->font);
1901 #endif
1902 	drv->unregister_bitmap(&bottom->bitmap);
1903 	mem_free(bottom);
1904 	lru_destroy_bottom(&font_cache);
1905 	return 1;
1906 }
1907 
1908 /* Prunes the cache to comply with maximum size */
prune_font_cache(void)1909 static int prune_font_cache(void)
1910 {
1911 	int r = 0;
1912 
1913 	while (font_cache.bytes > (unsigned)font_cache_size) {
1914 		if (destroy_font_cache_bottom()) {
1915 			r = 1;
1916 		} else {
1917 			break;
1918 		}
1919 	}
1920 	return r;
1921 }
1922 
1923 /* Prints a letter to the specified position and
1924  * returns the width of the printed letter */
print_letter(struct graphics_device * device,int x,int y,struct style * style,int char_number)1925 static inline int print_letter(struct graphics_device *device, int x, int y, struct style *style, int char_number)
1926 
1927 {
1928 	int xw;
1929 	struct font_cache_entry *found;
1930 	struct font_cache_entry templat;
1931 	struct letter *letter;
1932 
1933 	templat.r0 = style->r0;
1934 	templat.r1 = style->r1;
1935 	templat.g0 = style->g0;
1936 	templat.g1 = style->g1;
1937 	templat.b0 = style->b0;
1938 	templat.b1 = style->b1;
1939 	templat.flags = style->flags;
1940 	templat.char_number = char_number;
1941 	templat.mono_space = style->mono_space;
1942 	templat.mono_height = style->mono_height;
1943 	templat.bitmap.y = style->height;
1944 #ifdef HAVE_FREETYPE
1945 	templat.font = freetype_get_allocated_font_name(style);
1946 #endif
1947 
1948 #ifdef HAVE_FREETYPE
1949 	if (style->ft_face) {
1950 		found = lru_lookup(&font_cache, &templat, &freetype_cache[char_number & (sizeof_freetype_cache - 1)]);
1951 		letter = NULL;
1952 	} else
1953 bypass_freetype:
1954 #endif
1955 	{
1956 		/* Find a suitable letter */
1957 		letter = find_stored_letter(style, char_number);
1958 #ifdef DEBUG
1959 		if (!letter) internal_error("print_letter could not find a letter - even not the blotch!");
1960 #endif /* #ifdef DEBUG */
1961 		found = lru_lookup(&font_cache, &templat, &letter->color_list);
1962 	}
1963 
1964 	if (!found) {
1965 		found = supply_color_cache_entry(style, letter, char_number);
1966 #ifdef HAVE_FREETYPE
1967 		if (!found)
1968 			goto bypass_freetype;
1969 #endif
1970 	} else {
1971 		locked_color_entry = found;
1972 	}
1973 #ifdef HAVE_FREETYPE
1974 	if (templat.font) mem_free(templat.font);
1975 #endif
1976 #if 0
1977 	drv->fill_area(device, x, y, x + found->bitmap.x, y + found->bitmap.y, drv->get_color(0xff0000));
1978 	if (drv->flush) drv->flush(device);
1979 	portable_sleep(1);
1980 #endif
1981 	drv->draw_bitmap(device, &found->bitmap, x, y);
1982 	xw = found->bitmap.x;
1983 	if (locked_color_entry != found) internal_error("bad letter lock");
1984 	locked_color_entry = NULL;
1985 	prune_font_cache();
1986 	return xw;
1987 }
1988 
1989 /* Must return values that are:
1990  * >=0
1991  * <=height
1992  * at least 1 apart
1993  * Otherwise g_print_text will print nonsense (but won't segfault)
1994  */
get_underline_pos(int height,int * top,int * bottom)1995 static void get_underline_pos(int height, int *top, int *bottom)
1996 {
1997 	int thickness, baseline;
1998 	thickness=(height+15)/16;
1999 	baseline=height/7;
2000 	if (baseline<=0) baseline=1;
2001 	if (thickness>baseline) thickness=baseline;
2002 	*top=height-baseline;
2003 	*bottom=*top+thickness;
2004 }
2005 
2006 /* *width will be advanced by the width of the text */
g_print_text(struct graphics_device * device,int x,int y,struct style * style,unsigned char * text,int * width)2007 void g_print_text(struct graphics_device *device, int x, int y, struct style *style, unsigned char *text, int *width)
2008 {
2009 	int top_underline, bottom_underline, original_width, my_width;
2010 	unsigned char original_flags;
2011 	struct rect saved_clip;
2012 
2013 	if (y + style->height <= device->clip.y1 || y >= device->clip.y2)
2014 		goto o;
2015 	if (style->flags & FF_UNDERLINE) {
2016 		/* Underline */
2017 		if (!width) {
2018 		       width = &my_width;
2019 		       *width = 0;
2020 		}
2021 		original_flags = style->flags;
2022 		original_width = *width;
2023 		style->flags &= ~FF_UNDERLINE;
2024 		get_underline_pos(style->height, &top_underline, &bottom_underline);
2025 		restrict_clip_area(device, &saved_clip, 0, 0, device->size.x2, y + top_underline);
2026 		g_print_text(device, x, y, style, text, width);
2027 		set_clip_area(device, &saved_clip);
2028 		if (bottom_underline - top_underline == 1) {
2029 			/* Line */
2030 			drv->draw_hline(device, x, y + top_underline, safe_add(x, *width) - original_width, style->underline_color);
2031 		} else {
2032 			/* Area */
2033 			drv->fill_area(device, x, y + top_underline, safe_add(x, *width) - original_width, y + bottom_underline, style->underline_color);
2034 		}
2035 		if (bottom_underline < style->height) {
2036 			/* Do the bottom half only if the underline is above
2037 			 * the bottom of the letters.
2038 			 */
2039 			*width = original_width;
2040 			restrict_clip_area(device, &saved_clip, 0, y + bottom_underline, device->size.x2, device->size.y2);
2041 			g_print_text(device, x, y, style, text, width);
2042 			set_clip_area(device, &saved_clip);
2043 		}
2044 		style->flags = original_flags;
2045 		return;
2046 	}
2047 	while (*text) {
2048 		int p;
2049 		int u;
2050 		GET_UTF_8(text, u);
2051 		/* 00-09, 0b-1f, 80, 81, 84, 86-9f ignorovat
2052 		 * 0a = LF
2053 		 * 82 = ' '
2054 		 * 83 = nobrk
2055 		 * 85 = radkovy zlom
2056 		 * a0 = NBSP
2057 		 * ad = soft hyphen
2058 		 */
2059 #if 0
2060 		if (	(u>=0x00&&u<=0x09)||
2061 			(u>=0x0b&&u<=0x1f)||
2062 			u==0x80||
2063 			u==0x82||
2064 			u==0x84||
2065 			(u>=0x86&&u<=0x9f)
2066 		)continue;
2067 		if (u==0x82)u=' ';
2068 #endif
2069 		/* stare Mikulasovo patchovani, musim to opravit    -- Brain */
2070 		if (!u || u == 0xad)
2071 			continue;
2072 		if (u == 0x01 || u == 0xa0) u = ' ';
2073 		p = print_letter(device, x, y, style, u);
2074 		x += p;
2075 		if (width) {
2076 			*width = safe_add(*width, p);
2077 			continue;
2078 		}
2079 		if (x >= device->clip.x2)
2080 			return;
2081 	}
2082 	return;
2083 o:
2084 	if (width) {
2085 		int qw = g_text_width(style, text);
2086 		*width = safe_add(*width, qw);
2087 	}
2088 }
2089 
2090 /* 0=equality 1=inequality */
compare_font_entries(void * entry,void * templat)2091 static int compare_font_entries(void *entry, void *templat)
2092 {
2093 	struct font_cache_entry *e1 = entry;
2094 	struct font_cache_entry *e2 = templat;
2095 
2096 	if (e1->r0 != e2->r0) return 1;
2097 	if (e1->g0 != e2->g0) return 1;
2098 	if (e1->b0 != e2->b0) return 1;
2099 	if (e1->r1 != e2->r1) return 1;
2100 	if (e1->g1 != e2->g1) return 1;
2101 	if (e1->b1 != e2->b1) return 1;
2102 	if (e1->flags != e2->flags) return 1;
2103 	if (e1->char_number != e2->char_number) return 1;
2104 	if (e1->mono_space != e2->mono_space) return 1;
2105 	if (e1->mono_space >= 0) {
2106 		if (e1->mono_height != e2->mono_height) return 1;
2107 	}
2108 	if (e1->bitmap.y != e2->bitmap.y) return 1;
2109 #ifdef HAVE_FREETYPE
2110 	if (!e1->font != !e2->font) return 1;
2111 	if (e1->font && strcmp(cast_const_char e1->font, cast_const_char e2->font)) return 1;
2112 #endif
2113 	return 0;
2114 }
2115 
2116 /* If the cache already exists, it is destroyed and reallocated. If you call it with the same
2117  * size argument, only a cache flush will yield.
2118  */
init_font_cache(void)2119 static void init_font_cache(void)
2120 {
2121 	lru_init(&font_cache, &compare_font_entries);
2122 }
2123 
2124 /* Ensures there are no lru_entry objects allocated - destroys them.
2125  * Also destroys the bitmaps asociated with them. Does not destruct the
2126  font_cache per se.
2127  */
destroy_font_cache(void)2128 static void destroy_font_cache(void)
2129 {
2130 	while (destroy_font_cache_bottom())
2131 		;
2132 	if (lru_get_bottom(&font_cache))
2133 		internal_error("destroy_font_cache: cache not freed due to locks");
2134 }
2135 
2136 /* Returns 0 in case the char is not found. */
g_get_width(struct style * style,unsigned charcode)2137 static inline int g_get_width(struct style *style, unsigned charcode)
2138 {
2139 	int x, y, width;
2140 
2141 	if (!charcode || charcode == 0xad) return 0;
2142 	if (charcode == 0x01 || charcode == 0xa0) charcode = ' ';
2143 	if (style->mono_space >= 0) {
2144 		x = style->mono_space;
2145 		y = style->mono_height;
2146 	} else load_metric(style, charcode, &x, &y);
2147 	if (!(x && y)) width = 0;
2148 	else width = compute_width(x, y, style->height);
2149 	return width;
2150 }
2151 
g_text_width(struct style * style,unsigned char * text)2152 int g_text_width(struct style *style, unsigned char *text)
2153 {
2154 	int w = 0;
2155 	while (*text) {
2156 		int u;
2157 		int qw;
2158 		GET_UTF_8(text, u);
2159 		qw = g_get_width(style, u);
2160 		w = safe_add(w, qw);
2161 	}
2162 	return w;
2163 }
2164 
g_char_width(struct style * style,unsigned charcode)2165 int g_char_width(struct style *style, unsigned charcode)
2166 {
2167 	return g_get_width(style, charcode);
2168 }
2169 
g_wrap_text(struct wrap_struct * w)2170 int g_wrap_text(struct wrap_struct *w)
2171 {
2172 	unsigned char *init_text = w->text;
2173 	while (*w->text) {
2174 		int u;
2175 		int s;
2176 		unsigned char *l_text = w->text;
2177 		if (*l_text == ' ') w->last_wrap = l_text,
2178 				    w->last_wrap_obj = w->obj;
2179 		GET_UTF_8(w->text, u);
2180 		if (!u) continue;
2181 		s = g_get_width(w->style, u);
2182 		w->pos = safe_add(w->pos, s);
2183 		if (w->pos <= w->width) {
2184 			c:
2185 			if (u != 0xad || *w->text == ' ' || w->force_break) continue;
2186 			s = g_char_width(w->style, '-');
2187 			if (safe_add(w->pos, s) <= w->width || (!w->last_wrap && !w->last_wrap_obj)) {
2188 				w->last_wrap = l_text;
2189 				w->last_wrap_obj = w->obj;
2190 				continue;
2191 			}
2192 		}
2193 		if (w->force_break && !w->last_wrap && l_text != init_text) {
2194 			w->last_wrap = l_text;
2195 			w->last_wrap_obj = w->obj;
2196 		}
2197 		if (!w->last_wrap && !w->last_wrap_obj) goto c;
2198 		return 0;
2199 	}
2200 	return 1;
2201 }
2202 
update_aspect(void)2203 void update_aspect(void)
2204 {
2205 	aspect = (int)(65536 * bfu_aspect + 0.5);
2206 	destroy_font_cache();
2207 }
2208 
flush_bitmaps(int flush_font,int flush_images,int redraw_all)2209 void flush_bitmaps(int flush_font, int flush_images, int redraw_all)
2210 {
2211 	if (flush_font)
2212 		destroy_font_cache();
2213 	if (flush_images)
2214 		gamma_stamp++;
2215 	if (redraw_all)
2216 		cls_redraw_all_terminals();
2217 }
2218 
fontcache_info(int type)2219 my_uintptr_t fontcache_info(int type)
2220 {
2221 	switch (type) {
2222 		case CI_BYTES:
2223 			return font_cache.bytes;
2224 		case CI_FILES:
2225 			return font_cache.items;
2226 		default:
2227 			internal_error("fontcache_info: query %d", type);
2228 			return 0;
2229 	}
2230 }
2231 
shrink_font_cache(int u)2232 static int shrink_font_cache(int u)
2233 {
2234 	int freed_something = 0;
2235 	int has_something;
2236 	if (u == SH_CHECK_QUOTA) {
2237 		freed_something = prune_font_cache();
2238 	}
2239 	if (u == SH_FREE_ALL) {
2240 		while (destroy_font_cache_bottom())
2241 			freed_something = 1;
2242 	}
2243 	if (u == SH_FREE_SOMETHING) {
2244 		freed_something = destroy_font_cache_bottom();
2245 	}
2246 	has_something = !!lru_get_bottom(&font_cache);
2247 	return	(freed_something ? ST_SOMETHING_FREED : 0) |
2248 		(has_something ? 0 : ST_CACHE_EMPTY);
2249 }
2250 
init_dip(void)2251 void init_dip(void)
2252 {
2253 	init_font_cache();
2254 	update_aspect();
2255 	register_cache_upcall(shrink_font_cache, MF_GPI, cast_uchar "fontcache");
2256 }
2257 
g_invert_style(struct style * old)2258 struct style *g_invert_style(struct style *old)
2259 {
2260 	struct style *st;
2261 	st = mem_alloc(sizeof(struct style));
2262 	st->refcount = 1;
2263 	st->r0 = old->r1;
2264 	st->g0 = old->g1;
2265 	st->b0 = old->b1;
2266 	st->r1 = old->r0;
2267 	st->g1 = old->g0;
2268 	st->b1 = old->b0;
2269 	st->height = old->height;
2270 	st->flags = old->flags;
2271 #ifdef HAVE_FREETYPE
2272 	st->ft_face = old->ft_face;
2273 #endif
2274 	if (st->flags & FF_UNDERLINE) {
2275 		/* We have to get a foreground color for underlining */
2276 		st->underline_color = dip_get_color_sRGB((st->r1 << 16) | (st->g1 << 8) | (st->b1));
2277 	}
2278 	st->mono_space = old->mono_space;
2279 	st->mono_height = old->mono_height;
2280 	return st;
2281 }
2282 
hack_rgb(int rgb)2283 int hack_rgb(int rgb)
2284 {
2285 	if (((drv->depth >> 3) & 0x1f) <= 4) {
2286 		int r,g,b;
2287 		r=(rgb>>16)&255;
2288 		g=(rgb>>8)&255;
2289 		b=rgb&255;
2290 		if (r == g && g == b) {
2291 			if (r < 128) return 0;
2292 			else return 0xffffff;
2293 		}
2294 	}
2295 	return rgb;
2296 }
2297 
2298 /* Never returns NULL. */
g_get_style_font(int fg,int bg,int size,int fflags,unsigned char * font)2299 struct style *g_get_style_font(int fg, int bg, int size, int fflags, unsigned char *font)
2300 {
2301 	struct style *st;
2302 
2303 	bg = hack_rgb(bg);
2304 
2305 	st = mem_alloc(sizeof(struct style));
2306 	st->refcount = 1;
2307 	st->r0 = bg >> 16;
2308 	st->g0 = (bg >> 8) & 255;
2309 	st->b0 = bg & 255;
2310 	st->r1 = fg >> 16;
2311 	st->g1 = (fg >> 8) & 255;
2312 	st->b1 = fg & 255;
2313 	if (size <= 0) size = 1;
2314 	st->height = size;
2315 	st->flags = (unsigned char)fflags;
2316 #ifdef HAVE_FREETYPE
2317 	if (!font)
2318 		st->ft_face = freetype_flags_to_face(fflags);
2319 	else
2320 		st->ft_face = freetype_get_font(font);
2321 #endif
2322 	if (fflags & FF_UNDERLINE) {
2323 		/* We have to get a foreground color for underlining */
2324 		st->underline_color = dip_get_color_sRGB(fg);
2325 	}
2326 	if (fflags & FF_MONOSPACED)
2327 		load_metric(st, ' ', &st->mono_space, &st->mono_height);
2328 	else
2329 		st->mono_space = -1;
2330 
2331 	return st;
2332 }
2333 
g_get_style(int fg,int bg,int size,int fflags)2334 struct style *g_get_style(int fg, int bg, int size, int fflags)
2335 {
2336 	return g_get_style_font(fg, bg, size, fflags, NULL);
2337 }
2338 
g_clone_style(struct style * st)2339 struct style *g_clone_style(struct style *st)
2340 {
2341 	st->refcount++;
2342 	return st;
2343 }
2344 
g_free_style(struct style * st)2345 void g_free_style(struct style *st)
2346 {
2347 	if (--st->refcount) return;
2348 #ifdef HAVE_FREETYPE
2349 	if (st->ft_face)
2350 		freetype_free_font(st->ft_face);
2351 #endif
2352 	mem_free(st);
2353 }
2354 
2355 tcount gamma_stamp = 1; /* stamp counter for gamma changes */
2356 
2357 long gamma_cache_color_1;
2358 int gamma_cache_rgb_1;
2359 long gamma_cache_color_2;
2360 int gamma_cache_rgb_2;
2361 
2362 /* IEC 61966-2-1
2363  * Input gamma: sRGB space (directly from HTML, i. e. unrounded)
2364  * Output: color index for graphics driver that is closest to the
2365  * given sRGB value.
2366  * We assume unsigned short holds at least 16 bits. */
real_dip_get_color_sRGB(int rgb)2367 long real_dip_get_color_sRGB(int rgb)
2368 {
2369 	unsigned short r, g, b;
2370 	int hacked_rgb, new_rgb;
2371 
2372 	hacked_rgb = hack_rgb(rgb);
2373 
2374 	round_color_sRGB_to_48(&r, &g, &b, hacked_rgb);
2375 	r = ags_16_to_8(r, (float)(1 / (float)(display_red_gamma tcc_hack)));
2376 	g = ags_16_to_8(g, (float)(1 / (float)(display_green_gamma tcc_hack)));
2377 	b = ags_16_to_8(b, (float)(1 / (float)(display_blue_gamma tcc_hack)));
2378 	new_rgb = b | (g << 8) | (r << 16);
2379 
2380 	gamma_cache_rgb_2 = gamma_cache_rgb_1;
2381 	gamma_cache_color_2 = gamma_cache_color_1;
2382 
2383 	gamma_cache_rgb_1 = rgb;
2384 	/* The get_color takes values with gamma of display_*_gamma */
2385 	return gamma_cache_color_1 = drv->get_color(new_rgb);
2386 }
2387 
2388 #include "links_ic.inc"
2389 
get_links_icon(unsigned char ** data,int * width,int * height,ssize_t * skip,int pad)2390 void get_links_icon(unsigned char **data, int *width, int *height, ssize_t *skip, int pad)
2391 {
2392 	struct bitmap b;
2393 	unsigned short *tmp1;
2394 	float g = (float)((float)(user_gamma tcc_hack) / (float)sRGB_gamma);
2395 
2396 	b.x = 48;
2397 	b.y = 48;
2398 	*width = b.x;
2399 	*height = b.y;
2400 	b.skip = b.x * (drv->depth & 7);
2401 	while (b.skip % pad) b.skip++;
2402 	*skip = b.skip;
2403 	b.data = *data = mem_alloc(b.skip * b.y);
2404 	tmp1 = mem_alloc(6 * b.y * b.x);
2405 	agx_24_to_48(tmp1, links_icon, b.x * b.y, g, g, g);
2406 	(*round_fn)(tmp1, &b);
2407 	mem_free(tmp1);
2408 }
2409 
qb_palette(unsigned r_max,unsigned g_max,unsigned b_max,unsigned r,unsigned g,unsigned b,unsigned scale,unsigned rgb[3])2410 static inline void qb_palette(unsigned r_max, unsigned g_max, unsigned b_max, unsigned r, unsigned g, unsigned b, unsigned scale, unsigned rgb[3])
2411 {
2412 	rgb[0] = (r * scale + r_max / 2) / r_max;
2413 	rgb[1] = (g * scale + g_max / 2) / g_max;
2414 	rgb[2] = (b * scale + b_max / 2) / b_max;
2415 }
2416 
q_palette(unsigned size,unsigned color,unsigned scale,unsigned rgb[3])2417 void q_palette(unsigned size, unsigned color, unsigned scale, unsigned rgb[3])
2418 {
2419 	if (color >= size) {
2420 		rgb[0] = rgb[1] = rgb[2] = 0;
2421 		return;
2422 	}
2423 	switch (size) {
2424 		case 8:
2425 			qb_palette(1, 1, 1, color >> 2, (color >> 1) & 1, color & 1, scale, rgb);
2426 			break;
2427 		case 16:
2428 			qb_palette(1, 3, 1, color >> 3, (color >> 1) & 3, color & 1, scale, rgb);
2429 			break;
2430 		case 216:
2431 			qb_palette(5, 5, 5, color / 36, color / 6 % 6, color % 6, scale, rgb);
2432 			break;
2433 		case 256:
2434 			qb_palette(7, 7, 3, color >> 5, (color >> 2) & 7, color & 3, scale, rgb);
2435 			break;
2436 		case 32768:
2437 			qb_palette(31, 31, 31, color >> 10, (color >> 5) & 31, color & 31, scale, rgb);
2438 			break;
2439 		case 65536:
2440 			qb_palette(31, 63, 31, color >> 11, (color >> 5) & 63, color & 31, scale, rgb);
2441 			break;
2442 		case 16777216:
2443 			qb_palette(255, 255, 255, color >> 16, (color >> 8) & 255, color & 255, scale, rgb);
2444 			break;
2445 		default:
2446 			internal_error("q_palette: invalid size %u", size);
2447 	}
2448 }
2449 
rgb_distance(int r1,int g1,int b1,int r2,int g2,int b2)2450 double rgb_distance(int r1, int g1, int b1, int r2, int g2, int b2)
2451 {
2452 	double diff_r, diff_g, diff_b;
2453 	diff_r = (r1 - r2) * .30;
2454 	diff_r *= diff_r;
2455 	diff_g = (g1 - g2) * .59;
2456 	diff_g *= diff_g;
2457 	diff_b = (b1 - b2) * .11;
2458 	diff_b *= diff_b;
2459 	return diff_r + diff_g + diff_b;
2460 }
2461 
2462 #endif /* G */
2463