wineps: Reset memory DC state on every page.
[wine.git] / dlls / wineps.drv / printproc.c
blob914fc23f69e79440d2d50d23e780ef8a7b00245c
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 <ntgdi.h>
26 #include <winspool.h>
27 #include <ddk/winsplp.h>
28 #include <usp10.h>
30 #include "psdrv.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
36 #define EMFSPOOL_VERSION 0x10000
37 #define PP_MAGIC 0x952173fe
39 struct pp_data
41 DWORD magic;
42 HANDLE hport;
43 WCHAR *doc_name;
44 WCHAR *out_file;
46 PSDRV_PDEVICE *pdev;
47 struct gdi_physdev font_dev;
49 struct brush_pattern *patterns;
50 BOOL path;
51 INT break_extra;
52 INT break_rem;
54 INT saved_dc_size;
55 INT saved_dc_top;
56 struct
58 INT break_extra;
59 INT break_rem;
60 } *saved_dc;
63 typedef enum
65 EMRI_METAFILE = 1,
66 EMRI_ENGINE_FONT,
67 EMRI_DEVMODE,
68 EMRI_TYPE1_FONT,
69 EMRI_PRESTARTPAGE,
70 EMRI_DESIGNVECTOR,
71 EMRI_SUBSET_FONT,
72 EMRI_DELTA_FONT,
73 EMRI_FORM_METAFILE,
74 EMRI_BW_METAFILE,
75 EMRI_BW_FORM_METAFILE,
76 EMRI_METAFILE_DATA,
77 EMRI_METAFILE_EXT,
78 EMRI_BW_METAFILE_EXT,
79 EMRI_ENGINE_FONT_EXT,
80 EMRI_TYPE1_FONT_EXT,
81 EMRI_DESIGNVECTOR_EXT,
82 EMRI_SUBSET_FONT_EXT,
83 EMRI_DELTA_FONT_EXT,
84 EMRI_PS_JOB_DATA,
85 EMRI_EMBED_FONT_EXT,
86 } record_type;
88 typedef struct
90 unsigned int dwVersion;
91 unsigned int cjSize;
92 unsigned int dpszDocName;
93 unsigned int dpszOutput;
94 } emfspool_header;
96 typedef struct
98 unsigned int ulID;
99 unsigned int cjSize;
100 } record_hdr;
102 typedef struct
104 EMR emr;
105 INT break_extra;
106 INT break_count;
107 } EMRSETTEXTJUSTIFICATION;
109 BOOL WINAPI SeekPrinter(HANDLE, LARGE_INTEGER, LARGE_INTEGER*, DWORD, BOOL);
111 static const WCHAR emf_1003[] = L"NT EMF 1.003";
113 #define EMRICASE(x) case x: return #x
114 static const char * debugstr_rec_type(int id)
116 switch (id)
118 EMRICASE(EMRI_METAFILE);
119 EMRICASE(EMRI_ENGINE_FONT);
120 EMRICASE(EMRI_DEVMODE);
121 EMRICASE(EMRI_TYPE1_FONT);
122 EMRICASE(EMRI_PRESTARTPAGE);
123 EMRICASE(EMRI_DESIGNVECTOR);
124 EMRICASE(EMRI_SUBSET_FONT);
125 EMRICASE(EMRI_DELTA_FONT);
126 EMRICASE(EMRI_FORM_METAFILE);
127 EMRICASE(EMRI_BW_METAFILE);
128 EMRICASE(EMRI_BW_FORM_METAFILE);
129 EMRICASE(EMRI_METAFILE_DATA);
130 EMRICASE(EMRI_METAFILE_EXT);
131 EMRICASE(EMRI_BW_METAFILE_EXT);
132 EMRICASE(EMRI_ENGINE_FONT_EXT);
133 EMRICASE(EMRI_TYPE1_FONT_EXT);
134 EMRICASE(EMRI_DESIGNVECTOR_EXT);
135 EMRICASE(EMRI_SUBSET_FONT_EXT);
136 EMRICASE(EMRI_DELTA_FONT_EXT);
137 EMRICASE(EMRI_PS_JOB_DATA);
138 EMRICASE(EMRI_EMBED_FONT_EXT);
139 default:
140 FIXME("unknown record type: %d\n", id);
141 return NULL;
144 #undef EMRICASE
146 static struct pp_data* get_handle_data(HANDLE pp)
148 struct pp_data *ret = (struct pp_data *)pp;
150 if (!ret || ret->magic != PP_MAGIC)
152 SetLastError(ERROR_INVALID_HANDLE);
153 return NULL;
155 return ret;
158 static BOOL CDECL font_EnumFonts(PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lp)
160 return EnumFontFamiliesExW(dev->hdc, lf, proc, lp, 0);
163 static BOOL CDECL font_GetCharWidth(PHYSDEV dev, UINT first, UINT count, const WCHAR *chars, INT *buffer)
165 XFORM old, xform = { .eM11 = 1.0f };
166 BOOL ret;
168 GetWorldTransform(dev->hdc, &old);
169 SetWorldTransform(dev->hdc, &xform);
170 ret = NtGdiGetCharWidthW(dev->hdc, first, count, (WCHAR *)chars, NTGDI_GETCHARWIDTH_INT, buffer);
171 SetWorldTransform(dev->hdc, &old);
172 return ret;
175 static BOOL CDECL font_GetTextExtentExPoint(PHYSDEV dev, const WCHAR *str, INT count, INT *dxs)
177 SIZE size;
178 return GetTextExtentExPointW(dev->hdc, str, count, -1, NULL, dxs, &size);
181 static BOOL CDECL font_GetTextMetrics(PHYSDEV dev, TEXTMETRICW *metrics)
183 return GetTextMetricsW(dev->hdc, metrics);
186 static HFONT CDECL font_SelectFont(PHYSDEV dev, HFONT hfont, UINT *aa_flags)
188 *aa_flags = GGO_BITMAP;
189 return SelectObject(dev->hdc, hfont) ? hfont : 0;
192 static const struct gdi_dc_funcs font_funcs =
194 .pEnumFonts = font_EnumFonts,
195 .pGetCharWidth = font_GetCharWidth,
196 .pGetTextExtentExPoint = font_GetTextExtentExPoint,
197 .pGetTextMetrics = font_GetTextMetrics,
198 .pSelectFont = font_SelectFont,
199 .priority = GDI_PRIORITY_FONT_DRV
202 static inline INT GDI_ROUND(double val)
204 return (int)floor(val + 0.5);
207 static void translate(RECT *rect, const XFORM *xform)
209 double x, y;
211 x = rect->left;
212 y = rect->top;
213 rect->left = GDI_ROUND(x * xform->eM11 + y * xform->eM21 + xform->eDx);
214 rect->top = GDI_ROUND(x * xform->eM12 + y * xform->eM22 + xform->eDy);
216 x = rect->right;
217 y = rect->bottom;
218 rect->right = GDI_ROUND(x * xform->eM11 + y * xform->eM21 + xform->eDx);
219 rect->bottom = GDI_ROUND(x * xform->eM12 + y * xform->eM22 + xform->eDy);
222 static inline void get_bounding_rect(RECT *rect, int x, int y, int width, int height)
224 rect->left = x;
225 rect->right = x + width;
226 rect->top = y;
227 rect->bottom = y + height;
228 if (rect->left > rect->right)
230 int tmp = rect->left;
231 rect->left = rect->right + 1;
232 rect->right = tmp + 1;
234 if (rect->top > rect->bottom)
236 int tmp = rect->top;
237 rect->top = rect->bottom + 1;
238 rect->bottom = tmp + 1;
242 static inline void order_rect(RECT *rect)
244 if (rect->left > rect->right)
246 int tmp = rect->left;
247 rect->left = rect->right;
248 rect->right = tmp;
250 if (rect->top > rect->bottom)
252 int tmp = rect->top;
253 rect->top = rect->bottom;
254 rect->bottom = tmp;
258 static BOOL intersect_vis_rectangles(struct bitblt_coords *dst, struct bitblt_coords *src)
260 RECT rect;
262 /* intersect the rectangles */
264 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
266 OffsetRect(&src->visrect, dst->x - src->x, dst->y - src->y);
267 if (!IntersectRect(&rect, &src->visrect, &dst->visrect)) return FALSE;
268 src->visrect = dst->visrect = rect;
269 OffsetRect(&src->visrect, src->x - dst->x, src->y - dst->y);
271 else /* stretching */
273 /* map source rectangle into destination coordinates */
274 rect = src->visrect;
275 OffsetRect(&rect,
276 -src->x - (src->width < 0 ? 1 : 0),
277 -src->y - (src->height < 0 ? 1 : 0));
278 rect.left = rect.left * dst->width / src->width;
279 rect.top = rect.top * dst->height / src->height;
280 rect.right = rect.right * dst->width / src->width;
281 rect.bottom = rect.bottom * dst->height / src->height;
282 order_rect(&rect);
284 /* when the source rectangle needs to flip and it doesn't fit in the source device
285 area, the destination area isn't flipped. So, adjust destination coordinates */
286 if (src->width < 0 && dst->width > 0 &&
287 (src->x + src->width + 1 < src->visrect.left || src->x > src->visrect.right))
288 dst->x += (dst->width - rect.right) - rect.left;
289 else if (src->width > 0 && dst->width < 0 &&
290 (src->x < src->visrect.left || src->x + src->width > src->visrect.right))
291 dst->x -= rect.right - (dst->width - rect.left);
293 if (src->height < 0 && dst->height > 0 &&
294 (src->y + src->height + 1 < src->visrect.top || src->y > src->visrect.bottom))
295 dst->y += (dst->height - rect.bottom) - rect.top;
296 else if (src->height > 0 && dst->height < 0 &&
297 (src->y < src->visrect.top || src->y + src->height > src->visrect.bottom))
298 dst->y -= rect.bottom - (dst->height - rect.top);
300 OffsetRect(&rect, dst->x, dst->y);
302 /* avoid rounding errors */
303 rect.left--;
304 rect.top--;
305 rect.right++;
306 rect.bottom++;
307 if (!IntersectRect(&dst->visrect, &rect, &dst->visrect)) return FALSE;
309 /* map destination rectangle back to source coordinates */
310 rect = dst->visrect;
311 OffsetRect(&rect,
312 -dst->x - (dst->width < 0 ? 1 : 0),
313 -dst->y - (dst->height < 0 ? 1 : 0));
314 rect.left = src->x + rect.left * src->width / dst->width;
315 rect.top = src->y + rect.top * src->height / dst->height;
316 rect.right = src->x + rect.right * src->width / dst->width;
317 rect.bottom = src->y + rect.bottom * src->height / dst->height;
318 order_rect(&rect);
320 /* avoid rounding errors */
321 rect.left--;
322 rect.top--;
323 rect.right++;
324 rect.bottom++;
325 if (!IntersectRect(&src->visrect, &rect, &src->visrect)) return FALSE;
327 return TRUE;
330 static void clip_visrect(HDC hdc, RECT *dst, const RECT *src)
332 HRGN hrgn;
334 hrgn = CreateRectRgn(0, 0, 0, 0);
335 if (GetRandomRgn(hdc, hrgn, 3) == 1)
337 GetRgnBox(hrgn, dst);
338 IntersectRect(dst, dst, src);
340 else
342 *dst = *src;
344 DeleteObject(hrgn);
347 static void get_vis_rectangles(HDC hdc, struct bitblt_coords *dst,
348 const XFORM *xform, DWORD width, DWORD height, struct bitblt_coords *src)
350 RECT rect;
352 rect.left = dst->log_x;
353 rect.top = dst->log_y;
354 rect.right = dst->log_x + dst->log_width;
355 rect.bottom = dst->log_y + dst->log_height;
356 LPtoDP(hdc, (POINT *)&rect, 2);
357 dst->x = rect.left;
358 dst->y = rect.top;
359 dst->width = rect.right - rect.left;
360 dst->height = rect.bottom - rect.top;
361 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
363 dst->x += dst->width;
364 dst->width = -dst->width;
366 get_bounding_rect(&rect, dst->x, dst->y, dst->width, dst->height);
367 clip_visrect(hdc, &dst->visrect, &rect);
369 if (!src) return;
371 rect.left = src->log_x;
372 rect.top = src->log_y;
373 rect.right = src->log_x + src->log_width;
374 rect.bottom = src->log_y + src->log_height;
375 translate(&rect, xform);
376 src->x = rect.left;
377 src->y = rect.top;
378 src->width = rect.right - rect.left;
379 src->height = rect.bottom - rect.top;
380 get_bounding_rect(&rect, src->x, src->y, src->width, src->height);
381 if (rect.left < 0) rect.left = 0;
382 if (rect.top < 0) rect.top = 0;
383 if (rect.right > width) rect.right = width;
384 if (rect.bottom > height) rect.bottom = height;
385 src->visrect = rect;
387 intersect_vis_rectangles(dst, src);
390 static int stretch_blt(PHYSDEV dev, const EMRSTRETCHBLT *blt,
391 const BITMAPINFO *bi, const BYTE *src_bits)
393 char dst_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
394 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
395 struct bitblt_coords src, dst;
396 struct gdi_image_bits bits;
397 DWORD err;
399 dst.log_x = blt->xDest;
400 dst.log_y = blt->yDest;
401 dst.log_width = blt->cxDest;
402 dst.log_height = blt->cyDest;
403 dst.layout = GetLayout(dev->hdc);
404 if (blt->dwRop & NOMIRRORBITMAP)
405 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
407 if (!blt->cbBmiSrc)
409 get_vis_rectangles(dev->hdc, &dst, NULL, 0, 0, NULL);
410 return PSDRV_PatBlt(dev, &dst, blt->dwRop);
413 src.log_x = blt->xSrc;
414 src.log_y = blt->ySrc;
415 src.log_width = blt->cxSrc;
416 src.log_height = blt->cySrc;
417 src.layout = 0;
419 get_vis_rectangles(dev->hdc, &dst, &blt->xformSrc,
420 bi->bmiHeader.biWidth, abs(bi->bmiHeader.biHeight), &src);
422 memcpy(dst_info, bi, blt->cbBmiSrc);
423 memset(&bits, 0, sizeof(bits));
424 bits.ptr = (BYTE *)src_bits;
425 err = PSDRV_PutImage(dev, 0, dst_info, &bits, &src, &dst, blt->dwRop);
426 if (err == ERROR_BAD_FORMAT)
428 HDC hdc = CreateCompatibleDC(NULL);
429 HBITMAP bitmap;
431 bits.is_copy = TRUE;
432 bitmap = CreateDIBSection(hdc, dst_info, DIB_RGB_COLORS, &bits.ptr, NULL, 0);
433 SetDIBits(hdc, bitmap, 0, bi->bmiHeader.biHeight, src_bits, bi, blt->iUsageSrc);
435 err = PSDRV_PutImage(dev, 0, dst_info, &bits, &src, &dst, blt->dwRop);
436 DeleteObject(bitmap);
437 DeleteObject(hdc);
440 if (err != ERROR_SUCCESS)
441 FIXME("PutImage returned %ld\n", err);
442 return !err;
445 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
446 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
448 static int mask_blt(PHYSDEV dev, const EMRMASKBLT *p, const BITMAPINFO *src_bi,
449 const BYTE *src_bits, const BITMAPINFO *mask_bi, const BYTE *mask_bits)
451 HBITMAP bmp1, old_bmp1, bmp2, old_bmp2, bmp_src, old_bmp_src;
452 char bmp2_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
453 BITMAPINFO *bmp2_info = (BITMAPINFO *)bmp2_buffer;
454 HBRUSH brush_mask, brush_dest, old_brush;
455 HDC hdc_src, hdc1, hdc2;
456 BYTE *bits;
457 EMRSTRETCHBLT blt;
459 static const DWORD ROP3Table[256] =
461 0x00000042, 0x00010289,
462 0x00020C89, 0x000300AA,
463 0x00040C88, 0x000500A9,
464 0x00060865, 0x000702C5,
465 0x00080F08, 0x00090245,
466 0x000A0329, 0x000B0B2A,
467 0x000C0324, 0x000D0B25,
468 0x000E08A5, 0x000F0001,
469 0x00100C85, 0x001100A6,
470 0x00120868, 0x001302C8,
471 0x00140869, 0x001502C9,
472 0x00165CCA, 0x00171D54,
473 0x00180D59, 0x00191CC8,
474 0x001A06C5, 0x001B0768,
475 0x001C06CA, 0x001D0766,
476 0x001E01A5, 0x001F0385,
477 0x00200F09, 0x00210248,
478 0x00220326, 0x00230B24,
479 0x00240D55, 0x00251CC5,
480 0x002606C8, 0x00271868,
481 0x00280369, 0x002916CA,
482 0x002A0CC9, 0x002B1D58,
483 0x002C0784, 0x002D060A,
484 0x002E064A, 0x002F0E2A,
485 0x0030032A, 0x00310B28,
486 0x00320688, 0x00330008,
487 0x003406C4, 0x00351864,
488 0x003601A8, 0x00370388,
489 0x0038078A, 0x00390604,
490 0x003A0644, 0x003B0E24,
491 0x003C004A, 0x003D18A4,
492 0x003E1B24, 0x003F00EA,
493 0x00400F0A, 0x00410249,
494 0x00420D5D, 0x00431CC4,
495 0x00440328, 0x00450B29,
496 0x004606C6, 0x0047076A,
497 0x00480368, 0x004916C5,
498 0x004A0789, 0x004B0605,
499 0x004C0CC8, 0x004D1954,
500 0x004E0645, 0x004F0E25,
501 0x00500325, 0x00510B26,
502 0x005206C9, 0x00530764,
503 0x005408A9, 0x00550009,
504 0x005601A9, 0x00570389,
505 0x00580785, 0x00590609,
506 0x005A0049, 0x005B18A9,
507 0x005C0649, 0x005D0E29,
508 0x005E1B29, 0x005F00E9,
509 0x00600365, 0x006116C6,
510 0x00620786, 0x00630608,
511 0x00640788, 0x00650606,
512 0x00660046, 0x006718A8,
513 0x006858A6, 0x00690145,
514 0x006A01E9, 0x006B178A,
515 0x006C01E8, 0x006D1785,
516 0x006E1E28, 0x006F0C65,
517 0x00700CC5, 0x00711D5C,
518 0x00720648, 0x00730E28,
519 0x00740646, 0x00750E26,
520 0x00761B28, 0x007700E6,
521 0x007801E5, 0x00791786,
522 0x007A1E29, 0x007B0C68,
523 0x007C1E24, 0x007D0C69,
524 0x007E0955, 0x007F03C9,
525 0x008003E9, 0x00810975,
526 0x00820C49, 0x00831E04,
527 0x00840C48, 0x00851E05,
528 0x008617A6, 0x008701C5,
529 0x008800C6, 0x00891B08,
530 0x008A0E06, 0x008B0666,
531 0x008C0E08, 0x008D0668,
532 0x008E1D7C, 0x008F0CE5,
533 0x00900C45, 0x00911E08,
534 0x009217A9, 0x009301C4,
535 0x009417AA, 0x009501C9,
536 0x00960169, 0x0097588A,
537 0x00981888, 0x00990066,
538 0x009A0709, 0x009B07A8,
539 0x009C0704, 0x009D07A6,
540 0x009E16E6, 0x009F0345,
541 0x00A000C9, 0x00A11B05,
542 0x00A20E09, 0x00A30669,
543 0x00A41885, 0x00A50065,
544 0x00A60706, 0x00A707A5,
545 0x00A803A9, 0x00A90189,
546 0x00AA0029, 0x00AB0889,
547 0x00AC0744, 0x00AD06E9,
548 0x00AE0B06, 0x00AF0229,
549 0x00B00E05, 0x00B10665,
550 0x00B21974, 0x00B30CE8,
551 0x00B4070A, 0x00B507A9,
552 0x00B616E9, 0x00B70348,
553 0x00B8074A, 0x00B906E6,
554 0x00BA0B09, 0x00BB0226,
555 0x00BC1CE4, 0x00BD0D7D,
556 0x00BE0269, 0x00BF08C9,
557 0x00C000CA, 0x00C11B04,
558 0x00C21884, 0x00C3006A,
559 0x00C40E04, 0x00C50664,
560 0x00C60708, 0x00C707AA,
561 0x00C803A8, 0x00C90184,
562 0x00CA0749, 0x00CB06E4,
563 0x00CC0020, 0x00CD0888,
564 0x00CE0B08, 0x00CF0224,
565 0x00D00E0A, 0x00D1066A,
566 0x00D20705, 0x00D307A4,
567 0x00D41D78, 0x00D50CE9,
568 0x00D616EA, 0x00D70349,
569 0x00D80745, 0x00D906E8,
570 0x00DA1CE9, 0x00DB0D75,
571 0x00DC0B04, 0x00DD0228,
572 0x00DE0268, 0x00DF08C8,
573 0x00E003A5, 0x00E10185,
574 0x00E20746, 0x00E306EA,
575 0x00E40748, 0x00E506E5,
576 0x00E61CE8, 0x00E70D79,
577 0x00E81D74, 0x00E95CE6,
578 0x00EA02E9, 0x00EB0849,
579 0x00EC02E8, 0x00ED0848,
580 0x00EE0086, 0x00EF0A08,
581 0x00F00021, 0x00F10885,
582 0x00F20B05, 0x00F3022A,
583 0x00F40B0A, 0x00F50225,
584 0x00F60265, 0x00F708C5,
585 0x00F802E5, 0x00F90845,
586 0x00FA0089, 0x00FB0A09,
587 0x00FC008A, 0x00FD0A0A,
588 0x00FE02A9, 0x00FF0062,
591 if (!p->cbBmiMask)
593 blt.rclBounds = p->rclBounds;
594 blt.xDest = p->xDest;
595 blt.yDest = p->yDest;
596 blt.cxDest = p->cxDest;
597 blt.cyDest = p->cyDest;
598 blt.dwRop = FRGND_ROP3(p->dwRop);
599 blt.xSrc = p->xSrc;
600 blt.ySrc = p->ySrc;
601 blt.xformSrc = p->xformSrc;
602 blt.crBkColorSrc = p->crBkColorSrc;
603 blt.iUsageSrc = p->iUsageSrc;
604 blt.offBmiSrc = 0;
605 blt.cbBmiSrc = p->cbBmiSrc;
606 blt.offBitsSrc = 0;
607 blt.cbBitsSrc = p->cbBitsSrc;
608 blt.cxSrc = p->cxDest;
609 blt.cySrc = p->cyDest;
611 return stretch_blt(dev, &blt, src_bi, src_bits);
614 hdc_src = CreateCompatibleDC(NULL);
615 SetGraphicsMode(hdc_src, GM_ADVANCED);
616 SetWorldTransform(hdc_src, &p->xformSrc);
617 brush_dest = CreateSolidBrush(p->crBkColorSrc);
618 old_brush = SelectObject(hdc_src, brush_dest);
619 PatBlt(hdc_src, p->rclBounds.left, p->rclBounds.top,
620 p->rclBounds.right - p->rclBounds.left,
621 p->rclBounds.bottom - p->rclBounds.top, PATCOPY);
622 SelectObject(hdc_src, old_brush);
623 DeleteObject(brush_dest);
625 bmp_src = CreateDIBSection(hdc_src, src_bi, p->iUsageSrc, (void **)&bits, NULL, 0);
626 memcpy(bits, src_bits, p->cbBitsSrc);
627 old_bmp_src = SelectObject(hdc_src, bmp_src);
629 bmp1 = CreateBitmap(mask_bi->bmiHeader.biWidth, mask_bi->bmiHeader.biHeight, 1, 1, NULL);
630 SetDIBits(dev->hdc, bmp1, 0, mask_bi->bmiHeader.biHeight, mask_bits, mask_bi, p->iUsageMask);
631 brush_mask = CreatePatternBrush(bmp1);
632 DeleteObject(bmp1);
633 brush_dest = SelectObject(dev->hdc, GetStockObject(NULL_BRUSH));
635 /* make bitmap */
636 hdc1 = CreateCompatibleDC(NULL);
637 bmp1 = CreateBitmap(p->cxDest, p->cyDest, 1, 32, NULL);
638 old_bmp1 = SelectObject(hdc1, bmp1);
640 /* draw using bkgnd rop */
641 old_brush = SelectObject(hdc1, brush_dest);
642 BitBlt(hdc1, 0, 0, p->cxDest, p->cyDest, hdc_src, p->xSrc, p->ySrc, BKGND_ROP3(p->dwRop));
643 SelectObject(hdc1, old_brush);
645 /* make bitmap */
646 hdc2 = CreateCompatibleDC(NULL);
647 bmp2_info->bmiHeader.biSize = sizeof(bmp2_info->bmiHeader);
648 bmp2_info->bmiHeader.biWidth = p->cxDest;
649 bmp2_info->bmiHeader.biHeight = p->cyDest;
650 bmp2_info->bmiHeader.biPlanes = 1;
651 bmp2_info->bmiHeader.biBitCount = 32;
652 bmp2_info->bmiHeader.biCompression = BI_RGB;
653 bmp2_info->bmiHeader.biSizeImage = p->cxDest * p->cyDest * bmp2_info->bmiHeader.biBitCount / 8;
654 bmp2 = CreateDIBSection(hdc2, bmp2_info, DIB_RGB_COLORS, (void **)&bits, NULL, 0);
655 old_bmp2 = SelectObject(hdc2, bmp2);
657 /* draw using foregnd rop */
658 old_brush = SelectObject(hdc2, brush_dest);
659 BitBlt(hdc2, 0, 0, p->cxDest, p->cyDest, hdc_src, p->xSrc, p->ySrc, FRGND_ROP3(p->dwRop));
661 /* combine both using the mask as a pattern brush */
662 SelectObject(hdc2, brush_mask);
663 SetBrushOrgEx(hdc2, -p->xMask, -p->yMask, NULL);
664 /* (D & P) | (S & ~P) */
665 BitBlt(hdc2, 0, 0, p->cxDest, p->cyDest, hdc1, 0, 0, 0xac0744);
666 SelectObject(hdc2, old_brush);
668 /* blit to dst */
669 blt.rclBounds = p->rclBounds;
670 blt.xDest = p->xDest;
671 blt.yDest = p->yDest;
672 blt.cxDest = p->cxDest;
673 blt.cyDest = p->cyDest;
674 blt.dwRop = SRCCOPY;
675 blt.xSrc = 0;
676 blt.ySrc = 0;
677 GetTransform(hdc2, 0x204, &blt.xformSrc);
678 blt.crBkColorSrc = p->crBkColorSrc;
679 blt.iUsageSrc = DIB_RGB_COLORS;
680 blt.offBmiSrc = 0;
681 blt.cbBmiSrc = bmp2_info->bmiHeader.biSize;
682 blt.offBitsSrc = 0;
683 blt.cbBitsSrc = bmp2_info->bmiHeader.biSizeImage;
684 blt.cxSrc = p->cxDest;
685 blt.cySrc = p->cyDest;
687 stretch_blt(dev, &blt, bmp2_info, bits);
689 /* restore all objects */
690 SelectObject(dev->hdc, brush_dest);
691 SelectObject(hdc1, old_bmp1);
692 SelectObject(hdc2, old_bmp2);
693 SelectObject(hdc_src, old_bmp_src);
695 /* delete all temp objects */
696 DeleteObject(bmp1);
697 DeleteObject(bmp2);
698 DeleteObject(bmp_src);
699 DeleteObject(brush_mask);
701 DeleteObject(hdc1);
702 DeleteObject(hdc2);
703 DeleteObject(hdc_src);
705 return TRUE;
708 static void combine_transform(XFORM *result, const XFORM *xform1, const XFORM *xform2)
710 XFORM r;
712 /* Create the result in a temporary XFORM, since result may be
713 * equal to xform1 or xform2 */
714 r.eM11 = xform1->eM11 * xform2->eM11 + xform1->eM12 * xform2->eM21;
715 r.eM12 = xform1->eM11 * xform2->eM12 + xform1->eM12 * xform2->eM22;
716 r.eM21 = xform1->eM21 * xform2->eM11 + xform1->eM22 * xform2->eM21;
717 r.eM22 = xform1->eM21 * xform2->eM12 + xform1->eM22 * xform2->eM22;
718 r.eDx = xform1->eDx * xform2->eM11 + xform1->eDy * xform2->eM21 + xform2->eDx;
719 r.eDy = xform1->eDx * xform2->eM12 + xform1->eDy * xform2->eM22 + xform2->eDy;
721 *result = r;
724 static int plg_blt(PHYSDEV dev, const EMRPLGBLT *p)
726 const BITMAPINFO *src_bi, *mask_bi;
727 const BYTE *src_bits, *mask_bits;
728 XFORM xf, xform_dest;
729 EMRMASKBLT maskblt;
730 /* rect coords */
731 POINT rect[3];
732 /* parallelogram coords */
733 POINT plg[3];
734 double det;
736 memcpy(plg, p->aptlDest, sizeof(plg));
737 rect[0].x = p->xSrc;
738 rect[0].y = p->ySrc;
739 rect[1].x = p->xSrc + p->cxSrc;
740 rect[1].y = p->ySrc;
741 rect[2].x = p->xSrc;
742 rect[2].y = p->ySrc + p->cySrc;
743 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
744 /* determinant */
745 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);
747 if (fabs(det) < 1e-5)
748 return TRUE;
750 TRACE("%ld,%ld,%ldx%ld -> %ld,%ld,%ld,%ld,%ld,%ld\n", p->xSrc, p->ySrc, p->cxSrc, p->cySrc,
751 plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
753 /* X components */
754 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;
755 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;
756 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
757 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
758 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
759 ) / det;
761 /* Y components */
762 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;
763 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;
764 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
765 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
766 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
767 ) / det;
769 combine_transform(&xf, &xf, &p->xformSrc);
771 GetTransform(dev->hdc, 0x203, &xform_dest);
772 SetWorldTransform(dev->hdc, &xf);
773 /* now destination and source DCs use same coords */
774 maskblt.rclBounds = p->rclBounds;
775 maskblt.xDest = p->xSrc;
776 maskblt.yDest = p->ySrc;
777 maskblt.cxDest = p->cxSrc;
778 maskblt.cyDest = p->cySrc;
779 maskblt.dwRop = SRCCOPY;
780 maskblt.xSrc = p->xSrc;
781 maskblt.ySrc = p->ySrc;
782 maskblt.xformSrc = p->xformSrc;
783 maskblt.crBkColorSrc = p->crBkColorSrc;
784 maskblt.iUsageSrc = p->iUsageSrc;
785 maskblt.offBmiSrc = 0;
786 maskblt.cbBmiSrc = p->cbBmiSrc;
787 maskblt.offBitsSrc = 0;
788 maskblt.cbBitsSrc = p->cbBitsSrc;
789 maskblt.xMask = p->xMask;
790 maskblt.yMask = p->yMask;
791 maskblt.iUsageMask = p->iUsageMask;
792 maskblt.offBmiMask = 0;
793 maskblt.cbBmiMask = p->cbBmiMask;
794 maskblt.offBitsMask = 0;
795 maskblt.cbBitsMask = p->cbBitsMask;
796 src_bi = (const BITMAPINFO *)((BYTE *)p + p->offBmiSrc);
797 src_bits = (BYTE *)p + p->offBitsSrc;
798 mask_bi = (const BITMAPINFO *)((BYTE *)p + p->offBmiMask);
799 mask_bits = (BYTE *)p + p->offBitsMask;
800 mask_blt(dev, &maskblt, src_bi, src_bits, mask_bi, mask_bits);
801 SetWorldTransform(dev->hdc, &xform_dest);
802 return TRUE;
805 static inline int get_dib_stride( int width, int bpp )
807 return ((width * bpp + 31) >> 3) & ~3;
810 static inline int get_dib_image_size( const BITMAPINFO *info )
812 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
813 * abs( info->bmiHeader.biHeight );
816 static int set_di_bits_to_device(PHYSDEV dev, const EMRSETDIBITSTODEVICE *p)
818 const BITMAPINFO *info = (const BITMAPINFO *)((BYTE *)p + p->offBmiSrc);
819 char bi_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
820 BITMAPINFO *bi = (BITMAPINFO *)bi_buffer;
821 HBITMAP bitmap, old_bitmap;
822 int width, height, ret;
823 BYTE *bits;
825 width = min(p->cxSrc, info->bmiHeader.biWidth);
826 height = min(p->cySrc, abs(info->bmiHeader.biHeight));
828 memset(bi_buffer, 0, sizeof(bi_buffer));
829 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
830 bi->bmiHeader.biWidth = width;
831 bi->bmiHeader.biHeight = height;
832 bi->bmiHeader.biPlanes = 1;
833 if (p->iUsageSrc == DIB_PAL_COLORS && (info->bmiHeader.biBitCount == 1 ||
834 info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8))
836 PALETTEENTRY pal[256];
837 HPALETTE hpal;
838 UINT i, size;
840 bi->bmiHeader.biBitCount = info->bmiHeader.biBitCount;
841 bi->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
842 bi->bmiHeader.biClrImportant = bi->bmiHeader.biClrUsed;
844 hpal = GetCurrentObject(dev->hdc, OBJ_PAL);
845 size = GetPaletteEntries(hpal, 0, bi->bmiHeader.biClrUsed, pal);
846 for (i = 0; i < size; i++)
848 bi->bmiColors[i].rgbBlue = pal[i].peBlue;
849 bi->bmiColors[i].rgbGreen = pal[i].peGreen;
850 bi->bmiColors[i].rgbRed = pal[i].peRed;
853 else
855 bi->bmiHeader.biBitCount = 24;
857 bi->bmiHeader.biCompression = BI_RGB;
858 bitmap = CreateDIBSection(dev->hdc, bi, DIB_RGB_COLORS, (void **)&bits, NULL, 0);
859 if (!bitmap)
860 return 1;
861 old_bitmap = SelectObject(dev->hdc, bitmap);
863 ret = SetDIBitsToDevice(dev->hdc, 0, 0, width, height, p->xSrc, p->ySrc,
864 p->iStartScan, p->cScans, (const BYTE*)p + p->offBitsSrc, info, p->iUsageSrc);
865 SelectObject(dev->hdc, old_bitmap);
866 if (ret)
868 EMRSTRETCHBLT blt;
870 memset(&blt, 0, sizeof(blt));
871 blt.rclBounds = p->rclBounds;
872 blt.xDest = p->xDest;
873 blt.yDest = p->yDest + p->cySrc - height;
874 blt.cxDest = width;
875 blt.cyDest = ret;
876 blt.dwRop = SRCCOPY;
877 blt.xformSrc.eM11 = 1;
878 blt.xformSrc.eM22 = 1;
879 blt.iUsageSrc = DIB_RGB_COLORS;
880 blt.cbBmiSrc = sizeof(bi_buffer);
881 blt.cbBitsSrc = get_dib_image_size(bi);
882 blt.cxSrc = blt.cxDest;
883 blt.cySrc = blt.cyDest;
884 stretch_blt(dev, &blt, bi, bits);
887 DeleteObject(bitmap);
888 return 1;
891 static int stretch_di_bits(PHYSDEV dev, const EMRSTRETCHDIBITS *p)
893 char bi_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
894 const BYTE *bits = (BYTE *)p + p->offBitsSrc;
895 BITMAPINFO *bi = (BITMAPINFO *)bi_buffer;
896 EMRSTRETCHBLT blt;
898 memcpy(bi, (BYTE *)p + p->offBmiSrc, p->cbBmiSrc);
899 memset(bi_buffer + p->cbBmiSrc, 0, sizeof(bi_buffer) - p->cbBmiSrc);
901 if (p->iUsageSrc == DIB_PAL_COLORS && (bi->bmiHeader.biBitCount == 1 ||
902 bi->bmiHeader.biBitCount == 4 || bi->bmiHeader.biBitCount == 8))
904 PALETTEENTRY pal[256];
905 HPALETTE hpal;
906 UINT i, size;
908 hpal = GetCurrentObject(dev->hdc, OBJ_PAL);
909 size = GetPaletteEntries(hpal, 0, 1 << bi->bmiHeader.biBitCount, pal);
910 for (i = 0; i < size; i++)
912 bi->bmiColors[i].rgbBlue = pal[i].peBlue;
913 bi->bmiColors[i].rgbGreen = pal[i].peGreen;
914 bi->bmiColors[i].rgbRed = pal[i].peRed;
918 memset(&blt, 0, sizeof(blt));
919 blt.rclBounds = p->rclBounds;
920 blt.xDest = p->xDest;
921 blt.yDest = p->yDest;
922 blt.cxDest = p->cxDest;
923 blt.cyDest = p->cyDest;
924 blt.dwRop = p->dwRop;
925 blt.xSrc = p->xSrc;
926 blt.ySrc = abs(bi->bmiHeader.biHeight) - p->ySrc - p->cySrc;
927 blt.xformSrc.eM11 = 1;
928 blt.xformSrc.eM22 = 1;
929 blt.iUsageSrc = p->iUsageSrc;
930 blt.cbBmiSrc = sizeof(bi_buffer);
931 blt.cbBitsSrc = p->cbBitsSrc;
932 blt.cxSrc = p->cxSrc;
933 blt.cySrc = p->cySrc;
934 return stretch_blt(dev, &blt, bi, bits);
937 static int poly_draw(PHYSDEV dev, const POINT *points, const BYTE *types, DWORD count)
939 POINT first, cur, pts[4];
940 DWORD i, num_pts;
942 /* check for valid point types */
943 for (i = 0; i < count; i++)
945 switch (types[i])
947 case PT_MOVETO:
948 case PT_LINETO | PT_CLOSEFIGURE:
949 case PT_LINETO:
950 break;
951 case PT_BEZIERTO:
952 if (i + 2 >= count) return FALSE;
953 if (types[i + 1] != PT_BEZIERTO) return FALSE;
954 if ((types[i + 2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO) return FALSE;
955 i += 2;
956 break;
957 default:
958 return FALSE;
962 GetCurrentPositionEx(dev->hdc, &cur);
963 first = cur;
965 for (i = 0; i < count; i++)
967 switch (types[i])
969 case PT_MOVETO:
970 first = points[i];
971 break;
972 case PT_LINETO:
973 case (PT_LINETO | PT_CLOSEFIGURE):
974 pts[0] = cur;
975 pts[1] = points[i];
976 num_pts = 2;
977 if (!PSDRV_PolyPolyline(dev, pts, &num_pts, 1))
978 return FALSE;
979 break;
980 case PT_BEZIERTO:
981 pts[0] = cur;
982 pts[1] = points[i];
983 pts[2] = points[i + 1];
984 pts[3] = points[i + 2];
985 if (!PSDRV_PolyBezier(dev, pts, 4))
986 return FALSE;
987 i += 2;
988 break;
991 cur = points[i];
992 if (types[i] & PT_CLOSEFIGURE)
994 pts[0] = cur;
995 pts[1] = first;
996 num_pts = 2;
997 if (!PSDRV_PolyPolyline(dev, pts, &num_pts, 1))
998 return FALSE;
1002 return TRUE;
1005 static inline void reset_bounds(RECT *bounds)
1007 bounds->left = bounds->top = INT_MAX;
1008 bounds->right = bounds->bottom = INT_MIN;
1011 static BOOL gradient_fill(PHYSDEV dev, const TRIVERTEX *vert_array, DWORD nvert,
1012 const void *grad_array, DWORD ngrad, ULONG mode)
1014 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1015 BITMAPINFO *info = (BITMAPINFO *)buffer;
1016 struct bitblt_coords src, dst;
1017 struct gdi_image_bits bits;
1018 HBITMAP bmp, old_bmp;
1019 BOOL ret = FALSE;
1020 TRIVERTEX *pts;
1021 unsigned int i;
1022 HDC hdc_src;
1023 HRGN rgn;
1025 if (!(pts = malloc(nvert * sizeof(*pts)))) return FALSE;
1026 memcpy(pts, vert_array, sizeof(*pts) * nvert);
1027 for (i = 0; i < nvert; i++)
1028 LPtoDP(dev->hdc, (POINT *)&pts[i], 1);
1030 /* compute bounding rect of all the rectangles/triangles */
1031 reset_bounds(&dst.visrect);
1032 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
1034 ULONG v = ((ULONG *)grad_array)[i];
1035 dst.visrect.left = min(dst.visrect.left, pts[v].x);
1036 dst.visrect.top = min(dst.visrect.top, pts[v].y);
1037 dst.visrect.right = max(dst.visrect.right, pts[v].x);
1038 dst.visrect.bottom = max(dst.visrect.bottom, pts[v].y);
1041 dst.x = dst.visrect.left;
1042 dst.y = dst.visrect.top;
1043 dst.width = dst.visrect.right - dst.visrect.left;
1044 dst.height = dst.visrect.bottom - dst.visrect.top;
1045 clip_visrect(dev->hdc, &dst.visrect, &dst.visrect);
1047 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1048 info->bmiHeader.biPlanes = 1;
1049 info->bmiHeader.biBitCount = 24;
1050 info->bmiHeader.biCompression = BI_RGB;
1051 info->bmiHeader.biXPelsPerMeter = 0;
1052 info->bmiHeader.biYPelsPerMeter = 0;
1053 info->bmiHeader.biClrUsed = 0;
1054 info->bmiHeader.biClrImportant = 0;
1055 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
1056 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
1057 info->bmiHeader.biSizeImage = 0;
1058 memset(&bits, 0, sizeof(bits));
1059 hdc_src = CreateCompatibleDC(NULL);
1060 if (!hdc_src)
1062 free(pts);
1063 return FALSE;
1065 bmp = CreateDIBSection(hdc_src, info, DIB_RGB_COLORS, &bits.ptr, NULL, 0);
1066 if (!bmp)
1068 DeleteObject(hdc_src);
1069 free(pts);
1070 return FALSE;
1072 old_bmp = SelectObject(hdc_src, bmp);
1074 /* make src and points relative to the bitmap */
1075 src = dst;
1076 src.x -= dst.visrect.left;
1077 src.y -= dst.visrect.top;
1078 OffsetRect(&src.visrect, -dst.visrect.left, -dst.visrect.top);
1079 for (i = 0; i < nvert; i++)
1081 pts[i].x -= dst.visrect.left;
1082 pts[i].y -= dst.visrect.top;
1084 ret = GdiGradientFill(hdc_src, pts, nvert, (void *)grad_array, ngrad, mode);
1085 SelectObject(hdc_src, old_bmp);
1086 DeleteObject(hdc_src);
1088 rgn = CreateRectRgn(0, 0, 0, 0);
1089 if (mode == GRADIENT_FILL_TRIANGLE)
1091 const GRADIENT_TRIANGLE *gt = grad_array;
1092 POINT triangle[3];
1093 HRGN tmp;
1095 for (i = 0; i < ngrad; i++)
1097 triangle[0].x = pts[gt[i].Vertex1].x;
1098 triangle[0].y = pts[gt[i].Vertex1].y;
1099 triangle[1].x = pts[gt[i].Vertex2].x;
1100 triangle[1].y = pts[gt[i].Vertex2].y;
1101 triangle[2].x = pts[gt[i].Vertex3].x;
1102 triangle[2].y = pts[gt[i].Vertex3].y;
1103 tmp = CreatePolygonRgn(triangle, 3, ALTERNATE);
1104 CombineRgn(rgn, rgn, tmp, RGN_OR);
1105 DeleteObject(tmp);
1108 else
1110 const GRADIENT_RECT *gr = grad_array;
1111 HRGN tmp = CreateRectRgn(0, 0, 0, 0);
1113 for (i = 0; i < ngrad; i++)
1115 SetRectRgn(tmp, pts[gr[i].UpperLeft].x, pts[gr[i].UpperLeft].y,
1116 pts[gr[i].LowerRight].x, pts[gr[i].LowerRight].y);
1117 CombineRgn(rgn, rgn, tmp, RGN_OR);
1119 DeleteObject(tmp);
1121 free(pts);
1123 OffsetRgn(rgn, dst.visrect.left, dst.visrect.top);
1124 if (ret)
1125 ret = (PSDRV_PutImage(dev, rgn, info, &bits, &src, &dst, SRCCOPY) == ERROR_SUCCESS);
1126 DeleteObject(rgn);
1127 DeleteObject(bmp);
1128 return ret;
1131 static HGDIOBJ get_object_handle(struct pp_data *data, HANDLETABLE *handletable,
1132 DWORD i, struct brush_pattern **pattern)
1134 if (i & 0x80000000)
1136 *pattern = NULL;
1137 if ((i & 0x7fffffff) == DEVICE_DEFAULT_FONT)
1138 return PSDRV_DefaultFont;
1139 return GetStockObject(i & 0x7fffffff);
1141 *pattern = data->patterns + i;
1142 return handletable->objectHandle[i];
1145 static BOOL select_hbrush(struct pp_data *data, HANDLETABLE *htable, int handle_count, HBRUSH brush)
1147 struct brush_pattern *pattern = NULL;
1148 int i;
1150 for (i = 0; i < handle_count; i++)
1152 if (htable->objectHandle[i] == brush)
1154 pattern = data->patterns + i;
1155 break;
1159 return PSDRV_SelectBrush(&data->pdev->dev, brush, pattern) != NULL;
1162 /* Performs a device to world transformation on the specified width (which
1163 * is in integer format).
1165 static inline INT INTERNAL_XDSTOWS(HDC hdc, INT width)
1167 double floatWidth;
1168 XFORM xform;
1170 GetWorldTransform(hdc, &xform);
1172 /* Perform operation with floating point */
1173 floatWidth = (double)width * xform.eM11;
1174 /* Round to integers */
1175 return GDI_ROUND(floatWidth);
1178 /* Performs a device to world transformation on the specified size (which
1179 * is in integer format).
1181 static inline INT INTERNAL_YDSTOWS(HDC hdc, INT height)
1183 double floatHeight;
1184 XFORM xform;
1186 GetWorldTransform(hdc, &xform);
1188 /* Perform operation with floating point */
1189 floatHeight = (double)height * xform.eM22;
1190 /* Round to integers */
1191 return GDI_ROUND(floatHeight);
1194 static inline INT INTERNAL_YWSTODS(HDC hdc, INT height)
1196 POINT pt[2];
1197 pt[0].x = pt[0].y = 0;
1198 pt[1].x = 0;
1199 pt[1].y = height;
1200 LPtoDP(hdc, pt, 2);
1201 return pt[1].y - pt[0].y;
1204 /* compute positions for text rendering, in device coords */
1205 static BOOL get_char_positions(struct pp_data *data, const WCHAR *str,
1206 INT count, INT *dx, SIZE *size)
1208 TEXTMETRICW tm;
1210 size->cx = size->cy = 0;
1211 if (!count) return TRUE;
1213 PSDRV_GetTextMetrics(&data->pdev->dev, &tm);
1214 if (!PSDRV_GetTextExtentExPoint(&data->pdev->dev, str, count, dx)) return FALSE;
1216 if (data->break_extra || data->break_rem)
1218 int i, space = 0, rem = data->break_rem;
1220 for (i = 0; i < count; i++)
1222 if (str[i] == tm.tmBreakChar)
1224 space += data->break_extra;
1225 if (rem > 0)
1227 space++;
1228 rem--;
1231 dx[i] += space;
1234 size->cx = dx[count - 1];
1235 size->cy = tm.tmHeight;
1236 return TRUE;
1239 static BOOL get_text_extent(struct pp_data *data, const WCHAR *str, INT count,
1240 INT max_ext, INT *nfit, INT *dxs, SIZE *size, UINT flags)
1242 INT buffer[256], *pos = dxs;
1243 int i, char_extra;
1244 BOOL ret;
1246 if (flags)
1247 return GetTextExtentExPointI(data->pdev->dev.hdc, str, count, max_ext, nfit, dxs, size);
1248 else if (data->pdev->font.fontloc == Download)
1249 return GetTextExtentExPointW(data->pdev->dev.hdc, str, count, max_ext, nfit, dxs, size);
1251 if (!dxs)
1253 pos = buffer;
1254 if (count > 256 && !(pos = malloc(count * sizeof(*pos))))
1255 return FALSE;
1258 if ((ret = get_char_positions(data, str, count, pos, size)))
1260 char_extra = GetTextCharacterExtra(data->pdev->dev.hdc);
1261 if (dxs || nfit)
1263 for (i = 0; i < count; i++)
1265 unsigned int dx = abs(INTERNAL_XDSTOWS(data->pdev->dev.hdc, pos[i]))
1266 + (i + 1) * char_extra;
1267 if (nfit && dx > (unsigned int)max_ext) break;
1268 if (dxs) dxs[i] = dx;
1270 if (nfit) *nfit = i;
1273 size->cx = abs(INTERNAL_XDSTOWS(data->pdev->dev.hdc, size->cx))
1274 + count * char_extra;
1275 size->cy = abs(INTERNAL_YDSTOWS(data->pdev->dev.hdc, size->cy));
1278 if (pos != buffer && pos != dxs) free(pos);
1280 TRACE("(%s, %d) returning %dx%d\n", debugstr_wn(str,count),
1281 max_ext, (int)size->cx, (int)size->cy);
1282 return ret;
1285 extern const unsigned short bidi_direction_table[] DECLSPEC_HIDDEN;
1287 /*------------------------------------------------------------------------
1288 Bidirectional Character Types
1290 as defined by the Unicode Bidirectional Algorithm Table 3-7.
1292 Note:
1294 The list of bidirectional character types here is not grouped the
1295 same way as the table 3-7, since the numeric values for the types
1296 are chosen to keep the state and action tables compact.
1297 ------------------------------------------------------------------------*/
1298 enum directions
1300 /* input types */
1301 /* ON MUST be zero, code relies on ON = N = 0 */
1302 ON = 0, /* Other Neutral */
1303 L, /* Left Letter */
1304 R, /* Right Letter */
1305 AN, /* Arabic Number */
1306 EN, /* European Number */
1307 AL, /* Arabic Letter (Right-to-left) */
1308 NSM, /* Non-spacing Mark */
1309 CS, /* Common Separator */
1310 ES, /* European Separator */
1311 ET, /* European Terminator (post/prefix e.g. $ and %) */
1313 /* resolved types */
1314 BN, /* Boundary neutral (type of RLE etc after explicit levels) */
1316 /* input types, */
1317 S, /* Segment Separator (TAB) // used only in L1 */
1318 WS, /* White space // used only in L1 */
1319 B, /* Paragraph Separator (aka as PS) */
1321 /* types for explicit controls */
1322 RLO, /* these are used only in X1-X9 */
1323 RLE,
1324 LRO,
1325 LRE,
1326 PDF,
1328 LRI, /* Isolate formatting characters new with 6.3 */
1329 RLI,
1330 FSI,
1331 PDI,
1333 /* resolved types, also resolved directions */
1334 NI = ON, /* alias, where ON, WS and S are treated the same */
1337 static inline unsigned short get_table_entry_32(const unsigned short *table, UINT ch)
1339 return table[table[table[table[ch >> 12] + ((ch >> 8) & 0x0f)] + ((ch >> 4) & 0x0f)] + (ch & 0xf)];
1342 /* Convert the libwine information to the direction enum */
1343 static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount)
1345 unsigned i;
1347 for (i = 0; i < uCount; ++i)
1348 chartype[i] = get_table_entry_32(bidi_direction_table, lpString[i]);
1351 /* Set a run of cval values at locations all prior to, but not including */
1352 /* iStart, to the new value nval. */
1353 static void SetDeferredRun(BYTE *pval, int cval, int iStart, int nval)
1355 int i = iStart - 1;
1356 for (; i >= iStart - cval; i--)
1358 pval[i] = nval;
1362 /* THE PARAGRAPH LEVEL */
1364 /*------------------------------------------------------------------------
1365 Function: resolveParagraphs
1367 Resolves the input strings into blocks over which the algorithm
1368 is then applied.
1370 Implements Rule P1 of the Unicode Bidi Algorithm
1372 Input: Text string
1373 Character count
1375 Output: revised character count
1377 Note: This is a very simplistic function. In effect it restricts
1378 the action of the algorithm to the first paragraph in the input
1379 where a paragraph ends at the end of the first block separator
1380 or at the end of the input text.
1382 ------------------------------------------------------------------------*/
1384 static int resolveParagraphs(WORD *types, int cch)
1386 /* skip characters not of type B */
1387 int ich = 0;
1388 for(; ich < cch && types[ich] != B; ich++);
1389 /* stop after first B, make it a BN for use in the next steps */
1390 if (ich < cch && types[ich] == B)
1391 types[ich++] = BN;
1392 return ich;
1395 /* REORDER */
1396 /*------------------------------------------------------------------------
1397 Function: resolveLines
1399 Breaks a paragraph into lines
1401 Input: Array of line break flags
1402 Character count
1403 In/Out: Array of characters
1405 Returns the count of characters on the first line
1407 Note: This function only breaks lines at hard line breaks. Other
1408 line breaks can be passed in. If pbrk[n] is TRUE, then a break
1409 occurs after the character in pszInput[n]. Breaks before the first
1410 character are not allowed.
1411 ------------------------------------------------------------------------*/
1412 static int resolveLines(LPCWSTR pszInput, const BOOL * pbrk, int cch)
1414 /* skip characters not of type LS */
1415 int ich = 0;
1416 for(; ich < cch; ich++)
1418 if (pszInput[ich] == (WCHAR)'\n' || (pbrk && pbrk[ich]))
1420 ich++;
1421 break;
1425 return ich;
1428 /*------------------------------------------------------------------------
1429 Function: resolveWhiteSpace
1431 Resolves levels for WS and S
1432 Implements rule L1 of the Unicode bidi Algorithm.
1434 Input: Base embedding level
1435 Character count
1436 Array of direction classes (for one line of text)
1438 In/Out: Array of embedding levels (for one line of text)
1440 Note: this should be applied a line at a time. The default driver
1441 code supplied in this file assumes a single line of text; for
1442 a real implementation, cch and the initial pointer values
1443 would have to be adjusted.
1444 ------------------------------------------------------------------------*/
1445 static void resolveWhitespace(int baselevel, const WORD *pcls, BYTE *plevel, int cch)
1447 int cchrun = 0;
1448 BYTE oldlevel = baselevel;
1450 int ich = 0;
1451 for (; ich < cch; ich++)
1453 switch(pcls[ich])
1455 default:
1456 cchrun = 0; /* any other character breaks the run */
1457 break;
1458 case WS:
1459 cchrun++;
1460 break;
1462 case RLE:
1463 case LRE:
1464 case LRO:
1465 case RLO:
1466 case PDF:
1467 case LRI:
1468 case RLI:
1469 case FSI:
1470 case PDI:
1471 case BN:
1472 plevel[ich] = oldlevel;
1473 cchrun++;
1474 break;
1476 case S:
1477 case B:
1478 /* reset levels for WS before eot */
1479 SetDeferredRun(plevel, cchrun, ich, baselevel);
1480 cchrun = 0;
1481 plevel[ich] = baselevel;
1482 break;
1484 oldlevel = plevel[ich];
1486 /* reset level before eot */
1487 SetDeferredRun(plevel, cchrun, ich, baselevel);
1490 /*------------------------------------------------------------------------
1491 Function: BidiLines
1493 Implements the Line-by-Line phases of the Unicode Bidi Algorithm
1495 Input: Count of characters
1496 Array of character directions
1498 Inp/Out: Input text
1499 Array of levels
1501 ------------------------------------------------------------------------*/
1502 static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, const WORD * pclsLine,
1503 BYTE * plevelLine, int cchPara, const BOOL * pbrk)
1505 int cchLine = 0;
1506 int done = 0;
1507 int *run;
1509 run = HeapAlloc(GetProcessHeap(), 0, cchPara * sizeof(int));
1510 if (!run)
1512 WARN("Out of memory\n");
1513 return;
1518 /* break lines at LS */
1519 cchLine = resolveLines(pszLine, pbrk, cchPara);
1521 /* resolve whitespace */
1522 resolveWhitespace(baselevel, pclsLine, plevelLine, cchLine);
1524 if (pszOutLine)
1526 int i;
1527 /* reorder each line in place */
1528 ScriptLayout(cchLine, plevelLine, NULL, run);
1529 for (i = 0; i < cchLine; i++)
1530 pszOutLine[done+run[i]] = pszLine[i];
1533 pszLine += cchLine;
1534 plevelLine += cchLine;
1535 pbrk += pbrk ? cchLine : 0;
1536 pclsLine += cchLine;
1537 cchPara -= cchLine;
1538 done += cchLine;
1540 } while (cchPara);
1542 HeapFree(GetProcessHeap(), 0, run);
1545 #define WINE_GCPW_FORCE_LTR 0
1546 #define WINE_GCPW_FORCE_RTL 1
1547 #define WINE_GCPW_DIR_MASK 3
1549 static BOOL BIDI_Reorder(HDC hDC, /* [in] Display DC */
1550 LPCWSTR lpString, /* [in] The string for which information is to be returned */
1551 INT uCount, /* [in] Number of WCHARs in string. */
1552 DWORD dwFlags, /* [in] GetCharacterPlacement compatible flags */
1553 DWORD dwWineGCP_Flags, /* [in] Wine internal flags - Force paragraph direction */
1554 LPWSTR lpOutString, /* [out] Reordered string */
1555 INT uCountOut, /* [in] Size of output buffer */
1556 UINT *lpOrder, /* [out] Logical -> Visual order map */
1557 WORD **lpGlyphs, /* [out] reordered, mirrored, shaped glyphs to display */
1558 INT *cGlyphs) /* [out] number of glyphs generated */
1560 WORD *chartype = NULL;
1561 BYTE *levels = NULL;
1562 INT i, done;
1563 unsigned glyph_i;
1564 BOOL is_complex, ret = FALSE;
1566 int maxItems;
1567 int nItems;
1568 SCRIPT_CONTROL Control;
1569 SCRIPT_STATE State;
1570 SCRIPT_ITEM *pItems = NULL;
1571 HRESULT res;
1572 SCRIPT_CACHE psc = NULL;
1573 WORD *run_glyphs = NULL;
1574 WORD *pwLogClust = NULL;
1575 SCRIPT_VISATTR *psva = NULL;
1576 DWORD cMaxGlyphs = 0;
1577 BOOL doGlyphs = TRUE;
1579 TRACE("%s, %d, 0x%08lx lpOutString=%p, lpOrder=%p\n",
1580 debugstr_wn(lpString, uCount), uCount, dwFlags,
1581 lpOutString, lpOrder);
1583 memset(&Control, 0, sizeof(Control));
1584 memset(&State, 0, sizeof(State));
1585 if (lpGlyphs)
1586 *lpGlyphs = NULL;
1588 if (!(dwFlags & GCP_REORDER))
1590 FIXME("Asked to reorder without reorder flag set\n");
1591 return FALSE;
1594 if (lpOutString && uCountOut < uCount)
1596 FIXME("lpOutString too small\n");
1597 return FALSE;
1600 chartype = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD));
1601 if (!chartype)
1603 WARN("Out of memory\n");
1604 return FALSE;
1607 if (lpOutString)
1608 memcpy(lpOutString, lpString, uCount * sizeof(WCHAR));
1610 is_complex = FALSE;
1611 for (i = 0; i < uCount && !is_complex; i++)
1613 if ((lpString[i] >= 0x900 && lpString[i] <= 0xfff) ||
1614 (lpString[i] >= 0x1cd0 && lpString[i] <= 0x1cff) ||
1615 (lpString[i] >= 0xa840 && lpString[i] <= 0xa8ff))
1616 is_complex = TRUE;
1619 /* Verify reordering will be required */
1620 if (WINE_GCPW_FORCE_RTL == (dwWineGCP_Flags & WINE_GCPW_DIR_MASK))
1621 State.uBidiLevel = 1;
1622 else if (!is_complex)
1624 done = 1;
1625 classify(lpString, chartype, uCount);
1626 for (i = 0; i < uCount; i++)
1627 switch (chartype[i])
1629 case R:
1630 case AL:
1631 case RLE:
1632 case RLO:
1633 done = 0;
1634 break;
1636 if (done)
1638 HeapFree(GetProcessHeap(), 0, chartype);
1639 if (lpOrder)
1641 for (i = 0; i < uCount; i++)
1642 lpOrder[i] = i;
1644 return TRUE;
1648 levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(BYTE));
1649 if (!levels)
1651 WARN("Out of memory\n");
1652 goto cleanup;
1655 maxItems = 5;
1656 pItems = HeapAlloc(GetProcessHeap(),0, maxItems * sizeof(SCRIPT_ITEM));
1657 if (!pItems)
1659 WARN("Out of memory\n");
1660 goto cleanup;
1663 if (lpGlyphs)
1665 cMaxGlyphs = 1.5 * uCount + 16;
1666 run_glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * cMaxGlyphs);
1667 if (!run_glyphs)
1669 WARN("Out of memory\n");
1670 goto cleanup;
1672 pwLogClust = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * uCount);
1673 if (!pwLogClust)
1675 WARN("Out of memory\n");
1676 goto cleanup;
1678 psva = HeapAlloc(GetProcessHeap(),0,sizeof(SCRIPT_VISATTR) * cMaxGlyphs);
1679 if (!psva)
1681 WARN("Out of memory\n");
1682 goto cleanup;
1686 done = 0;
1687 glyph_i = 0;
1688 while (done < uCount)
1690 INT j;
1691 classify(lpString + done, chartype, uCount - done);
1692 /* limit text to first block */
1693 i = resolveParagraphs(chartype, uCount - done);
1694 for (j = 0; j < i; ++j)
1695 switch(chartype[j])
1697 case B:
1698 case S:
1699 case WS:
1700 case ON: chartype[j] = NI;
1701 default: continue;
1704 res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
1705 while (res == E_OUTOFMEMORY)
1707 SCRIPT_ITEM *new_pItems = HeapReAlloc(GetProcessHeap(), 0, pItems, sizeof(*pItems) * maxItems * 2);
1708 if (!new_pItems)
1710 WARN("Out of memory\n");
1711 goto cleanup;
1713 pItems = new_pItems;
1714 maxItems *= 2;
1715 res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
1718 if (lpOutString || lpOrder)
1719 for (j = 0; j < nItems; j++)
1721 int k;
1722 for (k = pItems[j].iCharPos; k < pItems[j+1].iCharPos; k++)
1723 levels[k] = pItems[j].a.s.uBidiLevel;
1726 if (lpOutString)
1728 /* assign directional types again, but for WS, S this time */
1729 classify(lpString + done, chartype, i);
1731 BidiLines(State.uBidiLevel, lpOutString + done, lpString + done,
1732 chartype, levels, i, 0);
1735 if (lpOrder)
1737 int k, lastgood;
1738 for (j = lastgood = 0; j < i; ++j)
1739 if (levels[j] != levels[lastgood])
1741 --j;
1742 if (levels[lastgood] & 1)
1743 for (k = j; k >= lastgood; --k)
1744 lpOrder[done + k] = done + j - k;
1745 else
1746 for (k = lastgood; k <= j; ++k)
1747 lpOrder[done + k] = done + k;
1748 lastgood = ++j;
1750 if (levels[lastgood] & 1)
1751 for (k = j - 1; k >= lastgood; --k)
1752 lpOrder[done + k] = done + j - 1 - k;
1753 else
1754 for (k = lastgood; k < j; ++k)
1755 lpOrder[done + k] = done + k;
1758 if (lpGlyphs && doGlyphs)
1760 BYTE *runOrder;
1761 int *visOrder;
1762 SCRIPT_ITEM *curItem;
1764 runOrder = HeapAlloc(GetProcessHeap(), 0, maxItems * sizeof(*runOrder));
1765 visOrder = HeapAlloc(GetProcessHeap(), 0, maxItems * sizeof(*visOrder));
1766 if (!runOrder || !visOrder)
1768 WARN("Out of memory\n");
1769 HeapFree(GetProcessHeap(), 0, runOrder);
1770 HeapFree(GetProcessHeap(), 0, visOrder);
1771 goto cleanup;
1774 for (j = 0; j < nItems; j++)
1775 runOrder[j] = pItems[j].a.s.uBidiLevel;
1777 ScriptLayout(nItems, runOrder, visOrder, NULL);
1779 for (j = 0; j < nItems; j++)
1781 int k;
1782 int cChars,cOutGlyphs;
1783 curItem = &pItems[visOrder[j]];
1785 cChars = pItems[visOrder[j]+1].iCharPos - curItem->iCharPos;
1787 res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs);
1788 while (res == E_OUTOFMEMORY)
1790 WORD *new_run_glyphs = HeapReAlloc(GetProcessHeap(), 0, run_glyphs, sizeof(*run_glyphs) * cMaxGlyphs * 2);
1791 SCRIPT_VISATTR *new_psva = HeapReAlloc(GetProcessHeap(), 0, psva, sizeof(*psva) * cMaxGlyphs * 2);
1792 if (!new_run_glyphs || !new_psva)
1794 WARN("Out of memory\n");
1795 HeapFree(GetProcessHeap(), 0, runOrder);
1796 HeapFree(GetProcessHeap(), 0, visOrder);
1797 HeapFree(GetProcessHeap(), 0, *lpGlyphs);
1798 *lpGlyphs = NULL;
1799 if (new_run_glyphs)
1800 run_glyphs = new_run_glyphs;
1801 if (new_psva)
1802 psva = new_psva;
1803 goto cleanup;
1805 run_glyphs = new_run_glyphs;
1806 psva = new_psva;
1807 cMaxGlyphs *= 2;
1808 res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs);
1810 if (res)
1812 if (res == USP_E_SCRIPT_NOT_IN_FONT)
1813 TRACE("Unable to shape with currently selected font\n");
1814 else
1815 FIXME("Unable to shape string (%lx)\n",res);
1816 j = nItems;
1817 doGlyphs = FALSE;
1818 HeapFree(GetProcessHeap(), 0, *lpGlyphs);
1819 *lpGlyphs = NULL;
1821 else
1823 WORD *new_glyphs;
1824 if (*lpGlyphs)
1825 new_glyphs = HeapReAlloc(GetProcessHeap(), 0, *lpGlyphs, sizeof(**lpGlyphs) * (glyph_i + cOutGlyphs));
1826 else
1827 new_glyphs = HeapAlloc(GetProcessHeap(), 0, sizeof(**lpGlyphs) * (glyph_i + cOutGlyphs));
1828 if (!new_glyphs)
1830 WARN("Out of memory\n");
1831 HeapFree(GetProcessHeap(), 0, runOrder);
1832 HeapFree(GetProcessHeap(), 0, visOrder);
1833 HeapFree(GetProcessHeap(), 0, *lpGlyphs);
1834 *lpGlyphs = NULL;
1835 goto cleanup;
1837 *lpGlyphs = new_glyphs;
1838 for (k = 0; k < cOutGlyphs; k++)
1839 (*lpGlyphs)[glyph_i+k] = run_glyphs[k];
1840 glyph_i += cOutGlyphs;
1843 HeapFree(GetProcessHeap(), 0, runOrder);
1844 HeapFree(GetProcessHeap(), 0, visOrder);
1847 done += i;
1849 if (cGlyphs)
1850 *cGlyphs = glyph_i;
1852 ret = TRUE;
1853 cleanup:
1854 HeapFree(GetProcessHeap(), 0, chartype);
1855 HeapFree(GetProcessHeap(), 0, levels);
1856 HeapFree(GetProcessHeap(), 0, pItems);
1857 HeapFree(GetProcessHeap(), 0, run_glyphs);
1858 HeapFree(GetProcessHeap(), 0, pwLogClust);
1859 HeapFree(GetProcessHeap(), 0, psva);
1860 ScriptFreeCache(&psc);
1861 return ret;
1864 static inline BOOL intersect_rect(RECT *dst, const RECT *src1, const RECT *src2)
1866 dst->left = max(src1->left, src2->left);
1867 dst->top = max(src1->top, src2->top);
1868 dst->right = min(src1->right, src2->right);
1869 dst->bottom = min(src1->bottom, src2->bottom);
1870 return !IsRectEmpty(dst);
1873 /***********************************************************************
1874 * get_line_width
1876 * Scale the underline / strikeout line width.
1878 static inline int get_line_width(HDC hdc, int metric_size)
1880 int width = abs(INTERNAL_YWSTODS(hdc, metric_size));
1881 if (width == 0) width = 1;
1882 if (metric_size < 0) width = -width;
1883 return width;
1886 static BOOL ext_text_out(struct pp_data *data, HANDLETABLE *htable,
1887 int handle_count, INT x, INT y, UINT flags, const RECT *rect,
1888 const WCHAR *str, UINT count, const INT *dx)
1890 HDC hdc = data->pdev->dev.hdc;
1891 BOOL ret = FALSE;
1892 UINT align;
1893 DWORD layout;
1894 POINT pt;
1895 TEXTMETRICW tm;
1896 LOGFONTW lf;
1897 double cosEsc, sinEsc;
1898 INT char_extra;
1899 SIZE sz;
1900 RECT rc;
1901 POINT *deltas = NULL, width = {0, 0};
1902 INT breakRem;
1903 WORD *glyphs = NULL;
1904 XFORM xform;
1906 if (!(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0)
1908 int glyphs_count = 0;
1909 UINT bidi_flags;
1911 bidi_flags = (GetTextAlign(hdc) & TA_RTLREADING) || (flags & ETO_RTLREADING)
1912 ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR;
1914 BIDI_Reorder(hdc, str, count, GCP_REORDER, bidi_flags,
1915 NULL, 0, NULL, &glyphs, &glyphs_count);
1917 flags |= ETO_IGNORELANGUAGE;
1918 if (glyphs)
1920 flags |= ETO_GLYPH_INDEX;
1921 count = glyphs_count;
1922 str = glyphs;
1926 align = GetTextAlign(hdc);
1927 breakRem = data->break_rem;
1928 layout = GetLayout(hdc);
1930 if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
1931 if (layout & LAYOUT_RTL)
1933 if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
1934 align ^= TA_RTLREADING;
1937 TRACE("%d, %d, %08x, %s, %s, %d, %p)\n", x, y, flags,
1938 wine_dbgstr_rect(rect), debugstr_wn(str, count), count, dx);
1939 TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc),
1940 GetMapMode(hdc));
1942 if(align & TA_UPDATECP)
1944 GetCurrentPositionEx(hdc, &pt);
1945 x = pt.x;
1946 y = pt.y;
1949 PSDRV_GetTextMetrics(&data->pdev->dev, &tm);
1950 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1952 if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
1953 lf.lfEscapement = 0;
1955 GetWorldTransform(hdc, &xform);
1956 if (GetGraphicsMode(hdc) == GM_COMPATIBLE &&
1957 xform.eM11 * xform.eM22 < 0)
1959 lf.lfEscapement = -lf.lfEscapement;
1962 if(lf.lfEscapement != 0)
1964 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1965 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1967 else
1969 cosEsc = 1;
1970 sinEsc = 0;
1973 if (rect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
1975 rc = *rect;
1976 LPtoDP(hdc, (POINT*)&rc, 2);
1977 order_rect(&rc);
1978 if (flags & ETO_OPAQUE)
1979 PSDRV_ExtTextOut(&data->pdev->dev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1981 else flags &= ~ETO_CLIPPED;
1983 if(count == 0)
1985 ret = TRUE;
1986 goto done;
1989 pt.x = x;
1990 pt.y = y;
1991 LPtoDP(hdc, &pt, 1);
1992 x = pt.x;
1993 y = pt.y;
1995 char_extra = GetTextCharacterExtra(hdc);
1996 if (char_extra && dx)
1997 char_extra = 0; /* Printer drivers don't add char_extra if dx is supplied */
1999 if(char_extra || data->break_extra || breakRem || dx || lf.lfEscapement != 0)
2001 UINT i;
2002 POINT total = {0, 0}, desired[2];
2004 deltas = malloc(count * sizeof(*deltas));
2005 if (dx)
2007 if (flags & ETO_PDY)
2009 for (i = 0; i < count; i++)
2011 deltas[i].x = dx[i * 2] + char_extra;
2012 deltas[i].y = -dx[i * 2 + 1];
2015 else
2017 for (i = 0; i < count; i++)
2019 deltas[i].x = dx[i] + char_extra;
2020 deltas[i].y = 0;
2024 else
2026 INT *dx = malloc(count * sizeof(*dx));
2028 get_text_extent(data, str, count, -1, NULL, dx, &sz, !!(flags & ETO_GLYPH_INDEX));
2030 deltas[0].x = dx[0];
2031 deltas[0].y = 0;
2032 for (i = 1; i < count; i++)
2034 deltas[i].x = dx[i] - dx[i - 1];
2035 deltas[i].y = 0;
2037 free(dx);
2040 for(i = 0; i < count; i++)
2042 total.x += deltas[i].x;
2043 total.y += deltas[i].y;
2045 desired[0].x = desired[0].y = 0;
2047 desired[1].x = cosEsc * total.x + sinEsc * total.y;
2048 desired[1].y = -sinEsc * total.x + cosEsc * total.y;
2050 LPtoDP(hdc, desired, 2);
2051 desired[1].x -= desired[0].x;
2052 desired[1].y -= desired[0].y;
2054 if (GetGraphicsMode(hdc) == GM_COMPATIBLE)
2056 if (xform.eM11 < 0)
2057 desired[1].x = -desired[1].x;
2058 if (xform.eM22 < 0)
2059 desired[1].y = -desired[1].y;
2062 deltas[i].x = desired[1].x - width.x;
2063 deltas[i].y = desired[1].y - width.y;
2065 width = desired[1];
2067 flags |= ETO_PDY;
2069 else
2071 POINT desired[2];
2073 get_text_extent(data, str, count, 0, NULL, NULL, &sz, !!(flags & ETO_GLYPH_INDEX));
2074 desired[0].x = desired[0].y = 0;
2075 desired[1].x = sz.cx;
2076 desired[1].y = 0;
2077 LPtoDP(hdc, desired, 2);
2078 desired[1].x -= desired[0].x;
2079 desired[1].y -= desired[0].y;
2081 if (GetGraphicsMode(hdc) == GM_COMPATIBLE)
2083 if (xform.eM11 < 0)
2084 desired[1].x = -desired[1].x;
2085 if (xform.eM22 < 0)
2086 desired[1].y = -desired[1].y;
2088 width = desired[1];
2091 tm.tmAscent = abs(INTERNAL_YWSTODS(hdc, tm.tmAscent));
2092 tm.tmDescent = abs(INTERNAL_YWSTODS(hdc, tm.tmDescent));
2093 switch(align & (TA_LEFT | TA_RIGHT | TA_CENTER))
2095 case TA_LEFT:
2096 if (align & TA_UPDATECP)
2098 pt.x = x + width.x;
2099 pt.y = y + width.y;
2100 DPtoLP(hdc, &pt, 1);
2101 MoveToEx(hdc, pt.x, pt.y, NULL);
2103 break;
2105 case TA_CENTER:
2106 x -= width.x / 2;
2107 y -= width.y / 2;
2108 break;
2110 case TA_RIGHT:
2111 x -= width.x;
2112 y -= width.y;
2113 if (align & TA_UPDATECP)
2115 pt.x = x;
2116 pt.y = y;
2117 DPtoLP(hdc, &pt, 1);
2118 MoveToEx(hdc, pt.x, pt.y, NULL);
2120 break;
2123 switch(align & (TA_TOP | TA_BOTTOM | TA_BASELINE))
2125 case TA_TOP:
2126 y += tm.tmAscent * cosEsc;
2127 x += tm.tmAscent * sinEsc;
2128 break;
2130 case TA_BOTTOM:
2131 y -= tm.tmDescent * cosEsc;
2132 x -= tm.tmDescent * sinEsc;
2133 break;
2135 case TA_BASELINE:
2136 break;
2139 if (GetBkMode(hdc) != TRANSPARENT)
2141 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
2143 if(!(flags & ETO_OPAQUE) || !rect ||
2144 x < rc.left || x + width.x >= rc.right ||
2145 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
2147 RECT text_box;
2148 text_box.left = x;
2149 text_box.right = x + width.x;
2150 text_box.top = y - tm.tmAscent;
2151 text_box.bottom = y + tm.tmDescent;
2153 if (flags & ETO_CLIPPED) intersect_rect(&text_box, &text_box, &rc);
2154 if (!IsRectEmpty(&text_box))
2155 PSDRV_ExtTextOut(&data->pdev->dev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL);
2160 ret = PSDRV_ExtTextOut(&data->pdev->dev, x, y, (flags & ~ETO_OPAQUE), &rc,
2161 str, count, (INT*)deltas);
2163 done:
2164 free(deltas);
2166 if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2168 int underlinePos, strikeoutPos;
2169 int underlineWidth, strikeoutWidth;
2170 UINT size = NtGdiGetOutlineTextMetricsInternalW(hdc, 0, NULL, 0);
2171 OUTLINETEXTMETRICW* otm = NULL;
2172 POINT pts[5];
2173 HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));
2174 HPEN hpen = GetStockObject(NULL_PEN);
2176 PSDRV_SelectPen(&data->pdev->dev, hpen, NULL);
2177 hpen = SelectObject(hdc, hpen);
2179 PSDRV_SelectBrush(&data->pdev->dev, hbrush, NULL);
2180 hbrush = SelectObject(hdc, hbrush);
2182 if(!size)
2184 underlinePos = 0;
2185 underlineWidth = tm.tmAscent / 20 + 1;
2186 strikeoutPos = tm.tmAscent / 2;
2187 strikeoutWidth = underlineWidth;
2189 else
2191 otm = malloc(size);
2192 NtGdiGetOutlineTextMetricsInternalW(hdc, size, otm, 0);
2193 underlinePos = abs(INTERNAL_YWSTODS(hdc, otm->otmsUnderscorePosition));
2194 if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
2195 underlineWidth = get_line_width(hdc, otm->otmsUnderscoreSize);
2196 strikeoutPos = abs(INTERNAL_YWSTODS(hdc, otm->otmsStrikeoutPosition));
2197 if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
2198 strikeoutWidth = get_line_width(hdc, otm->otmsStrikeoutSize);
2199 free(otm);
2203 if (lf.lfUnderline)
2205 const INT cnt = 5;
2206 pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
2207 pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
2208 pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
2209 pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2210 pts[2].x = pts[1].x + underlineWidth * sinEsc;
2211 pts[2].y = pts[1].y + underlineWidth * cosEsc;
2212 pts[3].x = pts[0].x + underlineWidth * sinEsc;
2213 pts[3].y = pts[0].y + underlineWidth * cosEsc;
2214 pts[4].x = pts[0].x;
2215 pts[4].y = pts[0].y;
2216 DPtoLP(hdc, pts, 5);
2217 PSDRV_PolyPolygon(&data->pdev->dev, pts, &cnt, 1);
2220 if (lf.lfStrikeOut)
2222 const INT cnt = 5;
2223 pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2224 pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2225 pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
2226 pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2227 pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
2228 pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
2229 pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
2230 pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
2231 pts[4].x = pts[0].x;
2232 pts[4].y = pts[0].y;
2233 DPtoLP(hdc, pts, 5);
2234 PSDRV_PolyPolygon(&data->pdev->dev, pts, &cnt, 1);
2237 PSDRV_SelectPen(&data->pdev->dev, hpen, NULL);
2238 SelectObject(hdc, hpen);
2239 select_hbrush(data, htable, handle_count, hbrush);
2240 SelectObject(hdc, hbrush);
2241 DeleteObject(hbrush);
2244 HeapFree(GetProcessHeap(), 0, glyphs);
2245 return ret;
2248 static BOOL fill_rgn(struct pp_data *data, HANDLETABLE *htable, int handle_count, DWORD brush, HRGN rgn)
2250 struct brush_pattern *pattern;
2251 HBRUSH hbrush;
2252 int ret;
2254 hbrush = get_object_handle(data, htable, brush, &pattern);
2255 PSDRV_SelectBrush(&data->pdev->dev, hbrush, pattern);
2256 ret = PSDRV_PaintRgn(&data->pdev->dev, rgn);
2257 select_hbrush(data, htable, handle_count, GetCurrentObject(data->pdev->dev.hdc, OBJ_BRUSH));
2258 PSDRV_SelectBrush(&data->pdev->dev, hbrush, pattern);
2259 return ret;
2262 static BOOL is_path_record(int type)
2264 switch(type)
2266 case EMR_POLYBEZIER:
2267 case EMR_POLYGON:
2268 case EMR_POLYLINE:
2269 case EMR_POLYBEZIERTO:
2270 case EMR_POLYLINETO:
2271 case EMR_POLYPOLYLINE:
2272 case EMR_POLYPOLYGON:
2273 case EMR_MOVETOEX:
2274 case EMR_ANGLEARC:
2275 case EMR_ELLIPSE:
2276 case EMR_RECTANGLE:
2277 case EMR_ROUNDRECT:
2278 case EMR_ARC:
2279 case EMR_CHORD:
2280 case EMR_PIE:
2281 case EMR_LINETO:
2282 case EMR_ARCTO:
2283 case EMR_POLYDRAW:
2284 case EMR_EXTTEXTOUTA:
2285 case EMR_EXTTEXTOUTW:
2286 case EMR_POLYBEZIER16:
2287 case EMR_POLYGON16:
2288 case EMR_POLYLINE16:
2289 case EMR_POLYBEZIERTO16:
2290 case EMR_POLYLINETO16:
2291 case EMR_POLYPOLYLINE16:
2292 case EMR_POLYPOLYGON16:
2293 case EMR_POLYDRAW16:
2294 return TRUE;
2295 default:
2296 return FALSE;
2300 static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable,
2301 const ENHMETARECORD *rec, int handle_count, LPARAM arg)
2303 struct pp_data *data = (struct pp_data *)arg;
2305 if (data->path && is_path_record(rec->iType))
2306 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count);
2308 switch (rec->iType)
2310 case EMR_HEADER:
2312 const ENHMETAHEADER *header = (const ENHMETAHEADER *)rec;
2314 data->patterns = calloc(sizeof(*data->patterns), header->nHandles);
2315 return data->patterns && PSDRV_StartPage(&data->pdev->dev);
2317 case EMR_POLYBEZIER:
2319 const EMRPOLYBEZIER *p = (const EMRPOLYBEZIER *)rec;
2321 return PSDRV_PolyBezier(&data->pdev->dev, (const POINT *)p->aptl, p->cptl);
2323 case EMR_POLYGON:
2325 const EMRPOLYGON *p = (const EMRPOLYGON *)rec;
2327 return PSDRV_PolyPolygon(&data->pdev->dev, (const POINT *)p->aptl,
2328 (const INT *)&p->cptl, 1);
2330 case EMR_POLYLINE:
2332 const EMRPOLYLINE *p = (const EMRPOLYLINE *)rec;
2334 return PSDRV_PolyPolyline(&data->pdev->dev,
2335 (const POINT *)p->aptl, &p->cptl, 1);
2337 case EMR_POLYBEZIERTO:
2339 const EMRPOLYBEZIERTO *p = (const EMRPOLYBEZIERTO *)rec;
2341 return PSDRV_PolyBezierTo(&data->pdev->dev, (const POINT *)p->aptl, p->cptl) &&
2342 MoveToEx(data->pdev->dev.hdc, p->aptl[p->cptl - 1].x, p->aptl[p->cptl - 1].y, NULL);
2344 case EMR_POLYLINETO:
2346 const EMRPOLYLINETO *p = (const EMRPOLYLINETO *)rec;
2347 POINT *pts;
2348 DWORD cnt;
2349 int ret;
2351 cnt = p->cptl + 1;
2352 pts = malloc(sizeof(*pts) * cnt);
2353 if (!pts) return 0;
2355 GetCurrentPositionEx(data->pdev->dev.hdc, pts);
2356 memcpy(pts + 1, p->aptl, sizeof(*pts) * p->cptl);
2357 ret = PSDRV_PolyPolyline(&data->pdev->dev, pts, &cnt, 1) &&
2358 MoveToEx(data->pdev->dev.hdc, pts[cnt - 1].x, pts[cnt - 1].y, NULL);
2359 free(pts);
2360 return ret;
2362 case EMR_POLYPOLYLINE:
2364 const EMRPOLYPOLYLINE *p = (const EMRPOLYPOLYLINE *)rec;
2366 return PSDRV_PolyPolyline(&data->pdev->dev,
2367 (const POINT *)(p->aPolyCounts + p->nPolys),
2368 p->aPolyCounts, p->nPolys);
2370 case EMR_POLYPOLYGON:
2372 const EMRPOLYPOLYGON *p = (const EMRPOLYPOLYGON *)rec;
2374 return PSDRV_PolyPolygon(&data->pdev->dev,
2375 (const POINT *)(p->aPolyCounts + p->nPolys),
2376 (const INT *)p->aPolyCounts, p->nPolys);
2378 case EMR_EOF:
2379 return PSDRV_EndPage(&data->pdev->dev);
2380 case EMR_SETPIXELV:
2382 const EMRSETPIXELV *p = (const EMRSETPIXELV *)rec;
2384 return PSDRV_SetPixel(&data->pdev->dev, p->ptlPixel.x,
2385 p->ptlPixel.y, p->crColor);
2387 case EMR_SETTEXTCOLOR:
2389 const EMRSETTEXTCOLOR *p = (const EMRSETTEXTCOLOR *)rec;
2391 SetTextColor(data->pdev->dev.hdc, p->crColor);
2392 PSDRV_SetTextColor(&data->pdev->dev, p->crColor);
2393 return 1;
2395 case EMR_SETBKCOLOR:
2397 const EMRSETBKCOLOR *p = (const EMRSETBKCOLOR *)rec;
2399 SetBkColor(data->pdev->dev.hdc, p->crColor);
2400 PSDRV_SetBkColor(&data->pdev->dev, p->crColor);
2401 return 1;
2403 case EMR_SAVEDC:
2405 int ret = PlayEnhMetaFileRecord(hdc, htable, rec, handle_count);
2407 if (!data->saved_dc_size)
2409 data->saved_dc = malloc(8 * sizeof(*data->saved_dc));
2410 if (data->saved_dc)
2411 data->saved_dc_size = 8;
2413 else if (data->saved_dc_size == data->saved_dc_top)
2415 void *alloc = realloc(data->saved_dc, data->saved_dc_size * 2);
2417 if (alloc)
2419 data->saved_dc = alloc;
2420 data->saved_dc_size *= 2;
2423 if (data->saved_dc_size == data->saved_dc_top)
2424 return 0;
2426 data->saved_dc[data->saved_dc_top].break_extra = data->break_extra;
2427 data->saved_dc[data->saved_dc_top].break_rem = data->break_rem;
2428 data->saved_dc_top++;
2429 return ret;
2431 case EMR_RESTOREDC:
2433 const EMRRESTOREDC *p = (const EMRRESTOREDC *)rec;
2434 HDC hdc = data->pdev->dev.hdc;
2435 int ret = PlayEnhMetaFileRecord(hdc, htable, rec, handle_count);
2436 UINT aa_flags;
2438 if (ret)
2440 select_hbrush(data, htable, handle_count, GetCurrentObject(hdc, OBJ_BRUSH));
2441 PSDRV_SelectFont(&data->pdev->dev, GetCurrentObject(hdc, OBJ_FONT), &aa_flags);
2442 PSDRV_SelectPen(&data->pdev->dev, GetCurrentObject(hdc, OBJ_PEN), NULL);
2443 PSDRV_SetBkColor(&data->pdev->dev, GetBkColor(hdc));
2444 PSDRV_SetTextColor(&data->pdev->dev, GetTextColor(hdc));
2446 if (p->iRelative >= 0 || data->saved_dc_top + p->iRelative < 0)
2447 return 0;
2448 data->saved_dc_top += p->iRelative;
2449 data->break_extra = data->saved_dc[data->saved_dc_top].break_extra;
2450 data->break_rem = data->saved_dc[data->saved_dc_top].break_rem;
2452 return ret;
2454 case EMR_SELECTOBJECT:
2456 const EMRSELECTOBJECT *so = (const EMRSELECTOBJECT *)rec;
2457 struct brush_pattern *pattern;
2458 UINT aa_flags;
2459 HGDIOBJ obj;
2461 obj = get_object_handle(data, htable, so->ihObject, &pattern);
2462 SelectObject(data->pdev->dev.hdc, obj);
2464 switch (GetObjectType(obj))
2466 case OBJ_PEN: return PSDRV_SelectPen(&data->pdev->dev, obj, NULL) != NULL;
2467 case OBJ_BRUSH: return PSDRV_SelectBrush(&data->pdev->dev, obj, pattern) != NULL;
2468 case OBJ_FONT: return PSDRV_SelectFont(&data->pdev->dev, obj, &aa_flags) != NULL;
2469 default:
2470 FIXME("unhandled object type %ld\n", GetObjectType(obj));
2471 return 1;
2474 case EMR_DELETEOBJECT:
2476 const EMRDELETEOBJECT *p = (const EMRDELETEOBJECT *)rec;
2478 memset(&data->patterns[p->ihObject], 0, sizeof(*data->patterns));
2479 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count);
2481 case EMR_ANGLEARC:
2483 const EMRANGLEARC *p = (const EMRANGLEARC *)rec;
2484 int arc_dir = SetArcDirection(data->pdev->dev.hdc,
2485 p->eSweepAngle >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE);
2486 EMRARCTO arcto;
2487 int ret;
2489 arcto.emr.iType = EMR_ARCTO;
2490 arcto.rclBox.left = p->ptlCenter.x - p->nRadius;
2491 arcto.rclBox.top = p->ptlCenter.y - p->nRadius;
2492 arcto.rclBox.right = p->ptlCenter.x + p->nRadius;
2493 arcto.rclBox.bottom = p->ptlCenter.y + p->nRadius;
2494 arcto.ptlStart.x = GDI_ROUND(p->ptlCenter.x +
2495 cos(p->eStartAngle * M_PI / 180) * p->nRadius);
2496 arcto.ptlStart.y = GDI_ROUND(p->ptlCenter.y -
2497 sin(p->eStartAngle * M_PI / 180) * p->nRadius);
2498 arcto.ptlEnd.x = GDI_ROUND(p->ptlCenter.x +
2499 cos((p->eStartAngle + p->eSweepAngle) * M_PI / 180) * p->nRadius);
2500 arcto.ptlEnd.y = GDI_ROUND(p->ptlCenter.y -
2501 sin((p->eStartAngle + p->eSweepAngle) * M_PI / 180) * p->nRadius);
2503 ret = hmf_proc(hdc, htable, (ENHMETARECORD *)&arcto, handle_count, arg);
2504 SetArcDirection(data->pdev->dev.hdc, arc_dir);
2505 return ret;
2507 case EMR_ELLIPSE:
2509 const EMRELLIPSE *p = (const EMRELLIPSE *)rec;
2510 const RECTL *r = &p->rclBox;
2512 return PSDRV_Ellipse(&data->pdev->dev, r->left, r->top, r->right, r->bottom);
2514 case EMR_RECTANGLE:
2516 const EMRRECTANGLE *rect = (const EMRRECTANGLE *)rec;
2518 return PSDRV_Rectangle(&data->pdev->dev, rect->rclBox.left,
2519 rect->rclBox.top, rect->rclBox.right, rect->rclBox.bottom);
2521 case EMR_ROUNDRECT:
2523 const EMRROUNDRECT *p = (const EMRROUNDRECT *)rec;
2525 return PSDRV_RoundRect(&data->pdev->dev, p->rclBox.left,
2526 p->rclBox.top, p->rclBox.right, p->rclBox.bottom,
2527 p->szlCorner.cx, p->szlCorner.cy);
2529 case EMR_ARC:
2531 const EMRARC *p = (const EMRARC *)rec;
2533 return PSDRV_Arc(&data->pdev->dev, p->rclBox.left, p->rclBox.top,
2534 p->rclBox.right, p->rclBox.bottom, p->ptlStart.x,
2535 p->ptlStart.y, p->ptlEnd.x, p->ptlEnd.y);
2537 case EMR_CHORD:
2539 const EMRCHORD *p = (const EMRCHORD *)rec;
2541 return PSDRV_Chord(&data->pdev->dev, p->rclBox.left, p->rclBox.top,
2542 p->rclBox.right, p->rclBox.bottom, p->ptlStart.x,
2543 p->ptlStart.y, p->ptlEnd.x, p->ptlEnd.y);
2545 case EMR_PIE:
2547 const EMRPIE *p = (const EMRPIE *)rec;
2549 return PSDRV_Pie(&data->pdev->dev, p->rclBox.left, p->rclBox.top,
2550 p->rclBox.right, p->rclBox.bottom, p->ptlStart.x,
2551 p->ptlStart.y, p->ptlEnd.x, p->ptlEnd.y);
2553 case EMR_LINETO:
2555 const EMRLINETO *line = (const EMRLINETO *)rec;
2557 return PSDRV_LineTo(&data->pdev->dev, line->ptl.x, line->ptl.y) &&
2558 MoveToEx(data->pdev->dev.hdc, line->ptl.x, line->ptl.y, NULL);
2560 case EMR_ARCTO:
2562 const EMRARCTO *p = (const EMRARCTO *)rec;
2563 POINT pt;
2564 BOOL ret;
2566 ret = GetCurrentPositionEx(data->pdev->dev.hdc, &pt);
2567 if (ret)
2569 ret = ArcTo(data->pdev->dev.hdc, p->rclBox.left, p->rclBox.top,
2570 p->rclBox.right, p->rclBox.bottom, p->ptlStart.x,
2571 p->ptlStart.y, p->ptlStart.x, p->ptlStart.y);
2573 if (ret)
2574 ret = PSDRV_LineTo(&data->pdev->dev, pt.x, pt.y);
2575 if (ret)
2577 ret = PSDRV_Arc(&data->pdev->dev, p->rclBox.left, p->rclBox.top,
2578 p->rclBox.right, p->rclBox.bottom, p->ptlStart.x,
2579 p->ptlStart.y, p->ptlEnd.x, p->ptlEnd.y);
2581 if (ret)
2583 ret = ArcTo(data->pdev->dev.hdc, p->rclBox.left, p->rclBox.top,
2584 p->rclBox.right, p->rclBox.bottom, p->ptlEnd.x,
2585 p->ptlEnd.y, p->ptlEnd.x, p->ptlEnd.y);
2587 return ret;
2589 case EMR_POLYDRAW:
2591 const EMRPOLYDRAW *p = (const EMRPOLYDRAW *)rec;
2592 const POINT *pts = (const POINT *)p->aptl;
2594 return poly_draw(&data->pdev->dev, pts, (BYTE *)(p->aptl + p->cptl), p->cptl) &&
2595 MoveToEx(data->pdev->dev.hdc, pts[p->cptl - 1].x, pts[p->cptl - 1].y, NULL);
2597 case EMR_BEGINPATH:
2599 data->path = TRUE;
2600 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count);
2602 case EMR_ENDPATH:
2604 data->path = FALSE;
2605 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count);
2607 case EMR_FILLPATH:
2608 PSDRV_FillPath(&data->pdev->dev);
2609 return 1;
2610 case EMR_STROKEANDFILLPATH:
2611 PSDRV_StrokeAndFillPath(&data->pdev->dev);
2612 return 1;
2613 case EMR_STROKEPATH:
2614 PSDRV_StrokePath(&data->pdev->dev);
2615 return 1;
2616 case EMR_ABORTPATH:
2618 data->path = FALSE;
2619 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count);
2621 case EMR_FILLRGN:
2623 const EMRFILLRGN *p = (const EMRFILLRGN *)rec;
2624 HRGN rgn;
2625 int ret;
2627 rgn = ExtCreateRegion(NULL, p->cbRgnData, (const RGNDATA *)p->RgnData);
2628 ret = fill_rgn(data, htable, handle_count, p->ihBrush, rgn);
2629 DeleteObject(rgn);
2630 return ret;
2632 case EMR_FRAMERGN:
2634 const EMRFRAMERGN *p = (const EMRFRAMERGN *)rec;
2635 HRGN rgn, frame;
2636 int ret;
2638 rgn = ExtCreateRegion(NULL, p->cbRgnData, (const RGNDATA *)p->RgnData);
2639 frame = CreateRectRgn(0, 0, 0, 0);
2641 CombineRgn(frame, rgn, 0, RGN_COPY);
2642 OffsetRgn(frame, -p->szlStroke.cx, 0);
2643 OffsetRgn(rgn, p->szlStroke.cx, 0);
2644 CombineRgn(frame, frame, rgn, RGN_AND);
2645 OffsetRgn(rgn, -p->szlStroke.cx, -p->szlStroke.cy);
2646 CombineRgn(frame, frame, rgn, RGN_AND);
2647 OffsetRgn(rgn, 0, 2*p->szlStroke.cy);
2648 CombineRgn(frame, frame, rgn, RGN_AND);
2649 OffsetRgn(rgn, 0, -p->szlStroke.cy);
2650 CombineRgn(frame, rgn, frame, RGN_DIFF);
2652 ret = fill_rgn(data, htable, handle_count, p->ihBrush, frame);
2653 DeleteObject(rgn);
2654 DeleteObject(frame);
2655 return ret;
2657 case EMR_INVERTRGN:
2659 const EMRINVERTRGN *p = (const EMRINVERTRGN *)rec;
2660 int old_rop, ret;
2661 HRGN rgn;
2663 rgn = ExtCreateRegion(NULL, p->cbRgnData, (const RGNDATA *)p->RgnData);
2664 old_rop = SetROP2(data->pdev->dev.hdc, R2_NOT);
2665 ret = fill_rgn(data, htable, handle_count, 0x80000000 | BLACK_BRUSH, rgn);
2666 SetROP2(data->pdev->dev.hdc, old_rop);
2667 DeleteObject(rgn);
2668 return ret;
2670 case EMR_PAINTRGN:
2672 const EMRPAINTRGN *p = (const EMRPAINTRGN *)rec;
2673 HRGN rgn = ExtCreateRegion(NULL, p->cbRgnData, (const RGNDATA *)p->RgnData);
2674 int ret;
2676 ret = PSDRV_PaintRgn(&data->pdev->dev, rgn);
2677 DeleteObject(rgn);
2678 return ret;
2680 case EMR_BITBLT:
2682 const EMRBITBLT *p = (const EMRBITBLT *)rec;
2683 const BITMAPINFO *bi = (const BITMAPINFO *)((BYTE *)p + p->offBmiSrc);
2684 const BYTE *src_bits = (BYTE *)p + p->offBitsSrc;
2685 EMRSTRETCHBLT blt;
2688 blt.rclBounds = p->rclBounds;
2689 blt.xDest = p->xDest;
2690 blt.yDest = p->yDest;
2691 blt.cxDest = p->cxDest;
2692 blt.cyDest = p->cyDest;
2693 blt.dwRop = p->dwRop;
2694 blt.xSrc = p->xSrc;
2695 blt.ySrc = p->ySrc;
2696 blt.xformSrc = p->xformSrc;
2697 blt.crBkColorSrc = p->crBkColorSrc;
2698 blt.iUsageSrc = p->iUsageSrc;
2699 blt.offBmiSrc = p->offBmiSrc;
2700 blt.cbBmiSrc = p->cbBmiSrc;
2701 blt.offBitsSrc = p->offBitsSrc;
2702 blt.cbBitsSrc = p->cbBitsSrc;
2703 blt.cxSrc = p->cxDest;
2704 blt.cySrc = p->cyDest;
2706 return stretch_blt(&data->pdev->dev, &blt, bi, src_bits);
2708 case EMR_STRETCHBLT:
2710 const EMRSTRETCHBLT *p = (const EMRSTRETCHBLT *)rec;
2711 const BITMAPINFO *bi = (const BITMAPINFO *)((BYTE *)p + p->offBmiSrc);
2712 const BYTE *src_bits = (BYTE *)p + p->offBitsSrc;
2714 return stretch_blt(&data->pdev->dev, p, bi, src_bits);
2716 case EMR_MASKBLT:
2718 const EMRMASKBLT *p = (const EMRMASKBLT *)rec;
2719 const BITMAPINFO *mask_bi = (const BITMAPINFO *)((BYTE *)p + p->offBmiMask);
2720 const BITMAPINFO *src_bi = (const BITMAPINFO *)((BYTE *)p + p->offBmiSrc);
2721 const BYTE *mask_bits = (BYTE *)p + p->offBitsMask;
2722 const BYTE *src_bits = (BYTE *)p + p->offBitsSrc;
2724 return mask_blt(&data->pdev->dev, p, src_bi, src_bits, mask_bi, mask_bits);
2726 case EMR_PLGBLT:
2728 const EMRPLGBLT *p = (const EMRPLGBLT *)rec;
2730 return plg_blt(&data->pdev->dev, p);
2732 case EMR_SETDIBITSTODEVICE:
2733 return set_di_bits_to_device(&data->pdev->dev, (const EMRSETDIBITSTODEVICE *)rec);
2734 case EMR_STRETCHDIBITS:
2735 return stretch_di_bits(&data->pdev->dev, (const EMRSTRETCHDIBITS *)rec);
2736 case EMR_EXTTEXTOUTW:
2738 const EMREXTTEXTOUTW *p = (const EMREXTTEXTOUTW *)rec;
2739 HDC hdc = data->pdev->dev.hdc;
2740 const INT *dx = NULL;
2741 int old_mode, ret;
2742 RECT rect;
2744 rect.left = p->emrtext.rcl.left;
2745 rect.top = p->emrtext.rcl.top;
2746 rect.right = p->emrtext.rcl.right;
2747 rect.bottom = p->emrtext.rcl.bottom;
2749 old_mode = SetGraphicsMode(hdc, p->iGraphicsMode);
2750 /* Reselect the font back into the dc so that the transformation
2751 gets updated. */
2752 SelectObject(hdc, GetCurrentObject(hdc, OBJ_FONT));
2754 if (p->emrtext.offDx)
2755 dx = (const INT *)((const BYTE *)rec + p->emrtext.offDx);
2757 ret = ext_text_out(data, htable, handle_count, p->emrtext.ptlReference.x,
2758 p->emrtext.ptlReference.y, p->emrtext.fOptions, &rect,
2759 (LPCWSTR)((const BYTE *)rec + p->emrtext.offString), p->emrtext.nChars, dx);
2761 SetGraphicsMode(hdc, old_mode);
2762 return ret;
2764 case EMR_POLYBEZIER16:
2766 const EMRPOLYBEZIER16 *p = (const EMRPOLYBEZIER16 *)rec;
2767 POINT *pts;
2768 int i;
2770 pts = malloc(sizeof(*pts) * p->cpts);
2771 if (!pts) return 0;
2772 for (i = 0; i < p->cpts; i++)
2774 pts[i].x = p->apts[i].x;
2775 pts[i].y = p->apts[i].y;
2777 i = PSDRV_PolyBezier(&data->pdev->dev, pts, p->cpts);
2778 free(pts);
2779 return i;
2781 case EMR_POLYGON16:
2783 const EMRPOLYGON16 *p = (const EMRPOLYGON16 *)rec;
2784 POINT *pts;
2785 int i;
2787 pts = malloc(sizeof(*pts) * p->cpts);
2788 if (!pts) return 0;
2789 for (i = 0; i < p->cpts; i++)
2791 pts[i].x = p->apts[i].x;
2792 pts[i].y = p->apts[i].y;
2794 i = PSDRV_PolyPolygon(&data->pdev->dev, pts, (const INT *)&p->cpts, 1);
2795 free(pts);
2796 return i;
2798 case EMR_POLYLINE16:
2800 const EMRPOLYLINE16 *p = (const EMRPOLYLINE16 *)rec;
2801 POINT *pts;
2802 int i;
2804 pts = malloc(sizeof(*pts) * p->cpts);
2805 if (!pts) return 0;
2806 for (i = 0; i < p->cpts; i++)
2808 pts[i].x = p->apts[i].x;
2809 pts[i].y = p->apts[i].y;
2811 i = PSDRV_PolyPolyline(&data->pdev->dev, pts, &p->cpts, 1);
2812 free(pts);
2813 return i;
2815 case EMR_POLYBEZIERTO16:
2817 const EMRPOLYBEZIERTO16 *p = (const EMRPOLYBEZIERTO16 *)rec;
2818 POINT *pts;
2819 int i;
2821 pts = malloc(sizeof(*pts) * p->cpts);
2822 if (!pts) return 0;
2823 for (i = 0; i < p->cpts; i++)
2825 pts[i].x = p->apts[i].x;
2826 pts[i].y = p->apts[i].y;
2828 i = PSDRV_PolyBezierTo(&data->pdev->dev, pts, p->cpts) &&
2829 MoveToEx(data->pdev->dev.hdc, pts[p->cpts - 1].x, pts[p->cpts - 1].y, NULL);
2830 free(pts);
2831 return i;
2833 case EMR_POLYLINETO16:
2835 const EMRPOLYLINETO16 *p = (const EMRPOLYLINETO16 *)rec;
2836 POINT *pts;
2837 DWORD cnt;
2838 int i;
2840 cnt = p->cpts + 1;
2841 pts = malloc(sizeof(*pts) * cnt);
2842 if (!pts) return 0;
2843 GetCurrentPositionEx(data->pdev->dev.hdc, pts);
2844 for (i = 0; i < p->cpts; i++)
2846 pts[i + 1].x = p->apts[i].x;
2847 pts[i + 1].y = p->apts[i].y;
2849 i = PSDRV_PolyPolyline(&data->pdev->dev, pts, &cnt, 1) &&
2850 MoveToEx(data->pdev->dev.hdc, pts[cnt - 1].x, pts[cnt - 1].y, NULL);
2851 free(pts);
2852 return i;
2854 case EMR_POLYPOLYLINE16:
2856 const EMRPOLYPOLYLINE16 *p = (const EMRPOLYPOLYLINE16 *)rec;
2857 POINT *pts;
2858 int i;
2860 pts = malloc(sizeof(*pts) * p->cpts);
2861 if (!pts) return 0;
2862 for (i = 0; i < p->cpts; i++)
2864 pts[i].x = ((const POINTS *)(p->aPolyCounts + p->nPolys))[i].x;
2865 pts[i].y = ((const POINTS *)(p->aPolyCounts + p->nPolys))[i].y;
2867 i = PSDRV_PolyPolyline(&data->pdev->dev, pts, p->aPolyCounts, p->nPolys);
2868 free(pts);
2869 return i;
2871 case EMR_POLYPOLYGON16:
2873 const EMRPOLYPOLYGON16 *p = (const EMRPOLYPOLYGON16 *)rec;
2874 POINT *pts;
2875 int i;
2877 pts = malloc(sizeof(*pts) * p->cpts);
2878 if (!pts) return 0;
2879 for (i = 0; i < p->cpts; i++)
2881 pts[i].x = ((const POINTS *)(p->aPolyCounts + p->nPolys))[i].x;
2882 pts[i].y = ((const POINTS *)(p->aPolyCounts + p->nPolys))[i].y;
2884 i = PSDRV_PolyPolygon(&data->pdev->dev, pts, (const INT *)p->aPolyCounts, p->nPolys);
2885 free(pts);
2886 return i;
2888 case EMR_POLYDRAW16:
2890 const EMRPOLYDRAW16 *p = (const EMRPOLYDRAW16 *)rec;
2891 POINT *pts;
2892 int i;
2894 pts = malloc(sizeof(*pts) * p->cpts);
2895 if (!pts) return 0;
2896 for (i = 0; i < p->cpts; i++)
2898 pts[i].x = p->apts[i].x;
2899 pts[i].y = p->apts[i].y;
2901 i = poly_draw(&data->pdev->dev, pts, (BYTE *)(p->apts + p->cpts), p->cpts) &&
2902 MoveToEx(data->pdev->dev.hdc, pts[p->cpts - 1].x, pts[p->cpts - 1].y, NULL);
2903 free(pts);
2904 return i;
2906 case EMR_CREATEMONOBRUSH:
2908 const EMRCREATEMONOBRUSH *p = (const EMRCREATEMONOBRUSH *)rec;
2910 if (!PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count))
2911 return 0;
2912 data->patterns[p->ihBrush].usage = p->iUsage;
2913 data->patterns[p->ihBrush].info = (BITMAPINFO *)((BYTE *)p + p->offBmi);
2914 data->patterns[p->ihBrush].bits.ptr = (BYTE *)p + p->offBits;
2915 return 1;
2917 case EMR_CREATEDIBPATTERNBRUSHPT:
2919 const EMRCREATEDIBPATTERNBRUSHPT *p = (const EMRCREATEDIBPATTERNBRUSHPT *)rec;
2921 if (!PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count))
2922 return 0;
2923 data->patterns[p->ihBrush].usage = p->iUsage;
2924 data->patterns[p->ihBrush].info = (BITMAPINFO *)((BYTE *)p + p->offBmi);
2925 data->patterns[p->ihBrush].bits.ptr = (BYTE *)p + p->offBits;
2926 return 1;
2928 case EMR_EXTESCAPE:
2930 const struct EMREXTESCAPE
2932 EMR emr;
2933 DWORD escape;
2934 DWORD size;
2935 BYTE data[1];
2936 } *p = (const struct EMREXTESCAPE *)rec;
2938 PSDRV_ExtEscape(&data->pdev->dev, p->escape, p->size, p->data, 0, NULL);
2939 return 1;
2941 case EMR_GRADIENTFILL:
2943 const EMRGRADIENTFILL *p = (const EMRGRADIENTFILL *)rec;
2945 return gradient_fill(&data->pdev->dev, p->Ver, p->nVer,
2946 p->Ver + p->nVer, p->nTri, p->ulMode);
2948 case EMR_SETTEXTJUSTIFICATION:
2950 const EMRSETTEXTJUSTIFICATION *p = (const EMRSETTEXTJUSTIFICATION *)rec;
2952 data->break_extra = p->break_extra / p->break_count;
2953 data->break_rem = p->break_extra - data->break_extra * p->break_count;
2954 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count);
2957 case EMR_EXTFLOODFILL:
2958 case EMR_ALPHABLEND:
2959 break;
2961 case EMR_SETWINDOWEXTEX:
2962 case EMR_SETWINDOWORGEX:
2963 case EMR_SETVIEWPORTEXTEX:
2964 case EMR_SETVIEWPORTORGEX:
2965 case EMR_SETBRUSHORGEX:
2966 case EMR_SETMAPPERFLAGS:
2967 case EMR_SETMAPMODE:
2968 case EMR_SETBKMODE:
2969 case EMR_SETPOLYFILLMODE:
2970 case EMR_SETROP2:
2971 case EMR_SETSTRETCHBLTMODE:
2972 case EMR_SETTEXTALIGN:
2973 case EMR_OFFSETCLIPRGN:
2974 case EMR_MOVETOEX:
2975 case EMR_EXCLUDECLIPRECT:
2976 case EMR_INTERSECTCLIPRECT:
2977 case EMR_SCALEVIEWPORTEXTEX:
2978 case EMR_SCALEWINDOWEXTEX:
2979 case EMR_SETWORLDTRANSFORM:
2980 case EMR_MODIFYWORLDTRANSFORM:
2981 case EMR_CREATEPEN:
2982 case EMR_CREATEBRUSHINDIRECT:
2983 case EMR_SELECTPALETTE:
2984 case EMR_CREATEPALETTE:
2985 case EMR_SETPALETTEENTRIES:
2986 case EMR_RESIZEPALETTE:
2987 case EMR_REALIZEPALETTE:
2988 case EMR_SETARCDIRECTION:
2989 case EMR_CLOSEFIGURE:
2990 case EMR_FLATTENPATH:
2991 case EMR_WIDENPATH:
2992 case EMR_SELECTCLIPPATH:
2993 case EMR_EXTSELECTCLIPRGN:
2994 case EMR_EXTCREATEFONTINDIRECTW:
2995 case EMR_SETLAYOUT:
2996 return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, handle_count);
2997 default:
2998 FIXME("unsupported record: %ld\n", rec->iType);
3001 return 1;
3004 static BOOL print_metafile(struct pp_data *data, HANDLE hdata)
3006 XFORM xform = { .eM11 = 1, .eM22 = 1 };
3007 record_hdr header;
3008 HENHMETAFILE hmf;
3009 BYTE *buf;
3010 BOOL ret;
3011 DWORD r;
3013 if (!ReadPrinter(hdata, &header, sizeof(header), &r))
3014 return FALSE;
3015 if (r != sizeof(header))
3017 SetLastError(ERROR_INVALID_DATA);
3018 return FALSE;
3021 buf = malloc(header.cjSize);
3022 if (!buf)
3023 return FALSE;
3025 if (!ReadPrinter(hdata, buf, header.cjSize, &r))
3027 free(buf);
3028 return FALSE;
3030 if (r != header.cjSize)
3032 free(buf);
3033 SetLastError(ERROR_INVALID_DATA);
3034 return FALSE;
3037 hmf = SetEnhMetaFileBits(header.cjSize, buf);
3038 free(buf);
3039 if (!hmf)
3040 return FALSE;
3042 AbortPath(data->pdev->dev.hdc);
3043 SetBkColor(data->pdev->dev.hdc, RGB(255, 255, 255));
3044 SetBkMode(data->pdev->dev.hdc, OPAQUE);
3045 SetMapMode(data->pdev->dev.hdc, MM_TEXT);
3046 SetPolyFillMode(data->pdev->dev.hdc, ALTERNATE);
3047 SetROP2(data->pdev->dev.hdc, R2_COPYPEN);
3048 SetStretchBltMode(data->pdev->dev.hdc, BLACKONWHITE);
3049 SetTextAlign(data->pdev->dev.hdc, TA_LEFT | TA_TOP);
3050 SetTextColor(data->pdev->dev.hdc, 0);
3051 SetTextJustification(data->pdev->dev.hdc, 0, 0);
3052 SetWorldTransform(data->pdev->dev.hdc, &xform);
3053 PSDRV_SetTextColor(&data->pdev->dev, 0);
3054 PSDRV_SetBkColor(&data->pdev->dev, RGB(255, 255, 255));
3056 ret = EnumEnhMetaFile(NULL, hmf, hmf_proc, (void *)data, NULL);
3057 DeleteEnhMetaFile(hmf);
3058 free(data->patterns);
3059 data->patterns = NULL;
3060 data->path = FALSE;
3061 data->break_extra = 0;
3062 data->break_rem = 0;
3063 data->saved_dc_top = 0;
3064 return ret;
3067 BOOL WINAPI EnumPrintProcessorDatatypesW(WCHAR *server, WCHAR *name, DWORD level,
3068 BYTE *datatypes, DWORD size, DWORD *needed, DWORD *no)
3070 DATATYPES_INFO_1W *info = (DATATYPES_INFO_1W *)datatypes;
3072 TRACE("%s, %s, %ld, %p, %ld, %p, %p\n", debugstr_w(server), debugstr_w(name),
3073 level, datatypes, size, needed, no);
3075 if (!needed || !no)
3077 SetLastError(ERROR_INVALID_PARAMETER);
3078 return FALSE;
3081 *no = 0;
3082 *needed = sizeof(*info) + sizeof(emf_1003);
3084 if (level != 1 || (size && !datatypes))
3086 SetLastError(ERROR_INVALID_PARAMETER);
3087 return FALSE;
3090 if (size < *needed)
3092 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3093 return FALSE;
3096 *no = 1;
3097 info->pName = (WCHAR*)(info + 1);
3098 memcpy(info + 1, emf_1003, sizeof(emf_1003));
3099 return TRUE;
3102 HANDLE WINAPI OpenPrintProcessor(WCHAR *port, PRINTPROCESSOROPENDATA *open_data)
3104 struct pp_data *data;
3105 HANDLE hport;
3106 HDC hdc;
3108 TRACE("%s, %p\n", debugstr_w(port), open_data);
3110 if (!port || !open_data || !open_data->pDatatype)
3112 SetLastError(ERROR_INVALID_PARAMETER);
3113 return NULL;
3115 if (wcscmp(open_data->pDatatype, emf_1003))
3117 SetLastError(ERROR_INVALID_DATATYPE);
3118 return NULL;
3121 if (!OpenPrinterW(port, &hport, NULL))
3122 return NULL;
3124 data = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*data));
3125 if (!data)
3126 return NULL;
3127 data->magic = PP_MAGIC;
3128 data->hport = hport;
3129 data->doc_name = wcsdup(open_data->pDocumentName);
3130 data->out_file = wcsdup(open_data->pOutputFile);
3132 hdc = CreateCompatibleDC(NULL);
3133 if (!hdc)
3135 LocalFree(data);
3136 return NULL;
3138 SetGraphicsMode(hdc, GM_ADVANCED);
3139 data->pdev = create_psdrv_physdev(hdc, open_data->pPrinterName,
3140 (const PSDRV_DEVMODE *)open_data->pDevMode);
3141 if (!data->pdev)
3143 DeleteDC(hdc);
3144 LocalFree(data);
3145 return NULL;
3147 data->pdev->dev.hdc = hdc;
3148 data->pdev->dev.next = &data->font_dev;
3149 data->font_dev.funcs = &font_funcs;
3150 data->font_dev.hdc = hdc;
3151 return (HANDLE)data;
3154 BOOL WINAPI PrintDocumentOnPrintProcessor(HANDLE pp, WCHAR *doc_name)
3156 struct pp_data *data = get_handle_data(pp);
3157 emfspool_header header;
3158 LARGE_INTEGER pos, cur;
3159 record_hdr record;
3160 HANDLE spool_data;
3161 DOC_INFO_1W info;
3162 BOOL ret;
3163 DWORD r;
3165 TRACE("%p, %s\n", pp, debugstr_w(doc_name));
3167 if (!data)
3168 return FALSE;
3170 if (!OpenPrinterW(doc_name, &spool_data, NULL))
3171 return FALSE;
3173 info.pDocName = data->doc_name;
3174 info.pOutputFile = data->out_file;
3175 info.pDatatype = (WCHAR *)L"RAW";
3176 data->pdev->job.id = StartDocPrinterW(data->hport, 1, (BYTE *)&info);
3177 if (!data->pdev->job.id)
3179 ClosePrinter(spool_data);
3180 return FALSE;
3183 if (!(ret = ReadPrinter(spool_data, &header, sizeof(header), &r)))
3184 goto cleanup;
3185 if (r != sizeof(header))
3187 SetLastError(ERROR_INVALID_DATA);
3188 ret = FALSE;
3189 goto cleanup;
3192 if (header.dwVersion != EMFSPOOL_VERSION)
3194 FIXME("unrecognized spool file format\n");
3195 SetLastError(ERROR_INTERNAL_ERROR);
3196 goto cleanup;
3198 pos.QuadPart = header.cjSize;
3199 if (!(ret = SeekPrinter(spool_data, pos, NULL, FILE_BEGIN, FALSE)))
3200 goto cleanup;
3202 data->pdev->job.hprinter = data->hport;
3203 if (!PSDRV_WriteHeader(&data->pdev->dev, data->doc_name))
3205 WARN("Failed to write header\n");
3206 goto cleanup;
3208 data->pdev->job.banding = FALSE;
3209 data->pdev->job.OutOfPage = TRUE;
3210 data->pdev->job.PageNo = 0;
3211 data->pdev->job.quiet = FALSE;
3212 data->pdev->job.passthrough_state = passthrough_none;
3213 data->pdev->job.doc_name = strdupW(data->doc_name);
3215 while (1)
3217 if (!(ret = ReadPrinter(spool_data, &record, sizeof(record), &r)))
3218 goto cleanup;
3219 if (!r)
3220 break;
3221 if (r != sizeof(record))
3223 SetLastError(ERROR_INVALID_DATA);
3224 ret = FALSE;
3225 goto cleanup;
3228 switch (record.ulID)
3230 case EMRI_METAFILE_DATA:
3231 pos.QuadPart = record.cjSize;
3232 ret = SeekPrinter(spool_data, pos, NULL, FILE_CURRENT, FALSE);
3233 if (!ret)
3234 goto cleanup;
3235 break;
3236 case EMRI_METAFILE_EXT:
3237 case EMRI_BW_METAFILE_EXT:
3238 pos.QuadPart = 0;
3239 ret = SeekPrinter(spool_data, pos, &cur, FILE_CURRENT, FALSE);
3240 if (ret)
3242 cur.QuadPart += record.cjSize;
3243 ret = ReadPrinter(spool_data, &pos, sizeof(pos), &r);
3244 if (r != sizeof(pos))
3246 SetLastError(ERROR_INVALID_DATA);
3247 ret = FALSE;
3250 pos.QuadPart = -pos.QuadPart - 2 * sizeof(record);
3251 if (ret)
3252 ret = SeekPrinter(spool_data, pos, NULL, FILE_CURRENT, FALSE);
3253 if (ret)
3254 ret = print_metafile(data, spool_data);
3255 if (ret)
3256 ret = SeekPrinter(spool_data, cur, NULL, FILE_BEGIN, FALSE);
3257 if (!ret)
3258 goto cleanup;
3259 break;
3260 default:
3261 FIXME("%s not supported, skipping\n", debugstr_rec_type(record.ulID));
3262 pos.QuadPart = record.cjSize;
3263 ret = SeekPrinter(spool_data, pos, NULL, FILE_CURRENT, FALSE);
3264 if (!ret)
3265 goto cleanup;
3266 break;
3270 cleanup:
3271 if (data->pdev->job.PageNo)
3272 PSDRV_WriteFooter(&data->pdev->dev);
3274 HeapFree(GetProcessHeap(), 0, data->pdev->job.doc_name);
3275 ClosePrinter(spool_data);
3276 return EndDocPrinter(data->hport) && ret;
3279 BOOL WINAPI ControlPrintProcessor(HANDLE pp, DWORD cmd)
3281 FIXME("%p, %ld\n", pp, cmd);
3282 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3283 return FALSE;
3286 BOOL WINAPI ClosePrintProcessor(HANDLE pp)
3288 struct pp_data *data = get_handle_data(pp);
3290 TRACE("%p\n", pp);
3292 if (!data)
3293 return FALSE;
3295 ClosePrinter(data->hport);
3296 free(data->doc_name);
3297 free(data->out_file);
3298 DeleteDC(data->pdev->dev.hdc);
3299 HeapFree(GetProcessHeap(), 0, data->pdev->Devmode);
3300 HeapFree(GetProcessHeap(), 0, data->pdev);
3301 free(data->saved_dc);
3303 memset(data, 0, sizeof(*data));
3304 LocalFree(data);
3305 return TRUE;
3308 HRESULT WINAPI DllRegisterServer(void)
3310 AddPrintProcessorW(NULL, (WCHAR *)L"Windows 4.0", (WCHAR *)L"wineps.drv", (WCHAR *)L"wineps");
3311 AddPrintProcessorW(NULL, NULL, (WCHAR *)L"wineps.drv", (WCHAR *)L"wineps");
3312 return S_OK;