Release 941122
[wine/multimedia.git] / objects / bitblt.c
blobfa58dad4ab3f10ad1d89ae0af6b91e2652e8d25e
1 /*
2 * GDI bit-blit operations
4 * Copyright 1993 Alexandre Julliard
5 */
7 static char Copyright[] = "Copyright Alexandre Julliard, 1993";
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <X11/Xlib.h>
12 #include <X11/Intrinsic.h>
14 #include "gdi.h"
15 #include "metafile.h"
16 #include "options.h"
17 #include "stddebug.h"
18 /* #define DEBUG_GDI */
19 /* #undef DEBUG_GDI */
20 #include "debug.h"
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 /***********************************************************************
30 * BITBLT_GetImage
32 static XImage *BITBLT_GetImage( HDC hdc, int x, int y, int width, int height )
34 XImage *image;
35 RECT rect;
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,
44 AllPlanes, ZPixmap );
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))
56 int x1, y1, x2, y2;
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 );
66 return image;
70 /***********************************************************************
71 * PatBlt (GDI.29)
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 );
77 if (!dc)
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));
83 return TRUE;
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 */
90 rop >>= 16;
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 );
100 rop = R2_COPYPEN;
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)
111 width = -width;
112 left -= width;
114 if ((height = (height * dc->w.VportExtY) / dc->w.WndExtY) < 0)
116 height = -height;
117 top -= height;
120 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
121 left, top, width, height );
122 return TRUE;
126 /***********************************************************************
127 * BitBlt (GDI.34)
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;
134 DWORD saverop = rop;
135 DC *dcDest, *dcSrc;
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 );
144 rop >>= 16;
146 dcSrc = (DC *) GDI_GetObjPtr( hdcSrc, DC_MAGIC );
147 if (!dcSrc) return FALSE;
148 dcDest = (DC *) GDI_GetObjPtr( hdcDest, DC_MAGIC );
149 if (!dcDest)
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);
155 return TRUE;
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) );
182 else
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 );
191 else
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;
196 long colors[256];
198 /* HDC hdcBrush = CreateCompatibleDC(hdcDest);
199 DC *dcBrush;*/
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++)
218 entry.pixel = 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);
231 if (s<256)
232 cs=colors[s];
233 else
235 sentry.pixel = s;
236 XQueryColor ( display, COLOR_WinColormap, &sentry);
237 cs = (int) RGB( sentry.red>>8,sentry.green>>8, sentry.blue>>8 );
239 if (d<256)
240 cd=colors[d];
241 else
243 dentry.pixel = d;
244 XQueryColor ( display, COLOR_WinColormap, &dentry);
245 cd = (int) RGB( dentry.red>>8, dentry.green>>8,dentry.blue>>8 );
247 if (p<256)
248 cp=colors[p];
249 else
251 pentry.pixel = p;
252 XQueryColor ( display, COLOR_WinColormap, &pentry);
253 cp = (int) RGB( pentry.red>>8, pentry.green>>8,pentry.blue>>8 );
255 cres = 0;
256 for(i=0; i<24; i++)
258 ofs=1<<(((cp>>i)&1)*4+((cs>>i)&1)*2+((cd>>i)&1));
259 if (rop & ofs)
260 cres |= (1<<i);
262 if (cres==cs)
263 res=s;
264 else if (cres==cd)
265 res=d;
266 else if (cres==cp)
267 res=p;
268 else
270 res = -1;
271 for (i=0; i<min(256,1<<(dcDest->w.bitsPerPixel)); i++)
272 if (colors[i]==cres)
274 res = i;
275 break;
277 if (res == -1)
278 res = GetNearestPaletteIndex(dcDest->w.hPalette, res);
280 XPutPixel(dxi, x, y, res);
284 else
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);
288 XDestroyImage(sxi);
289 XDestroyImage(dxi);
290 XDestroyImage(bxi);
291 /*DeleteDC(hdcBrush);*/
293 return TRUE;
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;
306 register int x, y;
307 Pixel whitep;
308 int totalx, totaly, xavgwhite, yavgwhite;
309 register int i;
310 int endx, endy;
312 deltax = (float)widthSrc/widthDest;
313 deltay = (float)heightSrc/heightDest;
314 whitep = WhitePixel(display, DefaultScreen(display));
316 oldsourcex = 0;
317 for (x=0, sourcex=0.0; x<widthDest;
318 x++, oldsourcex=sourcex, sourcex+=deltax) {
319 xavgwhite = 0;
320 if (deltax > 1.0) {
321 totalx = 0;
322 endx = (int)sourcex;
323 for (i=(int)oldsourcex; i<=endx; i++)
324 if (XGetPixel(sxi, i, (int)sourcey) == whitep)
325 totalx++;
326 xavgwhite = (totalx > (int)(deltax / 2.0));
327 } else {
328 xavgwhite = 0;
331 oldsourcey = 0;
332 for (y=0, sourcey=0.0; y<heightDest;
333 y++, oldsourcey=sourcey, sourcey+=deltay) {
334 yavgwhite = 0;
335 if (deltay > 1.0) {
336 totaly = 0;
337 endy = (int)sourcey;
338 for (i=(int)oldsourcey; i<=endy; i++)
339 if (XGetPixel(sxi, (int)sourcex, i) == whitep)
340 totaly++;
341 yavgwhite = (totaly > ((int)deltay / 2));
342 } else {
343 yavgwhite = 0;
345 if (xavgwhite && yavgwhite)
346 XPutPixel(dxi, x, y, whitep);
347 else
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;
363 register int x, y;
364 Pixel blackp;
365 int totalx, totaly, xavgblack, yavgblack;
366 register int i;
367 int endx, endy;
369 deltax = (float)widthSrc/widthDest;
370 deltay = (float)heightSrc/heightDest;
371 blackp = WhitePixel(display, DefaultScreen(display));
373 oldsourcex = 0;
374 for (x=0, sourcex=0.0; x<widthDest;
375 x++, oldsourcex=sourcex, sourcex+=deltax) {
376 xavgblack = 0;
377 if (deltax > 1.0) {
378 totalx = 0;
379 endx = (int)sourcex;
380 for (i=(int)oldsourcex; i<=endx; i++)
381 if (XGetPixel(sxi, i, (int)sourcey) == blackp)
382 totalx++;
383 xavgblack = (totalx > (int)(deltax / 2.0));
384 } else {
385 xavgblack = 0;
388 oldsourcey = 0;
389 for (y=0, sourcey=0.0; y<heightDest;
390 y++, oldsourcey=sourcey, sourcey+=deltay) {
391 yavgblack = 0;
392 if (deltay > 1.0) {
393 totaly = 0;
394 endy = (int)sourcey;
395 for (i=(int)oldsourcey; i<=endy; i++)
396 if (XGetPixel(sxi, (int)sourcex, i) == blackp)
397 totaly++;
398 yavgblack = (totaly > ((int)deltay / 2));
399 } else {
400 yavgblack = 0;
402 if (xavgblack && yavgblack)
403 XPutPixel(dxi, x, y, blackp);
404 else
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 */
419 #ifdef i386
420 int result;
421 __asm__(
422 "imull %%edx\n\t"
423 "idivl %3\n\t"
424 : "=&a" (result) /* out */
425 : "0" (m1), "d" (m2), "g" (d) /* in */
426 : "%edx" /* mod */
428 return result;
429 #else
430 return m1 * m2 / d;
431 #endif
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);
446 sy = 0;
448 for (y = 0; y < heightDest;)
450 int sourcey = sy >> 16;
451 sx = 0;
452 for (x = 0; x < widthDest; x++) {
453 XPutPixel(dxi, x, y, XGetPixel(sxi, sx >> 16, sourcey));
454 sx += xfactor;
456 y++;
457 while (y < heightDest) {
458 int py;
460 sourcey = sy >> 16;
461 sy += yfactor;
463 if ((sy >> 16) != sourcey)
464 break;
466 /* vertical stretch => copy previous line */
468 py = y - 1;
470 for (x = 0; x < widthDest; x++)
471 XPutPixel(dxi, x, y, XGetPixel(dxi, x, py));
472 y++;
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
484 * speed it up.
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;
493 DC *dcDest, *dcSrc;
494 XImage *sxi, *dxi;
495 DWORD saverop = rop;
496 WORD stretchmode;
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);
518 rop >>= 16;
519 if ((rop & 0x0f) != (rop >> 4))
521 fprintf(stdnimp, "StretchBlt: Unimplemented ROP %02lx\n", rop );
522 return FALSE;
525 dcSrc = (DC *) GDI_GetObjPtr( hdcSrc, DC_MAGIC );
526 if (!dcSrc) return FALSE;
527 dcDest = (DC *) GDI_GetObjPtr( hdcDest, DC_MAGIC );
528 if (!dcDest)
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);
534 return TRUE;
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
548 * the pixels
551 sxi = BITBLT_GetImage( hdcSrc, xs1, ys1, widthSrc, heightSrc );
552 dxi = XCreateImage(display, DefaultVisualOfScreen(screen),
553 screenDepth, ZPixmap,
554 0, NULL, widthDest, heightDest,
555 32, 0);
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
562 * the future
565 switch (stretchmode) {
566 case BLACKONWHITE:
567 color_stretch(sxi, dxi, widthSrc, heightSrc,
568 widthDest, heightDest);
569 /* bonw_stretch(sxi, dxi, widthSrc, heightSrc,
570 widthDest, heightDest);
571 */ break;
572 case WHITEONBLACK:
573 color_stretch(sxi, dxi, widthSrc, heightSrc,
574 widthDest, heightDest);
575 /* wonb_stretch(sxi, dxi, widthSrc, heightSrc,
576 widthDest, heightDest);
577 */ break;
578 case COLORONCOLOR:
579 color_stretch(sxi, dxi, widthSrc, heightSrc,
580 widthDest, heightDest);
581 break;
582 default:
583 fprintf(stderr, "StretchBlt: unknown stretchmode '%d'\n",
584 stretchmode);
585 break;
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 */
596 XDestroyImage(sxi);
597 XDestroyImage(dxi);
599 return TRUE;