wineps: Handle EMR_STROKEANDFILLPATH record in spool files.
[wine.git] / dlls / wineps.drv / printproc.c
blob69e92dca28f5bb6badbcea12c5968db67a21dba5
1 /*
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
21 #include <math.h>
22 #include <stdlib.h>
24 #include <windows.h>
25 #include <winspool.h>
26 #include <ddk/winsplp.h>
28 #include "psdrv.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
34 #define EMFSPOOL_VERSION 0x10000
35 #define PP_MAGIC 0x952173fe
37 struct pp_data
39 DWORD magic;
40 HANDLE hport;
41 WCHAR *doc_name;
42 WCHAR *out_file;
43 PSDRV_PDEVICE *pdev;
44 DWORD brush;
45 struct brush_pattern *patterns;
46 BOOL path;
49 typedef enum
51 EMRI_METAFILE = 1,
52 EMRI_ENGINE_FONT,
53 EMRI_DEVMODE,
54 EMRI_TYPE1_FONT,
55 EMRI_PRESTARTPAGE,
56 EMRI_DESIGNVECTOR,
57 EMRI_SUBSET_FONT,
58 EMRI_DELTA_FONT,
59 EMRI_FORM_METAFILE,
60 EMRI_BW_METAFILE,
61 EMRI_BW_FORM_METAFILE,
62 EMRI_METAFILE_DATA,
63 EMRI_METAFILE_EXT,
64 EMRI_BW_METAFILE_EXT,
65 EMRI_ENGINE_FONT_EXT,
66 EMRI_TYPE1_FONT_EXT,
67 EMRI_DESIGNVECTOR_EXT,
68 EMRI_SUBSET_FONT_EXT,
69 EMRI_DELTA_FONT_EXT,
70 EMRI_PS_JOB_DATA,
71 EMRI_EMBED_FONT_EXT,
72 } record_type;
74 typedef struct
76 unsigned int dwVersion;
77 unsigned int cjSize;
78 unsigned int dpszDocName;
79 unsigned int dpszOutput;
80 } emfspool_header;
82 typedef struct
84 unsigned int ulID;
85 unsigned int cjSize;
86 } record_hdr;
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)
95 switch (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);
118 default:
119 FIXME("unknown record type: %d\n", id);
120 return NULL;
123 #undef EMRICASE
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);
132 return NULL;
134 return ret;
137 static inline INT GDI_ROUND(double val)
139 return (int)floor(val + 0.5);
142 static void translate(RECT *rect, const XFORM *xform)
144 double x, y;
146 x = rect->left;
147 y = rect->top;
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);
151 x = rect->right;
152 y = rect->bottom;
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)
159 rect->left = x;
160 rect->right = x + width;
161 rect->top = y;
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)
171 int tmp = rect->top;
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;
183 rect->right = tmp;
185 if (rect->top > rect->bottom)
187 int tmp = rect->top;
188 rect->top = rect->bottom;
189 rect->bottom = tmp;
193 static BOOL intersect_vis_rectangles(struct bitblt_coords *dst, struct bitblt_coords *src)
195 RECT rect;
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 */
209 rect = src->visrect;
210 OffsetRect(&rect,
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;
217 order_rect(&rect);
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 */
238 rect.left--;
239 rect.top--;
240 rect.right++;
241 rect.bottom++;
242 if (!IntersectRect(&dst->visrect, &rect, &dst->visrect)) return FALSE;
244 /* map destination rectangle back to source coordinates */
245 rect = dst->visrect;
246 OffsetRect(&rect,
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;
253 order_rect(&rect);
255 /* avoid rounding errors */
256 rect.left--;
257 rect.top--;
258 rect.right++;
259 rect.bottom++;
260 if (!IntersectRect(&src->visrect, &rect, &src->visrect)) return FALSE;
262 return TRUE;
265 static void clip_visrect(HDC hdc, RECT *dst, const RECT *src)
267 HRGN hrgn;
269 hrgn = CreateRectRgn(0, 0, 0, 0);
270 if (GetRandomRgn(hdc, hrgn, 3) == 1)
272 GetRgnBox(hrgn, dst);
273 IntersectRect(dst, dst, src);
275 else
277 *dst = *src;
279 DeleteObject(hrgn);
282 static void get_vis_rectangles(HDC hdc, struct bitblt_coords *dst,
283 const XFORM *xform, DWORD width, DWORD height, struct bitblt_coords *src)
285 RECT rect;
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);
292 dst->x = rect.left;
293 dst->y = rect.top;
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);
304 if (!src) return;
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);
311 src->x = rect.left;
312 src->y = rect.top;
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);
316 src->visrect = rect;
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;
328 DWORD err;
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;
338 if (!blt->cbBmiSrc)
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;
348 src.layout = 0;
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);
360 HBITMAP bitmap;
362 bits.is_copy = TRUE;
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);
368 DeleteObject(hdc);
371 if (err != ERROR_SUCCESS)
372 FIXME("PutImage returned %ld\n", err);
373 return !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;
387 BYTE *bits;
388 EMRSTRETCHBLT blt;
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,
522 if (!p->cbBmiMask)
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);
530 blt.xSrc = p->xSrc;
531 blt.ySrc = p->ySrc;
532 blt.xformSrc = p->xformSrc;
533 blt.crBkColorSrc = p->crBkColorSrc;
534 blt.iUsageSrc = p->iUsageSrc;
535 blt.offBmiSrc = 0;
536 blt.cbBmiSrc = p->cbBmiSrc;
537 blt.offBitsSrc = 0;
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);
563 DeleteObject(bmp1);
564 brush_dest = SelectObject(dev->hdc, GetStockObject(NULL_BRUSH));
566 /* make bitmap */
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);
576 /* make bitmap */
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);
599 /* blit to dst */
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;
605 blt.dwRop = SRCCOPY;
606 blt.xSrc = 0;
607 blt.ySrc = 0;
608 GetTransform(hdc2, 0x204, &blt.xformSrc);
609 blt.crBkColorSrc = p->crBkColorSrc;
610 blt.iUsageSrc = DIB_RGB_COLORS;
611 blt.offBmiSrc = 0;
612 blt.cbBmiSrc = bmp2_info->bmiHeader.biSize;
613 blt.offBitsSrc = 0;
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 */
627 DeleteObject(bmp1);
628 DeleteObject(bmp2);
629 DeleteObject(bmp_src);
630 DeleteObject(brush_mask);
632 DeleteObject(hdc1);
633 DeleteObject(hdc2);
634 DeleteObject(hdc_src);
636 return TRUE;
639 static void combine_transform(XFORM *result, const XFORM *xform1, const XFORM *xform2)
641 XFORM r;
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;
652 *result = r;
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;
660 EMRMASKBLT maskblt;
661 /* rect coords */
662 POINT rect[3];
663 /* parallelogram coords */
664 POINT plg[3];
665 double det;
667 memcpy(plg, p->aptlDest, sizeof(plg));
668 rect[0].x = p->xSrc;
669 rect[0].y = p->ySrc;
670 rect[1].x = p->xSrc + p->cxSrc;
671 rect[1].y = p->ySrc;
672 rect[2].x = p->xSrc;
673 rect[2].y = p->ySrc + p->cySrc;
674 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
675 /* determinant */
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)
679 return TRUE;
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);
684 /* X components */
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)
690 ) / det;
692 /* Y components */
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)
698 ) / det;
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);
733 return TRUE;
736 static int poly_draw(PHYSDEV dev, const POINT *points, const BYTE *types, DWORD count)
738 POINT first, cur, pts[4];
739 DWORD i, num_pts;
741 /* check for valid point types */
742 for (i = 0; i < count; i++)
744 switch (types[i])
746 case PT_MOVETO:
747 case PT_LINETO | PT_CLOSEFIGURE:
748 case PT_LINETO:
749 break;
750 case PT_BEZIERTO:
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;
754 i += 2;
755 break;
756 default:
757 return FALSE;
761 GetCurrentPositionEx(dev->hdc, &cur);
762 first = cur;
764 for (i = 0; i < count; i++)
766 switch (types[i])
768 case PT_MOVETO:
769 first = points[i];
770 break;
771 case PT_LINETO:
772 case (PT_LINETO | PT_CLOSEFIGURE):
773 pts[0] = cur;
774 pts[1] = points[i];
775 num_pts = 2;
776 if (!PSDRV_PolyPolyline(dev, pts, &num_pts, 1))
777 return FALSE;
778 break;
779 case PT_BEZIERTO:
780 pts[0] = cur;
781 pts[1] = points[i];
782 pts[2] = points[i + 1];
783 pts[3] = points[i + 2];
784 if (!PSDRV_PolyBezier(dev, pts, 4))
785 return FALSE;
786 i += 2;
787 break;
790 cur = points[i];
791 if (types[i] & PT_CLOSEFIGURE)
793 pts[0] = cur;
794 pts[1] = first;
795 num_pts = 2;
796 if (!PSDRV_PolyPolyline(dev, pts, &num_pts, 1))
797 return FALSE;
801 return TRUE;
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;
818 BOOL ret = FALSE;
819 TRIVERTEX *pts;
820 unsigned int i;
821 HDC hdc_src;
822 HRGN rgn;
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);
859 if (!hdc_src)
861 free(pts);
862 return FALSE;
864 bmp = CreateDIBSection(hdc_src, info, DIB_RGB_COLORS, &bits.ptr, NULL, 0);
865 if (!bmp)
867 DeleteObject(hdc_src);
868 free(pts);
869 return FALSE;
871 old_bmp = SelectObject(hdc_src, bmp);
873 /* make src and points relative to the bitmap */
874 src = dst;
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;
891 POINT triangle[3];
892 HRGN tmp;
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);
904 DeleteObject(tmp);
907 else
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);
918 DeleteObject(tmp);
920 free(pts);
922 OffsetRgn(rgn, dst.visrect.left, dst.visrect.top);
923 if (ret)
924 ret = (PSDRV_PutImage(dev, rgn, info, &bits, &src, &dst, SRCCOPY) == ERROR_SUCCESS);
925 DeleteObject(rgn);
926 DeleteObject(bmp);
927 return ret;
930 static HGDIOBJ get_object_handle(struct pp_data *data, HANDLETABLE *handletable,
931 DWORD i, struct brush_pattern **pattern)
933 if (i & 0x80000000)
935 *pattern = NULL;
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;
945 HBRUSH hbrush;
946 int ret;
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);
953 return ret;
956 static BOOL is_path_record(int type)
958 switch(type)
960 case EMR_POLYBEZIER:
961 case EMR_POLYGON:
962 case EMR_POLYLINE:
963 case EMR_POLYBEZIERTO:
964 case EMR_POLYLINETO:
965 case EMR_POLYPOLYLINE:
966 case EMR_POLYPOLYGON:
967 case EMR_MOVETOEX:
968 case EMR_ANGLEARC:
969 case EMR_ELLIPSE:
970 case EMR_RECTANGLE:
971 case EMR_ROUNDRECT:
972 case EMR_ARC:
973 case EMR_CHORD:
974 case EMR_PIE:
975 case EMR_LINETO:
976 case EMR_ARCTO:
977 case EMR_POLYDRAW:
978 case EMR_EXTTEXTOUTA:
979 case EMR_EXTTEXTOUTW:
980 case EMR_POLYBEZIER16:
981 case EMR_POLYGON16:
982 case EMR_POLYLINE16:
983 case EMR_POLYBEZIERTO16:
984 case EMR_POLYLINETO16:
985 case EMR_POLYPOLYLINE16:
986 case EMR_POLYPOLYGON16:
987 case EMR_POLYDRAW16:
988 return TRUE;
989 default:
990 return FALSE;
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);
1002 switch (rec->iType)
1004 case EMR_HEADER:
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);
1017 case EMR_POLYGON:
1019 const EMRPOLYGON *p = (const EMRPOLYGON *)rec;
1021 return PSDRV_PolyPolygon(&data->pdev->dev, (const POINT *)p->aptl,
1022 (const INT *)&p->cptl, 1);
1024 case EMR_POLYLINE:
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;
1041 POINT *pts;
1042 DWORD cnt;
1043 int ret;
1045 cnt = p->cptl + 1;
1046 pts = malloc(sizeof(*pts) * cnt);
1047 if (!pts) return 0;
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);
1053 free(pts);
1054 return ret;
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);
1072 case EMR_EOF:
1073 return PSDRV_EndPage(&data->pdev->dev);
1074 case EMR_SETPIXELV:
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;
1085 HGDIOBJ obj;
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;
1093 case OBJ_BRUSH:
1094 if (PSDRV_SelectBrush(&data->pdev->dev, obj, pattern))
1096 data->brush = so->ihObject;
1097 return 1;
1099 return 0;
1100 default:
1101 FIXME("unhandled object type %ld\n", GetObjectType(obj));
1102 return 1;
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);
1112 case EMR_ANGLEARC:
1114 const EMRANGLEARC *p = (const EMRANGLEARC *)rec;
1115 int arc_dir = SetArcDirection(data->pdev->dev.hdc,
1116 p->eSweepAngle >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE);
1117 EMRARCTO arcto;
1118 int ret;
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);
1136 return ret;
1138 case EMR_ELLIPSE:
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);
1145 case EMR_RECTANGLE:
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);
1152 case EMR_ROUNDRECT:
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);
1160 case EMR_ARC:
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);
1168 case EMR_CHORD:
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);
1176 case EMR_PIE:
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);
1184 case EMR_LINETO:
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);
1191 case EMR_ARCTO:
1193 const EMRARCTO *p = (const EMRARCTO *)rec;
1194 POINT pt;
1195 BOOL ret;
1197 ret = GetCurrentPositionEx(data->pdev->dev.hdc, &pt);
1198 if (ret)
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);
1204 if (ret)
1205 ret = PSDRV_LineTo(&data->pdev->dev, pt.x, pt.y);
1206 if (ret)
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);
1212 if (ret)
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);
1218 return ret;
1220 case EMR_POLYDRAW:
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);
1228 case EMR_BEGINPATH:
1230 data->path = TRUE;
1231 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n);
1233 case EMR_ENDPATH:
1235 data->path = FALSE;
1236 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n);
1238 case EMR_FILLPATH:
1239 return PSDRV_FillPath(&data->pdev->dev);
1240 case EMR_STROKEANDFILLPATH:
1241 return PSDRV_StrokeAndFillPath(&data->pdev->dev);
1242 case EMR_ABORTPATH:
1244 data->path = FALSE;
1245 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n);
1247 case EMR_FILLRGN:
1249 const EMRFILLRGN *p = (const EMRFILLRGN *)rec;
1250 HRGN rgn;
1251 int ret;
1253 rgn = ExtCreateRegion(NULL, p->cbRgnData, (const RGNDATA *)p->RgnData);
1254 ret = fill_rgn(data, htable, p->ihBrush, rgn);
1255 DeleteObject(rgn);
1256 return ret;
1258 case EMR_FRAMERGN:
1260 const EMRFRAMERGN *p = (const EMRFRAMERGN *)rec;
1261 HRGN rgn, frame;
1262 int ret;
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);
1279 DeleteObject(rgn);
1280 DeleteObject(frame);
1281 return ret;
1283 case EMR_INVERTRGN:
1285 const EMRINVERTRGN *p = (const EMRINVERTRGN *)rec;
1286 int old_rop, ret;
1287 HRGN rgn;
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);
1293 DeleteObject(rgn);
1294 return ret;
1296 case EMR_PAINTRGN:
1298 const EMRPAINTRGN *p = (const EMRPAINTRGN *)rec;
1299 HRGN rgn = ExtCreateRegion(NULL, p->cbRgnData, (const RGNDATA *)p->RgnData);
1300 int ret;
1302 ret = PSDRV_PaintRgn(&data->pdev->dev, rgn);
1303 DeleteObject(rgn);
1304 return ret;
1306 case EMR_BITBLT:
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;
1311 EMRSTRETCHBLT blt;
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;
1320 blt.xSrc = p->xSrc;
1321 blt.ySrc = p->ySrc;
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);
1342 case EMR_MASKBLT:
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);
1352 case EMR_PLGBLT:
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;
1361 POINT *pts;
1362 int i;
1364 pts = malloc(sizeof(*pts) * p->cpts);
1365 if (!pts) return 0;
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);
1372 free(pts);
1373 return i;
1375 case EMR_POLYGON16:
1377 const EMRPOLYGON16 *p = (const EMRPOLYGON16 *)rec;
1378 POINT *pts;
1379 int i;
1381 pts = malloc(sizeof(*pts) * p->cpts);
1382 if (!pts) return 0;
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);
1389 free(pts);
1390 return i;
1392 case EMR_POLYLINE16:
1394 const EMRPOLYLINE16 *p = (const EMRPOLYLINE16 *)rec;
1395 POINT *pts;
1396 int i;
1398 pts = malloc(sizeof(*pts) * p->cpts);
1399 if (!pts) return 0;
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);
1406 free(pts);
1407 return i;
1409 case EMR_POLYBEZIERTO16:
1411 const EMRPOLYBEZIERTO16 *p = (const EMRPOLYBEZIERTO16 *)rec;
1412 POINT *pts;
1413 int i;
1415 pts = malloc(sizeof(*pts) * p->cpts);
1416 if (!pts) return 0;
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);
1424 free(pts);
1425 return i;
1427 case EMR_POLYLINETO16:
1429 const EMRPOLYLINETO16 *p = (const EMRPOLYLINETO16 *)rec;
1430 POINT *pts;
1431 DWORD cnt;
1432 int i;
1434 cnt = p->cpts + 1;
1435 pts = malloc(sizeof(*pts) * cnt);
1436 if (!pts) return 0;
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);
1445 free(pts);
1446 return i;
1448 case EMR_POLYPOLYLINE16:
1450 const EMRPOLYPOLYLINE16 *p = (const EMRPOLYPOLYLINE16 *)rec;
1451 POINT *pts;
1452 int i;
1454 pts = malloc(sizeof(*pts) * p->cpts);
1455 if (!pts) return 0;
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);
1462 free(pts);
1463 return i;
1465 case EMR_POLYPOLYGON16:
1467 const EMRPOLYPOLYGON16 *p = (const EMRPOLYPOLYGON16 *)rec;
1468 POINT *pts;
1469 int i;
1471 pts = malloc(sizeof(*pts) * p->cpts);
1472 if (!pts) return 0;
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);
1479 free(pts);
1480 return i;
1482 case EMR_POLYDRAW16:
1484 const EMRPOLYDRAW16 *p = (const EMRPOLYDRAW16 *)rec;
1485 POINT *pts;
1486 int i;
1488 pts = malloc(sizeof(*pts) * p->cpts);
1489 if (!pts) return 0;
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);
1497 free(pts);
1498 return i;
1500 case EMR_CREATEMONOBRUSH:
1502 const EMRCREATEMONOBRUSH *p = (const EMRCREATEMONOBRUSH *)rec;
1504 if (!PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n))
1505 return 0;
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;
1509 return 1;
1511 case EMR_CREATEDIBPATTERNBRUSHPT:
1513 const EMRCREATEDIBPATTERNBRUSHPT *p = (const EMRCREATEDIBPATTERNBRUSHPT *)rec;
1515 if (!PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n))
1516 return 0;
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;
1520 return 1;
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:
1535 case EMR_SETROP2:
1536 case EMR_SETSTRETCHBLTMODE:
1537 case EMR_SETTEXTALIGN:
1538 case EMR_OFFSETCLIPRGN:
1539 case EMR_MOVETOEX:
1540 case EMR_EXCLUDECLIPRECT:
1541 case EMR_INTERSECTCLIPRECT:
1542 case EMR_SCALEVIEWPORTEXTEX:
1543 case EMR_SCALEWINDOWEXTEX:
1544 case EMR_SETWORLDTRANSFORM:
1545 case EMR_MODIFYWORLDTRANSFORM:
1546 case EMR_CREATEPEN:
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);
1552 default:
1553 FIXME("unsupported record: %ld\n", rec->iType);
1556 return 1;
1559 static BOOL print_metafile(struct pp_data *data, HANDLE hdata)
1561 record_hdr header;
1562 HENHMETAFILE hmf;
1563 BYTE *buf;
1564 BOOL ret;
1565 DWORD r;
1567 if (!ReadPrinter(hdata, &header, sizeof(header), &r))
1568 return FALSE;
1569 if (r != sizeof(header))
1571 SetLastError(ERROR_INVALID_DATA);
1572 return FALSE;
1575 buf = malloc(header.cjSize);
1576 if (!buf)
1577 return FALSE;
1579 if (!ReadPrinter(hdata, buf, header.cjSize, &r))
1581 free(buf);
1582 return FALSE;
1584 if (r != header.cjSize)
1586 free(buf);
1587 SetLastError(ERROR_INVALID_DATA);
1588 return FALSE;
1591 hmf = SetEnhMetaFileBits(header.cjSize, buf);
1592 free(buf);
1593 if (!hmf)
1594 return FALSE;
1596 ret = EnumEnhMetaFile(NULL, hmf, hmf_proc, (void *)data, NULL);
1597 DeleteEnhMetaFile(hmf);
1598 free(data->patterns);
1599 data->patterns = NULL;
1600 return ret;
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);
1611 if (!needed || !no)
1613 SetLastError(ERROR_INVALID_PARAMETER);
1614 return FALSE;
1617 *no = 0;
1618 *needed = sizeof(*info) + sizeof(emf_1003);
1620 if (level != 1 || (size && !datatypes))
1622 SetLastError(ERROR_INVALID_PARAMETER);
1623 return FALSE;
1626 if (size < *needed)
1628 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1629 return FALSE;
1632 *no = 1;
1633 info->pName = (WCHAR*)(info + 1);
1634 memcpy(info + 1, emf_1003, sizeof(emf_1003));
1635 return TRUE;
1638 HANDLE WINAPI OpenPrintProcessor(WCHAR *port, PRINTPROCESSOROPENDATA *open_data)
1640 struct pp_data *data;
1641 HANDLE hport;
1642 HDC hdc;
1644 TRACE("%s, %p\n", debugstr_w(port), open_data);
1646 if (!port || !open_data || !open_data->pDatatype)
1648 SetLastError(ERROR_INVALID_PARAMETER);
1649 return NULL;
1651 if (wcscmp(open_data->pDatatype, emf_1003))
1653 SetLastError(ERROR_INVALID_DATATYPE);
1654 return NULL;
1657 if (!OpenPrinterW(port, &hport, NULL))
1658 return NULL;
1660 data = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*data));
1661 if (!data)
1662 return NULL;
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);
1669 if (!hdc)
1671 LocalFree(data);
1672 return NULL;
1674 SetGraphicsMode(hdc, GM_ADVANCED);
1675 data->pdev = create_psdrv_physdev(hdc, open_data->pPrinterName,
1676 (const PSDRV_DEVMODE *)open_data->pDevMode);
1677 if (!data->pdev)
1679 DeleteDC(hdc);
1680 LocalFree(data);
1681 return NULL;
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;
1692 record_hdr record;
1693 HANDLE spool_data;
1694 DOC_INFO_1W info;
1695 BOOL ret;
1696 DWORD r;
1698 TRACE("%p, %s\n", pp, debugstr_w(doc_name));
1700 if (!data)
1701 return FALSE;
1703 if (!OpenPrinterW(doc_name, &spool_data, NULL))
1704 return FALSE;
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);
1713 return FALSE;
1716 if (!(ret = ReadPrinter(spool_data, &header, sizeof(header), &r)))
1717 goto cleanup;
1718 if (r != sizeof(header))
1720 SetLastError(ERROR_INVALID_DATA);
1721 ret = FALSE;
1722 goto cleanup;
1725 if (header.dwVersion != EMFSPOOL_VERSION)
1727 FIXME("unrecognized spool file format\n");
1728 SetLastError(ERROR_INTERNAL_ERROR);
1729 goto cleanup;
1731 pos.QuadPart = header.cjSize;
1732 if (!(ret = SeekPrinter(spool_data, pos, NULL, FILE_BEGIN, FALSE)))
1733 goto cleanup;
1735 data->pdev->job.hprinter = data->hport;
1736 if (!PSDRV_WriteHeader(&data->pdev->dev, data->doc_name))
1738 WARN("Failed to write header\n");
1739 goto cleanup;
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);
1748 while (1)
1750 if (!(ret = ReadPrinter(spool_data, &record, sizeof(record), &r)))
1751 goto cleanup;
1752 if (!r)
1753 break;
1754 if (r != sizeof(record))
1756 SetLastError(ERROR_INVALID_DATA);
1757 ret = FALSE;
1758 goto cleanup;
1761 switch (record.ulID)
1763 case EMRI_METAFILE_DATA:
1764 pos.QuadPart = record.cjSize;
1765 ret = SeekPrinter(spool_data, pos, NULL, FILE_CURRENT, FALSE);
1766 if (!ret)
1767 goto cleanup;
1768 break;
1769 case EMRI_METAFILE_EXT:
1770 case EMRI_BW_METAFILE_EXT:
1771 pos.QuadPart = 0;
1772 ret = SeekPrinter(spool_data, pos, &cur, FILE_CURRENT, FALSE);
1773 if (ret)
1775 cur.QuadPart += record.cjSize;
1776 ret = ReadPrinter(spool_data, &pos, sizeof(pos), &r);
1777 if (r != sizeof(pos))
1779 SetLastError(ERROR_INVALID_DATA);
1780 ret = FALSE;
1783 pos.QuadPart = -pos.QuadPart - 2 * sizeof(record);
1784 if (ret)
1785 ret = SeekPrinter(spool_data, pos, NULL, FILE_CURRENT, FALSE);
1786 if (ret)
1787 ret = print_metafile(data, spool_data);
1788 if (ret)
1789 ret = SeekPrinter(spool_data, cur, NULL, FILE_BEGIN, FALSE);
1790 if (!ret)
1791 goto cleanup;
1792 break;
1793 default:
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);
1797 if (!ret)
1798 goto cleanup;
1799 break;
1803 cleanup:
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);
1816 return FALSE;
1819 BOOL WINAPI ClosePrintProcessor(HANDLE pp)
1821 struct pp_data *data = get_handle_data(pp);
1823 TRACE("%p\n", pp);
1825 if (!data)
1826 return FALSE;
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));
1836 LocalFree(data);
1837 return TRUE;
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");
1844 return S_OK;