DIB Engine: Add clipping on xxxBlt and AlphaBlend
[wine/hacks.git] / dlls / winedib.drv / bitblt.c
blob05c9392e85c0442eb12f637d65a3b94fc3f773f9
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 static inline void setRect(RECT *r, int x1, int y1, int x2, int y2)
38 r->left = x1;
39 r->top = y1;
40 r->right = x2;
41 r->bottom = y2;
44 static inline void setPoint(POINT *p, int x, int y)
46 p->x = x;
47 p->y = y;
50 static inline void setSize(SIZE *sz, int cx, int cy)
52 sz->cx = cx;
53 sz->cy = cy;
56 /* clips a source and destination areas to their respective clip rectangles
57 returning both source and dest modified; result is TRUE if clipping
58 leads to a non null rectangle, FALSE otherwise */
59 static BOOL BitBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *sz, RECT*srcClip, RECT*dstClip)
61 int xs1, ys1, xs2, ys2;
62 int xsc1, ysc1, xsc2, ysc2;
63 int xd1, yd1, xd2, yd2;
64 int xdc1, ydc1, xdc2, ydc2;
65 int w, h, dx, dy;
67 /* extract sizes */
68 w = sz->cx; h = sz->cy;
70 /* if sizes null or negative, just return false */
71 if(w <= 0 || h <= 0)
72 return FALSE;
74 /* extract dest area data */
75 xd1 = pd->x;
76 yd1 = pd->y;
77 xd2 = xd1 + w;
78 yd2 = yd1 + h;
80 /* extract source data */
81 xs1 = ps->x;
82 ys1 = ps->y;
83 xs2 = xs1 + w;
84 ys2 = ys1 + h;
86 /* if source clip area is not null, do first clipping on it */
87 if(srcClip)
89 /* extract source clipping area */
90 xsc1 = srcClip->left;
91 ysc1 = srcClip->top;
92 xsc2 = srcClip->right;
93 ysc2 = srcClip->bottom;
95 /* order clip area rectangle points */
96 if(xsc1 > xsc2) intSwap(&xsc1, &xsc2);
97 if(ysc1 > ysc2) intSwap(&ysc1, &ysc2);
99 /* clip on source clipping start point */
100 if(xs1 < xsc1) { dx = xsc1 - xs1; w -= dx; xd1 += dx; xs1 = xsc1; }
101 if(ys1 < ysc1) { dy = ysc1 - ys1; h -= dy; yd1 += dy; ys1 = ysc1; }
103 /* clip on source clipping end point */
104 if(xs2 > xsc2) { dx = xs2 - xsc2; w -= dx; xd2 -= dx; xs2 = xsc2; }
105 if(ys2 > ysc2) { dy = ys2 - ysc2; h -= dy; yd2 -= dy; ys2 = ysc2; }
107 /* if already zero area, return false */
108 if(w <= 0 || h <= 0)
109 return FALSE;
111 /* now do clipping on destination area */
113 if(dstClip)
115 /* extract destination clipping area */
116 xdc1 = dstClip->left;
117 ydc1 = dstClip->top;
118 xdc2 = dstClip->right;
119 ydc2 = dstClip->bottom;
121 /* order clip area rectangle points */
122 if(xdc1 > xdc2) intSwap(&xdc1, &xdc2);
123 if(ydc1 > ydc2) intSwap(&ydc1, &ydc2);
125 /* clip on dest clipping start point */
126 if(xd1 < xdc1) { dx = xdc1 - xd1; w -= dx; xs1 += dx; xd1 = xdc1; }
127 if(yd1 < ydc1) { dy = ydc1 - yd1; h -= dy; ys1 += dy; yd1 = ydc1; }
129 /* clip on dest clipping end point */
130 if(xd2 > xdc2) { dx = xd2 - xdc2; w -= dx; xs2 -= dx; xd2 = xdc2; }
131 if(yd2 > ydc2) { dy = yd2 - ydc2; h -= dy; ys2 -= dy; yd2 = ydc2; }
133 /* if already zero area, return false */
134 if(w <= 0 || h <= 0)
135 return FALSE;
138 /* sets clipped/translated points and sizes and returns TRUE */
139 ps->x = xs1; ps->y = ys1;
140 pd->x = xd1; pd->y = yd1;
141 sz->cx = w; sz->cy = h;
143 return TRUE;
148 /* clips a source and destination areas to their respective clip rectangles
149 returning both source and dest modified; result is TRUE if clipping
150 leads to a non null rectangle, FALSE otherwise */
151 static BOOL StretchBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *szSrc, SIZE *szDst, RECT*srcClip, RECT*dstClip)
153 int xs1, ys1, xs2, ys2;
154 int xsc1, ysc1, xsc2, ysc2;
155 int xd1, yd1, xd2, yd2;
156 int xdc1, ydc1, xdc2, ydc2;
157 int ws, hs, wd, hd, dx, dy;
158 int mulh, divh, mulv, divv;
160 /* extract sizes */
161 ws = szSrc->cx; hs = szSrc->cy;
162 wd = szDst->cx; hd = szDst->cy;
164 /* if sizes null or negative, just return false */
165 /* FIXME : add support for mirror stretch */
166 if(ws <= 0 || hs <= 0 || wd <= 0 || hd <= 0)
167 return FALSE;
169 /* stores scaling factors from source rect to dest one */
170 mulh = wd; divh = ws;
171 mulv = hd; divv = hs;
173 /* extract dest area data */
174 xd1 = pd->x;
175 yd1 = pd->y;
176 xd2 = xd1 + wd;
177 yd2 = yd1 + hd;
179 /* extract source data */
180 xs1 = ps->x;
181 ys1 = ps->y;
182 xs2 = xs1 + ws;
183 ys2 = ys1 + hs;
185 /* if source clip area is not null, do first clipping on it */
186 if(srcClip)
188 /* extract source clipping area */
189 xsc1 = srcClip->left;
190 ysc1 = srcClip->top;
191 xsc2 = srcClip->right;
192 ysc2 = srcClip->bottom;
194 /* order clip area rectangle points */
195 if(xsc1 > xsc2) intSwap(&xsc1, &xsc2);
196 if(ysc1 > ysc2) intSwap(&ysc1, &ysc2);
198 /* clip on source clipping start point */
199 if(xs1 < xsc1) { dx = xsc1 - xs1; ws -= dx; xd1 += MulDiv(dx, mulh, divh); xs1 = xsc1; }
200 if(ys1 < ysc1) { dy = ysc1 - ys1; hs -= dy; yd1 += MulDiv(dy, mulv, divv); ys1 = ysc1; }
202 /* clip on source clipping end point */
203 if(xs2 > xsc2) { dx = xs2 - xsc2; ws -= dx; xd2 -= MulDiv(dx, mulh, divh); xs2 = xsc2; }
204 if(ys2 > ysc2) { dy = ys2 - ysc2; hs -= dy; yd2 -= MulDiv(dy, mulv, divv); ys2 = ysc2; }
206 /* if already zero area, return false */
207 if(ws <= 0 || hs <= 0)
208 return FALSE;
209 wd = xd2 - xd1;
210 hd = yd2 - yd1;
212 /* now do clipping on destination area */
214 if(dstClip)
216 /* extract destination clipping area */
217 xdc1 = dstClip->left;
218 ydc1 = dstClip->top;
219 xdc2 = dstClip->right;
220 ydc2 = dstClip->bottom;
222 /* order clip area rectangle points */
223 if(xdc1 > xdc2) intSwap(&xdc1, &xdc2);
224 if(ydc1 > ydc2) intSwap(&ydc1, &ydc2);
226 /* clip on dest clipping start point */
227 if(xd1 < xdc1) { dx = xdc1 - xd1; wd -= dx; xs1 += MulDiv(dx, divh, mulh); xd1 = xdc1; }
228 if(yd1 < ydc1) { dy = ydc1 - yd1; hd -= dy; ys1 += MulDiv(dy, divv, mulv); yd1 = ydc1; }
230 /* clip on dest clipping end point */
231 if(xd2 > xdc2) { dx = xd2 - xdc2; wd -= dx; xs2 -= MulDiv(dx, divh, mulh); xd2 = xdc2; }
232 if(yd2 > ydc2) { dy = yd2 - ydc2; hd -= dy; ys2 -= MulDiv(dy, divv, mulv); yd2 = ydc2; }
234 /* if already zero area, return false */
235 if(wd <= 0 || hd <= 0)
236 return FALSE;
238 ws = xs2 - xs1;
239 hs = ys2 - ys1;
242 /* sets clipped/translated points and sizes and returns TRUE */
243 ps->x = xs1; ps->y = ys1;
244 pd->x = xd1; pd->y = yd1;
245 szSrc->cx = ws; szSrc->cy = hs;
246 szDst->cx = wd; szDst->cy = hd;
248 return TRUE;
252 /***********************************************************************
253 * _DIBDRV_InternalAlphaBlend
255 BOOL _DIBDRV_InternalAlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
256 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
257 BLENDFUNCTION blendfn)
259 BOOL res;
260 POINT pd, ps;
261 SIZE szSrc, szDst;
262 int iRec;
263 RECT dstClip, srcClip;
265 /* first clip on physical DC sizes */
266 setPoint(&pd, xDst, yDst);
267 setPoint(&ps, xSrc, ySrc);
268 setSize(&szDst, widthDst, heightDst);
269 setSize(&szSrc, widthSrc, heightSrc);
270 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
271 if(physDevSrc)
273 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
274 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
276 else
277 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
278 if(!res)
279 return FALSE;
280 xDst = pd.x; yDst = pd.y;
281 xSrc = ps.x; ySrc = ps.y;
282 widthDst = szDst.cx; heightDst = szDst.cy;
283 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
285 /* then, do blitting for each dest clip area (no clipping on source) */
286 res = FALSE;
287 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
289 RECT *r = physDevDst->regionRects + iRec;
290 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
291 setPoint(&pd, xDst, yDst);
292 setPoint(&ps, xSrc, ySrc);
293 setSize(&szDst, widthDst, heightDst);
294 setSize(&szSrc, widthSrc, heightSrc);
295 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
296 continue;
297 if(physDevDst->physBitmap.funcs->AlphaBlend(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
298 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, blendfn))
299 res = TRUE;
301 return res;
304 /***********************************************************************
305 * DIBDRV_AlphaBlend
307 BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
308 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
309 BLENDFUNCTION blendfn)
311 BOOL res;
313 POINT pd = {xDst, yDst};
314 POINT ps = {xSrc, ySrc};
315 SIZE szDst = {widthDst, heightDst};
316 SIZE szSrc = {widthSrc, heightSrc};
318 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",
319 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
320 xDst, yDst, widthDst, heightDst,
321 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
322 xSrc, ySrc, widthSrc, heightSrc));
325 /* if sizes are null or negative, returns false */
326 if(widthSrc <= 0 || heightSrc <= 0 || widthDst <= 0 || heightDst <= 0)
328 res = FALSE;
329 goto fin;
332 /* source sould be a 32 bit DIB */
333 if(!physDevSrc)
335 FIXME("Null source bitmap -- shouldn't happen\n");
336 res = FALSE;
337 goto fin;
339 else if(!physDevSrc->hasDIB)
341 FIXME("DDB source bitmap -- shouldn't happen\n");
342 res = FALSE;
343 goto fin;
346 if(physDevDst->hasDIB)
348 /* DIB section selected in dest DC, use DIB Engine */
349 MAYBE(TRACE("Blending DIB->DIB\n"));
350 res = _DIBDRV_InternalAlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst,
351 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
353 else
355 /* DDB selected on dest DC -- must double-convert */
356 HBITMAP tmpDIB, stock;
357 HDC tmpDC;
358 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
359 MAYBE(TRACE("Blending DIB->DDB\n"));
361 /* clip blit area */
362 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, 0);
363 if(!res)
364 goto fin;
365 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
366 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
368 /* converts dest DDB onto a temporary DIB -- just the needed part */
369 tmpDIB = _DIBDRV_ConvertDevDDBtoDIB(physDevDst->hdc, physDevSrc->hdc, xDst, yDst, widthDst, heightDst);
370 if(!tmpDIB)
372 ERR("Couldn't convert dest DDB to DIB\n");
373 res = FALSE;
374 goto fin;
377 /* selects the temporary DIB into a temporary DC */
378 tmpDC = CreateCompatibleDC(physDevDst->hdc);
379 if(!tmpDC)
381 ERR("Couldn't create temporary DC\n");
382 DeleteObject(tmpDIB);
383 res = FALSE;
384 goto fin;
386 stock = SelectObject(tmpDC, tmpDIB);
387 if(!stock)
389 ERR("Couldn't select temporary DIB into temporary DC\n");
390 DeleteDC(tmpDC);
391 DeleteObject(tmpDIB);
392 res = FALSE;
393 goto fin;
396 /* blends source DIB onto temp DIB and re-blits onto dest DC */
397 res = GdiAlphaBlend(tmpDC, 0, 0, widthDst, heightDst, physDevSrc->hdc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
398 if(!res)
399 MAYBE(TRACE("AlphaBlend failed\n"));
400 else
401 res = BitBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, tmpDC, 0, 0, SRCCOPY);
403 /* frees resources */
404 SelectObject(tmpDC, stock);
405 DeleteDC(tmpDC);
406 DeleteObject(tmpDIB);
408 fin:
409 return res;
412 /***********************************************************************
413 * _DIBDRV_InternalBitBlt
415 BOOL _DIBDRV_InternalBitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
416 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
417 INT xSrc, INT ySrc, DWORD rop )
419 BOOL res;
420 POINT pd, ps;
421 SIZE sz;
422 int iRec;
423 RECT dstClip, srcClip;
425 /* first clip on physical DC sizes */
426 setPoint(&pd, xDst, yDst);
427 setPoint(&ps, xSrc, ySrc);
428 setSize(&sz, width, height);
429 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
430 if(physDevSrc)
432 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
433 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, &dstClip);
435 else
436 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
437 if(!res)
438 return FALSE;
439 xDst = pd.x; yDst = pd.y;
440 xSrc = ps.x; ySrc = ps.y;
441 width = sz.cx; height = sz.cy;
443 /* then, do blitting for each dest clip area (no clipping on source) */
444 res = FALSE;
445 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
447 RECT *r = physDevDst->regionRects + iRec;
448 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
449 setPoint(&pd, xDst, yDst);
450 setPoint(&ps, xSrc, ySrc);
451 setSize(&sz, width, height);
452 if(!BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip))
453 continue;
454 if(physDevDst->physBitmap.funcs->BitBlt(physDevDst, pd.x, pd.y, sz.cx, sz.cy, physDevSrc, ps.x, ps.y, rop))
455 res = TRUE;
457 return res;
460 /***********************************************************************
461 * DIBDRV_BitBlt */
462 BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
463 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
464 INT xSrc, INT ySrc, DWORD rop )
466 BOOL res;
468 /* clip blit area */
469 POINT pd = {xDst, yDst};
470 POINT ps = {xSrc, ySrc};
471 SIZE sz = {width, height};
473 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",
474 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
475 xDst, yDst, width, height,
476 physDevSrc, physDevSrc ? (physDevSrc->hasDIB ? "DIB-" : "DDB"): "---", physDevSrc && physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
477 xSrc, ySrc, rop));
479 if(physDevDst->hasDIB)
481 /* DIB section selected in dest DC, use DIB Engine */
482 /* clip blit area */
483 RECT dstClip = {0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height};
485 if(!physDevSrc || physDevSrc->hasDIB)
487 /* source is null or has a DIB, no need to convert anyting */
488 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, rop);
490 else
492 /* source is a DDB, must convert it to DIB */
494 /* don't clip on source */
495 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
496 if(!res)
497 goto noBlt2;
498 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
500 /* we must differentiate from 2 cases :
501 1) source DC is a memory DC
502 2) source DC is a device DC */
503 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
505 /* memory DC */
506 HBITMAP dib, ddb;
508 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
509 if(!ddb)
511 ERR("Couldn't select out DDB from source HDC\n");
512 res = 0;
513 goto noBlt1;
515 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, height);
516 if(!dib)
518 ERR("Failed converting source DDB to DIB\n");
519 SelectObject(physDevSrc->hdc, ddb);
520 res = 0;
521 goto noBlt1;
523 SelectObject(physDevSrc->hdc, dib);
524 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, 0, rop);
525 SelectObject(physDevSrc->hdc, ddb);
526 DeleteObject(dib);
527 noBlt1:
530 else
532 /* device DC */
533 HBITMAP dib, stock;
534 HDC memHdc;
536 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, width, height);
537 if(!dib)
539 ERR("Failed converting source DDB tp DIB for device DC\n");
540 res = 0;
541 goto noBlt2;
543 memHdc = CreateCompatibleDC(physDevDst->hdc);
544 if(!memHdc)
546 ERR("Failed creating temporary memory DC\n");
547 DeleteObject(dib);
548 res = 0;
549 goto noBlt2;
551 stock = SelectObject(memHdc, dib);
552 if(!stock)
554 ERR("Failed selecting converted DIB into temporary memory DC\n");
555 DeleteObject(dib);
556 DeleteDC(memHdc);
557 res = 0;
558 goto noBlt2;
560 res = BitBlt(physDevDst->hdc, xDst, yDst, width, height, memHdc, 0, 0, rop);
562 SelectObject(memHdc, stock);
563 DeleteObject(dib);
564 DeleteDC(memHdc);
565 noBlt2:
570 else /* dest is a DDB */
572 /* DDB selected on dest DC, use X11 Driver */
573 if(!physDevSrc || !physDevSrc->hasDIB)
575 /* source is null or has also a DDB, no need to convert anything */
576 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
577 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, rop);
579 else
581 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
582 HBITMAP dib, ddb;
584 /* clip blit area */
585 if(physDevSrc)
587 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
588 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, 0);
590 else
591 res = TRUE;
592 if(!res)
593 goto noBlt3;
594 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
596 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
597 if(!dib)
599 ERR("Couldn't select out DIB from source HDC\n");
600 res = 0;
601 goto noBlt3;
603 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, height);
604 if(!ddb)
606 ERR("Failed converting source DIB to DDB\n");
607 SelectObject(physDevSrc->hdc, dib);
608 res = 0;
609 goto noBlt3;
611 SelectObject(physDevSrc->hdc, ddb);
612 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
613 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, rop);
614 SelectObject(physDevSrc->hdc, dib);
615 DeleteObject(ddb);
616 noBlt3:
620 return res;
623 /***********************************************************************
624 * _DIBDRV_InternalStretchBlt
626 BOOL _DIBDRV_InternalStretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
627 INT widthDst, INT heightDst, DIBDRVPHYSDEV *physDevSrc,
628 INT xSrc, INT ySrc, int widthSrc, int heightSrc, DWORD rop )
630 BOOL res;
631 POINT pd, ps;
632 SIZE szSrc, szDst;
633 int iRec;
634 RECT dstClip, srcClip;
636 /* first clip on physical DC sizes */
637 setPoint(&pd, xDst, yDst);
638 setPoint(&ps, xSrc, ySrc);
639 setSize(&szDst, widthDst, heightDst);
640 setSize(&szSrc, widthSrc, heightSrc);
641 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
642 if(physDevSrc)
644 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
645 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
647 else
648 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
649 if(!res)
650 return FALSE;
651 xDst = pd.x; yDst = pd.y;
652 xSrc = ps.x; ySrc = ps.y;
653 widthDst = szDst.cx; heightDst = szDst.cy;
654 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
656 /* then, do blitting for each dest clip area (no clipping on source) */
657 res = FALSE;
658 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
660 RECT *r = physDevDst->regionRects + iRec;
661 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
662 setPoint(&pd, xDst, yDst);
663 setPoint(&ps, xSrc, ySrc);
664 setSize(&szDst, widthDst, heightDst);
665 setSize(&szSrc, widthSrc, heightSrc);
666 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
667 continue;
668 if(physDevDst->physBitmap.funcs->StretchBlt(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
669 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, rop))
670 res = TRUE;
672 return res;
675 /***********************************************************************
676 * DIBDRV_StretchBlt
678 BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
679 INT widthDst, INT heightDst,
680 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc,
681 INT widthSrc, INT heightSrc, DWORD rop )
683 BOOL res;
685 /* clip blit area */
686 POINT pd = {xDst, yDst};
687 POINT ps = {xSrc, ySrc};
688 SIZE szDst = {widthDst, heightDst};
689 SIZE szSrc = {widthSrc, heightSrc};
691 /* if source and dest sizes match, just call BitBlt(), it's faster */
692 if(!physDevSrc || (widthDst == widthSrc && heightDst == heightSrc))
693 return DIBDRV_BitBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, rop);
695 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",
696 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
697 xDst, yDst, widthDst, heightDst,
698 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
699 xSrc, ySrc, widthSrc, heightSrc, rop));
701 if(physDevDst->hasDIB)
703 /* DIB section selected in dest DC, use DIB Engine */
705 if(!physDevSrc || physDevSrc->hasDIB)
707 /* source is null or has a DIB, no need to convert anyting */
708 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop);
710 else
712 /* source is a DDB, must convert it to DIB */
714 /* we must differentiate from 2 cases :
715 1) source DC is a memory DC
716 2) source DC is a device DC */
717 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
719 /* memory DC */
720 HBITMAP dib, ddb;
722 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
723 if(!ddb)
725 ERR("Couldn't select out DDB from source HDC\n");
726 res = 0;
727 goto noBlt1;
729 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, heightSrc);
730 if(!dib)
732 ERR("Failed converting source DDB to DIB\n");
733 SelectObject(physDevSrc->hdc, ddb);
734 res = 0;
735 goto noBlt1;
737 SelectObject(physDevSrc->hdc, dib);
738 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst,
739 physDevSrc, xSrc, 0, widthSrc, heightSrc, rop);
740 SelectObject(physDevSrc->hdc, ddb);
741 DeleteObject(dib);
742 noBlt1:
745 else
747 /* device DC */
748 HBITMAP dib, stock;
749 HDC memHdc;
751 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, widthSrc, heightSrc);
752 if(!dib)
754 ERR("Failed converting source DDB tp DIB for device DC\n");
755 res = 0;
756 goto noBlt2;
758 memHdc = CreateCompatibleDC(physDevDst->hdc);
759 if(!memHdc)
761 ERR("Failed creating temporary memory DC\n");
762 DeleteObject(dib);
763 res = 0;
764 goto noBlt2;
766 stock = SelectObject(memHdc, dib);
767 if(!stock)
769 ERR("Failed selecting converted DIB into temporary memory DC\n");
770 DeleteObject(dib);
771 DeleteDC(memHdc);
772 res = 0;
773 goto noBlt2;
775 res = StretchBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, memHdc, 0, 0, widthSrc, widthDst, rop);
777 SelectObject(memHdc, stock);
778 DeleteObject(dib);
779 DeleteDC(memHdc);
780 noBlt2:
785 else /* dest is a DDB */
787 /* DDB selected on dest DC, use X11 Driver */
788 if(!physDevSrc || !physDevSrc->hasDIB)
790 /* source is null or has also a DDB, no need to convert anything */
791 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
792 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, widthSrc, heightSrc, rop);
794 else
796 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
797 HBITMAP dib, ddb;
799 /* clip blit area */
800 if(physDevSrc)
802 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
803 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, 0);
805 else
806 res = TRUE;
807 if(!res)
808 goto noBlt3;
809 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
810 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
812 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
813 if(!dib)
815 ERR("Couldn't select out DIB from source HDC\n");
816 res = 0;
817 goto noBlt3;
819 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, heightSrc);
820 if(!ddb)
822 ERR("Failed converting source DIB to DDB\n");
823 SelectObject(physDevSrc->hdc, dib);
824 res = 0;
825 goto noBlt3;
827 if(!SelectObject(physDevSrc->hdc, ddb))
829 ERR("Failed to select converted DDB into source HDC\n");
830 SelectObject(physDevSrc->hdc, dib);
831 DeleteObject(ddb);
832 res = 0;
833 goto noBlt3;
835 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
836 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, widthSrc, heightSrc, rop);
837 SelectObject(physDevSrc->hdc, dib);
838 DeleteObject(ddb);
839 noBlt3:
843 return res;
846 /***********************************************************************
847 * DIBDRV_PatBlt
849 BOOL DIBDRV_PatBlt( DIBDRVPHYSDEV *physDev, INT left, INT top, INT width, INT height, DWORD rop )
851 BOOL res;
853 MAYBE(TRACE("physDev:%p, left:%d, top:%d, width:%d, height:%d, rop:%06x\n", physDev, left, top, width, height, rop));
855 if(physDev->hasDIB)
857 /* DIB section selected in, use DIB Engine */
858 ONCE(FIXME("TEMPORARY - use BitBlt by now\n"));
859 res = DIBDRV_BitBlt(physDev, left, top, width, height, NULL, 0, 0, rop);
861 else
863 /* DDB selected in, use X11 driver */
864 res = _DIBDRV_GetDisplayDriver()->pPatBlt(physDev->X11PhysDev, left, top, width, height, rop);
866 return res;