DIB Engine: fixes clipping, text and more
[wine/hacks.git] / dlls / winedib.drv / bitblt.c
blobdb66142800563e7c277d29c1df976d76b8725b7b
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 /* converts to device spaces */
266 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
267 _DIBDRV_Sizes_ws2ds(physDevDst, &widthDst, &heightDst);
268 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
269 _DIBDRV_Sizes_ws2ds(physDevSrc, &widthSrc, &heightSrc);
271 /* first clip on physical DC sizes */
272 setPoint(&pd, xDst, yDst);
273 setPoint(&ps, xSrc, ySrc);
274 setSize(&szDst, widthDst, heightDst);
275 setSize(&szSrc, widthSrc, heightSrc);
276 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
277 if(physDevSrc)
279 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
280 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
282 else
283 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
284 if(!res)
285 return FALSE;
286 xDst = pd.x; yDst = pd.y;
287 xSrc = ps.x; ySrc = ps.y;
288 widthDst = szDst.cx; heightDst = szDst.cy;
289 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
291 /* then, do blitting for each dest clip area (no clipping on source) */
292 res = FALSE;
293 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
295 RECT *r = physDevDst->regionRects + iRec;
296 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
297 setPoint(&pd, xDst, yDst);
298 setPoint(&ps, xSrc, ySrc);
299 setSize(&szDst, widthDst, heightDst);
300 setSize(&szSrc, widthSrc, heightSrc);
301 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
302 continue;
303 if(physDevDst->physBitmap.funcs->AlphaBlend(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
304 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, blendfn))
305 res = TRUE;
307 return res;
310 /***********************************************************************
311 * DIBDRV_AlphaBlend
313 BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
314 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
315 BLENDFUNCTION blendfn)
317 BOOL res;
319 POINT pd = {xDst, yDst};
320 POINT ps = {xSrc, ySrc};
321 SIZE szDst = {widthDst, heightDst};
322 SIZE szSrc = {widthSrc, heightSrc};
324 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",
325 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
326 xDst, yDst, widthDst, heightDst,
327 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
328 xSrc, ySrc, widthSrc, heightSrc));
330 /* if sizes are null or negative, returns false */
331 if(widthSrc <= 0 || heightSrc <= 0 || widthDst <= 0 || heightDst <= 0)
333 res = FALSE;
334 goto fin;
337 /* source sould be a 32 bit DIB */
338 if(!physDevSrc)
340 FIXME("Null source bitmap -- shouldn't happen\n");
341 res = FALSE;
342 goto fin;
344 else if(!physDevSrc->hasDIB)
346 FIXME("DDB source bitmap -- shouldn't happen\n");
347 res = FALSE;
348 goto fin;
351 if(physDevDst->hasDIB)
353 /* DIB section selected in dest DC, use DIB Engine */
354 MAYBE(TRACE("Blending DIB->DIB\n"));
355 res = _DIBDRV_InternalAlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst,
356 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
358 else
360 /* DDB selected on dest DC -- must double-convert */
361 HBITMAP tmpDIB, stock;
362 HDC tmpDC;
363 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
364 MAYBE(TRACE("Blending DIB->DDB\n"));
366 /* clip blit area */
367 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, 0);
368 if(!res)
369 goto fin;
370 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
371 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
373 /* converts dest DDB onto a temporary DIB -- just the needed part */
374 tmpDIB = _DIBDRV_ConvertDevDDBtoDIB(physDevDst->hdc, physDevSrc->hdc, xDst, yDst, widthDst, heightDst);
375 if(!tmpDIB)
377 ERR("Couldn't convert dest DDB to DIB\n");
378 res = FALSE;
379 goto fin;
382 /* selects the temporary DIB into a temporary DC */
383 tmpDC = CreateCompatibleDC(physDevDst->hdc);
384 if(!tmpDC)
386 ERR("Couldn't create temporary DC\n");
387 DeleteObject(tmpDIB);
388 res = FALSE;
389 goto fin;
391 stock = SelectObject(tmpDC, tmpDIB);
392 if(!stock)
394 ERR("Couldn't select temporary DIB into temporary DC\n");
395 DeleteDC(tmpDC);
396 DeleteObject(tmpDIB);
397 res = FALSE;
398 goto fin;
401 /* blends source DIB onto temp DIB and re-blits onto dest DC */
402 res = GdiAlphaBlend(tmpDC, 0, 0, widthDst, heightDst, physDevSrc->hdc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
403 if(!res)
404 MAYBE(TRACE("AlphaBlend failed\n"));
405 else
406 res = BitBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, tmpDC, 0, 0, SRCCOPY);
408 /* frees resources */
409 SelectObject(tmpDC, stock);
410 DeleteDC(tmpDC);
411 DeleteObject(tmpDIB);
413 fin:
414 return res;
417 /***********************************************************************
418 * _DIBDRV_InternalBitBlt
420 BOOL _DIBDRV_InternalBitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
421 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
422 INT xSrc, INT ySrc, DWORD rop )
424 BOOL res;
425 POINT pd, ps;
426 SIZE sz;
427 int iRec;
428 RECT dstClip, srcClip;
430 /* converts to device spaces */
431 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
432 _DIBDRV_Sizes_ws2ds(physDevDst, &width, &height);
433 if(physDevSrc)
434 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
436 /* first clip on physical DC sizes */
437 setPoint(&pd, xDst, yDst);
438 setPoint(&ps, xSrc, ySrc);
439 setSize(&sz, width, height);
440 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
441 if(physDevSrc)
443 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
444 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, &dstClip);
446 else
447 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
448 if(!res)
449 return FALSE;
450 xDst = pd.x; yDst = pd.y;
451 xSrc = ps.x; ySrc = ps.y;
452 width = sz.cx; height = sz.cy;
454 /* then, do blitting for each dest clip area (no clipping on source) */
455 res = FALSE;
456 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
458 RECT *r = physDevDst->regionRects + iRec;
459 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
460 setPoint(&pd, xDst, yDst);
461 setPoint(&ps, xSrc, ySrc);
462 setSize(&sz, width, height);
463 if(!BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip))
464 continue;
465 if(physDevDst->physBitmap.funcs->BitBlt(physDevDst, pd.x, pd.y, sz.cx, sz.cy, physDevSrc, ps.x, ps.y, rop))
466 res = TRUE;
468 return res;
471 /***********************************************************************
472 * DIBDRV_BitBlt */
473 BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
474 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
475 INT xSrc, INT ySrc, DWORD rop )
477 BOOL res;
479 /* clip blit area */
480 POINT pd = {xDst, yDst};
481 POINT ps = {xSrc, ySrc};
482 SIZE sz = {width, height};
484 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",
485 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
486 xDst, yDst, width, height,
487 physDevSrc, physDevSrc ? (physDevSrc->hasDIB ? "DIB-" : "DDB"): "---", physDevSrc && physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
488 xSrc, ySrc, rop));
490 if(physDevDst->hasDIB)
492 /* DIB section selected in dest DC, use DIB Engine */
493 /* clip blit area */
494 RECT dstClip = {0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height};
496 if(!physDevSrc || physDevSrc->hasDIB)
498 /* source is null or has a DIB, no need to convert anyting */
499 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, rop);
501 else
503 /* source is a DDB, must convert it to DIB */
505 /* don't clip on source */
506 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
507 if(!res)
508 goto noBlt2;
509 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
511 /* we must differentiate from 2 cases :
512 1) source DC is a memory DC
513 2) source DC is a device DC */
514 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
516 /* memory DC */
517 HBITMAP dib, ddb;
519 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
520 if(!ddb)
522 ERR("Couldn't select out DDB from source HDC\n");
523 res = 0;
524 goto noBlt1;
526 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, height);
527 if(!dib)
529 ERR("Failed converting source DDB to DIB\n");
530 SelectObject(physDevSrc->hdc, ddb);
531 res = 0;
532 goto noBlt1;
534 SelectObject(physDevSrc->hdc, dib);
535 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, 0, rop);
536 SelectObject(physDevSrc->hdc, ddb);
537 DeleteObject(dib);
538 noBlt1:
541 else
543 /* device DC */
544 HBITMAP dib, stock;
545 HDC memHdc;
547 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, width, height);
548 if(!dib)
550 ERR("Failed converting source DDB tp DIB for device DC\n");
551 res = 0;
552 goto noBlt2;
554 memHdc = CreateCompatibleDC(physDevDst->hdc);
555 if(!memHdc)
557 ERR("Failed creating temporary memory DC\n");
558 DeleteObject(dib);
559 res = 0;
560 goto noBlt2;
562 stock = SelectObject(memHdc, dib);
563 if(!stock)
565 ERR("Failed selecting converted DIB into temporary memory DC\n");
566 DeleteObject(dib);
567 DeleteDC(memHdc);
568 res = 0;
569 goto noBlt2;
571 res = BitBlt(physDevDst->hdc, xDst, yDst, width, height, memHdc, 0, 0, rop);
573 SelectObject(memHdc, stock);
574 DeleteObject(dib);
575 DeleteDC(memHdc);
576 noBlt2:
581 else /* dest is a DDB */
583 /* DDB selected on dest DC, use X11 Driver */
584 if(!physDevSrc || !physDevSrc->hasDIB)
586 /* source is null or has also a DDB, no need to convert anything */
587 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
588 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, rop);
590 else
592 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
593 HBITMAP dib, ddb;
595 /* clip blit area */
596 if(physDevSrc)
598 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
599 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, 0);
601 else
602 res = TRUE;
603 if(!res)
604 goto noBlt3;
605 xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
607 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
608 if(!dib)
610 ERR("Couldn't select out DIB from source HDC\n");
611 res = 0;
612 goto noBlt3;
614 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, height);
615 if(!ddb)
617 ERR("Failed converting source DIB to DDB\n");
618 SelectObject(physDevSrc->hdc, dib);
619 res = 0;
620 goto noBlt3;
622 SelectObject(physDevSrc->hdc, ddb);
623 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
624 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, rop);
625 SelectObject(physDevSrc->hdc, dib);
626 DeleteObject(ddb);
627 noBlt3:
631 return res;
634 /***********************************************************************
635 * _DIBDRV_InternalStretchBlt
637 BOOL _DIBDRV_InternalStretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
638 INT widthDst, INT heightDst, DIBDRVPHYSDEV *physDevSrc,
639 INT xSrc, INT ySrc, int widthSrc, int heightSrc, DWORD rop )
641 BOOL res;
642 POINT pd, ps;
643 SIZE szSrc, szDst;
644 int iRec;
645 RECT dstClip, srcClip;
647 /* converts to device spaces */
648 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
649 _DIBDRV_Sizes_ws2ds(physDevDst, &widthDst, &heightDst);
650 if(physDevSrc)
652 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
653 _DIBDRV_Sizes_ws2ds(physDevSrc, &widthSrc, &heightSrc);
656 /* first clip on physical DC sizes */
657 setPoint(&pd, xDst, yDst);
658 setPoint(&ps, xSrc, ySrc);
659 setSize(&szDst, widthDst, heightDst);
660 setSize(&szSrc, widthSrc, heightSrc);
661 setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
662 if(physDevSrc)
664 setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
665 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
667 else
668 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
669 if(!res)
670 return FALSE;
671 xDst = pd.x; yDst = pd.y;
672 xSrc = ps.x; ySrc = ps.y;
673 widthDst = szDst.cx; heightDst = szDst.cy;
674 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
676 /* then, do blitting for each dest clip area (no clipping on source) */
677 res = FALSE;
678 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
680 RECT *r = physDevDst->regionRects + iRec;
681 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
682 setPoint(&pd, xDst, yDst);
683 setPoint(&ps, xSrc, ySrc);
684 setSize(&szDst, widthDst, heightDst);
685 setSize(&szSrc, widthSrc, heightSrc);
686 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
687 continue;
688 if(physDevDst->physBitmap.funcs->StretchBlt(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
689 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, rop))
690 res = TRUE;
692 return res;
695 /***********************************************************************
696 * DIBDRV_StretchBlt
698 BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
699 INT widthDst, INT heightDst,
700 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc,
701 INT widthSrc, INT heightSrc, DWORD rop )
703 BOOL res;
705 /* clip blit area */
706 POINT pd = {xDst, yDst};
707 POINT ps = {xSrc, ySrc};
708 SIZE szDst = {widthDst, heightDst};
709 SIZE szSrc = {widthSrc, heightSrc};
711 /* if source and dest sizes match, just call BitBlt(), it's faster */
712 if(!physDevSrc || (widthDst == widthSrc && heightDst == heightSrc))
713 return DIBDRV_BitBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, rop);
715 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",
716 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
717 xDst, yDst, widthDst, heightDst,
718 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
719 xSrc, ySrc, widthSrc, heightSrc, rop));
721 if(physDevDst->hasDIB)
723 /* DIB section selected in dest DC, use DIB Engine */
725 if(!physDevSrc || physDevSrc->hasDIB)
727 /* source is null or has a DIB, no need to convert anyting */
728 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop);
730 else
732 /* source is a DDB, must convert it to DIB */
734 /* we must differentiate from 2 cases :
735 1) source DC is a memory DC
736 2) source DC is a device DC */
737 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
739 /* memory DC */
740 HBITMAP dib, ddb;
742 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
743 if(!ddb)
745 ERR("Couldn't select out DDB from source HDC\n");
746 res = 0;
747 goto noBlt1;
749 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, ySrc, heightSrc);
750 if(!dib)
752 ERR("Failed converting source DDB to DIB\n");
753 SelectObject(physDevSrc->hdc, ddb);
754 res = 0;
755 goto noBlt1;
757 SelectObject(physDevSrc->hdc, dib);
758 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst,
759 physDevSrc, xSrc, 0, widthSrc, heightSrc, rop);
760 SelectObject(physDevSrc->hdc, ddb);
761 DeleteObject(dib);
762 noBlt1:
765 else
767 /* device DC */
768 HBITMAP dib, stock;
769 HDC memHdc;
771 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, xSrc, ySrc, widthSrc, heightSrc);
772 if(!dib)
774 ERR("Failed converting source DDB tp DIB for device DC\n");
775 res = 0;
776 goto noBlt2;
778 memHdc = CreateCompatibleDC(physDevDst->hdc);
779 if(!memHdc)
781 ERR("Failed creating temporary memory DC\n");
782 DeleteObject(dib);
783 res = 0;
784 goto noBlt2;
786 stock = SelectObject(memHdc, dib);
787 if(!stock)
789 ERR("Failed selecting converted DIB into temporary memory DC\n");
790 DeleteObject(dib);
791 DeleteDC(memHdc);
792 res = 0;
793 goto noBlt2;
795 res = StretchBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, memHdc, 0, 0, widthSrc, widthDst, rop);
797 SelectObject(memHdc, stock);
798 DeleteObject(dib);
799 DeleteDC(memHdc);
800 noBlt2:
805 else /* dest is a DDB */
807 /* DDB selected on dest DC, use X11 Driver */
808 if(!physDevSrc || !physDevSrc->hasDIB)
810 /* source is null or has also a DDB, no need to convert anything */
811 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
812 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, widthSrc, heightSrc, rop);
814 else
816 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
817 HBITMAP dib, ddb;
819 /* clip blit area */
820 if(physDevSrc)
822 RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
823 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, 0);
825 else
826 res = TRUE;
827 if(!res)
828 goto noBlt3;
829 xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
830 xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
832 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
833 if(!dib)
835 ERR("Couldn't select out DIB from source HDC\n");
836 res = 0;
837 goto noBlt3;
839 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, ySrc, heightSrc);
840 if(!ddb)
842 ERR("Failed converting source DIB to DDB\n");
843 SelectObject(physDevSrc->hdc, dib);
844 res = 0;
845 goto noBlt3;
847 if(!SelectObject(physDevSrc->hdc, ddb))
849 ERR("Failed to select converted DDB into source HDC\n");
850 SelectObject(physDevSrc->hdc, dib);
851 DeleteObject(ddb);
852 res = 0;
853 goto noBlt3;
855 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
856 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, 0, widthSrc, heightSrc, rop);
857 SelectObject(physDevSrc->hdc, dib);
858 DeleteObject(ddb);
859 noBlt3:
863 return res;
866 /***********************************************************************
867 * DIBDRV_PatBlt
869 BOOL DIBDRV_PatBlt( DIBDRVPHYSDEV *physDev, INT left, INT top, INT width, INT height, DWORD rop )
871 BOOL res;
873 MAYBE(TRACE("physDev:%p, left:%d, top:%d, width:%d, height:%d, rop:%06x\n", physDev, left, top, width, height, rop));
875 if(physDev->hasDIB)
877 /* DIB section selected in, use DIB Engine */
878 ONCE(FIXME("TEMPORARY - use BitBlt by now\n"));
879 res = DIBDRV_BitBlt(physDev, left, top, width, height, NULL, 0, 0, rop);
881 else
883 /* DDB selected in, use X11 driver */
884 res = _DIBDRV_GetDisplayDriver()->pPatBlt(physDev->X11PhysDev, left, top, width, height, rop);
886 return res;