1 #include "win32\win32guts.h"
2 #ifndef _APRICOT_H_
3 #include "apricot.h"
4 #endif
5 #include "img_conv.h"
6 #include "guts.h"
7 #include "Window.h"
8 #include "Icon.h"
9 #include "DeviceBitmap.h"
10 
11 #ifdef __cplusplus
12 extern "C" {
13 #endif
14 
15 
16 #define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
17 #define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
18 #define var (( PWidget) self)->
19 #define HANDLE sys handle
20 #define DHANDLE(x) dsys(x) handle
21 
22 static int
image_guess_bitmap_type(Handle self)23 image_guess_bitmap_type( Handle self )
24 {
25 	if ( is_apt( aptIcon ) && PIcon(self)-> maskType == imbpp8 )
26 		return BM_LAYERED;
27 	else if ( PImage( self)-> type == imBW)
28 		return BM_BITMAP;
29 	else
30 		return BM_PIXMAP;
31 }
32 
33 
34 BITMAPINFO *
image_fill_bitmap_info(Handle self,XBITMAPINFO * bi,int bm_type)35 image_fill_bitmap_info( Handle self, XBITMAPINFO * bi, int bm_type)
36 {
37 	int    i;
38 	PImage image = ( PImage) self;
39 	int    colors, depth;
40 
41 	if ( bm_type == BM_AUTO )
42 		bm_type = image_guess_bitmap_type( self );
43 
44 	switch (bm_type) {
45 	case BM_BITMAP:
46 		depth   = 1;
47 		colors  = 2;
48 		break;
49 	case BM_PIXMAP:
50 		depth   = image-> type & imBPP;
51 		colors  = (1 << depth) & 0x1ff;
52 		break;
53 	case BM_LAYERED:
54 		colors  = 0;
55 		depth   = 32;
56 		break;
57 	default:
58 		warn("panic: bad use of image_fill_bitmap_info(%d)", bm_type);
59 		return NULL;
60 	}
61 
62 	if ( image-> type & ( imSignedInt | imRealNumber | imComplexNumber | imTrigComplexNumber)) {
63 		warn("panic: image_fill_bitmap_info called on incompatible image");
64 		return NULL;
65 	}
66 
67 	if ( colors > image-> palSize) colors = image-> palSize;
68 	memset( bi, 0, sizeof( BITMAPINFOHEADER) + colors * sizeof( RGBQUAD));
69 	bi-> bmiHeader. biSize          = sizeof( BITMAPINFOHEADER);
70 	bi-> bmiHeader. biWidth         = image-> w;
71 	bi-> bmiHeader. biHeight        = image-> h;
72 	bi-> bmiHeader. biPlanes        = 1;
73 	bi-> bmiHeader. biBitCount      = depth;
74 	bi-> bmiHeader. biCompression   = BI_RGB;
75 	bi-> bmiHeader. biClrUsed       = colors;
76 	bi-> bmiHeader. biClrImportant  = colors;
77 
78 	for ( i = 0; i < colors; i++) {
79 		bi-> bmiColors[ i]. rgbRed    = image-> palette[ i]. r;
80 		bi-> bmiColors[ i]. rgbGreen  = image-> palette[ i]. g;
81 		bi-> bmiColors[ i]. rgbBlue   = image-> palette[ i]. b;
82 	}
83 
84 	return ( BITMAPINFO *) bi;
85 }
86 
87 HPALETTE
image_create_palette(Handle self)88 image_create_palette( Handle self)
89 {
90 	PDrawable i    = ( PDrawable) self;
91 	int j, nColors = i-> palSize;
92 	XLOGPALETTE lp;
93 	HPALETTE r;
94 	RGBColor  dest[ 256];
95 	PRGBColor logp = i-> palette;
96 
97 	lp. palVersion = 0x300;
98 	lp. palNumEntries = nColors;
99 
100 	if ( nColors == 0) return NULL;
101 	if ( is_apt(aptImage) && PImage(self)->type == imRGB) return NULL;
102 
103 	if ( !sys p256) {
104 		if ( nColors > 256) {
105 			sys p256 = ( PXLOGPALETTE) malloc( sizeof( XLOGPALETTE));
106 			cm_squeeze_palette( i-> palette, nColors, dest, 256);
107 			nColors = lp. palNumEntries = 256;
108 			logp = dest;
109 		}
110 
111 		for ( j = 0; j < nColors; j++) {
112 			lp. palPalEntry[ j]. peRed    = logp[ j]. r;
113 			lp. palPalEntry[ j]. peGreen  = logp[ j]. g;
114 			lp. palPalEntry[ j]. peBlue   = logp[ j]. b;
115 			lp. palPalEntry[ j]. peFlags  = 0;
116 		}
117 
118 		if ( sys p256)
119 			memcpy( sys p256, &lp, sizeof( XLOGPALETTE));
120 		if ( !( r = CreatePalette(( LOGPALETTE*) &lp))) apiErrRet;
121 	} else {
122 		if ( !( r = CreatePalette(( LOGPALETTE*) sys p256))) apiErrRet;
123 	}
124 	return r;
125 }
126 
127 static Bool
icon2argb(PIcon i,uint32_t * argb_bits)128 icon2argb( PIcon i, uint32_t * argb_bits)
129 {
130 	Byte * rgb_bits, *a_bits, *mask;
131 	int y, maskLineSize, free_mask;
132 
133 	if ( i-> maskType != imbpp8 ) {
134 		free_mask    = true;
135 		maskLineSize = LINE_SIZE(i->w, imbpp8);
136 		mask         = i->self->convert_mask(( Handle ) i, imbpp8 );
137 		if ( !mask )
138 			return false;
139 	} else {
140 		free_mask    = false;
141 		mask         = i-> mask;
142 		maskLineSize = i-> maskLine;
143 	}
144 
145 	for (
146 		y = 0,
147 			rgb_bits  = i->data,
148 			a_bits    = mask;
149 		y < i->h;
150 		y++,
151 			rgb_bits  += i-> lineSize,
152 			a_bits    += maskLineSize,
153 			argb_bits += i-> w
154 	) {
155 		register Byte *rgb_ptr = rgb_bits, *a_ptr = a_bits, *argb_ptr = (Byte*) argb_bits;
156 		register int x = i->w;
157 		for ( ; x > 0; x--) {
158 			*argb_ptr++ = *rgb_ptr++;
159 			*argb_ptr++ = *rgb_ptr++;
160 			*argb_ptr++ = *rgb_ptr++;
161 			*argb_ptr++ = *a_ptr++;
162 		}
163 	}
164 
165 	if ( free_mask ) free(mask);
166 	return true;
167 }
168 
169 static HBITMAP
image_create_argb_bitmap(Handle self,uint32_t ** argb_bits_ptr)170 image_create_argb_bitmap( Handle self, uint32_t ** argb_bits_ptr )
171 {
172 	HBITMAP bm;
173 	XBITMAPINFO xbi;
174 	BITMAPINFO * bi;
175 	HDC dc, compat_dc;
176 	PIcon i = (PIcon) self;
177 	uint32_t * argb_bits;
178 
179 	if ( !is_apt(aptIcon)) {
180 		warn("panic: image_create_argb_bitmap called on a non-icon");
181 		return NULL;
182 	}
183 
184 	if (i-> type != imRGB ) {
185 		HBITMAP ret;
186 		Handle dup = CImage(self)->dup(self);
187 		CImage(dup)->set_type(dup, imRGB);
188 		ret = image_create_argb_bitmap( dup, argb_bits_ptr );
189 		Object_destroy(dup);
190 		return ret;
191 	}
192 
193 	if ( argb_bits_ptr == NULL )
194 		argb_bits_ptr = &argb_bits;
195 
196 	bm = NULL;
197 
198 	bi  = image_fill_bitmap_info( self, &xbi, BM_LAYERED);
199 	if ( !bi)
200 		return NULL;
201 
202 	dc = GetDC(NULL);
203 	compat_dc = CreateCompatibleDC(dc);
204 
205 	bi-> bmiHeader. biBitCount = 32;
206 	bi-> bmiHeader. biSizeImage = bi->bmiHeader.biWidth * bi->bmiHeader. biHeight * 4;
207 	bm = CreateDIBSection(compat_dc, bi, DIB_RGB_COLORS,
208 			(LPVOID*) argb_bits_ptr, NULL, 0x0);
209 	if (!bm) {
210 		apiErr;
211 		goto EXIT;
212 	}
213 
214 	if ( !icon2argb(i, *argb_bits_ptr)) {
215 		DeleteObject(bm);
216 		bm = NULL;
217 	}
218 
219 EXIT:
220 	DeleteDC( compat_dc);
221 	ReleaseDC( NULL, dc);
222 	return bm;
223 }
224 
225 
226 HBITMAP
image_create_bitmap_by_type(Handle self,HPALETTE pal,XBITMAPINFO * bitmapinfo,int bm_type)227 image_create_bitmap_by_type( Handle self, HPALETTE pal, XBITMAPINFO * bitmapinfo, int bm_type)
228 {
229 	HBITMAP bm;
230 	XBITMAPINFO xbi;
231 	BITMAPINFO * bi;
232 	HPALETTE old = NULL, xpal = pal;
233 	HDC dc;
234 	PIcon i = (PIcon) self;
235 
236 	if ( bm_type == BM_AUTO )
237 		bm_type = image_guess_bitmap_type( self );
238 
239 	if ( bitmapinfo == NULL)
240 		bitmapinfo = &xbi;
241 	bi  = image_fill_bitmap_info( self, bitmapinfo, bm_type);
242 	if ( !bi)
243 		return NULL;
244 
245 	dc = GetDC(NULL);
246 
247 	if ( bi-> bmiHeader. biClrUsed > 0)
248 		bi-> bmiHeader. biClrUsed = bi-> bmiHeader. biClrImportant = i-> palSize;
249 
250 	if ( xpal == NULL)
251 		xpal = image_create_palette( self);
252 
253 	if ( xpal) {
254 		old = SelectPalette( dc, xpal, 1);
255 		RealizePalette( dc);
256 	}
257 
258 	switch (bm_type) {
259 	case BM_BITMAP:
260 		if ( i-> type != imBW )
261 			warn("panic: image_create_bitmap(BM_BITMAP) called on not a imBW image");
262 		bm = CreateBitmap( bi-> bmiHeader. biWidth, bi-> bmiHeader. biHeight, 1, 1, NULL);
263 		if (bm)
264 			SetDIBits( dc, bm, 0, bi-> bmiHeader. biHeight, i-> data, bi, DIB_RGB_COLORS);
265 		break;
266 	case BM_PIXMAP:
267 		bm = CreateCompatibleBitmap( dc, i->w, i->h);
268 		if (bm)
269 			SetDIBits( dc, bm, 0, bi-> bmiHeader. biHeight, i-> data, bi, DIB_RGB_COLORS);
270 		break;
271 	case BM_LAYERED:
272 		bm = image_create_argb_bitmap(( Handle) i, NULL );
273 		break;
274 	default:
275 		warn("panic: bad use of image_create_bitmap(%d)", bm_type);
276 		return NULL;
277 	}
278 
279 	if ( !bm)
280 		apiErr;
281 
282 	if ( old) {
283 		SelectPalette( dc, old, 1);
284 		RealizePalette( dc);
285 	}
286 
287 	if ( xpal != pal)
288 		DeleteObject( xpal);
289 
290 	ReleaseDC( NULL, dc);
291 
292 	return bm;
293 }
294 
295 HBITMAP
image_create_bitmap(Handle self)296 image_create_bitmap( Handle self)
297 {
298 	return image_create_bitmap_by_type(self, NULL, NULL, BM_AUTO);
299 }
300 
301 static XBITMAPINFO a1_info_header = {
302 	{ sizeof( BITMAPINFOHEADER), 0, 0, 1, 1, BI_RGB, 0, 0, 0, 2, 2},
303 	{ {0,0,0,0}, {255,255,255,0}}
304 };
305 
306 static XBITMAPINFO a8_info_header = {
307 	{ sizeof( BITMAPINFOHEADER), 0, 0, 1, 8, BI_RGB, 0, 0, 0, 256, 256},
308 	{ {255,255,255,0}, {0,0,0,0}}
309 };
310 
311 static int a_info_headers_initialized = false;
312 
313 static XBITMAPINFO *
image_alpha_bitmap_header(int type)314 image_alpha_bitmap_header( int type )
315 {
316 	if ( !a_info_headers_initialized ) {
317 		a_info_headers_initialized = true;
318 		memset( a8_info_header. bmiColors + 1, 0, 255 * sizeof(RGBQUAD));
319 	}
320 	return (( type == imbpp1 ) ? &a1_info_header : &a8_info_header);
321 }
322 
323 /* convert from funky types */
324 static Handle
image_convert_for_gdi(Handle image)325 image_convert_for_gdi( Handle image )
326 {
327 	Handle dup;
328 	PImage img = (PImage) image;
329 
330 	if ( !( img-> type & ( imSignedInt | imRealNumber | imComplexNumber | imTrigComplexNumber)))
331 		return NULL_HANDLE;
332 
333 	dup = CImage(image)->dup(image);
334 	img = (PImage) dup;
335 	img->self->resample(
336 		dup,
337 		img-> self->stats( dup, false, isRangeLo, 0),
338 		img-> self->stats( dup, false, isRangeHi, 0),
339 		0, 255
340 	);
341 	img->self->set_type( dup, imByte );
342 	return dup;
343 }
344 
345 /* create a copy with given type, unless it is of this type alredy */
346 static Handle
image_convert_to_type(Handle image,int type,Bool inplace)347 image_convert_to_type( Handle image, int type, Bool inplace )
348 {
349 	Handle dup;
350 
351 	if (((PImage)image)->type == type)
352 		return NULL_HANDLE;
353 
354 	dup = inplace ? image : CImage(image)->dup(image);
355 	CImage(dup)->set_type(dup, type);
356 
357 	return dup;
358 }
359 
360 #define image_convert_for_bitmap(image,inplace) image_convert_to_type(image,imBW,inplace)
361 #define image_convert_for_rgb(image,inplace)    image_convert_to_type(image,imRGB,inplace)
362 
363 static Handle
image_convert_rgb_for_screen(Handle image,Bool inplace)364 image_convert_rgb_for_screen( Handle image, Bool inplace )
365 {
366 	int bpp;
367 	PImage img = (PImage) image;
368 
369 	if ( img-> type != imRGB)
370 		return NULL_HANDLE;
371 
372 	/* use Prima downsampling methods from RGB to 8,4,1 */
373 	bpp = guts. displayBMInfo. bmiHeader. biBitCount *
374 			guts. displayBMInfo. bmiHeader. biPlanes;
375 	if ( bpp == 0 || bpp > 8)
376 		return NULL_HANDLE;
377 	if ( bpp < 4) bpp = 1;
378 	else if ( bpp < 8) bpp = 4;
379 	return image_convert_to_type( image, bpp, inplace );
380 }
381 
382 static Handle
image_convert_rgb_for_paletted(Handle image,Handle screen,Bool inplace)383 image_convert_rgb_for_paletted( Handle image, Handle screen, Bool inplace )
384 {
385 	int bpp;
386 	PImage img = (PImage) image;
387 
388 	if ( img-> type != imRGB)
389 		return NULL_HANDLE;
390 
391 	if ( dsys( screen) bpp == 0) {
392 		if ( !dsys(screen) ps)
393 			return image_convert_for_bitmap( image, inplace );
394 		dsys( screen) bpp = GetDeviceCaps( dsys(screen) ps, BITSPIXEL);
395 	}
396 
397 	if ( dsys( screen) bpp > 8)
398 		return NULL_HANDLE;
399 
400 	bpp = dsys( screen) bpp;
401 	if ( bpp < 4) bpp = 1;
402 	else if ( bpp < 8) bpp = 4;
403 	return image_convert_to_type( image, bpp, inplace );
404 }
405 
406 static void
image_fill_bitmap_cache(Handle self,int bm_type,Handle optimize_for_surface)407 image_fill_bitmap_cache( Handle self, int bm_type, Handle optimize_for_surface)
408 {
409 	Handle copy;
410 
411 	if ( bm_type == BM_AUTO )
412 		bm_type = image_guess_bitmap_type( self );
413 
414 	if ( bm_type == sys s. image. cache. cacheType )
415 		return;
416 
417 	/* free old stuff */
418 	image_destroy_cache( self );
419 	sys s. image. cache. cacheType = BM_NONE;
420 
421 	/* create new image, if any */
422 	copy = image_convert_for_gdi( self );
423 	if ( copy == NULL_HANDLE )
424 		copy = self;
425 
426 	switch (bm_type) {
427 	case BM_BITMAP:
428 		copy = image_convert_for_bitmap( copy, copy != self);
429 		break;
430 	case BM_PIXMAP:
431 		if (((PImage)copy)-> type == imRGB) {
432 			if (!optimize_for_surface)
433 				copy = image_convert_rgb_for_screen( copy, copy != self );
434 			else if ( dsys(optimize_for_surface) options. aptPrinter ) {
435 				/* do nothing, let printer driver do the downsampling */
436 			} else if ( ! dsys(optimize_for_surface)options.aptCompatiblePS && dsys(optimize_for_surface)ps)
437 				copy = image_convert_rgb_for_paletted( copy, optimize_for_surface, copy != self );
438 			else
439 				copy = image_convert_rgb_for_screen( copy, copy != self );
440 		}
441 		break;
442 	case BM_LAYERED:
443 		copy = image_convert_for_rgb( copy, copy != self);
444 		break;
445 	default:
446 		warn("panic: bad use of image_fill_bitmap_cache(%d)", bm_type);
447 		if ( copy != self )
448 		Object_destroy(copy);
449 		return;
450 	}
451 	if ( copy == NULL_HANDLE )
452 		copy = self;
453 
454 	/* try to create HBITMAP */
455 	switch (bm_type) {
456 	case BM_LAYERED:
457 		sys bm = image_create_argb_bitmap( copy, &sys s. image. argbBits );
458 		if ( !sys bm) {
459 			warn("panic: couldn't create argb bitmap");
460 			if ( copy != self )
461 				Object_destroy(copy);
462 			return;
463 		}
464 		break;
465 	default:
466 		sys pal = image_create_palette( copy);
467 		sys bm  = image_create_bitmap_by_type( copy, sys pal, &sys s. image. cache. rawHeader, bm_type );
468 		if ( sys bm ) {
469 			hash_store( imageMan, &self, sizeof(self), (void*)self);
470 		} else {
471 			PImage i = (PImage) copy;
472 			sys s. image. cache. rawBits = i->data;
473 			if ( copy != self ) {
474 				i-> data = malloc(1); /* dirty, dirty hack */
475 				sys s. image. cache. freeBits = true;
476 			}
477 		}
478 	}
479 	if ( copy != self )
480 		Object_destroy(copy);
481 
482 	sys s. image. cache. cacheType = bm_type;
483 }
484 
485 void
image_argb_query_bits(Handle self)486 image_argb_query_bits( Handle self)
487 {
488 	PIcon i = (PIcon) self;
489 	uint32_t * argb_bits;
490 	Byte * rgb_bits, *a_bits;
491 	int y;
492 
493 	if ( i-> type != imRGB || i-> maskType != imbpp8)
494 		i-> self-> create_empty_icon( self, i-> w, i-> h, imRGB, imbpp8);
495 
496 	for (
497 		y = 0,
498 			rgb_bits = i->data,
499 			a_bits   = i->mask,
500 			argb_bits = sys s. image. argbBits;
501 		y < i->h;
502 		y++,
503 			rgb_bits  += i-> lineSize,
504 			a_bits    += i-> maskLine,
505 			argb_bits += i-> w
506 	) {
507 		register Byte *rgb_ptr = rgb_bits, *a_ptr = a_bits, *argb_ptr = (Byte*) argb_bits;
508 		register int x = i->w;
509 		for ( ; x > 0; x--) {
510 			*rgb_ptr++ = *argb_ptr++;
511 			*rgb_ptr++ = *argb_ptr++;
512 			*rgb_ptr++ = *argb_ptr++;
513 			*a_ptr++   = *argb_ptr++;
514 		}
515 	}
516 }
517 
518 void
image_destroy_cache(Handle self)519 image_destroy_cache( Handle self)
520 {
521 	if ( sys bm) {
522 		if ( !DeleteObject( sys bm)) apiErr;
523 		hash_delete( imageMan, &self, sizeof( self), false);
524 		sys bm = NULL;
525 		sys s. image. cache. bitmap = NULL;
526 	}
527 	if ( sys pal) {
528 		if ( !DeleteObject( sys pal)) apiErr;
529 		sys pal = NULL;
530 	}
531 	if ( sys s. image. imgCachedRegion) {
532 		if ( !DeleteObject( sys s. image. imgCachedRegion)) apiErr;
533 		sys s. image. imgCachedRegion = NULL;
534 	}
535 	if ( sys s. image. cache. freeBits)
536 		free( sys s. image. cache. rawBits);
537 	sys s. image. cache. rawBits = NULL;
538 	sys s. image. cache. freeBits = false;
539 	sys s. image. argbBits = NULL;
540 	sys s. image. cache. cacheType = BM_NONE;
541 }
542 
543 void
image_query_bits(Handle self,Bool forceNewImage)544 image_query_bits( Handle self, Bool forceNewImage)
545 {
546 	PImage i = ( PImage) self;
547 	XBITMAPINFO xbi;
548 	BITMAPINFO * bi;
549 	int  newBits;
550 	HDC  ops = NULL;
551 	BITMAP bitmap;
552 
553 	if ( forceNewImage) {
554 		ops = sys ps;
555 		if ( !ops) {
556 			if ( !( sys ps = dc_alloc())) return;
557 		}
558 	}
559 
560 	if ( !GetObject( sys bm, sizeof( BITMAP), ( LPSTR) &bitmap)) {
561 		apiErr;
562 		return;
563 		// if GetObject fails to get even BITMAP, there will be no good in farther run for sure.
564 	}
565 
566 	if (( bitmap. bmPlanes == 1) && (
567 			( bitmap. bmBitsPixel == 1) ||
568 			( bitmap. bmBitsPixel == 4) ||
569 			( bitmap. bmBitsPixel == 8) ||
570 			( bitmap. bmBitsPixel == 24)
571 		))
572 		newBits = bitmap. bmBitsPixel;
573 	else {
574 		newBits = ( bitmap. bmBitsPixel <= 4) ? 4 :
575 					(( bitmap. bmBitsPixel <= 8) ? 8 : 24);
576 	}
577 
578 
579 	if ( forceNewImage) {
580 		i-> self-> create_empty( self, bitmap. bmWidth, bitmap. bmHeight, newBits);
581 	} else {
582 		if (( newBits != ( i-> type & imBPP)) || (( i-> type & ~imBPP) != 0))
583 			i-> self-> create_empty( self, i-> w, i-> h, newBits);
584 	}
585 
586 	bi = image_fill_bitmap_info( self, &xbi, BM_PIXMAP);
587 
588 	if ( !GetDIBits( sys ps, sys bm, 0, i-> h, i-> data, bi, DIB_RGB_COLORS)) apiErr;
589 	if (( i-> type & imBPP) < 24) {
590 		int j, nColors = 1 << ( i-> type & imBPP);
591 		for ( j = 0; j < nColors; j++) {
592 			i-> palette[ j]. r = xbi. bmiColors[ j]. rgbRed;
593 			i-> palette[ j]. g = xbi. bmiColors[ j]. rgbGreen;
594 			i-> palette[ j]. b = xbi. bmiColors[ j]. rgbBlue;
595 		}
596 	}
597 
598 	if ( forceNewImage) {
599 		if ( !ops) {
600 			dc_free();
601 		}
602 		sys ps = ops;
603 	}
604 }
605 
606 static Handle ctx_rop2R4[] = {
607 ropCopyPut      ,  SRCCOPY          ,
608 ropXorPut       ,  SRCINVERT        ,
609 ropAndPut       ,  SRCAND           ,
610 ropOrPut        ,  SRCPAINT         ,
611 ropNotPut       ,  NOTSRCCOPY       ,
612 ropNotDestAnd   ,  SRCERASE         ,
613 ropNotDestOr    ,  0x00DD0228       ,
614 ropNotSrcAnd    ,  0x00220326       ,
615 ropNotSrcOr     ,  MERGEPAINT       ,
616 ropNotXor       ,  0x00990066       ,
617 ropNotAnd       ,  0x007700E6       ,
618 ropNotOr        ,  NOTSRCERASE      ,
619 ropNoOper       ,  0x00AA0029       ,
620 ropBlackness    ,  BLACKNESS        ,
621 ropWhiteness    ,  WHITENESS        ,
622 ropInvert       ,  DSTINVERT        ,
623 endCtx
624 };
625 
626 static Handle
image_from_dc(Handle image)627 image_from_dc( Handle image )
628 {
629 	Handle img      = ( Handle) create_object("Prima::Image", "");
630 	HDC adc         = dsys( image) ps;
631 	HBITMAP abitmap = dsys( image) bm;
632 	dsys( img) ps   = dsys( image) ps;
633 	dsys( img) bm   = dsys( image) bm;
634 	image_query_bits( img, true);
635 	dsys( img) ps   = adc;
636 	dsys( img) bm   = abitmap;
637 	return img;
638 }
639 
640 static int
rop_reduce(COLORREF fore,COLORREF back,int rop)641 rop_reduce(COLORREF fore, COLORREF back, int rop)
642 {
643 /*
644 Special case with current foreground and background colors, see also
645 L<pod/Prima/Drawable.pod | Monochrome bitmaps>.
646 
647 Raster ops can be identified by a fingerprint.  For example, Or's is 14
648 and Noop's is 10:
649 
650 	0 | 0 =    0                      0 | 0 =    0
651 	0 | 1 =   1                       0 | 1 =   1
652 	1 | 0 =  1                        1 | 0 =  0
653 	1 | 1 = 1                         1 | 1 = 1
654 		---                               ---
655 		1110 = 14                         1010 = 10
656 
657 when this special case uses not actual 0s and 1s, but bit values of
658 foreground and background color instead, the resulting operation can
659 still be expressed in rops, but these needs to be adjusted. Let's
660 consider a case where both colors are 0, and rop = OrPut:
661 
662 	0 | 0 =    0
663 	0 | 1 =   1
664 	0 | 0 =  0
665 	0 | 1 = 1
666 		---
667 		1010 = 10
668 
669 this means that in these conditions, Or (as well as Xor and AndInverted) becomes Noop.
670 
671 */
672 
673 	fore &= 0xffffff;
674 	back &= 0xffffff;
675 	if ( fore == 0 && back == 0 ) {
676 		switch( rop) {
677 			case ropAndPut:
678 			case ropNotDestAnd:
679 			case ropBlackness:
680 			case ropCopyPut:          rop = ropBlackness;      break;
681 			case ropNotXor:
682 			case ropInvert:
683 			case ropNotOr:
684 			case ropNotDestOr:        rop = ropInvert;         break;
685 			case ropNotSrcAnd:
686 			case ropNoOper:
687 			case ropOrPut:
688 			case ropXorPut:           rop = ropNoOper;         break;
689 			case ropNotAnd:
690 			case ropNotPut:
691 			case ropNotSrcOr:
692 			case ropWhiteness:        rop = ropWhiteness;      break;
693 		}
694 	} else if ( fore != 0 && back == 0 ) {
695 		switch( rop) {
696 			case ropAndPut:           rop = ropNotSrcAnd;      break;
697 			case ropNotSrcAnd:        rop = ropAndPut;         break;
698 			case ropNotDestAnd:       rop = ropNotOr;          break;
699 			case ropBlackness:        rop = ropBlackness;      break;
700 			case ropCopyPut:          rop = ropNotPut;         break;
701 			case ropNotPut:           rop = ropCopyPut;        break;
702 			case ropNotXor:           rop = ropXorPut;         break;
703 			case ropInvert:           rop = ropInvert;         break;
704 			case ropNotAnd:           rop = ropNotDestOr;      break;
705 			case ropNoOper:           rop = ropNoOper;         break;
706 			case ropNotOr:            rop = ropNotDestAnd;     break;
707 			case ropOrPut:            rop = ropNotSrcOr;       break;
708 			case ropNotSrcOr:         rop = ropOrPut;          break;
709 			case ropNotDestOr:        rop = ropNotAnd;         break;
710 			case ropWhiteness:        rop = ropWhiteness;      break;
711 			case ropXorPut:           rop = ropNotXor;         break;
712 		}
713 	} else if ( fore != 0 && back != 0 ) {
714 		switch( rop) {
715 			case ropAndPut:
716 			case ropNotSrcOr:
717 			case ropNotXor:
718 			case ropNoOper:           rop = ropNoOper;         break;
719 			case ropNotSrcAnd:
720 			case ropBlackness:
721 			case ropNotPut:
722 			case ropNotOr:            rop = ropBlackness;      break;
723 			case ropInvert:
724 			case ropNotAnd:
725 			case ropNotDestAnd:
726 			case ropXorPut:           rop = ropInvert;         break;
727 			case ropOrPut:
728 			case ropNotDestOr:
729 			case ropWhiteness:
730 			case ropCopyPut:          rop = ropWhiteness;      break;
731 		}
732 	}
733 	return rop;
734 }
735 
736 typedef struct {
737 	HDC src;
738 	int src_x;
739 	int src_y;
740 	int src_w;
741 	int src_h;
742 	int dst_x;
743 	int dst_y;
744 	int dst_w;
745 	int dst_h;
746 	int rop;
747 } PutImageRequest;
748 
749 typedef Bool PutImageFunc( Handle self, Handle image, PutImageRequest * req);
750 
751 #define SRC_BITMAP          0
752 #define SRC_PIXMAP          1
753 #define SRC_LAYERED         2
754 #define SRC_IMAGE           3
755 #define SRC_A8              4
756 #define SRC_ARGB            5
757 #define SRC_MAX             5
758 #define SRC_NUM            SRC_MAX+1
759 
760 static Bool
img_put_stretch_blt(HDC dst,HDC src,PutImageRequest * req)761 img_put_stretch_blt( HDC dst, HDC src, PutImageRequest * req)
762 {
763 	Bool ok = true;
764 	int rop = ctx_remap_def( req->rop, ctx_rop2R4, true, SRCCOPY);
765 	if ( !StretchBlt(
766 		dst, req-> dst_x, req-> dst_y, req-> dst_w, req-> dst_h,
767 		src, req-> src_x, req-> src_y, req-> src_w, req-> src_h,
768 		rop)) {
769 		apiErr;
770 		ok = false;
771 	}
772 	return ok;
773 }
774 
775 static Bool
img_put_stretch_bits(HDC dst,Handle self,PutImageRequest * req)776 img_put_stretch_bits( HDC dst, Handle self, PutImageRequest * req)
777 {
778 	int rop;
779 
780 	if ( !sys s. image. cache. rawBits )
781 		return false;
782 
783 	rop = ctx_remap_def( req->rop, ctx_rop2R4, true, SRCCOPY);
784 	if ( StretchDIBits( dst,
785 			req-> dst_x, req-> dst_y, req-> dst_w, req-> dst_h,
786 			req-> src_x, req-> src_y, req-> src_w, req-> src_h,
787 			sys s. image. cache. rawBits, (BITMAPINFO*) & sys s. image. cache. rawHeader,
788 			DIB_RGB_COLORS, rop) == GDI_ERROR) {
789 		apiErr;
790 		return false;
791 	}
792 
793 	return true;
794 }
795 
796 static Bool
img_put_and_mask(HDC dst,Handle image,PutImageRequest * req)797 img_put_and_mask( HDC dst, Handle image, PutImageRequest * req)
798 {
799 	XBITMAPINFO * bi = image_alpha_bitmap_header(PIcon(image)->maskType);
800 
801 	bi-> bmiHeader. biWidth  = ((PImage)image)-> w;
802 	bi-> bmiHeader. biHeight = ((PImage)image)-> h;
803 
804 	if ( StretchDIBits( dst,
805 			req-> dst_x, req-> dst_y, req-> dst_w, req-> dst_h,
806 			req-> src_x, req-> src_y, req-> src_w, req-> src_h,
807 			PIcon(image)->mask, (BITMAPINFO*) bi, DIB_RGB_COLORS, SRCAND
808 		) == GDI_ERROR) {
809 		apiErr;
810 		return false;
811 	}
812 	return true;
813 }
814 
815 static Bool
img_put_image_on_bitmap_or_pixmap(Handle self,Handle image,PutImageRequest * req,int bm_type)816 img_put_image_on_bitmap_or_pixmap( Handle self, Handle image, PutImageRequest * req, int bm_type)
817 {
818 	Bool ok;
819 	HDC src;
820 	HPALETTE pal_src, pal_src_save, pal_dst_save;
821 	HBITMAP bm_src_save;
822 	COLORREF oFore = 0, oBack = 0;
823 	PImage i = (PImage) image;
824 
825 	image_fill_bitmap_cache( image, bm_type, self );
826 	if ( dsys( image) bm == NULL ) /* we're low on memory, reverting to StretchDIBits */
827 		return img_put_stretch_bits( sys ps, image, req);
828 
829 	/* create and prepare DC */
830 	src = CreateCompatibleDC( sys ps);
831 
832 	if (( pal_src = dsys( image) pal) != NULL)
833 		pal_src_save = SelectPalette( src, pal_src, 0);
834 	else
835 		pal_src_save = NULL;
836 
837 	bm_src_save = SelectObject( src, dsys( image) bm);
838 	if ( pal_src) {
839 		pal_dst_save = SelectPalette( sys ps, pal_src, 1);
840 		RealizePalette( sys ps);
841 	} else
842 		pal_dst_save = NULL;
843 
844 	if ((bm_type == BM_PIXMAP) && (( i->type & imBPP) == 1)) {
845 		oFore  = GetTextColor( sys ps);
846 		oBack  = GetBkColor( sys ps);
847 		SetTextColor( sys ps, 0x00000000);
848 		SetBkColor  ( sys ps, 0x00FFFFFF);
849 	}
850 
851 	/* draw */
852 	ok = img_put_stretch_blt( sys ps, src, req );
853 
854 	/* clean up */
855 	if ((bm_type == BM_PIXMAP) && (( i->type & imBPP) == 1)) {
856 		SetTextColor( sys ps, oFore);
857 		SetBkColor( sys ps, oBack);
858 	}
859 
860 	if ( pal_src) {
861 		if ( pal_src_save) SelectPalette( src, pal_src_save, 1);
862 	}
863 	if ( pal_dst_save) {
864 		if ( is_apt(aptCompatiblePS))
865 			SelectPalette( sys ps, pal_dst_save, 1);
866 		else {
867 			DeleteObject( pal_dst_save );
868 			dsys( image) pal = image_create_palette( image);
869 		}
870 	}
871 	if ( bm_src_save) SelectObject( src, bm_src_save);
872 	DeleteDC( src);
873 
874 	return ok;
875 }
876 
877 static Bool
img_put_alpha_blend(HDC dst,HDC src,PutImageRequest * req)878 img_put_alpha_blend( HDC dst, HDC src, PutImageRequest * req)
879 {
880 	Bool ok;
881 	BLENDFUNCTION bf;
882 	bf.BlendOp             = AC_SRC_OVER;
883 	bf.BlendFlags          = 0;
884 	bf.SourceConstantAlpha = 0xff;
885 	bf.AlphaFormat         = AC_SRC_ALPHA;
886 	ok = AlphaBlend(
887 		dst, req-> dst_x, req-> dst_y, req-> dst_w, req-> dst_h,
888 		src, req-> src_x, req-> src_y, req-> src_w, req-> src_h,
889 		bf);
890 
891 	if (!ok) apiErr;
892 	return ok;
893 }
894 
895 /* on bitmap */
896 static Bool
img_put_bitmap_on_bitmap(Handle self,Handle image,PutImageRequest * req)897 img_put_bitmap_on_bitmap( Handle self, Handle image, PutImageRequest * req)
898 {
899 	STYLUS_USE_TEXT( sys ps);
900 	STYLUS_USE_BRUSH( sys ps);
901 	if ( dsys( image) options. aptDeviceBitmap )
902 		req-> rop = rop_reduce(GetTextColor( sys ps), GetBkColor( sys ps), req-> rop);
903 	return img_put_stretch_blt( sys ps, dsys(image)ps, req);
904 }
905 
906 static Bool
img_put_pixmap_on_bitmap(Handle self,Handle image,PutImageRequest * req)907 img_put_pixmap_on_bitmap( Handle self, Handle image, PutImageRequest * req)
908 {
909 	return img_put_stretch_blt( sys ps, dsys(image)ps, req);
910 }
911 
912 static Bool
img_put_image_on_bitmap(Handle self,Handle image,PutImageRequest * req)913 img_put_image_on_bitmap( Handle self, Handle image, PutImageRequest * req)
914 {
915 	return img_put_image_on_bitmap_or_pixmap( self, image, req, BM_BITMAP);
916 }
917 
918 static Bool
img_put_argb_on_bitmap(Handle self,Handle image,PutImageRequest * req)919 img_put_argb_on_bitmap( Handle self, Handle image, PutImageRequest * req)
920 {
921 	if ( !img_put_and_mask( sys ps, image, req))
922 		return false;
923 	req-> rop = (req->rop == ropSrcCopy) ? ropCopyPut : ropOrPut;
924 	return img_put_image_on_bitmap( self, image, req );
925 }
926 
927 static Bool
img_put_layered_on_bitmap(Handle self,Handle image,PutImageRequest * req)928 img_put_layered_on_bitmap( Handle self, Handle image, PutImageRequest * req)
929 {
930 	Bool ok;
931 	Handle icon;
932 	PIcon i;
933 	uint32_t * argb_bits;
934 	Byte * rgb_bits, *a_bits;
935 	int y;
936 
937 	icon = (Handle) create_object("Prima::Icon", "");
938 	i = (PIcon) icon;
939 
940 	CIcon(icon)-> create_empty_icon( icon, req->src_w, req->src_h, imRGB, imbpp8);
941 	for (
942 		y = 0,
943 			rgb_bits = i->data,
944 			a_bits   = i->mask,
945 			argb_bits = dsys(image) s. image. argbBits + req->src_y * i-> w + req-> src_x;
946 		y < req-> src_h;
947 		y++,
948 			rgb_bits  += i-> lineSize,
949 			a_bits    += i-> maskLine,
950 			argb_bits += i-> w
951 	) {
952 		register Byte *rgb_ptr = rgb_bits, *a_ptr = a_bits, *argb_ptr = (Byte*) argb_bits;
953 		register int x = req-> src_w;
954 		for ( ; x > 0; x--) {
955 			*rgb_ptr++ = *argb_ptr++;
956 			*rgb_ptr++ = *argb_ptr++;
957 			*rgb_ptr++ = *argb_ptr++;
958 			*a_ptr++   = *argb_ptr++;
959 		}
960 	}
961 	ok = img_put_argb_on_bitmap( self, icon, req);
962 	Object_destroy( icon );
963 	return ok;
964 }
965 
966 /* on pixmap */
967 static Bool
img_put_monodc_on_pixmap(HDC dst,HDC src,PutImageRequest * req)968 img_put_monodc_on_pixmap( HDC dst, HDC src, PutImageRequest * req)
969 {
970 	Bool ok;
971 	COLORREF oFore  = GetTextColor( dst);
972 	COLORREF oBack  = GetBkColor( dst);
973 	SetTextColor( dst, 0x00000000);
974 	SetBkColor  ( dst, 0x00FFFFFF);
975 	ok = img_put_stretch_blt( dst, src, req);
976 	SetTextColor( dst, oFore);
977 	SetBkColor  ( dst, oBack);
978 	return ok;
979 }
980 
981 static Bool
img_put_bitmap_on_pixmap(Handle self,Handle image,PutImageRequest * req)982 img_put_bitmap_on_pixmap( Handle self, Handle image, PutImageRequest * req)
983 {
984 	if ( dsys( image) options. aptDeviceBitmap ) {
985 		STYLUS_USE_TEXT( sys ps);
986 		STYLUS_USE_BRUSH( sys ps);
987 		return img_put_stretch_blt( sys ps, dsys(image)ps, req);
988 	} else
989 		return img_put_monodc_on_pixmap( sys ps, dsys(image)ps, req);
990 }
991 
992 static Bool
img_put_image_on_pixmap(Handle self,Handle image,PutImageRequest * req)993 img_put_image_on_pixmap( Handle self, Handle image, PutImageRequest * req)
994 {
995 	return img_put_image_on_bitmap_or_pixmap( self, image, req, BM_PIXMAP);
996 }
997 
998 static Bool
img_put_pixmap_on_pixmap(Handle self,Handle image,PutImageRequest * req)999 img_put_pixmap_on_pixmap( Handle self, Handle image, PutImageRequest * req)
1000 {
1001 	if ( dsys( image ) options. aptImage && (( PImage(image)-> type & imBPP ) == 1))
1002 		return img_put_monodc_on_pixmap( sys ps, dsys(image)ps, req);
1003 	else if ( !dsys(image) options. aptCompatiblePS) {
1004 		Bool ok;
1005 		Handle img = image_from_dc(image);
1006 		ok = img_put_image_on_pixmap(self, img, req);
1007 		Object_destroy( img);
1008 		return ok;
1009 	} else
1010 		return img_put_stretch_blt( sys ps, dsys(image)ps, req);
1011 }
1012 
1013 static Bool
img_put_argb_on_pixmap(Handle self,Handle image,PutImageRequest * req)1014 img_put_argb_on_pixmap( Handle self, Handle image, PutImageRequest * req)
1015 {
1016 	Bool ok;
1017 	HDC src;
1018 	HBITMAP old;
1019 
1020 	if ( req-> rop == ropSrcCopy ) {
1021 		req-> rop = ropCopyPut;
1022 		return img_put_image_on_pixmap( self, image, req);
1023 	}
1024 
1025 	image_fill_bitmap_cache( image, BM_LAYERED, self );
1026 	if ( dsys(image) bm == NULL)
1027 		return false;
1028 
1029 	src = CreateCompatibleDC(sys ps);
1030 	old = SelectObject(src, dsys (image) bm);
1031 	ok = img_put_alpha_blend( sys ps, src, req);
1032 	SelectObject(src, old);
1033 	DeleteDC(src);
1034 
1035 	return ok;
1036 }
1037 
1038 static Bool
img_put_layered_on_pixmap(Handle self,Handle image,PutImageRequest * req)1039 img_put_layered_on_pixmap( Handle self, Handle image, PutImageRequest * req)
1040 {
1041 	if ( req-> rop == ropSrcCopy ) {
1042 		req-> rop = ropCopyPut;
1043 		return img_put_pixmap_on_pixmap( self, image, req);
1044 	} else
1045 		return img_put_alpha_blend( sys ps, dsys(image)ps, req);
1046 }
1047 
1048 /* layered */
1049 static void
img_draw_black_rect(Handle self,PutImageRequest * req)1050 img_draw_black_rect( Handle self, PutImageRequest * req)
1051 {
1052 	HGDIOBJ  oldp = SelectObject( sys ps, hPenHollow);
1053 	HGDIOBJ  oldh = SelectObject( sys ps, CreateSolidBrush( RGB(0,0,0 )));
1054 	if ( !SetROP2( sys ps, R2_COPYPEN)) apiErr;
1055 	if ( !Rectangle( sys ps, req-> dst_x, req-> dst_y, req-> dst_x + req-> dst_w + 1, req-> dst_y + req-> dst_h + 1)) apiErr;
1056 	if ( !SetROP2( sys ps, sys currentROP)) apiErr;
1057 	SelectObject( sys ps, oldp);
1058 	DeleteObject( SelectObject( sys ps, oldh));
1059 }
1060 
1061 static Bool
img_put_argb_on_layered(Handle self,Handle image,PutImageRequest * req)1062 img_put_argb_on_layered( Handle self, Handle image, PutImageRequest * req)
1063 {
1064 	Bool ok;
1065 	HDC src;
1066 	HBITMAP old;
1067 
1068 	image_fill_bitmap_cache( image, BM_LAYERED, self );
1069 	if ( dsys(image) bm == NULL)
1070 		return false;
1071 
1072 	src = CreateCompatibleDC(sys ps);
1073 	old = SelectObject(src, dsys (image) bm);
1074 	if ( req-> rop == ropSrcCopy ) {
1075 		req-> rop = ropCopyPut;
1076 		img_draw_black_rect( self, req );
1077 		ok = img_put_stretch_blt( sys ps, src, req);
1078 	} else
1079 		ok = img_put_alpha_blend( sys ps, src, req);
1080 	SelectObject(src, old);
1081 	DeleteDC(src);
1082 
1083 	return ok;
1084 }
1085 
1086 static Bool
img_put_a8_on_layered(Handle self,Handle image,PutImageRequest * req)1087 img_put_a8_on_layered( Handle self, Handle image, PutImageRequest * req)
1088 {
1089 	Bool ok;
1090 	HDC dc, buf_dc;
1091 	HBITMAP buf_bm, old_bm;
1092 	PImage i;
1093 	unsigned int dst_lw, src_lw, y;
1094 	Byte *src, *dst;
1095 
1096 	i = (PImage) image;
1097 	if ( i-> type != imByte || i-> w != req-> dst_w || i-> h != req-> dst_h ) {
1098 		Handle dup = CImage( image )->dup(image);
1099 		if ( i-> type != imByte )
1100 			CImage( dup )->set_type(dup, imByte);
1101 		if (i-> w != req-> dst_w || i-> h != req-> dst_h )
1102 			CImage( dup )->stretch(dup, req->dst_w, req-> dst_h);
1103 		ok = img_put_a8_on_layered( self, dup, req);
1104 		Object_destroy(dup);
1105 		return ok;
1106 	}
1107 
1108 	dc     = GetDC(NULL);
1109 	buf_dc = CreateCompatibleDC(dc);
1110 	if ( !(buf_bm = image_create_argb_dib_section(dc, req-> dst_w, req-> dst_h, (uint32_t**) &dst))) {
1111 		DeleteDC(buf_dc);
1112 		ReleaseDC(NULL, dc);
1113 		return false;
1114 	}
1115 
1116 	old_bm = SelectObject(buf_dc, buf_bm);
1117 
1118 	BitBlt( buf_dc, 0, 0, req-> dst_w, req-> dst_h, sys ps, req-> dst_x, req-> dst_y, SRCCOPY);
1119 
1120 	src    = i-> data;
1121 	dst_lw = req-> dst_w * 4;
1122 	src_lw = i-> lineSize;
1123 	for ( y = 0; y < i-> h; y++, src += src_lw, dst += dst_lw ) {
1124 		register Byte *ss = src, *dd = dst + 3;
1125 		register unsigned int w = i-> w;
1126 		while (w--) {
1127 			*dd = *ss++;
1128 			dd += 4;
1129 		}
1130 	}
1131 
1132 	BitBlt( sys ps, req-> dst_x, req-> dst_y, req-> dst_w, req-> dst_h, buf_dc, 0, 0, SRCCOPY);
1133 
1134 	SelectObject(buf_dc, old_bm);
1135 	DeleteDC(buf_dc);
1136 	DeleteObject(buf_bm);
1137 	ReleaseDC(NULL, dc);
1138 	return true;
1139 }
1140 
1141 static Bool
img_put_layered_on_layered(Handle self,Handle image,PutImageRequest * req)1142 img_put_layered_on_layered( Handle self, Handle image, PutImageRequest * req)
1143 {
1144 	if ( req-> rop == ropSrcCopy ) {
1145 		req-> rop = ropCopyPut;
1146 		img_draw_black_rect( self, req );
1147 		return img_put_stretch_blt( sys ps, dsys(image)ps, req);
1148 	} else
1149 		return img_put_alpha_blend( sys ps, dsys(image)ps, req);
1150 }
1151 
1152 PutImageFunc (*img_put_on_bitmap[SRC_NUM]) = {
1153 	img_put_bitmap_on_bitmap,
1154 	img_put_pixmap_on_bitmap,
1155 	img_put_layered_on_bitmap,
1156 	img_put_image_on_bitmap,
1157 	img_put_image_on_bitmap,
1158 	img_put_argb_on_bitmap,
1159 };
1160 
1161 PutImageFunc (*img_put_on_pixmap[SRC_NUM]) = {
1162 	img_put_bitmap_on_pixmap,
1163 	img_put_pixmap_on_pixmap,
1164 	img_put_layered_on_pixmap,
1165 	img_put_image_on_pixmap,
1166 	img_put_image_on_pixmap,
1167 	img_put_argb_on_pixmap,
1168 };
1169 
1170 PutImageFunc (*img_put_on_layered[SRC_NUM]) = {
1171 	img_put_bitmap_on_pixmap,
1172 	img_put_pixmap_on_pixmap,
1173 	img_put_layered_on_layered,
1174 	img_put_image_on_pixmap,
1175 	img_put_a8_on_layered,
1176 	img_put_argb_on_layered,
1177 };
1178 
1179 Bool
apc_gp_stretch_image(Handle self,Handle image,int dst_x,int dst_y,int src_x,int src_y,int dst_w,int dst_h,int src_w,int src_h,int rop)1180 apc_gp_stretch_image( Handle self, Handle image,
1181 	int dst_x, int dst_y, int src_x, int src_y,
1182 	int dst_w, int dst_h, int src_w, int src_h, int rop)
1183 {
1184 	PIcon img = (PIcon) image;
1185 	PutImageRequest req;
1186 	PutImageFunc ** dst = NULL;
1187 	int src = -1;
1188 	Bool and_mask = false;
1189 
1190 	objCheck false;
1191 	dobjCheck(image) false;
1192 
1193 	if ( src_h < 0) {
1194 		src_h = -src_h;
1195 		dst_h = -dst_h;
1196 	}
1197 	if ( src_w < 0) {
1198 		src_w = -src_w;
1199 		dst_w = -dst_w;
1200 	}
1201 	if ( abs(src_x) >= img-> w) return false;
1202 	if ( abs(src_y) >= img-> h) return false;
1203 	if ( src_w == 0 || src_h == 0) return false;
1204 	if ( src_x < 0) {
1205 		dst_x -= src_x * dst_w / src_w;
1206 		dst_w += src_x * dst_w / src_w;
1207 		src_w += src_x;
1208 		src_x = 0;
1209 	}
1210 	if ( src_y < 0) {
1211 		dst_y -= src_y * dst_h / src_h;
1212 		dst_h += src_y * dst_h / src_h;
1213 		src_h += src_y;
1214 		src_y = 0;
1215 	}
1216 	if ( src_x + src_w > img-> w) {
1217 		dst_w = (img-> w - src_x) * dst_w / src_w;
1218 		src_w = img-> w - src_x;
1219 	}
1220 	if ( src_y + src_h > img-> h) {
1221 		dst_h = (img-> h - src_y) * dst_h / src_h;
1222 		src_h = img-> h - src_y;
1223 	}
1224 	if ( src_w <= 0 || src_h <= 0) return false;
1225 
1226 	memset( &req, 0, sizeof(req));
1227 	req. src_x = src_x;
1228 	req. src_y = img->h - src_y - src_h;
1229 	req. src_w = src_w;
1230 	req. src_h = src_h;
1231 	req. dst_x = sys gp_transform.x + dst_x;
1232 	req. dst_y = sys gp_transform.y + sys lastSize. y - dst_y - dst_h;
1233 	req. dst_w = dst_w;
1234 	req. dst_h = dst_h;
1235 	req. rop   = rop;
1236 
1237 	if ( dsys( image) options. aptDeviceBitmap ) {
1238 		PDeviceBitmap p = (PDeviceBitmap) image;
1239 		switch (p->type) {
1240 		case dbtBitmap:  src = SRC_BITMAP;  break;
1241 		case dbtPixmap:  src = SRC_PIXMAP;  break;
1242 		case dbtLayered: src = SRC_LAYERED; break;
1243 		}
1244 	} else if ( dsys( image) options. aptIcon ) {
1245 		Bool src_mono = img-> type == imBW;
1246 		if ( img-> maskType == imbpp1 || guts. displayBMInfo. bmiHeader. biBitCount <= 8) {
1247 			if ( img-> options. optInDraw )
1248 				src = src_mono ? SRC_BITMAP : SRC_PIXMAP;
1249 			else
1250 				src = SRC_IMAGE;
1251 			and_mask = true;
1252 		} else if ( img-> maskType == imbpp8 ) {
1253 			if ( img-> options. optInDraw ) {
1254 				src = SRC_LAYERED;
1255 			} else
1256 				src = SRC_ARGB;
1257 		}
1258 	} else if ( dsys( image) options. aptImage ) {
1259 		Bool src_mono = img-> type == imBW;
1260 		if ( img-> options. optInDraw )
1261 			src = src_mono ? SRC_BITMAP : SRC_PIXMAP;
1262 		else
1263 			src = SRC_IMAGE;
1264 	}
1265 	if ( src < 0 ) {
1266 		warn("cannot guess image type");
1267 		return false;
1268 	}
1269 
1270 	if (( is_apt(aptDeviceBitmap) && ((PDeviceBitmap)self)->type == dbtBitmap) ||
1271 		( is_apt(aptImage)        && ((PImage)self)-> type == imBW ))
1272 		dst = img_put_on_bitmap;
1273 	else if ( is_apt(aptLayered))
1274 		dst = img_put_on_layered;
1275 	else if (( is_apt(aptDeviceBitmap) && ((PDeviceBitmap)self)->type == dbtPixmap) ||
1276 		(is_apt(aptImage)        && ((PImage)self)-> type != imBW ))
1277 		dst = img_put_on_pixmap;
1278 	else if ( apc_widget_get_layered_request(self) && apc_widget_surface_is_layered(self))
1279 		dst = img_put_on_layered;
1280 	else
1281 		dst = img_put_on_pixmap;
1282 
1283 	if (
1284 		dst == img_put_on_layered &&
1285 		src == SRC_IMAGE &&
1286 		!dsys( image) options. aptIcon &&
1287 		(((PImage)image)->type & imGrayScale) &&
1288 		rop == ropAlphaCopy ) {
1289 		src = SRC_A8;
1290 		rop = ropCopyPut;
1291 	}
1292 
1293 	if ( rop > ropNoOper ) return false;
1294 
1295 	if ( dst[src] == NULL ) {
1296 		warn("not implemented");
1297 		return false;
1298 	}
1299 
1300 	if ( and_mask ) {
1301 		if ( !img_put_and_mask(sys ps, image, &req))
1302 			return false;
1303 		req. rop = ropXorPut;
1304 	}
1305 
1306 	return (*dst[src])(self, image, &req);
1307 }
1308 
1309 
1310 Bool
apc_image_create(Handle self)1311 apc_image_create( Handle self)
1312 {
1313 	objCheck false;
1314 	apt_set( aptImage);
1315 	if ( kind_of( self, CIcon )) apt_set( aptIcon );
1316 	image_destroy_cache( self);
1317 	sys lastSize. x = var w;
1318 	sys lastSize. y = var h;
1319 	return true;
1320 }
1321 
1322 Bool
apc_image_destroy(Handle self)1323 apc_image_destroy( Handle self)
1324 {
1325 	objCheck false;
1326 	image_destroy_cache( self);
1327 	return true;
1328 }
1329 
1330 Bool
apc_image_begin_paint(Handle self)1331 apc_image_begin_paint( Handle self)
1332 {
1333 	apcErrClear;
1334 	objCheck false;
1335 	image_fill_bitmap_cache( self, BM_AUTO, NULL_HANDLE);
1336 	if ( sys bm == NULL ) {
1337 		image_destroy_cache( self );
1338 		return false;
1339 	}
1340 	if ( !( sys ps = CreateCompatibleDC( 0))) apiErrRet;
1341 	sys stockBM = SelectObject( sys ps, sys bm);
1342 	hwnd_enter_paint( self);
1343 
1344 	apt_clear( aptLayered );
1345 	if ( is_apt( aptIcon ) && PIcon(self)-> maskType == imbpp8 ) {
1346 		sys bpp = 32;
1347 		apt_set( aptLayered );
1348 	}
1349 	else if ( PImage( self)-> type == imBW)
1350 		sys bpp = 1;
1351 	if ( sys pal) {
1352 		SelectPalette( sys ps, sys pal, 0);
1353 		RealizePalette( sys ps);
1354 	}
1355 	return true;
1356 }
1357 
1358 Bool
apc_image_begin_paint_info(Handle self)1359 apc_image_begin_paint_info( Handle self)
1360 {
1361 	apcErrClear;
1362 	objCheck false;
1363 	if ( !( sys ps = CreateCompatibleDC( 0))) apiErrRet;
1364 	if ( !sys pal) sys pal = image_create_palette( self);
1365 	if ( sys pal) SelectPalette( sys ps, sys pal, 0);
1366 	hwnd_enter_paint( self);
1367 	if ( PImage( self)-> type == imBW)
1368 		sys bpp = 1;
1369 	else if ( is_apt( aptIcon ) && PIcon(self)-> maskType == imbpp8 ) {
1370 		sys bpp = 32;
1371 		apt_set( aptLayered );
1372 	}
1373 	return true;
1374 }
1375 
1376 Bool
apc_image_end_paint(Handle self)1377 apc_image_end_paint( Handle self)
1378 {
1379 	apcErrClear;
1380 	objCheck false;
1381 
1382 	if ( is_apt( aptLayered))
1383 		image_argb_query_bits( self);
1384 	else
1385 		image_query_bits( self, false);
1386 	hwnd_leave_paint( self);
1387 	if ( sys stockBM)
1388 		SelectObject( sys ps, sys stockBM);
1389 	DeleteDC( sys ps);
1390 	sys stockBM = NULL;
1391 	sys ps = NULL;
1392 	return apcError == errOk;
1393 }
1394 
1395 Bool
apc_image_end_paint_info(Handle self)1396 apc_image_end_paint_info( Handle self)
1397 {
1398 	objCheck false;
1399 	apcErrClear;
1400 	hwnd_leave_paint( self);
1401 	DeleteDC( sys ps);
1402 	sys ps = NULL;
1403 	return apcError == errOk;
1404 }
1405 
1406 
1407 Bool
apc_image_update_change(Handle self)1408 apc_image_update_change( Handle self)
1409 {
1410 	objCheck false;
1411 	image_destroy_cache( self);
1412 	sys lastSize. x = var w;
1413 	sys lastSize. y = var h;
1414 	return true;
1415 }
1416 
1417 HBITMAP
image_create_argb_dib_section(HDC dc,int w,int h,uint32_t ** ptr)1418 image_create_argb_dib_section( HDC dc, int w, int h, uint32_t ** ptr)
1419 {
1420 	HBITMAP bm;
1421 	BITMAPINFO bmi;
1422 	uint32_t * dummy;
1423 
1424 	if ( !ptr ) ptr = &dummy;
1425 
1426 	ZeroMemory(&bmi, sizeof(BITMAPINFO));
1427 	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1428 	bmi.bmiHeader.biWidth       = w;
1429 	bmi.bmiHeader.biHeight      = h;
1430 	bmi.bmiHeader.biPlanes      = 1;
1431 	bmi.bmiHeader.biBitCount    = 32;
1432 	bmi.bmiHeader.biCompression = BI_RGB;
1433 	bmi.bmiHeader.biSizeImage   = w * h * 4;
1434 	if ( !( bm = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, (LPVOID*)ptr, NULL, 0x0))) {
1435 		apiErr;
1436 		return NULL;
1437 	}
1438 	return bm;
1439 }
1440 
1441 Bool
apc_dbm_create(Handle self,int type)1442 apc_dbm_create( Handle self, int type)
1443 {
1444 	HDC dc;
1445 	Bool palc = 0;
1446 
1447 	objCheck false;
1448 	apcErrClear;
1449 	apt_set( aptBitmap);
1450 	apt_set( aptDeviceBitmap);
1451 	apt_set( aptCompatiblePS);
1452 
1453 	if ( !( sys ps = CreateCompatibleDC( 0))) apiErrRet;
1454 	sys lastSize. x = var w;
1455 	sys lastSize. y = var h;
1456 
1457 	if ( type == dbtLayered && guts. displayBMInfo. bmiHeader. biBitCount <= 8)
1458 		type = dbtPixmap;
1459 
1460 	switch ( type ) {
1461 	case dbtBitmap:
1462 		dc = NULL;
1463 		sys bm = CreateBitmap( var w, var h, 1, 1, NULL);
1464 		break;
1465 	case dbtPixmap:
1466 		if (!( dc = dc_alloc())) {
1467 			DeleteDC( sys ps);
1468 			return false;
1469 		}
1470 		if (( sys pal = palette_create( self))) {
1471 			sys stockPalette = SelectPalette( sys ps, sys pal, 1);
1472 			RealizePalette( sys ps);
1473 			palc = 1;
1474 		}
1475 		sys bm = CreateCompatibleBitmap( dc, var w, var h);
1476 		if ( guts. displayBMInfo. bmiHeader. biBitCount == 8)
1477 			apt_clear( aptCompatiblePS);
1478 		break;
1479 	case dbtLayered:
1480 		apt_set( aptLayered );
1481 		if (!( dc = dc_alloc())) {
1482 			DeleteDC( sys ps);
1483 			return false;
1484 		}
1485 		sys bm = image_create_argb_dib_section( dc, var w, var h, &sys s. image. argbBits);
1486 		break;
1487 	default:
1488 		DeleteDC( sys ps);
1489 		return false;
1490 	}
1491 
1492 	if ( !sys bm) {
1493 		apiErr;
1494 		if ( dc) dc_free();
1495 		if ( palc) {
1496 			SelectPalette( sys ps, sys stockPalette, 1);
1497 			DeleteObject( sys stockPalette);
1498 			sys stockPalette = NULL;
1499 		}
1500 		DeleteDC( sys ps);
1501 		return false;
1502 	}
1503 	if ( dc) dc_free();
1504 
1505 	sys stockBM = SelectObject( sys ps, sys bm);
1506 
1507 	hwnd_enter_paint( self);
1508 	switch ( type ) {
1509 	case dbtBitmap:
1510 		sys bpp = 1;
1511 		break;
1512 	case dbtLayered:
1513 		sys bpp = 32;
1514 		break;
1515 	}
1516 
1517 	hash_store( imageMan, &self, sizeof( self), (void*)self);
1518 	return true;
1519 }
1520 
1521 void
dbm_recreate(Handle self)1522 dbm_recreate( Handle self)
1523 {
1524 	HBITMAP bm, stock;
1525 	HDC dc, dca;
1526 	HPALETTE p = NULL;
1527 	Event ev = {cmSysHandle};
1528 
1529 	if ((( PDeviceBitmap) self)-> type != dbtPixmap ) return;
1530 
1531 	if ( !( dc = CreateCompatibleDC( 0))) {
1532 		apiErr;
1533 		return;
1534 	}
1535 	if (!( dca = dc_alloc())) {
1536 		DeleteDC( dc);
1537 		return;
1538 	}
1539 
1540 	if ( sys pal) {
1541 		p = SelectPalette( dc, sys pal, 1);
1542 		RealizePalette( dc);
1543 	}
1544 
1545 	if ( !( bm = CreateCompatibleBitmap( dca, var w, var h))) {
1546 		DeleteDC( dc);
1547 		dc_free();
1548 		apiErr;
1549 		return;
1550 	}
1551 	stock = SelectObject( dc, bm);
1552 
1553 	BitBlt( dc, 0, 0, var w, var h, sys ps, 0, 0, SRCCOPY);
1554 
1555 	if ( sys pal) {
1556 		SelectPalette( sys ps, sys stockPalette, 1);
1557 		sys stockPalette = p;
1558 	} else
1559 		sys stockPalette = GetCurrentObject( dc, OBJ_PAL);
1560 
1561 	if ( sys stockBM)
1562 		SelectObject( sys ps, sys stockBM);
1563 	DeleteObject( sys bm);
1564 	DeleteDC( sys ps);
1565 
1566 	sys ps = dc;
1567 	sys bm = bm;
1568 	sys stockBM = stock;
1569 	dc_free();
1570 
1571 	ev. gen. source = self;
1572 	var self-> message( self, &ev);
1573 }
1574 
1575 Bool
apc_dbm_destroy(Handle self)1576 apc_dbm_destroy( Handle self)
1577 {
1578 	apcErrClear;
1579 	hash_delete( imageMan, &self, sizeof( self), false);
1580 	objCheck false;
1581 
1582 	hwnd_leave_paint( self);
1583 
1584 	if ( sys pal)
1585 		DeleteObject( sys pal);
1586 	if ( sys stockBM)
1587 	SelectObject( sys ps, sys stockBM);
1588 	DeleteObject( sys bm);
1589 	DeleteDC( sys ps);
1590 	sys pal = NULL;
1591 	sys stockBM = NULL;
1592 	sys ps = NULL;
1593 	sys bm = NULL;
1594 	return true;
1595 }
1596 
1597 HICON
image_make_icon_handle(Handle img,Point size,Point * hotSpot)1598 image_make_icon_handle( Handle img, Point size, Point * hotSpot)
1599 {
1600 	PIcon i = ( PIcon) img;
1601 	HICON    r;
1602 	ICONINFO ii;
1603 	int    bpp = i-> type & imBPP;
1604 	Bool  noSZ   = i-> w != size. x || i-> h != size. y;
1605 	Bool  noBPP  = bpp != 1 && bpp != 4 && bpp != 8 && bpp != 24;
1606 	HDC dc;
1607 	Bool notAnIcon = !dsys( img ) options. aptIcon;
1608 
1609 	ii. fIcon = hotSpot ? false : true;
1610 	ii. xHotspot = hotSpot ? hotSpot-> x : 0;
1611 	ii. yHotspot = hotSpot ? hotSpot-> y : 0;
1612 
1613 	if (!notAnIcon && i->maskType == 8 && bpp != 24 ) {
1614 		bpp = 24;
1615 		noBPP = true;
1616 	}
1617 
1618 	if ( noSZ || noBPP) {
1619 		i = ( PIcon)( i-> self-> dup( img));
1620 
1621 		if ( noSZ)
1622 			i-> self-> set_size(( Handle) i, size);
1623 		if ( noBPP)
1624 			i-> self-> set_type(( Handle) i,
1625 				( bpp < 4) ? 1 :
1626 				(( bpp < 8) ? 4 :
1627 				(( bpp < 24) ? 8 : 24))
1628 		);
1629 	}
1630 
1631 	if (!( dc = dc_alloc())) {
1632 		if (( Handle) i != img) Object_destroy(( Handle) i);
1633 		return NULL;
1634 	}
1635 
1636 	if (!notAnIcon && i->maskType == 8) {
1637 		/* argb icon */
1638 		int j, size;
1639 		void *mask;
1640 		Byte * argb;
1641 		XBITMAPINFO bi;
1642 		image_fill_bitmap_info(( Handle)i, &bi, BM_BITMAP);
1643 		bi. bmiColors[ 0]. rgbRed = bi. bmiColors[ 0]. rgbGreen = bi. bmiColors[ 0]. rgbBlue = 0;
1644 		bi. bmiColors[ 1]. rgbRed = bi. bmiColors[ 1]. rgbGreen = bi. bmiColors[ 1]. rgbBlue = 255;
1645 		mask = i->self->convert_mask(img, imbpp1);
1646 		ii. hbmMask = CreateDIBitmap( dc, &bi. bmiHeader, CBM_INIT,
1647 			mask, ( BITMAPINFO*) &bi, DIB_RGB_COLORS);
1648 		free(mask);
1649 		if ( ii. hbmMask == NULL ) return false;
1650 
1651 		if (( ii. hbmColor = image_create_argb_bitmap(( Handle) i , (uint32_t**) &argb )) == NULL ) {
1652 			DeleteObject( ii. hbmMask);
1653 			return false;
1654 		}
1655 		/* alpha 0 is treated very strange if all alpha bytes are 0 and there are not a single non-0 byte -
1656 		cursor becomes a negative version of itself. Might be a driver bug though */
1657 		size = i-> w * i-> h;
1658 		for ( j = 0, argb += 3; j < size; j++, argb += 4)
1659 			if ( *argb == 0) *argb = 1;
1660 	} else {
1661 		XBITMAPINFO bi;
1662 		Byte * mask;
1663 		image_fill_bitmap_info(( Handle)i, &bi, BM_PIXMAP);
1664 		if ( bi. bmiHeader. biClrUsed > 0)
1665 			bi. bmiHeader. biClrUsed = bi. bmiHeader. biClrImportant = i-> palSize;
1666 
1667 		if ( !( ii. hbmColor = CreateDIBitmap( dc, &bi. bmiHeader, CBM_INIT,
1668 			i-> data, ( BITMAPINFO*) &bi, DIB_RGB_COLORS))) apiErr;
1669 		bi. bmiHeader. biBitCount = bi. bmiHeader. biPlanes = 1;
1670 		bi. bmiColors[ 0]. rgbRed = bi. bmiColors[ 0]. rgbGreen = bi. bmiColors[ 0]. rgbBlue = 0;
1671 		bi. bmiColors[ 1]. rgbRed = bi. bmiColors[ 1]. rgbGreen = bi. bmiColors[ 1]. rgbBlue = 255;
1672 
1673 		if ( notAnIcon )
1674 			mask = NULL;
1675 		else
1676 			mask = i-> mask;
1677 		if ( !( ii. hbmMask  = CreateDIBitmap( dc, &bi. bmiHeader, CBM_INIT,
1678 			mask, ( BITMAPINFO*) &bi, DIB_RGB_COLORS))) apiErr;
1679 	}
1680 
1681 	dc_free();
1682 
1683 	if ( !( r = CreateIconIndirect( &ii))) apiErr;
1684 
1685 	DeleteObject( ii. hbmColor);
1686 	DeleteObject( ii. hbmMask);
1687 	if (( Handle) i != img) Object_destroy(( Handle) i);
1688 	return r;
1689 }
1690 
1691 void *
image_create_dib(Handle image,Bool global_alloc)1692 image_create_dib(Handle image, Bool global_alloc)
1693 {
1694 	int size, offset;
1695 	XBITMAPINFO bi;
1696 	PIcon i;
1697 	void *ptr, *ret;
1698 	Byte * data;
1699 
1700 	i = (PIcon) image;
1701 	if ( dsys(image)options.aptIcon && i->type != imRGB ) {
1702 		Handle dup = CImage(image)->dup(image);
1703 		CImage(dup)->set_type( dup, imRGB );
1704 		ret = image_create_dib(dup, global_alloc);
1705 		Object_destroy(dup);
1706 		return ret;
1707 	} else if ( i->type & (imSignedInt | imRealNumber | imComplexNumber | imTrigComplexNumber)) {
1708 		Handle dup = CImage(image)->dup(image);
1709 		CImage(dup)->set_type( dup, imByte );
1710 		ret = image_create_dib(dup, global_alloc);
1711 		Object_destroy(dup);
1712 		return ret;
1713 	}
1714 
1715 	image_fill_bitmap_info(image, &bi, BM_AUTO);
1716 	if ( bi.bmiHeader.biClrUsed > 0)
1717 		bi.bmiHeader.biClrUsed = bi.bmiHeader.biClrImportant = i-> palSize;
1718 
1719 	offset = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * bi.bmiHeader.biClrUsed;
1720 	size = i->dataSize + sizeof(BITMAPINFOHEADER) + offset;
1721 	if ( global_alloc ) {
1722 		if (!( ret = GlobalAlloc( GMEM_DDESHARE, size)))
1723 			return NULL;
1724 		if ( !( ptr = GlobalLock( ret))) {
1725 			GlobalFree( ret );
1726 			return NULL;
1727 		}
1728 	} else {
1729 		if ( !( ptr = ret = malloc(size)))
1730 			return NULL;
1731 	}
1732 
1733 	memcpy( ptr, &bi, offset);
1734 	data = ptr;
1735 	data += offset;
1736 
1737 	if ( bi. bmiHeader. biBitCount == 32 ) {
1738 		if ( !icon2argb(i, (uint32_t*)data)) {
1739 			if ( global_alloc ) {
1740 				GlobalUnlock( ret );
1741 				GlobalFree( ret );
1742 			} else
1743 				free(ret);
1744 			return NULL;
1745 		}
1746 	} else
1747 		memcpy( data, i->data, i->dataSize );
1748 
1749 	if ( global_alloc )
1750 		GlobalUnlock( ret );
1751 
1752 	return ret;
1753 }
1754 
1755 ApiHandle
apc_image_get_handle(Handle self)1756 apc_image_get_handle( Handle self)
1757 {
1758 	objCheck 0;
1759 	return ( ApiHandle) sys ps;
1760 }
1761 
1762 ApiHandle
apc_dbm_get_handle(Handle self)1763 apc_dbm_get_handle( Handle self)
1764 {
1765 	objCheck 0;
1766 	return ( ApiHandle) sys ps;
1767 }
1768 
1769 
1770 #ifdef __cplusplus
1771 }
1772 #endif
1773