DIB Engine: introduction of bitmaplist structure
[wine/hacks.git] / dlls / winedib.drv / bitblt.c
blobb5b70f7c904306a36d042cb3fe0517084903c42f
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 coords out of phys spaces are not allowed */
271 if(xDst < 0 || yDst < 0 || xSrc < 0 || ySrc < 0 ||
272 xDst + widthDst > physDevDst->physBitmap->width ||
273 yDst + heightDst > physDevDst->physBitmap->height ||
274 xSrc + widthSrc > physDevSrc->physBitmap->width ||
275 ySrc + heightSrc > physDevSrc->physBitmap->height)
277 SetLastError(ERROR_INVALID_PARAMETER);
278 return FALSE;
281 /* first clip on physical DC sizes */
282 setPoint(&pd, xDst, yDst);
283 setPoint(&ps, xSrc, ySrc);
284 setSize(&szDst, widthDst, heightDst);
285 setSize(&szSrc, widthSrc, heightSrc);
286 setRect(&dstClip, 0, 0, physDevDst->physBitmap->width, physDevDst->physBitmap->height);
287 if(physDevSrc)
289 setRect(&srcClip, 0, 0, physDevSrc->physBitmap->width, physDevSrc->physBitmap->height);
290 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
292 else
293 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
294 if(!res)
295 return TRUE;
296 xDst = pd.x; yDst = pd.y;
297 xSrc = ps.x; ySrc = ps.y;
298 widthDst = szDst.cx; heightDst = szDst.cy;
299 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
301 /* then, do blitting for each dest clip area (no clipping on source) */
302 res = FALSE;
303 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
305 RECT *r = physDevDst->regionRects + iRec;
306 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
307 setPoint(&pd, xDst, yDst);
308 setPoint(&ps, xSrc, ySrc);
309 setSize(&szDst, widthDst, heightDst);
310 setSize(&szSrc, widthSrc, heightSrc);
311 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
312 continue;
313 if(physDevDst->physBitmap->funcs->AlphaBlend(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
314 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, blendfn))
315 res = TRUE;
317 return res;
320 /***********************************************************************
321 * DIBDRV_AlphaBlend
323 BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
324 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
325 BLENDFUNCTION blendfn)
327 BOOL res;
329 POINT pd = {xDst, yDst};
330 SIZE szDst = {widthDst, heightDst};
332 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",
333 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevDst->physBitmap) : "",
334 xDst, yDst, widthDst, heightDst,
335 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevSrc->physBitmap) : "",
336 xSrc, ySrc, widthSrc, heightSrc));
338 /* if sizes are null or negative, or source positions are negatives, returns false */
339 if(widthSrc <= 0 || heightSrc <= 0 ||
340 widthDst <= 0 || heightDst <= 0)
342 res = FALSE;
343 SetLastError(ERROR_INVALID_PARAMETER);
344 goto fin;
347 /* source sould be a 32 bit DIB */
348 if(!physDevSrc)
350 FIXME("Null source bitmap -- shouldn't happen\n");
351 res = FALSE;
352 goto fin;
354 else if(!physDevSrc->hasDIB)
356 FIXME("DDB source bitmap still not supported\n");
357 res = FALSE;
358 goto fin;
361 if(physDevDst->hasDIB)
363 /* DIB section selected in dest DC, use DIB Engine */
364 MAYBE(TRACE("Blending DIB->DIB\n"));
365 res = _DIBDRV_InternalAlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst,
366 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
368 else
370 /* DDB selected on dest DC -- must double-convert */
371 HBITMAP tmpDIB, stock;
372 HDC tmpDC;
373 MAYBE(TRACE("Blending DIB->DDB\n"));
375 /* we should anyways convert dest to physical coordinates here before processing
376 in order to check its consistency -- source coords will be converted/clipped later
377 As we do a conversion to a temporary DIB for destination, we don't care about it */
378 _DIBDRV_Position_ws2ds(physDevDst, &pd.x, &pd.y);
379 _DIBDRV_Sizes_ws2ds(physDevDst, &szDst.cx, &szDst.cy);
381 /* test shows that negatives origins are not allowed */
382 if(pd.x < 0 || pd.y < 0)
384 SetLastError(ERROR_INVALID_PARAMETER);
385 res = FALSE;
386 goto fin;
389 /* converts dest DDB onto a temporary DIB -- just the needed part */
390 /* WARNING -- that one could fail if rectangle on dest id out of range */
391 tmpDIB = _DIBDRV_ConvertDevDDBtoDIB(physDevDst->hdc, physDevSrc->hdc, pd.x, pd.y, szDst.cx, szDst.cy);
392 if(!tmpDIB)
394 ERR("Couldn't convert dest DDB to DIB\n");
395 res = FALSE;
396 goto fin;
399 /* selects the temporary DIB into a temporary DC */
400 tmpDC = CreateCompatibleDC(physDevDst->hdc);
401 if(!tmpDC)
403 ERR("Couldn't create temporary DC\n");
404 DeleteObject(tmpDIB);
405 res = FALSE;
406 goto fin;
408 stock = SelectObject(tmpDC, tmpDIB);
409 if(!stock)
411 ERR("Couldn't select temporary DIB into temporary DC\n");
412 DeleteDC(tmpDC);
413 DeleteObject(tmpDIB);
414 res = FALSE;
415 goto fin;
418 /* blends source DIB onto temp DIB and re-blits onto dest DC */
419 res = GdiAlphaBlend(tmpDC, 0, 0, szDst.cx, szDst.cy, physDevSrc->hdc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
420 if(!res)
421 MAYBE(TRACE("AlphaBlend failed\n"));
422 else
423 res = BitBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, tmpDC, 0, 0, SRCCOPY);
425 /* frees resources */
426 SelectObject(tmpDC, stock);
427 DeleteDC(tmpDC);
428 DeleteObject(tmpDIB);
430 fin:
431 return res;
434 /***********************************************************************
435 * _DIBDRV_InternalBitBlt
437 BOOL _DIBDRV_InternalBitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
438 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
439 INT xSrc, INT ySrc, DWORD rop )
441 BOOL res;
442 POINT pd, ps;
443 SIZE sz;
444 int iRec;
445 RECT dstClip, srcClip;
447 /* converts to device spaces */
448 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
449 _DIBDRV_Sizes_ws2ds(physDevDst, &width, &height);
450 if(physDevSrc)
451 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
453 /* first clip on physical DC sizes */
454 setPoint(&pd, xDst, yDst);
455 setPoint(&ps, xSrc, ySrc);
456 setSize(&sz, width, height);
457 setRect(&dstClip, 0, 0, physDevDst->physBitmap->width, physDevDst->physBitmap->height);
459 if(physDevSrc)
461 setRect(&srcClip, 0, 0, physDevSrc->physBitmap->width, physDevSrc->physBitmap->height);
462 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, &dstClip);
464 else
465 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
466 if(!res)
467 return TRUE;
468 xDst = pd.x; yDst = pd.y;
469 xSrc = ps.x; ySrc = ps.y;
470 width = sz.cx; height = sz.cy;
472 /* then, do blitting for each dest clip area (no clipping on source) */
473 res = TRUE;
474 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
476 RECT *r = physDevDst->regionRects + iRec;
477 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
478 setPoint(&pd, xDst, yDst);
479 setPoint(&ps, xSrc, ySrc);
480 setSize(&sz, width, height);
481 if(!BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip))
482 continue;
483 if(!physDevDst->physBitmap->funcs->BitBlt(physDevDst, pd.x, pd.y, sz.cx, sz.cy, physDevSrc, ps.x, ps.y, rop))
484 res = FALSE;
486 return res;
489 /***********************************************************************
490 * DIBDRV_BitBlt */
491 BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
492 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
493 INT xSrc, INT ySrc, DWORD rop )
495 BOOL res;
497 /* clip blit area */
498 POINT pd = {xDst, yDst};
499 POINT ps = {xSrc, ySrc};
500 SIZE sz = {width, height};
502 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",
503 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevDst->physBitmap) : "",
504 xDst, yDst, width, height,
505 physDevSrc, physDevSrc ? (physDevSrc->hasDIB ? "DIB-" : "DDB"): "---", physDevSrc && physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevSrc->physBitmap) : "",
506 xSrc, ySrc, rop));
508 if(physDevDst->hasDIB)
510 /* DIB section selected in dest DC, use DIB Engine */
511 /* clip blit area */
512 RECT dstClip = {0, 0, physDevDst->physBitmap->width, physDevDst->physBitmap->height};
514 if(!physDevSrc || physDevSrc->hasDIB)
516 /* source is null or has a DIB, no need to convert anyting */
517 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, rop);
519 else
521 /* source is a DDB, must convert it to DIB */
523 /* don't clip on source */
524 res = !BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
525 if(res)
526 goto noBlt2;
527 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
529 /* we must differentiate from 2 cases :
530 1) source DC is a memory DC
531 2) source DC is a device DC */
532 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
534 /* memory DC */
535 HBITMAP dib, ddb;
537 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
538 if(!ddb)
540 ERR("Couldn't select out DDB from source HDC\n");
541 res = 0;
542 goto noBlt1;
544 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, height);
545 if(!dib)
547 ERR("Failed converting source DDB to DIB\n");
548 SelectObject(physDevSrc->hdc, ddb);
549 res = 0;
550 goto noBlt1;
552 SelectObject(physDevSrc->hdc, dib);
553 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, 0, rop);
554 SelectObject(physDevSrc->hdc, ddb);
555 DeleteObject(dib);
556 noBlt1:
559 else
561 /* device DC */
562 HBITMAP dib, stock;
563 HDC memHdc;
565 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, width, height);
566 if(!dib)
568 ERR("Failed converting source DDB tp DIB for device DC\n");
569 res = 0;
570 goto noBlt2;
572 memHdc = CreateCompatibleDC(physDevDst->hdc);
573 if(!memHdc)
575 ERR("Failed creating temporary memory DC\n");
576 DeleteObject(dib);
577 res = 0;
578 goto noBlt2;
580 stock = SelectObject(memHdc, dib);
581 if(!stock)
583 ERR("Failed selecting converted DIB into temporary memory DC\n");
584 DeleteObject(dib);
585 DeleteDC(memHdc);
586 res = 0;
587 goto noBlt2;
589 res = BitBlt(physDevDst->hdc, xDst, yDst, width, height, memHdc, 0, 0, rop);
591 SelectObject(memHdc, stock);
592 DeleteObject(dib);
593 DeleteDC(memHdc);
594 noBlt2:
599 else /* dest is a DDB */
601 /* DDB selected on dest DC, use X11 Driver */
602 if(!physDevSrc || !physDevSrc->hasDIB)
604 /* source is null or has also a DDB, no need to convert anything */
605 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
606 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, rop);
608 else
610 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
611 HBITMAP dib, ddb;
613 /* clip blit area */
614 if(physDevSrc)
616 RECT srcClip = {0, 0, physDevSrc->physBitmap->width, physDevSrc->physBitmap->height};
617 res = !BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, 0);
619 else
620 res = FALSE;
621 if(res)
622 goto noBlt3;
623 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
625 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
626 if(!dib)
628 ERR("Couldn't select out DIB from source HDC\n");
629 res = 0;
630 goto noBlt3;
632 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, height);
633 if(!ddb)
635 ERR("Failed converting source DIB to DDB\n");
636 SelectObject(physDevSrc->hdc, dib);
637 res = 0;
638 goto noBlt3;
640 SelectObject(physDevSrc->hdc, ddb);
641 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
642 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, rop);
643 SelectObject(physDevSrc->hdc, dib);
644 DeleteObject(ddb);
645 noBlt3:
649 return res;
652 /***********************************************************************
653 * _DIBDRV_InternalStretchBlt
655 BOOL _DIBDRV_InternalStretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
656 INT widthDst, INT heightDst, DIBDRVPHYSDEV *physDevSrc,
657 INT xSrc, INT ySrc, int widthSrc, int heightSrc, DWORD rop )
659 BOOL res;
660 POINT pd, ps;
661 SIZE szSrc, szDst;
662 int iRec;
663 RECT dstClip, srcClip;
665 /* converts to device spaces */
666 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
667 _DIBDRV_Sizes_ws2ds(physDevDst, &widthDst, &heightDst);
668 if(physDevSrc)
670 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
671 _DIBDRV_Sizes_ws2ds(physDevSrc, &widthSrc, &heightSrc);
674 /* first clip on physical DC sizes */
675 setPoint(&pd, xDst, yDst);
676 setPoint(&ps, xSrc, ySrc);
677 setSize(&szDst, widthDst, heightDst);
678 setSize(&szSrc, widthSrc, heightSrc);
679 setRect(&dstClip, 0, 0, physDevDst->physBitmap->width, physDevDst->physBitmap->height);
680 if(physDevSrc)
682 setRect(&srcClip, 0, 0, physDevSrc->physBitmap->width, physDevSrc->physBitmap->height);
683 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
685 else
686 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
687 if(!res)
688 return FALSE;
689 xDst = pd.x; yDst = pd.y;
690 xSrc = ps.x; ySrc = ps.y;
691 widthDst = szDst.cx; heightDst = szDst.cy;
692 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
694 /* then, do blitting for each dest clip area (no clipping on source) */
695 res = FALSE;
696 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
698 RECT *r = physDevDst->regionRects + iRec;
699 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
700 setPoint(&pd, xDst, yDst);
701 setPoint(&ps, xSrc, ySrc);
702 setSize(&szDst, widthDst, heightDst);
703 setSize(&szSrc, widthSrc, heightSrc);
704 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
705 continue;
706 if(physDevDst->physBitmap->funcs->StretchBlt(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
707 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, rop))
708 res = TRUE;
710 return res;
713 /***********************************************************************
714 * DIBDRV_StretchBlt
716 BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
717 INT widthDst, INT heightDst,
718 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc,
719 INT widthSrc, INT heightSrc, DWORD rop )
721 BOOL res;
723 /* clip blit area */
724 POINT pd = {xDst, yDst};
725 POINT ps = {xSrc, ySrc};
726 SIZE szDst = {widthDst, heightDst};
727 SIZE szSrc = {widthSrc, heightSrc};
729 /* if source and dest sizes match, just call BitBlt(), it's faster */
730 if(!physDevSrc || (widthDst == widthSrc && heightDst == heightSrc))
731 return DIBDRV_BitBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, rop);
733 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",
734 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevDst->physBitmap) : "",
735 xDst, yDst, widthDst, heightDst,
736 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevSrc->physBitmap) : "",
737 xSrc, ySrc, widthSrc, heightSrc, rop));
739 if(physDevDst->hasDIB)
741 /* DIB section selected in dest DC, use DIB Engine */
743 if(!physDevSrc || physDevSrc->hasDIB)
745 /* source is null or has a DIB, no need to convert anyting */
746 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop);
748 else
750 /* source is a DDB, must convert it to DIB */
752 /* we must differentiate from 2 cases :
753 1) source DC is a memory DC
754 2) source DC is a device DC */
755 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
757 /* memory DC */
758 HBITMAP dib, ddb;
760 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
761 if(!ddb)
763 ERR("Couldn't select out DDB from source HDC\n");
764 res = 0;
765 goto noBlt1;
767 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, heightSrc);
768 if(!dib)
770 ERR("Failed converting source DDB to DIB\n");
771 SelectObject(physDevSrc->hdc, ddb);
772 res = 0;
773 goto noBlt1;
775 SelectObject(physDevSrc->hdc, dib);
776 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst,
777 physDevSrc, xSrc, 0, widthSrc, heightSrc, rop);
778 SelectObject(physDevSrc->hdc, ddb);
779 DeleteObject(dib);
780 noBlt1:
783 else
785 /* device DC */
786 HBITMAP dib, stock;
787 HDC memHdc;
789 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, widthSrc, heightSrc);
790 if(!dib)
792 ERR("Failed converting source DDB tp DIB for device DC\n");
793 res = 0;
794 goto noBlt2;
796 memHdc = CreateCompatibleDC(physDevDst->hdc);
797 if(!memHdc)
799 ERR("Failed creating temporary memory DC\n");
800 DeleteObject(dib);
801 res = 0;
802 goto noBlt2;
804 stock = SelectObject(memHdc, dib);
805 if(!stock)
807 ERR("Failed selecting converted DIB into temporary memory DC\n");
808 DeleteObject(dib);
809 DeleteDC(memHdc);
810 res = 0;
811 goto noBlt2;
813 res = StretchBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, memHdc, 0, 0, widthSrc, widthDst, rop);
815 SelectObject(memHdc, stock);
816 DeleteObject(dib);
817 DeleteDC(memHdc);
818 noBlt2:
823 else /* dest is a DDB */
825 /* DDB selected on dest DC, use X11 Driver */
826 if(!physDevSrc || !physDevSrc->hasDIB)
828 /* source is null or has also a DDB, no need to convert anything */
829 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
830 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, widthSrc, heightSrc, rop);
832 else
834 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
835 HBITMAP dib, ddb;
837 /* clip blit area */
838 if(physDevSrc)
840 RECT srcClip = {0, 0, physDevSrc->physBitmap->width, physDevSrc->physBitmap->height};
841 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, 0);
843 else
844 res = TRUE;
845 if(!res)
846 goto noBlt3;
847 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
848 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
850 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
851 if(!dib)
853 ERR("Couldn't select out DIB from source HDC\n");
854 res = 0;
855 goto noBlt3;
857 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, heightSrc);
858 if(!ddb)
860 ERR("Failed converting source DIB to DDB\n");
861 SelectObject(physDevSrc->hdc, dib);
862 res = 0;
863 goto noBlt3;
865 if(!SelectObject(physDevSrc->hdc, ddb))
867 ERR("Failed to select converted DDB into source HDC\n");
868 SelectObject(physDevSrc->hdc, dib);
869 DeleteObject(ddb);
870 res = 0;
871 goto noBlt3;
873 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
874 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, widthSrc, heightSrc, rop);
875 SelectObject(physDevSrc->hdc, dib);
876 DeleteObject(ddb);
877 noBlt3:
881 return res;
884 /***********************************************************************
885 * DIBDRV_PatBlt
887 BOOL DIBDRV_PatBlt( DIBDRVPHYSDEV *physDev, INT left, INT top, INT width, INT height, DWORD rop )
889 BOOL res;
891 MAYBE(TRACE("physDev:%p, left:%d, top:%d, width:%d, height:%d, rop:%06x\n", physDev, left, top, width, height, rop));
893 if(physDev->hasDIB)
895 /* DIB section selected in, use DIB Engine */
896 ONCE(FIXME("TEMPORARY - use BitBlt by now\n"));
897 res = DIBDRV_BitBlt(physDev, left, top, width, height, NULL, 0, 0, rop);
899 else
901 /* DDB selected in, use X11 driver */
902 res = _DIBDRV_GetDisplayDriver()->pPatBlt(physDev->X11PhysDev, left, top, width, height, rop);
904 return res;