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
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
;
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
))
55 unsigned char dib_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
56 BITMAPINFO
*dib_info
= (BITMAPINFO
*)dib_info_buffer
;
57 BITMAP bmp
= dib
.dsBm
;
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
)
77 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xf800;
78 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x07e0;
79 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x001f;
82 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xff0000;
83 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x00ff00;
84 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x0000ff;
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
))
93 if (!(blit_dc
= NtGdiCreateCompatibleDC( hdc_src
))) return FALSE
;
94 if (!(blit_bitmap
= CreateDIBSection( blit_dc
, dib_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0 )))
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
))
100 if (!GetDIBits( blit_dc
, blit_bitmap
, 0, INT_MAX
, NULL
, &src_info
, DIB_RGB_COLORS
))
103 bpp
= src_info
.bmiHeader
.biBitCount
;
105 bmi_size
= sizeof(BITMAPINFOHEADER
) + (1 << bpp
) * sizeof(RGBQUAD
);
106 else if (bpp
== 16 || bpp
== 32)
107 bmi_size
= sizeof(BITMAPINFOHEADER
) + 3 * sizeof(RGBQUAD
);
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;
125 emr
->cxDest
= width_dst
;
126 emr
->cyDest
= height_dst
;
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
;
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
);
150 ret
= EMFDRV_WriteRecord( dev_dst
, (EMR
*)emr
);
151 if (ret
) EMFDRV_UpdateBBox( dev_dst
, &emr
->rclBounds
);
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
);
161 BOOL
EMFDC_AlphaBlend( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
162 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
163 BLENDFUNCTION blend_function
)
165 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width_dst
, height_dst
, hdc_src
, x_src
, y_src
,
166 width_src
, height_src
, *(DWORD
*)&blend_function
, EMR_ALPHABLEND
);
169 BOOL CDECL
EMFDRV_AlphaBlend( PHYSDEV dev_dst
, struct bitblt_coords
*dst
,
170 PHYSDEV dev_src
, struct bitblt_coords
*src
, BLENDFUNCTION func
)
172 /* FIXME: update bound rect */
176 BOOL CDECL
EMFDRV_PatBlt( PHYSDEV dev
, struct bitblt_coords
*dst
, DWORD rop
)
178 /* FIXME: update bound rect */
182 BOOL
EMFDC_PatBlt( DC_ATTR
*dc_attr
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
184 EMFDRV_PDEVICE
*emf
= dc_attr
->emf
;
188 emr
.emr
.iType
= EMR_BITBLT
;
189 emr
.emr
.nSize
= sizeof(emr
);
190 emr
.rclBounds
.left
= left
;
191 emr
.rclBounds
.top
= top
;
192 emr
.rclBounds
.right
= left
+ width
- 1;
193 emr
.rclBounds
.bottom
= top
+ height
- 1;
201 emr
.xformSrc
.eM11
= 1.0;
202 emr
.xformSrc
.eM12
= 0.0;
203 emr
.xformSrc
.eM21
= 0.0;
204 emr
.xformSrc
.eM22
= 1.0;
205 emr
.xformSrc
.eDx
= 0.0;
206 emr
.xformSrc
.eDy
= 0.0;
207 emr
.crBkColorSrc
= 0;
214 ret
= EMFDRV_WriteRecord( &emf
->dev
, &emr
.emr
);
216 EMFDRV_UpdateBBox( &emf
->dev
, &emr
.rclBounds
);
220 static inline BOOL
rop_uses_src( DWORD rop
)
222 return ((rop
>> 2) & 0x330000) != (rop
& 0x330000);
225 BOOL
EMFDC_BitBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width
, INT height
,
226 HDC hdc_src
, INT x_src
, INT y_src
, DWORD rop
)
228 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width
, height
, rop
);
229 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width
, height
,
230 hdc_src
, x_src
, y_src
, width
, height
, rop
, EMR_BITBLT
);
233 BOOL
EMFDC_StretchBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
234 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
237 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
238 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width_dst
, height_dst
,
239 hdc_src
, x_src
, y_src
, width_src
,
240 height_src
, rop
, EMR_STRETCHBLT
);
243 INT CDECL
EMFDRV_StretchDIBits( PHYSDEV dev
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
244 INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
, const void *bits
,
245 BITMAPINFO
*info
, UINT wUsage
, DWORD dwRop
)
247 EMRSTRETCHDIBITS
*emr
;
249 UINT bmi_size
, emr_size
;
251 /* calculate the size of the colour table */
252 bmi_size
= get_dib_info_size(info
, wUsage
);
254 emr_size
= sizeof (EMRSTRETCHDIBITS
) + bmi_size
+ info
->bmiHeader
.biSizeImage
;
255 emr
= HeapAlloc(GetProcessHeap(), 0, emr_size
);
258 /* write a bitmap info header (with colours) to the record */
259 memcpy( &emr
[1], info
, bmi_size
);
261 /* write bitmap bits to the record */
262 memcpy ( ( (BYTE
*) (&emr
[1]) ) + bmi_size
, bits
, info
->bmiHeader
.biSizeImage
);
264 /* fill in the EMR header at the front of our piece of memory */
265 emr
->emr
.iType
= EMR_STRETCHDIBITS
;
266 emr
->emr
.nSize
= emr_size
;
270 emr
->cxDest
= widthDst
;
271 emr
->cyDest
= heightDst
;
273 emr
->xSrc
= xSrc
; /* FIXME: only save the piece of the bitmap needed */
276 emr
->iUsageSrc
= wUsage
;
277 emr
->offBmiSrc
= sizeof (EMRSTRETCHDIBITS
);
278 emr
->cbBmiSrc
= bmi_size
;
279 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
280 emr
->cbBitsSrc
= info
->bmiHeader
.biSizeImage
;
282 emr
->cxSrc
= widthSrc
;
283 emr
->cySrc
= heightSrc
;
285 emr
->rclBounds
.left
= xDst
;
286 emr
->rclBounds
.top
= yDst
;
287 emr
->rclBounds
.right
= xDst
+ widthDst
;
288 emr
->rclBounds
.bottom
= yDst
+ heightDst
;
290 /* save the record we just created */
291 ret
= EMFDRV_WriteRecord( dev
, &emr
->emr
);
293 EMFDRV_UpdateBBox( dev
, &emr
->rclBounds
);
295 HeapFree(GetProcessHeap(), 0, emr
);
297 return ret
? heightSrc
: GDI_ERROR
;
300 INT CDECL
EMFDRV_SetDIBitsToDevice( PHYSDEV dev
, INT xDst
, INT yDst
, DWORD width
, DWORD height
,
301 INT xSrc
, INT ySrc
, UINT startscan
, UINT lines
,
302 LPCVOID bits
, BITMAPINFO
*info
, UINT wUsage
)
304 EMRSETDIBITSTODEVICE
* pEMR
;
305 DWORD bmiSize
= get_dib_info_size(info
, wUsage
);
306 DWORD size
= sizeof(EMRSETDIBITSTODEVICE
) + bmiSize
+ info
->bmiHeader
.biSizeImage
;
308 pEMR
= HeapAlloc(GetProcessHeap(), 0, size
);
311 pEMR
->emr
.iType
= EMR_SETDIBITSTODEVICE
;
312 pEMR
->emr
.nSize
= size
;
313 pEMR
->rclBounds
.left
= xDst
;
314 pEMR
->rclBounds
.top
= yDst
;
315 pEMR
->rclBounds
.right
= xDst
+ width
- 1;
316 pEMR
->rclBounds
.bottom
= yDst
+ height
- 1;
322 pEMR
->cySrc
= height
;
323 pEMR
->offBmiSrc
= sizeof(EMRSETDIBITSTODEVICE
);
324 pEMR
->cbBmiSrc
= bmiSize
;
325 pEMR
->offBitsSrc
= sizeof(EMRSETDIBITSTODEVICE
) + bmiSize
;
326 pEMR
->cbBitsSrc
= info
->bmiHeader
.biSizeImage
;
327 pEMR
->iUsageSrc
= wUsage
;
328 pEMR
->iStartScan
= startscan
;
329 pEMR
->cScans
= lines
;
330 memcpy((BYTE
*)pEMR
+ pEMR
->offBmiSrc
, info
, bmiSize
);
331 memcpy((BYTE
*)pEMR
+ pEMR
->offBitsSrc
, bits
, info
->bmiHeader
.biSizeImage
);
333 if (EMFDRV_WriteRecord(dev
, (EMR
*)pEMR
))
334 EMFDRV_UpdateBBox(dev
, &(pEMR
->rclBounds
));
336 HeapFree( GetProcessHeap(), 0, pEMR
);