2 * Print processor implementation.
4 * Copyright 2022 Piotr Caban 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
26 #include <ddk/winsplp.h>
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(psdrv
);
34 #define EMFSPOOL_VERSION 0x10000
35 #define PP_MAGIC 0x952173fe
45 struct brush_pattern
*patterns
;
61 EMRI_BW_FORM_METAFILE
,
67 EMRI_DESIGNVECTOR_EXT
,
76 unsigned int dwVersion
;
78 unsigned int dpszDocName
;
79 unsigned int dpszOutput
;
88 BOOL WINAPI
SeekPrinter(HANDLE
, LARGE_INTEGER
, LARGE_INTEGER
*, DWORD
, BOOL
);
90 static const WCHAR emf_1003
[] = L
"NT EMF 1.003";
92 #define EMRICASE(x) case x: return #x
93 static const char * debugstr_rec_type(int id
)
97 EMRICASE(EMRI_METAFILE
);
98 EMRICASE(EMRI_ENGINE_FONT
);
99 EMRICASE(EMRI_DEVMODE
);
100 EMRICASE(EMRI_TYPE1_FONT
);
101 EMRICASE(EMRI_PRESTARTPAGE
);
102 EMRICASE(EMRI_DESIGNVECTOR
);
103 EMRICASE(EMRI_SUBSET_FONT
);
104 EMRICASE(EMRI_DELTA_FONT
);
105 EMRICASE(EMRI_FORM_METAFILE
);
106 EMRICASE(EMRI_BW_METAFILE
);
107 EMRICASE(EMRI_BW_FORM_METAFILE
);
108 EMRICASE(EMRI_METAFILE_DATA
);
109 EMRICASE(EMRI_METAFILE_EXT
);
110 EMRICASE(EMRI_BW_METAFILE_EXT
);
111 EMRICASE(EMRI_ENGINE_FONT_EXT
);
112 EMRICASE(EMRI_TYPE1_FONT_EXT
);
113 EMRICASE(EMRI_DESIGNVECTOR_EXT
);
114 EMRICASE(EMRI_SUBSET_FONT_EXT
);
115 EMRICASE(EMRI_DELTA_FONT_EXT
);
116 EMRICASE(EMRI_PS_JOB_DATA
);
117 EMRICASE(EMRI_EMBED_FONT_EXT
);
119 FIXME("unknown record type: %d\n", id
);
125 static struct pp_data
* get_handle_data(HANDLE pp
)
127 struct pp_data
*ret
= (struct pp_data
*)pp
;
129 if (!ret
|| ret
->magic
!= PP_MAGIC
)
131 SetLastError(ERROR_INVALID_HANDLE
);
137 static inline INT
GDI_ROUND(double val
)
139 return (int)floor(val
+ 0.5);
142 static void translate(RECT
*rect
, const XFORM
*xform
)
148 rect
->left
= GDI_ROUND(x
* xform
->eM11
+ y
* xform
->eM21
+ xform
->eDx
);
149 rect
->top
= GDI_ROUND(x
* xform
->eM12
+ y
* xform
->eM22
+ xform
->eDy
);
153 rect
->right
= GDI_ROUND(x
* xform
->eM11
+ y
* xform
->eM21
+ xform
->eDx
);
154 rect
->bottom
= GDI_ROUND(x
* xform
->eM12
+ y
* xform
->eM22
+ xform
->eDy
);
157 static inline void get_bounding_rect(RECT
*rect
, int x
, int y
, int width
, int height
)
160 rect
->right
= x
+ width
;
162 rect
->bottom
= y
+ height
;
163 if (rect
->left
> rect
->right
)
165 int tmp
= rect
->left
;
166 rect
->left
= rect
->right
+ 1;
167 rect
->right
= tmp
+ 1;
169 if (rect
->top
> rect
->bottom
)
172 rect
->top
= rect
->bottom
+ 1;
173 rect
->bottom
= tmp
+ 1;
177 static inline void order_rect(RECT
*rect
)
179 if (rect
->left
> rect
->right
)
181 int tmp
= rect
->left
;
182 rect
->left
= rect
->right
;
185 if (rect
->top
> rect
->bottom
)
188 rect
->top
= rect
->bottom
;
193 static BOOL
intersect_vis_rectangles(struct bitblt_coords
*dst
, struct bitblt_coords
*src
)
197 /* intersect the rectangles */
199 if ((src
->width
== dst
->width
) && (src
->height
== dst
->height
)) /* no stretching */
201 OffsetRect(&src
->visrect
, dst
->x
- src
->x
, dst
->y
- src
->y
);
202 if (!IntersectRect(&rect
, &src
->visrect
, &dst
->visrect
)) return FALSE
;
203 src
->visrect
= dst
->visrect
= rect
;
204 OffsetRect(&src
->visrect
, src
->x
- dst
->x
, src
->y
- dst
->y
);
206 else /* stretching */
208 /* map source rectangle into destination coordinates */
211 -src
->x
- (src
->width
< 0 ? 1 : 0),
212 -src
->y
- (src
->height
< 0 ? 1 : 0));
213 rect
.left
= rect
.left
* dst
->width
/ src
->width
;
214 rect
.top
= rect
.top
* dst
->height
/ src
->height
;
215 rect
.right
= rect
.right
* dst
->width
/ src
->width
;
216 rect
.bottom
= rect
.bottom
* dst
->height
/ src
->height
;
219 /* when the source rectangle needs to flip and it doesn't fit in the source device
220 area, the destination area isn't flipped. So, adjust destination coordinates */
221 if (src
->width
< 0 && dst
->width
> 0 &&
222 (src
->x
+ src
->width
+ 1 < src
->visrect
.left
|| src
->x
> src
->visrect
.right
))
223 dst
->x
+= (dst
->width
- rect
.right
) - rect
.left
;
224 else if (src
->width
> 0 && dst
->width
< 0 &&
225 (src
->x
< src
->visrect
.left
|| src
->x
+ src
->width
> src
->visrect
.right
))
226 dst
->x
-= rect
.right
- (dst
->width
- rect
.left
);
228 if (src
->height
< 0 && dst
->height
> 0 &&
229 (src
->y
+ src
->height
+ 1 < src
->visrect
.top
|| src
->y
> src
->visrect
.bottom
))
230 dst
->y
+= (dst
->height
- rect
.bottom
) - rect
.top
;
231 else if (src
->height
> 0 && dst
->height
< 0 &&
232 (src
->y
< src
->visrect
.top
|| src
->y
+ src
->height
> src
->visrect
.bottom
))
233 dst
->y
-= rect
.bottom
- (dst
->height
- rect
.top
);
235 OffsetRect(&rect
, dst
->x
, dst
->y
);
237 /* avoid rounding errors */
242 if (!IntersectRect(&dst
->visrect
, &rect
, &dst
->visrect
)) return FALSE
;
244 /* map destination rectangle back to source coordinates */
247 -dst
->x
- (dst
->width
< 0 ? 1 : 0),
248 -dst
->y
- (dst
->height
< 0 ? 1 : 0));
249 rect
.left
= src
->x
+ rect
.left
* src
->width
/ dst
->width
;
250 rect
.top
= src
->y
+ rect
.top
* src
->height
/ dst
->height
;
251 rect
.right
= src
->x
+ rect
.right
* src
->width
/ dst
->width
;
252 rect
.bottom
= src
->y
+ rect
.bottom
* src
->height
/ dst
->height
;
255 /* avoid rounding errors */
260 if (!IntersectRect(&src
->visrect
, &rect
, &src
->visrect
)) return FALSE
;
265 static void clip_visrect(HDC hdc
, RECT
*dst
, const RECT
*src
)
269 hrgn
= CreateRectRgn(0, 0, 0, 0);
270 if (GetRandomRgn(hdc
, hrgn
, 3) == 1)
272 GetRgnBox(hrgn
, dst
);
273 IntersectRect(dst
, dst
, src
);
282 static void get_vis_rectangles(HDC hdc
, struct bitblt_coords
*dst
,
283 const XFORM
*xform
, DWORD width
, DWORD height
, struct bitblt_coords
*src
)
287 rect
.left
= dst
->log_x
;
288 rect
.top
= dst
->log_y
;
289 rect
.right
= dst
->log_x
+ dst
->log_width
;
290 rect
.bottom
= dst
->log_y
+ dst
->log_height
;
291 LPtoDP(hdc
, (POINT
*)&rect
, 2);
294 dst
->width
= rect
.right
- rect
.left
;
295 dst
->height
= rect
.bottom
- rect
.top
;
296 if (dst
->layout
& LAYOUT_RTL
&& dst
->layout
& LAYOUT_BITMAPORIENTATIONPRESERVED
)
298 dst
->x
+= dst
->width
;
299 dst
->width
= -dst
->width
;
301 get_bounding_rect(&rect
, dst
->x
, dst
->y
, dst
->width
, dst
->height
);
302 clip_visrect(hdc
, &dst
->visrect
, &rect
);
306 rect
.left
= src
->log_x
;
307 rect
.top
= src
->log_y
;
308 rect
.right
= src
->log_x
+ src
->log_width
;
309 rect
.bottom
= src
->log_y
+ src
->log_height
;
310 translate(&rect
, xform
);
313 src
->width
= rect
.right
- rect
.left
;
314 src
->height
= rect
.bottom
- rect
.top
;
315 get_bounding_rect(&rect
, src
->x
, src
->y
, src
->width
, src
->height
);
318 intersect_vis_rectangles(dst
, src
);
321 static int stretch_blt(PHYSDEV dev
, const EMRSTRETCHBLT
*blt
,
322 const BITMAPINFO
*bi
, const BYTE
*src_bits
)
324 char dst_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
325 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
326 struct bitblt_coords src
, dst
;
327 struct gdi_image_bits bits
;
330 dst
.log_x
= blt
->xDest
;
331 dst
.log_y
= blt
->yDest
;
332 dst
.log_width
= blt
->cxDest
;
333 dst
.log_height
= blt
->cyDest
;
334 dst
.layout
= GetLayout(dev
->hdc
);
335 if (blt
->dwRop
& NOMIRRORBITMAP
)
336 dst
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
340 get_vis_rectangles(dev
->hdc
, &dst
, NULL
, 0, 0, NULL
);
341 return PSDRV_PatBlt(dev
, &dst
, blt
->dwRop
);
344 src
.log_x
= blt
->xSrc
;
345 src
.log_y
= blt
->ySrc
;
346 src
.log_width
= blt
->cxSrc
;
347 src
.log_height
= blt
->cySrc
;
350 get_vis_rectangles(dev
->hdc
, &dst
, &blt
->xformSrc
,
351 bi
->bmiHeader
.biWidth
, bi
->bmiHeader
.biHeight
, &src
);
353 memcpy(dst_info
, bi
, blt
->cbBmiSrc
);
354 memset(&bits
, 0, sizeof(bits
));
355 bits
.ptr
= (BYTE
*)src_bits
;
356 err
= PSDRV_PutImage(dev
, 0, dst_info
, &bits
, &src
, &dst
, blt
->dwRop
);
357 if (err
== ERROR_BAD_FORMAT
)
359 HDC hdc
= CreateCompatibleDC(NULL
);
363 bitmap
= CreateDIBSection(hdc
, dst_info
, DIB_RGB_COLORS
, &bits
.ptr
, NULL
, 0);
364 SetDIBits(hdc
, bitmap
, 0, bi
->bmiHeader
.biHeight
, src_bits
, bi
, blt
->iUsageSrc
);
366 err
= PSDRV_PutImage(dev
, 0, dst_info
, &bits
, &src
, &dst
, blt
->dwRop
);
367 DeleteObject(bitmap
);
371 if (err
!= ERROR_SUCCESS
)
372 FIXME("PutImage returned %ld\n", err
);
376 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
377 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
379 static int mask_blt(PHYSDEV dev
, const EMRMASKBLT
*p
, const BITMAPINFO
*src_bi
,
380 const BYTE
*src_bits
, const BITMAPINFO
*mask_bi
, const BYTE
*mask_bits
)
382 HBITMAP bmp1
, old_bmp1
, bmp2
, old_bmp2
, bmp_src
, old_bmp_src
;
383 char bmp2_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
384 BITMAPINFO
*bmp2_info
= (BITMAPINFO
*)bmp2_buffer
;
385 HBRUSH brush_mask
, brush_dest
, old_brush
;
386 HDC hdc_src
, hdc1
, hdc2
;
390 static const DWORD ROP3Table
[256] =
392 0x00000042, 0x00010289,
393 0x00020C89, 0x000300AA,
394 0x00040C88, 0x000500A9,
395 0x00060865, 0x000702C5,
396 0x00080F08, 0x00090245,
397 0x000A0329, 0x000B0B2A,
398 0x000C0324, 0x000D0B25,
399 0x000E08A5, 0x000F0001,
400 0x00100C85, 0x001100A6,
401 0x00120868, 0x001302C8,
402 0x00140869, 0x001502C9,
403 0x00165CCA, 0x00171D54,
404 0x00180D59, 0x00191CC8,
405 0x001A06C5, 0x001B0768,
406 0x001C06CA, 0x001D0766,
407 0x001E01A5, 0x001F0385,
408 0x00200F09, 0x00210248,
409 0x00220326, 0x00230B24,
410 0x00240D55, 0x00251CC5,
411 0x002606C8, 0x00271868,
412 0x00280369, 0x002916CA,
413 0x002A0CC9, 0x002B1D58,
414 0x002C0784, 0x002D060A,
415 0x002E064A, 0x002F0E2A,
416 0x0030032A, 0x00310B28,
417 0x00320688, 0x00330008,
418 0x003406C4, 0x00351864,
419 0x003601A8, 0x00370388,
420 0x0038078A, 0x00390604,
421 0x003A0644, 0x003B0E24,
422 0x003C004A, 0x003D18A4,
423 0x003E1B24, 0x003F00EA,
424 0x00400F0A, 0x00410249,
425 0x00420D5D, 0x00431CC4,
426 0x00440328, 0x00450B29,
427 0x004606C6, 0x0047076A,
428 0x00480368, 0x004916C5,
429 0x004A0789, 0x004B0605,
430 0x004C0CC8, 0x004D1954,
431 0x004E0645, 0x004F0E25,
432 0x00500325, 0x00510B26,
433 0x005206C9, 0x00530764,
434 0x005408A9, 0x00550009,
435 0x005601A9, 0x00570389,
436 0x00580785, 0x00590609,
437 0x005A0049, 0x005B18A9,
438 0x005C0649, 0x005D0E29,
439 0x005E1B29, 0x005F00E9,
440 0x00600365, 0x006116C6,
441 0x00620786, 0x00630608,
442 0x00640788, 0x00650606,
443 0x00660046, 0x006718A8,
444 0x006858A6, 0x00690145,
445 0x006A01E9, 0x006B178A,
446 0x006C01E8, 0x006D1785,
447 0x006E1E28, 0x006F0C65,
448 0x00700CC5, 0x00711D5C,
449 0x00720648, 0x00730E28,
450 0x00740646, 0x00750E26,
451 0x00761B28, 0x007700E6,
452 0x007801E5, 0x00791786,
453 0x007A1E29, 0x007B0C68,
454 0x007C1E24, 0x007D0C69,
455 0x007E0955, 0x007F03C9,
456 0x008003E9, 0x00810975,
457 0x00820C49, 0x00831E04,
458 0x00840C48, 0x00851E05,
459 0x008617A6, 0x008701C5,
460 0x008800C6, 0x00891B08,
461 0x008A0E06, 0x008B0666,
462 0x008C0E08, 0x008D0668,
463 0x008E1D7C, 0x008F0CE5,
464 0x00900C45, 0x00911E08,
465 0x009217A9, 0x009301C4,
466 0x009417AA, 0x009501C9,
467 0x00960169, 0x0097588A,
468 0x00981888, 0x00990066,
469 0x009A0709, 0x009B07A8,
470 0x009C0704, 0x009D07A6,
471 0x009E16E6, 0x009F0345,
472 0x00A000C9, 0x00A11B05,
473 0x00A20E09, 0x00A30669,
474 0x00A41885, 0x00A50065,
475 0x00A60706, 0x00A707A5,
476 0x00A803A9, 0x00A90189,
477 0x00AA0029, 0x00AB0889,
478 0x00AC0744, 0x00AD06E9,
479 0x00AE0B06, 0x00AF0229,
480 0x00B00E05, 0x00B10665,
481 0x00B21974, 0x00B30CE8,
482 0x00B4070A, 0x00B507A9,
483 0x00B616E9, 0x00B70348,
484 0x00B8074A, 0x00B906E6,
485 0x00BA0B09, 0x00BB0226,
486 0x00BC1CE4, 0x00BD0D7D,
487 0x00BE0269, 0x00BF08C9,
488 0x00C000CA, 0x00C11B04,
489 0x00C21884, 0x00C3006A,
490 0x00C40E04, 0x00C50664,
491 0x00C60708, 0x00C707AA,
492 0x00C803A8, 0x00C90184,
493 0x00CA0749, 0x00CB06E4,
494 0x00CC0020, 0x00CD0888,
495 0x00CE0B08, 0x00CF0224,
496 0x00D00E0A, 0x00D1066A,
497 0x00D20705, 0x00D307A4,
498 0x00D41D78, 0x00D50CE9,
499 0x00D616EA, 0x00D70349,
500 0x00D80745, 0x00D906E8,
501 0x00DA1CE9, 0x00DB0D75,
502 0x00DC0B04, 0x00DD0228,
503 0x00DE0268, 0x00DF08C8,
504 0x00E003A5, 0x00E10185,
505 0x00E20746, 0x00E306EA,
506 0x00E40748, 0x00E506E5,
507 0x00E61CE8, 0x00E70D79,
508 0x00E81D74, 0x00E95CE6,
509 0x00EA02E9, 0x00EB0849,
510 0x00EC02E8, 0x00ED0848,
511 0x00EE0086, 0x00EF0A08,
512 0x00F00021, 0x00F10885,
513 0x00F20B05, 0x00F3022A,
514 0x00F40B0A, 0x00F50225,
515 0x00F60265, 0x00F708C5,
516 0x00F802E5, 0x00F90845,
517 0x00FA0089, 0x00FB0A09,
518 0x00FC008A, 0x00FD0A0A,
519 0x00FE02A9, 0x00FF0062,
524 blt
.rclBounds
= p
->rclBounds
;
525 blt
.xDest
= p
->xDest
;
526 blt
.yDest
= p
->yDest
;
527 blt
.cxDest
= p
->cxDest
;
528 blt
.cyDest
= p
->cyDest
;
529 blt
.dwRop
= FRGND_ROP3(p
->dwRop
);
532 blt
.xformSrc
= p
->xformSrc
;
533 blt
.crBkColorSrc
= p
->crBkColorSrc
;
534 blt
.iUsageSrc
= p
->iUsageSrc
;
536 blt
.cbBmiSrc
= p
->cbBmiSrc
;
538 blt
.cbBitsSrc
= p
->cbBitsSrc
;
539 blt
.cxSrc
= p
->cxDest
;
540 blt
.cySrc
= p
->cyDest
;
542 return stretch_blt(dev
, &blt
, src_bi
, src_bits
);
545 hdc_src
= CreateCompatibleDC(NULL
);
546 SetGraphicsMode(hdc_src
, GM_ADVANCED
);
547 SetWorldTransform(hdc_src
, &p
->xformSrc
);
548 brush_dest
= CreateSolidBrush(p
->crBkColorSrc
);
549 old_brush
= SelectObject(hdc_src
, brush_dest
);
550 PatBlt(hdc_src
, p
->rclBounds
.left
, p
->rclBounds
.top
,
551 p
->rclBounds
.right
- p
->rclBounds
.left
,
552 p
->rclBounds
.bottom
- p
->rclBounds
.top
, PATCOPY
);
553 SelectObject(hdc_src
, old_brush
);
554 DeleteObject(brush_dest
);
556 bmp_src
= CreateDIBSection(hdc_src
, src_bi
, p
->iUsageSrc
, (void **)&bits
, NULL
, 0);
557 memcpy(bits
, src_bits
, p
->cbBitsSrc
);
558 old_bmp_src
= SelectObject(hdc_src
, bmp_src
);
560 bmp1
= CreateBitmap(mask_bi
->bmiHeader
.biWidth
, mask_bi
->bmiHeader
.biHeight
, 1, 1, NULL
);
561 SetDIBits(dev
->hdc
, bmp1
, 0, mask_bi
->bmiHeader
.biHeight
, mask_bits
, mask_bi
, p
->iUsageMask
);
562 brush_mask
= CreatePatternBrush(bmp1
);
564 brush_dest
= SelectObject(dev
->hdc
, GetStockObject(NULL_BRUSH
));
567 hdc1
= CreateCompatibleDC(NULL
);
568 bmp1
= CreateBitmap(p
->cxDest
, p
->cyDest
, 1, 32, NULL
);
569 old_bmp1
= SelectObject(hdc1
, bmp1
);
571 /* draw using bkgnd rop */
572 old_brush
= SelectObject(hdc1
, brush_dest
);
573 BitBlt(hdc1
, 0, 0, p
->cxDest
, p
->cyDest
, hdc_src
, p
->xSrc
, p
->ySrc
, BKGND_ROP3(p
->dwRop
));
574 SelectObject(hdc1
, old_brush
);
577 hdc2
= CreateCompatibleDC(NULL
);
578 bmp2_info
->bmiHeader
.biSize
= sizeof(bmp2_info
->bmiHeader
);
579 bmp2_info
->bmiHeader
.biWidth
= p
->cxDest
;
580 bmp2_info
->bmiHeader
.biHeight
= p
->cyDest
;
581 bmp2_info
->bmiHeader
.biPlanes
= 1;
582 bmp2_info
->bmiHeader
.biBitCount
= 32;
583 bmp2_info
->bmiHeader
.biCompression
= BI_RGB
;
584 bmp2_info
->bmiHeader
.biSizeImage
= p
->cxDest
* p
->cyDest
* bmp2_info
->bmiHeader
.biBitCount
/ 8;
585 bmp2
= CreateDIBSection(hdc2
, bmp2_info
, DIB_RGB_COLORS
, (void **)&bits
, NULL
, 0);
586 old_bmp2
= SelectObject(hdc2
, bmp2
);
588 /* draw using foregnd rop */
589 old_brush
= SelectObject(hdc2
, brush_dest
);
590 BitBlt(hdc2
, 0, 0, p
->cxDest
, p
->cyDest
, hdc_src
, p
->xSrc
, p
->ySrc
, FRGND_ROP3(p
->dwRop
));
592 /* combine both using the mask as a pattern brush */
593 SelectObject(hdc2
, brush_mask
);
594 SetBrushOrgEx(hdc2
, -p
->xMask
, -p
->yMask
, NULL
);
595 /* (D & P) | (S & ~P) */
596 BitBlt(hdc2
, 0, 0, p
->cxDest
, p
->cyDest
, hdc1
, 0, 0, 0xac0744);
597 SelectObject(hdc2
, old_brush
);
600 blt
.rclBounds
= p
->rclBounds
;
601 blt
.xDest
= p
->xDest
;
602 blt
.yDest
= p
->yDest
;
603 blt
.cxDest
= p
->cxDest
;
604 blt
.cyDest
= p
->cyDest
;
608 GetTransform(hdc2
, 0x204, &blt
.xformSrc
);
609 blt
.crBkColorSrc
= p
->crBkColorSrc
;
610 blt
.iUsageSrc
= DIB_RGB_COLORS
;
612 blt
.cbBmiSrc
= bmp2_info
->bmiHeader
.biSize
;
614 blt
.cbBitsSrc
= bmp2_info
->bmiHeader
.biSizeImage
;
615 blt
.cxSrc
= p
->cxDest
;
616 blt
.cySrc
= p
->cyDest
;
618 stretch_blt(dev
, &blt
, bmp2_info
, bits
);
620 /* restore all objects */
621 SelectObject(dev
->hdc
, brush_dest
);
622 SelectObject(hdc1
, old_bmp1
);
623 SelectObject(hdc2
, old_bmp2
);
624 SelectObject(hdc_src
, old_bmp_src
);
626 /* delete all temp objects */
629 DeleteObject(bmp_src
);
630 DeleteObject(brush_mask
);
634 DeleteObject(hdc_src
);
639 static void combine_transform(XFORM
*result
, const XFORM
*xform1
, const XFORM
*xform2
)
643 /* Create the result in a temporary XFORM, since result may be
644 * equal to xform1 or xform2 */
645 r
.eM11
= xform1
->eM11
* xform2
->eM11
+ xform1
->eM12
* xform2
->eM21
;
646 r
.eM12
= xform1
->eM11
* xform2
->eM12
+ xform1
->eM12
* xform2
->eM22
;
647 r
.eM21
= xform1
->eM21
* xform2
->eM11
+ xform1
->eM22
* xform2
->eM21
;
648 r
.eM22
= xform1
->eM21
* xform2
->eM12
+ xform1
->eM22
* xform2
->eM22
;
649 r
.eDx
= xform1
->eDx
* xform2
->eM11
+ xform1
->eDy
* xform2
->eM21
+ xform2
->eDx
;
650 r
.eDy
= xform1
->eDx
* xform2
->eM12
+ xform1
->eDy
* xform2
->eM22
+ xform2
->eDy
;
655 static int plg_blt(PHYSDEV dev
, const EMRPLGBLT
*p
)
657 const BITMAPINFO
*src_bi
, *mask_bi
;
658 const BYTE
*src_bits
, *mask_bits
;
659 XFORM xf
, xform_dest
;
663 /* parallelogram coords */
667 memcpy(plg
, p
->aptlDest
, sizeof(plg
));
670 rect
[1].x
= p
->xSrc
+ p
->cxSrc
;
673 rect
[2].y
= p
->ySrc
+ p
->cySrc
;
674 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
676 det
= rect
[1].x
*(rect
[2].y
- rect
[0].y
) - rect
[2].x
*(rect
[1].y
- rect
[0].y
) - rect
[0].x
*(rect
[2].y
- rect
[1].y
);
678 if (fabs(det
) < 1e-5)
681 TRACE("%ld,%ld,%ldx%ld -> %ld,%ld,%ld,%ld,%ld,%ld\n", p
->xSrc
, p
->ySrc
, p
->cxSrc
, p
->cySrc
,
682 plg
[0].x
, plg
[0].y
, plg
[1].x
, plg
[1].y
, plg
[2].x
, plg
[2].y
);
685 xf
.eM11
= (plg
[1].x
*(rect
[2].y
- rect
[0].y
) - plg
[2].x
*(rect
[1].y
- rect
[0].y
) - plg
[0].x
*(rect
[2].y
- rect
[1].y
)) / det
;
686 xf
.eM21
= (rect
[1].x
*(plg
[2].x
- plg
[0].x
) - rect
[2].x
*(plg
[1].x
- plg
[0].x
) - rect
[0].x
*(plg
[2].x
- plg
[1].x
)) / det
;
687 xf
.eDx
= (rect
[0].x
*(rect
[1].y
*plg
[2].x
- rect
[2].y
*plg
[1].x
) -
688 rect
[1].x
*(rect
[0].y
*plg
[2].x
- rect
[2].y
*plg
[0].x
) +
689 rect
[2].x
*(rect
[0].y
*plg
[1].x
- rect
[1].y
*plg
[0].x
)
693 xf
.eM12
= (plg
[1].y
*(rect
[2].y
- rect
[0].y
) - plg
[2].y
*(rect
[1].y
- rect
[0].y
) - plg
[0].y
*(rect
[2].y
- rect
[1].y
)) / det
;
694 xf
.eM22
= (rect
[1].x
*(plg
[2].y
- plg
[0].y
) - rect
[2].x
*(plg
[1].y
- plg
[0].y
) - rect
[0].x
*(plg
[2].y
- plg
[1].y
)) / det
;
695 xf
.eDy
= (rect
[0].x
*(rect
[1].y
*plg
[2].y
- rect
[2].y
*plg
[1].y
) -
696 rect
[1].x
*(rect
[0].y
*plg
[2].y
- rect
[2].y
*plg
[0].y
) +
697 rect
[2].x
*(rect
[0].y
*plg
[1].y
- rect
[1].y
*plg
[0].y
)
700 combine_transform(&xf
, &xf
, &p
->xformSrc
);
702 GetTransform(dev
->hdc
, 0x203, &xform_dest
);
703 SetWorldTransform(dev
->hdc
, &xf
);
704 /* now destination and source DCs use same coords */
705 maskblt
.rclBounds
= p
->rclBounds
;
706 maskblt
.xDest
= p
->xSrc
;
707 maskblt
.yDest
= p
->ySrc
;
708 maskblt
.cxDest
= p
->cxSrc
;
709 maskblt
.cyDest
= p
->cySrc
;
710 maskblt
.dwRop
= SRCCOPY
;
711 maskblt
.xSrc
= p
->xSrc
;
712 maskblt
.ySrc
= p
->ySrc
;
713 maskblt
.xformSrc
= p
->xformSrc
;
714 maskblt
.crBkColorSrc
= p
->crBkColorSrc
;
715 maskblt
.iUsageSrc
= p
->iUsageSrc
;
716 maskblt
.offBmiSrc
= 0;
717 maskblt
.cbBmiSrc
= p
->cbBmiSrc
;
718 maskblt
.offBitsSrc
= 0;
719 maskblt
.cbBitsSrc
= p
->cbBitsSrc
;
720 maskblt
.xMask
= p
->xMask
;
721 maskblt
.yMask
= p
->yMask
;
722 maskblt
.iUsageMask
= p
->iUsageMask
;
723 maskblt
.offBmiMask
= 0;
724 maskblt
.cbBmiMask
= p
->cbBmiMask
;
725 maskblt
.offBitsMask
= 0;
726 maskblt
.cbBitsMask
= p
->cbBitsMask
;
727 src_bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
728 src_bits
= (BYTE
*)p
+ p
->offBitsSrc
;
729 mask_bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiMask
);
730 mask_bits
= (BYTE
*)p
+ p
->offBitsMask
;
731 mask_blt(dev
, &maskblt
, src_bi
, src_bits
, mask_bi
, mask_bits
);
732 SetWorldTransform(dev
->hdc
, &xform_dest
);
736 static int poly_draw(PHYSDEV dev
, const POINT
*points
, const BYTE
*types
, DWORD count
)
738 POINT first
, cur
, pts
[4];
741 /* check for valid point types */
742 for (i
= 0; i
< count
; i
++)
747 case PT_LINETO
| PT_CLOSEFIGURE
:
751 if (i
+ 2 >= count
) return FALSE
;
752 if (types
[i
+ 1] != PT_BEZIERTO
) return FALSE
;
753 if ((types
[i
+ 2] & ~PT_CLOSEFIGURE
) != PT_BEZIERTO
) return FALSE
;
761 GetCurrentPositionEx(dev
->hdc
, &cur
);
764 for (i
= 0; i
< count
; i
++)
772 case (PT_LINETO
| PT_CLOSEFIGURE
):
776 if (!PSDRV_PolyPolyline(dev
, pts
, &num_pts
, 1))
782 pts
[2] = points
[i
+ 1];
783 pts
[3] = points
[i
+ 2];
784 if (!PSDRV_PolyBezier(dev
, pts
, 4))
791 if (types
[i
] & PT_CLOSEFIGURE
)
796 if (!PSDRV_PolyPolyline(dev
, pts
, &num_pts
, 1))
804 static inline void reset_bounds(RECT
*bounds
)
806 bounds
->left
= bounds
->top
= INT_MAX
;
807 bounds
->right
= bounds
->bottom
= INT_MIN
;
810 static BOOL
gradient_fill(PHYSDEV dev
, const TRIVERTEX
*vert_array
, DWORD nvert
,
811 const void *grad_array
, DWORD ngrad
, ULONG mode
)
813 char buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
814 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
815 struct bitblt_coords src
, dst
;
816 struct gdi_image_bits bits
;
817 HBITMAP bmp
, old_bmp
;
824 if (!(pts
= malloc(nvert
* sizeof(*pts
)))) return FALSE
;
825 memcpy(pts
, vert_array
, sizeof(*pts
) * nvert
);
826 for (i
= 0; i
< nvert
; i
++)
827 LPtoDP(dev
->hdc
, (POINT
*)&pts
[i
], 1);
829 /* compute bounding rect of all the rectangles/triangles */
830 reset_bounds(&dst
.visrect
);
831 for (i
= 0; i
< ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2); i
++)
833 ULONG v
= ((ULONG
*)grad_array
)[i
];
834 dst
.visrect
.left
= min(dst
.visrect
.left
, pts
[v
].x
);
835 dst
.visrect
.top
= min(dst
.visrect
.top
, pts
[v
].y
);
836 dst
.visrect
.right
= max(dst
.visrect
.right
, pts
[v
].x
);
837 dst
.visrect
.bottom
= max(dst
.visrect
.bottom
, pts
[v
].y
);
840 dst
.x
= dst
.visrect
.left
;
841 dst
.y
= dst
.visrect
.top
;
842 dst
.width
= dst
.visrect
.right
- dst
.visrect
.left
;
843 dst
.height
= dst
.visrect
.bottom
- dst
.visrect
.top
;
844 clip_visrect(dev
->hdc
, &dst
.visrect
, &dst
.visrect
);
846 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
847 info
->bmiHeader
.biPlanes
= 1;
848 info
->bmiHeader
.biBitCount
= 24;
849 info
->bmiHeader
.biCompression
= BI_RGB
;
850 info
->bmiHeader
.biXPelsPerMeter
= 0;
851 info
->bmiHeader
.biYPelsPerMeter
= 0;
852 info
->bmiHeader
.biClrUsed
= 0;
853 info
->bmiHeader
.biClrImportant
= 0;
854 info
->bmiHeader
.biWidth
= dst
.visrect
.right
- dst
.visrect
.left
;
855 info
->bmiHeader
.biHeight
= dst
.visrect
.bottom
- dst
.visrect
.top
;
856 info
->bmiHeader
.biSizeImage
= 0;
857 memset(&bits
, 0, sizeof(bits
));
858 hdc_src
= CreateCompatibleDC(NULL
);
864 bmp
= CreateDIBSection(hdc_src
, info
, DIB_RGB_COLORS
, &bits
.ptr
, NULL
, 0);
867 DeleteObject(hdc_src
);
871 old_bmp
= SelectObject(hdc_src
, bmp
);
873 /* make src and points relative to the bitmap */
875 src
.x
-= dst
.visrect
.left
;
876 src
.y
-= dst
.visrect
.top
;
877 OffsetRect(&src
.visrect
, -dst
.visrect
.left
, -dst
.visrect
.top
);
878 for (i
= 0; i
< nvert
; i
++)
880 pts
[i
].x
-= dst
.visrect
.left
;
881 pts
[i
].y
-= dst
.visrect
.top
;
883 ret
= GdiGradientFill(hdc_src
, pts
, nvert
, (void *)grad_array
, ngrad
, mode
);
884 SelectObject(hdc_src
, old_bmp
);
885 DeleteObject(hdc_src
);
887 rgn
= CreateRectRgn(0, 0, 0, 0);
888 if (mode
== GRADIENT_FILL_TRIANGLE
)
890 const GRADIENT_TRIANGLE
*gt
= grad_array
;
894 for (i
= 0; i
< ngrad
; i
++)
896 triangle
[0].x
= pts
[gt
[i
].Vertex1
].x
;
897 triangle
[0].y
= pts
[gt
[i
].Vertex1
].y
;
898 triangle
[1].x
= pts
[gt
[i
].Vertex2
].x
;
899 triangle
[1].y
= pts
[gt
[i
].Vertex2
].y
;
900 triangle
[2].x
= pts
[gt
[i
].Vertex3
].x
;
901 triangle
[2].y
= pts
[gt
[i
].Vertex3
].y
;
902 tmp
= CreatePolygonRgn(triangle
, 3, ALTERNATE
);
903 CombineRgn(rgn
, rgn
, tmp
, RGN_OR
);
909 const GRADIENT_RECT
*gr
= grad_array
;
910 HRGN tmp
= CreateRectRgn(0, 0, 0, 0);
912 for (i
= 0; i
< ngrad
; i
++)
914 SetRectRgn(tmp
, pts
[gr
[i
].UpperLeft
].x
, pts
[gr
[i
].UpperLeft
].y
,
915 pts
[gr
[i
].LowerRight
].x
, pts
[gr
[i
].LowerRight
].y
);
916 CombineRgn(rgn
, rgn
, tmp
, RGN_OR
);
922 OffsetRgn(rgn
, dst
.visrect
.left
, dst
.visrect
.top
);
924 ret
= (PSDRV_PutImage(dev
, rgn
, info
, &bits
, &src
, &dst
, SRCCOPY
) == ERROR_SUCCESS
);
930 static HGDIOBJ
get_object_handle(struct pp_data
*data
, HANDLETABLE
*handletable
,
931 DWORD i
, struct brush_pattern
**pattern
)
936 return GetStockObject(i
& 0x7fffffff);
938 *pattern
= data
->patterns
+ i
;
939 return handletable
->objectHandle
[i
];
942 static BOOL
fill_rgn(struct pp_data
*data
, HANDLETABLE
*htable
, DWORD brush
, HRGN rgn
)
944 struct brush_pattern
*pattern
;
948 hbrush
= get_object_handle(data
, htable
, brush
, &pattern
);
949 PSDRV_SelectBrush(&data
->pdev
->dev
, hbrush
, pattern
);
950 ret
= PSDRV_PaintRgn(&data
->pdev
->dev
, rgn
);
951 hbrush
= get_object_handle(data
, htable
, data
->brush
, &pattern
);
952 PSDRV_SelectBrush(&data
->pdev
->dev
, hbrush
, pattern
);
956 static BOOL
is_path_record(int type
)
963 case EMR_POLYBEZIERTO
:
965 case EMR_POLYPOLYLINE
:
966 case EMR_POLYPOLYGON
:
978 case EMR_EXTTEXTOUTA
:
979 case EMR_EXTTEXTOUTW
:
980 case EMR_POLYBEZIER16
:
983 case EMR_POLYBEZIERTO16
:
984 case EMR_POLYLINETO16
:
985 case EMR_POLYPOLYLINE16
:
986 case EMR_POLYPOLYGON16
:
994 static int WINAPI
hmf_proc(HDC hdc
, HANDLETABLE
*htable
,
995 const ENHMETARECORD
*rec
, int n
, LPARAM arg
)
997 struct pp_data
*data
= (struct pp_data
*)arg
;
999 if (data
->path
&& is_path_record(rec
->iType
))
1000 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, n
);
1006 const ENHMETAHEADER
*header
= (const ENHMETAHEADER
*)rec
;
1008 data
->patterns
= calloc(sizeof(*data
->patterns
), header
->nHandles
);
1009 return data
->patterns
&& PSDRV_StartPage(&data
->pdev
->dev
);
1011 case EMR_POLYBEZIER
:
1013 const EMRPOLYBEZIER
*p
= (const EMRPOLYBEZIER
*)rec
;
1015 return PSDRV_PolyBezier(&data
->pdev
->dev
, (const POINT
*)p
->aptl
, p
->cptl
);
1019 const EMRPOLYGON
*p
= (const EMRPOLYGON
*)rec
;
1021 return PSDRV_PolyPolygon(&data
->pdev
->dev
, (const POINT
*)p
->aptl
,
1022 (const INT
*)&p
->cptl
, 1);
1026 const EMRPOLYLINE
*p
= (const EMRPOLYLINE
*)rec
;
1028 return PSDRV_PolyPolyline(&data
->pdev
->dev
,
1029 (const POINT
*)p
->aptl
, &p
->cptl
, 1);
1031 case EMR_POLYBEZIERTO
:
1033 const EMRPOLYBEZIERTO
*p
= (const EMRPOLYBEZIERTO
*)rec
;
1035 return PSDRV_PolyBezierTo(&data
->pdev
->dev
, (const POINT
*)p
->aptl
, p
->cptl
) &&
1036 MoveToEx(data
->pdev
->dev
.hdc
, p
->aptl
[p
->cptl
- 1].x
, p
->aptl
[p
->cptl
- 1].y
, NULL
);
1038 case EMR_POLYLINETO
:
1040 const EMRPOLYLINETO
*p
= (const EMRPOLYLINETO
*)rec
;
1046 pts
= malloc(sizeof(*pts
) * cnt
);
1049 GetCurrentPositionEx(data
->pdev
->dev
.hdc
, pts
);
1050 memcpy(pts
+ 1, p
->aptl
, sizeof(*pts
) * p
->cptl
);
1051 ret
= PSDRV_PolyPolyline(&data
->pdev
->dev
, pts
, &cnt
, 1) &&
1052 MoveToEx(data
->pdev
->dev
.hdc
, pts
[cnt
- 1].x
, pts
[cnt
- 1].y
, NULL
);
1056 case EMR_POLYPOLYLINE
:
1058 const EMRPOLYPOLYLINE
*p
= (const EMRPOLYPOLYLINE
*)rec
;
1060 return PSDRV_PolyPolyline(&data
->pdev
->dev
,
1061 (const POINT
*)(p
->aPolyCounts
+ p
->nPolys
),
1062 p
->aPolyCounts
, p
->nPolys
);
1064 case EMR_POLYPOLYGON
:
1066 const EMRPOLYPOLYGON
*p
= (const EMRPOLYPOLYGON
*)rec
;
1068 return PSDRV_PolyPolygon(&data
->pdev
->dev
,
1069 (const POINT
*)(p
->aPolyCounts
+ p
->nPolys
),
1070 (const INT
*)p
->aPolyCounts
, p
->nPolys
);
1073 return PSDRV_EndPage(&data
->pdev
->dev
);
1076 const EMRSETPIXELV
*p
= (const EMRSETPIXELV
*)rec
;
1078 return PSDRV_SetPixel(&data
->pdev
->dev
, p
->ptlPixel
.x
,
1079 p
->ptlPixel
.y
, p
->crColor
);
1081 case EMR_SELECTOBJECT
:
1083 const EMRSELECTOBJECT
*so
= (const EMRSELECTOBJECT
*)rec
;
1084 struct brush_pattern
*pattern
;
1087 obj
= get_object_handle(data
, htable
, so
->ihObject
, &pattern
);
1088 SelectObject(data
->pdev
->dev
.hdc
, obj
);
1090 switch (GetObjectType(obj
))
1092 case OBJ_PEN
: return PSDRV_SelectPen(&data
->pdev
->dev
, obj
, NULL
) != NULL
;
1094 if (PSDRV_SelectBrush(&data
->pdev
->dev
, obj
, pattern
))
1096 data
->brush
= so
->ihObject
;
1101 FIXME("unhandled object type %ld\n", GetObjectType(obj
));
1105 case EMR_DELETEOBJECT
:
1107 const EMRDELETEOBJECT
*p
= (const EMRDELETEOBJECT
*)rec
;
1109 memset(&data
->patterns
[p
->ihObject
], 0, sizeof(*data
->patterns
));
1110 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, n
);
1114 const EMRANGLEARC
*p
= (const EMRANGLEARC
*)rec
;
1115 int arc_dir
= SetArcDirection(data
->pdev
->dev
.hdc
,
1116 p
->eSweepAngle
>= 0 ? AD_COUNTERCLOCKWISE
: AD_CLOCKWISE
);
1120 arcto
.emr
.iType
= EMR_ARCTO
;
1121 arcto
.rclBox
.left
= p
->ptlCenter
.x
- p
->nRadius
;
1122 arcto
.rclBox
.top
= p
->ptlCenter
.y
- p
->nRadius
;
1123 arcto
.rclBox
.right
= p
->ptlCenter
.x
+ p
->nRadius
;
1124 arcto
.rclBox
.bottom
= p
->ptlCenter
.y
+ p
->nRadius
;
1125 arcto
.ptlStart
.x
= GDI_ROUND(p
->ptlCenter
.x
+
1126 cos(p
->eStartAngle
* M_PI
/ 180) * p
->nRadius
);
1127 arcto
.ptlStart
.y
= GDI_ROUND(p
->ptlCenter
.y
-
1128 sin(p
->eStartAngle
* M_PI
/ 180) * p
->nRadius
);
1129 arcto
.ptlEnd
.x
= GDI_ROUND(p
->ptlCenter
.x
+
1130 cos((p
->eStartAngle
+ p
->eSweepAngle
) * M_PI
/ 180) * p
->nRadius
);
1131 arcto
.ptlEnd
.y
= GDI_ROUND(p
->ptlCenter
.y
-
1132 sin((p
->eStartAngle
+ p
->eSweepAngle
) * M_PI
/ 180) * p
->nRadius
);
1134 ret
= hmf_proc(hdc
, htable
, (ENHMETARECORD
*)&arcto
, n
, arg
);
1135 SetArcDirection(data
->pdev
->dev
.hdc
, arc_dir
);
1140 const EMRELLIPSE
*p
= (const EMRELLIPSE
*)rec
;
1141 const RECTL
*r
= &p
->rclBox
;
1143 return PSDRV_Ellipse(&data
->pdev
->dev
, r
->left
, r
->top
, r
->right
, r
->bottom
);
1147 const EMRRECTANGLE
*rect
= (const EMRRECTANGLE
*)rec
;
1149 return PSDRV_Rectangle(&data
->pdev
->dev
, rect
->rclBox
.left
,
1150 rect
->rclBox
.top
, rect
->rclBox
.right
, rect
->rclBox
.bottom
);
1154 const EMRROUNDRECT
*p
= (const EMRROUNDRECT
*)rec
;
1156 return PSDRV_RoundRect(&data
->pdev
->dev
, p
->rclBox
.left
,
1157 p
->rclBox
.top
, p
->rclBox
.right
, p
->rclBox
.bottom
,
1158 p
->szlCorner
.cx
, p
->szlCorner
.cy
);
1162 const EMRARC
*p
= (const EMRARC
*)rec
;
1164 return PSDRV_Arc(&data
->pdev
->dev
, p
->rclBox
.left
, p
->rclBox
.top
,
1165 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
1166 p
->ptlStart
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
1170 const EMRCHORD
*p
= (const EMRCHORD
*)rec
;
1172 return PSDRV_Chord(&data
->pdev
->dev
, p
->rclBox
.left
, p
->rclBox
.top
,
1173 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
1174 p
->ptlStart
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
1178 const EMRPIE
*p
= (const EMRPIE
*)rec
;
1180 return PSDRV_Pie(&data
->pdev
->dev
, p
->rclBox
.left
, p
->rclBox
.top
,
1181 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
1182 p
->ptlStart
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
1186 const EMRLINETO
*line
= (const EMRLINETO
*)rec
;
1188 return PSDRV_LineTo(&data
->pdev
->dev
, line
->ptl
.x
, line
->ptl
.y
) &&
1189 MoveToEx(data
->pdev
->dev
.hdc
, line
->ptl
.x
, line
->ptl
.y
, NULL
);
1193 const EMRARCTO
*p
= (const EMRARCTO
*)rec
;
1197 ret
= GetCurrentPositionEx(data
->pdev
->dev
.hdc
, &pt
);
1200 ret
= ArcTo(data
->pdev
->dev
.hdc
, p
->rclBox
.left
, p
->rclBox
.top
,
1201 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
1202 p
->ptlStart
.y
, p
->ptlStart
.x
, p
->ptlStart
.y
);
1205 ret
= PSDRV_LineTo(&data
->pdev
->dev
, pt
.x
, pt
.y
);
1208 ret
= PSDRV_Arc(&data
->pdev
->dev
, p
->rclBox
.left
, p
->rclBox
.top
,
1209 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
1210 p
->ptlStart
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
1214 ret
= ArcTo(data
->pdev
->dev
.hdc
, p
->rclBox
.left
, p
->rclBox
.top
,
1215 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlEnd
.x
,
1216 p
->ptlEnd
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
1222 const EMRPOLYDRAW
*p
= (const EMRPOLYDRAW
*)rec
;
1223 const POINT
*pts
= (const POINT
*)p
->aptl
;
1225 return poly_draw(&data
->pdev
->dev
, pts
, (BYTE
*)(p
->aptl
+ p
->cptl
), p
->cptl
) &&
1226 MoveToEx(data
->pdev
->dev
.hdc
, pts
[p
->cptl
- 1].x
, pts
[p
->cptl
- 1].y
, NULL
);
1231 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, n
);
1236 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, n
);
1239 return PSDRV_FillPath(&data
->pdev
->dev
);
1240 case EMR_STROKEANDFILLPATH
:
1241 return PSDRV_StrokeAndFillPath(&data
->pdev
->dev
);
1245 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, n
);
1249 const EMRFILLRGN
*p
= (const EMRFILLRGN
*)rec
;
1253 rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
1254 ret
= fill_rgn(data
, htable
, p
->ihBrush
, rgn
);
1260 const EMRFRAMERGN
*p
= (const EMRFRAMERGN
*)rec
;
1264 rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
1265 frame
= CreateRectRgn(0, 0, 0, 0);
1267 CombineRgn(frame
, rgn
, 0, RGN_COPY
);
1268 OffsetRgn(frame
, -p
->szlStroke
.cx
, 0);
1269 OffsetRgn(rgn
, p
->szlStroke
.cx
, 0);
1270 CombineRgn(frame
, frame
, rgn
, RGN_AND
);
1271 OffsetRgn(rgn
, -p
->szlStroke
.cx
, -p
->szlStroke
.cy
);
1272 CombineRgn(frame
, frame
, rgn
, RGN_AND
);
1273 OffsetRgn(rgn
, 0, 2*p
->szlStroke
.cy
);
1274 CombineRgn(frame
, frame
, rgn
, RGN_AND
);
1275 OffsetRgn(rgn
, 0, -p
->szlStroke
.cy
);
1276 CombineRgn(frame
, rgn
, frame
, RGN_DIFF
);
1278 ret
= fill_rgn(data
, htable
, p
->ihBrush
, frame
);
1280 DeleteObject(frame
);
1285 const EMRINVERTRGN
*p
= (const EMRINVERTRGN
*)rec
;
1289 rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
1290 old_rop
= SetROP2(data
->pdev
->dev
.hdc
, R2_NOT
);
1291 ret
= fill_rgn(data
, htable
, 0x80000000 | BLACK_BRUSH
, rgn
);
1292 SetROP2(data
->pdev
->dev
.hdc
, old_rop
);
1298 const EMRPAINTRGN
*p
= (const EMRPAINTRGN
*)rec
;
1299 HRGN rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
1302 ret
= PSDRV_PaintRgn(&data
->pdev
->dev
, rgn
);
1308 const EMRBITBLT
*p
= (const EMRBITBLT
*)rec
;
1309 const BITMAPINFO
*bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
1310 const BYTE
*src_bits
= (BYTE
*)p
+ p
->offBitsSrc
;
1314 blt
.rclBounds
= p
->rclBounds
;
1315 blt
.xDest
= p
->xDest
;
1316 blt
.yDest
= p
->yDest
;
1317 blt
.cxDest
= p
->cxDest
;
1318 blt
.cyDest
= p
->cyDest
;
1319 blt
.dwRop
= p
->dwRop
;
1322 blt
.xformSrc
= p
->xformSrc
;
1323 blt
.crBkColorSrc
= p
->crBkColorSrc
;
1324 blt
.iUsageSrc
= p
->iUsageSrc
;
1325 blt
.offBmiSrc
= p
->offBmiSrc
;
1326 blt
.cbBmiSrc
= p
->cbBmiSrc
;
1327 blt
.offBitsSrc
= p
->offBitsSrc
;
1328 blt
.cbBitsSrc
= p
->cbBitsSrc
;
1329 blt
.cxSrc
= p
->cxDest
;
1330 blt
.cySrc
= p
->cyDest
;
1332 return stretch_blt(&data
->pdev
->dev
, &blt
, bi
, src_bits
);
1334 case EMR_STRETCHBLT
:
1336 const EMRSTRETCHBLT
*p
= (const EMRSTRETCHBLT
*)rec
;
1337 const BITMAPINFO
*bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
1338 const BYTE
*src_bits
= (BYTE
*)p
+ p
->offBitsSrc
;
1340 return stretch_blt(&data
->pdev
->dev
, p
, bi
, src_bits
);
1344 const EMRMASKBLT
*p
= (const EMRMASKBLT
*)rec
;
1345 const BITMAPINFO
*mask_bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiMask
);
1346 const BITMAPINFO
*src_bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
1347 const BYTE
*mask_bits
= (BYTE
*)p
+ p
->offBitsMask
;
1348 const BYTE
*src_bits
= (BYTE
*)p
+ p
->offBitsSrc
;
1350 return mask_blt(&data
->pdev
->dev
, p
, src_bi
, src_bits
, mask_bi
, mask_bits
);
1354 const EMRPLGBLT
*p
= (const EMRPLGBLT
*)rec
;
1356 return plg_blt(&data
->pdev
->dev
, p
);
1358 case EMR_POLYBEZIER16
:
1360 const EMRPOLYBEZIER16
*p
= (const EMRPOLYBEZIER16
*)rec
;
1364 pts
= malloc(sizeof(*pts
) * p
->cpts
);
1366 for (i
= 0; i
< p
->cpts
; i
++)
1368 pts
[i
].x
= p
->apts
[i
].x
;
1369 pts
[i
].y
= p
->apts
[i
].y
;
1371 i
= PSDRV_PolyBezier(&data
->pdev
->dev
, pts
, p
->cpts
);
1377 const EMRPOLYGON16
*p
= (const EMRPOLYGON16
*)rec
;
1381 pts
= malloc(sizeof(*pts
) * p
->cpts
);
1383 for (i
= 0; i
< p
->cpts
; i
++)
1385 pts
[i
].x
= p
->apts
[i
].x
;
1386 pts
[i
].y
= p
->apts
[i
].y
;
1388 i
= PSDRV_PolyPolygon(&data
->pdev
->dev
, pts
, (const INT
*)&p
->cpts
, 1);
1392 case EMR_POLYLINE16
:
1394 const EMRPOLYLINE16
*p
= (const EMRPOLYLINE16
*)rec
;
1398 pts
= malloc(sizeof(*pts
) * p
->cpts
);
1400 for (i
= 0; i
< p
->cpts
; i
++)
1402 pts
[i
].x
= p
->apts
[i
].x
;
1403 pts
[i
].y
= p
->apts
[i
].y
;
1405 i
= PSDRV_PolyPolyline(&data
->pdev
->dev
, pts
, &p
->cpts
, 1);
1409 case EMR_POLYBEZIERTO16
:
1411 const EMRPOLYBEZIERTO16
*p
= (const EMRPOLYBEZIERTO16
*)rec
;
1415 pts
= malloc(sizeof(*pts
) * p
->cpts
);
1417 for (i
= 0; i
< p
->cpts
; i
++)
1419 pts
[i
].x
= p
->apts
[i
].x
;
1420 pts
[i
].y
= p
->apts
[i
].y
;
1422 i
= PSDRV_PolyBezierTo(&data
->pdev
->dev
, pts
, p
->cpts
) &&
1423 MoveToEx(data
->pdev
->dev
.hdc
, pts
[p
->cpts
- 1].x
, pts
[p
->cpts
- 1].y
, NULL
);
1427 case EMR_POLYLINETO16
:
1429 const EMRPOLYLINETO16
*p
= (const EMRPOLYLINETO16
*)rec
;
1435 pts
= malloc(sizeof(*pts
) * cnt
);
1437 GetCurrentPositionEx(data
->pdev
->dev
.hdc
, pts
);
1438 for (i
= 0; i
< p
->cpts
; i
++)
1440 pts
[i
+ 1].x
= p
->apts
[i
].x
;
1441 pts
[i
+ 1].y
= p
->apts
[i
].y
;
1443 i
= PSDRV_PolyPolyline(&data
->pdev
->dev
, pts
, &cnt
, 1) &&
1444 MoveToEx(data
->pdev
->dev
.hdc
, pts
[cnt
- 1].x
, pts
[cnt
- 1].y
, NULL
);
1448 case EMR_POLYPOLYLINE16
:
1450 const EMRPOLYPOLYLINE16
*p
= (const EMRPOLYPOLYLINE16
*)rec
;
1454 pts
= malloc(sizeof(*pts
) * p
->cpts
);
1456 for (i
= 0; i
< p
->cpts
; i
++)
1458 pts
[i
].x
= ((const POINTS
*)(p
->aPolyCounts
+ p
->nPolys
))[i
].x
;
1459 pts
[i
].y
= ((const POINTS
*)(p
->aPolyCounts
+ p
->nPolys
))[i
].y
;
1461 i
= PSDRV_PolyPolyline(&data
->pdev
->dev
, pts
, p
->aPolyCounts
, p
->nPolys
);
1465 case EMR_POLYPOLYGON16
:
1467 const EMRPOLYPOLYGON16
*p
= (const EMRPOLYPOLYGON16
*)rec
;
1471 pts
= malloc(sizeof(*pts
) * p
->cpts
);
1473 for (i
= 0; i
< p
->cpts
; i
++)
1475 pts
[i
].x
= ((const POINTS
*)(p
->aPolyCounts
+ p
->nPolys
))[i
].x
;
1476 pts
[i
].y
= ((const POINTS
*)(p
->aPolyCounts
+ p
->nPolys
))[i
].y
;
1478 i
= PSDRV_PolyPolygon(&data
->pdev
->dev
, pts
, (const INT
*)p
->aPolyCounts
, p
->nPolys
);
1482 case EMR_POLYDRAW16
:
1484 const EMRPOLYDRAW16
*p
= (const EMRPOLYDRAW16
*)rec
;
1488 pts
= malloc(sizeof(*pts
) * p
->cpts
);
1490 for (i
= 0; i
< p
->cpts
; i
++)
1492 pts
[i
].x
= p
->apts
[i
].x
;
1493 pts
[i
].y
= p
->apts
[i
].y
;
1495 i
= poly_draw(&data
->pdev
->dev
, pts
, (BYTE
*)(p
->apts
+ p
->cpts
), p
->cpts
) &&
1496 MoveToEx(data
->pdev
->dev
.hdc
, pts
[p
->cpts
- 1].x
, pts
[p
->cpts
- 1].y
, NULL
);
1500 case EMR_CREATEMONOBRUSH
:
1502 const EMRCREATEMONOBRUSH
*p
= (const EMRCREATEMONOBRUSH
*)rec
;
1504 if (!PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, n
))
1506 data
->patterns
[p
->ihBrush
].usage
= p
->iUsage
;
1507 data
->patterns
[p
->ihBrush
].info
= (BITMAPINFO
*)((BYTE
*)p
+ p
->offBmi
);
1508 data
->patterns
[p
->ihBrush
].bits
.ptr
= (BYTE
*)p
+ p
->offBits
;
1511 case EMR_CREATEDIBPATTERNBRUSHPT
:
1513 const EMRCREATEDIBPATTERNBRUSHPT
*p
= (const EMRCREATEDIBPATTERNBRUSHPT
*)rec
;
1515 if (!PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, n
))
1517 data
->patterns
[p
->ihBrush
].usage
= p
->iUsage
;
1518 data
->patterns
[p
->ihBrush
].info
= (BITMAPINFO
*)((BYTE
*)p
+ p
->offBmi
);
1519 data
->patterns
[p
->ihBrush
].bits
.ptr
= (BYTE
*)p
+ p
->offBits
;
1522 case EMR_GRADIENTFILL
:
1524 const EMRGRADIENTFILL
*p
= (const EMRGRADIENTFILL
*)rec
;
1526 return gradient_fill(&data
->pdev
->dev
, p
->Ver
, p
->nVer
,
1527 p
->Ver
+ p
->nVer
, p
->nTri
, p
->ulMode
);
1530 case EMR_SETWINDOWEXTEX
:
1531 case EMR_SETWINDOWORGEX
:
1532 case EMR_SETVIEWPORTEXTEX
:
1533 case EMR_SETVIEWPORTORGEX
:
1534 case EMR_SETBRUSHORGEX
:
1536 case EMR_SETSTRETCHBLTMODE
:
1537 case EMR_SETTEXTALIGN
:
1538 case EMR_OFFSETCLIPRGN
:
1540 case EMR_EXCLUDECLIPRECT
:
1541 case EMR_INTERSECTCLIPRECT
:
1542 case EMR_SCALEVIEWPORTEXTEX
:
1543 case EMR_SCALEWINDOWEXTEX
:
1544 case EMR_SETWORLDTRANSFORM
:
1545 case EMR_MODIFYWORLDTRANSFORM
:
1547 case EMR_CREATEBRUSHINDIRECT
:
1548 case EMR_SETARCDIRECTION
:
1549 case EMR_SELECTCLIPPATH
:
1550 case EMR_EXTSELECTCLIPRGN
:
1551 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, n
);
1553 FIXME("unsupported record: %ld\n", rec
->iType
);
1559 static BOOL
print_metafile(struct pp_data
*data
, HANDLE hdata
)
1567 if (!ReadPrinter(hdata
, &header
, sizeof(header
), &r
))
1569 if (r
!= sizeof(header
))
1571 SetLastError(ERROR_INVALID_DATA
);
1575 buf
= malloc(header
.cjSize
);
1579 if (!ReadPrinter(hdata
, buf
, header
.cjSize
, &r
))
1584 if (r
!= header
.cjSize
)
1587 SetLastError(ERROR_INVALID_DATA
);
1591 hmf
= SetEnhMetaFileBits(header
.cjSize
, buf
);
1596 ret
= EnumEnhMetaFile(NULL
, hmf
, hmf_proc
, (void *)data
, NULL
);
1597 DeleteEnhMetaFile(hmf
);
1598 free(data
->patterns
);
1599 data
->patterns
= NULL
;
1603 BOOL WINAPI
EnumPrintProcessorDatatypesW(WCHAR
*server
, WCHAR
*name
, DWORD level
,
1604 BYTE
*datatypes
, DWORD size
, DWORD
*needed
, DWORD
*no
)
1606 DATATYPES_INFO_1W
*info
= (DATATYPES_INFO_1W
*)datatypes
;
1608 TRACE("%s, %s, %ld, %p, %ld, %p, %p\n", debugstr_w(server
), debugstr_w(name
),
1609 level
, datatypes
, size
, needed
, no
);
1613 SetLastError(ERROR_INVALID_PARAMETER
);
1618 *needed
= sizeof(*info
) + sizeof(emf_1003
);
1620 if (level
!= 1 || (size
&& !datatypes
))
1622 SetLastError(ERROR_INVALID_PARAMETER
);
1628 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1633 info
->pName
= (WCHAR
*)(info
+ 1);
1634 memcpy(info
+ 1, emf_1003
, sizeof(emf_1003
));
1638 HANDLE WINAPI
OpenPrintProcessor(WCHAR
*port
, PRINTPROCESSOROPENDATA
*open_data
)
1640 struct pp_data
*data
;
1644 TRACE("%s, %p\n", debugstr_w(port
), open_data
);
1646 if (!port
|| !open_data
|| !open_data
->pDatatype
)
1648 SetLastError(ERROR_INVALID_PARAMETER
);
1651 if (wcscmp(open_data
->pDatatype
, emf_1003
))
1653 SetLastError(ERROR_INVALID_DATATYPE
);
1657 if (!OpenPrinterW(port
, &hport
, NULL
))
1660 data
= LocalAlloc(LMEM_FIXED
| LMEM_ZEROINIT
, sizeof(*data
));
1663 data
->magic
= PP_MAGIC
;
1664 data
->hport
= hport
;
1665 data
->doc_name
= wcsdup(open_data
->pDocumentName
);
1666 data
->out_file
= wcsdup(open_data
->pOutputFile
);
1668 hdc
= CreateCompatibleDC(NULL
);
1674 SetGraphicsMode(hdc
, GM_ADVANCED
);
1675 data
->pdev
= create_psdrv_physdev(hdc
, open_data
->pPrinterName
,
1676 (const PSDRV_DEVMODE
*)open_data
->pDevMode
);
1683 data
->pdev
->dev
.hdc
= hdc
;
1684 return (HANDLE
)data
;
1687 BOOL WINAPI
PrintDocumentOnPrintProcessor(HANDLE pp
, WCHAR
*doc_name
)
1689 struct pp_data
*data
= get_handle_data(pp
);
1690 emfspool_header header
;
1691 LARGE_INTEGER pos
, cur
;
1698 TRACE("%p, %s\n", pp
, debugstr_w(doc_name
));
1703 if (!OpenPrinterW(doc_name
, &spool_data
, NULL
))
1706 info
.pDocName
= data
->doc_name
;
1707 info
.pOutputFile
= data
->out_file
;
1708 info
.pDatatype
= (WCHAR
*)L
"RAW";
1709 data
->pdev
->job
.id
= StartDocPrinterW(data
->hport
, 1, (BYTE
*)&info
);
1710 if (!data
->pdev
->job
.id
)
1712 ClosePrinter(spool_data
);
1716 if (!(ret
= ReadPrinter(spool_data
, &header
, sizeof(header
), &r
)))
1718 if (r
!= sizeof(header
))
1720 SetLastError(ERROR_INVALID_DATA
);
1725 if (header
.dwVersion
!= EMFSPOOL_VERSION
)
1727 FIXME("unrecognized spool file format\n");
1728 SetLastError(ERROR_INTERNAL_ERROR
);
1731 pos
.QuadPart
= header
.cjSize
;
1732 if (!(ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_BEGIN
, FALSE
)))
1735 data
->pdev
->job
.hprinter
= data
->hport
;
1736 if (!PSDRV_WriteHeader(&data
->pdev
->dev
, data
->doc_name
))
1738 WARN("Failed to write header\n");
1741 data
->pdev
->job
.banding
= FALSE
;
1742 data
->pdev
->job
.OutOfPage
= TRUE
;
1743 data
->pdev
->job
.PageNo
= 0;
1744 data
->pdev
->job
.quiet
= FALSE
;
1745 data
->pdev
->job
.passthrough_state
= passthrough_none
;
1746 data
->pdev
->job
.doc_name
= strdupW(data
->doc_name
);
1750 if (!(ret
= ReadPrinter(spool_data
, &record
, sizeof(record
), &r
)))
1754 if (r
!= sizeof(record
))
1756 SetLastError(ERROR_INVALID_DATA
);
1761 switch (record
.ulID
)
1763 case EMRI_METAFILE_DATA
:
1764 pos
.QuadPart
= record
.cjSize
;
1765 ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_CURRENT
, FALSE
);
1769 case EMRI_METAFILE_EXT
:
1770 case EMRI_BW_METAFILE_EXT
:
1772 ret
= SeekPrinter(spool_data
, pos
, &cur
, FILE_CURRENT
, FALSE
);
1775 cur
.QuadPart
+= record
.cjSize
;
1776 ret
= ReadPrinter(spool_data
, &pos
, sizeof(pos
), &r
);
1777 if (r
!= sizeof(pos
))
1779 SetLastError(ERROR_INVALID_DATA
);
1783 pos
.QuadPart
= -pos
.QuadPart
- 2 * sizeof(record
);
1785 ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_CURRENT
, FALSE
);
1787 ret
= print_metafile(data
, spool_data
);
1789 ret
= SeekPrinter(spool_data
, cur
, NULL
, FILE_BEGIN
, FALSE
);
1794 FIXME("%s not supported, skipping\n", debugstr_rec_type(record
.ulID
));
1795 pos
.QuadPart
= record
.cjSize
;
1796 ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_CURRENT
, FALSE
);
1804 if (data
->pdev
->job
.PageNo
)
1805 PSDRV_WriteFooter(&data
->pdev
->dev
);
1807 HeapFree(GetProcessHeap(), 0, data
->pdev
->job
.doc_name
);
1808 ClosePrinter(spool_data
);
1809 return EndDocPrinter(data
->hport
) && ret
;
1812 BOOL WINAPI
ControlPrintProcessor(HANDLE pp
, DWORD cmd
)
1814 FIXME("%p, %ld\n", pp
, cmd
);
1815 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1819 BOOL WINAPI
ClosePrintProcessor(HANDLE pp
)
1821 struct pp_data
*data
= get_handle_data(pp
);
1828 ClosePrinter(data
->hport
);
1829 free(data
->doc_name
);
1830 free(data
->out_file
);
1831 DeleteDC(data
->pdev
->dev
.hdc
);
1832 HeapFree(GetProcessHeap(), 0, data
->pdev
->Devmode
);
1833 HeapFree(GetProcessHeap(), 0, data
->pdev
);
1835 memset(data
, 0, sizeof(*data
));
1840 HRESULT WINAPI
DllRegisterServer(void)
1842 AddPrintProcessorW(NULL
, (WCHAR
*)L
"Windows 4.0", (WCHAR
*)L
"wineps.drv", (WCHAR
*)L
"wineps");
1843 AddPrintProcessorW(NULL
, NULL
, (WCHAR
*)L
"wineps.drv", (WCHAR
*)L
"wineps");