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
48 struct ps_brush_pattern
*patterns
;
74 EMRI_BW_FORM_METAFILE
,
80 EMRI_DESIGNVECTOR_EXT
,
89 unsigned int dwVersion
;
91 unsigned int dpszDocName
;
92 unsigned int dpszOutput
;
106 } EMRSETTEXTJUSTIFICATION
;
108 BOOL WINAPI
SeekPrinter(HANDLE
, LARGE_INTEGER
, LARGE_INTEGER
*, DWORD
, BOOL
);
110 static const WCHAR emf_1003
[] = L
"NT EMF 1.003";
112 #define EMRICASE(x) case x: return #x
113 static const char * debugstr_rec_type(int id
)
117 EMRICASE(EMRI_METAFILE
);
118 EMRICASE(EMRI_ENGINE_FONT
);
119 EMRICASE(EMRI_DEVMODE
);
120 EMRICASE(EMRI_TYPE1_FONT
);
121 EMRICASE(EMRI_PRESTARTPAGE
);
122 EMRICASE(EMRI_DESIGNVECTOR
);
123 EMRICASE(EMRI_SUBSET_FONT
);
124 EMRICASE(EMRI_DELTA_FONT
);
125 EMRICASE(EMRI_FORM_METAFILE
);
126 EMRICASE(EMRI_BW_METAFILE
);
127 EMRICASE(EMRI_BW_FORM_METAFILE
);
128 EMRICASE(EMRI_METAFILE_DATA
);
129 EMRICASE(EMRI_METAFILE_EXT
);
130 EMRICASE(EMRI_BW_METAFILE_EXT
);
131 EMRICASE(EMRI_ENGINE_FONT_EXT
);
132 EMRICASE(EMRI_TYPE1_FONT_EXT
);
133 EMRICASE(EMRI_DESIGNVECTOR_EXT
);
134 EMRICASE(EMRI_SUBSET_FONT_EXT
);
135 EMRICASE(EMRI_DELTA_FONT_EXT
);
136 EMRICASE(EMRI_PS_JOB_DATA
);
137 EMRICASE(EMRI_EMBED_FONT_EXT
);
139 FIXME("unknown record type: %d\n", id
);
145 static struct pp_data
* get_handle_data(HANDLE pp
)
147 struct pp_data
*ret
= (struct pp_data
*)pp
;
149 if (!ret
|| ret
->magic
!= PP_MAGIC
)
151 SetLastError(ERROR_INVALID_HANDLE
);
157 static inline INT
GDI_ROUND(double val
)
159 return (int)floor(val
+ 0.5);
162 static void translate(RECT
*rect
, const XFORM
*xform
)
168 rect
->left
= GDI_ROUND(x
* xform
->eM11
+ y
* xform
->eM21
+ xform
->eDx
);
169 rect
->top
= GDI_ROUND(x
* xform
->eM12
+ y
* xform
->eM22
+ xform
->eDy
);
173 rect
->right
= GDI_ROUND(x
* xform
->eM11
+ y
* xform
->eM21
+ xform
->eDx
);
174 rect
->bottom
= GDI_ROUND(x
* xform
->eM12
+ y
* xform
->eM22
+ xform
->eDy
);
177 static inline void get_bounding_rect(RECT
*rect
, int x
, int y
, int width
, int height
)
180 rect
->right
= x
+ width
;
182 rect
->bottom
= y
+ height
;
183 if (rect
->left
> rect
->right
)
185 int tmp
= rect
->left
;
186 rect
->left
= rect
->right
+ 1;
187 rect
->right
= tmp
+ 1;
189 if (rect
->top
> rect
->bottom
)
192 rect
->top
= rect
->bottom
+ 1;
193 rect
->bottom
= tmp
+ 1;
197 static inline void order_rect(RECT
*rect
)
199 if (rect
->left
> rect
->right
)
201 int tmp
= rect
->left
;
202 rect
->left
= rect
->right
;
205 if (rect
->top
> rect
->bottom
)
208 rect
->top
= rect
->bottom
;
213 static BOOL
intersect_vis_rectangles(struct ps_bitblt_coords
*dst
, struct ps_bitblt_coords
*src
)
217 /* intersect the rectangles */
219 if ((src
->width
== dst
->width
) && (src
->height
== dst
->height
)) /* no stretching */
221 OffsetRect(&src
->visrect
, dst
->x
- src
->x
, dst
->y
- src
->y
);
222 if (!IntersectRect(&rect
, &src
->visrect
, &dst
->visrect
)) return FALSE
;
223 src
->visrect
= dst
->visrect
= rect
;
224 OffsetRect(&src
->visrect
, src
->x
- dst
->x
, src
->y
- dst
->y
);
226 else /* stretching */
228 /* map source rectangle into destination coordinates */
231 -src
->x
- (src
->width
< 0 ? 1 : 0),
232 -src
->y
- (src
->height
< 0 ? 1 : 0));
233 rect
.left
= rect
.left
* dst
->width
/ src
->width
;
234 rect
.top
= rect
.top
* dst
->height
/ src
->height
;
235 rect
.right
= rect
.right
* dst
->width
/ src
->width
;
236 rect
.bottom
= rect
.bottom
* dst
->height
/ src
->height
;
239 /* when the source rectangle needs to flip and it doesn't fit in the source device
240 area, the destination area isn't flipped. So, adjust destination coordinates */
241 if (src
->width
< 0 && dst
->width
> 0 &&
242 (src
->x
+ src
->width
+ 1 < src
->visrect
.left
|| src
->x
> src
->visrect
.right
))
243 dst
->x
+= (dst
->width
- rect
.right
) - rect
.left
;
244 else if (src
->width
> 0 && dst
->width
< 0 &&
245 (src
->x
< src
->visrect
.left
|| src
->x
+ src
->width
> src
->visrect
.right
))
246 dst
->x
-= rect
.right
- (dst
->width
- rect
.left
);
248 if (src
->height
< 0 && dst
->height
> 0 &&
249 (src
->y
+ src
->height
+ 1 < src
->visrect
.top
|| src
->y
> src
->visrect
.bottom
))
250 dst
->y
+= (dst
->height
- rect
.bottom
) - rect
.top
;
251 else if (src
->height
> 0 && dst
->height
< 0 &&
252 (src
->y
< src
->visrect
.top
|| src
->y
+ src
->height
> src
->visrect
.bottom
))
253 dst
->y
-= rect
.bottom
- (dst
->height
- rect
.top
);
255 OffsetRect(&rect
, dst
->x
, dst
->y
);
257 /* avoid rounding errors */
262 if (!IntersectRect(&dst
->visrect
, &rect
, &dst
->visrect
)) return FALSE
;
264 /* map destination rectangle back to source coordinates */
267 -dst
->x
- (dst
->width
< 0 ? 1 : 0),
268 -dst
->y
- (dst
->height
< 0 ? 1 : 0));
269 rect
.left
= src
->x
+ rect
.left
* src
->width
/ dst
->width
;
270 rect
.top
= src
->y
+ rect
.top
* src
->height
/ dst
->height
;
271 rect
.right
= src
->x
+ rect
.right
* src
->width
/ dst
->width
;
272 rect
.bottom
= src
->y
+ rect
.bottom
* src
->height
/ dst
->height
;
275 /* avoid rounding errors */
280 if (!IntersectRect(&src
->visrect
, &rect
, &src
->visrect
)) return FALSE
;
285 static void clip_visrect(HDC hdc
, RECT
*dst
, const RECT
*src
)
289 hrgn
= CreateRectRgn(0, 0, 0, 0);
290 if (GetRandomRgn(hdc
, hrgn
, 3) == 1)
292 GetRgnBox(hrgn
, dst
);
293 IntersectRect(dst
, dst
, src
);
302 static void get_vis_rectangles(HDC hdc
, struct ps_bitblt_coords
*dst
,
303 const XFORM
*xform
, DWORD width
, DWORD height
, struct ps_bitblt_coords
*src
)
307 rect
.left
= dst
->log_x
;
308 rect
.top
= dst
->log_y
;
309 rect
.right
= dst
->log_x
+ dst
->log_width
;
310 rect
.bottom
= dst
->log_y
+ dst
->log_height
;
311 LPtoDP(hdc
, (POINT
*)&rect
, 2);
314 dst
->width
= rect
.right
- rect
.left
;
315 dst
->height
= rect
.bottom
- rect
.top
;
316 if (dst
->layout
& LAYOUT_RTL
&& dst
->layout
& LAYOUT_BITMAPORIENTATIONPRESERVED
)
318 dst
->x
+= dst
->width
;
319 dst
->width
= -dst
->width
;
321 get_bounding_rect(&rect
, dst
->x
, dst
->y
, dst
->width
, dst
->height
);
322 clip_visrect(hdc
, &dst
->visrect
, &rect
);
326 rect
.left
= src
->log_x
;
327 rect
.top
= src
->log_y
;
328 rect
.right
= src
->log_x
+ src
->log_width
;
329 rect
.bottom
= src
->log_y
+ src
->log_height
;
330 translate(&rect
, xform
);
333 src
->width
= rect
.right
- rect
.left
;
334 src
->height
= rect
.bottom
- rect
.top
;
335 get_bounding_rect(&rect
, src
->x
, src
->y
, src
->width
, src
->height
);
336 if (rect
.left
< 0) rect
.left
= 0;
337 if (rect
.top
< 0) rect
.top
= 0;
338 if (rect
.right
> width
) rect
.right
= width
;
339 if (rect
.bottom
> height
) rect
.bottom
= height
;
342 intersect_vis_rectangles(dst
, src
);
345 static int stretch_blt(print_ctx
*ctx
, const EMRSTRETCHBLT
*blt
,
346 const BITMAPINFO
*bi
, const BYTE
*src_bits
)
348 char dst_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
349 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
350 struct ps_bitblt_coords src
, dst
;
351 struct ps_image_bits bits
;
354 dst
.log_x
= blt
->xDest
;
355 dst
.log_y
= blt
->yDest
;
356 dst
.log_width
= blt
->cxDest
;
357 dst
.log_height
= blt
->cyDest
;
358 dst
.layout
= GetLayout(ctx
->hdc
);
359 if (blt
->dwRop
& NOMIRRORBITMAP
)
360 dst
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
364 get_vis_rectangles(ctx
->hdc
, &dst
, NULL
, 0, 0, NULL
);
365 return PSDRV_PatBlt(ctx
, &dst
, blt
->dwRop
);
368 src
.log_x
= blt
->xSrc
;
369 src
.log_y
= blt
->ySrc
;
370 src
.log_width
= blt
->cxSrc
;
371 src
.log_height
= blt
->cySrc
;
374 get_vis_rectangles(ctx
->hdc
, &dst
, &blt
->xformSrc
,
375 bi
->bmiHeader
.biWidth
, abs(bi
->bmiHeader
.biHeight
), &src
);
377 memcpy(dst_info
, bi
, blt
->cbBmiSrc
);
378 memset(&bits
, 0, sizeof(bits
));
379 bits
.ptr
= (BYTE
*)src_bits
;
380 err
= PSDRV_PutImage(ctx
, 0, dst_info
, &bits
, &src
, &dst
, blt
->dwRop
);
381 if (err
== ERROR_BAD_FORMAT
)
383 HDC hdc
= CreateCompatibleDC(NULL
);
387 bitmap
= CreateDIBSection(hdc
, dst_info
, DIB_RGB_COLORS
, &bits
.ptr
, NULL
, 0);
388 SetDIBits(hdc
, bitmap
, 0, bi
->bmiHeader
.biHeight
, src_bits
, bi
, blt
->iUsageSrc
);
390 err
= PSDRV_PutImage(ctx
, 0, dst_info
, &bits
, &src
, &dst
, blt
->dwRop
);
391 DeleteObject(bitmap
);
395 if (err
!= ERROR_SUCCESS
)
396 FIXME("PutImage returned %ld\n", err
);
400 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
401 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
403 static int mask_blt(print_ctx
*ctx
, const EMRMASKBLT
*p
, const BITMAPINFO
*src_bi
,
404 const BYTE
*src_bits
, const BITMAPINFO
*mask_bi
, const BYTE
*mask_bits
)
406 HBITMAP bmp1
, old_bmp1
, bmp2
, old_bmp2
, bmp_src
, old_bmp_src
;
407 char bmp2_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
408 BITMAPINFO
*bmp2_info
= (BITMAPINFO
*)bmp2_buffer
;
409 HBRUSH brush_mask
, brush_dest
, old_brush
;
410 HDC hdc_src
, hdc1
, hdc2
;
414 static const DWORD ROP3Table
[256] =
416 0x00000042, 0x00010289,
417 0x00020C89, 0x000300AA,
418 0x00040C88, 0x000500A9,
419 0x00060865, 0x000702C5,
420 0x00080F08, 0x00090245,
421 0x000A0329, 0x000B0B2A,
422 0x000C0324, 0x000D0B25,
423 0x000E08A5, 0x000F0001,
424 0x00100C85, 0x001100A6,
425 0x00120868, 0x001302C8,
426 0x00140869, 0x001502C9,
427 0x00165CCA, 0x00171D54,
428 0x00180D59, 0x00191CC8,
429 0x001A06C5, 0x001B0768,
430 0x001C06CA, 0x001D0766,
431 0x001E01A5, 0x001F0385,
432 0x00200F09, 0x00210248,
433 0x00220326, 0x00230B24,
434 0x00240D55, 0x00251CC5,
435 0x002606C8, 0x00271868,
436 0x00280369, 0x002916CA,
437 0x002A0CC9, 0x002B1D58,
438 0x002C0784, 0x002D060A,
439 0x002E064A, 0x002F0E2A,
440 0x0030032A, 0x00310B28,
441 0x00320688, 0x00330008,
442 0x003406C4, 0x00351864,
443 0x003601A8, 0x00370388,
444 0x0038078A, 0x00390604,
445 0x003A0644, 0x003B0E24,
446 0x003C004A, 0x003D18A4,
447 0x003E1B24, 0x003F00EA,
448 0x00400F0A, 0x00410249,
449 0x00420D5D, 0x00431CC4,
450 0x00440328, 0x00450B29,
451 0x004606C6, 0x0047076A,
452 0x00480368, 0x004916C5,
453 0x004A0789, 0x004B0605,
454 0x004C0CC8, 0x004D1954,
455 0x004E0645, 0x004F0E25,
456 0x00500325, 0x00510B26,
457 0x005206C9, 0x00530764,
458 0x005408A9, 0x00550009,
459 0x005601A9, 0x00570389,
460 0x00580785, 0x00590609,
461 0x005A0049, 0x005B18A9,
462 0x005C0649, 0x005D0E29,
463 0x005E1B29, 0x005F00E9,
464 0x00600365, 0x006116C6,
465 0x00620786, 0x00630608,
466 0x00640788, 0x00650606,
467 0x00660046, 0x006718A8,
468 0x006858A6, 0x00690145,
469 0x006A01E9, 0x006B178A,
470 0x006C01E8, 0x006D1785,
471 0x006E1E28, 0x006F0C65,
472 0x00700CC5, 0x00711D5C,
473 0x00720648, 0x00730E28,
474 0x00740646, 0x00750E26,
475 0x00761B28, 0x007700E6,
476 0x007801E5, 0x00791786,
477 0x007A1E29, 0x007B0C68,
478 0x007C1E24, 0x007D0C69,
479 0x007E0955, 0x007F03C9,
480 0x008003E9, 0x00810975,
481 0x00820C49, 0x00831E04,
482 0x00840C48, 0x00851E05,
483 0x008617A6, 0x008701C5,
484 0x008800C6, 0x00891B08,
485 0x008A0E06, 0x008B0666,
486 0x008C0E08, 0x008D0668,
487 0x008E1D7C, 0x008F0CE5,
488 0x00900C45, 0x00911E08,
489 0x009217A9, 0x009301C4,
490 0x009417AA, 0x009501C9,
491 0x00960169, 0x0097588A,
492 0x00981888, 0x00990066,
493 0x009A0709, 0x009B07A8,
494 0x009C0704, 0x009D07A6,
495 0x009E16E6, 0x009F0345,
496 0x00A000C9, 0x00A11B05,
497 0x00A20E09, 0x00A30669,
498 0x00A41885, 0x00A50065,
499 0x00A60706, 0x00A707A5,
500 0x00A803A9, 0x00A90189,
501 0x00AA0029, 0x00AB0889,
502 0x00AC0744, 0x00AD06E9,
503 0x00AE0B06, 0x00AF0229,
504 0x00B00E05, 0x00B10665,
505 0x00B21974, 0x00B30CE8,
506 0x00B4070A, 0x00B507A9,
507 0x00B616E9, 0x00B70348,
508 0x00B8074A, 0x00B906E6,
509 0x00BA0B09, 0x00BB0226,
510 0x00BC1CE4, 0x00BD0D7D,
511 0x00BE0269, 0x00BF08C9,
512 0x00C000CA, 0x00C11B04,
513 0x00C21884, 0x00C3006A,
514 0x00C40E04, 0x00C50664,
515 0x00C60708, 0x00C707AA,
516 0x00C803A8, 0x00C90184,
517 0x00CA0749, 0x00CB06E4,
518 0x00CC0020, 0x00CD0888,
519 0x00CE0B08, 0x00CF0224,
520 0x00D00E0A, 0x00D1066A,
521 0x00D20705, 0x00D307A4,
522 0x00D41D78, 0x00D50CE9,
523 0x00D616EA, 0x00D70349,
524 0x00D80745, 0x00D906E8,
525 0x00DA1CE9, 0x00DB0D75,
526 0x00DC0B04, 0x00DD0228,
527 0x00DE0268, 0x00DF08C8,
528 0x00E003A5, 0x00E10185,
529 0x00E20746, 0x00E306EA,
530 0x00E40748, 0x00E506E5,
531 0x00E61CE8, 0x00E70D79,
532 0x00E81D74, 0x00E95CE6,
533 0x00EA02E9, 0x00EB0849,
534 0x00EC02E8, 0x00ED0848,
535 0x00EE0086, 0x00EF0A08,
536 0x00F00021, 0x00F10885,
537 0x00F20B05, 0x00F3022A,
538 0x00F40B0A, 0x00F50225,
539 0x00F60265, 0x00F708C5,
540 0x00F802E5, 0x00F90845,
541 0x00FA0089, 0x00FB0A09,
542 0x00FC008A, 0x00FD0A0A,
543 0x00FE02A9, 0x00FF0062,
548 blt
.rclBounds
= p
->rclBounds
;
549 blt
.xDest
= p
->xDest
;
550 blt
.yDest
= p
->yDest
;
551 blt
.cxDest
= p
->cxDest
;
552 blt
.cyDest
= p
->cyDest
;
553 blt
.dwRop
= FRGND_ROP3(p
->dwRop
);
556 blt
.xformSrc
= p
->xformSrc
;
557 blt
.crBkColorSrc
= p
->crBkColorSrc
;
558 blt
.iUsageSrc
= p
->iUsageSrc
;
560 blt
.cbBmiSrc
= p
->cbBmiSrc
;
562 blt
.cbBitsSrc
= p
->cbBitsSrc
;
563 blt
.cxSrc
= p
->cxDest
;
564 blt
.cySrc
= p
->cyDest
;
566 return stretch_blt(ctx
, &blt
, src_bi
, src_bits
);
569 hdc_src
= CreateCompatibleDC(NULL
);
570 SetGraphicsMode(hdc_src
, GM_ADVANCED
);
571 SetWorldTransform(hdc_src
, &p
->xformSrc
);
572 brush_dest
= CreateSolidBrush(p
->crBkColorSrc
);
573 old_brush
= SelectObject(hdc_src
, brush_dest
);
574 PatBlt(hdc_src
, p
->rclBounds
.left
, p
->rclBounds
.top
,
575 p
->rclBounds
.right
- p
->rclBounds
.left
,
576 p
->rclBounds
.bottom
- p
->rclBounds
.top
, PATCOPY
);
577 SelectObject(hdc_src
, old_brush
);
578 DeleteObject(brush_dest
);
580 bmp_src
= CreateDIBSection(hdc_src
, src_bi
, p
->iUsageSrc
, (void **)&bits
, NULL
, 0);
581 memcpy(bits
, src_bits
, p
->cbBitsSrc
);
582 old_bmp_src
= SelectObject(hdc_src
, bmp_src
);
584 bmp1
= CreateBitmap(mask_bi
->bmiHeader
.biWidth
, mask_bi
->bmiHeader
.biHeight
, 1, 1, NULL
);
585 SetDIBits(ctx
->hdc
, bmp1
, 0, mask_bi
->bmiHeader
.biHeight
, mask_bits
, mask_bi
, p
->iUsageMask
);
586 brush_mask
= CreatePatternBrush(bmp1
);
588 brush_dest
= SelectObject(ctx
->hdc
, GetStockObject(NULL_BRUSH
));
591 hdc1
= CreateCompatibleDC(NULL
);
592 bmp1
= CreateBitmap(p
->cxDest
, p
->cyDest
, 1, 32, NULL
);
593 old_bmp1
= SelectObject(hdc1
, bmp1
);
595 /* draw using bkgnd rop */
596 old_brush
= SelectObject(hdc1
, brush_dest
);
597 BitBlt(hdc1
, 0, 0, p
->cxDest
, p
->cyDest
, hdc_src
, p
->xSrc
, p
->ySrc
, BKGND_ROP3(p
->dwRop
));
598 SelectObject(hdc1
, old_brush
);
601 hdc2
= CreateCompatibleDC(NULL
);
602 bmp2_info
->bmiHeader
.biSize
= sizeof(bmp2_info
->bmiHeader
);
603 bmp2_info
->bmiHeader
.biWidth
= p
->cxDest
;
604 bmp2_info
->bmiHeader
.biHeight
= p
->cyDest
;
605 bmp2_info
->bmiHeader
.biPlanes
= 1;
606 bmp2_info
->bmiHeader
.biBitCount
= 32;
607 bmp2_info
->bmiHeader
.biCompression
= BI_RGB
;
608 bmp2_info
->bmiHeader
.biSizeImage
= p
->cxDest
* p
->cyDest
* bmp2_info
->bmiHeader
.biBitCount
/ 8;
609 bmp2
= CreateDIBSection(hdc2
, bmp2_info
, DIB_RGB_COLORS
, (void **)&bits
, NULL
, 0);
610 old_bmp2
= SelectObject(hdc2
, bmp2
);
612 /* draw using foregnd rop */
613 old_brush
= SelectObject(hdc2
, brush_dest
);
614 BitBlt(hdc2
, 0, 0, p
->cxDest
, p
->cyDest
, hdc_src
, p
->xSrc
, p
->ySrc
, FRGND_ROP3(p
->dwRop
));
616 /* combine both using the mask as a pattern brush */
617 SelectObject(hdc2
, brush_mask
);
618 SetBrushOrgEx(hdc2
, -p
->xMask
, -p
->yMask
, NULL
);
619 /* (D & P) | (S & ~P) */
620 BitBlt(hdc2
, 0, 0, p
->cxDest
, p
->cyDest
, hdc1
, 0, 0, 0xac0744);
621 SelectObject(hdc2
, old_brush
);
624 blt
.rclBounds
= p
->rclBounds
;
625 blt
.xDest
= p
->xDest
;
626 blt
.yDest
= p
->yDest
;
627 blt
.cxDest
= p
->cxDest
;
628 blt
.cyDest
= p
->cyDest
;
632 GetTransform(hdc2
, 0x204, &blt
.xformSrc
);
633 blt
.crBkColorSrc
= p
->crBkColorSrc
;
634 blt
.iUsageSrc
= DIB_RGB_COLORS
;
636 blt
.cbBmiSrc
= bmp2_info
->bmiHeader
.biSize
;
638 blt
.cbBitsSrc
= bmp2_info
->bmiHeader
.biSizeImage
;
639 blt
.cxSrc
= p
->cxDest
;
640 blt
.cySrc
= p
->cyDest
;
642 stretch_blt(ctx
, &blt
, bmp2_info
, bits
);
644 /* restore all objects */
645 SelectObject(ctx
->hdc
, brush_dest
);
646 SelectObject(hdc1
, old_bmp1
);
647 SelectObject(hdc2
, old_bmp2
);
648 SelectObject(hdc_src
, old_bmp_src
);
650 /* delete all temp objects */
653 DeleteObject(bmp_src
);
654 DeleteObject(brush_mask
);
658 DeleteObject(hdc_src
);
663 static void combine_transform(XFORM
*result
, const XFORM
*xform1
, const XFORM
*xform2
)
667 /* Create the result in a temporary XFORM, since result may be
668 * equal to xform1 or xform2 */
669 r
.eM11
= xform1
->eM11
* xform2
->eM11
+ xform1
->eM12
* xform2
->eM21
;
670 r
.eM12
= xform1
->eM11
* xform2
->eM12
+ xform1
->eM12
* xform2
->eM22
;
671 r
.eM21
= xform1
->eM21
* xform2
->eM11
+ xform1
->eM22
* xform2
->eM21
;
672 r
.eM22
= xform1
->eM21
* xform2
->eM12
+ xform1
->eM22
* xform2
->eM22
;
673 r
.eDx
= xform1
->eDx
* xform2
->eM11
+ xform1
->eDy
* xform2
->eM21
+ xform2
->eDx
;
674 r
.eDy
= xform1
->eDx
* xform2
->eM12
+ xform1
->eDy
* xform2
->eM22
+ xform2
->eDy
;
679 static int plg_blt(print_ctx
*ctx
, const EMRPLGBLT
*p
)
681 const BITMAPINFO
*src_bi
, *mask_bi
;
682 const BYTE
*src_bits
, *mask_bits
;
683 XFORM xf
, xform_dest
;
687 /* parallelogram coords */
691 memcpy(plg
, p
->aptlDest
, sizeof(plg
));
694 rect
[1].x
= p
->xSrc
+ p
->cxSrc
;
697 rect
[2].y
= p
->ySrc
+ p
->cySrc
;
698 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
700 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
);
702 if (fabs(det
) < 1e-5)
705 TRACE("%ld,%ld,%ldx%ld -> %ld,%ld,%ld,%ld,%ld,%ld\n", p
->xSrc
, p
->ySrc
, p
->cxSrc
, p
->cySrc
,
706 plg
[0].x
, plg
[0].y
, plg
[1].x
, plg
[1].y
, plg
[2].x
, plg
[2].y
);
709 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
;
710 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
;
711 xf
.eDx
= (rect
[0].x
*(rect
[1].y
*plg
[2].x
- rect
[2].y
*plg
[1].x
) -
712 rect
[1].x
*(rect
[0].y
*plg
[2].x
- rect
[2].y
*plg
[0].x
) +
713 rect
[2].x
*(rect
[0].y
*plg
[1].x
- rect
[1].y
*plg
[0].x
)
717 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
;
718 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
;
719 xf
.eDy
= (rect
[0].x
*(rect
[1].y
*plg
[2].y
- rect
[2].y
*plg
[1].y
) -
720 rect
[1].x
*(rect
[0].y
*plg
[2].y
- rect
[2].y
*plg
[0].y
) +
721 rect
[2].x
*(rect
[0].y
*plg
[1].y
- rect
[1].y
*plg
[0].y
)
724 combine_transform(&xf
, &xf
, &p
->xformSrc
);
726 GetTransform(ctx
->hdc
, 0x203, &xform_dest
);
727 SetWorldTransform(ctx
->hdc
, &xf
);
728 /* now destination and source DCs use same coords */
729 maskblt
.rclBounds
= p
->rclBounds
;
730 maskblt
.xDest
= p
->xSrc
;
731 maskblt
.yDest
= p
->ySrc
;
732 maskblt
.cxDest
= p
->cxSrc
;
733 maskblt
.cyDest
= p
->cySrc
;
734 maskblt
.dwRop
= SRCCOPY
;
735 maskblt
.xSrc
= p
->xSrc
;
736 maskblt
.ySrc
= p
->ySrc
;
737 maskblt
.xformSrc
= p
->xformSrc
;
738 maskblt
.crBkColorSrc
= p
->crBkColorSrc
;
739 maskblt
.iUsageSrc
= p
->iUsageSrc
;
740 maskblt
.offBmiSrc
= 0;
741 maskblt
.cbBmiSrc
= p
->cbBmiSrc
;
742 maskblt
.offBitsSrc
= 0;
743 maskblt
.cbBitsSrc
= p
->cbBitsSrc
;
744 maskblt
.xMask
= p
->xMask
;
745 maskblt
.yMask
= p
->yMask
;
746 maskblt
.iUsageMask
= p
->iUsageMask
;
747 maskblt
.offBmiMask
= 0;
748 maskblt
.cbBmiMask
= p
->cbBmiMask
;
749 maskblt
.offBitsMask
= 0;
750 maskblt
.cbBitsMask
= p
->cbBitsMask
;
751 src_bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
752 src_bits
= (BYTE
*)p
+ p
->offBitsSrc
;
753 mask_bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiMask
);
754 mask_bits
= (BYTE
*)p
+ p
->offBitsMask
;
755 mask_blt(ctx
, &maskblt
, src_bi
, src_bits
, mask_bi
, mask_bits
);
756 SetWorldTransform(ctx
->hdc
, &xform_dest
);
760 static inline int get_dib_stride( int width
, int bpp
)
762 return ((width
* bpp
+ 31) >> 3) & ~3;
765 static inline int get_dib_image_size( const BITMAPINFO
*info
)
767 return get_dib_stride( info
->bmiHeader
.biWidth
, info
->bmiHeader
.biBitCount
)
768 * abs( info
->bmiHeader
.biHeight
);
771 static int set_di_bits_to_device(print_ctx
*ctx
, const EMRSETDIBITSTODEVICE
*p
)
773 const BITMAPINFO
*info
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
774 char bi_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
775 BITMAPINFO
*bi
= (BITMAPINFO
*)bi_buffer
;
776 HBITMAP bitmap
, old_bitmap
;
777 int width
, height
, ret
;
780 width
= min(p
->cxSrc
, info
->bmiHeader
.biWidth
);
781 height
= min(p
->cySrc
, abs(info
->bmiHeader
.biHeight
));
783 memset(bi_buffer
, 0, sizeof(bi_buffer
));
784 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
785 bi
->bmiHeader
.biWidth
= width
;
786 bi
->bmiHeader
.biHeight
= height
;
787 bi
->bmiHeader
.biPlanes
= 1;
788 if (p
->iUsageSrc
== DIB_PAL_COLORS
&& (info
->bmiHeader
.biBitCount
== 1 ||
789 info
->bmiHeader
.biBitCount
== 4 || info
->bmiHeader
.biBitCount
== 8))
791 PALETTEENTRY pal
[256];
795 bi
->bmiHeader
.biBitCount
= info
->bmiHeader
.biBitCount
;
796 bi
->bmiHeader
.biClrUsed
= 1 << info
->bmiHeader
.biBitCount
;
797 bi
->bmiHeader
.biClrImportant
= bi
->bmiHeader
.biClrUsed
;
799 hpal
= GetCurrentObject(ctx
->hdc
, OBJ_PAL
);
800 size
= GetPaletteEntries(hpal
, 0, bi
->bmiHeader
.biClrUsed
, pal
);
801 for (i
= 0; i
< size
; i
++)
803 bi
->bmiColors
[i
].rgbBlue
= pal
[i
].peBlue
;
804 bi
->bmiColors
[i
].rgbGreen
= pal
[i
].peGreen
;
805 bi
->bmiColors
[i
].rgbRed
= pal
[i
].peRed
;
810 bi
->bmiHeader
.biBitCount
= 24;
812 bi
->bmiHeader
.biCompression
= BI_RGB
;
813 bitmap
= CreateDIBSection(ctx
->hdc
, bi
, DIB_RGB_COLORS
, (void **)&bits
, NULL
, 0);
816 old_bitmap
= SelectObject(ctx
->hdc
, bitmap
);
818 ret
= SetDIBitsToDevice(ctx
->hdc
, 0, 0, width
, height
, p
->xSrc
, p
->ySrc
,
819 p
->iStartScan
, p
->cScans
, (const BYTE
*)p
+ p
->offBitsSrc
, info
, p
->iUsageSrc
);
820 SelectObject(ctx
->hdc
, old_bitmap
);
825 memset(&blt
, 0, sizeof(blt
));
826 blt
.rclBounds
= p
->rclBounds
;
827 blt
.xDest
= p
->xDest
;
828 blt
.yDest
= p
->yDest
+ p
->cySrc
- height
;
832 blt
.xformSrc
.eM11
= 1;
833 blt
.xformSrc
.eM22
= 1;
834 blt
.iUsageSrc
= DIB_RGB_COLORS
;
835 blt
.cbBmiSrc
= sizeof(bi_buffer
);
836 blt
.cbBitsSrc
= get_dib_image_size(bi
);
837 blt
.cxSrc
= blt
.cxDest
;
838 blt
.cySrc
= blt
.cyDest
;
839 stretch_blt(ctx
, &blt
, bi
, bits
);
842 DeleteObject(bitmap
);
846 static int stretch_di_bits(print_ctx
*ctx
, const EMRSTRETCHDIBITS
*p
)
848 char bi_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
849 const BYTE
*bits
= (BYTE
*)p
+ p
->offBitsSrc
;
850 BITMAPINFO
*bi
= (BITMAPINFO
*)bi_buffer
;
853 memcpy(bi
, (BYTE
*)p
+ p
->offBmiSrc
, p
->cbBmiSrc
);
854 memset(bi_buffer
+ p
->cbBmiSrc
, 0, sizeof(bi_buffer
) - p
->cbBmiSrc
);
856 if (p
->iUsageSrc
== DIB_PAL_COLORS
&& (bi
->bmiHeader
.biBitCount
== 1 ||
857 bi
->bmiHeader
.biBitCount
== 4 || bi
->bmiHeader
.biBitCount
== 8))
859 PALETTEENTRY pal
[256];
863 hpal
= GetCurrentObject(ctx
->hdc
, OBJ_PAL
);
864 size
= GetPaletteEntries(hpal
, 0, 1 << bi
->bmiHeader
.biBitCount
, pal
);
865 for (i
= 0; i
< size
; i
++)
867 bi
->bmiColors
[i
].rgbBlue
= pal
[i
].peBlue
;
868 bi
->bmiColors
[i
].rgbGreen
= pal
[i
].peGreen
;
869 bi
->bmiColors
[i
].rgbRed
= pal
[i
].peRed
;
873 memset(&blt
, 0, sizeof(blt
));
874 blt
.rclBounds
= p
->rclBounds
;
875 blt
.xDest
= p
->xDest
;
876 blt
.yDest
= p
->yDest
;
877 blt
.cxDest
= p
->cxDest
;
878 blt
.cyDest
= p
->cyDest
;
879 blt
.dwRop
= p
->dwRop
;
881 blt
.ySrc
= abs(bi
->bmiHeader
.biHeight
) - p
->ySrc
- p
->cySrc
;
882 blt
.xformSrc
.eM11
= 1;
883 blt
.xformSrc
.eM22
= 1;
884 blt
.iUsageSrc
= p
->iUsageSrc
;
885 blt
.cbBmiSrc
= sizeof(bi_buffer
);
886 blt
.cbBitsSrc
= p
->cbBitsSrc
;
887 blt
.cxSrc
= p
->cxSrc
;
888 blt
.cySrc
= p
->cySrc
;
889 return stretch_blt(ctx
, &blt
, bi
, bits
);
892 static int poly_draw(print_ctx
*ctx
, const POINT
*points
, const BYTE
*types
, DWORD count
)
894 POINT first
, cur
, pts
[4];
897 /* check for valid point types */
898 for (i
= 0; i
< count
; i
++)
903 case PT_LINETO
| PT_CLOSEFIGURE
:
907 if (i
+ 2 >= count
) return FALSE
;
908 if (types
[i
+ 1] != PT_BEZIERTO
) return FALSE
;
909 if ((types
[i
+ 2] & ~PT_CLOSEFIGURE
) != PT_BEZIERTO
) return FALSE
;
917 GetCurrentPositionEx(ctx
->hdc
, &cur
);
920 for (i
= 0; i
< count
; i
++)
928 case (PT_LINETO
| PT_CLOSEFIGURE
):
932 if (!PSDRV_PolyPolyline(ctx
, pts
, &num_pts
, 1))
938 pts
[2] = points
[i
+ 1];
939 pts
[3] = points
[i
+ 2];
940 if (!PSDRV_PolyBezier(ctx
, pts
, 4))
947 if (types
[i
] & PT_CLOSEFIGURE
)
952 if (!PSDRV_PolyPolyline(ctx
, pts
, &num_pts
, 1))
960 static inline void reset_bounds(RECT
*bounds
)
962 bounds
->left
= bounds
->top
= INT_MAX
;
963 bounds
->right
= bounds
->bottom
= INT_MIN
;
966 static BOOL
gradient_fill(print_ctx
*ctx
, const TRIVERTEX
*vert_array
, DWORD nvert
,
967 const void *grad_array
, DWORD ngrad
, ULONG mode
)
969 char buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
970 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
971 struct ps_bitblt_coords src
, dst
;
972 struct ps_image_bits bits
;
973 HBITMAP bmp
, old_bmp
;
980 if (!(pts
= malloc(nvert
* sizeof(*pts
)))) return FALSE
;
981 memcpy(pts
, vert_array
, sizeof(*pts
) * nvert
);
982 for (i
= 0; i
< nvert
; i
++)
983 LPtoDP(ctx
->hdc
, (POINT
*)&pts
[i
], 1);
985 /* compute bounding rect of all the rectangles/triangles */
986 reset_bounds(&dst
.visrect
);
987 for (i
= 0; i
< ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2); i
++)
989 ULONG v
= ((ULONG
*)grad_array
)[i
];
990 dst
.visrect
.left
= min(dst
.visrect
.left
, pts
[v
].x
);
991 dst
.visrect
.top
= min(dst
.visrect
.top
, pts
[v
].y
);
992 dst
.visrect
.right
= max(dst
.visrect
.right
, pts
[v
].x
);
993 dst
.visrect
.bottom
= max(dst
.visrect
.bottom
, pts
[v
].y
);
996 dst
.x
= dst
.visrect
.left
;
997 dst
.y
= dst
.visrect
.top
;
998 dst
.width
= dst
.visrect
.right
- dst
.visrect
.left
;
999 dst
.height
= dst
.visrect
.bottom
- dst
.visrect
.top
;
1000 clip_visrect(ctx
->hdc
, &dst
.visrect
, &dst
.visrect
);
1002 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
1003 info
->bmiHeader
.biPlanes
= 1;
1004 info
->bmiHeader
.biBitCount
= 24;
1005 info
->bmiHeader
.biCompression
= BI_RGB
;
1006 info
->bmiHeader
.biXPelsPerMeter
= 0;
1007 info
->bmiHeader
.biYPelsPerMeter
= 0;
1008 info
->bmiHeader
.biClrUsed
= 0;
1009 info
->bmiHeader
.biClrImportant
= 0;
1010 info
->bmiHeader
.biWidth
= dst
.visrect
.right
- dst
.visrect
.left
;
1011 info
->bmiHeader
.biHeight
= dst
.visrect
.bottom
- dst
.visrect
.top
;
1012 info
->bmiHeader
.biSizeImage
= 0;
1013 memset(&bits
, 0, sizeof(bits
));
1014 hdc_src
= CreateCompatibleDC(NULL
);
1020 bmp
= CreateDIBSection(hdc_src
, info
, DIB_RGB_COLORS
, &bits
.ptr
, NULL
, 0);
1023 DeleteObject(hdc_src
);
1027 old_bmp
= SelectObject(hdc_src
, bmp
);
1029 /* make src and points relative to the bitmap */
1031 src
.x
-= dst
.visrect
.left
;
1032 src
.y
-= dst
.visrect
.top
;
1033 OffsetRect(&src
.visrect
, -dst
.visrect
.left
, -dst
.visrect
.top
);
1034 for (i
= 0; i
< nvert
; i
++)
1036 pts
[i
].x
-= dst
.visrect
.left
;
1037 pts
[i
].y
-= dst
.visrect
.top
;
1039 ret
= GdiGradientFill(hdc_src
, pts
, nvert
, (void *)grad_array
, ngrad
, mode
);
1040 SelectObject(hdc_src
, old_bmp
);
1041 DeleteObject(hdc_src
);
1043 rgn
= CreateRectRgn(0, 0, 0, 0);
1044 if (mode
== GRADIENT_FILL_TRIANGLE
)
1046 const GRADIENT_TRIANGLE
*gt
= grad_array
;
1050 for (i
= 0; i
< ngrad
; i
++)
1052 triangle
[0].x
= pts
[gt
[i
].Vertex1
].x
;
1053 triangle
[0].y
= pts
[gt
[i
].Vertex1
].y
;
1054 triangle
[1].x
= pts
[gt
[i
].Vertex2
].x
;
1055 triangle
[1].y
= pts
[gt
[i
].Vertex2
].y
;
1056 triangle
[2].x
= pts
[gt
[i
].Vertex3
].x
;
1057 triangle
[2].y
= pts
[gt
[i
].Vertex3
].y
;
1058 tmp
= CreatePolygonRgn(triangle
, 3, ALTERNATE
);
1059 CombineRgn(rgn
, rgn
, tmp
, RGN_OR
);
1065 const GRADIENT_RECT
*gr
= grad_array
;
1066 HRGN tmp
= CreateRectRgn(0, 0, 0, 0);
1068 for (i
= 0; i
< ngrad
; i
++)
1070 SetRectRgn(tmp
, pts
[gr
[i
].UpperLeft
].x
, pts
[gr
[i
].UpperLeft
].y
,
1071 pts
[gr
[i
].LowerRight
].x
, pts
[gr
[i
].LowerRight
].y
);
1072 CombineRgn(rgn
, rgn
, tmp
, RGN_OR
);
1078 OffsetRgn(rgn
, dst
.visrect
.left
, dst
.visrect
.top
);
1080 ret
= (PSDRV_PutImage(ctx
, rgn
, info
, &bits
, &src
, &dst
, SRCCOPY
) == ERROR_SUCCESS
);
1086 static HGDIOBJ
get_object_handle(struct pp_data
*data
, HANDLETABLE
*handletable
,
1087 DWORD i
, struct ps_brush_pattern
**pattern
)
1092 return GetStockObject(i
& 0x7fffffff);
1094 *pattern
= data
->patterns
+ i
;
1095 return handletable
->objectHandle
[i
];
1098 static BOOL
select_hbrush(struct pp_data
*data
, HANDLETABLE
*htable
, int handle_count
, HBRUSH brush
)
1100 struct ps_brush_pattern
*pattern
= NULL
;
1103 for (i
= 0; i
< handle_count
; i
++)
1105 if (htable
->objectHandle
[i
] == brush
)
1107 pattern
= data
->patterns
+ i
;
1112 return PSDRV_SelectBrush(data
->ctx
, brush
, pattern
) != NULL
;
1115 /* Performs a device to world transformation on the specified size (which
1116 * is in integer format).
1118 static inline INT
INTERNAL_YWSTODS(HDC hdc
, INT height
)
1121 pt
[0].x
= pt
[0].y
= 0;
1125 return pt
[1].y
- pt
[0].y
;
1128 extern const unsigned short bidi_direction_table
[];
1130 /*------------------------------------------------------------------------
1131 Bidirectional Character Types
1133 as defined by the Unicode Bidirectional Algorithm Table 3-7.
1137 The list of bidirectional character types here is not grouped the
1138 same way as the table 3-7, since the numeric values for the types
1139 are chosen to keep the state and action tables compact.
1140 ------------------------------------------------------------------------*/
1144 /* ON MUST be zero, code relies on ON = N = 0 */
1145 ON
= 0, /* Other Neutral */
1146 L
, /* Left Letter */
1147 R
, /* Right Letter */
1148 AN
, /* Arabic Number */
1149 EN
, /* European Number */
1150 AL
, /* Arabic Letter (Right-to-left) */
1151 NSM
, /* Non-spacing Mark */
1152 CS
, /* Common Separator */
1153 ES
, /* European Separator */
1154 ET
, /* European Terminator (post/prefix e.g. $ and %) */
1156 /* resolved types */
1157 BN
, /* Boundary neutral (type of RLE etc after explicit levels) */
1160 S
, /* Segment Separator (TAB) // used only in L1 */
1161 WS
, /* White space // used only in L1 */
1162 B
, /* Paragraph Separator (aka as PS) */
1164 /* types for explicit controls */
1165 RLO
, /* these are used only in X1-X9 */
1171 LRI
, /* Isolate formatting characters new with 6.3 */
1176 /* resolved types, also resolved directions */
1177 NI
= ON
, /* alias, where ON, WS and S are treated the same */
1180 static inline unsigned short get_table_entry_32(const unsigned short *table
, UINT ch
)
1182 return table
[table
[table
[table
[ch
>> 12] + ((ch
>> 8) & 0x0f)] + ((ch
>> 4) & 0x0f)] + (ch
& 0xf)];
1185 /* Convert the libwine information to the direction enum */
1186 static void classify(LPCWSTR lpString
, WORD
*chartype
, DWORD uCount
)
1190 for (i
= 0; i
< uCount
; ++i
)
1191 chartype
[i
] = get_table_entry_32(bidi_direction_table
, lpString
[i
]);
1194 /* Set a run of cval values at locations all prior to, but not including */
1195 /* iStart, to the new value nval. */
1196 static void SetDeferredRun(BYTE
*pval
, int cval
, int iStart
, int nval
)
1199 for (; i
>= iStart
- cval
; i
--)
1205 /* THE PARAGRAPH LEVEL */
1207 /*------------------------------------------------------------------------
1208 Function: resolveParagraphs
1210 Resolves the input strings into blocks over which the algorithm
1213 Implements Rule P1 of the Unicode Bidi Algorithm
1218 Output: revised character count
1220 Note: This is a very simplistic function. In effect it restricts
1221 the action of the algorithm to the first paragraph in the input
1222 where a paragraph ends at the end of the first block separator
1223 or at the end of the input text.
1225 ------------------------------------------------------------------------*/
1227 static int resolveParagraphs(WORD
*types
, int cch
)
1229 /* skip characters not of type B */
1231 for(; ich
< cch
&& types
[ich
] != B
; ich
++);
1232 /* stop after first B, make it a BN for use in the next steps */
1233 if (ich
< cch
&& types
[ich
] == B
)
1239 /*------------------------------------------------------------------------
1240 Function: resolveLines
1242 Breaks a paragraph into lines
1244 Input: Array of line break flags
1246 In/Out: Array of characters
1248 Returns the count of characters on the first line
1250 Note: This function only breaks lines at hard line breaks. Other
1251 line breaks can be passed in. If pbrk[n] is TRUE, then a break
1252 occurs after the character in pszInput[n]. Breaks before the first
1253 character are not allowed.
1254 ------------------------------------------------------------------------*/
1255 static int resolveLines(LPCWSTR pszInput
, const BOOL
* pbrk
, int cch
)
1257 /* skip characters not of type LS */
1259 for(; ich
< cch
; ich
++)
1261 if (pszInput
[ich
] == (WCHAR
)'\n' || (pbrk
&& pbrk
[ich
]))
1271 /*------------------------------------------------------------------------
1272 Function: resolveWhiteSpace
1274 Resolves levels for WS and S
1275 Implements rule L1 of the Unicode bidi Algorithm.
1277 Input: Base embedding level
1279 Array of direction classes (for one line of text)
1281 In/Out: Array of embedding levels (for one line of text)
1283 Note: this should be applied a line at a time. The default driver
1284 code supplied in this file assumes a single line of text; for
1285 a real implementation, cch and the initial pointer values
1286 would have to be adjusted.
1287 ------------------------------------------------------------------------*/
1288 static void resolveWhitespace(int baselevel
, const WORD
*pcls
, BYTE
*plevel
, int cch
)
1291 BYTE oldlevel
= baselevel
;
1294 for (; ich
< cch
; ich
++)
1299 cchrun
= 0; /* any other character breaks the run */
1315 plevel
[ich
] = oldlevel
;
1321 /* reset levels for WS before eot */
1322 SetDeferredRun(plevel
, cchrun
, ich
, baselevel
);
1324 plevel
[ich
] = baselevel
;
1327 oldlevel
= plevel
[ich
];
1329 /* reset level before eot */
1330 SetDeferredRun(plevel
, cchrun
, ich
, baselevel
);
1333 /*------------------------------------------------------------------------
1336 Implements the Line-by-Line phases of the Unicode Bidi Algorithm
1338 Input: Count of characters
1339 Array of character directions
1344 ------------------------------------------------------------------------*/
1345 static void BidiLines(int baselevel
, LPWSTR pszOutLine
, LPCWSTR pszLine
, const WORD
* pclsLine
,
1346 BYTE
* plevelLine
, int cchPara
, const BOOL
* pbrk
)
1352 run
= HeapAlloc(GetProcessHeap(), 0, cchPara
* sizeof(int));
1355 WARN("Out of memory\n");
1361 /* break lines at LS */
1362 cchLine
= resolveLines(pszLine
, pbrk
, cchPara
);
1364 /* resolve whitespace */
1365 resolveWhitespace(baselevel
, pclsLine
, plevelLine
, cchLine
);
1370 /* reorder each line in place */
1371 ScriptLayout(cchLine
, plevelLine
, NULL
, run
);
1372 for (i
= 0; i
< cchLine
; i
++)
1373 pszOutLine
[done
+run
[i
]] = pszLine
[i
];
1377 plevelLine
+= cchLine
;
1378 pbrk
+= pbrk
? cchLine
: 0;
1379 pclsLine
+= cchLine
;
1385 HeapFree(GetProcessHeap(), 0, run
);
1388 #define WINE_GCPW_FORCE_LTR 0
1389 #define WINE_GCPW_FORCE_RTL 1
1390 #define WINE_GCPW_DIR_MASK 3
1392 static BOOL
BIDI_Reorder(HDC hDC
, /* [in] Display DC */
1393 LPCWSTR lpString
, /* [in] The string for which information is to be returned */
1394 INT uCount
, /* [in] Number of WCHARs in string. */
1395 DWORD dwFlags
, /* [in] GetCharacterPlacement compatible flags */
1396 DWORD dwWineGCP_Flags
, /* [in] Wine internal flags - Force paragraph direction */
1397 LPWSTR lpOutString
, /* [out] Reordered string */
1398 INT uCountOut
, /* [in] Size of output buffer */
1399 UINT
*lpOrder
, /* [out] Logical -> Visual order map */
1400 WORD
**lpGlyphs
, /* [out] reordered, mirrored, shaped glyphs to display */
1401 INT
*cGlyphs
) /* [out] number of glyphs generated */
1403 WORD
*chartype
= NULL
;
1404 BYTE
*levels
= NULL
;
1407 BOOL is_complex
, ret
= FALSE
;
1411 SCRIPT_CONTROL Control
;
1413 SCRIPT_ITEM
*pItems
= NULL
;
1415 SCRIPT_CACHE psc
= NULL
;
1416 WORD
*run_glyphs
= NULL
;
1417 WORD
*pwLogClust
= NULL
;
1418 SCRIPT_VISATTR
*psva
= NULL
;
1419 DWORD cMaxGlyphs
= 0;
1420 BOOL doGlyphs
= TRUE
;
1422 TRACE("%s, %d, 0x%08lx lpOutString=%p, lpOrder=%p\n",
1423 debugstr_wn(lpString
, uCount
), uCount
, dwFlags
,
1424 lpOutString
, lpOrder
);
1426 memset(&Control
, 0, sizeof(Control
));
1427 memset(&State
, 0, sizeof(State
));
1431 if (!(dwFlags
& GCP_REORDER
))
1433 FIXME("Asked to reorder without reorder flag set\n");
1437 if (lpOutString
&& uCountOut
< uCount
)
1439 FIXME("lpOutString too small\n");
1443 chartype
= HeapAlloc(GetProcessHeap(), 0, uCount
* sizeof(WORD
));
1446 WARN("Out of memory\n");
1451 memcpy(lpOutString
, lpString
, uCount
* sizeof(WCHAR
));
1454 for (i
= 0; i
< uCount
&& !is_complex
; i
++)
1456 if ((lpString
[i
] >= 0x900 && lpString
[i
] <= 0xfff) ||
1457 (lpString
[i
] >= 0x1cd0 && lpString
[i
] <= 0x1cff) ||
1458 (lpString
[i
] >= 0xa840 && lpString
[i
] <= 0xa8ff))
1462 /* Verify reordering will be required */
1463 if (WINE_GCPW_FORCE_RTL
== (dwWineGCP_Flags
& WINE_GCPW_DIR_MASK
))
1464 State
.uBidiLevel
= 1;
1465 else if (!is_complex
)
1468 classify(lpString
, chartype
, uCount
);
1469 for (i
= 0; i
< uCount
; i
++)
1470 switch (chartype
[i
])
1481 HeapFree(GetProcessHeap(), 0, chartype
);
1484 for (i
= 0; i
< uCount
; i
++)
1491 levels
= HeapAlloc(GetProcessHeap(), 0, uCount
* sizeof(BYTE
));
1494 WARN("Out of memory\n");
1499 pItems
= HeapAlloc(GetProcessHeap(),0, maxItems
* sizeof(SCRIPT_ITEM
));
1502 WARN("Out of memory\n");
1508 cMaxGlyphs
= 1.5 * uCount
+ 16;
1509 run_glyphs
= HeapAlloc(GetProcessHeap(),0,sizeof(WORD
) * cMaxGlyphs
);
1512 WARN("Out of memory\n");
1515 pwLogClust
= HeapAlloc(GetProcessHeap(),0,sizeof(WORD
) * uCount
);
1518 WARN("Out of memory\n");
1521 psva
= HeapAlloc(GetProcessHeap(),0,sizeof(SCRIPT_VISATTR
) * cMaxGlyphs
);
1524 WARN("Out of memory\n");
1531 while (done
< uCount
)
1534 classify(lpString
+ done
, chartype
, uCount
- done
);
1535 /* limit text to first block */
1536 i
= resolveParagraphs(chartype
, uCount
- done
);
1537 for (j
= 0; j
< i
; ++j
)
1543 case ON
: chartype
[j
] = NI
;
1547 res
= ScriptItemize(lpString
+ done
, i
, maxItems
, &Control
, &State
, pItems
, &nItems
);
1548 while (res
== E_OUTOFMEMORY
)
1550 SCRIPT_ITEM
*new_pItems
= HeapReAlloc(GetProcessHeap(), 0, pItems
, sizeof(*pItems
) * maxItems
* 2);
1553 WARN("Out of memory\n");
1556 pItems
= new_pItems
;
1558 res
= ScriptItemize(lpString
+ done
, i
, maxItems
, &Control
, &State
, pItems
, &nItems
);
1561 if (lpOutString
|| lpOrder
)
1562 for (j
= 0; j
< nItems
; j
++)
1565 for (k
= pItems
[j
].iCharPos
; k
< pItems
[j
+1].iCharPos
; k
++)
1566 levels
[k
] = pItems
[j
].a
.s
.uBidiLevel
;
1571 /* assign directional types again, but for WS, S this time */
1572 classify(lpString
+ done
, chartype
, i
);
1574 BidiLines(State
.uBidiLevel
, lpOutString
+ done
, lpString
+ done
,
1575 chartype
, levels
, i
, 0);
1581 for (j
= lastgood
= 0; j
< i
; ++j
)
1582 if (levels
[j
] != levels
[lastgood
])
1585 if (levels
[lastgood
] & 1)
1586 for (k
= j
; k
>= lastgood
; --k
)
1587 lpOrder
[done
+ k
] = done
+ j
- k
;
1589 for (k
= lastgood
; k
<= j
; ++k
)
1590 lpOrder
[done
+ k
] = done
+ k
;
1593 if (levels
[lastgood
] & 1)
1594 for (k
= j
- 1; k
>= lastgood
; --k
)
1595 lpOrder
[done
+ k
] = done
+ j
- 1 - k
;
1597 for (k
= lastgood
; k
< j
; ++k
)
1598 lpOrder
[done
+ k
] = done
+ k
;
1601 if (lpGlyphs
&& doGlyphs
)
1605 SCRIPT_ITEM
*curItem
;
1607 runOrder
= HeapAlloc(GetProcessHeap(), 0, maxItems
* sizeof(*runOrder
));
1608 visOrder
= HeapAlloc(GetProcessHeap(), 0, maxItems
* sizeof(*visOrder
));
1609 if (!runOrder
|| !visOrder
)
1611 WARN("Out of memory\n");
1612 HeapFree(GetProcessHeap(), 0, runOrder
);
1613 HeapFree(GetProcessHeap(), 0, visOrder
);
1617 for (j
= 0; j
< nItems
; j
++)
1618 runOrder
[j
] = pItems
[j
].a
.s
.uBidiLevel
;
1620 ScriptLayout(nItems
, runOrder
, visOrder
, NULL
);
1622 for (j
= 0; j
< nItems
; j
++)
1625 int cChars
,cOutGlyphs
;
1626 curItem
= &pItems
[visOrder
[j
]];
1628 cChars
= pItems
[visOrder
[j
]+1].iCharPos
- curItem
->iCharPos
;
1630 res
= ScriptShape(hDC
, &psc
, lpString
+ done
+ curItem
->iCharPos
, cChars
, cMaxGlyphs
, &curItem
->a
, run_glyphs
, pwLogClust
, psva
, &cOutGlyphs
);
1631 while (res
== E_OUTOFMEMORY
)
1633 WORD
*new_run_glyphs
= HeapReAlloc(GetProcessHeap(), 0, run_glyphs
, sizeof(*run_glyphs
) * cMaxGlyphs
* 2);
1634 SCRIPT_VISATTR
*new_psva
= HeapReAlloc(GetProcessHeap(), 0, psva
, sizeof(*psva
) * cMaxGlyphs
* 2);
1635 if (!new_run_glyphs
|| !new_psva
)
1637 WARN("Out of memory\n");
1638 HeapFree(GetProcessHeap(), 0, runOrder
);
1639 HeapFree(GetProcessHeap(), 0, visOrder
);
1640 HeapFree(GetProcessHeap(), 0, *lpGlyphs
);
1643 run_glyphs
= new_run_glyphs
;
1648 run_glyphs
= new_run_glyphs
;
1651 res
= ScriptShape(hDC
, &psc
, lpString
+ done
+ curItem
->iCharPos
, cChars
, cMaxGlyphs
, &curItem
->a
, run_glyphs
, pwLogClust
, psva
, &cOutGlyphs
);
1655 if (res
== USP_E_SCRIPT_NOT_IN_FONT
)
1656 TRACE("Unable to shape with currently selected font\n");
1658 FIXME("Unable to shape string (%lx)\n",res
);
1661 HeapFree(GetProcessHeap(), 0, *lpGlyphs
);
1668 new_glyphs
= HeapReAlloc(GetProcessHeap(), 0, *lpGlyphs
, sizeof(**lpGlyphs
) * (glyph_i
+ cOutGlyphs
));
1670 new_glyphs
= HeapAlloc(GetProcessHeap(), 0, sizeof(**lpGlyphs
) * (glyph_i
+ cOutGlyphs
));
1673 WARN("Out of memory\n");
1674 HeapFree(GetProcessHeap(), 0, runOrder
);
1675 HeapFree(GetProcessHeap(), 0, visOrder
);
1676 HeapFree(GetProcessHeap(), 0, *lpGlyphs
);
1680 *lpGlyphs
= new_glyphs
;
1681 for (k
= 0; k
< cOutGlyphs
; k
++)
1682 (*lpGlyphs
)[glyph_i
+k
] = run_glyphs
[k
];
1683 glyph_i
+= cOutGlyphs
;
1686 HeapFree(GetProcessHeap(), 0, runOrder
);
1687 HeapFree(GetProcessHeap(), 0, visOrder
);
1697 HeapFree(GetProcessHeap(), 0, chartype
);
1698 HeapFree(GetProcessHeap(), 0, levels
);
1699 HeapFree(GetProcessHeap(), 0, pItems
);
1700 HeapFree(GetProcessHeap(), 0, run_glyphs
);
1701 HeapFree(GetProcessHeap(), 0, pwLogClust
);
1702 HeapFree(GetProcessHeap(), 0, psva
);
1703 ScriptFreeCache(&psc
);
1707 static inline BOOL
intersect_rect(RECT
*dst
, const RECT
*src1
, const RECT
*src2
)
1709 dst
->left
= max(src1
->left
, src2
->left
);
1710 dst
->top
= max(src1
->top
, src2
->top
);
1711 dst
->right
= min(src1
->right
, src2
->right
);
1712 dst
->bottom
= min(src1
->bottom
, src2
->bottom
);
1713 return !IsRectEmpty(dst
);
1716 /***********************************************************************
1719 * Scale the underline / strikeout line width.
1721 static inline int get_line_width(HDC hdc
, int metric_size
)
1723 int width
= abs(INTERNAL_YWSTODS(hdc
, metric_size
));
1724 if (width
== 0) width
= 1;
1725 if (metric_size
< 0) width
= -width
;
1729 static BOOL
ext_text_out(struct pp_data
*data
, HANDLETABLE
*htable
,
1730 int handle_count
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
1731 const WCHAR
*str
, UINT count
, const INT
*dx
)
1733 HDC hdc
= data
->ctx
->hdc
;
1740 double cosEsc
, sinEsc
;
1744 POINT
*deltas
= NULL
, width
= {0, 0};
1746 WORD
*glyphs
= NULL
;
1749 if (!(flags
& (ETO_GLYPH_INDEX
| ETO_IGNORELANGUAGE
)) && count
> 0)
1751 int glyphs_count
= 0;
1754 bidi_flags
= (GetTextAlign(hdc
) & TA_RTLREADING
) || (flags
& ETO_RTLREADING
)
1755 ? WINE_GCPW_FORCE_RTL
: WINE_GCPW_FORCE_LTR
;
1757 BIDI_Reorder(hdc
, str
, count
, GCP_REORDER
, bidi_flags
,
1758 NULL
, 0, NULL
, &glyphs
, &glyphs_count
);
1760 flags
|= ETO_IGNORELANGUAGE
;
1763 flags
|= ETO_GLYPH_INDEX
;
1764 count
= glyphs_count
;
1769 align
= GetTextAlign(hdc
);
1770 breakRem
= data
->break_rem
;
1771 layout
= GetLayout(hdc
);
1773 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
1774 if (layout
& LAYOUT_RTL
)
1776 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
1777 align
^= TA_RTLREADING
;
1780 TRACE("%d, %d, %08x, %s, %s, %d, %p)\n", x
, y
, flags
,
1781 wine_dbgstr_rect(rect
), debugstr_wn(str
, count
), count
, dx
);
1782 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, GetBkMode(hdc
),
1785 if(align
& TA_UPDATECP
)
1787 GetCurrentPositionEx(hdc
, &pt
);
1792 GetTextMetricsW(hdc
, &tm
);
1793 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1795 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
1796 lf
.lfEscapement
= 0;
1798 GetWorldTransform(hdc
, &xform
);
1799 if (GetGraphicsMode(hdc
) == GM_COMPATIBLE
&&
1800 xform
.eM11
* xform
.eM22
< 0)
1802 lf
.lfEscapement
= -lf
.lfEscapement
;
1805 if(lf
.lfEscapement
!= 0)
1807 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1808 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1816 if (rect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
1819 LPtoDP(hdc
, (POINT
*)&rc
, 2);
1821 if (flags
& ETO_OPAQUE
)
1822 PSDRV_ExtTextOut(data
->ctx
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
1824 else flags
&= ~ETO_CLIPPED
;
1834 LPtoDP(hdc
, &pt
, 1);
1838 char_extra
= GetTextCharacterExtra(hdc
);
1839 if (char_extra
&& dx
)
1840 char_extra
= 0; /* Printer drivers don't add char_extra if dx is supplied */
1842 if(char_extra
|| data
->break_extra
|| breakRem
|| dx
|| lf
.lfEscapement
!= 0)
1845 POINT total
= {0, 0}, desired
[2];
1847 deltas
= malloc(count
* sizeof(*deltas
));
1850 if (flags
& ETO_PDY
)
1852 for (i
= 0; i
< count
; i
++)
1854 deltas
[i
].x
= dx
[i
* 2] + char_extra
;
1855 deltas
[i
].y
= -dx
[i
* 2 + 1];
1860 for (i
= 0; i
< count
; i
++)
1862 deltas
[i
].x
= dx
[i
] + char_extra
;
1869 INT
*dx
= malloc(count
* sizeof(*dx
));
1871 NtGdiGetTextExtentExW(hdc
, str
, count
, -1, NULL
, dx
, &sz
, !!(flags
& ETO_GLYPH_INDEX
));
1873 deltas
[0].x
= dx
[0];
1875 for (i
= 1; i
< count
; i
++)
1877 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
1883 for(i
= 0; i
< count
; i
++)
1885 total
.x
+= deltas
[i
].x
;
1886 total
.y
+= deltas
[i
].y
;
1888 desired
[0].x
= desired
[0].y
= 0;
1890 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
1891 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
1893 LPtoDP(hdc
, desired
, 2);
1894 desired
[1].x
-= desired
[0].x
;
1895 desired
[1].y
-= desired
[0].y
;
1897 if (GetGraphicsMode(hdc
) == GM_COMPATIBLE
)
1900 desired
[1].x
= -desired
[1].x
;
1902 desired
[1].y
= -desired
[1].y
;
1905 deltas
[i
].x
= desired
[1].x
- width
.x
;
1906 deltas
[i
].y
= desired
[1].y
- width
.y
;
1916 NtGdiGetTextExtentExW(hdc
, str
, count
, 0, NULL
, NULL
, &sz
, !!(flags
& ETO_GLYPH_INDEX
));
1917 desired
[0].x
= desired
[0].y
= 0;
1918 desired
[1].x
= sz
.cx
;
1920 LPtoDP(hdc
, desired
, 2);
1921 desired
[1].x
-= desired
[0].x
;
1922 desired
[1].y
-= desired
[0].y
;
1924 if (GetGraphicsMode(hdc
) == GM_COMPATIBLE
)
1927 desired
[1].x
= -desired
[1].x
;
1929 desired
[1].y
= -desired
[1].y
;
1934 tm
.tmAscent
= abs(INTERNAL_YWSTODS(hdc
, tm
.tmAscent
));
1935 tm
.tmDescent
= abs(INTERNAL_YWSTODS(hdc
, tm
.tmDescent
));
1936 switch(align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
))
1939 if (align
& TA_UPDATECP
)
1943 DPtoLP(hdc
, &pt
, 1);
1944 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
1956 if (align
& TA_UPDATECP
)
1960 DPtoLP(hdc
, &pt
, 1);
1961 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
1966 switch(align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
))
1969 y
+= tm
.tmAscent
* cosEsc
;
1970 x
+= tm
.tmAscent
* sinEsc
;
1974 y
-= tm
.tmDescent
* cosEsc
;
1975 x
-= tm
.tmDescent
* sinEsc
;
1982 if (GetBkMode(hdc
) != TRANSPARENT
)
1984 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
1986 if(!(flags
& ETO_OPAQUE
) || !rect
||
1987 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
1988 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
1992 text_box
.right
= x
+ width
.x
;
1993 text_box
.top
= y
- tm
.tmAscent
;
1994 text_box
.bottom
= y
+ tm
.tmDescent
;
1996 if (flags
& ETO_CLIPPED
) intersect_rect(&text_box
, &text_box
, &rc
);
1997 if (!IsRectEmpty(&text_box
))
1998 PSDRV_ExtTextOut(data
->ctx
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
2003 ret
= PSDRV_ExtTextOut(data
->ctx
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
2004 str
, count
, (INT
*)deltas
);
2009 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
2011 int underlinePos
, strikeoutPos
;
2012 int underlineWidth
, strikeoutWidth
;
2013 UINT size
= NtGdiGetOutlineTextMetricsInternalW(hdc
, 0, NULL
, 0);
2014 OUTLINETEXTMETRICW
* otm
= NULL
;
2016 HBRUSH hbrush
= CreateSolidBrush(GetTextColor(hdc
));
2017 HPEN hpen
= GetStockObject(NULL_PEN
);
2019 PSDRV_SelectPen(data
->ctx
, hpen
, NULL
);
2020 hpen
= SelectObject(hdc
, hpen
);
2022 PSDRV_SelectBrush(data
->ctx
, hbrush
, NULL
);
2023 hbrush
= SelectObject(hdc
, hbrush
);
2028 underlineWidth
= tm
.tmAscent
/ 20 + 1;
2029 strikeoutPos
= tm
.tmAscent
/ 2;
2030 strikeoutWidth
= underlineWidth
;
2035 NtGdiGetOutlineTextMetricsInternalW(hdc
, size
, otm
, 0);
2036 underlinePos
= abs(INTERNAL_YWSTODS(hdc
, otm
->otmsUnderscorePosition
));
2037 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
2038 underlineWidth
= get_line_width(hdc
, otm
->otmsUnderscoreSize
);
2039 strikeoutPos
= abs(INTERNAL_YWSTODS(hdc
, otm
->otmsStrikeoutPosition
));
2040 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
2041 strikeoutWidth
= get_line_width(hdc
, otm
->otmsStrikeoutSize
);
2049 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
2050 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
2051 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
2052 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
2053 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
2054 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
2055 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
2056 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
2057 pts
[4].x
= pts
[0].x
;
2058 pts
[4].y
= pts
[0].y
;
2059 DPtoLP(hdc
, pts
, 5);
2060 PSDRV_PolyPolygon(data
->ctx
, pts
, &cnt
, 1);
2066 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
2067 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
2068 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
2069 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
2070 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
2071 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
2072 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
2073 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
2074 pts
[4].x
= pts
[0].x
;
2075 pts
[4].y
= pts
[0].y
;
2076 DPtoLP(hdc
, pts
, 5);
2077 PSDRV_PolyPolygon(data
->ctx
, pts
, &cnt
, 1);
2080 PSDRV_SelectPen(data
->ctx
, hpen
, NULL
);
2081 SelectObject(hdc
, hpen
);
2082 select_hbrush(data
, htable
, handle_count
, hbrush
);
2083 SelectObject(hdc
, hbrush
);
2084 DeleteObject(hbrush
);
2087 HeapFree(GetProcessHeap(), 0, glyphs
);
2091 static BOOL
fill_rgn(struct pp_data
*data
, HANDLETABLE
*htable
, int handle_count
, DWORD brush
, HRGN rgn
)
2093 struct ps_brush_pattern
*pattern
;
2097 hbrush
= get_object_handle(data
, htable
, brush
, &pattern
);
2098 PSDRV_SelectBrush(data
->ctx
, hbrush
, pattern
);
2099 ret
= PSDRV_PaintRgn(data
->ctx
, rgn
);
2100 select_hbrush(data
, htable
, handle_count
, GetCurrentObject(data
->ctx
->hdc
, OBJ_BRUSH
));
2101 PSDRV_SelectBrush(data
->ctx
, hbrush
, pattern
);
2105 static BOOL
is_path_record(int type
)
2109 case EMR_POLYBEZIER
:
2112 case EMR_POLYBEZIERTO
:
2113 case EMR_POLYLINETO
:
2114 case EMR_POLYPOLYLINE
:
2115 case EMR_POLYPOLYGON
:
2127 case EMR_EXTTEXTOUTA
:
2128 case EMR_EXTTEXTOUTW
:
2129 case EMR_POLYBEZIER16
:
2131 case EMR_POLYLINE16
:
2132 case EMR_POLYBEZIERTO16
:
2133 case EMR_POLYLINETO16
:
2134 case EMR_POLYPOLYLINE16
:
2135 case EMR_POLYPOLYGON16
:
2136 case EMR_POLYDRAW16
:
2143 static int WINAPI
hmf_proc(HDC hdc
, HANDLETABLE
*htable
,
2144 const ENHMETARECORD
*rec
, int handle_count
, LPARAM arg
)
2146 struct pp_data
*data
= (struct pp_data
*)arg
;
2148 if (data
->path
&& is_path_record(rec
->iType
))
2149 return PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
);
2155 const ENHMETAHEADER
*header
= (const ENHMETAHEADER
*)rec
;
2157 data
->patterns
= calloc(sizeof(*data
->patterns
), header
->nHandles
);
2158 return data
->patterns
&& PSDRV_StartPage(data
->ctx
);
2160 case EMR_POLYBEZIER
:
2162 const EMRPOLYBEZIER
*p
= (const EMRPOLYBEZIER
*)rec
;
2164 return PSDRV_PolyBezier(data
->ctx
, (const POINT
*)p
->aptl
, p
->cptl
);
2168 const EMRPOLYGON
*p
= (const EMRPOLYGON
*)rec
;
2170 return PSDRV_PolyPolygon(data
->ctx
, (const POINT
*)p
->aptl
,
2171 (const INT
*)&p
->cptl
, 1);
2175 const EMRPOLYLINE
*p
= (const EMRPOLYLINE
*)rec
;
2177 return PSDRV_PolyPolyline(data
->ctx
,
2178 (const POINT
*)p
->aptl
, &p
->cptl
, 1);
2180 case EMR_POLYBEZIERTO
:
2182 const EMRPOLYBEZIERTO
*p
= (const EMRPOLYBEZIERTO
*)rec
;
2184 return PSDRV_PolyBezierTo(data
->ctx
, (const POINT
*)p
->aptl
, p
->cptl
) &&
2185 MoveToEx(data
->ctx
->hdc
, p
->aptl
[p
->cptl
- 1].x
, p
->aptl
[p
->cptl
- 1].y
, NULL
);
2187 case EMR_POLYLINETO
:
2189 const EMRPOLYLINETO
*p
= (const EMRPOLYLINETO
*)rec
;
2195 pts
= malloc(sizeof(*pts
) * cnt
);
2198 GetCurrentPositionEx(data
->ctx
->hdc
, pts
);
2199 memcpy(pts
+ 1, p
->aptl
, sizeof(*pts
) * p
->cptl
);
2200 ret
= PSDRV_PolyPolyline(data
->ctx
, pts
, &cnt
, 1) &&
2201 MoveToEx(data
->ctx
->hdc
, pts
[cnt
- 1].x
, pts
[cnt
- 1].y
, NULL
);
2205 case EMR_POLYPOLYLINE
:
2207 const EMRPOLYPOLYLINE
*p
= (const EMRPOLYPOLYLINE
*)rec
;
2209 return PSDRV_PolyPolyline(data
->ctx
,
2210 (const POINT
*)(p
->aPolyCounts
+ p
->nPolys
),
2211 p
->aPolyCounts
, p
->nPolys
);
2213 case EMR_POLYPOLYGON
:
2215 const EMRPOLYPOLYGON
*p
= (const EMRPOLYPOLYGON
*)rec
;
2217 return PSDRV_PolyPolygon(data
->ctx
,
2218 (const POINT
*)(p
->aPolyCounts
+ p
->nPolys
),
2219 (const INT
*)p
->aPolyCounts
, p
->nPolys
);
2222 return PSDRV_EndPage(data
->ctx
);
2225 const EMRSETPIXELV
*p
= (const EMRSETPIXELV
*)rec
;
2227 return PSDRV_SetPixel(data
->ctx
, p
->ptlPixel
.x
,
2228 p
->ptlPixel
.y
, p
->crColor
);
2230 case EMR_SETTEXTCOLOR
:
2232 const EMRSETTEXTCOLOR
*p
= (const EMRSETTEXTCOLOR
*)rec
;
2234 SetTextColor(data
->ctx
->hdc
, p
->crColor
);
2235 PSDRV_SetTextColor(data
->ctx
, p
->crColor
);
2238 case EMR_SETBKCOLOR
:
2240 const EMRSETBKCOLOR
*p
= (const EMRSETBKCOLOR
*)rec
;
2242 SetBkColor(data
->ctx
->hdc
, p
->crColor
);
2243 PSDRV_SetBkColor(data
->ctx
, p
->crColor
);
2248 int ret
= PlayEnhMetaFileRecord(hdc
, htable
, rec
, handle_count
);
2250 if (!data
->saved_dc_size
)
2252 data
->saved_dc
= malloc(8 * sizeof(*data
->saved_dc
));
2254 data
->saved_dc_size
= 8;
2256 else if (data
->saved_dc_size
== data
->saved_dc_top
)
2258 void *alloc
= realloc(data
->saved_dc
, data
->saved_dc_size
* 2);
2262 data
->saved_dc
= alloc
;
2263 data
->saved_dc_size
*= 2;
2266 if (data
->saved_dc_size
== data
->saved_dc_top
)
2269 data
->saved_dc
[data
->saved_dc_top
].break_extra
= data
->break_extra
;
2270 data
->saved_dc
[data
->saved_dc_top
].break_rem
= data
->break_rem
;
2271 data
->saved_dc_top
++;
2276 const EMRRESTOREDC
*p
= (const EMRRESTOREDC
*)rec
;
2277 HDC hdc
= data
->ctx
->hdc
;
2278 int ret
= PlayEnhMetaFileRecord(hdc
, htable
, rec
, handle_count
);
2283 select_hbrush(data
, htable
, handle_count
, GetCurrentObject(hdc
, OBJ_BRUSH
));
2284 PSDRV_SelectFont(data
->ctx
, GetCurrentObject(hdc
, OBJ_FONT
), &aa_flags
);
2285 PSDRV_SelectPen(data
->ctx
, GetCurrentObject(hdc
, OBJ_PEN
), NULL
);
2286 PSDRV_SetBkColor(data
->ctx
, GetBkColor(hdc
));
2287 PSDRV_SetTextColor(data
->ctx
, GetTextColor(hdc
));
2289 if (p
->iRelative
>= 0 || data
->saved_dc_top
+ p
->iRelative
< 0)
2291 data
->saved_dc_top
+= p
->iRelative
;
2292 data
->break_extra
= data
->saved_dc
[data
->saved_dc_top
].break_extra
;
2293 data
->break_rem
= data
->saved_dc
[data
->saved_dc_top
].break_rem
;
2297 case EMR_SELECTOBJECT
:
2299 const EMRSELECTOBJECT
*so
= (const EMRSELECTOBJECT
*)rec
;
2300 struct ps_brush_pattern
*pattern
;
2304 obj
= get_object_handle(data
, htable
, so
->ihObject
, &pattern
);
2305 SelectObject(data
->ctx
->hdc
, obj
);
2307 switch (GetObjectType(obj
))
2309 case OBJ_PEN
: return PSDRV_SelectPen(data
->ctx
, obj
, NULL
) != NULL
;
2310 case OBJ_BRUSH
: return PSDRV_SelectBrush(data
->ctx
, obj
, pattern
) != NULL
;
2311 case OBJ_FONT
: return PSDRV_SelectFont(data
->ctx
, obj
, &aa_flags
) != NULL
;
2313 FIXME("unhandled object type %ld\n", GetObjectType(obj
));
2317 case EMR_DELETEOBJECT
:
2319 const EMRDELETEOBJECT
*p
= (const EMRDELETEOBJECT
*)rec
;
2321 memset(&data
->patterns
[p
->ihObject
], 0, sizeof(*data
->patterns
));
2322 return PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
);
2326 const EMRANGLEARC
*p
= (const EMRANGLEARC
*)rec
;
2327 int arc_dir
= SetArcDirection(data
->ctx
->hdc
,
2328 p
->eSweepAngle
>= 0 ? AD_COUNTERCLOCKWISE
: AD_CLOCKWISE
);
2332 arcto
.emr
.iType
= EMR_ARCTO
;
2333 arcto
.rclBox
.left
= p
->ptlCenter
.x
- p
->nRadius
;
2334 arcto
.rclBox
.top
= p
->ptlCenter
.y
- p
->nRadius
;
2335 arcto
.rclBox
.right
= p
->ptlCenter
.x
+ p
->nRadius
;
2336 arcto
.rclBox
.bottom
= p
->ptlCenter
.y
+ p
->nRadius
;
2337 arcto
.ptlStart
.x
= GDI_ROUND(p
->ptlCenter
.x
+
2338 cos(p
->eStartAngle
* M_PI
/ 180) * p
->nRadius
);
2339 arcto
.ptlStart
.y
= GDI_ROUND(p
->ptlCenter
.y
-
2340 sin(p
->eStartAngle
* M_PI
/ 180) * p
->nRadius
);
2341 arcto
.ptlEnd
.x
= GDI_ROUND(p
->ptlCenter
.x
+
2342 cos((p
->eStartAngle
+ p
->eSweepAngle
) * M_PI
/ 180) * p
->nRadius
);
2343 arcto
.ptlEnd
.y
= GDI_ROUND(p
->ptlCenter
.y
-
2344 sin((p
->eStartAngle
+ p
->eSweepAngle
) * M_PI
/ 180) * p
->nRadius
);
2346 ret
= hmf_proc(hdc
, htable
, (ENHMETARECORD
*)&arcto
, handle_count
, arg
);
2347 SetArcDirection(data
->ctx
->hdc
, arc_dir
);
2352 const EMRELLIPSE
*p
= (const EMRELLIPSE
*)rec
;
2353 const RECTL
*r
= &p
->rclBox
;
2355 return PSDRV_Ellipse(data
->ctx
, r
->left
, r
->top
, r
->right
, r
->bottom
);
2359 const EMRRECTANGLE
*rect
= (const EMRRECTANGLE
*)rec
;
2361 return PSDRV_Rectangle(data
->ctx
, rect
->rclBox
.left
,
2362 rect
->rclBox
.top
, rect
->rclBox
.right
, rect
->rclBox
.bottom
);
2366 const EMRROUNDRECT
*p
= (const EMRROUNDRECT
*)rec
;
2368 return PSDRV_RoundRect(data
->ctx
, p
->rclBox
.left
,
2369 p
->rclBox
.top
, p
->rclBox
.right
, p
->rclBox
.bottom
,
2370 p
->szlCorner
.cx
, p
->szlCorner
.cy
);
2374 const EMRARC
*p
= (const EMRARC
*)rec
;
2376 return PSDRV_Arc(data
->ctx
, p
->rclBox
.left
, p
->rclBox
.top
,
2377 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
2378 p
->ptlStart
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
2382 const EMRCHORD
*p
= (const EMRCHORD
*)rec
;
2384 return PSDRV_Chord(data
->ctx
, p
->rclBox
.left
, p
->rclBox
.top
,
2385 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
2386 p
->ptlStart
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
2390 const EMRPIE
*p
= (const EMRPIE
*)rec
;
2392 return PSDRV_Pie(data
->ctx
, p
->rclBox
.left
, p
->rclBox
.top
,
2393 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
2394 p
->ptlStart
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
2398 const EMRLINETO
*line
= (const EMRLINETO
*)rec
;
2400 return PSDRV_LineTo(data
->ctx
, line
->ptl
.x
, line
->ptl
.y
) &&
2401 MoveToEx(data
->ctx
->hdc
, line
->ptl
.x
, line
->ptl
.y
, NULL
);
2405 const EMRARCTO
*p
= (const EMRARCTO
*)rec
;
2409 ret
= GetCurrentPositionEx(data
->ctx
->hdc
, &pt
);
2412 ret
= ArcTo(data
->ctx
->hdc
, p
->rclBox
.left
, p
->rclBox
.top
,
2413 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
2414 p
->ptlStart
.y
, p
->ptlStart
.x
, p
->ptlStart
.y
);
2417 ret
= PSDRV_LineTo(data
->ctx
, pt
.x
, pt
.y
);
2420 ret
= PSDRV_Arc(data
->ctx
, p
->rclBox
.left
, p
->rclBox
.top
,
2421 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlStart
.x
,
2422 p
->ptlStart
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
2426 ret
= ArcTo(data
->ctx
->hdc
, p
->rclBox
.left
, p
->rclBox
.top
,
2427 p
->rclBox
.right
, p
->rclBox
.bottom
, p
->ptlEnd
.x
,
2428 p
->ptlEnd
.y
, p
->ptlEnd
.x
, p
->ptlEnd
.y
);
2434 const EMRPOLYDRAW
*p
= (const EMRPOLYDRAW
*)rec
;
2435 const POINT
*pts
= (const POINT
*)p
->aptl
;
2437 return poly_draw(data
->ctx
, pts
, (BYTE
*)(p
->aptl
+ p
->cptl
), p
->cptl
) &&
2438 MoveToEx(data
->ctx
->hdc
, pts
[p
->cptl
- 1].x
, pts
[p
->cptl
- 1].y
, NULL
);
2443 return PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
);
2448 return PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
);
2451 PSDRV_FillPath(data
->ctx
);
2453 case EMR_STROKEANDFILLPATH
:
2454 PSDRV_StrokeAndFillPath(data
->ctx
);
2456 case EMR_STROKEPATH
:
2457 PSDRV_StrokePath(data
->ctx
);
2462 return PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
);
2466 const EMRFILLRGN
*p
= (const EMRFILLRGN
*)rec
;
2470 rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
2471 ret
= fill_rgn(data
, htable
, handle_count
, p
->ihBrush
, rgn
);
2477 const EMRFRAMERGN
*p
= (const EMRFRAMERGN
*)rec
;
2481 rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
2482 frame
= CreateRectRgn(0, 0, 0, 0);
2484 CombineRgn(frame
, rgn
, 0, RGN_COPY
);
2485 OffsetRgn(frame
, -p
->szlStroke
.cx
, 0);
2486 OffsetRgn(rgn
, p
->szlStroke
.cx
, 0);
2487 CombineRgn(frame
, frame
, rgn
, RGN_AND
);
2488 OffsetRgn(rgn
, -p
->szlStroke
.cx
, -p
->szlStroke
.cy
);
2489 CombineRgn(frame
, frame
, rgn
, RGN_AND
);
2490 OffsetRgn(rgn
, 0, 2*p
->szlStroke
.cy
);
2491 CombineRgn(frame
, frame
, rgn
, RGN_AND
);
2492 OffsetRgn(rgn
, 0, -p
->szlStroke
.cy
);
2493 CombineRgn(frame
, rgn
, frame
, RGN_DIFF
);
2495 ret
= fill_rgn(data
, htable
, handle_count
, p
->ihBrush
, frame
);
2497 DeleteObject(frame
);
2502 const EMRINVERTRGN
*p
= (const EMRINVERTRGN
*)rec
;
2506 rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
2507 old_rop
= SetROP2(data
->ctx
->hdc
, R2_NOT
);
2508 ret
= fill_rgn(data
, htable
, handle_count
, 0x80000000 | BLACK_BRUSH
, rgn
);
2509 SetROP2(data
->ctx
->hdc
, old_rop
);
2515 const EMRPAINTRGN
*p
= (const EMRPAINTRGN
*)rec
;
2516 HRGN rgn
= ExtCreateRegion(NULL
, p
->cbRgnData
, (const RGNDATA
*)p
->RgnData
);
2519 ret
= PSDRV_PaintRgn(data
->ctx
, rgn
);
2525 const EMRBITBLT
*p
= (const EMRBITBLT
*)rec
;
2526 const BITMAPINFO
*bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
2527 const BYTE
*src_bits
= (BYTE
*)p
+ p
->offBitsSrc
;
2531 blt
.rclBounds
= p
->rclBounds
;
2532 blt
.xDest
= p
->xDest
;
2533 blt
.yDest
= p
->yDest
;
2534 blt
.cxDest
= p
->cxDest
;
2535 blt
.cyDest
= p
->cyDest
;
2536 blt
.dwRop
= p
->dwRop
;
2539 blt
.xformSrc
= p
->xformSrc
;
2540 blt
.crBkColorSrc
= p
->crBkColorSrc
;
2541 blt
.iUsageSrc
= p
->iUsageSrc
;
2542 blt
.offBmiSrc
= p
->offBmiSrc
;
2543 blt
.cbBmiSrc
= p
->cbBmiSrc
;
2544 blt
.offBitsSrc
= p
->offBitsSrc
;
2545 blt
.cbBitsSrc
= p
->cbBitsSrc
;
2546 blt
.cxSrc
= p
->cxDest
;
2547 blt
.cySrc
= p
->cyDest
;
2549 return stretch_blt(data
->ctx
, &blt
, bi
, src_bits
);
2551 case EMR_STRETCHBLT
:
2553 const EMRSTRETCHBLT
*p
= (const EMRSTRETCHBLT
*)rec
;
2554 const BITMAPINFO
*bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
2555 const BYTE
*src_bits
= (BYTE
*)p
+ p
->offBitsSrc
;
2557 return stretch_blt(data
->ctx
, p
, bi
, src_bits
);
2561 const EMRMASKBLT
*p
= (const EMRMASKBLT
*)rec
;
2562 const BITMAPINFO
*mask_bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiMask
);
2563 const BITMAPINFO
*src_bi
= (const BITMAPINFO
*)((BYTE
*)p
+ p
->offBmiSrc
);
2564 const BYTE
*mask_bits
= (BYTE
*)p
+ p
->offBitsMask
;
2565 const BYTE
*src_bits
= (BYTE
*)p
+ p
->offBitsSrc
;
2567 return mask_blt(data
->ctx
, p
, src_bi
, src_bits
, mask_bi
, mask_bits
);
2571 const EMRPLGBLT
*p
= (const EMRPLGBLT
*)rec
;
2573 return plg_blt(data
->ctx
, p
);
2575 case EMR_SETDIBITSTODEVICE
:
2576 return set_di_bits_to_device(data
->ctx
, (const EMRSETDIBITSTODEVICE
*)rec
);
2577 case EMR_STRETCHDIBITS
:
2578 return stretch_di_bits(data
->ctx
, (const EMRSTRETCHDIBITS
*)rec
);
2579 case EMR_EXTTEXTOUTW
:
2581 const EMREXTTEXTOUTW
*p
= (const EMREXTTEXTOUTW
*)rec
;
2582 HDC hdc
= data
->ctx
->hdc
;
2583 const INT
*dx
= NULL
;
2587 rect
.left
= p
->emrtext
.rcl
.left
;
2588 rect
.top
= p
->emrtext
.rcl
.top
;
2589 rect
.right
= p
->emrtext
.rcl
.right
;
2590 rect
.bottom
= p
->emrtext
.rcl
.bottom
;
2592 old_mode
= SetGraphicsMode(hdc
, p
->iGraphicsMode
);
2593 /* Reselect the font back into the dc so that the transformation
2595 SelectObject(hdc
, GetCurrentObject(hdc
, OBJ_FONT
));
2597 if (p
->emrtext
.offDx
)
2598 dx
= (const INT
*)((const BYTE
*)rec
+ p
->emrtext
.offDx
);
2600 ret
= ext_text_out(data
, htable
, handle_count
, p
->emrtext
.ptlReference
.x
,
2601 p
->emrtext
.ptlReference
.y
, p
->emrtext
.fOptions
, &rect
,
2602 (LPCWSTR
)((const BYTE
*)rec
+ p
->emrtext
.offString
), p
->emrtext
.nChars
, dx
);
2604 SetGraphicsMode(hdc
, old_mode
);
2607 case EMR_POLYBEZIER16
:
2609 const EMRPOLYBEZIER16
*p
= (const EMRPOLYBEZIER16
*)rec
;
2613 pts
= malloc(sizeof(*pts
) * p
->cpts
);
2615 for (i
= 0; i
< p
->cpts
; i
++)
2617 pts
[i
].x
= p
->apts
[i
].x
;
2618 pts
[i
].y
= p
->apts
[i
].y
;
2620 i
= PSDRV_PolyBezier(data
->ctx
, pts
, p
->cpts
);
2626 const EMRPOLYGON16
*p
= (const EMRPOLYGON16
*)rec
;
2630 pts
= malloc(sizeof(*pts
) * p
->cpts
);
2632 for (i
= 0; i
< p
->cpts
; i
++)
2634 pts
[i
].x
= p
->apts
[i
].x
;
2635 pts
[i
].y
= p
->apts
[i
].y
;
2637 i
= PSDRV_PolyPolygon(data
->ctx
, pts
, (const INT
*)&p
->cpts
, 1);
2641 case EMR_POLYLINE16
:
2643 const EMRPOLYLINE16
*p
= (const EMRPOLYLINE16
*)rec
;
2647 pts
= malloc(sizeof(*pts
) * p
->cpts
);
2649 for (i
= 0; i
< p
->cpts
; i
++)
2651 pts
[i
].x
= p
->apts
[i
].x
;
2652 pts
[i
].y
= p
->apts
[i
].y
;
2654 i
= PSDRV_PolyPolyline(data
->ctx
, pts
, &p
->cpts
, 1);
2658 case EMR_POLYBEZIERTO16
:
2660 const EMRPOLYBEZIERTO16
*p
= (const EMRPOLYBEZIERTO16
*)rec
;
2664 pts
= malloc(sizeof(*pts
) * p
->cpts
);
2666 for (i
= 0; i
< p
->cpts
; i
++)
2668 pts
[i
].x
= p
->apts
[i
].x
;
2669 pts
[i
].y
= p
->apts
[i
].y
;
2671 i
= PSDRV_PolyBezierTo(data
->ctx
, pts
, p
->cpts
) &&
2672 MoveToEx(data
->ctx
->hdc
, pts
[p
->cpts
- 1].x
, pts
[p
->cpts
- 1].y
, NULL
);
2676 case EMR_POLYLINETO16
:
2678 const EMRPOLYLINETO16
*p
= (const EMRPOLYLINETO16
*)rec
;
2684 pts
= malloc(sizeof(*pts
) * cnt
);
2686 GetCurrentPositionEx(data
->ctx
->hdc
, pts
);
2687 for (i
= 0; i
< p
->cpts
; i
++)
2689 pts
[i
+ 1].x
= p
->apts
[i
].x
;
2690 pts
[i
+ 1].y
= p
->apts
[i
].y
;
2692 i
= PSDRV_PolyPolyline(data
->ctx
, pts
, &cnt
, 1) &&
2693 MoveToEx(data
->ctx
->hdc
, pts
[cnt
- 1].x
, pts
[cnt
- 1].y
, NULL
);
2697 case EMR_POLYPOLYLINE16
:
2699 const EMRPOLYPOLYLINE16
*p
= (const EMRPOLYPOLYLINE16
*)rec
;
2703 pts
= malloc(sizeof(*pts
) * p
->cpts
);
2705 for (i
= 0; i
< p
->cpts
; i
++)
2707 pts
[i
].x
= ((const POINTS
*)(p
->aPolyCounts
+ p
->nPolys
))[i
].x
;
2708 pts
[i
].y
= ((const POINTS
*)(p
->aPolyCounts
+ p
->nPolys
))[i
].y
;
2710 i
= PSDRV_PolyPolyline(data
->ctx
, pts
, p
->aPolyCounts
, p
->nPolys
);
2714 case EMR_POLYPOLYGON16
:
2716 const EMRPOLYPOLYGON16
*p
= (const EMRPOLYPOLYGON16
*)rec
;
2720 pts
= malloc(sizeof(*pts
) * p
->cpts
);
2722 for (i
= 0; i
< p
->cpts
; i
++)
2724 pts
[i
].x
= ((const POINTS
*)(p
->aPolyCounts
+ p
->nPolys
))[i
].x
;
2725 pts
[i
].y
= ((const POINTS
*)(p
->aPolyCounts
+ p
->nPolys
))[i
].y
;
2727 i
= PSDRV_PolyPolygon(data
->ctx
, pts
, (const INT
*)p
->aPolyCounts
, p
->nPolys
);
2731 case EMR_POLYDRAW16
:
2733 const EMRPOLYDRAW16
*p
= (const EMRPOLYDRAW16
*)rec
;
2737 pts
= malloc(sizeof(*pts
) * p
->cpts
);
2739 for (i
= 0; i
< p
->cpts
; i
++)
2741 pts
[i
].x
= p
->apts
[i
].x
;
2742 pts
[i
].y
= p
->apts
[i
].y
;
2744 i
= poly_draw(data
->ctx
, pts
, (BYTE
*)(p
->apts
+ p
->cpts
), p
->cpts
) &&
2745 MoveToEx(data
->ctx
->hdc
, pts
[p
->cpts
- 1].x
, pts
[p
->cpts
- 1].y
, NULL
);
2749 case EMR_CREATEMONOBRUSH
:
2751 const EMRCREATEMONOBRUSH
*p
= (const EMRCREATEMONOBRUSH
*)rec
;
2753 if (!PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
))
2755 data
->patterns
[p
->ihBrush
].usage
= p
->iUsage
;
2756 data
->patterns
[p
->ihBrush
].info
= (BITMAPINFO
*)((BYTE
*)p
+ p
->offBmi
);
2757 data
->patterns
[p
->ihBrush
].bits
.ptr
= (BYTE
*)p
+ p
->offBits
;
2760 case EMR_CREATEDIBPATTERNBRUSHPT
:
2762 const EMRCREATEDIBPATTERNBRUSHPT
*p
= (const EMRCREATEDIBPATTERNBRUSHPT
*)rec
;
2764 if (!PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
))
2766 data
->patterns
[p
->ihBrush
].usage
= p
->iUsage
;
2767 data
->patterns
[p
->ihBrush
].info
= (BITMAPINFO
*)((BYTE
*)p
+ p
->offBmi
);
2768 data
->patterns
[p
->ihBrush
].bits
.ptr
= (BYTE
*)p
+ p
->offBits
;
2773 const struct EMREXTESCAPE
2779 } *p
= (const struct EMREXTESCAPE
*)rec
;
2781 PSDRV_ExtEscape(data
->ctx
, p
->escape
, p
->size
, p
->data
, 0, NULL
);
2784 case EMR_GRADIENTFILL
:
2786 const EMRGRADIENTFILL
*p
= (const EMRGRADIENTFILL
*)rec
;
2788 return gradient_fill(data
->ctx
, p
->Ver
, p
->nVer
,
2789 p
->Ver
+ p
->nVer
, p
->nTri
, p
->ulMode
);
2791 case EMR_SETTEXTJUSTIFICATION
:
2793 const EMRSETTEXTJUSTIFICATION
*p
= (const EMRSETTEXTJUSTIFICATION
*)rec
;
2795 data
->break_extra
= p
->break_extra
/ p
->break_count
;
2796 data
->break_rem
= p
->break_extra
- data
->break_extra
* p
->break_count
;
2797 return PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
);
2800 case EMR_EXTFLOODFILL
:
2801 case EMR_ALPHABLEND
:
2804 case EMR_SETWINDOWEXTEX
:
2805 case EMR_SETWINDOWORGEX
:
2806 case EMR_SETVIEWPORTEXTEX
:
2807 case EMR_SETVIEWPORTORGEX
:
2808 case EMR_SETBRUSHORGEX
:
2809 case EMR_SETMAPPERFLAGS
:
2810 case EMR_SETMAPMODE
:
2812 case EMR_SETPOLYFILLMODE
:
2814 case EMR_SETSTRETCHBLTMODE
:
2815 case EMR_SETTEXTALIGN
:
2816 case EMR_OFFSETCLIPRGN
:
2818 case EMR_EXCLUDECLIPRECT
:
2819 case EMR_INTERSECTCLIPRECT
:
2820 case EMR_SCALEVIEWPORTEXTEX
:
2821 case EMR_SCALEWINDOWEXTEX
:
2822 case EMR_SETWORLDTRANSFORM
:
2823 case EMR_MODIFYWORLDTRANSFORM
:
2825 case EMR_CREATEBRUSHINDIRECT
:
2826 case EMR_SELECTPALETTE
:
2827 case EMR_CREATEPALETTE
:
2828 case EMR_SETPALETTEENTRIES
:
2829 case EMR_RESIZEPALETTE
:
2830 case EMR_REALIZEPALETTE
:
2831 case EMR_SETARCDIRECTION
:
2832 case EMR_CLOSEFIGURE
:
2833 case EMR_FLATTENPATH
:
2835 case EMR_SELECTCLIPPATH
:
2836 case EMR_EXTSELECTCLIPRGN
:
2837 case EMR_EXTCREATEFONTINDIRECTW
:
2839 return PlayEnhMetaFileRecord(data
->ctx
->hdc
, htable
, rec
, handle_count
);
2841 FIXME("unsupported record: %ld\n", rec
->iType
);
2847 static BOOL
print_metafile(struct pp_data
*data
, HANDLE hdata
)
2849 XFORM xform
= { .eM11
= 1, .eM22
= 1 };
2856 if (!ReadPrinter(hdata
, &header
, sizeof(header
), &r
))
2858 if (r
!= sizeof(header
))
2860 SetLastError(ERROR_INVALID_DATA
);
2864 buf
= malloc(header
.cjSize
);
2868 if (!ReadPrinter(hdata
, buf
, header
.cjSize
, &r
))
2873 if (r
!= header
.cjSize
)
2876 SetLastError(ERROR_INVALID_DATA
);
2880 hmf
= SetEnhMetaFileBits(header
.cjSize
, buf
);
2885 AbortPath(data
->ctx
->hdc
);
2886 MoveToEx(data
->ctx
->hdc
, 0, 0, NULL
);
2887 SetBkColor(data
->ctx
->hdc
, RGB(255, 255, 255));
2888 SetBkMode(data
->ctx
->hdc
, OPAQUE
);
2889 SetMapMode(data
->ctx
->hdc
, MM_TEXT
);
2890 SetPolyFillMode(data
->ctx
->hdc
, ALTERNATE
);
2891 SetROP2(data
->ctx
->hdc
, R2_COPYPEN
);
2892 SetStretchBltMode(data
->ctx
->hdc
, BLACKONWHITE
);
2893 SetTextAlign(data
->ctx
->hdc
, TA_LEFT
| TA_TOP
);
2894 SetTextColor(data
->ctx
->hdc
, 0);
2895 SetTextJustification(data
->ctx
->hdc
, 0, 0);
2896 SetWorldTransform(data
->ctx
->hdc
, &xform
);
2897 PSDRV_SetTextColor(data
->ctx
, 0);
2898 PSDRV_SetBkColor(data
->ctx
, RGB(255, 255, 255));
2900 ret
= EnumEnhMetaFile(NULL
, hmf
, hmf_proc
, (void *)data
, NULL
);
2901 DeleteEnhMetaFile(hmf
);
2902 free(data
->patterns
);
2903 data
->patterns
= NULL
;
2905 data
->break_extra
= 0;
2906 data
->break_rem
= 0;
2907 data
->saved_dc_top
= 0;
2911 BOOL WINAPI
EnumPrintProcessorDatatypesW(WCHAR
*server
, WCHAR
*name
, DWORD level
,
2912 BYTE
*datatypes
, DWORD size
, DWORD
*needed
, DWORD
*no
)
2914 DATATYPES_INFO_1W
*info
= (DATATYPES_INFO_1W
*)datatypes
;
2916 TRACE("%s, %s, %ld, %p, %ld, %p, %p\n", debugstr_w(server
), debugstr_w(name
),
2917 level
, datatypes
, size
, needed
, no
);
2921 SetLastError(ERROR_INVALID_PARAMETER
);
2926 *needed
= sizeof(*info
) + sizeof(emf_1003
);
2928 if (level
!= 1 || (size
&& !datatypes
))
2930 SetLastError(ERROR_INVALID_PARAMETER
);
2936 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2941 info
->pName
= (WCHAR
*)(info
+ 1);
2942 memcpy(info
+ 1, emf_1003
, sizeof(emf_1003
));
2946 HANDLE WINAPI
OpenPrintProcessor(WCHAR
*port
, PRINTPROCESSOROPENDATA
*open_data
)
2948 struct pp_data
*data
;
2952 TRACE("%s, %p\n", debugstr_w(port
), open_data
);
2954 if (!port
|| !open_data
|| !open_data
->pDatatype
)
2956 SetLastError(ERROR_INVALID_PARAMETER
);
2959 if (wcscmp(open_data
->pDatatype
, emf_1003
))
2961 SetLastError(ERROR_INVALID_DATATYPE
);
2965 if (!OpenPrinterW(port
, &hport
, NULL
))
2968 data
= LocalAlloc(LMEM_FIXED
| LMEM_ZEROINIT
, sizeof(*data
));
2971 data
->magic
= PP_MAGIC
;
2972 data
->hport
= hport
;
2973 data
->doc_name
= wcsdup(open_data
->pDocumentName
);
2974 data
->out_file
= wcsdup(open_data
->pOutputFile
);
2976 hdc
= CreateDCW(L
"winspool", open_data
->pPrinterName
, NULL
, open_data
->pDevMode
);
2982 SetGraphicsMode(hdc
, GM_ADVANCED
);
2983 data
->ctx
= create_print_ctx(hdc
, open_data
->pPrinterName
, open_data
->pDevMode
);
2990 return (HANDLE
)data
;
2993 BOOL WINAPI
PrintDocumentOnPrintProcessor(HANDLE pp
, WCHAR
*doc_name
)
2995 struct pp_data
*data
= get_handle_data(pp
);
2996 emfspool_header header
;
2997 LARGE_INTEGER pos
, cur
;
3004 TRACE("%p, %s\n", pp
, debugstr_w(doc_name
));
3009 if (!OpenPrinterW(doc_name
, &spool_data
, NULL
))
3012 info
.pDocName
= data
->doc_name
;
3013 info
.pOutputFile
= data
->out_file
;
3014 info
.pDatatype
= (WCHAR
*)L
"RAW";
3015 data
->ctx
->job
.id
= StartDocPrinterW(data
->hport
, 1, (BYTE
*)&info
);
3016 if (!data
->ctx
->job
.id
)
3018 ClosePrinter(spool_data
);
3022 if (!(ret
= ReadPrinter(spool_data
, &header
, sizeof(header
), &r
)))
3024 if (r
!= sizeof(header
))
3026 SetLastError(ERROR_INVALID_DATA
);
3031 if (header
.dwVersion
!= EMFSPOOL_VERSION
)
3033 FIXME("unrecognized spool file format\n");
3034 SetLastError(ERROR_INTERNAL_ERROR
);
3037 pos
.QuadPart
= header
.cjSize
;
3038 if (!(ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_BEGIN
, FALSE
)))
3041 data
->ctx
->job
.hprinter
= data
->hport
;
3042 if (!PSDRV_WriteHeader(data
->ctx
, data
->doc_name
))
3044 WARN("Failed to write header\n");
3047 data
->ctx
->job
.OutOfPage
= TRUE
;
3048 data
->ctx
->job
.PageNo
= 0;
3049 data
->ctx
->job
.quiet
= FALSE
;
3050 data
->ctx
->job
.passthrough_state
= passthrough_none
;
3051 data
->ctx
->job
.doc_name
= strdupW(data
->doc_name
);
3055 if (!(ret
= ReadPrinter(spool_data
, &record
, sizeof(record
), &r
)))
3059 if (r
!= sizeof(record
))
3061 SetLastError(ERROR_INVALID_DATA
);
3066 switch (record
.ulID
)
3070 DEVMODEW
*devmode
= NULL
;
3074 devmode
= malloc(record
.cjSize
);
3077 ret
= ReadPrinter(spool_data
, devmode
, record
.cjSize
, &r
);
3078 if (ret
&& r
!= record
.cjSize
)
3080 SetLastError(ERROR_INVALID_DATA
);
3086 ret
= PSDRV_ResetDC(data
->ctx
, devmode
);
3092 case EMRI_METAFILE_DATA
:
3093 pos
.QuadPart
= record
.cjSize
;
3094 ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_CURRENT
, FALSE
);
3098 case EMRI_METAFILE_EXT
:
3099 case EMRI_BW_METAFILE_EXT
:
3101 ret
= SeekPrinter(spool_data
, pos
, &cur
, FILE_CURRENT
, FALSE
);
3104 cur
.QuadPart
+= record
.cjSize
;
3105 ret
= ReadPrinter(spool_data
, &pos
, sizeof(pos
), &r
);
3106 if (ret
&& r
!= sizeof(pos
))
3108 SetLastError(ERROR_INVALID_DATA
);
3112 pos
.QuadPart
= -pos
.QuadPart
- 2 * sizeof(record
);
3114 ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_CURRENT
, FALSE
);
3116 ret
= print_metafile(data
, spool_data
);
3118 ret
= SeekPrinter(spool_data
, cur
, NULL
, FILE_BEGIN
, FALSE
);
3123 FIXME("%s not supported, skipping\n", debugstr_rec_type(record
.ulID
));
3124 pos
.QuadPart
= record
.cjSize
;
3125 ret
= SeekPrinter(spool_data
, pos
, NULL
, FILE_CURRENT
, FALSE
);
3133 if (data
->ctx
->job
.PageNo
)
3134 PSDRV_WriteFooter(data
->ctx
);
3136 HeapFree(GetProcessHeap(), 0, data
->ctx
->job
.doc_name
);
3137 ClosePrinter(spool_data
);
3138 return EndDocPrinter(data
->hport
) && ret
;
3141 BOOL WINAPI
ControlPrintProcessor(HANDLE pp
, DWORD cmd
)
3143 FIXME("%p, %ld\n", pp
, cmd
);
3144 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3148 BOOL WINAPI
ClosePrintProcessor(HANDLE pp
)
3150 struct pp_data
*data
= get_handle_data(pp
);
3157 ClosePrinter(data
->hport
);
3158 free(data
->doc_name
);
3159 free(data
->out_file
);
3160 DeleteDC(data
->ctx
->hdc
);
3161 HeapFree(GetProcessHeap(), 0, data
->ctx
->Devmode
);
3162 HeapFree(GetProcessHeap(), 0, data
->ctx
);
3163 free(data
->saved_dc
);
3165 memset(data
, 0, sizeof(*data
));
3170 HRESULT WINAPI
DllRegisterServer(void)
3172 AddPrintProcessorW(NULL
, (WCHAR
*)L
"Windows 4.0", (WCHAR
*)L
"wineps.drv", (WCHAR
*)L
"wineps");
3173 AddPrintProcessorW(NULL
, NULL
, (WCHAR
*)L
"wineps.drv", (WCHAR
*)L
"wineps");