20cdcaa6cdd49abd91bee189cfe72da5d138e659
[wine/hacks.git] / dlls / winedib.drv / bitblt.c
blob20cdcaa6cdd49abd91bee189cfe72da5d138e659
1 /*
2 * DIBDRV bit-blit operations
4 * Copyright 2009 Massimo Del Fedele
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include "dibdrv.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dibdrv);
28 static inline void intSwap(int *a, int *b)
30 int tmp;
31 tmp = *a;
32 *a = *b;
33 *b = tmp;
36 /* clips a source and destination areas to their respective clip rectangles
37 returning both source and dest modified; result is TRUE if clipping
38 leads to a non null rectangle, FALSE otherwise */
39 static BOOL BitBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *sz, RECT*srcClip, RECT*dstClip)
41 int xs1, ys1, xs2, ys2;
42 int xsc1, ysc1, xsc2, ysc2;
43 int xd1, yd1, xd2, yd2;
44 int xdc1, ydc1, xdc2, ydc2;
45 int w, h, dx, dy;
47 /* extract sizes */
48 w = sz->cx; h = sz->cy;
50 /* if sizes null or negative, just return false */
51 if(w <= 0 || h <= 0)
52 return FALSE;
54 /* extract dest area data */
55 xd1 = pd->x;
56 yd1 = pd->y;
57 xd2 = xd1 + w;
58 yd2 = yd1 + h;
60 /* extract source data */
61 xs1 = ps->x;
62 ys1 = ps->y;
63 xs2 = xs1 + w;
64 ys2 = ys1 + h;
66 /* if source clip area is not null, do first clipping on it */
67 if(srcClip)
69 /* extract source clipping area */
70 xsc1 = srcClip->left;
71 ysc1 = srcClip->top;
72 xsc2 = srcClip->right;
73 ysc2 = srcClip->bottom;
75 /* order clip area rectangle points */
76 if(xsc1 > xsc2) intSwap(&xsc1, &xsc2);
77 if(ysc1 > ysc2) intSwap(&ysc1, &ysc2);
79 /* clip on source clipping start point */
80 if(xs1 < xsc1) { dx = xsc1 - xs1; w -= dx; xd1 += dx; xs1 = xsc1; }
81 if(ys1 < ysc1) { dy = ysc1 - ys1; h -= dy; yd1 += dy; ys1 = ysc1; }
83 /* clip on source clipping end point */
84 if(xs2 > xsc2) { dx = xs2 - xsc2; w -= dx; xd2 -= dx; xs2 = xsc2; }
85 if(ys2 > ysc2) { dy = ys2 - ysc2; h -= dy; yd2 -= dy; ys2 = ysc2; }
87 /* if already zero area, return false */
88 if(w <= 0 || h <= 0)
89 return FALSE;
91 /* now do clipping on destination area */
93 if(dstClip)
95 /* extract destination clipping area */
96 xdc1 = dstClip->left;
97 ydc1 = dstClip->top;
98 xdc2 = dstClip->right;
99 ydc2 = dstClip->bottom;
101 /* order clip area rectangle points */
102 if(xdc1 > xdc2) intSwap(&xdc1, &xdc2);
103 if(ydc1 > ydc2) intSwap(&ydc1, &ydc2);
105 /* clip on dest clipping start point */
106 if(xd1 < xdc1) { dx = xdc1 - xd1; w -= dx; xs1 += dx; xd1 = xdc1; }
107 if(yd1 < ydc1) { dy = ydc1 - yd1; h -= dy; ys1 += dy; yd1 = ydc1; }
109 /* clip on dest clipping end point */
110 if(xd2 > xdc2) { dx = xd2 - xdc2; w -= dx; xs2 -= dx; xd2 = xdc2; }
111 if(yd2 > ydc2) { dy = yd2 - ydc2; h -= dy; ys2 -= dy; yd2 = ydc2; }
113 /* if already zero area, return false */
114 if(w <= 0 || h <= 0)
115 return FALSE;
118 /* sets clipped/translated points and sizes and returns TRUE */
119 ps->x = xs1; ps->y = ys1;
120 pd->x = xd1; pd->y = yd1;
121 sz->cx = w; sz->cy = h;
123 return TRUE;
128 /* clips a source and destination areas to their respective clip rectangles
129 returning both source and dest modified; result is TRUE if clipping
130 leads to a non null rectangle, FALSE otherwise */
131 static BOOL StretchBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *szSrc, SIZE *szDst, RECT*srcClip, RECT*dstClip)
133 ONCE(FIXME("TO DO\n"));
135 return TRUE;
139 /***********************************************************************
140 * DIBDRV_AlphaBlend
142 BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
143 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
144 BLENDFUNCTION blendfn)
146 BOOL res;
148 MAYBE(TRACE("physDevDst:%p(%s%s), xDst:%d, yDst:%d, widthDst:%d, heightDst:%d, physDevSrc:%p(%s%s), xSrc:%d, ySrc:%d, widthSrc:%d, heightSrc:%d\n",
149 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
150 xDst, yDst, widthDst, heightDst,
151 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
152 xSrc, ySrc, widthSrc, heightSrc));
154 if(physDevDst->hasDIB && physDevSrc->hasDIB)
156 /* DIB section selected in both source and dest DC, use DIB Engine */
157 ONCE(FIXME("STUB\n"));
158 res = TRUE;
160 else if(!physDevDst->hasDIB && !physDevSrc->hasDIB)
162 /* DDB selected in noth source and dest DC, use X11 driver */
163 res = _DIBDRV_GetDisplayDriver()->pAlphaBlend(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
164 physDevSrc->X11PhysDev, xSrc, ySrc, widthSrc, heightSrc,
165 blendfn);
167 else if(physDevSrc->hasDIB)
169 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
170 ONCE(FIXME("TEMPORARY - fallback to X11 driver\n"));
171 res = _DIBDRV_GetDisplayDriver()->pAlphaBlend(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
172 physDevSrc->X11PhysDev, xSrc, ySrc, widthSrc, heightSrc,
173 blendfn);
175 else /* if(physDevDst->hasDIB) */
177 /* DDB on source, DIB on dest -- must convert source DDB to DIB and use the engine for blit */
178 ONCE(FIXME("STUB\n"));
179 res = TRUE;
181 return res;
184 /***********************************************************************
185 * DIBDRV_BitBlt
187 BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
188 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
189 INT xSrc, INT ySrc, DWORD rop )
191 BOOL res;
193 /* clip blit area */
194 POINT pd = {xDst, yDst};
195 POINT ps = {xSrc, ySrc};
196 SIZE sz = {width, height};
198 MAYBE(TRACE("physDevDst:%p(%s%s), xDst:%d, yDst:%d, width:%d, height:%d, physDevSrc:%p(%s%s), xSrc:%d, ySrc:%d, rop:%08x\n",
199 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
200 xDst, yDst, width, height,
201 physDevSrc, physDevSrc ? (physDevSrc->hasDIB ? "DIB-" : "DDB"): "---", physDevSrc && physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
202 xSrc, ySrc, rop));
204 if(physDevDst->hasDIB)
206 /* DIB section selected in dest DC, use DIB Engine */
208 /* clip blit area */
209 RECT dstClip = {0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height};
211 if(!physDevSrc || physDevSrc->hasDIB)
213 /* clip blit area */
214 if(physDevSrc)
216 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
217 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, &dstClip);
219 else
220 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
221 if(!res)
222 goto noBlt2;
223 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
225 /* source is null or has a DIB, no need to convert anyting */
226 res = physDevDst->physBitmap.funcs->BitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, rop);
228 else
230 /* source is a DDB, must convert it to DIB */
232 /* don't clip on source */
233 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
234 if(!res)
235 goto noBlt2;
236 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
238 /* we must differentiate from 2 cases :
239 1) source DC is a memory DC
240 2) source DC is a device DC */
241 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
243 /* memory DC */
244 HBITMAP dib, ddb;
246 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
247 if(!ddb)
249 ERR("Couldn't select out DDB from source HDC\n");
250 res = 0;
251 goto noBlt1;
253 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, height);
254 if(!dib)
256 ERR("Failed converting source DDB to DIB\n");
257 SelectObject(physDevSrc->hdc, ddb);
258 res = 0;
259 goto noBlt1;
261 SelectObject(physDevSrc->hdc, dib);
262 res = physDevDst->physBitmap.funcs->BitBlt(physDevDst, xDst, yDst, width, height,
263 physDevSrc, xSrc, 0, rop);
264 SelectObject(physDevSrc->hdc, ddb);
265 DeleteObject(dib);
266 noBlt1:
269 else
271 /* device DC */
272 HBITMAP dib, stock;
273 HDC memHdc;
275 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, width, height);
276 if(!dib)
278 ERR("Failed converting source DDB tp DIB for device DC\n");
279 res = 0;
280 goto noBlt2;
282 memHdc = CreateCompatibleDC(physDevDst->hdc);
283 if(!memHdc)
285 ERR("Failed creating temporary memory DC\n");
286 DeleteObject(dib);
287 res = 0;
288 goto noBlt2;
290 stock = SelectObject(memHdc, dib);
291 if(!stock)
293 ERR("Failed selecting converted DIB into temporary memory DC\n");
294 DeleteObject(dib);
295 DeleteDC(memHdc);
296 res = 0;
297 goto noBlt2;
299 res = BitBlt(physDevDst->hdc, xDst, yDst, width, height, memHdc, 0, 0, rop);
301 SelectObject(memHdc, stock);
302 DeleteObject(dib);
303 DeleteDC(memHdc);
304 noBlt2:
309 else /* dest is a DDB */
311 /* DDB selected on dest DC, use X11 Driver */
312 if(!physDevSrc || !physDevSrc->hasDIB)
314 /* source is null or has also a DDB, no need to convert anything */
315 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
316 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, rop);
318 else
320 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
321 HBITMAP dib, ddb;
323 /* clip blit area */
324 if(physDevSrc)
326 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
327 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, 0);
329 else
330 res = TRUE;
331 if(!res)
332 goto noBlt3;
333 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
335 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
336 if(!dib)
338 ERR("Couldn't select out DIB from source HDC\n");
339 res = 0;
340 goto noBlt3;
342 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, height);
343 if(!ddb)
345 ERR("Failed converting source DIB to DDB\n");
346 SelectObject(physDevSrc->hdc, dib);
347 res = 0;
348 goto noBlt3;
350 SelectObject(physDevSrc->hdc, ddb);
351 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
352 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, rop);
353 SelectObject(physDevSrc->hdc, dib);
354 DeleteObject(ddb);
355 noBlt3:
359 return res;
362 /***********************************************************************
363 * DIBDRV_StretchBlt
365 BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
366 INT widthDst, INT heightDst,
367 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc,
368 INT widthSrc, INT heightSrc, DWORD rop )
370 BOOL res;
372 /* clip blit area */
373 POINT pd = {xDst, yDst};
374 POINT ps = {xSrc, ySrc};
375 SIZE szDst = {widthDst, heightDst};
376 SIZE szSrc = {widthSrc, heightSrc};
378 /* if source and dest sizes match, just call BitBlt(), it's faster */
379 if(!physDevSrc || (widthDst == widthSrc && heightDst == heightSrc))
380 return DIBDRV_BitBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, rop);
382 MAYBE(TRACE("physDevDst:%p(%s%s), xDst:%d, yDst:%d, widthDst:%d, heightDst:%d, physDevSrc:%p(%s%s), xSrc:%d, ySrc:%d, widthSrc:%d, heightSrc:%d, rop:%08x\n",
383 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
384 xDst, yDst, widthDst, heightDst,
385 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
386 xSrc, ySrc, widthSrc, heightSrc, rop));
388 if(physDevDst->hasDIB)
390 /* DIB section selected in dest DC, use DIB Engine */
392 /* clip blit area */
393 RECT dstClip = {0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height};
395 if(!physDevSrc || physDevSrc->hasDIB)
397 /* clip blit area */
398 if(physDevSrc)
400 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
401 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
403 else
404 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
405 if(!res)
406 goto noBlt2;
407 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
408 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
410 /* source is null or has a DIB, no need to convert anyting */
411 res = physDevDst->physBitmap.funcs->StretchBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop);
413 else
415 /* source is a DDB, must convert it to DIB */
417 /* don't clip on source */
418 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
419 if(!res)
420 goto noBlt2;
421 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
422 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
424 /* we must differentiate from 2 cases :
425 1) source DC is a memory DC
426 2) source DC is a device DC */
427 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
429 /* memory DC */
430 HBITMAP dib, ddb;
432 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
433 if(!ddb)
435 ERR("Couldn't select out DDB from source HDC\n");
436 res = 0;
437 goto noBlt1;
439 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, heightSrc);
440 if(!dib)
442 ERR("Failed converting source DDB to DIB\n");
443 SelectObject(physDevSrc->hdc, ddb);
444 res = 0;
445 goto noBlt1;
447 SelectObject(physDevSrc->hdc, dib);
448 res = physDevDst->physBitmap.funcs->StretchBlt(physDevDst, xDst, yDst, widthDst, heightDst,
449 physDevSrc, xSrc, 0, widthSrc, heightSrc, rop);
450 SelectObject(physDevSrc->hdc, ddb);
451 DeleteObject(dib);
452 noBlt1:
455 else
457 /* device DC */
458 HBITMAP dib, stock;
459 HDC memHdc;
461 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, widthSrc, heightSrc);
462 if(!dib)
464 ERR("Failed converting source DDB tp DIB for device DC\n");
465 res = 0;
466 goto noBlt2;
468 memHdc = CreateCompatibleDC(physDevDst->hdc);
469 if(!memHdc)
471 ERR("Failed creating temporary memory DC\n");
472 DeleteObject(dib);
473 res = 0;
474 goto noBlt2;
476 stock = SelectObject(memHdc, dib);
477 if(!stock)
479 ERR("Failed selecting converted DIB into temporary memory DC\n");
480 DeleteObject(dib);
481 DeleteDC(memHdc);
482 res = 0;
483 goto noBlt2;
485 res = StretchBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, memHdc, 0, 0, widthSrc, widthDst, rop);
487 SelectObject(memHdc, stock);
488 DeleteObject(dib);
489 DeleteDC(memHdc);
490 noBlt2:
495 else /* dest is a DDB */
497 /* DDB selected on dest DC, use X11 Driver */
498 if(!physDevSrc || !physDevSrc->hasDIB)
500 /* source is null or has also a DDB, no need to convert anything */
501 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
502 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, widthSrc, heightSrc, rop);
504 else
506 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
507 HBITMAP dib, ddb;
509 /* clip blit area */
510 if(physDevSrc)
512 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
513 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, 0);
515 else
516 res = TRUE;
517 if(!res)
518 goto noBlt3;
519 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
520 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
522 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
523 if(!dib)
525 ERR("Couldn't select out DIB from source HDC\n");
526 res = 0;
527 goto noBlt3;
529 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, heightSrc);
530 if(!ddb)
532 ERR("Failed converting source DIB to DDB\n");
533 SelectObject(physDevSrc->hdc, dib);
534 res = 0;
535 goto noBlt3;
537 if(!SelectObject(physDevSrc->hdc, ddb))
539 ERR("Failed to select converted DDB into source HDC\n");
540 SelectObject(physDevSrc->hdc, dib);
541 DeleteObject(ddb);
542 res = 0;
543 goto noBlt3;
545 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
546 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, widthSrc, heightSrc, rop);
547 SelectObject(physDevSrc->hdc, dib);
548 DeleteObject(ddb);
549 noBlt3:
553 return res;
556 /***********************************************************************
557 * DIBDRV_PatBlt
559 BOOL DIBDRV_PatBlt( DIBDRVPHYSDEV *physDev, INT left, INT top, INT width, INT height, DWORD rop )
561 BOOL res;
563 MAYBE(TRACE("physDev:%p, left:%d, top:%d, width:%d, height:%d, rop:%06x\n", physDev, left, top, width, height, rop));
565 if(physDev->hasDIB)
567 /* DIB section selected in, use DIB Engine */
568 ONCE(FIXME("TEMPORARY - use BitBlt by now\n"));
569 res = DIBDRV_BitBlt(physDev, left, top, width, height, NULL, 0, 0, rop);
571 else
573 /* DDB selected in, use X11 driver */
574 res = _DIBDRV_GetDisplayDriver()->pPatBlt(physDev->X11PhysDev, left, top, width, height, rop);
576 return res;