Release 940505
[wine/testsucceed.git] / objects / bitblt.c
blob24f05e09d9a3a49bf7141ec28c9c36202c442228
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
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;
315 #ifdef DEBUG_GDI
316 fprintf(stderr, "StretchBlt: %d %d,%d %dx%d %d %d,%d %dx%d %08x\n",
317 hdcDest, xDest, yDest, widthDest, heightDest, hdcSrc, xSrc,
318 ySrc, widthSrc, heightSrc, rop );
319 printf("StretchMode is %x\n",
320 ((DC *)GDI_GetObjPtr(hdcDest, DC_MAGIC))->w.stretchBltMode);
321 #endif
323 if ((rop & 0xcc0000) == ((rop & 0x330000) << 2))
324 return PatBlt( hdcDest, xDest, yDest, widthDest, heightDest, rop );
326 /* don't stretch the bitmap unless we have to; if we don't,
327 * call BitBlt for a performance boost
330 if (widthSrc == widthDest && heightSrc == heightDest) {
331 return BitBlt(hdcDest, xDest, yDest, widthSrc, heightSrc,
332 hdcSrc, xSrc, ySrc, rop);
335 rop >>= 16;
336 if ((rop & 0x0f) != (rop >> 4))
338 printf( "StretchBlt: Unimplemented ROP %02x\n", rop );
339 return FALSE;
342 dcDest = (DC *) GDI_GetObjPtr( hdcDest, DC_MAGIC );
343 if (!dcDest) return FALSE;
344 dcSrc = (DC *) GDI_GetObjPtr( hdcSrc, DC_MAGIC );
345 if (!dcSrc) return FALSE;
347 xs1 = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc );
348 xs2 = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc + widthSrc );
349 ys1 = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc );
350 ys2 = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc + heightSrc );
351 xd1 = dcDest->w.DCOrgX + XLPTODP( dcDest, xDest );
352 xd2 = dcDest->w.DCOrgX + XLPTODP( dcDest, xDest + widthDest );
353 yd1 = dcDest->w.DCOrgY + YLPTODP( dcDest, yDest );
354 yd2 = dcDest->w.DCOrgY + YLPTODP( dcDest, yDest + heightDest );
357 /* get a source and destination image so we can manipulate
358 * the pixels
361 sxi = XGetImage(display, dcSrc->u.x.drawable, xs1, ys1,
362 widthSrc, heightSrc, AllPlanes, ZPixmap);
363 dxi = XCreateImage(display, DefaultVisualOfScreen(screen),
364 screenDepth, ZPixmap,
365 0, NULL, widthDest, heightDest,
366 32, 0);
367 dxi->data = malloc(dxi->bytes_per_line * heightDest);
369 stretchmode = ((DC *)GDI_GetObjPtr(hdcDest, DC_MAGIC))->w.stretchBltMode;
371 /* the actual stretching is done here, we'll try to use
372 * some interolation to get some speed out of it in
373 * the future
376 switch (stretchmode) {
377 case BLACKONWHITE:
378 color_stretch(sxi, dxi, widthSrc, heightSrc,
379 widthDest, heightDest);
380 /* bonw_stretch(sxi, dxi, widthSrc, heightSrc,
381 widthDest, heightDest);
382 */ break;
383 case WHITEONBLACK:
384 color_stretch(sxi, dxi, widthSrc, heightSrc,
385 widthDest, heightDest);
386 /* wonb_stretch(sxi, dxi, widthSrc, heightSrc,
387 widthDest, heightDest);
388 */ break;
389 case COLORONCOLOR:
390 color_stretch(sxi, dxi, widthSrc, heightSrc,
391 widthDest, heightDest);
392 break;
393 default:
394 fprintf(stderr, "StretchBlt: unknown stretchmode '%d'\n",
395 stretchmode);
396 break;
399 DC_SetupGCForText(dcDest);
400 XSetFunction(display, dcDest->u.x.gc, DC_XROPfunction[rop & 0x0f]);
401 XPutImage(display, dcDest->u.x.drawable, dcDest->u.x.gc,
402 dxi, 0, 0, MIN(xd1,xd2), MIN(yd1,yd2),
403 widthDest, heightDest);
405 /* now free the images we created */
407 XDestroyImage(sxi);
408 XDestroyImage(dxi);
410 return TRUE;