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
27 #include <ddk/winsplp.h>
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(psdrv
);
36 #define EMFSPOOL_VERSION 0x10000
37 #define PP_MAGIC 0x952173fe
47 struct gdi_physdev font_dev
;
49 struct brush_pattern
*patterns
;
75 EMRI_BW_FORM_METAFILE
,
81 EMRI_DESIGNVECTOR_EXT
,
90 unsigned int dwVersion
;
92 unsigned int dpszDocName
;
93 unsigned int dpszOutput
;
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
)
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
);
140 FIXME("unknown record type: %d\n", id
);
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
);
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
};
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
);
175 static BOOL CDECL
font_GetTextExtentExPoint(PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
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
)
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
);
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
)
225 rect
->right
= x
+ width
;
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
)
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
;
250 if (rect
->top
> rect
->bottom
)
253 rect
->top
= rect
->bottom
;
258 static BOOL
intersect_vis_rectangles(struct bitblt_coords
*dst
, struct bitblt_coords
*src
)
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 */
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
;
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 */
307 if (!IntersectRect(&dst
->visrect
, &rect
, &dst
->visrect
)) return FALSE
;
309 /* map destination rectangle back to source coordinates */
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
;
320 /* avoid rounding errors */
325 if (!IntersectRect(&src
->visrect
, &rect
, &src
->visrect
)) return FALSE
;
330 static void clip_visrect(HDC hdc
, RECT
*dst
, const RECT
*src
)
334 hrgn
= CreateRectRgn(0, 0, 0, 0);
335 if (GetRandomRgn(hdc
, hrgn
, 3) == 1)
337 GetRgnBox(hrgn
, dst
);
338 IntersectRect(dst
, dst
, src
);
347 static void get_vis_rectangles(HDC hdc
, struct bitblt_coords
*dst
,
348 const XFORM
*xform
, DWORD width
, DWORD height
, struct bitblt_coords
*src
)
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);
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
);
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
);
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
;
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
;
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
;
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
;
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
);
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
);
440 if (err
!= ERROR_SUCCESS
)
441 FIXME("PutImage returned %ld\n", 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
;
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,
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
);
601 blt
.xformSrc
= p
->xformSrc
;
602 blt
.crBkColorSrc
= p
->crBkColorSrc
;
603 blt
.iUsageSrc
= p
->iUsageSrc
;
605 blt
.cbBmiSrc
= p
->cbBmiSrc
;
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
);
633 brush_dest
= SelectObject(dev
->hdc
, GetStockObject(NULL_BRUSH
));
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
);
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
);
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
;
677 GetTransform(hdc2
, 0x204, &blt
.xformSrc
);
678 blt
.crBkColorSrc
= p
->crBkColorSrc
;
679 blt
.iUsageSrc
= DIB_RGB_COLORS
;
681 blt
.cbBmiSrc
= bmp2_info
->bmiHeader
.biSize
;
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 */
698 DeleteObject(bmp_src
);
699 DeleteObject(brush_mask
);
703 DeleteObject(hdc_src
);
708 static void combine_transform(XFORM
*result
, const XFORM
*xform1
, const XFORM
*xform2
)
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
;
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
;
732 /* parallelogram coords */
736 memcpy(plg
, p
->aptlDest
, sizeof(plg
));
739 rect
[1].x
= p
->xSrc
+ p
->cxSrc
;
742 rect
[2].y
= p
->ySrc
+ p
->cySrc
;
743 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
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)
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
);
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
)
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
)
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
);
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
;
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];
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
;
855 bi
->bmiHeader
.biBitCount
= 24;
857 bi
->bmiHeader
.biCompression
= BI_RGB
;
858 bitmap
= CreateDIBSection(dev
->hdc
, bi
, DIB_RGB_COLORS
, (void **)&bits
, NULL
, 0);
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
);
870 memset(&blt
, 0, sizeof(blt
));
871 blt
.rclBounds
= p
->rclBounds
;
872 blt
.xDest
= p
->xDest
;
873 blt
.yDest
= p
->yDest
+ p
->cySrc
- height
;
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
);
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
;
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];
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
;
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];
942 /* check for valid point types */
943 for (i
= 0; i
< count
; i
++)
948 case PT_LINETO
| PT_CLOSEFIGURE
:
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
;
962 GetCurrentPositionEx(dev
->hdc
, &cur
);
965 for (i
= 0; i
< count
; i
++)
973 case (PT_LINETO
| PT_CLOSEFIGURE
):
977 if (!PSDRV_PolyPolyline(dev
, pts
, &num_pts
, 1))
983 pts
[2] = points
[i
+ 1];
984 pts
[3] = points
[i
+ 2];
985 if (!PSDRV_PolyBezier(dev
, pts
, 4))
992 if (types
[i
] & PT_CLOSEFIGURE
)
997 if (!PSDRV_PolyPolyline(dev
, pts
, &num_pts
, 1))
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
;
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
);
1065 bmp
= CreateDIBSection(hdc_src
, info
, DIB_RGB_COLORS
, &bits
.ptr
, NULL
, 0);
1068 DeleteObject(hdc_src
);
1072 old_bmp
= SelectObject(hdc_src
, bmp
);
1074 /* make src and points relative to the bitmap */
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
;
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
);
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
);
1123 OffsetRgn(rgn
, dst
.visrect
.left
, dst
.visrect
.top
);
1125 ret
= (PSDRV_PutImage(dev
, rgn
, info
, &bits
, &src
, &dst
, SRCCOPY
) == ERROR_SUCCESS
);
1131 static HGDIOBJ
get_object_handle(struct pp_data
*data
, HANDLETABLE
*handletable
,
1132 DWORD i
, struct brush_pattern
**pattern
)
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
;
1150 for (i
= 0; i
< handle_count
; i
++)
1152 if (htable
->objectHandle
[i
] == brush
)
1154 pattern
= data
->patterns
+ i
;
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
)
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
)
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
)
1197 pt
[0].x
= pt
[0].y
= 0;
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
)
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
;
1234 size
->cx
= dx
[count
- 1];
1235 size
->cy
= tm
.tmHeight
;
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
;
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
);
1254 if (count
> 256 && !(pos
= malloc(count
* sizeof(*pos
))))
1258 if ((ret
= get_char_positions(data
, str
, count
, pos
, size
)))
1260 char_extra
= GetTextCharacterExtra(data
->pdev
->dev
.hdc
);
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
);
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.
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 ------------------------------------------------------------------------*/
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) */
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 */
1328 LRI
, /* Isolate formatting characters new with 6.3 */
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
)
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
)
1356 for (; i
>= iStart
- cval
; i
--)
1362 /* THE PARAGRAPH LEVEL */
1364 /*------------------------------------------------------------------------
1365 Function: resolveParagraphs
1367 Resolves the input strings into blocks over which the algorithm
1370 Implements Rule P1 of the Unicode Bidi Algorithm
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 */
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
)
1396 /*------------------------------------------------------------------------
1397 Function: resolveLines
1399 Breaks a paragraph into lines
1401 Input: Array of line break flags
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 */
1416 for(; ich
< cch
; ich
++)
1418 if (pszInput
[ich
] == (WCHAR
)'\n' || (pbrk
&& pbrk
[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
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
)
1448 BYTE oldlevel
= baselevel
;
1451 for (; ich
< cch
; ich
++)
1456 cchrun
= 0; /* any other character breaks the run */
1472 plevel
[ich
] = oldlevel
;
1478 /* reset levels for WS before eot */
1479 SetDeferredRun(plevel
, cchrun
, ich
, baselevel
);
1481 plevel
[ich
] = baselevel
;
1484 oldlevel
= plevel
[ich
];
1486 /* reset level before eot */
1487 SetDeferredRun(plevel
, cchrun
, ich
, baselevel
);
1490 /*------------------------------------------------------------------------
1493 Implements the Line-by-Line phases of the Unicode Bidi Algorithm
1495 Input: Count of characters
1496 Array of character directions
1501 ------------------------------------------------------------------------*/
1502 static void BidiLines(int baselevel
, LPWSTR pszOutLine
, LPCWSTR pszLine
, const WORD
* pclsLine
,
1503 BYTE
* plevelLine
, int cchPara
, const BOOL
* pbrk
)
1509 run
= HeapAlloc(GetProcessHeap(), 0, cchPara
* sizeof(int));
1512 WARN("Out of memory\n");
1518 /* break lines at LS */
1519 cchLine
= resolveLines(pszLine
, pbrk
, cchPara
);
1521 /* resolve whitespace */
1522 resolveWhitespace(baselevel
, pclsLine
, plevelLine
, cchLine
);
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
];
1534 plevelLine
+= cchLine
;
1535 pbrk
+= pbrk
? cchLine
: 0;
1536 pclsLine
+= cchLine
;
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
;
1564 BOOL is_complex
, ret
= FALSE
;
1568 SCRIPT_CONTROL Control
;
1570 SCRIPT_ITEM
*pItems
= NULL
;
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
));
1588 if (!(dwFlags
& GCP_REORDER
))
1590 FIXME("Asked to reorder without reorder flag set\n");
1594 if (lpOutString
&& uCountOut
< uCount
)
1596 FIXME("lpOutString too small\n");
1600 chartype
= HeapAlloc(GetProcessHeap(), 0, uCount
* sizeof(WORD
));
1603 WARN("Out of memory\n");
1608 memcpy(lpOutString
, lpString
, uCount
* sizeof(WCHAR
));
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))
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
)
1625 classify(lpString
, chartype
, uCount
);
1626 for (i
= 0; i
< uCount
; i
++)
1627 switch (chartype
[i
])
1638 HeapFree(GetProcessHeap(), 0, chartype
);
1641 for (i
= 0; i
< uCount
; i
++)
1648 levels
= HeapAlloc(GetProcessHeap(), 0, uCount
* sizeof(BYTE
));
1651 WARN("Out of memory\n");
1656 pItems
= HeapAlloc(GetProcessHeap(),0, maxItems
* sizeof(SCRIPT_ITEM
));
1659 WARN("Out of memory\n");
1665 cMaxGlyphs
= 1.5 * uCount
+ 16;
1666 run_glyphs
= HeapAlloc(GetProcessHeap(),0,sizeof(WORD
) * cMaxGlyphs
);
1669 WARN("Out of memory\n");
1672 pwLogClust
= HeapAlloc(GetProcessHeap(),0,sizeof(WORD
) * uCount
);
1675 WARN("Out of memory\n");
1678 psva
= HeapAlloc(GetProcessHeap(),0,sizeof(SCRIPT_VISATTR
) * cMaxGlyphs
);
1681 WARN("Out of memory\n");
1688 while (done
< uCount
)
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
)
1700 case ON
: chartype
[j
] = NI
;
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);
1710 WARN("Out of memory\n");
1713 pItems
= new_pItems
;
1715 res
= ScriptItemize(lpString
+ done
, i
, maxItems
, &Control
, &State
, pItems
, &nItems
);
1718 if (lpOutString
|| lpOrder
)
1719 for (j
= 0; j
< nItems
; j
++)
1722 for (k
= pItems
[j
].iCharPos
; k
< pItems
[j
+1].iCharPos
; k
++)
1723 levels
[k
] = pItems
[j
].a
.s
.uBidiLevel
;
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);
1738 for (j
= lastgood
= 0; j
< i
; ++j
)
1739 if (levels
[j
] != levels
[lastgood
])
1742 if (levels
[lastgood
] & 1)
1743 for (k
= j
; k
>= lastgood
; --k
)
1744 lpOrder
[done
+ k
] = done
+ j
- k
;
1746 for (k
= lastgood
; k
<= j
; ++k
)
1747 lpOrder
[done
+ k
] = done
+ k
;
1750 if (levels
[lastgood
] & 1)
1751 for (k
= j
- 1; k
>= lastgood
; --k
)
1752 lpOrder
[done
+ k
] = done
+ j
- 1 - k
;
1754 for (k
= lastgood
; k
< j
; ++k
)
1755 lpOrder
[done
+ k
] = done
+ k
;
1758 if (lpGlyphs
&& doGlyphs
)
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
);
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
++)
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
);
1800 run_glyphs
= new_run_glyphs
;
1805 run_glyphs
= new_run_glyphs
;
1808 res
= ScriptShape(hDC
, &psc
, lpString
+ done
+ curItem
->iCharPos
, cChars
, cMaxGlyphs
, &curItem
->a
, run_glyphs
, pwLogClust
, psva
, &cOutGlyphs
);
1812 if (res
== USP_E_SCRIPT_NOT_IN_FONT
)
1813 TRACE("Unable to shape with currently selected font\n");
1815 FIXME("Unable to shape string (%lx)\n",res
);
1818 HeapFree(GetProcessHeap(), 0, *lpGlyphs
);
1825 new_glyphs
= HeapReAlloc(GetProcessHeap(), 0, *lpGlyphs
, sizeof(**lpGlyphs
) * (glyph_i
+ cOutGlyphs
));
1827 new_glyphs
= HeapAlloc(GetProcessHeap(), 0, sizeof(**lpGlyphs
) * (glyph_i
+ cOutGlyphs
));
1830 WARN("Out of memory\n");
1831 HeapFree(GetProcessHeap(), 0, runOrder
);
1832 HeapFree(GetProcessHeap(), 0, visOrder
);
1833 HeapFree(GetProcessHeap(), 0, *lpGlyphs
);
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
);
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
);
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 /***********************************************************************
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
;
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
;
1897 double cosEsc
, sinEsc
;
1901 POINT
*deltas
= NULL
, width
= {0, 0};
1903 WORD
*glyphs
= NULL
;
1906 if (!(flags
& (ETO_GLYPH_INDEX
| ETO_IGNORELANGUAGE
)) && count
> 0)
1908 int glyphs_count
= 0;
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
;
1920 flags
|= ETO_GLYPH_INDEX
;
1921 count
= glyphs_count
;
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
),
1942 if(align
& TA_UPDATECP
)
1944 GetCurrentPositionEx(hdc
, &pt
);
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);
1973 if (rect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
1976 LPtoDP(hdc
, (POINT
*)&rc
, 2);
1978 if (flags
& ETO_OPAQUE
)
1979 PSDRV_ExtTextOut(&data
->pdev
->dev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
1981 else flags
&= ~ETO_CLIPPED
;
1991 LPtoDP(hdc
, &pt
, 1);
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)
2002 POINT total
= {0, 0}, desired
[2];
2004 deltas
= malloc(count
* sizeof(*deltas
));
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];
2017 for (i
= 0; i
< count
; i
++)
2019 deltas
[i
].x
= dx
[i
] + char_extra
;
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];
2032 for (i
= 1; i
< count
; i
++)
2034 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
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
)
2057 desired
[1].x
= -desired
[1].x
;
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
;
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
;
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
)
2084 desired
[1].x
= -desired
[1].x
;
2086 desired
[1].y
= -desired
[1].y
;
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
))
2096 if (align
& TA_UPDATECP
)
2100 DPtoLP(hdc
, &pt
, 1);
2101 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
2113 if (align
& TA_UPDATECP
)
2117 DPtoLP(hdc
, &pt
, 1);
2118 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
2123 switch(align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
))
2126 y
+= tm
.tmAscent
* cosEsc
;
2127 x
+= tm
.tmAscent
* sinEsc
;
2131 y
-= tm
.tmDescent
* cosEsc
;
2132 x
-= tm
.tmDescent
* sinEsc
;
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
)
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
);
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
;
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
);
2185 underlineWidth
= tm
.tmAscent
/ 20 + 1;
2186 strikeoutPos
= tm
.tmAscent
/ 2;
2187 strikeoutWidth
= underlineWidth
;
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
);
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);
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
);
2248 static BOOL
fill_rgn(struct pp_data
*data
, HANDLETABLE
*htable
, int handle_count
, DWORD brush
, HRGN rgn
)
2250 struct brush_pattern
*pattern
;
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
);
2262 static BOOL
is_path_record(int type
)
2266 case EMR_POLYBEZIER
:
2269 case EMR_POLYBEZIERTO
:
2270 case EMR_POLYLINETO
:
2271 case EMR_POLYPOLYLINE
:
2272 case EMR_POLYPOLYGON
:
2284 case EMR_EXTTEXTOUTA
:
2285 case EMR_EXTTEXTOUTW
:
2286 case EMR_POLYBEZIER16
:
2288 case EMR_POLYLINE16
:
2289 case EMR_POLYBEZIERTO16
:
2290 case EMR_POLYLINETO16
:
2291 case EMR_POLYPOLYLINE16
:
2292 case EMR_POLYPOLYGON16
:
2293 case EMR_POLYDRAW16
:
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
);
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
);
2325 const EMRPOLYGON
*p
= (const EMRPOLYGON
*)rec
;
2327 return PSDRV_PolyPolygon(&data
->pdev
->dev
, (const POINT
*)p
->aptl
,
2328 (const INT
*)&p
->cptl
, 1);
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
;
2352 pts
= malloc(sizeof(*pts
) * cnt
);
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
);
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
);
2379 return PSDRV_EndPage(&data
->pdev
->dev
);
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
);
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
);
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
));
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);
2419 data
->saved_dc
= alloc
;
2420 data
->saved_dc_size
*= 2;
2423 if (data
->saved_dc_size
== data
->saved_dc_top
)
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
++;
2433 const EMRRESTOREDC
*p
= (const EMRRESTOREDC
*)rec
;
2434 HDC hdc
= data
->pdev
->dev
.hdc
;
2435 int ret
= PlayEnhMetaFileRecord(hdc
, htable
, rec
, handle_count
);
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)
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
;
2454 case EMR_SELECTOBJECT
:
2456 const EMRSELECTOBJECT
*so
= (const EMRSELECTOBJECT
*)rec
;
2457 struct brush_pattern
*pattern
;
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
;
2470 FIXME("unhandled object type %ld\n", GetObjectType(obj
));
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
);
2483 const EMRANGLEARC
*p
= (const EMRANGLEARC
*)rec
;
2484 int arc_dir
= SetArcDirection(data
->pdev
->dev
.hdc
,
2485 p
->eSweepAngle
>= 0 ? AD_COUNTERCLOCKWISE
: AD_CLOCKWISE
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
2562 const EMRARCTO
*p
= (const EMRARCTO
*)rec
;
2566 ret
= GetCurrentPositionEx(data
->pdev
->dev
.hdc
, &pt
);
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
);
2574 ret
= PSDRV_LineTo(&data
->pdev
->dev
, pt
.x
, pt
.y
);
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
);
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
);
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
);
2600 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, handle_count
);
2605 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, handle_count
);
2608 PSDRV_FillPath(&data
->pdev
->dev
);
2610 case EMR_STROKEANDFILLPATH
:
2611 PSDRV_StrokeAndFillPath(&data
->pdev
->dev
);
2613 case EMR_STROKEPATH
:
2614 PSDRV_StrokePath(&data
->pdev
->dev
);
2619 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, handle_count
);
2623 const EMRFILLRGN
*p
= (const EMRFILLRGN
*)rec
;
2627 rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
2628 ret
= fill_rgn(data
, htable
, handle_count
, p
->ihBrush
, rgn
);
2634 const EMRFRAMERGN
*p
= (const EMRFRAMERGN
*)rec
;
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
);
2654 DeleteObject(frame
);
2659 const EMRINVERTRGN
*p
= (const EMRINVERTRGN
*)rec
;
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
);
2672 const EMRPAINTRGN
*p
= (const EMRPAINTRGN
*)rec
;
2673 HRGN rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
2676 ret
= PSDRV_PaintRgn(&data
->pdev
->dev
, rgn
);
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
;
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
;
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
);
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
);
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
;
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
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
);
2764 case EMR_POLYBEZIER16
:
2766 const EMRPOLYBEZIER16
*p
= (const EMRPOLYBEZIER16
*)rec
;
2770 pts
= malloc(sizeof(*pts
) * p
->cpts
);
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
);
2783 const EMRPOLYGON16
*p
= (const EMRPOLYGON16
*)rec
;
2787 pts
= malloc(sizeof(*pts
) * p
->cpts
);
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);
2798 case EMR_POLYLINE16
:
2800 const EMRPOLYLINE16
*p
= (const EMRPOLYLINE16
*)rec
;
2804 pts
= malloc(sizeof(*pts
) * p
->cpts
);
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);
2815 case EMR_POLYBEZIERTO16
:
2817 const EMRPOLYBEZIERTO16
*p
= (const EMRPOLYBEZIERTO16
*)rec
;
2821 pts
= malloc(sizeof(*pts
) * p
->cpts
);
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
);
2833 case EMR_POLYLINETO16
:
2835 const EMRPOLYLINETO16
*p
= (const EMRPOLYLINETO16
*)rec
;
2841 pts
= malloc(sizeof(*pts
) * cnt
);
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
);
2854 case EMR_POLYPOLYLINE16
:
2856 const EMRPOLYPOLYLINE16
*p
= (const EMRPOLYPOLYLINE16
*)rec
;
2860 pts
= malloc(sizeof(*pts
) * p
->cpts
);
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
);
2871 case EMR_POLYPOLYGON16
:
2873 const EMRPOLYPOLYGON16
*p
= (const EMRPOLYPOLYGON16
*)rec
;
2877 pts
= malloc(sizeof(*pts
) * p
->cpts
);
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
);
2888 case EMR_POLYDRAW16
:
2890 const EMRPOLYDRAW16
*p
= (const EMRPOLYDRAW16
*)rec
;
2894 pts
= malloc(sizeof(*pts
) * p
->cpts
);
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
);
2906 case EMR_CREATEMONOBRUSH
:
2908 const EMRCREATEMONOBRUSH
*p
= (const EMRCREATEMONOBRUSH
*)rec
;
2910 if (!PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, handle_count
))
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
;
2917 case EMR_CREATEDIBPATTERNBRUSHPT
:
2919 const EMRCREATEDIBPATTERNBRUSHPT
*p
= (const EMRCREATEDIBPATTERNBRUSHPT
*)rec
;
2921 if (!PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, handle_count
))
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
;
2930 const struct EMREXTESCAPE
2936 } *p
= (const struct EMREXTESCAPE
*)rec
;
2938 PSDRV_ExtEscape(&data
->pdev
->dev
, p
->escape
, p
->size
, p
->data
, 0, NULL
);
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
:
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
:
2969 case EMR_SETPOLYFILLMODE
:
2971 case EMR_SETSTRETCHBLTMODE
:
2972 case EMR_SETTEXTALIGN
:
2973 case EMR_OFFSETCLIPRGN
:
2975 case EMR_EXCLUDECLIPRECT
:
2976 case EMR_INTERSECTCLIPRECT
:
2977 case EMR_SCALEVIEWPORTEXTEX
:
2978 case EMR_SCALEWINDOWEXTEX
:
2979 case EMR_SETWORLDTRANSFORM
:
2980 case EMR_MODIFYWORLDTRANSFORM
:
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
:
2992 case EMR_SELECTCLIPPATH
:
2993 case EMR_EXTSELECTCLIPRGN
:
2994 case EMR_EXTCREATEFONTINDIRECTW
:
2996 return PlayEnhMetaFileRecord(data
->pdev
->dev
.hdc
, htable
, rec
, handle_count
);
2998 FIXME("unsupported record: %ld\n", rec
->iType
);
3004 static BOOL
print_metafile(struct pp_data
*data
, HANDLE hdata
)
3006 XFORM xform
= { .eM11
= 1, .eM22
= 1 };
3013 if (!ReadPrinter(hdata
, &header
, sizeof(header
), &r
))
3015 if (r
!= sizeof(header
))
3017 SetLastError(ERROR_INVALID_DATA
);
3021 buf
= malloc(header
.cjSize
);
3025 if (!ReadPrinter(hdata
, buf
, header
.cjSize
, &r
))
3030 if (r
!= header
.cjSize
)
3033 SetLastError(ERROR_INVALID_DATA
);
3037 hmf
= SetEnhMetaFileBits(header
.cjSize
, buf
);
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
;
3061 data
->break_extra
= 0;
3062 data
->break_rem
= 0;
3063 data
->saved_dc_top
= 0;
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
);
3077 SetLastError(ERROR_INVALID_PARAMETER
);
3082 *needed
= sizeof(*info
) + sizeof(emf_1003
);
3084 if (level
!= 1 || (size
&& !datatypes
))
3086 SetLastError(ERROR_INVALID_PARAMETER
);
3092 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3097 info
->pName
= (WCHAR
*)(info
+ 1);
3098 memcpy(info
+ 1, emf_1003
, sizeof(emf_1003
));
3102 HANDLE WINAPI
OpenPrintProcessor(WCHAR
*port
, PRINTPROCESSOROPENDATA
*open_data
)
3104 struct pp_data
*data
;
3108 TRACE("%s, %p\n", debugstr_w(port
), open_data
);
3110 if (!port
|| !open_data
|| !open_data
->pDatatype
)
3112 SetLastError(ERROR_INVALID_PARAMETER
);
3115 if (wcscmp(open_data
->pDatatype
, emf_1003
))
3117 SetLastError(ERROR_INVALID_DATATYPE
);
3121 if (!OpenPrinterW(port
, &hport
, NULL
))
3124 data
= LocalAlloc(LMEM_FIXED
| LMEM_ZEROINIT
, sizeof(*data
));
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
);
3138 SetGraphicsMode(hdc
, GM_ADVANCED
);
3139 data
->pdev
= create_psdrv_physdev(hdc
, open_data
->pPrinterName
,
3140 (const PSDRV_DEVMODE
*)open_data
->pDevMode
);
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
;
3165 TRACE("%p, %s\n", pp
, debugstr_w(doc_name
));
3170 if (!OpenPrinterW(doc_name
, &spool_data
, NULL
))
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
);
3183 if (!(ret
= ReadPrinter(spool_data
, &header
, sizeof(header
), &r
)))
3185 if (r
!= sizeof(header
))
3187 SetLastError(ERROR_INVALID_DATA
);
3192 if (header
.dwVersion
!= EMFSPOOL_VERSION
)
3194 FIXME("unrecognized spool file format\n");
3195 SetLastError(ERROR_INTERNAL_ERROR
);
3198 pos
.QuadPart
= header
.cjSize
;
3199 if (!(ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_BEGIN
, FALSE
)))
3202 data
->pdev
->job
.hprinter
= data
->hport
;
3203 if (!PSDRV_WriteHeader(&data
->pdev
->dev
, data
->doc_name
))
3205 WARN("Failed to write header\n");
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
);
3217 if (!(ret
= ReadPrinter(spool_data
, &record
, sizeof(record
), &r
)))
3221 if (r
!= sizeof(record
))
3223 SetLastError(ERROR_INVALID_DATA
);
3228 switch (record
.ulID
)
3230 case EMRI_METAFILE_DATA
:
3231 pos
.QuadPart
= record
.cjSize
;
3232 ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_CURRENT
, FALSE
);
3236 case EMRI_METAFILE_EXT
:
3237 case EMRI_BW_METAFILE_EXT
:
3239 ret
= SeekPrinter(spool_data
, pos
, &cur
, FILE_CURRENT
, FALSE
);
3242 cur
.QuadPart
+= record
.cjSize
;
3243 ret
= ReadPrinter(spool_data
, &pos
, sizeof(pos
), &r
);
3244 if (r
!= sizeof(pos
))
3246 SetLastError(ERROR_INVALID_DATA
);
3250 pos
.QuadPart
= -pos
.QuadPart
- 2 * sizeof(record
);
3252 ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_CURRENT
, FALSE
);
3254 ret
= print_metafile(data
, spool_data
);
3256 ret
= SeekPrinter(spool_data
, cur
, NULL
, FILE_BEGIN
, FALSE
);
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
);
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
);
3286 BOOL WINAPI
ClosePrintProcessor(HANDLE pp
)
3288 struct pp_data
*data
= get_handle_data(pp
);
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
));
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");