DIB Engine: fixes against wine tests
[wine/hacks.git] / dlls / winedib.drv / bitblt.c
blob97feefdd96ee7ae20b3f210762b3eae9a2f6d904
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 */
112 if(dstClip)
114 /* extract destination clipping area */
115 xdc1 = dstClip->left;
116 ydc1 = dstClip->top;
117 xdc2 = dstClip->right;
118 ydc2 = dstClip->bottom;
120 /* order clip area rectangle points */
121 if(xdc1 > xdc2) intSwap(&xdc1, &xdc2);
122 if(ydc1 > ydc2) intSwap(&ydc1, &ydc2);
124 /* clip on dest clipping start point */
125 if(xd1 < xdc1) { dx = xdc1 - xd1; w -= dx; xs1 += dx; xd1 = xdc1; }
126 if(yd1 < ydc1) { dy = ydc1 - yd1; h -= dy; ys1 += dy; yd1 = ydc1; }
128 /* clip on dest clipping end point */
129 if(xd2 > xdc2) { dx = xd2 - xdc2; w -= dx; xs2 -= dx; xd2 = xdc2; }
130 if(yd2 > ydc2) { dy = yd2 - ydc2; h -= dy; ys2 -= dy; yd2 = ydc2; }
132 /* if already zero area, return false */
133 if(w <= 0 || h <= 0)
134 return FALSE;
137 /* sets clipped/translated points and sizes and returns TRUE */
138 ps->x = xs1; ps->y = ys1;
139 pd->x = xd1; pd->y = yd1;
140 sz->cx = w; sz->cy = h;
142 return TRUE;
147 /* clips a source and destination areas to their respective clip rectangles
148 returning both source and dest modified; result is TRUE if clipping
149 leads to a non null rectangle, FALSE otherwise */
150 static BOOL StretchBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *szSrc, SIZE *szDst, RECT*srcClip, RECT*dstClip)
152 int xs1, ys1, xs2, ys2;
153 int xsc1, ysc1, xsc2, ysc2;
154 int xd1, yd1, xd2, yd2;
155 int xdc1, ydc1, xdc2, ydc2;
156 int ws, hs, wd, hd, dx, dy;
157 int mulh, divh, mulv, divv;
159 /* extract sizes */
160 ws = szSrc->cx; hs = szSrc->cy;
161 wd = szDst->cx; hd = szDst->cy;
163 /* if sizes null or negative, just return false */
164 /* FIXME : add support for mirror stretch */
165 if(ws <= 0 || hs <= 0 || wd <= 0 || hd <= 0)
166 return FALSE;
168 /* stores scaling factors from source rect to dest one */
169 mulh = wd; divh = ws;
170 mulv = hd; divv = hs;
172 /* extract dest area data */
173 xd1 = pd->x;
174 yd1 = pd->y;
175 xd2 = xd1 + wd;
176 yd2 = yd1 + hd;
178 /* extract source data */
179 xs1 = ps->x;
180 ys1 = ps->y;
181 xs2 = xs1 + ws;
182 ys2 = ys1 + hs;
184 /* if source clip area is not null, do first clipping on it */
185 if(srcClip)
187 /* extract source clipping area */
188 xsc1 = srcClip->left;
189 ysc1 = srcClip->top;
190 xsc2 = srcClip->right;
191 ysc2 = srcClip->bottom;
193 /* order clip area rectangle points */
194 if(xsc1 > xsc2) intSwap(&xsc1, &xsc2);
195 if(ysc1 > ysc2) intSwap(&ysc1, &ysc2);
197 /* clip on source clipping start point */
198 if(xs1 < xsc1) { dx = xsc1 - xs1; ws -= dx; xd1 += MulDiv(dx, mulh, divh); xs1 = xsc1; }
199 if(ys1 < ysc1) { dy = ysc1 - ys1; hs -= dy; yd1 += MulDiv(dy, mulv, divv); ys1 = ysc1; }
201 /* clip on source clipping end point */
202 if(xs2 > xsc2) { dx = xs2 - xsc2; ws -= dx; xd2 -= MulDiv(dx, mulh, divh); xs2 = xsc2; }
203 if(ys2 > ysc2) { dy = ys2 - ysc2; hs -= dy; yd2 -= MulDiv(dy, mulv, divv); ys2 = ysc2; }
205 /* if already zero area, return false */
206 if(ws <= 0 || hs <= 0)
207 return FALSE;
208 wd = xd2 - xd1;
209 hd = yd2 - yd1;
211 /* now do clipping on destination area */
213 if(dstClip)
215 /* extract destination clipping area */
216 xdc1 = dstClip->left;
217 ydc1 = dstClip->top;
218 xdc2 = dstClip->right;
219 ydc2 = dstClip->bottom;
221 /* order clip area rectangle points */
222 if(xdc1 > xdc2) intSwap(&xdc1, &xdc2);
223 if(ydc1 > ydc2) intSwap(&ydc1, &ydc2);
225 /* clip on dest clipping start point */
226 if(xd1 < xdc1) { dx = xdc1 - xd1; wd -= dx; xs1 += MulDiv(dx, divh, mulh); xd1 = xdc1; }
227 if(yd1 < ydc1) { dy = ydc1 - yd1; hd -= dy; ys1 += MulDiv(dy, divv, mulv); yd1 = ydc1; }
229 /* clip on dest clipping end point */
230 if(xd2 > xdc2) { dx = xd2 - xdc2; wd -= dx; xs2 -= MulDiv(dx, divh, mulh); xd2 = xdc2; }
231 if(yd2 > ydc2) { dy = yd2 - ydc2; hd -= dy; ys2 -= MulDiv(dy, divv, mulv); yd2 = ydc2; }
233 /* if already zero area, return false */
234 if(wd <= 0 || hd <= 0)
235 return FALSE;
237 ws = xs2 - xs1;
238 hs = ys2 - ys1;
241 /* sets clipped/translated points and sizes and returns TRUE */
242 ps->x = xs1; ps->y = ys1;
243 pd->x = xd1; pd->y = yd1;
244 szSrc->cx = ws; szSrc->cy = hs;
245 szDst->cx = wd; szDst->cy = hd;
247 return TRUE;
251 /***********************************************************************
252 * _DIBDRV_InternalAlphaBlend
254 BOOL _DIBDRV_InternalAlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
255 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
256 BLENDFUNCTION blendfn)
258 BOOL res;
259 POINT pd, ps;
260 SIZE szSrc, szDst;
261 int iRec;
262 RECT dstClip, srcClip;
264 /* converts to device spaces */
265 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
266 _DIBDRV_Sizes_ws2ds(physDevDst, &widthDst, &heightDst);
267 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
268 _DIBDRV_Sizes_ws2ds(physDevSrc, &widthSrc, &heightSrc);
270 /* from tests, it seems that negative coords on phys space are not allowed */
271 if(xDst < 0 || yDst < 0 || xSrc < 0 || ySrc < 0)
273 SetLastError(ERROR_INVALID_PARAMETER);
274 return FALSE;
277 /* first clip on physical DC sizes */
278 setPoint(&pd, xDst, yDst);
279 setPoint(&ps, xSrc, ySrc);
280 setSize(&szDst, widthDst, heightDst);
281 setSize(&szSrc, widthSrc, heightSrc);
282 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
283 if(physDevSrc)
285 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
286 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
288 else
289 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
290 if(!res)
291 return TRUE;
292 xDst = pd.x; yDst = pd.y;
293 xSrc = ps.x; ySrc = ps.y;
294 widthDst = szDst.cx; heightDst = szDst.cy;
295 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
297 /* then, do blitting for each dest clip area (no clipping on source) */
298 res = FALSE;
299 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
301 RECT *r = physDevDst->regionRects + iRec;
302 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
303 setPoint(&pd, xDst, yDst);
304 setPoint(&ps, xSrc, ySrc);
305 setSize(&szDst, widthDst, heightDst);
306 setSize(&szSrc, widthSrc, heightSrc);
307 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
308 continue;
309 if(physDevDst->physBitmap.funcs->AlphaBlend(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
310 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, blendfn))
311 res = TRUE;
313 return res;
316 /***********************************************************************
317 * DIBDRV_AlphaBlend
319 BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
320 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
321 BLENDFUNCTION blendfn)
323 BOOL res;
325 POINT pd = {xDst, yDst};
326 SIZE szDst = {widthDst, heightDst};
328 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",
329 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
330 xDst, yDst, widthDst, heightDst,
331 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
332 xSrc, ySrc, widthSrc, heightSrc));
334 /* if sizes are null or negative, or source positions are negatives, returns false */
335 if(widthSrc <= 0 || heightSrc <= 0 ||
336 widthDst <= 0 || heightDst <= 0)
338 res = FALSE;
339 SetLastError(ERROR_INVALID_PARAMETER);
340 goto fin;
343 /* source sould be a 32 bit DIB */
344 if(!physDevSrc)
346 FIXME("Null source bitmap -- shouldn't happen\n");
347 res = FALSE;
348 goto fin;
350 else if(!physDevSrc->hasDIB)
352 FIXME("DDB source bitmap -- shouldn't happen\n");
353 res = FALSE;
354 goto fin;
357 if(physDevDst->hasDIB)
359 /* DIB section selected in dest DC, use DIB Engine */
360 MAYBE(TRACE("Blending DIB->DIB\n"));
361 res = _DIBDRV_InternalAlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst,
362 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
364 else
366 /* DDB selected on dest DC -- must double-convert */
367 HBITMAP tmpDIB, stock;
368 HDC tmpDC;
369 MAYBE(TRACE("Blending DIB->DDB\n"));
371 /* we should anyways convert dest to physical coordinates here before processing
372 in order to check its consistency -- source coords will be converted/clipped later
373 As we do a conversion to a temporary DIB for destination, we don't care about it */
374 _DIBDRV_Position_ws2ds(physDevDst, &pd.x, &pd.y);
375 _DIBDRV_Sizes_ws2ds(physDevDst, &szDst.cx, &szDst.cy);
377 /* test shows that negatives origins are not allowed */
378 if(pd.x < 0 || pd.y < 0)
380 SetLastError(ERROR_INVALID_PARAMETER);
381 res = FALSE;
382 goto fin;
385 /* converts dest DDB onto a temporary DIB -- just the needed part */
386 /* WARNING -- that one could fail if rectangle on dest id out of range */
387 tmpDIB = _DIBDRV_ConvertDevDDBtoDIB(physDevDst->hdc, physDevSrc->hdc, pd.x, pd.y, szDst.cx, szDst.cy);
388 if(!tmpDIB)
390 ERR("Couldn't convert dest DDB to DIB\n");
391 res = FALSE;
392 goto fin;
395 /* selects the temporary DIB into a temporary DC */
396 tmpDC = CreateCompatibleDC(physDevDst->hdc);
397 if(!tmpDC)
399 ERR("Couldn't create temporary DC\n");
400 DeleteObject(tmpDIB);
401 res = FALSE;
402 goto fin;
404 stock = SelectObject(tmpDC, tmpDIB);
405 if(!stock)
407 ERR("Couldn't select temporary DIB into temporary DC\n");
408 DeleteDC(tmpDC);
409 DeleteObject(tmpDIB);
410 res = FALSE;
411 goto fin;
414 /* blends source DIB onto temp DIB and re-blits onto dest DC */
415 res = GdiAlphaBlend(tmpDC, 0, 0, szDst.cx, szDst.cy, physDevSrc->hdc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
416 if(!res)
417 MAYBE(TRACE("AlphaBlend failed\n"));
418 else
419 res = BitBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, tmpDC, 0, 0, SRCCOPY);
421 /* frees resources */
422 SelectObject(tmpDC, stock);
423 DeleteDC(tmpDC);
424 DeleteObject(tmpDIB);
426 fin:
427 return res;
430 /***********************************************************************
431 * _DIBDRV_InternalBitBlt
433 BOOL _DIBDRV_InternalBitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
434 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
435 INT xSrc, INT ySrc, DWORD rop )
437 BOOL res;
438 POINT pd, ps;
439 SIZE sz;
440 int iRec;
441 RECT dstClip, srcClip;
443 /* converts to device spaces */
444 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
445 _DIBDRV_Sizes_ws2ds(physDevDst, &width, &height);
446 if(physDevSrc)
447 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
449 /* first clip on physical DC sizes */
450 setPoint(&pd, xDst, yDst);
451 setPoint(&ps, xSrc, ySrc);
452 setSize(&sz, width, height);
453 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
455 if(physDevSrc)
457 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
458 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, &dstClip);
460 else
461 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
462 if(!res)
463 return TRUE;
464 xDst = pd.x; yDst = pd.y;
465 xSrc = ps.x; ySrc = ps.y;
466 width = sz.cx; height = sz.cy;
468 /* then, do blitting for each dest clip area (no clipping on source) */
469 res = TRUE;
470 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
472 RECT *r = physDevDst->regionRects + iRec;
473 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
474 setPoint(&pd, xDst, yDst);
475 setPoint(&ps, xSrc, ySrc);
476 setSize(&sz, width, height);
477 if(!BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip))
478 continue;
479 if(!physDevDst->physBitmap.funcs->BitBlt(physDevDst, pd.x, pd.y, sz.cx, sz.cy, physDevSrc, ps.x, ps.y, rop))
480 res = FALSE;
482 return res;
485 /***********************************************************************
486 * DIBDRV_BitBlt */
487 BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
488 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
489 INT xSrc, INT ySrc, DWORD rop )
491 BOOL res;
493 /* clip blit area */
494 POINT pd = {xDst, yDst};
495 POINT ps = {xSrc, ySrc};
496 SIZE sz = {width, height};
498 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",
499 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
500 xDst, yDst, width, height,
501 physDevSrc, physDevSrc ? (physDevSrc->hasDIB ? "DIB-" : "DDB"): "---", physDevSrc && physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
502 xSrc, ySrc, rop));
504 if(physDevDst->hasDIB)
506 /* DIB section selected in dest DC, use DIB Engine */
507 /* clip blit area */
508 RECT dstClip = {0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height};
510 if(!physDevSrc || physDevSrc->hasDIB)
512 /* source is null or has a DIB, no need to convert anyting */
513 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, rop);
515 else
517 /* source is a DDB, must convert it to DIB */
519 /* don't clip on source */
520 res = !BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
521 if(res)
522 goto noBlt2;
523 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
525 /* we must differentiate from 2 cases :
526 1) source DC is a memory DC
527 2) source DC is a device DC */
528 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
530 /* memory DC */
531 HBITMAP dib, ddb;
533 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
534 if(!ddb)
536 ERR("Couldn't select out DDB from source HDC\n");
537 res = 0;
538 goto noBlt1;
540 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, height);
541 if(!dib)
543 ERR("Failed converting source DDB to DIB\n");
544 SelectObject(physDevSrc->hdc, ddb);
545 res = 0;
546 goto noBlt1;
548 SelectObject(physDevSrc->hdc, dib);
549 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, 0, rop);
550 SelectObject(physDevSrc->hdc, ddb);
551 DeleteObject(dib);
552 noBlt1:
555 else
557 /* device DC */
558 HBITMAP dib, stock;
559 HDC memHdc;
561 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, width, height);
562 if(!dib)
564 ERR("Failed converting source DDB tp DIB for device DC\n");
565 res = 0;
566 goto noBlt2;
568 memHdc = CreateCompatibleDC(physDevDst->hdc);
569 if(!memHdc)
571 ERR("Failed creating temporary memory DC\n");
572 DeleteObject(dib);
573 res = 0;
574 goto noBlt2;
576 stock = SelectObject(memHdc, dib);
577 if(!stock)
579 ERR("Failed selecting converted DIB into temporary memory DC\n");
580 DeleteObject(dib);
581 DeleteDC(memHdc);
582 res = 0;
583 goto noBlt2;
585 res = BitBlt(physDevDst->hdc, xDst, yDst, width, height, memHdc, 0, 0, rop);
587 SelectObject(memHdc, stock);
588 DeleteObject(dib);
589 DeleteDC(memHdc);
590 noBlt2:
595 else /* dest is a DDB */
597 /* DDB selected on dest DC, use X11 Driver */
598 if(!physDevSrc || !physDevSrc->hasDIB)
600 /* source is null or has also a DDB, no need to convert anything */
601 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
602 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, rop);
604 else
606 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
607 HBITMAP dib, ddb;
609 /* clip blit area */
610 if(physDevSrc)
612 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
613 res = !BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, 0);
615 else
616 res = FALSE;
617 if(res)
618 goto noBlt3;
619 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
621 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
622 if(!dib)
624 ERR("Couldn't select out DIB from source HDC\n");
625 res = 0;
626 goto noBlt3;
628 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, height);
629 if(!ddb)
631 ERR("Failed converting source DIB to DDB\n");
632 SelectObject(physDevSrc->hdc, dib);
633 res = 0;
634 goto noBlt3;
636 SelectObject(physDevSrc->hdc, ddb);
637 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
638 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, rop);
639 SelectObject(physDevSrc->hdc, dib);
640 DeleteObject(ddb);
641 noBlt3:
645 return res;
648 /***********************************************************************
649 * _DIBDRV_InternalStretchBlt
651 BOOL _DIBDRV_InternalStretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
652 INT widthDst, INT heightDst, DIBDRVPHYSDEV *physDevSrc,
653 INT xSrc, INT ySrc, int widthSrc, int heightSrc, DWORD rop )
655 BOOL res;
656 POINT pd, ps;
657 SIZE szSrc, szDst;
658 int iRec;
659 RECT dstClip, srcClip;
661 /* converts to device spaces */
662 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
663 _DIBDRV_Sizes_ws2ds(physDevDst, &widthDst, &heightDst);
664 if(physDevSrc)
666 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
667 _DIBDRV_Sizes_ws2ds(physDevSrc, &widthSrc, &heightSrc);
670 /* first clip on physical DC sizes */
671 setPoint(&pd, xDst, yDst);
672 setPoint(&ps, xSrc, ySrc);
673 setSize(&szDst, widthDst, heightDst);
674 setSize(&szSrc, widthSrc, heightSrc);
675 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
676 if(physDevSrc)
678 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
679 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
681 else
682 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
683 if(!res)
684 return FALSE;
685 xDst = pd.x; yDst = pd.y;
686 xSrc = ps.x; ySrc = ps.y;
687 widthDst = szDst.cx; heightDst = szDst.cy;
688 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
690 /* then, do blitting for each dest clip area (no clipping on source) */
691 res = FALSE;
692 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
694 RECT *r = physDevDst->regionRects + iRec;
695 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
696 setPoint(&pd, xDst, yDst);
697 setPoint(&ps, xSrc, ySrc);
698 setSize(&szDst, widthDst, heightDst);
699 setSize(&szSrc, widthSrc, heightSrc);
700 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
701 continue;
702 if(physDevDst->physBitmap.funcs->StretchBlt(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
703 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, rop))
704 res = TRUE;
706 return res;
709 /***********************************************************************
710 * DIBDRV_StretchBlt
712 BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
713 INT widthDst, INT heightDst,
714 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc,
715 INT widthSrc, INT heightSrc, DWORD rop )
717 BOOL res;
719 /* clip blit area */
720 POINT pd = {xDst, yDst};
721 POINT ps = {xSrc, ySrc};
722 SIZE szDst = {widthDst, heightDst};
723 SIZE szSrc = {widthSrc, heightSrc};
725 /* if source and dest sizes match, just call BitBlt(), it's faster */
726 if(!physDevSrc || (widthDst == widthSrc && heightDst == heightSrc))
727 return DIBDRV_BitBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, rop);
729 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",
730 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
731 xDst, yDst, widthDst, heightDst,
732 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
733 xSrc, ySrc, widthSrc, heightSrc, rop));
735 if(physDevDst->hasDIB)
737 /* DIB section selected in dest DC, use DIB Engine */
739 if(!physDevSrc || physDevSrc->hasDIB)
741 /* source is null or has a DIB, no need to convert anyting */
742 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop);
744 else
746 /* source is a DDB, must convert it to DIB */
748 /* we must differentiate from 2 cases :
749 1) source DC is a memory DC
750 2) source DC is a device DC */
751 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
753 /* memory DC */
754 HBITMAP dib, ddb;
756 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
757 if(!ddb)
759 ERR("Couldn't select out DDB from source HDC\n");
760 res = 0;
761 goto noBlt1;
763 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, heightSrc);
764 if(!dib)
766 ERR("Failed converting source DDB to DIB\n");
767 SelectObject(physDevSrc->hdc, ddb);
768 res = 0;
769 goto noBlt1;
771 SelectObject(physDevSrc->hdc, dib);
772 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst,
773 physDevSrc, xSrc, 0, widthSrc, heightSrc, rop);
774 SelectObject(physDevSrc->hdc, ddb);
775 DeleteObject(dib);
776 noBlt1:
779 else
781 /* device DC */
782 HBITMAP dib, stock;
783 HDC memHdc;
785 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, widthSrc, heightSrc);
786 if(!dib)
788 ERR("Failed converting source DDB tp DIB for device DC\n");
789 res = 0;
790 goto noBlt2;
792 memHdc = CreateCompatibleDC(physDevDst->hdc);
793 if(!memHdc)
795 ERR("Failed creating temporary memory DC\n");
796 DeleteObject(dib);
797 res = 0;
798 goto noBlt2;
800 stock = SelectObject(memHdc, dib);
801 if(!stock)
803 ERR("Failed selecting converted DIB into temporary memory DC\n");
804 DeleteObject(dib);
805 DeleteDC(memHdc);
806 res = 0;
807 goto noBlt2;
809 res = StretchBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, memHdc, 0, 0, widthSrc, widthDst, rop);
811 SelectObject(memHdc, stock);
812 DeleteObject(dib);
813 DeleteDC(memHdc);
814 noBlt2:
819 else /* dest is a DDB */
821 /* DDB selected on dest DC, use X11 Driver */
822 if(!physDevSrc || !physDevSrc->hasDIB)
824 /* source is null or has also a DDB, no need to convert anything */
825 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
826 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, widthSrc, heightSrc, rop);
828 else
830 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
831 HBITMAP dib, ddb;
833 /* clip blit area */
834 if(physDevSrc)
836 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
837 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, 0);
839 else
840 res = TRUE;
841 if(!res)
842 goto noBlt3;
843 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
844 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
846 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
847 if(!dib)
849 ERR("Couldn't select out DIB from source HDC\n");
850 res = 0;
851 goto noBlt3;
853 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, heightSrc);
854 if(!ddb)
856 ERR("Failed converting source DIB to DDB\n");
857 SelectObject(physDevSrc->hdc, dib);
858 res = 0;
859 goto noBlt3;
861 if(!SelectObject(physDevSrc->hdc, ddb))
863 ERR("Failed to select converted DDB into source HDC\n");
864 SelectObject(physDevSrc->hdc, dib);
865 DeleteObject(ddb);
866 res = 0;
867 goto noBlt3;
869 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
870 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, widthSrc, heightSrc, rop);
871 SelectObject(physDevSrc->hdc, dib);
872 DeleteObject(ddb);
873 noBlt3:
877 return res;
880 /***********************************************************************
881 * DIBDRV_PatBlt
883 BOOL DIBDRV_PatBlt( DIBDRVPHYSDEV *physDev, INT left, INT top, INT width, INT height, DWORD rop )
885 BOOL res;
887 MAYBE(TRACE("physDev:%p, left:%d, top:%d, width:%d, height:%d, rop:%06x\n", physDev, left, top, width, height, rop));
889 if(physDev->hasDIB)
891 /* DIB section selected in, use DIB Engine */
892 ONCE(FIXME("TEMPORARY - use BitBlt by now\n"));
893 res = DIBDRV_BitBlt(physDev, left, top, width, height, NULL, 0, 0, rop);
895 else
897 /* DDB selected in, use X11 driver */
898 res = _DIBDRV_GetDisplayDriver()->pPatBlt(physDev->X11PhysDev, left, top, width, height, rop);
900 return res;