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 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 */
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
;
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;
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;
207 ret
= EMFDRV_WriteRecord( &emf
->dev
, &emr
.emr
);
209 EMFDRV_UpdateBBox( &emf
->dev
, &emr
.rclBounds
);
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
,
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
;
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
);
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
;
259 emr
->cxDest
= widthDst
;
260 emr
->cyDest
= heightDst
;
262 emr
->xSrc
= xSrc
; /* FIXME: only save the piece of the bitmap needed */
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
);
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
);
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;
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
);