gdi32: Use NtGdiStretchBlt for StretchBlt.
[wine.git] / dlls / gdi32 / enhmfdrv / bitblt.c
blob8bd30ffb67132a1795574e2d1e37534b85ca92bb
1 /*
2 * Enhanced MetaFile driver BitBlt functions
4 * Copyright 2002 Huw D M Davies for CodeWeavers
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 <stdarg.h>
22 #include <string.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "enhmetafiledrv.h"
30 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
31 static BOOL emfdrv_stretchblt( PHYSDEV dev_dst, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
32 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
33 DWORD rop, DWORD type )
35 BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
36 UINT bmi_size, emr_size, size, bpp;
37 HBITMAP bitmap, blit_bitmap = NULL;
38 EMRBITBLT *emr = NULL;
39 BITMAPINFO *bmi;
40 DIBSECTION dib;
41 HDC blit_dc;
42 int info_size;
43 BOOL ret = FALSE;
45 if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
46 if (!(info_size = GetObjectW( bitmap, sizeof(dib), &dib ))) return FALSE;
48 if (info_size == sizeof(DIBSECTION))
50 blit_dc = hdc_src;
51 blit_bitmap = bitmap;
53 else
55 unsigned char dib_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
56 BITMAPINFO *dib_info = (BITMAPINFO *)dib_info_buffer;
57 BITMAP bmp = dib.dsBm;
58 HPALETTE palette;
59 void *bits;
61 assert( info_size == sizeof(BITMAP) );
63 dib_info->bmiHeader.biSize = sizeof(dib_info->bmiHeader);
64 dib_info->bmiHeader.biWidth = bmp.bmWidth;
65 dib_info->bmiHeader.biHeight = bmp.bmHeight;
66 dib_info->bmiHeader.biPlanes = 1;
67 dib_info->bmiHeader.biBitCount = bmp.bmBitsPixel;
68 dib_info->bmiHeader.biCompression = BI_RGB;
69 dib_info->bmiHeader.biSizeImage = 0;
70 dib_info->bmiHeader.biXPelsPerMeter = 0;
71 dib_info->bmiHeader.biYPelsPerMeter = 0;
72 dib_info->bmiHeader.biClrUsed = 0;
73 dib_info->bmiHeader.biClrImportant = 0;
74 switch (dib_info->bmiHeader.biBitCount)
76 case 16:
77 ((DWORD *)dib_info->bmiColors)[0] = 0xf800;
78 ((DWORD *)dib_info->bmiColors)[1] = 0x07e0;
79 ((DWORD *)dib_info->bmiColors)[2] = 0x001f;
80 break;
81 case 32:
82 ((DWORD *)dib_info->bmiColors)[0] = 0xff0000;
83 ((DWORD *)dib_info->bmiColors)[1] = 0x00ff00;
84 ((DWORD *)dib_info->bmiColors)[2] = 0x0000ff;
85 break;
86 default:
87 if (dib_info->bmiHeader.biBitCount > 8) break;
88 if (!(palette = GetCurrentObject( hdc_src, OBJ_PAL ))) return FALSE;
89 if (!GetPaletteEntries( palette, 0, 256, (PALETTEENTRY *)dib_info->bmiColors ))
90 return FALSE;
93 if (!(blit_dc = NtGdiCreateCompatibleDC( hdc_src ))) return FALSE;
94 if (!(blit_bitmap = CreateDIBSection( blit_dc, dib_info, DIB_RGB_COLORS, &bits, NULL, 0 )))
95 goto err;
96 if (!SelectObject( blit_dc, blit_bitmap )) goto err;
97 if (!BitBlt( blit_dc, 0, 0, bmp.bmWidth, bmp.bmHeight, hdc_src, 0, 0, SRCCOPY ))
98 goto err;
100 if (!GetDIBits( blit_dc, blit_bitmap, 0, INT_MAX, NULL, &src_info, DIB_RGB_COLORS ))
101 goto err;
103 bpp = src_info.bmiHeader.biBitCount;
104 if (bpp <= 8)
105 bmi_size = sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD);
106 else if (bpp == 16 || bpp == 32)
107 bmi_size = sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
108 else
109 bmi_size = sizeof(BITMAPINFOHEADER);
111 /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
112 emr_size = type == EMR_BITBLT ? sizeof(EMRBITBLT) : sizeof(EMRSTRETCHBLT);
113 size = emr_size + bmi_size + src_info.bmiHeader.biSizeImage;
115 if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
117 emr->emr.iType = type;
118 emr->emr.nSize = size;
119 emr->rclBounds.left = x_dst;
120 emr->rclBounds.top = y_dst;
121 emr->rclBounds.right = x_dst + width_dst - 1;
122 emr->rclBounds.bottom = y_dst + height_dst - 1;
123 emr->xDest = x_dst;
124 emr->yDest = y_dst;
125 emr->cxDest = width_dst;
126 emr->cyDest = height_dst;
127 emr->xSrc = x_src;
128 emr->ySrc = y_src;
129 if (type == EMR_STRETCHBLT || type == EMR_ALPHABLEND)
131 EMRSTRETCHBLT *emr_stretchblt = (EMRSTRETCHBLT *)emr;
132 emr_stretchblt->cxSrc = width_src;
133 emr_stretchblt->cySrc = height_src;
135 emr->dwRop = rop;
136 NtGdiGetTransform( hdc_src, 0x204, &emr->xformSrc );
137 emr->crBkColorSrc = GetBkColor( hdc_src );
138 emr->iUsageSrc = DIB_RGB_COLORS;
139 emr->offBmiSrc = emr_size;
140 emr->cbBmiSrc = bmi_size;
141 emr->offBitsSrc = emr_size + bmi_size;
142 emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
144 bmi = (BITMAPINFO *)((BYTE *)emr + emr->offBmiSrc);
145 bmi->bmiHeader = src_info.bmiHeader;
146 ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight, (BYTE *)emr + emr->offBitsSrc,
147 bmi, DIB_RGB_COLORS );
148 if (ret)
150 ret = EMFDRV_WriteRecord( dev_dst, (EMR *)emr );
151 if (ret) EMFDRV_UpdateBBox( dev_dst, &emr->rclBounds );
154 err:
155 HeapFree( GetProcessHeap(), 0, emr );
156 if (blit_bitmap && blit_bitmap != bitmap) DeleteObject( blit_bitmap );
157 if (blit_dc && blit_dc != hdc_src) DeleteDC( blit_dc );
158 return ret;
161 BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst,
162 PHYSDEV dev_src, struct bitblt_coords *src, BLENDFUNCTION func )
164 return emfdrv_stretchblt( dev_dst, dst->log_x, dst->log_y, dst->log_width, dst->log_height,
165 dev_src->hdc, src->log_x, src->log_y, src->log_width, src->log_height,
166 *(DWORD *)&func, EMR_ALPHABLEND );
169 BOOL CDECL EMFDRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
171 /* FIXME: update bound rect */
172 return TRUE;
175 BOOL EMFDC_PatBlt( DC_ATTR *dc_attr, INT left, INT top, INT width, INT height, DWORD rop )
177 EMFDRV_PDEVICE *emf = dc_attr->emf;
178 EMRBITBLT emr;
179 BOOL ret;
181 emr.emr.iType = EMR_BITBLT;
182 emr.emr.nSize = sizeof(emr);
183 emr.rclBounds.left = left;
184 emr.rclBounds.top = top;
185 emr.rclBounds.right = left + width - 1;
186 emr.rclBounds.bottom = top + height - 1;
187 emr.xDest = left;
188 emr.yDest = top;
189 emr.cxDest = width;
190 emr.cyDest = height;
191 emr.dwRop = rop;
192 emr.xSrc = 0;
193 emr.ySrc = 0;
194 emr.xformSrc.eM11 = 1.0;
195 emr.xformSrc.eM12 = 0.0;
196 emr.xformSrc.eM21 = 0.0;
197 emr.xformSrc.eM22 = 1.0;
198 emr.xformSrc.eDx = 0.0;
199 emr.xformSrc.eDy = 0.0;
200 emr.crBkColorSrc = 0;
201 emr.iUsageSrc = 0;
202 emr.offBmiSrc = 0;
203 emr.cbBmiSrc = 0;
204 emr.offBitsSrc = 0;
205 emr.cbBitsSrc = 0;
207 ret = EMFDRV_WriteRecord( &emf->dev, &emr.emr );
208 if(ret)
209 EMFDRV_UpdateBBox( &emf->dev, &emr.rclBounds );
210 return ret;
213 static inline BOOL rop_uses_src( DWORD rop )
215 return ((rop >> 2) & 0x330000) != (rop & 0x330000);
218 BOOL EMFDC_StretchBlt( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
219 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
220 DWORD rop )
222 if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop );
223 if (width_src == width_dst && height_src == height_dst)
224 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst,
225 hdc_src, x_src, y_src, width_src,
226 height_src, rop, EMR_BITBLT );
227 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst,
228 hdc_src, x_src, y_src, width_src,
229 height_src, rop, EMR_STRETCHBLT );
232 INT CDECL EMFDRV_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
233 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
234 BITMAPINFO *info, UINT wUsage, DWORD dwRop )
236 EMRSTRETCHDIBITS *emr;
237 BOOL ret;
238 UINT bmi_size, emr_size;
240 /* calculate the size of the colour table */
241 bmi_size = get_dib_info_size(info, wUsage);
243 emr_size = sizeof (EMRSTRETCHDIBITS) + bmi_size + info->bmiHeader.biSizeImage;
244 emr = HeapAlloc(GetProcessHeap(), 0, emr_size );
245 if (!emr) return 0;
247 /* write a bitmap info header (with colours) to the record */
248 memcpy( &emr[1], info, bmi_size);
250 /* write bitmap bits to the record */
251 memcpy ( ( (BYTE *) (&emr[1]) ) + bmi_size, bits, info->bmiHeader.biSizeImage);
253 /* fill in the EMR header at the front of our piece of memory */
254 emr->emr.iType = EMR_STRETCHDIBITS;
255 emr->emr.nSize = emr_size;
257 emr->xDest = xDst;
258 emr->yDest = yDst;
259 emr->cxDest = widthDst;
260 emr->cyDest = heightDst;
261 emr->dwRop = dwRop;
262 emr->xSrc = xSrc; /* FIXME: only save the piece of the bitmap needed */
263 emr->ySrc = ySrc;
265 emr->iUsageSrc = wUsage;
266 emr->offBmiSrc = sizeof (EMRSTRETCHDIBITS);
267 emr->cbBmiSrc = bmi_size;
268 emr->offBitsSrc = emr->offBmiSrc + bmi_size;
269 emr->cbBitsSrc = info->bmiHeader.biSizeImage;
271 emr->cxSrc = widthSrc;
272 emr->cySrc = heightSrc;
274 emr->rclBounds.left = xDst;
275 emr->rclBounds.top = yDst;
276 emr->rclBounds.right = xDst + widthDst;
277 emr->rclBounds.bottom = yDst + heightDst;
279 /* save the record we just created */
280 ret = EMFDRV_WriteRecord( dev, &emr->emr );
281 if(ret)
282 EMFDRV_UpdateBBox( dev, &emr->rclBounds );
284 HeapFree(GetProcessHeap(), 0, emr);
286 return ret ? heightSrc : GDI_ERROR;
289 INT CDECL EMFDRV_SetDIBitsToDevice( PHYSDEV dev, INT xDst, INT yDst, DWORD width, DWORD height,
290 INT xSrc, INT ySrc, UINT startscan, UINT lines,
291 LPCVOID bits, BITMAPINFO *info, UINT wUsage )
293 EMRSETDIBITSTODEVICE* pEMR;
294 DWORD bmiSize = get_dib_info_size(info, wUsage);
295 DWORD size = sizeof(EMRSETDIBITSTODEVICE) + bmiSize + info->bmiHeader.biSizeImage;
297 pEMR = HeapAlloc(GetProcessHeap(), 0, size);
298 if (!pEMR) return 0;
300 pEMR->emr.iType = EMR_SETDIBITSTODEVICE;
301 pEMR->emr.nSize = size;
302 pEMR->rclBounds.left = xDst;
303 pEMR->rclBounds.top = yDst;
304 pEMR->rclBounds.right = xDst + width - 1;
305 pEMR->rclBounds.bottom = yDst + height - 1;
306 pEMR->xDest = xDst;
307 pEMR->yDest = yDst;
308 pEMR->xSrc = xSrc;
309 pEMR->ySrc = ySrc;
310 pEMR->cxSrc = width;
311 pEMR->cySrc = height;
312 pEMR->offBmiSrc = sizeof(EMRSETDIBITSTODEVICE);
313 pEMR->cbBmiSrc = bmiSize;
314 pEMR->offBitsSrc = sizeof(EMRSETDIBITSTODEVICE) + bmiSize;
315 pEMR->cbBitsSrc = info->bmiHeader.biSizeImage;
316 pEMR->iUsageSrc = wUsage;
317 pEMR->iStartScan = startscan;
318 pEMR->cScans = lines;
319 memcpy((BYTE*)pEMR + pEMR->offBmiSrc, info, bmiSize);
320 memcpy((BYTE*)pEMR + pEMR->offBitsSrc, bits, info->bmiHeader.biSizeImage);
322 if (EMFDRV_WriteRecord(dev, (EMR*)pEMR))
323 EMFDRV_UpdateBBox(dev, &(pEMR->rclBounds));
325 HeapFree( GetProcessHeap(), 0, pEMR);
326 return lines;