2 * GDI bit-blit operations
4 * Copyright 1993 Alexandre Julliard
7 static char Copyright
[] = "Copyright Alexandre Julliard, 1993";
12 #include <X11/Intrinsic.h>
18 /* #define DEBUG_GDI */
19 /* #undef DEBUG_GDI */
22 extern const int DC_XROPfunction
[];
23 extern Colormap COLOR_WinColormap
;
25 #define MIN(a,b) ((a) < (b) ? (a) : (b))
26 #define MAX(a,b) ((a) > (b) ? (a) : (b))
29 /***********************************************************************
32 static XImage
*BITBLT_GetImage( HDC hdc
, int x
, int y
, int width
, int height
)
36 DC
* dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
);
38 GetClipBox( hdc
, &rect
);
39 OffsetRect( &rect
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
40 if ((x
>= rect
.left
) && (y
>= rect
.top
)
41 && (x
+width
< rect
.right
) && (y
+height
< rect
.bottom
))
43 image
= XGetImage( display
, dc
->u
.x
.drawable
, x
, y
, width
, height
,
46 else /* Get only the visible sub-image */
48 int width_bytes
= ((dc
->w
.bitsPerPixel
== 24 ? 32 : dc
->w
.bitsPerPixel
)
49 * width
+ 31) / 32 * 4;
50 char *data
= malloc( height
* width_bytes
);
51 image
= XCreateImage( display
, DefaultVisualOfScreen(screen
),
52 dc
->w
.bitsPerPixel
, ZPixmap
, 0, data
,
53 width
, height
, 32, width_bytes
);
54 if (image
&& !IsRectEmpty(&rect
))
57 x1
= max( x
, rect
.left
);
58 y1
= max( y
, rect
.top
);
59 x2
= min( x
+ width
, rect
.right
);
60 y2
= min( y
+ height
, rect
.bottom
);
61 if ((x1
< x2
) && (y1
< y2
))
62 XGetSubImage( display
, dc
->u
.x
.drawable
, x1
, y1
, x2
-x1
, y2
-y1
,
63 AllPlanes
, ZPixmap
, image
, x1
-x
, y1
-y
);
70 /***********************************************************************
73 BOOL
PatBlt( HDC hdc
, short left
, short top
,
74 short width
, short height
, DWORD rop
)
76 DC
* dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
);
79 dc
= (DC
*)GDI_GetObjPtr(hdc
, METAFILE_DC_MAGIC
);
80 if (!dc
) return FALSE
;
81 MF_MetaParam6(dc
, META_PATBLT
, left
, top
, width
, height
,
82 HIWORD(rop
), LOWORD(rop
));
86 dprintf_gdi(stddeb
, "PatBlt: %d %d,%d %dx%d %06lx\n",
87 hdc
, left
, top
, width
, height
, rop
);
89 /* Convert ROP3 code to ROP2 code */
91 if (!DC_SetupGCForBrush( dc
)) rop
&= 0x0f;
92 else rop
= (rop
& 0x03) | ((rop
>> 4) & 0x0c);
94 /* Special case for BLACKNESS and WHITENESS */
95 if (!Options
.usePrivateMap
&& ((rop
== R2_BLACK
-1) || (rop
== R2_WHITE
-1)))
97 XSetForeground( display
, dc
->u
.x
.gc
, (rop
== R2_BLACK
-1) ?
98 BlackPixelOfScreen(screen
) : WhitePixelOfScreen(screen
));
99 XSetFillStyle( display
, dc
->u
.x
.gc
, FillSolid
);
103 XSetFunction( display
, dc
->u
.x
.gc
, DC_XROPfunction
[rop
] );
105 left
= dc
->w
.DCOrgX
+ XLPTODP( dc
, left
);
106 top
= dc
->w
.DCOrgY
+ YLPTODP( dc
, top
);
108 /* Convert dimensions to device coords */
109 if ((width
= (width
* dc
->w
.VportExtX
) / dc
->w
.WndExtX
) < 0)
114 if ((height
= (height
* dc
->w
.VportExtY
) / dc
->w
.WndExtY
) < 0)
120 XFillRectangle( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
121 left
, top
, width
, height
);
126 /***********************************************************************
129 BOOL
BitBlt( HDC hdcDest
, short xDest
, short yDest
, short width
, short height
,
130 HDC hdcSrc
, short xSrc
, short ySrc
, DWORD rop
)
132 int xs1
, xs2
, ys1
, ys2
;
133 int xd1
, xd2
, yd1
, yd2
;
137 dprintf_gdi(stddeb
, "BitBlt: %04x %d,%d %dx%d %04x %d,%d %06lx\n",
138 hdcDest
, xDest
, yDest
, width
, height
, hdcSrc
, xSrc
, ySrc
, rop
);
140 if (width
== 0 || height
== 0) return FALSE
;
141 if ((rop
& 0xcc0000) == ((rop
& 0x330000) << 2))
142 return PatBlt( hdcDest
, xDest
, yDest
, width
, height
, rop
);
146 dcSrc
= (DC
*) GDI_GetObjPtr( hdcSrc
, DC_MAGIC
);
147 if (!dcSrc
) return FALSE
;
148 dcDest
= (DC
*) GDI_GetObjPtr( hdcDest
, DC_MAGIC
);
151 dcDest
= (DC
*)GDI_GetObjPtr(hdcDest
, METAFILE_DC_MAGIC
);
152 if (!dcDest
) return FALSE
;
153 MF_BitBlt(dcDest
, xDest
, yDest
, width
, height
,
154 hdcSrc
, xSrc
, ySrc
, saverop
);
158 xs1
= dcSrc
->w
.DCOrgX
+ XLPTODP( dcSrc
, xSrc
);
159 xs2
= dcSrc
->w
.DCOrgX
+ XLPTODP( dcSrc
, xSrc
+ width
);
160 ys1
= dcSrc
->w
.DCOrgY
+ YLPTODP( dcSrc
, ySrc
);
161 ys2
= dcSrc
->w
.DCOrgY
+ YLPTODP( dcSrc
, ySrc
+ height
);
162 xd1
= dcDest
->w
.DCOrgX
+ XLPTODP( dcDest
, xDest
);
163 xd2
= dcDest
->w
.DCOrgX
+ XLPTODP( dcDest
, xDest
+ width
);
164 yd1
= dcDest
->w
.DCOrgY
+ YLPTODP( dcDest
, yDest
);
165 yd2
= dcDest
->w
.DCOrgY
+ YLPTODP( dcDest
, yDest
+ height
);
167 if ((abs(xs2
-xs1
) != abs(xd2
-xd1
)) || (abs(ys2
-ys1
) != abs(yd2
-yd1
)))
168 return FALSE
; /* Should call StretchBlt here */
170 DC_SetupGCForText( dcDest
);
171 if (((rop
& 0x0f) == (rop
>> 4))&&(rop
!=0xbb))
172 /* FIXME: Test, whether more than just 0xbb has to be excluded */
174 XSetFunction( display
, dcDest
->u
.x
.gc
, DC_XROPfunction
[rop
& 0x0f] );
175 if (dcSrc
->w
.bitsPerPixel
== dcDest
->w
.bitsPerPixel
)
177 XCopyArea( display
, dcSrc
->u
.x
.drawable
,
178 dcDest
->u
.x
.drawable
, dcDest
->u
.x
.gc
,
179 min(xs1
,xs2
), min(ys1
,ys2
), abs(xs2
-xs1
), abs(ys2
-ys1
),
180 min(xd1
,xd2
), min(yd1
,yd2
) );
184 if (dcSrc
->w
.bitsPerPixel
!= 1) return FALSE
;
185 XCopyPlane( display
, dcSrc
->u
.x
.drawable
,
186 dcDest
->u
.x
.drawable
, dcDest
->u
.x
.gc
,
187 min(xs1
,xs2
), min(ys1
,ys2
), abs(xs2
-xs1
), abs(ys2
-ys1
),
188 min(xd1
,xd2
), min(yd1
,yd2
), 1 );
193 XImage
*sxi
, *dxi
, *bxi
;
194 int x
,y
,s
,d
,p
,res
,ofs
,i
,cp
,cs
,cd
,cres
;
195 XColor sentry
,dentry
,pentry
,entry
;
198 /* HDC hdcBrush = CreateCompatibleDC(hdcDest);
200 RECT r
= {min(xDest
,xDest
+width
), min(yDest
,yDest
+height
),
201 MAX(xDest
,xDest
+width
), MAX(yDest
,yDest
+height
)};
202 HBRUSH cur_brush
=SelectObject(hdcDest
, GetStockObject(BLACK_BRUSH
));
203 SelectObject(hdcDest
, cur_brush
);
204 /* FillRect(hdcBrush, &r, cur_brush);*/
205 sxi
= BITBLT_GetImage( hdcSrc
, min(xs1
,xs2
), min(ys1
,ys2
),
206 abs(xs2
-xs1
), abs(ys2
-ys1
) );
207 dxi
= BITBLT_GetImage( hdcDest
, min(xd1
,xd2
), min(yd1
,yd2
),
208 abs(xs2
-xs1
), abs(ys2
-ys1
) );
209 /* dcBrush = (DC *) GDI_GetObjPtr( hdcBrush, DC_MAGIC );*/
210 /* bxi=XGetImage(display, dcBrush->u.x.drawable, min(xd1,xd2),min(yd1,yd2),
211 abs(xs2-xs1), abs(ys2-ys1), AllPlanes, ZPixmap);*/
212 /* FIXME: It's really not necessary to do this on the visible screen */
213 FillRect(hdcDest
, &r
, cur_brush
);
214 bxi
= BITBLT_GetImage( hdcDest
, min(xd1
,xd2
), min(yd1
,yd2
),
215 abs(xs2
-xs1
), abs(ys2
-ys1
) );
216 for (i
=0; i
<min(256,1<<(dcDest
->w
.bitsPerPixel
)); i
++)
219 XQueryColor ( display
, COLOR_WinColormap
, &entry
);
220 colors
[i
] = (int) RGB( entry
.red
>>8, entry
.green
>>8, entry
.blue
>>8 );
222 if (dcSrc
->w
.bitsPerPixel
== dcDest
->w
.bitsPerPixel
)
224 for(x
=0; x
<abs(xs2
-xs1
); x
++)
226 for(y
=0; y
<abs(ys2
-ys1
); y
++)
228 s
= XGetPixel(sxi
, x
, y
);
229 d
= XGetPixel(dxi
, x
, y
);
230 p
= XGetPixel(bxi
, x
, y
);
236 XQueryColor ( display
, COLOR_WinColormap
, &sentry
);
237 cs
= (int) RGB( sentry
.red
>>8,sentry
.green
>>8, sentry
.blue
>>8 );
244 XQueryColor ( display
, COLOR_WinColormap
, &dentry
);
245 cd
= (int) RGB( dentry
.red
>>8, dentry
.green
>>8,dentry
.blue
>>8 );
252 XQueryColor ( display
, COLOR_WinColormap
, &pentry
);
253 cp
= (int) RGB( pentry
.red
>>8, pentry
.green
>>8,pentry
.blue
>>8 );
258 ofs
=1<<(((cp
>>i
)&1)*4+((cs
>>i
)&1)*2+((cd
>>i
)&1));
271 for (i
=0; i
<min(256,1<<(dcDest
->w
.bitsPerPixel
)); i
++)
278 res
= GetNearestPaletteIndex(dcDest
->w
.hPalette
, res
);
280 XPutPixel(dxi
, x
, y
, res
);
285 fprintf(stderr
,"BitBlt // depths different!\n");
286 XPutImage(display
, dcDest
->u
.x
.drawable
, dcDest
->u
.x
.gc
,
287 dxi
, 0, 0, min(xd1
,xd2
), min(yd1
,yd2
), abs(xs2
-xs1
), abs(ys2
-ys1
)+38);
291 /*DeleteDC(hdcBrush);*/
298 /***********************************************************************
299 * black on white stretch -- favors color pixels over white
302 static void bonw_stretch(XImage
*sxi
, XImage
*dxi
,
303 short widthSrc
, short heightSrc
, short widthDest
, short heightDest
)
305 float deltax
, deltay
, sourcex
, sourcey
, oldsourcex
, oldsourcey
;
308 int totalx
, totaly
, xavgwhite
, yavgwhite
;
312 deltax
= (float)widthSrc
/widthDest
;
313 deltay
= (float)heightSrc
/heightDest
;
314 whitep
= WhitePixel(display
, DefaultScreen(display
));
317 for (x
=0, sourcex
=0.0; x
<widthDest
;
318 x
++, oldsourcex
=sourcex
, sourcex
+=deltax
) {
323 for (i
=(int)oldsourcex
; i
<=endx
; i
++)
324 if (XGetPixel(sxi
, i
, (int)sourcey
) == whitep
)
326 xavgwhite
= (totalx
> (int)(deltax
/ 2.0));
332 for (y
=0, sourcey
=0.0; y
<heightDest
;
333 y
++, oldsourcey
=sourcey
, sourcey
+=deltay
) {
338 for (i
=(int)oldsourcey
; i
<=endy
; i
++)
339 if (XGetPixel(sxi
, (int)sourcex
, i
) == whitep
)
341 yavgwhite
= (totaly
> ((int)deltay
/ 2));
345 if (xavgwhite
&& yavgwhite
)
346 XPutPixel(dxi
, x
, y
, whitep
);
348 XPutPixel(dxi
, x
, y
, XGetPixel(sxi
, (int)sourcex
, (int)sourcey
));
350 } /* for all y in dest */
351 } /* for all x in dest */
355 /***********************************************************************
356 * white on black stretch -- favors color pixels over black
359 static void wonb_stretch(XImage
*sxi
, XImage
*dxi
,
360 short widthSrc
, short heightSrc
, short widthDest
, short heightDest
)
362 float deltax
, deltay
, sourcex
, sourcey
, oldsourcex
, oldsourcey
;
365 int totalx
, totaly
, xavgblack
, yavgblack
;
369 deltax
= (float)widthSrc
/widthDest
;
370 deltay
= (float)heightSrc
/heightDest
;
371 blackp
= WhitePixel(display
, DefaultScreen(display
));
374 for (x
=0, sourcex
=0.0; x
<widthDest
;
375 x
++, oldsourcex
=sourcex
, sourcex
+=deltax
) {
380 for (i
=(int)oldsourcex
; i
<=endx
; i
++)
381 if (XGetPixel(sxi
, i
, (int)sourcey
) == blackp
)
383 xavgblack
= (totalx
> (int)(deltax
/ 2.0));
389 for (y
=0, sourcey
=0.0; y
<heightDest
;
390 y
++, oldsourcey
=sourcey
, sourcey
+=deltay
) {
395 for (i
=(int)oldsourcey
; i
<=endy
; i
++)
396 if (XGetPixel(sxi
, (int)sourcex
, i
) == blackp
)
398 yavgblack
= (totaly
> ((int)deltay
/ 2));
402 if (xavgblack
&& yavgblack
)
403 XPutPixel(dxi
, x
, y
, blackp
);
405 XPutPixel(dxi
, x
, y
, XGetPixel(sxi
, (int)sourcex
, (int)sourcey
));
407 } /* for all y in dest */
408 } /* for all x in dest */
411 /* We use the 32-bit to 64-bit multiply and 64-bit to 32-bit divide of the */
412 /* 386 (which gcc doesn't know well enough) to efficiently perform integer */
413 /* scaling without having to worry about overflows. */
415 /* ##### muldiv64() borrowed from svgalib 1.03 ##### */
416 static __inline__
int muldiv64( int m1
, int m2
, int d
)
418 /* int32 * int32 -> int64 / int32 -> int32 */
424 : "=&a" (result
) /* out */
425 : "0" (m1
), "d" (m2
), "g" (d
) /* in */
434 /***********************************************************************
435 * color stretch -- deletes unused pixels
438 static void color_stretch(XImage
*sxi
, XImage
*dxi
,
439 short widthSrc
, short heightSrc
, short widthDest
, short heightDest
)
441 register int x
, y
, sx
, sy
, xfactor
, yfactor
;
443 xfactor
= muldiv64(widthSrc
, 65536, widthDest
);
444 yfactor
= muldiv64(heightSrc
, 65536, heightDest
);
448 for (y
= 0; y
< heightDest
;)
450 int sourcey
= sy
>> 16;
452 for (x
= 0; x
< widthDest
; x
++) {
453 XPutPixel(dxi
, x
, y
, XGetPixel(sxi
, sx
>> 16, sourcey
));
457 while (y
< heightDest
) {
463 if ((sy
>> 16) != sourcey
)
466 /* vertical stretch => copy previous line */
470 for (x
= 0; x
< widthDest
; x
++)
471 XPutPixel(dxi
, x
, y
, XGetPixel(dxi
, x
, py
));
477 /***********************************************************************
478 * StretchBlt (GDI.35)
480 * o StretchBlt is CPU intensive so we only call it if we have
481 * to. Checks are made to see if we can call BitBlt instead.
483 * o the stretching is slowish, some integer interpolation would
486 * o only black on white and color copy have been tested
488 BOOL
StretchBlt( HDC hdcDest
, short xDest
, short yDest
, short widthDest
, short heightDest
,
489 HDC hdcSrc
, short xSrc
, short ySrc
, short widthSrc
, short heightSrc
, DWORD rop
)
491 int xs1
, xs2
, ys1
, ys2
;
492 int xd1
, xd2
, yd1
, yd2
;
498 dprintf_gdi(stddeb
, "StretchBlt: %d %d,%d %dx%d %d %d,%d %dx%d %06lx\n",
499 hdcDest
, xDest
, yDest
, widthDest
, heightDest
, hdcSrc
, xSrc
,
500 ySrc
, widthSrc
, heightSrc
, rop
);
501 dprintf_gdi(stddeb
, "StretchMode is %x\n",
502 ((DC
*)GDI_GetObjPtr(hdcDest
, DC_MAGIC
))->w
.stretchBltMode
);
504 if (widthDest
== 0 || heightDest
== 0) return FALSE
;
505 if (widthSrc
== 0 || heightSrc
== 0) return FALSE
;
506 if ((rop
& 0xcc0000) == ((rop
& 0x330000) << 2))
507 return PatBlt( hdcDest
, xDest
, yDest
, widthDest
, heightDest
, rop
);
509 /* don't stretch the bitmap unless we have to; if we don't,
510 * call BitBlt for a performance boost
513 if (widthSrc
== widthDest
&& heightSrc
== heightDest
) {
514 return BitBlt(hdcDest
, xDest
, yDest
, widthSrc
, heightSrc
,
515 hdcSrc
, xSrc
, ySrc
, rop
);
519 if ((rop
& 0x0f) != (rop
>> 4))
521 fprintf(stdnimp
, "StretchBlt: Unimplemented ROP %02lx\n", rop
);
525 dcSrc
= (DC
*) GDI_GetObjPtr( hdcSrc
, DC_MAGIC
);
526 if (!dcSrc
) return FALSE
;
527 dcDest
= (DC
*) GDI_GetObjPtr( hdcDest
, DC_MAGIC
);
530 dcDest
= (DC
*)GDI_GetObjPtr(hdcDest
, METAFILE_DC_MAGIC
);
531 if (!dcDest
) return FALSE
;
532 MF_StretchBlt(dcDest
, xDest
, yDest
, widthDest
, heightDest
,
533 hdcSrc
, xSrc
, ySrc
, widthSrc
, heightSrc
, saverop
);
537 xs1
= dcSrc
->w
.DCOrgX
+ XLPTODP( dcSrc
, xSrc
);
538 xs2
= dcSrc
->w
.DCOrgX
+ XLPTODP( dcSrc
, xSrc
+ widthSrc
);
539 ys1
= dcSrc
->w
.DCOrgY
+ YLPTODP( dcSrc
, ySrc
);
540 ys2
= dcSrc
->w
.DCOrgY
+ YLPTODP( dcSrc
, ySrc
+ heightSrc
);
541 xd1
= dcDest
->w
.DCOrgX
+ XLPTODP( dcDest
, xDest
);
542 xd2
= dcDest
->w
.DCOrgX
+ XLPTODP( dcDest
, xDest
+ widthDest
);
543 yd1
= dcDest
->w
.DCOrgY
+ YLPTODP( dcDest
, yDest
);
544 yd2
= dcDest
->w
.DCOrgY
+ YLPTODP( dcDest
, yDest
+ heightDest
);
547 /* get a source and destination image so we can manipulate
551 sxi
= BITBLT_GetImage( hdcSrc
, xs1
, ys1
, widthSrc
, heightSrc
);
552 dxi
= XCreateImage(display
, DefaultVisualOfScreen(screen
),
553 screenDepth
, ZPixmap
,
554 0, NULL
, widthDest
, heightDest
,
556 dxi
->data
= malloc(dxi
->bytes_per_line
* heightDest
);
558 stretchmode
= ((DC
*)GDI_GetObjPtr(hdcDest
, DC_MAGIC
))->w
.stretchBltMode
;
560 /* the actual stretching is done here, we'll try to use
561 * some interolation to get some speed out of it in
565 switch (stretchmode
) {
567 color_stretch(sxi
, dxi
, widthSrc
, heightSrc
,
568 widthDest
, heightDest
);
569 /* bonw_stretch(sxi, dxi, widthSrc, heightSrc,
570 widthDest, heightDest);
573 color_stretch(sxi
, dxi
, widthSrc
, heightSrc
,
574 widthDest
, heightDest
);
575 /* wonb_stretch(sxi, dxi, widthSrc, heightSrc,
576 widthDest, heightDest);
579 color_stretch(sxi
, dxi
, widthSrc
, heightSrc
,
580 widthDest
, heightDest
);
583 fprintf(stderr
, "StretchBlt: unknown stretchmode '%d'\n",
588 DC_SetupGCForText(dcDest
);
589 XSetFunction(display
, dcDest
->u
.x
.gc
, DC_XROPfunction
[rop
& 0x0f]);
590 XPutImage(display
, dcDest
->u
.x
.drawable
, dcDest
->u
.x
.gc
,
591 dxi
, 0, 0, min(xd1
,xd2
), min(yd1
,yd2
),
592 widthDest
, heightDest
);
594 /* now free the images we created */