1 /* img.c
2  * Generic image decoding and PNG and JPG decoders.
3  * (c) 2002 Karel 'Clock' Kulhavy
4  * This is a part of the Links program, released under GPL.
5 
6  * Used in graphics mode of Links only
7  TODO: odstranit zbytecne ditherovani z strip_optimized header_dimensions_known,
8        protoze pozadi obrazku musi byt stejne jako pozadi stranky, a to se nikdy
9        neditheruje, protoze je to vzdy jednolita barva. Kdyz uz to nepujde
10        odstranit tak tam aspon dat fixne zaokrouhlovani.
11  TODO: dodelat stripy do jpegu a png a tiff.
12  */
13 
14 #include "links.h"
15 
16 #ifdef G
17 
18 #define RESTART_SIZE 8192
19 /* Size of biggest chunk of compressed data that is processed in one run */
20 
21 static struct g_object_image *global_goi;
22 struct cached_image *global_cimg;
23 int end_callback_hit;
24 
is_image_size_sane(ssize_t x,ssize_t y)25 static int is_image_size_sane(ssize_t x, ssize_t y)
26 {
27 	size_t a;
28 	if (x < 0 || y < 0) return 0;
29 	if (x >= MAXINT || y >= MAXINT) return 0;
30 	a = (size_t)x * (size_t)y * (drv->depth & 7);
31 	if (y && (size_t)a / (size_t)y / (drv->depth & 7) != (size_t)x) return 0;
32 	return a <= MAX_SIZE_T / 2;
33 }
34 
35 /* mem_free(cimg->decoder) */
destroy_decoder(struct cached_image * cimg)36 static void destroy_decoder (struct cached_image *cimg)
37 {
38 	if (cimg->decoder){
39 		switch(cimg->image_type){
40 		case IM_PNG:
41 			png_destroy_decoder(cimg);
42 			break;
43 #ifdef HAVE_JPEG
44 		case IM_JPG:
45 			jpeg_destroy_decoder(cimg);
46 			break;
47 #endif /* #ifdef HAVE_JPEG */
48 		case IM_GIF:
49 			gif_destroy_decoder(cimg);
50 			break;
51 		case IM_XBM:
52 			/* do nothing */
53 			break;
54 #ifdef HAVE_TIFF
55 		case IM_TIFF:
56 			tiff_destroy_decoder(cimg);
57 			break;
58 #endif
59 #ifdef HAVE_SVG
60 		case IM_SVG:
61 			svg_destroy_decoder(cimg);
62 			break;
63 #endif
64 		}
65 		mem_free(cimg->decoder);
66 	}
67 }
68 
mem_free_buffer(struct cached_image * cimg)69 static void mem_free_buffer(struct cached_image *cimg)
70 {
71 	mem_free(cimg->buffer);
72 }
73 
img_destruct_image(struct g_object * object)74 static void img_destruct_image(struct g_object *object)
75 {
76 	struct g_object_image *goi = get_struct(object, struct g_object_image, goti.go);
77 
78 	if (goi->orig_src) mem_free(goi->orig_src);
79 	if (goi->alt) mem_free(goi->alt);
80 	if (goi->name) mem_free(goi->name);
81 	if (goi->src) mem_free(goi->src);
82 	release_image_map(goi->goti.map);
83 	if (goi->list_entry.next) del_from_list(goi);
84 	if (goi->goti.go.xw && goi->goti.go.yw) {
85 		 /* At least one dimension is zero */
86 		deref_cached_image(goi->cimg);
87 	}
88 	mem_free(goi);
89 }
90 
91 /* Frees all data allocated by cached_image including cached image itself */
img_destruct_cached_image(struct cached_image * cimg)92 void img_destruct_cached_image(struct cached_image *cimg)
93 {
94 	switch (cimg->state){
95 		case 0:
96 		case 1:
97 		case 2:
98 		case 3:
99 		case 9:
100 		case 11:
101 		break;
102 
103 		case 12:
104 		case 14:
105 		if (cimg->gamma_table) mem_free(cimg->gamma_table);
106 		if (cimg->bmp_used){
107 			drv->unregister_bitmap(&(cimg->bmp));
108 		}
109 		if (cimg->strip_optimized){
110 			if (cimg->dregs) mem_free(cimg->dregs);
111 		}else{
112 			mem_free_buffer(cimg);
113 		}
114 		/*-fallthrough*/
115 		case 8:
116 		case 10:
117 		destroy_decoder(cimg);
118 		break;
119 
120 		case 13:
121 		case 15:
122 		drv->unregister_bitmap(&(cimg->bmp));
123 		break;
124 
125 #ifdef DEBUG
126 		default:
127 		fprintf(stderr, "img_destruct_cached_image: state=%d\n", cimg->state);
128 		internal_error("Invalid state in struct cached_image");
129 #endif /* #ifdef DEBUG */
130 	}
131 	mem_free(cimg->url);
132 	mem_free(cimg);
133 }
134 
135 /* You throw in a vertical dimension of image and it returns
136  * new dimension according to the aspect ratio and user-set image
137  * scaling factor. When scaling factor is 100% and screen pixels
138  * are non-square, the picture will be always in one dimension
139  * untouched and in the second _ENLARGED_. So that no information
140  * in the picture will be lost.
141  * Input may be <0. In this case output=input
142  * Input may be 0. In this case output=0.
143  * If input is >0 the output is also >0.
144  */
img_scale_h(unsigned scale,ssize_t in)145 static ssize_t img_scale_h(unsigned scale, ssize_t in)
146 {
147 	ssize_t out;
148 	/* We assume unsigned long holds at least 32 bits */
149 	unsigned long pre;
150 
151 	if (in<=0) return in;
152 	pre=((unsigned long)(aspect<65536UL?65536UL:aspect)*scale+128)>>8;
153 	out=(size_t)(((unsigned long)in*pre+12800UL)/25600UL);
154 	if (out<1) out=1;
155 	return out;
156 }
157 
img_scale_v(unsigned scale,ssize_t in)158 static ssize_t img_scale_v(unsigned scale, ssize_t in)
159 {
160 	ssize_t out;
161 	unsigned long divisor;
162 
163 	if (in<=0) return in;
164 	divisor=(100*(aspect>=65536UL?65536UL:aspect)+128)>>8;
165 	out=(ssize_t)(((unsigned long)in*(scale*256)+(divisor>>1))/divisor);
166 	if (out<1) out=1;
167 	return out;
168 }
169 
170 /* Returns height (pixels) for prescribed width (pixels). Honours aspect. */
width2height(double width_px,double width_mm,double height_mm)171 static ssize_t width2height(double width_px, double width_mm, double height_mm)
172 {
173 	ssize_t height_px;
174 
175 	if (width_px<=0) return 0;
176 	height_px=(ssize_t)((height_mm*width_px*65536)/(aspect*width_mm));
177 	if (height_px<1) height_px=1;
178 	return height_px;
179 
180 }
181 
182 /* Returns width (pixels) for prescribed height (pixels). Honours aspect. */
height2width(double height_px,double width_mm,double height_mm)183 static ssize_t height2width(double height_px, double width_mm, double height_mm)
184 {
185 	ssize_t width_px;
186 
187 	if (height_px<=0) return 0;
188 	width_px=(ssize_t)((width_mm*height_px*aspect)/(65536*height_mm));
189 	if (width_px<1) width_px=1;
190 	return width_px;
191 
192 }
193 
194 /* Compute 8-bit background for filling buffer with cimg->*_gamma
195  * (performs rounding) */
compute_background_8(struct cached_image * cimg,unsigned char rgb[3])196 void compute_background_8(struct cached_image *cimg, unsigned char rgb[3])
197 {
198 	unsigned short red, green, blue;
199 
200 	round_color_sRGB_to_48(&red, &green, &blue, cimg->background_color);
201 	rgb[0] = ags_16_to_8(red, (float)(cimg->red_gamma/(float)(user_gamma tcc_hack)));
202 	rgb[1] = ags_16_to_8(green, (float)(cimg->green_gamma/(float)(user_gamma tcc_hack)));
203 	rgb[2] = ags_16_to_8(blue, (float)(cimg->blue_gamma/(float)(user_gamma tcc_hack)));
204 }
205 
206 /* updates cimg state when header dimensions are know. Only allowed to be called
207  * in state 8 and 10.
208  * Allocates right amount of memory into buffer, formats it (with background or
209  * zeroes, depens on buffer_bytes_per_pixel). Updates dimensions (xww and yww)
210  * according to newly known header dimensions. Fills in gamma_stamp, bmp_used
211  * (zero because we not bother with generating bitmap here)
212  * and rows_added.
213  * Resets strip_optimized if image will be scaled or
214  * Allocates dregs if on exit strip_optimized is nonzero.
215  * Allocates and computes gamma_table, otherwise
216  *	sets gamma_table to NULL. Also doesn't make gamma table if image contains less
217  *	than 1024 pixels (it would be probably a waste of time).
218  * Output state is always 12 (from input state 8) or 14 (from input state 10).
219  *
220  * The caller must have set the following elements of cimg:
221  *	width
222  *	height
223  *	buffer_bytes_per_pixel
224  *	red_gamma
225  *	green_gamma
226  *	blue_gamma
227  *	strip_optimized
228  */
header_dimensions_known(struct cached_image * cimg)229 int header_dimensions_known(struct cached_image *cimg)
230 {
231 	unsigned short red, green, blue;
232 
233 #ifdef DEBUG
234 	if ((cimg->state^8)&13){
235 		fprintf(stderr,"cimg->state=%d\n",cimg->state);
236 		internal_error("Invalid state in header_dimensions_known");
237 	}
238 #endif /* #ifdef DEBUG */
239 	if (cimg->width<1||cimg->height<1){
240 		/*fprintf(stderr,"width=%d height=%d\n",cimg->width, cimg->height);*/
241 		return 1;
242 	}
243 	if (!is_image_size_sane(cimg->width, cimg->height)) {
244 		return 1;
245 	}
246 	if (cimg->wanted_xw<0){
247 		/* Unspecified width */
248 		if (cimg->wanted_yw<0){
249 			/* Unspecified neither width nor height */
250 			cimg->xww=img_scale_h(cimg->scale, cimg->width);
251 			cimg->yww=img_scale_v(cimg->scale, cimg->height);
252 		}else{
253 			/* Unspecified width specified height */
254 			cimg->xww=height2width(cimg->yww,
255 					cimg->width, cimg->height);
256 			if (cimg->xww<=0) cimg->xww=1;
257 
258 		}
259 	}else{
260 		/* Specified width */
261 		if (cimg->wanted_yw<0){
262 			/* Unspecified height, specified width */
263 			cimg->yww=width2height(cimg->xww,
264 					cimg->width, cimg->height);
265 			if (cimg->yww<=0) cimg->yww=1;
266 		}else if (cimg->wanted_xyw_meaning==MEANING_AUTOSCALE){
267 			/* Specified height and width and autoscale meant */
268 			/* Try first to nail the height */
269 			cimg->yww=cimg->wanted_yw;
270 			cimg->xww=height2width(cimg->yww,
271 					cimg->width, cimg->height);
272 			if (cimg->xww>cimg->wanted_xw)
273 			{
274 				/* Width too much, we nail the width */
275 				cimg->xww=cimg->wanted_xw;
276 				cimg->yww=width2height(cimg->xww,
277 						cimg->width, cimg->height);
278 			}
279 
280 			/* Some sanity checks */
281 			if (cimg->xww<=0) cimg->xww=1;
282 			if (cimg->yww<=0) cimg->yww=1;
283 		}
284 	}
285 	if (!is_image_size_sane(cimg->xww, cimg->yww)) {
286 		cimg->xww = cimg->width;
287 		cimg->yww = cimg->height;
288 	}
289 
290 #ifdef HAVE_SVG
291 	if (cimg->image_type == IM_SVG) {
292 		/* SVG images are scaled using the cairo library, not the Links scaler */
293 		cimg->width = cimg->xww;
294 		cimg->height = cimg->yww;
295 	}
296 #endif
297 
298 	if (cimg->width!=cimg->xww||cimg->height!=cimg->yww) cimg->strip_optimized=0;
299 	cimg->gamma_stamp=gamma_stamp;
300 	if (cimg->strip_optimized){
301 		struct bitmap tmpbmp;
302 		unsigned short *buf_16;
303 		ssize_t i;
304 
305 		tmpbmp.x = (int)cimg->width;
306 		tmpbmp.y = 1;
307 		/* No buffer, bitmap is valid from the very beginning */
308 		cimg->bmp.x = (int)cimg->width;
309 		cimg->bmp.y = (int)cimg->height;
310 		if (drv->get_empty_bitmap(&(cimg->bmp))) {
311 			cimg->dregs = NULL;
312 			goto skip_img;
313 		}
314 		if ((size_t)cimg->width > MAX_SIZE_T / sizeof(*buf_16) / 3) overalloc();
315 		buf_16 = mem_alloc(sizeof(*buf_16) * 3 * (size_t)cimg->width);
316 		round_color_sRGB_to_48(&red, &green, &blue
317 			, cimg->background_color);
318 		mix_one_color_48(buf_16,cimg->width, red, green, blue);
319 #ifdef DEBUG
320 		if (cimg->height<=0){
321 			fprintf(stderr,"cimg->height=%ld\n", (long)cimg->height);
322 			internal_error("Invalid cimg->height in strip_optimized section of header_dimensions_known");
323 		}
324 #endif /* #ifdef DEBUG */
325 		/* The skip is uninitialized here and is read by dither_start
326 		 * but is not used in any malicious way so it doesn't matter
327 		 */
328 		tmpbmp.data = cimg->bmp.data;
329 		tmpbmp.skip = cimg->bmp.skip;
330 		cimg->dregs=dither_images?dither_start(buf_16,&tmpbmp):NULL;
331 		tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;
332 		if (cimg->dregs)
333 			for (i=cimg->height-1;i;i--){
334 				dither_restart(buf_16,&tmpbmp,cimg->dregs);
335 				tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;
336 			}
337 		else
338 			for (i=cimg->height-1;i;i--){
339 				(*round_fn)(buf_16,&tmpbmp);
340 				tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;
341 			}
342 		mem_free(buf_16);
343 		skip_img:
344 		drv->register_bitmap(&(cimg->bmp));
345 		if(cimg->dregs) memset(cimg->dregs,0,cimg->width*sizeof(*cimg->dregs)*3);
346 		cimg->bmp_used=1; /* Nonzero value */
347 		/* This ensures the dregs are none and because strip
348 		 * optimization is unusable in interlaced pictures,
349 		 * this saves the zeroing out at the beginning of the
350 		 * decoder itself.
351 		 */
352 	}else {
353 		cimg->rows_added=1;
354 		cimg->bmp_used=0;
355 		if (cimg->width && (size_t)cimg->width * (size_t)cimg->height / (size_t)cimg->width != (size_t)cimg->height) overalloc();
356 		cimg->buffer = mem_alloc_mayfail((size_t)cimg->width * (size_t)cimg->height * (size_t)cimg->buffer_bytes_per_pixel);
357 		if (!cimg->buffer)
358 			return 1;
359 		if (cimg->buffer_bytes_per_pixel==4
360 				||cimg->buffer_bytes_per_pixel==4
361 				*sizeof(unsigned short))
362 			{
363 			/* Make the buffer contain full transparency */
364 			memset(cimg->buffer, 0, (size_t)cimg->width * (size_t)cimg->height * (size_t)cimg->buffer_bytes_per_pixel);
365 		}else{
366 			/* Fill the buffer with background color */
367 			if (cimg->buffer_bytes_per_pixel > 4){
368 				/* 16-bit */
369 				unsigned short red, green, blue;
370 
371 				round_color_sRGB_to_48(&red, &green, &blue, cimg->background_color);
372 
373 				red=ags_16_to_16(red, (float)(cimg->red_gamma / (float)(user_gamma tcc_hack)));
374 				green=ags_16_to_16(green, (float)(cimg->green_gamma / (float)(user_gamma tcc_hack)));
375 				blue=ags_16_to_16(blue, (float)(cimg->blue_gamma / (float)(user_gamma tcc_hack)));
376 				mix_one_color_48((unsigned short *)cimg->buffer, cimg->width*cimg->height, red, green, blue);
377 			} else {
378 				unsigned char rgb[3];
379 
380 				/* 8-bit */
381 				compute_background_8(cimg, rgb);
382 				mix_one_color_24(cimg->buffer, cimg->width * cimg->height, rgb[0], rgb[1], rgb[2]);
383 			}
384 		}
385 	}
386 	if (cimg->buffer_bytes_per_pixel<=4&&cimg->width*cimg->height>=1024){
387 		make_gamma_table(cimg);
388 	}else if (cimg->buffer_bytes_per_pixel>=6&&cimg->width*cimg->height>=262144){
389 		make_gamma_table(cimg);
390 	}else cimg->gamma_table=NULL;
391 	cimg->state|=4; /* Update state */
392 	return 0;
393 }
394 
395 /* Fills "tmp" buffer with the resulting data and does not free the input
396  * buffer. May be called only in states 12 and 14 of cimg
397  */
buffer_to_16(unsigned short * tmp,struct cached_image * cimg,unsigned char * buffer,ssize_t height)398 static unsigned short *buffer_to_16(unsigned short *tmp, struct cached_image *cimg, unsigned char *buffer, ssize_t height)
399 {
400 	unsigned short red, green, blue;
401 
402 #ifdef DEBUG
403 	if (cimg->state != 12 && cimg->state != 14){
404 		fprintf(stderr, "cimg->state=%d\n", cimg->state);
405 		internal_error("invalid state in buffer_to_16");
406 	}
407 #endif /* #ifdef DEBUG */
408 	switch (cimg->buffer_bytes_per_pixel) {
409 		case 3:
410 			if (cimg->gamma_table) {
411 				agx_24_to_48_table(tmp, buffer, cimg->width*height, cimg->gamma_table);
412 			} else {
413 				agx_24_to_48(tmp, buffer, cimg->width * height,
414 					(float)((float)(user_gamma tcc_hack) / cimg->red_gamma),
415 					(float)((float)(user_gamma tcc_hack) / cimg->green_gamma),
416 					(float)((float)(user_gamma tcc_hack) / cimg->blue_gamma));
417 			}
418 		break;
419 
420 		case 3 * sizeof(unsigned short):
421 			if (cimg->gamma_table) {
422 				agx_48_to_48_table(tmp, (unsigned short *)buffer, cimg->width * height, cimg->gamma_table);
423 			} else {
424 				agx_48_to_48(tmp, (unsigned short *)buffer, cimg->width * height,
425 					(float)((float)(user_gamma tcc_hack) / cimg->red_gamma),
426 					(float)((float)(user_gamma tcc_hack) / cimg->green_gamma),
427 					(float)((float)(user_gamma tcc_hack) / cimg->blue_gamma));
428 			}
429 		break;
430 
431 		/* Alpha's: */
432 		case 4:
433 			round_color_sRGB_to_48(&red,&green,&blue,cimg->background_color);
434 			if (cimg->gamma_table) {
435 				agx_and_uc_32_to_48_table(tmp, buffer, cimg->width * height, cimg->gamma_table, red, green, blue);
436 			} else {
437 				agx_and_uc_32_to_48(tmp,buffer, cimg->width*height,
438 					(float)((float)(user_gamma tcc_hack) / cimg->red_gamma),
439 					(float)((float)(user_gamma tcc_hack) / cimg->green_gamma),
440 					(float)((float)(user_gamma tcc_hack) / cimg->blue_gamma),
441 					red, green, blue);
442 			}
443 		break;
444 
445 		case 4 * sizeof(unsigned short):
446 			round_color_sRGB_to_48(&red, &green, &blue, cimg->background_color);
447 			if (cimg->gamma_table) {
448 				agx_and_uc_64_to_48_table(tmp, (unsigned short *)buffer, cimg->width * height, cimg->gamma_table, red, green, blue);
449 			} else {
450 				agx_and_uc_64_to_48(tmp, (unsigned short *)buffer, cimg->width * height,
451 					(float)((float)(user_gamma tcc_hack) / cimg->red_gamma),
452 					(float)((float)(user_gamma tcc_hack) / cimg->green_gamma),
453 					(float)((float)(user_gamma tcc_hack) / cimg->blue_gamma),
454 					red,green,blue);
455 			}
456 		break;
457 
458 #ifdef DEBUG
459 		default:
460 			internal_error("buffer_to_16: unknown mem organization");
461 #endif /* #ifdef DEBUG */
462 
463 	}
464 	return tmp;
465 }
466 
467 /* Returns allocated buffer with the resulting data and does not free the input
468  * buffer. May be called only in states 12 and 14 of cimg
469  * use_strip: 1 if the image is already registered and prepare_strip and
470  * commit_strip is to be used
471  * 0: if the image is not yet registered and instead one big register_bitmap
472  * will be used eventually
473  * dregs must be externally allocated and contain required value or must be
474  * NULL.
475  * if !dregs then rounding is performed instead of dithering.
476  * dregs are not freed.
477  * bottom dregs are placed back into dregs.
478  * Before return the bitmap will be in registered state and changes will be
479  * commited.
480  * height must be >=1 !!!
481  */
buffer_to_bitmap_incremental(struct cached_image * cimg,unsigned char * buffer,ssize_t height,ssize_t yoff,int * dregs,int use_strip)482 void buffer_to_bitmap_incremental(struct cached_image *cimg,
483 	unsigned char *buffer, ssize_t height, ssize_t yoff, int *dregs, int use_strip)
484 {
485 #define max_height 16
486 /* max_height must be at least 1 */
487 	unsigned short *tmp;
488 	struct bitmap tmpbmp;
489 	ssize_t add1 = 0, add2;
490 
491 #ifdef DEBUG
492 	if (cimg->state!=12&&cimg->state!=14){
493 		fprintf(stderr,"cimg->state=%d\n",cimg->state);
494 		internal_error("Invalid state in buffer_to_bitmap_incremental\n");
495 	}
496 	if (height<1){
497 		fprintf(stderr,"height=%ld\n", (long)height);
498 		internal_error("Invalid height in buffer_to_bitmap_incremental\n");
499 	}
500 	if (cimg->width<1||cimg->height<1){
501 		fprintf(stderr,"cimg->width=%ld, cimg->height=%ld\n", (long)cimg->width, (long)cimg->height);
502 		internal_error("Invalid cimg->width x cimg->height in\
503 buffer_to_bitmap_incremental");
504 	}
505 #endif /* #ifdef DEBUG */
506 	if ((size_t)cimg->width > MAX_SIZE_T / (size_t)max_height / 3 / sizeof(*tmp)) overalloc();
507 	tmp=mem_alloc((size_t)cimg->width * (size_t)(height < max_height ? height : max_height) * 3 * sizeof(*tmp));
508 	/* Prepare a fake bitmap for dithering */
509 	tmpbmp.x = (int)cimg->width;
510 	if (!use_strip){
511 	       tmpbmp.data=(unsigned char *)cimg->bmp.data+cimg->bmp.skip*yoff;
512 	       add1=cimg->bmp.skip*max_height;
513 	}
514 	add2=cimg->buffer_bytes_per_pixel*cimg->width*max_height;
515 not_enough:
516 	tmpbmp.y = (int)(height < max_height ? height : max_height);
517 	if (use_strip) {
518 		tmpbmp.data = drv->prepare_strip(&(cimg->bmp), (int)yoff, tmpbmp.y);
519 		if (!tmpbmp.data) goto prepare_failed;
520 	}
521 	tmpbmp.skip=cimg->bmp.skip;
522 	buffer_to_16(tmp, cimg, buffer, tmpbmp.y);
523 	if (dregs) {
524 		dither_restart(tmp, &tmpbmp, dregs);
525 	} else {
526 		(*round_fn)(tmp, &tmpbmp);
527 	}
528 	if (use_strip) {
529 		prepare_failed:
530 		drv->commit_strip(&(cimg->bmp), (int)yoff, tmpbmp.y);
531 	}
532 	height-=tmpbmp.y;
533 	if (!height) goto end;
534 	buffer+=add2;
535 	yoff+=tmpbmp.y;
536 	tmpbmp.data=(unsigned char *)tmpbmp.data+add1;
537 	/* This has no effect if use_strip but it's faster
538 	 * to add to bogus value than to play with
539 	 * conditional jumps.
540 	 */
541 	goto not_enough;
542 end:
543 	mem_free(tmp);
544 	if (!use_strip) drv->register_bitmap(&(cimg->bmp));
545 }
546 
547 /* Takes the buffer and resamples the data into the bitmap. Automatically
548  * destroys the previous bitmap. Must be called only when cimg->buffer is valid.
549  * Sets bmp_used to non-zero.
550  * If gamma_table is used, it must be still allocated here (take care if you
551  * want to destroy gamma table and call buffer_to_bitmap, first call buffer_to_bitmap
552  * and then destroy gamma_table).
553  */
buffer_to_bitmap(struct cached_image * cimg)554 static void buffer_to_bitmap(struct cached_image *cimg)
555 {
556 	unsigned short *tmp, *tmp1;
557 	ssize_t ix, iy, ox, oy;
558 	int gonna_be_smart;
559 	int *dregs;
560 
561 #ifdef DEBUG
562 	if(cimg->state!=12&&cimg->state!=14){
563 		fprintf(stderr,"cimg->state=%d\n",cimg->state);
564 		internal_error("buffer_to_bitmap called in invalid state");
565 	}
566 	if (cimg->strip_optimized) internal_error("strip_optimized in buffer_to_bitmap");
567 	if (cimg->width<1||cimg->height<1){
568 		fprintf(stderr,"cimg->width=%ld, cimg->height=%ld\n", (long)cimg->width, (long)cimg->height);
569 		internal_error("Invalid cimg->width x cimg->height in buffer_to_bitmap");
570 	}
571 #endif /* #ifdef DEBUG */
572 
573 
574 	if (!cimg->rows_added) return;
575 
576 	/* Here of course width and height must be already filled */
577 	cimg->rows_added=0;
578 	ix=cimg->width;
579 	iy=cimg->height;
580 	ox=cimg->xww;
581 	oy=cimg->yww;
582 	if (ix==ox&&iy==oy) gonna_be_smart=1;
583 	else{
584 		gonna_be_smart=0;
585 		if (ix && (size_t)ix * (size_t)iy / (size_t)ix != (size_t)iy) overalloc();
586 		if ((size_t)ix * (size_t)iy > MAX_SIZE_T / sizeof(*tmp) / 3) overalloc();
587 		tmp = mem_alloc_mayfail((size_t)ix * (size_t)iy * 3 * sizeof(*tmp));
588 		if (tmp) buffer_to_16(tmp, cimg, cimg->buffer, iy);
589 		if (!cimg->decoder){
590 			mem_free_buffer(cimg);
591 			cimg->buffer=NULL;
592 		}
593 
594 		/* Scale the image to said size */
595 #ifdef DEBUG
596 		if (ox<=0||oy<=0){
597 			internal_error("ox or oy <=0 before resampling image");
598 		}
599 #endif /* #ifdef DEBUG */
600 		if (tmp && (ix!=ox || iy!=oy)) {
601 			/* We must really scale */
602 			tmp1=tmp;
603 			scale_color(tmp1,ix,iy,&tmp,ox,oy);
604 		}
605 	}
606 	if (cimg->bmp_used) drv->unregister_bitmap(&cimg->bmp);
607 	cimg->bmp.x = (int)ox;
608 	cimg->bmp.y = (int)oy;
609 	if (drv->get_empty_bitmap(&(cimg->bmp))) {
610 		if (!gonna_be_smart) {
611 			if (tmp) {
612 				mem_free(tmp);
613 			}
614 		}
615 		goto bitmap_failed;
616 	}
617 	if (gonna_be_smart){
618 		if (dither_images) {
619 			if ((size_t)cimg->width > MAX_SIZE_T / 3 / sizeof(*dregs)) overalloc();
620 			dregs = mem_calloc(sizeof(*dregs) * 3 * (size_t)cimg->width);
621 		} else {
622 			dregs = NULL;
623 		}
624 		buffer_to_bitmap_incremental(cimg, cimg->buffer, cimg->height,
625 			0, dregs, 0);
626 		if (dregs) mem_free(dregs);
627 	}else{
628 		if (tmp) {
629 			if (dither_images)
630 				dither(tmp, &cimg->bmp);
631 			else
632 				(*round_fn)(tmp, &cimg->bmp);
633 			mem_free(tmp);
634 		} else {
635 			int i;
636 			unsigned char *ptr = cimg->bmp.data;
637 			for (i = 0; i < cimg->bmp.y; i++) {
638 				memset(ptr, 0, cimg->bmp.x * (drv->depth & 7));
639 				ptr += cimg->bmp.skip;
640 			}
641 		}
642 		bitmap_failed:
643 		drv->register_bitmap(&(cimg->bmp));
644 	}
645 	cimg->bmp_used=1;
646 	/* Indicate that the bitmap is valid. The value is just any
647 	   nonzero value */
648 	cimg->rows_added=0;
649 	/* Indicate the bitmap is up-to-date */
650 }
651 
652 /* Performs state transition for end of stream or error in image or
653  * end of image */
img_end(struct cached_image * cimg)654 void img_end(struct cached_image *cimg)
655 {
656 	switch(cimg->state){
657 		case 12:
658 		case 14:
659 		if (cimg->strip_optimized){
660 		       if (cimg->dregs)	mem_free(cimg->dregs);
661 		}
662 		else{
663 			buffer_to_bitmap(cimg);
664 			mem_free_buffer(cimg);
665 		}
666 		if (cimg->gamma_table) mem_free(cimg->gamma_table);
667 		/*-fallthrough*/
668 		case 8:
669 		case 10:
670 		destroy_decoder(cimg);
671 		case 0:
672 		case 1:
673 		case 2:
674 		case 3:
675 		case 9:
676 		case 11:
677 		case 13:
678 		case 15:
679 		break;
680 #ifdef DEBUG
681 		default:
682 		fprintf(stderr,"state=%d\n",cimg->state);
683 		internal_error("Invalid state encountered in end");
684 #endif /* #ifdef DEBUG */
685 	}
686 	cimg->state|=1;
687 }
688 
r3l0ad(struct cached_image * cimg,struct g_object_image * goi)689 static void r3l0ad(struct cached_image *cimg, struct g_object_image *goi)
690 {
691 	cimg->eof_hit=0;
692 	cimg->last_count=goi->af->rq->ce->count;
693 	cimg->last_count2=goi->af->rq->ce->count2;
694 	cimg->gamma_stamp=gamma_stamp;
695 	switch(cimg->state){
696 		case 8:
697 		case 10:
698 		destroy_decoder(cimg);
699 		case 1:
700 		case 3:
701 		case 9:
702 		case 11:
703 		case 0:
704 		case 2:
705 		break;
706 
707 		case 12:
708 		if (cimg->gamma_table) mem_free(cimg->gamma_table);
709 		destroy_decoder(cimg);
710 		if (cimg->strip_optimized){
711 			if (cimg->dregs) mem_free(cimg->dregs);
712 		}else{
713 			mem_free_buffer(cimg);
714 		}
715 		if (cimg->bmp_used){
716 			case 13:
717 			drv->unregister_bitmap(&cimg->bmp);
718 		}
719 		cimg->xww=img_scale_h(cimg->scale, cimg->wanted_xw<0?32:cimg->wanted_xw);
720 		cimg->yww=img_scale_v(cimg->scale, cimg->wanted_yw<0?32:cimg->wanted_yw);
721 		break;
722 
723 		case 14:
724 		if (cimg->gamma_table) mem_free(cimg->gamma_table);
725 		destroy_decoder(cimg);
726 		if (cimg->strip_optimized){
727 			if (cimg->dregs) mem_free(cimg->dregs);
728 		}else{
729 			mem_free_buffer(cimg);
730 		}
731 		if (cimg->bmp_used){
732 			case 15:
733 			drv->unregister_bitmap(&cimg->bmp);
734 		}
735 		break;
736 
737 #ifdef DEBUG
738 		default:
739 		fprintf(stderr,"cimg->state=%d\n",cimg->state);
740 		internal_error("Invalid state in r3l0ad()");
741 #endif /* #ifdef DEBUG */
742 	}
743 	cimg->state&=2;
744 }
745 
746 /* Returns 1 if match.
747  * If doesn't return 1 then returns 0
748  */
dtest(unsigned char * templat,unsigned char * test)749 static inline int dtest(unsigned char *templat, unsigned char *test)
750 {
751 	return !casestrcmp(templat, test);
752 }
753 
754 /* This may be called only in state 0 or 2 */
type(struct cached_image * cimg,unsigned char * content_type,unsigned char * data)755 static void type(struct cached_image *cimg, unsigned char *content_type, unsigned char *data /* at least 4 bytes */)
756 {
757 #ifdef DEBUG
758 	if (cimg->state!=0&&cimg->state!=2){
759 		fprintf(stderr,"cimg->state=%d\n",cimg->state);
760 		internal_error("Invalid state encountered in type()");
761 	}
762 #endif /* #ifdef DEBUG */
763 #ifdef HAVE_JPEG
764 	if (data[0] == 0xff && data[1] == 0xd8)
765 		goto have_jpeg;
766 #endif
767 #ifdef HAVE_TIFF
768 	if (data[0] == 'I' && data[1] == 'I')
769 		goto have_tiff;
770 	if (data[0] == 'M' && data[1] == 'M')
771 		goto have_tiff;
772 #endif
773 #ifdef HAVE_SVG
774 	if (data[0] == '<' && data[1] == '?')
775 		goto have_svg;
776 #endif
777 	if (data[0] == 0x89 && data[1] == 'P' && data[2] == 'N' && data[3] == 'G')
778 		goto have_png;
779 	if (data[0] == 'G' && data[1] == 'I' && data[2] == 'F')
780 		goto have_gif;
781 #ifdef HAVE_JPEG
782 	if (dtest(cast_uchar "image/jpeg",content_type) ||
783 	    dtest(cast_uchar "image/jpg",content_type) ||
784 	    dtest(cast_uchar "image/jpe",content_type) ||
785 	    dtest(cast_uchar "image/pjpe",content_type) ||
786 	    dtest(cast_uchar "image/pjpeg",content_type) ||
787 	    dtest(cast_uchar "image/pjpg",content_type)) {
788 		have_jpeg:
789 		cimg->image_type=IM_JPG;
790 		jpeg_start(cimg);
791 	} else
792 #endif /* #ifdef HAVE_JPEG */
793 	if (dtest(cast_uchar "image/png",content_type) ||
794 	    dtest(cast_uchar "image/x-png",content_type)) {
795 		have_png:
796 		cimg->image_type=IM_PNG;
797 		png_start(cimg);
798 	} else if (dtest(cast_uchar "image/gif",content_type)){
799 		have_gif:
800 		cimg->image_type=IM_GIF;
801 		gif_start(cimg);
802 	} else if (dtest(cast_uchar "image/x-xbitmap",content_type)){
803 		cimg->image_type=IM_XBM;
804 		xbm_start(cimg);
805 	} else
806 #ifdef HAVE_TIFF
807 	if (dtest(cast_uchar "image/tiff",content_type) ||
808 	    dtest(cast_uchar "image/tif",content_type)) {
809 		have_tiff:
810 		cimg->image_type=IM_TIFF;
811 		tiff_start(cimg);
812 	} else
813 #endif /* #ifdef HAVE_TIFF */
814 #ifdef HAVE_SVG
815 	if (dtest(cast_uchar "image/svg+xml",content_type) ||
816 	    dtest(cast_uchar "image/svg",content_type)) {
817 		have_svg:
818 		cimg->image_type=IM_SVG;
819 		svg_start(cimg);
820 	} else
821 #endif /* #ifdef HAVE_SVG */
822 	{
823 		/* Error */
824 		img_end(cimg);
825 		return;
826 	}
827 	cimg->state|=8; /* Advance the state according to the table in
828 			   links-doc.html */
829 	cimg->last_length=0;
830 }
831 
832 /* Doesn't print anything. Downloads more data if available.
833  * Sets up cimg->reparse and cimg->xww and cimg->yww accordingly to
834  * the state of the decoder. When changing xww and yww also changes xw and yw
835  * in g_object_image.
836  *      return value 1 means the data were chopped and the caller shall not redraw
837  *		(because it would be too slow and because we are probably choked
838  *		up with the data)
839  */
img_process_download(struct g_object_image * goi,struct f_data_c * fdatac)840 static int img_process_download(struct g_object_image *goi, struct f_data_c *fdatac)
841 {
842 	unsigned char *data, *ctype;
843 	size_t total_len;
844 	struct cached_image *cimg = goi->cimg;
845 	int chopped=0;
846 
847 #ifdef DEBUG
848 	if (!goi->af) internal_error("NULL goi->af in process_download\n");
849 	if (cimg->state>=16){ /* Negative don't occur because it's unsigned char */
850 		fprintf(stderr,"cimg->state=%d\n",cimg->state);
851 		internal_error("Invalid cimg->state in img_process_download\n");
852 	}
853 #endif /* #ifdef DEBUG */
854 	if (!goi->af->rq) return 0;
855 	if (get_file(goi->af->rq, &data, &total_len)) goto end;
856 	if (total_len < 4) goto end;
857 	if (total_len > MAXINT) total_len = MAXINT;
858 	/*fprintf(stderr, "processing: %s\n", goi->af->rq->ce->url);*/
859 	if (goi->af->rq->ce->count2!=cimg->last_count2||
860 		(goi->af->rq->ce->count!=cimg->last_count && cimg->eof_hit) ||
861 		(cimg->state>=12&&gamma_stamp!=cimg->gamma_stamp)){
862 		/* Reload */
863 		r3l0ad(cimg,goi);
864 	}
865 	/*if (!goi->af->rq->ce->head) goto end;*/ /* Mikulas: head muze byt NULL*/ /* Mikulas: tak se to zpracuje a nebude se skakat na konec, kdyz je to NULL */
866 
867 	if (cimg->state==0||cimg->state==2){
868 		/* Type still unknown */
869 		ctype=get_content_type(goi->af->rq->ce->head,
870 			goi->af->rq->url);
871 		if (!ctype) ctype = stracpy(cast_uchar "application/octet-stream");
872 		type(cimg,ctype,data);
873 		mem_free(ctype);
874 	}
875 
876 	/* Now, if we are in state where decoder is running (8, 10, 12, 14), we may feed
877 	 * some data into it.
878 	 */
879 
880 	if (!((cimg->state^8)&9)){
881 		int length = (int)total_len;
882 		if (length<=cimg->last_length) goto end; /* No new data */
883 
884 		data+=cimg->last_length;
885 		length-=cimg->last_length;
886 		if (length>RESTART_SIZE){
887 			length=RESTART_SIZE;
888 			chopped=1;
889 			if (fdatac) {
890 				refresh_image(fdatac, &goi->goti.go, 0);
891 			}
892 		}
893 		/* Decoder has been already started */
894 		switch(cimg->image_type){
895 		case IM_PNG:
896 			png_restart(cimg,data,length);
897 			break;
898 #ifdef HAVE_JPEG
899 		case IM_JPG:
900 			jpeg_restart(cimg,data,length);
901 			break;
902 #endif /* #ifdef HAVE_JPEG */
903 		case IM_XBM:
904 			xbm_restart(cimg,data,length);
905 			break;
906 		case IM_GIF:
907 			gif_restart(data,length);
908 			break;
909 #ifdef HAVE_TIFF
910 		case IM_TIFF:
911 			tiff_restart(cimg,data,length);
912 			break;
913 #endif /* #ifdef HAVE_TIFF */
914 #ifdef HAVE_SVG
915 		case IM_SVG:
916 			svg_restart(cimg,data,length);
917 			break;
918 #endif /* #ifdef HAVE_SVG */
919 #ifdef DEBUG
920 		default:
921 			fprintf(stderr,"cimg->image_type=%d\n",cimg->state);
922 			internal_error("Invalid image_type encountered when processing data in\
923 img_process_download.\n");
924 #endif /* #ifdef DEBUG */
925 		}
926 		cimg->last_length+=length;
927 	}
928 	end:
929 
930 	/* Test end */
931 	if (!is_entry_used(goi->af->rq->ce) && (goi->af->rq->state < 0
932 		||(goi->af->rq->ce&&goi->af->rq->stat.state<0))){
933 		/* We must not perform end with chopped because some
934 		 * unprocessed data still wait for us :)
935 		 */
936 		if (!chopped){
937 			if (!((cimg->state^8)&9)) {
938 #ifdef HAVE_TIFF
939 				if (cimg->image_type==IM_TIFF)
940 					tiff_finish(cimg);
941 #endif
942 #ifdef HAVE_SVG
943 				if (cimg->image_type==IM_SVG)
944 					svg_finish(cimg);
945 #endif
946 			}
947 			cimg->eof_hit=1;
948 			if (goi->af->rq->ce)
949 				cimg->last_count=goi->af->rq->ce->count;
950 			img_end(cimg);
951 		}
952 	} else if (!chopped) {
953 		if (fdatac) {
954 			if (f_is_finished(fdatac->f_data)) {
955 				refresh_image(fdatac, &goi->goti.go, 2000);
956 			} else {
957 	/*
958 	 * Fix a bug - if we have a text file with html and built-in image using
959 	 * the data:// url. If we press '\' to toggle the view from text to
960 	 * html, the image is not displayed correctly. We need to reset
961 	 * fdatac->done to force re-parse.
962 	 */
963 				fdatac->done = 0;
964 			}
965 		}
966 	}
967 	return chopped;
968 }
969 
970 /* Input: rgb (sRGB) triplet (0...255)
971  * Returns a color that is very contrasty on that background sRGB color
972  */
get_foreground(int rgb)973 int get_foreground(int rgb)
974 {
975 	int r,g,b;
976 
977 	r=(rgb>>16)&255;
978 	g=(rgb>>8)&255;
979 	b=rgb&255;
980 
981 	r=r<128?255:0;
982 	g=g<128?255:0;
983 	b=b<128?255:0;
984 
985 	return (r<<16)|(g<<8)|b;
986 }
987 
draw_frame_mark(struct graphics_device * dev,int x,int y,int xw,int yw,long bg,long fg,int broken)988 static void draw_frame_mark(struct graphics_device *dev, int x, int y, int xw, int yw, long bg, long fg, int broken)
989 {
990 #ifdef DEBUG
991 	if (xw<1||yw<1) internal_error("zero dimension in draw_frame_mark");
992 #endif /* #ifdef DEBUG */
993 	if (broken == 1){
994 		/* Draw between ( 0 and 1/4 ) and ( 3/4 and 1 ) of each
995 		 * side (0-1)
996 		 */
997 		 int xl, xh, yl, yh;
998 
999 		 xh=xw-(xl=xw>>2);
1000 		 yh=yw-(yl=yw>>2);
1001 		/* Draw full sides and the box inside */
1002 		drv->draw_hline(dev,x,y,x+xl,fg);
1003 		drv->draw_hline(dev,x+xl,y,x+xh,bg);
1004 		drv->draw_hline(dev,x+xh,y,x+xw,fg);
1005 		if (yw>=1){
1006 			if (yw>=2){
1007 				drv->draw_vline(dev,x,y+1,y+yl,fg);
1008 				drv->draw_vline(dev,x,y+yl,y+yh,bg);
1009 				drv->draw_vline(dev,x,y+yh,y+yw-1,fg);
1010 				if (xw>=1){
1011 					if (xw>=2){
1012 						drv->fill_area(dev,
1013 							x+1,y+1,x+xw-1,y+yw-1,
1014 							bg);
1015 					}
1016 					drv->draw_vline(dev,x+xw-1,y+1,y+yl,fg);
1017 					drv->draw_vline(dev,x+xw-1,y+yl,y+yh,bg);
1018 					drv->draw_vline(dev,x+xw-1,y+yh,y+yw-1,fg);
1019 				}
1020 			}
1021 			drv->draw_hline(dev,x,y+yw-1,x+xl,fg);
1022 			drv->draw_hline(dev,x+xl,y+yw-1,x+xh,bg);
1023 			drv->draw_hline(dev,x+xh,y+yw-1,x+xw,fg);
1024 		}
1025 	}else {
1026 		/* Draw full sides and the box inside */
1027 		drv->draw_hline(dev,x,y,x+xw,fg);
1028 		if (yw>=1){
1029 			if (yw>=2){
1030 				drv->draw_vline(dev,x,y+1,y+yw-1,fg);
1031 				if (xw>=1){
1032 					if (xw>=2){
1033 						if (broken < 2) drv->fill_area(dev,
1034 							x+1,y+1,x+xw-1,y+yw-1,
1035 							bg);
1036 					}
1037 					drv->draw_vline(dev,x+xw-1,y+1,
1038 						y+yw-1,fg);
1039 				}
1040 			}
1041 			drv->draw_hline(dev,x,y+yw-1,x+xw,fg);
1042 		}
1043 		if (broken == 2 && xw > 2 && yw > 2) {
1044 			draw_frame_mark(dev, x + 1, y + 1, xw - 2, yw - 2, bg, fg, 3);
1045 		}
1046 	}
1047 }
1048 
image_backgronud(struct cached_image * cimg)1049 static long image_backgronud(struct cached_image *cimg)
1050 {
1051 	if (!cimg) return dip_get_color_sRGB(0x00c0c0c0);
1052 	return dip_get_color_sRGB(cimg->background_color);
1053 }
1054 
image_foregronud(struct cached_image * cimg)1055 static long image_foregronud(struct cached_image *cimg)
1056 {
1057 	if (!cimg) return dip_get_color_sRGB(0x00000000);
1058 	return dip_get_color_sRGB(get_foreground(cimg->background_color));
1059 }
1060 
1061 /* Entry is allowed only in states 12, 13, 14, 15
1062  * Draws the picture from bitmap.
1063  * Before doing so, ensures that bitmap is present and if not, converts it from
1064  * the buffer.
1065  */
draw_picture(struct f_data_c * fdatac,struct g_object_image * goi,int x,int y)1066 static void draw_picture(struct f_data_c *fdatac, struct g_object_image *goi, int x, int y)
1067 {
1068 	struct graphics_device *dev = fdatac->ses->term->dev;
1069 	struct cached_image *cimg = goi->cimg;
1070 	struct rect saved;
1071 
1072 #ifdef DEBUG
1073 	if (goi->cimg->state < 12 || goi->cimg->state >= 16) {
1074 		fprintf(stderr, "cimg->state=%d\n", cimg->state);
1075 		internal_error("Invalid cimg->state in draw_picture");
1076 	}
1077 #endif /* #ifdef DEBUG */
1078 	if (!(cimg->state & 1)) {
1079 		if (!cimg->bmp_used)
1080 			buffer_to_bitmap(cimg);
1081 	}
1082 #ifdef DEBUG
1083 	else if (!cimg->bmp_used) {
1084 		fprintf(stderr, "cimg->state=%d\n", cimg->state);
1085 		internal_error("Nonexistent bitmap in said cimg->state in draw_picture");
1086 	}
1087 #endif /* #ifdef DEBUG */
1088 	restrict_clip_area(dev, &saved, x, y, x + goi->goti.go.xw, y + goi->goti.go.yw);
1089 	drv->draw_bitmap(dev, &cimg->bmp, x, y);
1090 	if (cimg->bmp.x < goi->goti.go.xw ||
1091 	    cimg->bmp.y < goi->goti.go.yw) {
1092 		long bg = image_backgronud(cimg);
1093 		drv->fill_area(dev, x + cimg->bmp.x, y, x + goi->goti.go.xw, y + cimg->bmp.y, bg);
1094 		drv->fill_area(dev, x, y + cimg->bmp.y, x + goi->goti.go.xw, y + goi->goti.go.yw, bg);
1095 	}
1096 	set_clip_area(dev, &saved);
1097 }
1098 
1099 /* Ensures in buffer there is not newer picture than in bitmap. Allowed to be
1100  * called only in state 12, 13, 14, 15.
1101  */
update_bitmap(struct cached_image * cimg)1102 static void update_bitmap(struct cached_image *cimg)
1103 {
1104 #ifdef DEBUG
1105 	if (cimg->state < 12 || cimg->state >= 16) {
1106 		fprintf(stderr, "cimg->state=%d\n", cimg->state);
1107 		internal_error("Invalid state in update_bitmap");
1108 	}
1109 #endif /* #ifdef DEBUG */
1110 	if (!(cimg->state & 1) && !cimg->strip_optimized && cimg->rows_added)
1111 		buffer_to_bitmap(cimg);
1112 }
1113 
1114 /* Draws the image at x,y. Is called from other C sources. */
img_draw_image(struct f_data_c * fdatac,struct g_object * goi_,int x,int y)1115 static void img_draw_image(struct f_data_c *fdatac, struct g_object *goi_, int x, int y)
1116 {
1117 	struct g_object_image *goi = get_struct(goi_, struct g_object_image, goti.go);
1118 	struct cached_image *cimg = goi->cimg;
1119 	struct rect r;
1120 	/* refresh_image(fdatac, goi, 1000); To sem asi napsal mikulas jako
1121 	 * navod, jak se vola to refresh_image.  Nicmene ja jsem milostive
1122 	 * usoudil, ze zadnejch 1000, ale 0.
1123 	 */
1124 
1125 	if (!(goi->goti.go.xw && goi->goti.go.yw))
1126 		return; /* At least one dimension is zero */
1127 
1128 	memcpy(&r, &fdatac->ses->term->dev->clip, sizeof(struct rect));
1129 	if (fdatac->vs->g_display_link && fdatac->active && fdatac->vs->current_link != -1 && fdatac->vs->current_link == goi->goti.link_num) {
1130 		long fg = image_foregronud(cimg);
1131 		draw_frame_mark(fdatac->ses->term->dev, x, y, goi->goti.go.xw,
1132 			goi->goti.go.yw, fg, fg, 2);
1133 		restrict_clip_area(fdatac->ses->term->dev, &r, x + 2, y + 2, x + goi->goti.go.xw - 2, y + goi->goti.go.yw - 2);
1134 	}
1135 
1136 	global_goi=goi;
1137 	global_cimg=goi->cimg;
1138 	if (img_process_download(goi, fdatac)) goto ret; /* Choked with data, will not
1139 							* draw. */
1140 	/* Now we will only draw... */
1141 	if (!cimg || cimg->state < 12) {
1142 		long fg = image_foregronud(cimg);
1143 		long bg = image_backgronud(cimg);
1144 		draw_frame_mark(fdatac->ses->term->dev, x, y, goi->goti.go.xw,
1145 			goi->goti.go.yw, bg, fg, !cimg || cimg->state & 1);
1146 	} else {
1147 #ifdef DEBUG
1148 		if (cimg->state >= 16)
1149 			internal_error("Invalid state in img_draw_image: %d", cimg->state);
1150 #endif
1151 		update_bitmap(cimg);
1152 		draw_picture(fdatac, goi, x, y);
1153 	}
1154 ret:
1155 	set_clip_area(fdatac->ses->term->dev, &r);
1156 #ifdef LINKS_TESTMODE_IMAGE_AUTO_EXIT
1157 	if (cimg->state & 1)
1158 		terminate_loop = 1;
1159 #endif
1160 }
1161 
1162 /* Prior to calling this function you have to fill out
1163  * image -> xw (<0 means not known)
1164  * image -> yw (<0 means not known)
1165  * image -> xyw meaning (MEANING_AUTOSCALE or MEANING_DIMS)
1166  * image -> background
1167  *
1168  * The URL will not be freed.
1169  */
find_or_make_cached_image(struct g_object_image * image,unsigned char * url,int scale)1170 static void find_or_make_cached_image(struct g_object_image *image, unsigned char *url,
1171 	int scale)
1172 {
1173 	struct cached_image *cimg;
1174 
1175 	if (!(cimg = find_cached_image(image->background, url, image->goti.go.xw,
1176 		image->goti.go.yw, image->xyw_meaning, scale, aspect))){
1177 		/* We have to make a new image cache entry */
1178 		cimg = mem_alloc(sizeof(*cimg));
1179 		cimg->background_color = image->background;
1180 #ifdef DEBUG
1181 		if (!url)
1182 			internal_error("NULL url as argument of\
1183 find_or_make_cached_image");
1184 #endif /* #ifdef DEBUG */
1185 		cimg->scale = scale;
1186 		cimg->aspect = aspect;
1187 		cimg->url = stracpy(url);
1188 		cimg->wanted_xw = image->goti.go.xw;
1189 		cimg->wanted_yw = image->goti.go.yw;
1190 		cimg->wanted_xyw_meaning = image->xyw_meaning;
1191 		cimg->xww = image->goti.go.xw < 0 ? img_scale_h(cimg->scale, 32) : cimg->wanted_xw;
1192 		cimg->yww = image->goti.go.yw < 0 ? img_scale_v(cimg->scale, 32) : cimg->wanted_yw;
1193 		cimg->state=0;
1194 		/* width, height, image_type, buffer, buffer_bytes_per_pixel, red_gamma,
1195 		 * green_gamma, blue_gamma, gamma_stamp, bitmap, last_length, rows_added,
1196 		 * and decoder is invalid in both state 0 and state 2. Thus is need no to
1197 		 * be filled in.
1198 		 */
1199 
1200 		/* last_count2 is unitialized */
1201 		cimg->eof_hit = 0;
1202 		cimg->last_count = -1;
1203 		cimg->last_count2 = -1;
1204 		if (cimg->wanted_xw >= 0 && cimg->wanted_yw >=0) cimg->state |= 2;
1205 		add_image_to_cache(cimg);
1206 	}
1207 	global_cimg = image->cimg = cimg;
1208 }
1209 
1210 /* The original (unscaled, in pixels pace) size is requested in im->xsize and im->ysize.
1211  * <0 means unknown. Autoscale is requested in autoscale. When autoscale is on,
1212  * the requested dimensions are not scaled and they mean maximum allowed
1213  * dimensions. */
insert_image(struct g_part * p,struct image_description * im)1214 struct g_object_image *insert_image(struct g_part *p, struct image_description *im)
1215 {
1216 	struct g_object_image *image;
1217 	struct cached_image *cimg;
1218 	int retval;
1219 	ssize_t xw, yw;
1220 
1221 	image=mem_calloc(sizeof(struct g_object_image));
1222 	global_goi = image;
1223 	image->goti.go.mouse_event = g_text_mouse;
1224 	image->goti.go.draw = img_draw_image;
1225 	image->goti.go.destruct = img_destruct_image;
1226 	image->goti.go.get_list = NULL;
1227 	image->goti.link_num = im->link_num;
1228 	image->goti.link_order = im->link_order;
1229 	image->goti.map = NULL;
1230 	/*
1231 	image->goti.go.x is already filled
1232 	image->goti.go.y is already filled
1233 	*/
1234 	if (im->align == AL_MIDDLE) image->goti.go.y = G_OBJ_ALIGN_MIDDLE;
1235 	if (im->align == AL_TOP) image->goti.go.y = G_OBJ_ALIGN_TOP;
1236 
1237 	if (im->autoscale_x && im->autoscale_y) {
1238 		/* Autoscale requested */
1239 		xw = im->autoscale_x;
1240 		yw = im->autoscale_y;
1241 		image->goti.go.xw = (int)xw;
1242 		image->goti.go.yw = (int)yw;
1243 		image->xyw_meaning = MEANING_AUTOSCALE;
1244 	}else{
1245 		/* Autoscale not requested */
1246 		xw = img_scale_h(d_opt->image_scale, im->xsize);
1247 		yw = img_scale_v(d_opt->image_scale, im->ysize);
1248 		image->goti.go.xw = (int)xw;
1249 		image->goti.go.yw = (int)yw;
1250 		image->xyw_meaning = MEANING_DIMS;
1251 	}
1252 	if (xw >= 0 && yw >= 0) {
1253 		if (!is_image_size_sane(xw, yw)) {
1254 			mem_free(image);
1255 			return NULL;
1256 		}
1257 	}
1258 
1259 	/* Put the data for javascript inside */
1260 	image->id = current_f_data->n_images++;
1261 	image->name = stracpy(im->name);
1262 	image->alt = stracpy(im->alt);
1263 	image->orig_src = stracpy(im->src);
1264 	image->border = im->border;
1265 	image->vspace = im->vspace;
1266 	image->hspace = im->hspace;
1267 	image->src = stracpy(im->url);
1268 
1269 	if (!(image->goti.go.xw && image->goti.go.yw)) {
1270 		/* At least one is zero */
1271 		if (image->goti.go.xw < 0) image->goti.go.xw = 0;
1272 		if (image->goti.go.yw < 0) image->goti.go.yw = 0;
1273 		if (im->insert_flag) add_to_list(current_f_data->images, image);
1274 		else image->list_entry.prev = image->list_entry.next = NULL;
1275 		return image;
1276 	}
1277 	/*
1278 	image->parent is already filled
1279 	*/
1280 	image->af = request_additional_file(current_f_data, im->url);
1281 	if (image->goti.go.xw < 0 || image->goti.go.yw < 0) image->af->unknown_image_size = 1;
1282 	image->background = hack_rgb(p->root->bg->sRGB);
1283 
1284 	/* This supplies the result into image->cimg and global_cimg */
1285 	find_or_make_cached_image(image, im->url, d_opt->image_scale);
1286 	cimg = global_cimg;
1287 
1288 next_chunk:
1289 	retval = img_process_download(image, NULL);
1290 	if (retval && !(cimg->state & 4)) goto next_chunk;
1291 	image->goti.go.xw = (int)image->cimg->xww;
1292 	image->goti.go.yw = (int)image->cimg->yww;
1293 	if (cimg->state == 0 || cimg->state == 8 || image->af->unknown_image_size) if (image->af->need_reparse != -1) image->af->need_reparse = 1;
1294 	if (im->insert_flag) add_to_list(current_f_data->images, image);
1295 	else image->list_entry.prev = image->list_entry.next = NULL;
1296 	return image;
1297 }
1298 
1299 #ifdef JS
1300 
change_image(struct g_object_image * goi,unsigned char * url,unsigned char * src,struct f_data * fdata)1301 void change_image (struct g_object_image *goi, unsigned char *url, unsigned char *src, struct f_data *fdata)
1302 {
1303 	/*struct cached_image *cimg;*/
1304 
1305 	global_goi = goi;
1306 	mem_free(goi->src);
1307 	goi->src = stracpy(url);
1308 	if (goi->orig_src) mem_free(goi->orig_src);
1309 	goi->orig_src = stracpy(src);
1310 	if (!(goi->goti.go.xw && goi->goti.go.yw)) return;
1311 	deref_cached_image(goi->cimg);
1312 	goi->af = request_additional_file(fdata, url);
1313 	goi->af->need_reparse = -1;
1314 
1315 	find_or_make_cached_image(goi, url, fdata->opt.image_scale);
1316 	/* Automatically sets up global_cimg */
1317 
1318 	refresh_image(fdata->fd, &goi->goti.go, 0);
1319 }
1320 
1321 #endif
1322 
1323 #endif
1324 
known_image_type(unsigned char * type)1325 int known_image_type(unsigned char *type)
1326 {
1327 #ifdef G
1328 	if (!casestrcmp(type, cast_uchar "image/png")) return 1;
1329 	if (!casestrcmp(type, cast_uchar "image/x-png")) return 1;
1330 	if (!casestrcmp(type, cast_uchar "image/gif")) return 1;
1331 	if (!casestrcmp(type, cast_uchar "image/x-xbitmap")) return 1;
1332 #ifdef HAVE_JPEG
1333 	if (!casestrcmp(type, cast_uchar "image/jpeg")) return 1;
1334 	if (!casestrcmp(type, cast_uchar "image/jpg")) return 1;
1335 	if (!casestrcmp(type, cast_uchar "image/jpe")) return 1;
1336 	if (!casestrcmp(type, cast_uchar "image/pjpe")) return 1;
1337 	if (!casestrcmp(type, cast_uchar "image/pjpeg")) return 1;
1338 	if (!casestrcmp(type, cast_uchar "image/pjpg")) return 1;
1339 #endif
1340 #ifdef HAVE_TIFF
1341 	if (!casestrcmp(type, cast_uchar "image/tiff")) return 1;
1342 	if (!casestrcmp(type, cast_uchar "image/tif")) return 1;
1343 #endif
1344 #ifdef HAVE_SVG
1345 	if (!casestrcmp(type, cast_uchar "image/svg+xml")) return 1;
1346 	if (!casestrcmp(type, cast_uchar "image/svg")) return 1;
1347 #endif
1348 #endif
1349 	return 0;
1350 }
1351