Release 940510
[wine.git] / objects / bitblt.c
blob43023625bd850a824c4d8145d99033b43dd20c25
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"
16 extern const int DC_XROPfunction[];
18 #define MIN(a,b) ((a) < (b) ? (a) : (b))
19 #define MAX(a,b) ((a) > (b) ? (a) : (b))
22 /***********************************************************************
23 * PatBlt (GDI.29)
25 BOOL PatBlt( HDC hdc, short left, short top,
26 short width, short height, DWORD rop)
28 int x1, x2, y1, y2;
30 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
31 if (!dc) return FALSE;
32 #ifdef DEBUG_GDI
33 printf( "PatBlt: %d %d,%d %dx%d %06x\n",
34 hdc, left, top, width, height, rop );
35 #endif
37 rop >>= 16;
38 if (!DC_SetupGCForBrush( dc )) rop &= 0x0f;
39 else rop = (rop & 0x03) | ((rop >> 4) & 0x0c);
40 XSetFunction( XT_display, dc->u.x.gc, DC_XROPfunction[rop] );
42 x1 = dc->w.DCOrgX + XLPTODP( dc, left );
43 x2 = dc->w.DCOrgX + XLPTODP( dc, left + width );
44 y1 = dc->w.DCOrgY + YLPTODP( dc, top );
45 y2 = dc->w.DCOrgY + YLPTODP( dc, top + height );
46 XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc,
47 MIN(x1,x2), MIN(y1,y2), abs(x2-x1), abs(y2-y1) );
48 return TRUE;
52 /***********************************************************************
53 * BitBlt (GDI.34)
55 BOOL BitBlt( HDC hdcDest, short xDest, short yDest, short width, short height,
56 HDC hdcSrc, short xSrc, short ySrc, DWORD rop )
58 int xs1, xs2, ys1, ys2;
59 int xd1, xd2, yd1, yd2;
60 DC *dcDest, *dcSrc;
62 #ifdef DEBUG_GDI
63 printf( "BitBlt: %d %d,%d %dx%d %d %d,%d %08x\n",
64 hdcDest, xDest, yDest, width, height, hdcSrc, xSrc, ySrc, rop );
65 #endif
66 if (width == 0 || height == 0) return FALSE;
67 if ((rop & 0xcc0000) == ((rop & 0x330000) << 2))
68 return PatBlt( hdcDest, xDest, yDest, width, height, rop );
70 rop >>= 16;
71 if ((rop & 0x0f) != (rop >> 4))
73 printf( "BitBlt: Unimplemented ROP %02x\n", rop );
74 return FALSE;
77 dcDest = (DC *) GDI_GetObjPtr( hdcDest, DC_MAGIC );
78 if (!dcDest) return FALSE;
79 dcSrc = (DC *) GDI_GetObjPtr( hdcSrc, DC_MAGIC );
80 if (!dcSrc) return FALSE;
82 xs1 = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc );
83 xs2 = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc + width );
84 ys1 = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc );
85 ys2 = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc + height );
86 xd1 = dcDest->w.DCOrgX + XLPTODP( dcDest, xDest );
87 xd2 = dcDest->w.DCOrgX + XLPTODP( dcDest, xDest + width );
88 yd1 = dcDest->w.DCOrgY + YLPTODP( dcDest, yDest );
89 yd2 = dcDest->w.DCOrgY + YLPTODP( dcDest, yDest + height );
91 if ((abs(xs2-xs1) != abs(xd2-xd1)) || (abs(ys2-ys1) != abs(yd2-yd1)))
92 return FALSE; /* Should call StretchBlt here */
94 DC_SetupGCForText( dcDest );
95 XSetFunction( XT_display, dcDest->u.x.gc, DC_XROPfunction[rop & 0x0f] );
96 if (dcSrc->w.bitsPerPixel == dcDest->w.bitsPerPixel)
98 XCopyArea( XT_display, dcSrc->u.x.drawable,
99 dcDest->u.x.drawable, dcDest->u.x.gc,
100 MIN(xs1,xs2), MIN(ys1,ys2), abs(xs2-xs1), abs(ys2-ys1),
101 MIN(xd1,xd2), MIN(yd1,yd2) );
103 else
105 if (dcSrc->w.bitsPerPixel != 1) return FALSE;
106 XCopyPlane( XT_display, dcSrc->u.x.drawable,
107 dcDest->u.x.drawable, dcDest->u.x.gc,
108 MIN(xs1,xs2), MIN(ys1,ys2), abs(xs2-xs1), abs(ys2-ys1),
109 MIN(xd1,xd2), MIN(yd1,yd2), 1 );
111 return TRUE;
116 /***********************************************************************
117 * black on white stretch -- favors color pixels over white
120 static void bonw_stretch(XImage *sxi, XImage *dxi,
121 short widthSrc, short heightSrc, short widthDest, short heightDest)
123 float deltax, deltay, sourcex, sourcey, oldsourcex, oldsourcey;
124 register int x, y;
125 Pixel whitep;
126 int totalx, totaly, xavgwhite, yavgwhite;
127 register int i;
128 int endx, endy;
130 deltax = (float)widthSrc/widthDest;
131 deltay = (float)heightSrc/heightDest;
132 whitep = WhitePixel(display, DefaultScreen(display));
134 oldsourcex = 0;
135 for (x=0, sourcex=0.0; x<widthDest;
136 x++, oldsourcex=sourcex, sourcex+=deltax) {
137 xavgwhite = 0;
138 if (deltax > 1.0) {
139 totalx = 0;
140 endx = (int)sourcex;
141 for (i=(int)oldsourcex; i<=endx; i++)
142 if (XGetPixel(sxi, i, (int)sourcey) == whitep)
143 totalx++;
144 xavgwhite = (totalx > (int)(deltax / 2.0));
145 } else {
146 xavgwhite = 0;
149 oldsourcey = 0;
150 for (y=0, sourcey=0.0; y<heightDest;
151 y++, oldsourcey=sourcey, sourcey+=deltay) {
152 yavgwhite = 0;
153 if (deltay > 1.0) {
154 totaly = 0;
155 endy = (int)sourcey;
156 for (i=(int)oldsourcey; i<=endy; i++)
157 if (XGetPixel(sxi, (int)sourcex, i) == whitep)
158 totaly++;
159 yavgwhite = (totaly > ((int)deltay / 2));
160 } else {
161 yavgwhite = 0;
163 if (xavgwhite && yavgwhite)
164 XPutPixel(dxi, x, y, whitep);
165 else
166 XPutPixel(dxi, x, y, XGetPixel(sxi, (int)sourcex, (int)sourcey));
168 } /* for all y in dest */
169 } /* for all x in dest */
173 /***********************************************************************
174 * white on black stretch -- favors color pixels over black
177 static void wonb_stretch(XImage *sxi, XImage *dxi,
178 short widthSrc, short heightSrc, short widthDest, short heightDest)
180 float deltax, deltay, sourcex, sourcey, oldsourcex, oldsourcey;
181 register int x, y;
182 Pixel blackp;
183 int totalx, totaly, xavgblack, yavgblack;
184 register int i;
185 int endx, endy;
187 deltax = (float)widthSrc/widthDest;
188 deltay = (float)heightSrc/heightDest;
189 blackp = WhitePixel(display, DefaultScreen(display));
191 oldsourcex = 0;
192 for (x=0, sourcex=0.0; x<widthDest;
193 x++, oldsourcex=sourcex, sourcex+=deltax) {
194 xavgblack = 0;
195 if (deltax > 1.0) {
196 totalx = 0;
197 endx = (int)sourcex;
198 for (i=(int)oldsourcex; i<=endx; i++)
199 if (XGetPixel(sxi, i, (int)sourcey) == blackp)
200 totalx++;
201 xavgblack = (totalx > (int)(deltax / 2.0));
202 } else {
203 xavgblack = 0;
206 oldsourcey = 0;
207 for (y=0, sourcey=0.0; y<heightDest;
208 y++, oldsourcey=sourcey, sourcey+=deltay) {
209 yavgblack = 0;
210 if (deltay > 1.0) {
211 totaly = 0;
212 endy = (int)sourcey;
213 for (i=(int)oldsourcey; i<=endy; i++)
214 if (XGetPixel(sxi, (int)sourcex, i) == blackp)
215 totaly++;
216 yavgblack = (totaly > ((int)deltay / 2));
217 } else {
218 yavgblack = 0;
220 if (xavgblack && yavgblack)
221 XPutPixel(dxi, x, y, blackp);
222 else
223 XPutPixel(dxi, x, y, XGetPixel(sxi, (int)sourcex, (int)sourcey));
225 } /* for all y in dest */
226 } /* for all x in dest */
229 /* We use the 32-bit to 64-bit multiply and 64-bit to 32-bit divide of the */
230 /* 386 (which gcc doesn't know well enough) to efficiently perform integer */
231 /* scaling without having to worry about overflows. */
233 /* ##### muldiv64() borrowed from svgalib 1.03 ##### */
234 static inline int muldiv64( int m1, int m2, int d )
236 /* int32 * int32 -> int64 / int32 -> int32 */
237 #ifdef i386
238 int result;
239 __asm__(
240 "imull %%edx\n\t"
241 "idivl %3\n\t"
242 : "=a" (result) /* out */
243 : "a" (m1), "d" (m2), "g" (d) /* in */
244 : "ax", "dx" /* mod */
246 return result;
247 #else
248 return m1 * m2 / d;
249 #endif
252 /***********************************************************************
253 * color stretch -- deletes unused pixels
256 static void color_stretch(XImage *sxi, XImage *dxi,
257 short widthSrc, short heightSrc, short widthDest, short heightDest)
259 register int x, y, sx, sy, xfactor, yfactor;
261 xfactor = muldiv64(widthSrc, 65536, widthDest);
262 yfactor = muldiv64(heightSrc, 65536, heightDest);
264 sy = 0;
266 for (y = 0; y < heightDest;)
268 int sourcey = sy >> 16;
269 sx = 0;
270 for (x = 0; x < widthDest; x++) {
271 XPutPixel(dxi, x, y, XGetPixel(sxi, sx >> 16, sourcey));
272 sx += xfactor;
274 y++;
275 while (y < heightDest) {
276 int py;
278 sourcey = sy >> 16;
279 sy += yfactor;
281 if ((sy >> 16) != sourcey)
282 break;
284 /* vertical stretch => copy previous line */
286 py = y - 1;
288 for (x = 0; x < widthDest; x++)
289 XPutPixel(dxi, x, y, XGetPixel(dxi, x, py));
290 y++;
295 /***********************************************************************
296 * StretchBlt (GDI.35)
298 * o StretchBlt is CPU intensive so we only call it if we have
299 * to. Checks are made to see if we can call BitBlt instead.
301 * o the stretching is slowish, some integer interpolation would
302 * speed it up.
304 * o only black on white and color copy have been tested
306 BOOL StretchBlt( HDC hdcDest, short xDest, short yDest, short widthDest, short heightDest,
307 HDC hdcSrc, short xSrc, short ySrc, short widthSrc, short heightSrc, DWORD rop )
309 int xs1, xs2, ys1, ys2;
310 int xd1, xd2, yd1, yd2;
311 DC *dcDest, *dcSrc;
312 XImage *sxi, *dxi;
313 WORD stretchmode;
314 BOOL flg;
316 #ifdef DEBUG_GDI
317 fprintf(stderr, "StretchBlt: %d %d,%d %dx%d %d %d,%d %dx%d %08x\n",
318 hdcDest, xDest, yDest, widthDest, heightDest, hdcSrc, xSrc,
319 ySrc, widthSrc, heightSrc, rop );
320 printf("StretchMode is %x\n",
321 ((DC *)GDI_GetObjPtr(hdcDest, DC_MAGIC))->w.stretchBltMode);
322 #endif
324 if (widthDest == 0 || heightDest == 0) return FALSE;
325 if (widthSrc == 0 || heightSrc == 0) return FALSE;
326 if ((rop & 0xcc0000) == ((rop & 0x330000) << 2))
327 return PatBlt( hdcDest, xDest, yDest, widthDest, heightDest, rop );
329 /* don't stretch the bitmap unless we have to; if we don't,
330 * call BitBlt for a performance boost
333 if (widthSrc == widthDest && heightSrc == heightDest) {
334 return BitBlt(hdcDest, xDest, yDest, widthSrc, heightSrc,
335 hdcSrc, xSrc, ySrc, rop);
338 rop >>= 16;
339 if ((rop & 0x0f) != (rop >> 4))
341 printf( "StretchBlt: Unimplemented ROP %02x\n", rop );
342 return FALSE;
345 dcDest = (DC *) GDI_GetObjPtr( hdcDest, DC_MAGIC );
346 if (!dcDest) return FALSE;
347 dcSrc = (DC *) GDI_GetObjPtr( hdcSrc, DC_MAGIC );
348 if (!dcSrc) return FALSE;
350 xs1 = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc );
351 xs2 = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc + widthSrc );
352 ys1 = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc );
353 ys2 = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc + heightSrc );
354 xd1 = dcDest->w.DCOrgX + XLPTODP( dcDest, xDest );
355 xd2 = dcDest->w.DCOrgX + XLPTODP( dcDest, xDest + widthDest );
356 yd1 = dcDest->w.DCOrgY + YLPTODP( dcDest, yDest );
357 yd2 = dcDest->w.DCOrgY + YLPTODP( dcDest, yDest + heightDest );
360 /* get a source and destination image so we can manipulate
361 * the pixels
364 sxi = XGetImage(display, dcSrc->u.x.drawable, xs1, ys1,
365 widthSrc, heightSrc, AllPlanes, ZPixmap);
366 dxi = XCreateImage(display, DefaultVisualOfScreen(screen),
367 screenDepth, ZPixmap,
368 0, NULL, widthDest, heightDest,
369 32, 0);
370 dxi->data = malloc(dxi->bytes_per_line * heightDest);
372 stretchmode = ((DC *)GDI_GetObjPtr(hdcDest, DC_MAGIC))->w.stretchBltMode;
374 /* the actual stretching is done here, we'll try to use
375 * some interolation to get some speed out of it in
376 * the future
379 switch (stretchmode) {
380 case BLACKONWHITE:
381 color_stretch(sxi, dxi, widthSrc, heightSrc,
382 widthDest, heightDest);
383 /* bonw_stretch(sxi, dxi, widthSrc, heightSrc,
384 widthDest, heightDest);
385 */ break;
386 case WHITEONBLACK:
387 color_stretch(sxi, dxi, widthSrc, heightSrc,
388 widthDest, heightDest);
389 /* wonb_stretch(sxi, dxi, widthSrc, heightSrc,
390 widthDest, heightDest);
391 */ break;
392 case COLORONCOLOR:
393 color_stretch(sxi, dxi, widthSrc, heightSrc,
394 widthDest, heightDest);
395 break;
396 default:
397 fprintf(stderr, "StretchBlt: unknown stretchmode '%d'\n",
398 stretchmode);
399 break;
402 DC_SetupGCForText(dcDest);
403 XSetFunction(display, dcDest->u.x.gc, DC_XROPfunction[rop & 0x0f]);
404 XPutImage(display, dcDest->u.x.drawable, dcDest->u.x.gc,
405 dxi, 0, 0, MIN(xd1,xd2), MIN(yd1,yd2),
406 widthDest, heightDest);
408 /* now free the images we created */
410 XDestroyImage(sxi);
411 XDestroyImage(dxi);
413 return TRUE;