DIB Engine: fix MapModes for xxxBlt
[wine/hacks.git] / dlls / winedib.drv / bitblt.c
blob5fcc9e0bfc2bf930f1f03128e89f248e60c12327
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 void CheckMapping(const char *func, const char *s, DIBDRVPHYSDEV *physDev)
30 int a, b;
32 if(!physDev)
33 return;
35 a=10;b=20;
36 _DIBDRV_Position_ws2ds(physDev, &a, &b);
37 if(a != 10 || b != 20)
38 FIXME("%s:%s:Position(10, 20) translated to(%d, %d)\n", func, s, a, b);
39 a=10;b=20;
40 _DIBDRV_Sizes_ws2ds(physDev, &a, &b);
41 if(a != 10 || b != 20)
42 FIXME("%s:%s:sizes (10, 20) translated to(%d, %d)\n", func, s, a, b);
45 static inline void intSwap(int *a, int *b)
47 int tmp;
48 tmp = *a;
49 *a = *b;
50 *b = tmp;
53 static inline void setRect(RECT *r, int x1, int y1, int x2, int y2)
55 r->left = x1;
56 r->top = y1;
57 r->right = x2;
58 r->bottom = y2;
61 static inline void setPoint(POINT *p, int x, int y)
63 p->x = x;
64 p->y = y;
67 static inline void setSize(SIZE *sz, int cx, int cy)
69 sz->cx = cx;
70 sz->cy = cy;
73 /* clips a source and destination areas to their respective clip rectangles
74 returning both source and dest modified; result is TRUE if clipping
75 leads to a non null rectangle, FALSE otherwise */
76 static BOOL BitBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *sz, RECT*srcClip, RECT*dstClip)
78 int xs1, ys1, xs2, ys2;
79 int xsc1, ysc1, xsc2, ysc2;
80 int xd1, yd1, xd2, yd2;
81 int xdc1, ydc1, xdc2, ydc2;
82 int w, h, dx, dy;
84 /* extract sizes */
85 w = sz->cx; h = sz->cy;
87 /* if sizes null or negative, just return false */
88 if(w <= 0 || h <= 0)
89 return FALSE;
91 /* extract dest area data */
92 xd1 = pd->x;
93 yd1 = pd->y;
94 xd2 = xd1 + w;
95 yd2 = yd1 + h;
97 /* extract source data */
98 xs1 = ps->x;
99 ys1 = ps->y;
100 xs2 = xs1 + w;
101 ys2 = ys1 + h;
103 /* if source clip area is not null, do first clipping on it */
104 if(srcClip)
106 /* extract source clipping area */
107 xsc1 = srcClip->left;
108 ysc1 = srcClip->top;
109 xsc2 = srcClip->right;
110 ysc2 = srcClip->bottom;
112 /* order clip area rectangle points */
113 if(xsc1 > xsc2) intSwap(&xsc1, &xsc2);
114 if(ysc1 > ysc2) intSwap(&ysc1, &ysc2);
116 /* clip on source clipping start point */
117 if(xs1 < xsc1) { dx = xsc1 - xs1; w -= dx; xd1 += dx; xs1 = xsc1; }
118 if(ys1 < ysc1) { dy = ysc1 - ys1; h -= dy; yd1 += dy; ys1 = ysc1; }
120 /* clip on source clipping end point */
121 if(xs2 > xsc2) { dx = xs2 - xsc2; w -= dx; xd2 -= dx; xs2 = xsc2; }
122 if(ys2 > ysc2) { dy = ys2 - ysc2; h -= dy; yd2 -= dy; ys2 = ysc2; }
124 /* if already zero area, return false */
125 if(w <= 0 || h <= 0)
126 return FALSE;
128 /* now do clipping on destination area */
129 if(dstClip)
131 /* extract destination clipping area */
132 xdc1 = dstClip->left;
133 ydc1 = dstClip->top;
134 xdc2 = dstClip->right;
135 ydc2 = dstClip->bottom;
137 /* order clip area rectangle points */
138 if(xdc1 > xdc2) intSwap(&xdc1, &xdc2);
139 if(ydc1 > ydc2) intSwap(&ydc1, &ydc2);
141 /* clip on dest clipping start point */
142 if(xd1 < xdc1) { dx = xdc1 - xd1; w -= dx; xs1 += dx; xd1 = xdc1; }
143 if(yd1 < ydc1) { dy = ydc1 - yd1; h -= dy; ys1 += dy; yd1 = ydc1; }
145 /* clip on dest clipping end point */
146 if(xd2 > xdc2) { dx = xd2 - xdc2; w -= dx; xs2 -= dx; xd2 = xdc2; }
147 if(yd2 > ydc2) { dy = yd2 - ydc2; h -= dy; ys2 -= dy; yd2 = ydc2; }
149 /* if already zero area, return false */
150 if(w <= 0 || h <= 0)
151 return FALSE;
154 /* sets clipped/translated points and sizes and returns TRUE */
155 ps->x = xs1; ps->y = ys1;
156 pd->x = xd1; pd->y = yd1;
157 sz->cx = w; sz->cy = h;
159 return TRUE;
164 /* clips a source and destination areas to their respective clip rectangles
165 returning both source and dest modified; result is TRUE if clipping
166 leads to a non null rectangle, FALSE otherwise */
167 static BOOL StretchBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *szSrc, SIZE *szDst, RECT*srcClip, RECT*dstClip)
169 int xs1, ys1, xs2, ys2;
170 int xsc1, ysc1, xsc2, ysc2;
171 int xd1, yd1, xd2, yd2;
172 int xdc1, ydc1, xdc2, ydc2;
173 int ws, hs, wd, hd, dx, dy;
174 int mulh, divh, mulv, divv;
176 /* extract sizes */
177 ws = szSrc->cx; hs = szSrc->cy;
178 wd = szDst->cx; hd = szDst->cy;
180 /* if sizes null or negative, just return false */
181 /* FIXME : add support for mirror stretch */
182 if(ws <= 0 || hs <= 0 || wd <= 0 || hd <= 0)
183 return FALSE;
185 /* stores scaling factors from source rect to dest one */
186 mulh = wd; divh = ws;
187 mulv = hd; divv = hs;
189 /* extract dest area data */
190 xd1 = pd->x;
191 yd1 = pd->y;
192 xd2 = xd1 + wd;
193 yd2 = yd1 + hd;
195 /* extract source data */
196 xs1 = ps->x;
197 ys1 = ps->y;
198 xs2 = xs1 + ws;
199 ys2 = ys1 + hs;
201 /* if source clip area is not null, do first clipping on it */
202 if(srcClip)
204 /* extract source clipping area */
205 xsc1 = srcClip->left;
206 ysc1 = srcClip->top;
207 xsc2 = srcClip->right;
208 ysc2 = srcClip->bottom;
210 /* order clip area rectangle points */
211 if(xsc1 > xsc2) intSwap(&xsc1, &xsc2);
212 if(ysc1 > ysc2) intSwap(&ysc1, &ysc2);
214 /* clip on source clipping start point */
215 if(xs1 < xsc1) { dx = xsc1 - xs1; ws -= dx; xd1 += MulDiv(dx, mulh, divh); xs1 = xsc1; }
216 if(ys1 < ysc1) { dy = ysc1 - ys1; hs -= dy; yd1 += MulDiv(dy, mulv, divv); ys1 = ysc1; }
218 /* clip on source clipping end point */
219 if(xs2 > xsc2) { dx = xs2 - xsc2; ws -= dx; xd2 -= MulDiv(dx, mulh, divh); xs2 = xsc2; }
220 if(ys2 > ysc2) { dy = ys2 - ysc2; hs -= dy; yd2 -= MulDiv(dy, mulv, divv); ys2 = ysc2; }
222 /* if already zero area, return false */
223 if(ws <= 0 || hs <= 0)
224 return FALSE;
225 wd = xd2 - xd1;
226 hd = yd2 - yd1;
228 /* now do clipping on destination area */
230 if(dstClip)
232 /* extract destination clipping area */
233 xdc1 = dstClip->left;
234 ydc1 = dstClip->top;
235 xdc2 = dstClip->right;
236 ydc2 = dstClip->bottom;
238 /* order clip area rectangle points */
239 if(xdc1 > xdc2) intSwap(&xdc1, &xdc2);
240 if(ydc1 > ydc2) intSwap(&ydc1, &ydc2);
242 /* clip on dest clipping start point */
243 if(xd1 < xdc1) { dx = xdc1 - xd1; wd -= dx; xs1 += MulDiv(dx, divh, mulh); xd1 = xdc1; }
244 if(yd1 < ydc1) { dy = ydc1 - yd1; hd -= dy; ys1 += MulDiv(dy, divv, mulv); yd1 = ydc1; }
246 /* clip on dest clipping end point */
247 if(xd2 > xdc2) { dx = xd2 - xdc2; wd -= dx; xs2 -= MulDiv(dx, divh, mulh); xd2 = xdc2; }
248 if(yd2 > ydc2) { dy = yd2 - ydc2; hd -= dy; ys2 -= MulDiv(dy, divv, mulv); yd2 = ydc2; }
250 /* if already zero area, return false */
251 if(wd <= 0 || hd <= 0)
252 return FALSE;
254 ws = xs2 - xs1;
255 hs = ys2 - ys1;
258 /* sets clipped/translated points and sizes and returns TRUE */
259 ps->x = xs1; ps->y = ys1;
260 pd->x = xd1; pd->y = yd1;
261 szSrc->cx = ws; szSrc->cy = hs;
262 szDst->cx = wd; szDst->cy = hd;
264 return TRUE;
268 /***********************************************************************
269 * _DIBDRV_InternalAlphaBlend
271 BOOL _DIBDRV_InternalAlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
272 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
273 BLENDFUNCTION blendfn)
275 BOOL res;
276 POINT pd, ps;
277 SIZE szSrc, szDst;
278 int iRec;
279 RECT dstClip, srcClip;
281 /* converts to device spaces */
282 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
283 _DIBDRV_Sizes_ws2ds(physDevDst, &widthDst, &heightDst);
284 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
285 _DIBDRV_Sizes_ws2ds(physDevSrc, &widthSrc, &heightSrc);
287 /* from tests, it seems that coords out of phys spaces are not allowed */
288 if(xDst < 0 || yDst < 0 || xSrc < 0 || ySrc < 0 ||
289 xDst + widthDst > physDevDst->physBitmap->width ||
290 yDst + heightDst > physDevDst->physBitmap->height ||
291 xSrc + widthSrc > physDevSrc->physBitmap->width ||
292 ySrc + heightSrc > physDevSrc->physBitmap->height)
294 SetLastError(ERROR_INVALID_PARAMETER);
295 return FALSE;
298 /* first clip on physical DC sizes */
299 setPoint(&pd, xDst, yDst);
300 setPoint(&ps, xSrc, ySrc);
301 setSize(&szDst, widthDst, heightDst);
302 setSize(&szSrc, widthSrc, heightSrc);
303 setRect(&dstClip, 0, 0, physDevDst->physBitmap->width, physDevDst->physBitmap->height);
304 setRect(&srcClip, 0, 0, physDevSrc->physBitmap->width, physDevSrc->physBitmap->height);
305 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
306 if(!res)
307 return TRUE;
308 xDst = pd.x; yDst = pd.y;
309 xSrc = ps.x; ySrc = ps.y;
310 widthDst = szDst.cx; heightDst = szDst.cy;
311 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
313 /* then, do blitting for each dest clip area (no clipping on source) */
314 res = FALSE;
315 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
317 RECT *r = physDevDst->regionRects + iRec;
318 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
319 setPoint(&pd, xDst, yDst);
320 setPoint(&ps, xSrc, ySrc);
321 setSize(&szDst, widthDst, heightDst);
322 setSize(&szSrc, widthSrc, heightSrc);
323 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
324 continue;
325 if(physDevDst->physBitmap->funcs->AlphaBlend(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
326 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, blendfn))
327 res = TRUE;
329 return res;
332 /***********************************************************************
333 * DIBDRV_AlphaBlend
335 BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
336 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
337 BLENDFUNCTION blendfn)
339 BOOL res;
341 POINT pd = {xDst, yDst};
342 SIZE szDst = {widthDst, heightDst};
344 CheckMapping(__FUNCTION__, "DEST", physDevDst);
345 CheckMapping(__FUNCTION__, "SOURCE",physDevSrc);
347 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",
348 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevDst->physBitmap) : "",
349 xDst, yDst, widthDst, heightDst,
350 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevSrc->physBitmap) : "",
351 xSrc, ySrc, widthSrc, heightSrc));
353 /* if sizes are null or negative, or source positions are negatives, returns false */
354 if(widthSrc <= 0 || heightSrc <= 0 ||
355 widthDst <= 0 || heightDst <= 0)
357 res = FALSE;
358 SetLastError(ERROR_INVALID_PARAMETER);
359 goto fin;
362 /* source sould be a 32 bit DIB */
363 if(!physDevSrc)
365 FIXME("Null source bitmap -- shouldn't happen\n");
366 res = FALSE;
367 goto fin;
369 else if(!physDevSrc->hasDIB)
371 FIXME("DDB source bitmap still not supported\n");
372 res = FALSE;
373 goto fin;
376 if(physDevDst->hasDIB)
378 /* DIB section selected in dest DC, use DIB Engine */
379 MAYBE(TRACE("Blending DIB->DIB\n"));
380 res = _DIBDRV_InternalAlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst,
381 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
383 else
385 /* DDB selected on dest DC -- must double-convert */
386 HBITMAP tmpDIB, stock;
387 HDC tmpDC;
388 MAYBE(TRACE("Blending DIB->DDB\n"));
390 /* we should anyways convert dest to physical coordinates here before processing
391 in order to check its consistency -- source coords will be converted/clipped later
392 As we do a conversion to a temporary DIB for destination, we don't care about it */
393 _DIBDRV_Position_ws2ds(physDevDst, &pd.x, &pd.y);
394 _DIBDRV_Sizes_ws2ds(physDevDst, &szDst.cx, &szDst.cy);
396 /* test shows that negatives origins are not allowed */
397 if(pd.x < 0 || pd.y < 0)
399 SetLastError(ERROR_INVALID_PARAMETER);
400 res = FALSE;
401 goto fin;
404 /* converts dest DDB onto a temporary DIB -- just the needed part */
405 /* WARNING -- that one could fail if rectangle on dest id out of range */
406 tmpDIB = _DIBDRV_ConvertDevDDBtoDIB(physDevDst->hdc, physDevSrc->hdc, pd.x, pd.y, szDst.cx, szDst.cy);
407 if(!tmpDIB)
409 ERR("Couldn't convert dest DDB to DIB\n");
410 res = FALSE;
411 goto fin;
414 /* selects the temporary DIB into a temporary DC */
415 tmpDC = CreateCompatibleDC(physDevDst->hdc);
416 if(!tmpDC)
418 ERR("Couldn't create temporary DC\n");
419 DeleteObject(tmpDIB);
420 res = FALSE;
421 goto fin;
423 stock = SelectObject(tmpDC, tmpDIB);
424 if(!stock)
426 ERR("Couldn't select temporary DIB into temporary DC\n");
427 DeleteDC(tmpDC);
428 DeleteObject(tmpDIB);
429 res = FALSE;
430 goto fin;
433 /* blends source DIB onto temp DIB and re-blits onto dest DC */
434 res = GdiAlphaBlend(tmpDC, 0, 0, szDst.cx, szDst.cy, physDevSrc->hdc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
435 if(!res)
436 MAYBE(TRACE("AlphaBlend failed\n"));
437 else
438 res = BitBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, tmpDC, 0, 0, SRCCOPY);
440 /* frees resources */
441 SelectObject(tmpDC, stock);
442 DeleteDC(tmpDC);
443 DeleteObject(tmpDIB);
445 fin:
446 return res;
449 /***********************************************************************
450 * _DIBDRV_InternalBitBlt
452 BOOL _DIBDRV_InternalBitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
453 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
454 INT xSrc, INT ySrc, DWORD rop )
456 BOOL res;
457 POINT pd, ps;
458 SIZE sz;
459 int iRec;
460 RECT dstClip, srcClip;
462 /* converts to device spaces */
463 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
464 _DIBDRV_Sizes_ws2ds(physDevDst, &width, &height);
465 if(physDevSrc)
466 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
468 /* first clip on physical DC sizes */
469 setPoint(&pd, xDst, yDst);
470 setPoint(&ps, xSrc, ySrc);
471 setSize(&sz, width, height);
472 setRect(&dstClip, 0, 0, physDevDst->physBitmap->width, physDevDst->physBitmap->height);
474 if(physDevSrc)
476 setRect(&srcClip, 0, 0, physDevSrc->physBitmap->width, physDevSrc->physBitmap->height);
477 res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, &dstClip);
479 else
480 res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
481 if(!res)
482 return TRUE;
483 xDst = pd.x; yDst = pd.y;
484 xSrc = ps.x; ySrc = ps.y;
485 width = sz.cx; height = sz.cy;
487 /* then, do blitting for each dest clip area (no clipping on source) */
488 res = TRUE;
489 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
491 RECT *r = physDevDst->regionRects + iRec;
492 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
493 setPoint(&pd, xDst, yDst);
494 setPoint(&ps, xSrc, ySrc);
495 setSize(&sz, width, height);
496 if(!BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip))
497 continue;
498 if(!physDevDst->physBitmap->funcs->BitBlt(physDevDst, pd.x, pd.y, sz.cx, sz.cy, physDevSrc, ps.x, ps.y, rop))
499 res = FALSE;
501 return res;
504 /***********************************************************************
505 * DIBDRV_BitBlt */
506 BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
507 INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
508 INT xSrc, INT ySrc, DWORD rop )
510 BOOL res;
511 int dummy;
512 int devXSrc, devWidth;
513 int devYSrc, devHeight, zeroYSrc;
515 CheckMapping(__FUNCTION__, "DEST", physDevDst);
516 CheckMapping(__FUNCTION__, "SOURCE",physDevSrc);
517 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",
518 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevDst->physBitmap) : "",
519 xDst, yDst, width, height,
520 physDevSrc, physDevSrc ? (physDevSrc->hasDIB ? "DIB-" : "DDB"): "---", physDevSrc && physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevSrc->physBitmap) : "",
521 xSrc, ySrc, rop));
523 if(physDevDst->hasDIB)
525 /* DIB section selected in dest DC, use DIB Engine */
527 if(!physDevSrc || physDevSrc->hasDIB)
529 /* source is null or has a DIB, no need to convert anyting */
530 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, rop);
532 else
534 /* source is a DDB, must convert it to DIB */
536 /* we must differentiate from 2 cases :
537 1) source DC is a memory DC
538 2) source DC is a device DC */
539 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
541 /* memory DC */
542 HBITMAP dib, ddb;
544 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
545 if(!ddb)
547 ERR("Couldn't select out DDB from source HDC\n");
548 res = 0;
549 goto noBlt1;
552 /* we need device coordinates for ySrc and height, as the conversion
553 functions operates directly on bitmap without the hdc */
554 devYSrc = ySrc;
555 _DIBDRV_Position_ws2ds(physDevSrc, &dummy, &devYSrc);
556 devHeight = height;
557 _DIBDRV_Sizes_ws2ds(physDevSrc, &dummy, &devHeight);
559 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, devYSrc, devHeight);
560 if(!dib)
562 ERR("Failed converting source DDB to DIB\n");
563 SelectObject(physDevSrc->hdc, ddb);
564 res = 0;
565 goto noBlt1;
567 SelectObject(physDevSrc->hdc, dib);
569 /* we need to convert the '0' starting position on converted bitmap tp the world
570 space of bitmap's hdc */
571 zeroYSrc = 0;
572 _DIBDRV_Position_ds2ws(physDevSrc, &dummy, &zeroYSrc);
573 res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, zeroYSrc, rop);
574 SelectObject(physDevSrc->hdc, ddb);
575 DeleteObject(dib);
576 noBlt1:
579 else
581 /* device DC */
582 HBITMAP dib, stock;
583 HDC memHdc;
585 /* we need device coordinates for ySrc and height, as the conversion
586 functions operates directly on bitmap without the hdc */
587 devXSrc = xSrc;
588 devYSrc = ySrc;
589 _DIBDRV_Position_ws2ds(physDevSrc, &devXSrc, &devYSrc);
590 devWidth = width;
591 devHeight = height;
592 _DIBDRV_Sizes_ws2ds(physDevSrc, &devWidth, &devHeight);
594 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, devXSrc, devYSrc, devWidth, devHeight);
595 if(!dib)
597 ERR("Failed converting source DDB tp DIB for device DC\n");
598 res = 0;
599 goto noBlt2;
601 memHdc = CreateCompatibleDC(physDevDst->hdc);
602 if(!memHdc)
604 ERR("Failed creating temporary memory DC\n");
605 DeleteObject(dib);
606 res = 0;
607 goto noBlt2;
609 stock = SelectObject(memHdc, dib);
610 if(!stock)
612 ERR("Failed selecting converted DIB into temporary memory DC\n");
613 DeleteObject(dib);
614 DeleteDC(memHdc);
615 res = 0;
616 goto noBlt2;
618 res = BitBlt(physDevDst->hdc, xDst, yDst, width, height, memHdc, 0, 0, rop);
620 SelectObject(memHdc, stock);
621 DeleteObject(dib);
622 DeleteDC(memHdc);
623 noBlt2:
628 else /* dest is a DDB */
630 /* DDB selected on dest DC, use X11 Driver */
631 if(!physDevSrc || !physDevSrc->hasDIB)
633 /* source is null or has also a DDB, no need to convert anything */
634 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
635 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, rop);
637 else
639 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
640 HBITMAP dib, ddb;
641 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
642 if(!dib)
644 ERR("Couldn't select out DIB from source HDC\n");
645 res = 0;
646 goto noBlt3;
649 /* we need device coordinates for ySrc and height, as the conversion
650 functions operates directly on bitmap without the hdc */
651 devYSrc = ySrc;
652 _DIBDRV_Position_ws2ds(physDevSrc, &dummy, &devYSrc);
653 devHeight = height;
654 _DIBDRV_Sizes_ws2ds(physDevSrc, &dummy, &devHeight);
656 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, devYSrc, devHeight);
657 if(!ddb)
659 ERR("Failed converting source DIB to DDB\n");
660 SelectObject(physDevSrc->hdc, dib);
661 res = 0;
662 goto noBlt3;
664 SelectObject(physDevSrc->hdc, ddb);
666 /* we need to convert the '0' starting position on converted bitmap tp the world
667 space of bitmap's hdc */
668 zeroYSrc = 0;
669 _DIBDRV_Position_ds2ws(physDevSrc, &dummy, &zeroYSrc);
671 res = _DIBDRV_GetDisplayDriver()->pBitBlt(physDevDst->X11PhysDev, xDst, yDst, width, height,
672 physDevSrc->X11PhysDev, xSrc, zeroYSrc, rop);
673 SelectObject(physDevSrc->hdc, dib);
674 DeleteObject(ddb);
675 noBlt3:
679 return res;
682 /***********************************************************************
683 * _DIBDRV_InternalStretchBlt
685 BOOL _DIBDRV_InternalStretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
686 INT widthDst, INT heightDst, DIBDRVPHYSDEV *physDevSrc,
687 INT xSrc, INT ySrc, int widthSrc, int heightSrc, DWORD rop )
689 BOOL res;
690 POINT pd, ps;
691 SIZE szSrc, szDst;
692 int iRec;
693 RECT dstClip, srcClip;
695 /* converts to device spaces */
696 _DIBDRV_Position_ws2ds(physDevDst, &xDst, &yDst);
697 _DIBDRV_Sizes_ws2ds(physDevDst, &widthDst, &heightDst);
698 if(physDevSrc)
700 _DIBDRV_Position_ws2ds(physDevSrc, &xSrc, &ySrc);
701 _DIBDRV_Sizes_ws2ds(physDevSrc, &widthSrc, &heightSrc);
704 /* first clip on physical DC sizes */
705 setPoint(&pd, xDst, yDst);
706 setPoint(&ps, xSrc, ySrc);
707 setSize(&szDst, widthDst, heightDst);
708 setSize(&szSrc, widthSrc, heightSrc);
709 setRect(&dstClip, 0, 0, physDevDst->physBitmap->width, physDevDst->physBitmap->height);
710 if(physDevSrc)
712 setRect(&srcClip, 0, 0, physDevSrc->physBitmap->width, physDevSrc->physBitmap->height);
713 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
715 else
716 res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
717 if(!res)
718 return FALSE;
719 xDst = pd.x; yDst = pd.y;
720 xSrc = ps.x; ySrc = ps.y;
721 widthDst = szDst.cx; heightDst = szDst.cy;
722 widthSrc = szSrc.cx; heightSrc = szSrc.cy;
724 /* then, do blitting for each dest clip area (no clipping on source) */
725 res = FALSE;
726 for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
728 RECT *r = physDevDst->regionRects + iRec;
729 setRect(&dstClip, r->left, r->top, r->right, r->bottom);
730 setPoint(&pd, xDst, yDst);
731 setPoint(&ps, xSrc, ySrc);
732 setSize(&szDst, widthDst, heightDst);
733 setSize(&szSrc, widthSrc, heightSrc);
734 if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
735 continue;
736 if(physDevDst->physBitmap->funcs->StretchBlt(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
737 physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, rop))
738 res = TRUE;
740 return res;
743 /***********************************************************************
744 * DIBDRV_StretchBlt
746 BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
747 INT widthDst, INT heightDst,
748 DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc,
749 INT widthSrc, INT heightSrc, DWORD rop )
751 BOOL res;
752 int dummy;
753 int devXSrc, devWidthSrc;
754 int devYSrc, devHeightSrc, zeroYSrc;
756 /* if source and dest sizes match, just call BitBlt(), it's faster */
757 if(!physDevSrc || (widthDst == widthSrc && heightDst == heightSrc))
758 return DIBDRV_BitBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, rop);
760 CheckMapping(__FUNCTION__, "DEST", physDevDst);
761 CheckMapping(__FUNCTION__, "SOURCE",physDevSrc);
762 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",
763 physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevDst->physBitmap) : "",
764 xDst, yDst, widthDst, heightDst,
765 physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(physDevSrc->physBitmap) : "",
766 xSrc, ySrc, widthSrc, heightSrc, rop));
768 if(physDevDst->hasDIB)
770 /* DIB section selected in dest DC, use DIB Engine */
772 if(!physDevSrc || physDevSrc->hasDIB)
774 /* source is null or has a DIB, no need to convert anyting */
775 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop);
777 else
779 /* source is a DDB, must convert it to DIB */
781 /* we must differentiate from 2 cases :
782 1) source DC is a memory DC
783 2) source DC is a device DC */
784 if(GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
786 /* memory DC */
787 HBITMAP dib, ddb;
789 ddb = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
790 if(!ddb)
792 ERR("Couldn't select out DDB from source HDC\n");
793 res = 0;
794 goto noBlt1;
797 /* we need device coordinates for ySrc and height, as the conversion
798 functions operates directly on bitmap without the hdc */
799 devYSrc = ySrc;
800 _DIBDRV_Position_ws2ds(physDevSrc, &dummy, &devYSrc);
801 devHeightSrc = heightSrc;
802 _DIBDRV_Sizes_ws2ds(physDevSrc, &dummy, &devHeightSrc);
804 dib = _DIBDRV_ConvertDDBtoDIB(physDevSrc->hdc, ddb, devYSrc, devHeightSrc);
805 if(!dib)
807 ERR("Failed converting source DDB to DIB\n");
808 SelectObject(physDevSrc->hdc, ddb);
809 res = 0;
810 goto noBlt1;
812 SelectObject(physDevSrc->hdc, dib);
815 /* we need to convert the '0' starting position on converted bitmap tp the world
816 space of bitmap's hdc */
817 zeroYSrc = 0;
818 _DIBDRV_Position_ds2ws(physDevSrc, &dummy, &zeroYSrc);
820 res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst,
821 physDevSrc, xSrc, zeroYSrc, widthSrc, heightSrc, rop);
822 SelectObject(physDevSrc->hdc, ddb);
823 DeleteObject(dib);
824 noBlt1:
827 else
829 /* device DC */
830 HBITMAP dib, stock;
831 HDC memHdc;
833 /* we need device coordinates for ySrc and height, as the conversion
834 functions operates directly on bitmap without the hdc */
835 devXSrc = xSrc;
836 devYSrc = ySrc;
837 _DIBDRV_Position_ws2ds(physDevSrc, &devXSrc, &devYSrc);
838 devWidthSrc = widthSrc;
839 devHeightSrc = heightSrc;
840 _DIBDRV_Sizes_ws2ds(physDevSrc, &devWidthSrc, &devHeightSrc);
842 dib = _DIBDRV_ConvertDevDDBtoDIB(physDevSrc->hdc, physDevDst->hdc, devXSrc, devYSrc, devWidthSrc, devHeightSrc);
843 if(!dib)
845 ERR("Failed converting source DDB tp DIB for device DC\n");
846 res = 0;
847 goto noBlt2;
849 memHdc = CreateCompatibleDC(physDevDst->hdc);
850 if(!memHdc)
852 ERR("Failed creating temporary memory DC\n");
853 DeleteObject(dib);
854 res = 0;
855 goto noBlt2;
857 stock = SelectObject(memHdc, dib);
858 if(!stock)
860 ERR("Failed selecting converted DIB into temporary memory DC\n");
861 DeleteObject(dib);
862 DeleteDC(memHdc);
863 res = 0;
864 goto noBlt2;
866 res = StretchBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, memHdc, 0, 0, widthSrc, widthDst, rop);
868 SelectObject(memHdc, stock);
869 DeleteObject(dib);
870 DeleteDC(memHdc);
871 noBlt2:
876 else /* dest is a DDB */
878 /* DDB selected on dest DC, use X11 Driver */
879 if(!physDevSrc || !physDevSrc->hasDIB)
881 /* source is null or has also a DDB, no need to convert anything */
882 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
883 physDevSrc ? physDevSrc->X11PhysDev : 0, xSrc, ySrc, widthSrc, heightSrc, rop);
885 else
887 /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
888 HBITMAP dib, ddb;
890 dib = SelectObject(physDevSrc->hdc, GetStockObject(DEFAULT_BITMAP));
891 if(!dib)
893 ERR("Couldn't select out DIB from source HDC\n");
894 res = 0;
895 goto noBlt3;
898 /* we need device coordinates for ySrc and height, as the conversion
899 functions operates directly on bitmap without the hdc */
900 devYSrc = ySrc;
901 _DIBDRV_Position_ws2ds(physDevSrc, &dummy, &devYSrc);
902 devHeightSrc = heightSrc;
903 _DIBDRV_Sizes_ws2ds(physDevSrc, &dummy, &devHeightSrc);
905 ddb = _DIBDRV_ConvertDIBtoDDB(physDevSrc->hdc, dib, devYSrc, devHeightSrc);
906 if(!ddb)
908 ERR("Failed converting source DIB to DDB\n");
909 SelectObject(physDevSrc->hdc, dib);
910 res = 0;
911 goto noBlt3;
913 if(!SelectObject(physDevSrc->hdc, ddb))
915 ERR("Failed to select converted DDB into source HDC\n");
916 SelectObject(physDevSrc->hdc, dib);
917 DeleteObject(ddb);
918 res = 0;
919 goto noBlt3;
922 /* we need to convert the '0' starting position on converted bitmap tp the world
923 space of bitmap's hdc */
924 zeroYSrc = 0;
925 _DIBDRV_Position_ds2ws(physDevSrc, &dummy, &zeroYSrc);
926 res = _DIBDRV_GetDisplayDriver()->pStretchBlt(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
927 physDevSrc->X11PhysDev, xSrc, zeroYSrc, widthSrc, heightSrc, rop);
928 SelectObject(physDevSrc->hdc, dib);
929 DeleteObject(ddb);
930 noBlt3:
934 return res;
937 /***********************************************************************
938 * DIBDRV_PatBlt
940 BOOL DIBDRV_PatBlt( DIBDRVPHYSDEV *physDev, INT left, INT top, INT width, INT height, DWORD rop )
942 BOOL res;
944 MAYBE(TRACE("physDev:%p, left:%d, top:%d, width:%d, height:%d, rop:%06x\n", physDev, left, top, width, height, rop));
946 if(physDev->hasDIB)
948 /* DIB section selected in, use DIB Engine */
949 ONCE(FIXME("TEMPORARY - use BitBlt by now\n"));
950 res = DIBDRV_BitBlt(physDev, left, top, width, height, NULL, 0, 0, rop);
952 else
954 /* DDB selected in, use X11 driver */
955 res = _DIBDRV_GetDisplayDriver()->pPatBlt(physDev->X11PhysDev, left, top, width, height, rop);
957 return res;