2 * Unix interface for wineps.drv
4 * Copyright 1998 Huw D M Davies
5 * Copyright 2001 Marcus Meissner
6 * Copyright 2023 Piotr Caban for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
37 #include "ddk/winddi.h"
38 #include "wine/gdi_driver.h"
39 #include "wine/debug.h"
40 #include "wine/wingdi16.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(psdrv
);
44 static const WCHAR timesW
[] = {'T','i','m','e','s',0};
45 static const WCHAR helveticaW
[] = {'H','e','l','v','e','t','i','c','a',0};
46 static const WCHAR courierW
[] = {'C','o','u','r','i','e','r',0};
47 static const WCHAR symbolW
[] = {'S','y','m','b','o','l',0};
48 static const WCHAR arialW
[] = {'A','r','i','a','l',0};
49 static const WCHAR systemW
[] = {'S','y','s','t','e','m',0};
50 static const WCHAR times_new_romanW
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
51 static const WCHAR courier_newW
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
53 static const struct gdi_dc_funcs psdrv_funcs
;
68 struct glyph_info
*glyphs
;
69 struct glyph_info def_glyph
;
72 static struct list fonts
= LIST_INIT(fonts
);
78 const PSDRV_DEVMODE
*devmode
;
81 static struct list printer_info_list
= LIST_INIT(printer_info_list
);
92 struct gdi_physdev dev
;
93 PSDRV_DEVMODE
*devmode
;
94 const struct printer_info
*pi
;
96 /* builtin font info */
99 const struct font_data
*font
;
104 SIZE page_size
; /* Physical page size in device units */
105 RECT imageable_area
; /* Imageable area in device units */
106 int horz_res
; /* device caps */
114 static inline PSDRV_PDEVICE
*get_psdrv_dev(PHYSDEV dev
)
116 return (PSDRV_PDEVICE
*)dev
;
119 /* copied from kernelbase */
120 static int muldiv(int a
, int b
, int c
)
126 /* We want to deal with a positive divisor to simplify the logic. */
133 /* If the result is positive, we "add" to round. else, we subtract to round. */
134 if ((a
< 0 && b
< 0) || (a
>= 0 && b
>= 0))
135 ret
= (((LONGLONG
)a
* b
) + (c
/ 2)) / c
;
137 ret
= (((LONGLONG
)a
* b
) - (c
/ 2)) / c
;
139 if (ret
> 2147483647 || ret
< -2147483647) return -1;
143 static void dump_fields(int fields
)
147 #define CHECK_FIELD(flag) \
152 if (add_space++) TRACE(" "); \
159 CHECK_FIELD(DM_ORIENTATION
);
160 CHECK_FIELD(DM_PAPERSIZE
);
161 CHECK_FIELD(DM_PAPERLENGTH
);
162 CHECK_FIELD(DM_PAPERWIDTH
);
163 CHECK_FIELD(DM_SCALE
);
164 CHECK_FIELD(DM_POSITION
);
166 CHECK_FIELD(DM_DISPLAYORIENTATION
);
167 CHECK_FIELD(DM_COPIES
);
168 CHECK_FIELD(DM_DEFAULTSOURCE
);
169 CHECK_FIELD(DM_PRINTQUALITY
);
170 CHECK_FIELD(DM_COLOR
);
171 CHECK_FIELD(DM_DUPLEX
);
172 CHECK_FIELD(DM_YRESOLUTION
);
173 CHECK_FIELD(DM_TTOPTION
);
174 CHECK_FIELD(DM_COLLATE
);
175 CHECK_FIELD(DM_FORMNAME
);
176 CHECK_FIELD(DM_LOGPIXELS
);
177 CHECK_FIELD(DM_BITSPERPEL
);
178 CHECK_FIELD(DM_PELSWIDTH
);
179 CHECK_FIELD(DM_PELSHEIGHT
);
180 CHECK_FIELD(DM_DISPLAYFLAGS
);
181 CHECK_FIELD(DM_DISPLAYFREQUENCY
);
182 CHECK_FIELD(DM_ICMMETHOD
);
183 CHECK_FIELD(DM_ICMINTENT
);
184 CHECK_FIELD(DM_MEDIATYPE
);
185 CHECK_FIELD(DM_DITHERTYPE
);
186 CHECK_FIELD(DM_PANNINGWIDTH
);
187 CHECK_FIELD(DM_PANNINGHEIGHT
);
188 if (fields
) TRACE(" %#x", fields
);
193 static void dump_devmode(const DEVMODEW
*dm
)
195 if (!TRACE_ON(psdrv
)) return;
197 TRACE("dmDeviceName: %s\n", debugstr_w(dm
->dmDeviceName
));
198 TRACE("dmSpecVersion: 0x%04x\n", dm
->dmSpecVersion
);
199 TRACE("dmDriverVersion: 0x%04x\n", dm
->dmDriverVersion
);
200 TRACE("dmSize: 0x%04x\n", dm
->dmSize
);
201 TRACE("dmDriverExtra: 0x%04x\n", dm
->dmDriverExtra
);
202 TRACE("dmFields: 0x%04x\n", (int)dm
->dmFields
);
203 dump_fields(dm
->dmFields
);
204 TRACE("dmOrientation: %d\n", dm
->dmOrientation
);
205 TRACE("dmPaperSize: %d\n", dm
->dmPaperSize
);
206 TRACE("dmPaperLength: %d\n", dm
->dmPaperLength
);
207 TRACE("dmPaperWidth: %d\n", dm
->dmPaperWidth
);
208 TRACE("dmScale: %d\n", dm
->dmScale
);
209 TRACE("dmCopies: %d\n", dm
->dmCopies
);
210 TRACE("dmDefaultSource: %d\n", dm
->dmDefaultSource
);
211 TRACE("dmPrintQuality: %d\n", dm
->dmPrintQuality
);
212 TRACE("dmColor: %d\n", dm
->dmColor
);
213 TRACE("dmDuplex: %d\n", dm
->dmDuplex
);
214 TRACE("dmYResolution: %d\n", dm
->dmYResolution
);
215 TRACE("dmTTOption: %d\n", dm
->dmTTOption
);
216 TRACE("dmCollate: %d\n", dm
->dmCollate
);
217 TRACE("dmFormName: %s\n", debugstr_w(dm
->dmFormName
));
218 TRACE("dmLogPixels %u\n", dm
->dmLogPixels
);
219 TRACE("dmBitsPerPel %u\n", (unsigned int)dm
->dmBitsPerPel
);
220 TRACE("dmPelsWidth %u\n", (unsigned int)dm
->dmPelsWidth
);
221 TRACE("dmPelsHeight %u\n", (unsigned int)dm
->dmPelsHeight
);
224 static INT CDECL
get_device_caps(PHYSDEV dev
, INT cap
)
226 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
228 TRACE("%p,%d\n", dev
->hdc
, cap
);
235 return DT_RASPRINTER
;
237 return muldiv(pdev
->horz_size
, 100, pdev
->devmode
->dmPublic
.dmScale
);
239 return muldiv(pdev
->vert_size
, 100, pdev
->devmode
->dmPublic
.dmScale
);
241 return pdev
->horz_res
;
243 return pdev
->vert_res
;
245 /* Although Windows returns 1 for monochrome printers, we want
246 CreateCompatibleBitmap to provide something other than 1 bpp */
255 return sizeof(PSDRV_PDEVICE
);
257 return TC_CR_ANY
| TC_VA_ABLE
; /* psdrv 0x59f7 */
259 return (RC_BITBLT
| RC_BITMAP64
| RC_GDI20_OUTPUT
| RC_DIBTODEV
|
260 RC_STRETCHBLT
| RC_STRETCHDIB
); /* psdrv 0x6e99 */
262 return pdev
->log_pixels_x
;
264 return pdev
->log_pixels_y
;
266 return muldiv(pdev
->log_pixels_x
, pdev
->devmode
->dmPublic
.dmScale
, 100);
268 return muldiv(pdev
->log_pixels_y
, pdev
->devmode
->dmPublic
.dmScale
, 100);
274 return (pdev
->devmode
->dmPublic
.dmOrientation
== DMORIENT_LANDSCAPE
) ?
275 pdev
->page_size
.cy
: pdev
->page_size
.cx
;
277 return (pdev
->devmode
->dmPublic
.dmOrientation
== DMORIENT_LANDSCAPE
) ?
278 pdev
->page_size
.cx
: pdev
->page_size
.cy
;
279 case PHYSICALOFFSETX
:
280 if (pdev
->devmode
->dmPublic
.dmOrientation
== DMORIENT_LANDSCAPE
)
282 if (pdev
->devmode
->landscape_orientation
== -90)
283 return pdev
->page_size
.cy
- pdev
->imageable_area
.top
;
285 return pdev
->imageable_area
.bottom
;
287 return pdev
->imageable_area
.left
;
289 case PHYSICALOFFSETY
:
290 if (pdev
->devmode
->dmPublic
.dmOrientation
== DMORIENT_LANDSCAPE
)
292 if (pdev
->devmode
->landscape_orientation
== -90)
293 return pdev
->page_size
.cx
- pdev
->imageable_area
.right
;
295 return pdev
->imageable_area
.left
;
297 return pdev
->page_size
.cy
- pdev
->imageable_area
.top
;
300 dev
= GET_NEXT_PHYSDEV(dev
, pGetDeviceCaps
);
301 return dev
->funcs
->pGetDeviceCaps(dev
, cap
);
305 static inline int paper_size_from_points(float size
)
307 return size
* 254 / 72;
310 static const struct input_slot
*find_slot(const struct printer_info
*pi
,
313 const struct input_slot
*slot
= (const struct input_slot
*)pi
->devmode
->data
;
316 for (i
= 0; i
< pi
->devmode
->input_slots
; i
++)
318 if (slot
[i
].win_bin
== dm
->dmDefaultSource
)
324 static const struct page_size
*find_pagesize(const struct printer_info
*pi
,
327 const struct page_size
*page
;
330 page
= (const struct page_size
*)(pi
->devmode
->data
+
331 pi
->devmode
->input_slots
* sizeof(struct input_slot
) +
332 pi
->devmode
->resolutions
* sizeof(struct resolution
));
333 for (i
= 0; i
< pi
->devmode
->page_sizes
; i
++)
335 if (page
[i
].win_page
== dm
->dmPaperSize
)
341 static void merge_devmodes(PSDRV_DEVMODE
*dm1
, const DEVMODEW
*dm2
,
342 const struct printer_info
*pi
)
344 /* some sanity checks here on dm2 */
346 if (dm2
->dmFields
& DM_ORIENTATION
)
348 dm1
->dmPublic
.dmOrientation
= dm2
->dmOrientation
;
349 TRACE("Changing orientation to %d (%s)\n",
350 dm1
->dmPublic
.dmOrientation
,
351 dm1
->dmPublic
.dmOrientation
== DMORIENT_PORTRAIT
?
353 (dm1
->dmPublic
.dmOrientation
== DMORIENT_LANDSCAPE
?
354 "Landscape" : "unknown"));
357 /* NB PaperWidth is always < PaperLength */
358 if (dm2
->dmFields
& DM_PAPERSIZE
)
360 const struct page_size
*page
= find_pagesize(pi
, dm2
);
364 dm1
->dmPublic
.dmPaperSize
= dm2
->dmPaperSize
;
365 dm1
->dmPublic
.dmPaperWidth
= paper_size_from_points(page
->paper_dimension
.x
);
366 dm1
->dmPublic
.dmPaperLength
= paper_size_from_points(page
->paper_dimension
.y
);
367 dm1
->dmPublic
.dmFields
|= DM_PAPERSIZE
| DM_PAPERWIDTH
| DM_PAPERLENGTH
;
368 TRACE("Changing page to %s %d x %d\n", debugstr_w(page
->name
),
369 dm1
->dmPublic
.dmPaperWidth
,
370 dm1
->dmPublic
.dmPaperLength
);
372 if (dm1
->dmPublic
.dmSize
>= FIELD_OFFSET(DEVMODEW
, dmFormName
) + CCHFORMNAME
* sizeof(WCHAR
))
374 memcpy(dm1
->dmPublic
.dmFormName
, page
->name
, sizeof(page
->name
));
375 dm1
->dmPublic
.dmFields
|= DM_FORMNAME
;
379 TRACE("Trying to change to unsupported pagesize %d\n", dm2
->dmPaperSize
);
382 else if ((dm2
->dmFields
& DM_PAPERLENGTH
) &&
383 (dm2
->dmFields
& DM_PAPERWIDTH
))
385 dm1
->dmPublic
.dmPaperLength
= dm2
->dmPaperLength
;
386 dm1
->dmPublic
.dmPaperWidth
= dm2
->dmPaperWidth
;
387 TRACE("Changing PaperLength|Width to %dx%d\n",
390 dm1
->dmPublic
.dmFields
&= ~DM_PAPERSIZE
;
391 dm1
->dmPublic
.dmFields
|= (DM_PAPERLENGTH
| DM_PAPERWIDTH
);
393 else if (dm2
->dmFields
& (DM_PAPERLENGTH
| DM_PAPERWIDTH
))
395 /* You might think that this would be allowed if dm1 is in custom size
396 mode, but apparently Windows reverts to standard paper mode even in
398 FIXME("Trying to change only paperlength or paperwidth\n");
399 dm1
->dmPublic
.dmFields
&= ~(DM_PAPERLENGTH
| DM_PAPERWIDTH
);
400 dm1
->dmPublic
.dmFields
|= DM_PAPERSIZE
;
403 if (dm2
->dmFields
& DM_SCALE
)
405 dm1
->dmPublic
.dmScale
= dm2
->dmScale
;
406 TRACE("Changing Scale to %d\n", dm2
->dmScale
);
409 if (dm2
->dmFields
& DM_COPIES
)
411 dm1
->dmPublic
.dmCopies
= dm2
->dmCopies
;
412 TRACE("Changing Copies to %d\n", dm2
->dmCopies
);
415 if (dm2
->dmFields
& DM_DEFAULTSOURCE
)
417 const struct input_slot
*slot
= find_slot(pi
, dm2
);
420 dm1
->dmPublic
.dmDefaultSource
= dm2
->dmDefaultSource
;
422 TRACE("Trying to change to unsupported bin %d\n", dm2
->dmDefaultSource
);
425 if (dm2
->dmFields
& DM_DEFAULTSOURCE
)
426 dm1
->dmPublic
.dmDefaultSource
= dm2
->dmDefaultSource
;
427 if (dm2
->dmFields
& DM_PRINTQUALITY
)
428 dm1
->dmPublic
.dmPrintQuality
= dm2
->dmPrintQuality
;
429 if (dm2
->dmFields
& DM_COLOR
)
430 dm1
->dmPublic
.dmColor
= dm2
->dmColor
;
431 if (dm2
->dmFields
& DM_DUPLEX
&& pi
->devmode
->duplex
)
432 dm1
->dmPublic
.dmDuplex
= dm2
->dmDuplex
;
433 if (dm2
->dmFields
& DM_YRESOLUTION
)
434 dm1
->dmPublic
.dmYResolution
= dm2
->dmYResolution
;
435 if (dm2
->dmFields
& DM_TTOPTION
)
436 dm1
->dmPublic
.dmTTOption
= dm2
->dmTTOption
;
437 if (dm2
->dmFields
& DM_COLLATE
)
438 dm1
->dmPublic
.dmCollate
= dm2
->dmCollate
;
439 if (dm2
->dmFields
& DM_FORMNAME
)
440 lstrcpynW(dm1
->dmPublic
.dmFormName
, dm2
->dmFormName
, CCHFORMNAME
);
441 if (dm2
->dmFields
& DM_BITSPERPEL
)
442 dm1
->dmPublic
.dmBitsPerPel
= dm2
->dmBitsPerPel
;
443 if (dm2
->dmFields
& DM_PELSWIDTH
)
444 dm1
->dmPublic
.dmPelsWidth
= dm2
->dmPelsWidth
;
445 if (dm2
->dmFields
& DM_PELSHEIGHT
)
446 dm1
->dmPublic
.dmPelsHeight
= dm2
->dmPelsHeight
;
447 if (dm2
->dmFields
& DM_DISPLAYFLAGS
)
448 dm1
->dmPublic
.dmDisplayFlags
= dm2
->dmDisplayFlags
;
449 if (dm2
->dmFields
& DM_DISPLAYFREQUENCY
)
450 dm1
->dmPublic
.dmDisplayFrequency
= dm2
->dmDisplayFrequency
;
451 if (dm2
->dmFields
& DM_POSITION
)
452 dm1
->dmPublic
.dmPosition
= dm2
->dmPosition
;
453 if (dm2
->dmFields
& DM_LOGPIXELS
)
454 dm1
->dmPublic
.dmLogPixels
= dm2
->dmLogPixels
;
455 if (dm2
->dmFields
& DM_ICMMETHOD
)
456 dm1
->dmPublic
.dmICMMethod
= dm2
->dmICMMethod
;
457 if (dm2
->dmFields
& DM_ICMINTENT
)
458 dm1
->dmPublic
.dmICMIntent
= dm2
->dmICMIntent
;
459 if (dm2
->dmFields
& DM_MEDIATYPE
)
460 dm1
->dmPublic
.dmMediaType
= dm2
->dmMediaType
;
461 if (dm2
->dmFields
& DM_DITHERTYPE
)
462 dm1
->dmPublic
.dmDitherType
= dm2
->dmDitherType
;
463 if (dm2
->dmFields
& DM_PANNINGWIDTH
)
464 dm1
->dmPublic
.dmPanningWidth
= dm2
->dmPanningWidth
;
465 if (dm2
->dmFields
& DM_PANNINGHEIGHT
)
466 dm1
->dmPublic
.dmPanningHeight
= dm2
->dmPanningHeight
;
469 static void update_dev_caps(PSDRV_PDEVICE
*pdev
)
471 INT width
= 0, height
= 0, resx
= 0, resy
= 0;
472 const struct resolution
*res
;
473 const struct page_size
*page
;
476 dump_devmode(&pdev
->devmode
->dmPublic
);
478 if (pdev
->devmode
->dmPublic
.dmFields
& (DM_PRINTQUALITY
| DM_YRESOLUTION
| DM_LOGPIXELS
))
480 if (pdev
->devmode
->dmPublic
.dmFields
& DM_PRINTQUALITY
)
481 resx
= resy
= pdev
->devmode
->dmPublic
.dmPrintQuality
;
483 if (pdev
->devmode
->dmPublic
.dmFields
& DM_YRESOLUTION
)
484 resy
= pdev
->devmode
->dmPublic
.dmYResolution
;
486 if (pdev
->devmode
->dmPublic
.dmFields
& DM_LOGPIXELS
)
487 resx
= resy
= pdev
->devmode
->dmPublic
.dmLogPixels
;
489 res
= (const struct resolution
*)(pdev
->devmode
->data
490 + pdev
->devmode
->input_slots
* sizeof(struct input_slot
));
491 for (i
= 0; i
< pdev
->devmode
->resolutions
; i
++)
493 if (res
[i
].x
== resx
&& res
[i
].y
== resy
)
495 pdev
->log_pixels_x
= resx
;
496 pdev
->log_pixels_y
= resy
;
501 if (i
== pdev
->devmode
->resolutions
)
503 WARN("Requested resolution %dx%d is not supported by device\n", resx
, resy
);
504 pdev
->log_pixels_x
= pdev
->devmode
->default_resolution
;
505 pdev
->log_pixels_y
= pdev
->log_pixels_x
;
510 WARN("Using default device resolution %d\n", pdev
->devmode
->default_resolution
);
511 pdev
->log_pixels_x
= pdev
->devmode
->default_resolution
;
512 pdev
->log_pixels_y
= pdev
->log_pixels_x
;
515 if (pdev
->devmode
->dmPublic
.dmFields
& DM_PAPERSIZE
) {
516 page
= find_pagesize(pdev
->pi
, &pdev
->devmode
->dmPublic
);
520 FIXME("Can't find page\n");
521 SetRectEmpty(&pdev
->imageable_area
);
522 pdev
->page_size
.cx
= 0;
523 pdev
->page_size
.cy
= 0;
527 /* pdev sizes in device units; ppd sizes in 1/72" */
528 SetRect(&pdev
->imageable_area
,
529 page
->imageable_area
.left
* pdev
->log_pixels_x
/ 72,
530 page
->imageable_area
.top
* pdev
->log_pixels_y
/ 72,
531 page
->imageable_area
.right
* pdev
->log_pixels_x
/ 72,
532 page
->imageable_area
.bottom
* pdev
->log_pixels_y
/ 72);
533 pdev
->page_size
.cx
= page
->paper_dimension
.x
* pdev
->log_pixels_x
/ 72;
534 pdev
->page_size
.cy
= page
->paper_dimension
.y
* pdev
->log_pixels_y
/ 72;
536 } else if ((pdev
->devmode
->dmPublic
.dmFields
& DM_PAPERLENGTH
) &&
537 (pdev
->devmode
->dmPublic
.dmFields
& DM_PAPERWIDTH
)) {
538 /* pdev sizes in device units; devmode sizes in 1/10 mm */
539 pdev
->imageable_area
.left
= pdev
->imageable_area
.bottom
= 0;
540 pdev
->imageable_area
.right
= pdev
->page_size
.cx
=
541 pdev
->devmode
->dmPublic
.dmPaperWidth
* pdev
->log_pixels_x
/ 254;
542 pdev
->imageable_area
.top
= pdev
->page_size
.cy
=
543 pdev
->devmode
->dmPublic
.dmPaperLength
* pdev
->log_pixels_y
/ 254;
545 FIXME("Odd dmFields %x\n", (int)pdev
->devmode
->dmPublic
.dmFields
);
546 SetRectEmpty(&pdev
->imageable_area
);
547 pdev
->page_size
.cx
= 0;
548 pdev
->page_size
.cy
= 0;
551 TRACE("imageable_area = %s: page_size = %dx%d\n", wine_dbgstr_rect(&pdev
->imageable_area
),
552 (int)pdev
->page_size
.cx
, (int)pdev
->page_size
.cy
);
554 /* these are in device units */
555 width
= pdev
->imageable_area
.right
- pdev
->imageable_area
.left
;
556 height
= pdev
->imageable_area
.top
- pdev
->imageable_area
.bottom
;
558 if (pdev
->devmode
->dmPublic
.dmOrientation
== DMORIENT_PORTRAIT
) {
559 pdev
->horz_res
= width
;
560 pdev
->vert_res
= height
;
562 pdev
->horz_res
= height
;
563 pdev
->vert_res
= width
;
566 /* these are in mm */
567 pdev
->horz_size
= (pdev
->horz_res
* 25.4) / pdev
->log_pixels_x
;
568 pdev
->vert_size
= (pdev
->vert_res
* 25.4) / pdev
->log_pixels_y
;
570 TRACE("devcaps: horz_size = %dmm, vert_size = %dmm, "
571 "horz_res = %d, vert_res = %d\n",
572 pdev
->horz_size
, pdev
->vert_size
,
573 pdev
->horz_res
, pdev
->vert_res
);
576 static BOOL CDECL
reset_dc(PHYSDEV dev
, const DEVMODEW
*devmode
)
578 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
582 merge_devmodes(pdev
->devmode
, devmode
, pdev
->pi
);
583 update_dev_caps(pdev
);
588 static int cmp_glyph_info(const void *a
, const void *b
)
590 return (int)((const struct glyph_info
*)a
)->wch
-
591 (int)((const struct glyph_info
*)b
)->wch
;
594 const struct glyph_info
*uv_metrics(WCHAR wch
, const struct font_data
*font
)
596 const struct glyph_info
*needle
;
597 struct glyph_info key
;
600 * Ugly work-around for symbol fonts. Wine is sending characters which
601 * belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII
602 * characters (U+0020 - U+00FF).
604 if ((font
->glyphs
->wch
& 0xff00) == 0xf000 && wch
< 0x100)
608 needle
= bsearch(&key
, font
->glyphs
, font
->glyph_count
, sizeof(*font
->glyphs
), cmp_glyph_info
);
611 WARN("No glyph for U+%.4X in '%s'\n", wch
, font
->name
);
612 needle
= font
->glyphs
;
617 static int CDECL
ext_escape(PHYSDEV dev
, int escape
, int input_size
, const void *input
,
618 int output_size
, void *output
)
620 TRACE("%p,%d,%d,%p,%d,%p\n",
621 dev
->hdc
, escape
, input_size
, input
, output_size
, output
);
625 case QUERYESCSUPPORT
:
626 if (input_size
< sizeof(SHORT
))
628 WARN("input_size < sizeof(SHORT) (=%d) for QUERYESCSUPPORT\n", input_size
);
633 DWORD num
= (input_size
< sizeof(DWORD
)) ? *(const USHORT
*)input
: *(const DWORD
*)input
;
634 TRACE("QUERYESCSUPPORT for %d\n", (int)num
);
646 case EXT_DEVICE_CAPS
:
649 case POSTSCRIPT_DATA
:
651 case POSTSCRIPT_PASSTHROUGH
:
652 case POSTSCRIPT_IGNORE
:
656 /*case DRAWPATTERNRECT:*/
658 /* PageMaker checks for it */
661 /* PageMaker doesn't check for DOWNLOADFACE and GETFACENAME but
662 * uses them, they are supposed to be supported by any PS printer.
666 /* PageMaker checks for these as a part of process of detecting
667 * a "fully compatible" PS printer, but doesn't actually use them.
673 /* Windows PS driver reports 0, but still supports this escape */
675 return FALSE
; /* suppress the FIXME below */
678 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", (int)num
);
684 FIXME("OPENCHANNEL: stub\n");
688 FIXME("CLOSECHANNEL: stub\n");
692 FIXME("DOWNLOADHEADER: stub\n");
693 /* should return name of the downloaded procset */
698 FIXME("GETFACENAME: stub\n");
699 lstrcpynA(output
, "Courier", output_size
);
703 FIXME("DOWNLOADFACE: stub\n");
708 FIXME("MFCOMMENT(%p, %d)\n", input
, input_size
);
711 case DRAWPATTERNRECT
:
713 DRAWPATRECT
*dpr
= (DRAWPATRECT
*)input
;
715 FIXME("DRAWPATTERNRECT(pos (%d,%d), size %dx%d, style %d, pattern %x), stub!\n",
716 (int)dpr
->ptPosition
.x
, (int)dpr
->ptPosition
.y
,
717 (int)dpr
->ptSize
.x
, (int)dpr
->ptSize
.y
,
718 dpr
->wStyle
, dpr
->wPattern
);
723 struct band_info
*ibi
= (struct band_info
*)input
;
724 struct band_info
*obi
= (struct band_info
*)output
;
726 FIXME("BANDINFO(graphics %d, text %d, rect %s), stub!\n", ibi
->graphics_flag
,
727 ibi
->text_flag
, wine_dbgstr_rect(&ibi
->graphics_rect
));
734 const INT
*NumCopies
= input
;
735 INT
*ActualCopies
= output
;
736 if (input_size
!= sizeof(INT
))
738 WARN("input_size != sizeof(INT) (=%d) for SETCOPYCOUNT\n", input_size
);
741 TRACE("SETCOPYCOUNT %d\n", *NumCopies
);
749 strcpy(p
, "PostScript");
750 *(p
+ strlen(p
) + 1) = '\0'; /* 2 '\0's at end of string */
756 INT newCap
= *(const INT
*)input
;
757 if (input_size
!= sizeof(INT
))
759 WARN("input_size != sizeof(INT) (=%d) for SETLINECAP\n", input_size
);
762 TRACE("SETLINECAP %d\n", newCap
);
768 INT newJoin
= *(const INT
*)input
;
769 if (input_size
!= sizeof(INT
))
771 WARN("input_size != sizeof(INT) (=%d) for SETLINEJOIN\n", input_size
);
774 TRACE("SETLINEJOIN %d\n", newJoin
);
780 INT newLimit
= *(const INT
*)input
;
781 if (input_size
!= sizeof(INT
))
783 WARN("input_size != sizeof(INT) (=%d) for SETMITERLIMIT\n", input_size
);
786 TRACE("SETMITERLIMIT %d\n", newLimit
);
791 /* Undocumented escape used by winword6.
792 Switches between ANSI and a special charset.
793 If *lpInData == 1 we require that
797 0x94 is quotedblright
801 0xa0 is non break space - yeah right.
803 If *lpInData == 0 we get ANSI.
804 Since there's nothing else there, let's just make these the default
805 anyway and see what happens...
809 case EXT_DEVICE_CAPS
:
811 UINT cap
= *(const UINT
*)input
;
812 if (input_size
!= sizeof(UINT
))
814 WARN("input_size != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", input_size
);
817 TRACE("EXT_DEVICE_CAPS %d\n", cap
);
823 const RECT
*r
= input
;
824 if (input_size
!= sizeof(RECT
))
826 WARN("input_size != sizeof(RECT) (=%d) for SET_BOUNDS\n", input_size
);
829 TRACE("SET_BOUNDS %s\n", wine_dbgstr_rect(r
));
835 UINT epsprint
= *(const UINT
*)input
;
836 /* FIXME: In this mode we do not need to send page intros and page
837 * ends according to the doc. But I just ignore that detail
840 TRACE("EPS Printing support %sable.\n",epsprint
?"en":"dis");
844 case POSTSCRIPT_DATA
:
846 case POSTSCRIPT_PASSTHROUGH
:
849 case POSTSCRIPT_IGNORE
:
852 case GETSETPRINTORIENT
:
854 /* If lpInData is present, it is a 20 byte structure, first 32
855 * bit LONG value is the orientation. if lpInData is NULL, it
856 * returns the current orientation.
858 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",input
);
870 case PSDRV_CHECK_WCHAR
:
872 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
873 WCHAR
*uv
= (WCHAR
*)input
;
874 WCHAR out
= uv_metrics(*uv
, pdev
->font
)->wch
;
876 if ((out
& 0xff00) == 0xf000) out
&= ~0xf000;
877 *(WCHAR
*)output
= out
;
881 case PSDRV_GET_BUILTIN_FONT_INFO
:
883 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
884 struct font_info
*font_info
= (struct font_info
*)output
;
889 lstrcpynA(font_info
->font_name
, pdev
->font
->name
, sizeof(font_info
->font_name
));
890 font_info
->size
= pdev
->size
;
891 font_info
->escapement
= pdev
->escapement
;
896 FIXME("Unimplemented code %d\n", escape
);
901 static inline float gdi_round(float f
)
903 return f
> 0 ? f
+ 0.5 : f
- 0.5;
906 static void scale_font(PSDRV_PDEVICE
*pdev
, const struct font_data
*font
, LONG height
, TEXTMETRICW
*tm
)
908 SHORT ascender
, descender
, line_gap
, avg_char_width
;
909 USHORT units_per_em
, win_ascent
, win_descent
;
910 const IFIMETRICS
*m
= font
->metrics
;
914 TRACE("'%s' %i\n", font
->name
, (int)height
);
916 if (height
< 0) /* match em height */
917 scale
= -(height
/ (float)m
->fwdUnitsPerEm
);
918 else /* match cell height */
919 scale
= height
/ (float)(m
->fwdWinAscender
+ m
->fwdWinDescender
);
921 size
.cx
= (INT
)gdi_round(scale
* (float)m
->fwdUnitsPerEm
);
922 size
.cy
= -(INT
)gdi_round(scale
* (float)m
->fwdUnitsPerEm
);
924 units_per_em
= (USHORT
)gdi_round((float)m
->fwdUnitsPerEm
* scale
);
925 ascender
= (SHORT
)gdi_round((float)m
->fwdMacAscender
* scale
);
926 descender
= (SHORT
)gdi_round((float)m
->fwdMacDescender
* scale
);
927 line_gap
= (SHORT
)gdi_round((float)m
->fwdMacLineGap
* scale
);
928 win_ascent
= (USHORT
)gdi_round((float)m
->fwdWinAscender
* scale
);
929 win_descent
= (USHORT
)gdi_round((float)m
->fwdWinDescender
* scale
);
930 avg_char_width
= (SHORT
)gdi_round((float)m
->fwdAveCharWidth
* scale
);
932 tm
->tmAscent
= (LONG
)win_ascent
;
933 tm
->tmDescent
= (LONG
)win_descent
;
934 tm
->tmHeight
= tm
->tmAscent
+ tm
->tmDescent
;
936 tm
->tmInternalLeading
= tm
->tmHeight
- (LONG
)units_per_em
;
937 if (tm
->tmInternalLeading
< 0)
938 tm
->tmInternalLeading
= 0;
940 tm
->tmExternalLeading
=
941 (LONG
)(ascender
- descender
+ line_gap
) - tm
->tmHeight
;
942 if (tm
->tmExternalLeading
< 0)
943 tm
->tmExternalLeading
= 0;
945 tm
->tmAveCharWidth
= (LONG
)avg_char_width
;
947 tm
->tmWeight
= m
->usWinWeight
;
948 tm
->tmItalic
= !!(m
->fsSelection
& FM_SEL_ITALIC
);
949 tm
->tmUnderlined
= !!(m
->fsSelection
& FM_SEL_UNDERSCORE
);
950 tm
->tmStruckOut
= !!(m
->fsSelection
& FM_SEL_STRIKEOUT
);
951 tm
->tmFirstChar
= font
->glyphs
[0].wch
;
952 tm
->tmLastChar
= font
->glyphs
[font
->glyph_count
- 1].wch
;
953 tm
->tmDefaultChar
= 0x001f; /* Win2K does this - FIXME? */
954 tm
->tmBreakChar
= tm
->tmFirstChar
; /* should be 'space' */
956 tm
->tmPitchAndFamily
= TMPF_DEVICE
| TMPF_VECTOR
;
957 if (!(m
->jWinPitchAndFamily
& FIXED_PITCH
))
958 tm
->tmPitchAndFamily
|= TMPF_FIXED_PITCH
; /* yes, it's backwards */
959 if (m
->fwdUnitsPerEm
!= 1000)
960 tm
->tmPitchAndFamily
|= TMPF_TRUETYPE
;
962 tm
->tmCharSet
= ANSI_CHARSET
; /* FIXME */
966 * This is kludgy. font->scale is used in several places in the driver
967 * to adjust PostScript-style metrics. Since these metrics have been
968 * "normalized" to an em-square size of 1000, font->scale needs to be
969 * similarly adjusted..
972 scale
*= (float)m
->fwdUnitsPerEm
/ 1000.0;
974 tm
->tmMaxCharWidth
= (LONG
)gdi_round((m
->rclFontBox
.right
- m
->rclFontBox
.left
) * scale
);
982 TRACE("Selected PS font '%s' size %d weight %d.\n", font
->name
,
983 (int)size
.cx
, (int)tm
->tmWeight
);
984 TRACE("H = %d As = %d Des = %d IL = %d EL = %d\n", (int)tm
->tmHeight
,
985 (int)tm
->tmAscent
, (int)tm
->tmDescent
, (int)tm
->tmInternalLeading
,
986 (int)tm
->tmExternalLeading
);
989 static inline BOOL
is_stock_font(HFONT font
)
992 for (i
= OEM_FIXED_FONT
; i
<= DEFAULT_GUI_FONT
; i
++)
994 if (i
!= DEFAULT_PALETTE
&& font
== GetStockObject(i
)) return TRUE
;
999 static struct font_data
*find_font_data(const char *name
)
1001 struct font_data
*font
;
1003 LIST_FOR_EACH_ENTRY(font
, &fonts
, struct font_data
, entry
)
1005 if (!strcmp(font
->name
, name
))
1011 static struct font_data
*find_builtin_font(const PSDRV_DEVMODE
*devmode
,
1012 const WCHAR
*facename
, BOOL it
, BOOL bd
)
1014 struct installed_font
*installed_font
;
1015 BOOL best_it
, best_bd
, cur_it
, cur_bd
;
1016 struct font_data
*best
= NULL
, *cur
;
1020 installed_font
= (struct installed_font
*)(devmode
->data
+
1021 devmode
->input_slots
* sizeof(struct input_slot
) +
1022 devmode
->resolutions
* sizeof(struct resolution
) +
1023 devmode
->page_sizes
* sizeof(struct page_size
) +
1024 devmode
->font_subs
* sizeof(struct font_sub
));
1025 for (i
= 0; i
< devmode
->installed_fonts
; i
++)
1027 cur
= find_font_data(installed_font
[i
].name
);
1030 name
= (WCHAR
*)((char *)cur
->metrics
+ cur
->metrics
->dpwszFaceName
);
1031 cur_it
= !!(cur
->metrics
->fsSelection
& FM_SEL_ITALIC
);
1032 cur_bd
= !!(cur
->metrics
->fsSelection
& FM_SEL_BOLD
);
1034 if (!facename
&& it
== cur_it
&& bd
== cur_bd
)
1036 if (facename
&& !wcscmp(facename
, name
) && it
== cur_it
&& bd
== cur_bd
)
1038 if (facename
&& wcscmp(facename
, name
))
1041 if (!best
|| (best_it
!= it
&& cur_it
== it
) ||
1042 (best_it
!= it
&& best_bd
!= bd
&& cur_bd
== bd
))
1053 static BOOL
select_builtin_font(PSDRV_PDEVICE
*pdev
, HFONT hfont
, LOGFONTW
*plf
)
1055 struct font_data
*font_data
;
1056 BOOL bd
= FALSE
, it
= FALSE
;
1059 TRACE("Trying to find facename %s\n", debugstr_w(plf
->lfFaceName
));
1063 if (plf
->lfWeight
> 550)
1066 /* Look for a matching font family */
1067 font_data
= find_builtin_font(pdev
->devmode
, plf
->lfFaceName
, it
, bd
);
1070 /* Fallback for Window's font families to common PostScript families */
1071 if (!wcscmp(plf
->lfFaceName
, arialW
))
1072 wcscpy(plf
->lfFaceName
, helveticaW
);
1073 else if (!wcscmp(plf
->lfFaceName
, systemW
))
1074 wcscpy(plf
->lfFaceName
, helveticaW
);
1075 else if (!wcscmp(plf
->lfFaceName
, times_new_romanW
))
1076 wcscpy(plf
->lfFaceName
, timesW
);
1077 else if (!wcscmp(plf
->lfFaceName
, courier_newW
))
1078 wcscpy(plf
->lfFaceName
, courierW
);
1080 font_data
= find_builtin_font(pdev
->devmode
, plf
->lfFaceName
, it
, bd
);
1082 /* If all else fails, use the first font defined for the printer */
1084 font_data
= find_builtin_font(pdev
->devmode
, NULL
, it
, bd
);
1086 TRACE("Got family %s font '%s'\n", debugstr_w((WCHAR
*)((char *)font_data
->metrics
+
1087 font_data
->metrics
->dpwszFaceName
)), font_data
->name
);
1089 pdev
->builtin
= TRUE
;
1091 pdev
->font
= font_data
;
1093 height
= plf
->lfHeight
;
1094 /* stock fonts ignore the mapping mode */
1095 if (!is_stock_font(hfont
))
1098 pts
[0].x
= pts
[0].y
= pts
[1].x
= 0;
1100 NtGdiTransformPoints(pdev
->dev
.hdc
, pts
, pts
, 2, NtGdiLPtoDP
);
1101 height
= pts
[1].y
- pts
[0].y
;
1103 scale_font(pdev
, font_data
, height
, &pdev
->tm
);
1105 /* Does anyone know if these are supposed to be reversed like this? */
1106 pdev
->tm
.tmDigitizedAspectX
= pdev
->log_pixels_y
;
1107 pdev
->tm
.tmDigitizedAspectY
= pdev
->log_pixels_x
;
1111 static HFONT CDECL
select_font(PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
1113 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
1114 PHYSDEV next
= GET_NEXT_PHYSDEV(dev
, pSelectFont
);
1115 const struct font_sub
*font_sub
;
1121 if (!NtGdiExtGetObjectW(hfont
, sizeof(lf
), &lf
)) return 0;
1123 *aa_flags
= GGO_BITMAP
; /* no anti-aliasing on printer devices */
1125 TRACE("FaceName = %s Height = %d Italic = %d Weight = %d\n",
1126 debugstr_w(lf
.lfFaceName
), (int)lf
.lfHeight
, lf
.lfItalic
,
1129 if (lf
.lfFaceName
[0] == '\0')
1131 switch(lf
.lfPitchAndFamily
& 0xf0)
1137 wcscpy(lf
.lfFaceName
, timesW
);
1140 wcscpy(lf
.lfFaceName
, helveticaW
);
1143 wcscpy(lf
.lfFaceName
, courierW
);
1146 wcscpy(lf
.lfFaceName
, symbolW
);
1151 if (lf
.lfFaceName
[0] == '\0')
1153 switch(lf
.lfPitchAndFamily
& 0x0f)
1155 case VARIABLE_PITCH
:
1156 wcscpy(lf
.lfFaceName
, timesW
);
1159 wcscpy(lf
.lfFaceName
, courierW
);
1164 font_sub
= (const struct font_sub
*)(pdev
->devmode
->data
+
1165 pdev
->devmode
->input_slots
* sizeof(struct input_slot
) +
1166 pdev
->devmode
->resolutions
* sizeof(struct resolution
) +
1167 pdev
->devmode
->page_sizes
* sizeof(struct page_size
));
1168 for (i
= 0; i
< pdev
->devmode
->font_subs
; i
++)
1170 if (!wcsicmp(lf
.lfFaceName
, font_sub
[i
].name
))
1172 TRACE("substituting facename %s for %s\n",
1173 debugstr_w(font_sub
[i
].sub
), debugstr_w(lf
.lfFaceName
));
1174 if (wcslen(font_sub
[i
].sub
) < LF_FACESIZE
)
1176 wcscpy(lf
.lfFaceName
, font_sub
[i
].sub
);
1181 WARN("Facename %s is too long; ignoring substitution\n",
1182 debugstr_w(font_sub
[i
].sub
));
1188 pdev
->escapement
= lf
.lfEscapement
;
1190 if (!subst
&& ((ret
= next
->funcs
->pSelectFont(next
, hfont
, aa_flags
))))
1192 pdev
->builtin
= FALSE
;
1196 select_builtin_font(pdev
, hfont
, &lf
);
1197 next
->funcs
->pSelectFont(next
, 0, aa_flags
); /* tell next driver that we selected a device font */
1201 static UINT
get_font_metric(const struct font_data
*font
,
1202 NEWTEXTMETRICEXW
*ntmx
, ENUMLOGFONTEXW
*elfx
)
1204 /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */
1205 TEXTMETRICW
*tm
= (TEXTMETRICW
*)&(ntmx
->ntmTm
);
1206 LOGFONTW
*lf
= &(elfx
->elfLogFont
);
1208 memset(ntmx
, 0, sizeof(*ntmx
));
1209 memset(elfx
, 0, sizeof(*elfx
));
1211 scale_font(NULL
, font
, -(LONG
)font
->metrics
->fwdUnitsPerEm
, tm
);
1213 lf
->lfHeight
= tm
->tmHeight
;
1214 lf
->lfWidth
= tm
->tmAveCharWidth
;
1215 lf
->lfWeight
= tm
->tmWeight
;
1216 lf
->lfItalic
= tm
->tmItalic
;
1217 lf
->lfCharSet
= tm
->tmCharSet
;
1219 lf
->lfPitchAndFamily
= font
->metrics
->jWinPitchAndFamily
& FIXED_PITCH
? FIXED_PITCH
: VARIABLE_PITCH
;
1221 lstrcpynW(lf
->lfFaceName
, (WCHAR
*)((char *)font
->metrics
+ font
->metrics
->dpwszFaceName
), LF_FACESIZE
);
1222 return DEVICE_FONTTYPE
;
1225 static BOOL CDECL
enum_fonts(PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lp
)
1227 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
1228 PHYSDEV next
= GET_NEXT_PHYSDEV(dev
, pEnumFonts
);
1229 PSDRV_DEVMODE
*devmode
= pdev
->devmode
;
1230 struct installed_font
*installed_font
;
1231 struct font_data
*cur
;
1233 NEWTEXTMETRICEXW tm
;
1239 ret
= next
->funcs
->pEnumFonts(next
, plf
, proc
, lp
);
1240 if (!ret
) return FALSE
;
1242 installed_font
= (struct installed_font
*)(devmode
->data
+
1243 devmode
->input_slots
* sizeof(struct input_slot
) +
1244 devmode
->resolutions
* sizeof(struct resolution
) +
1245 devmode
->page_sizes
* sizeof(struct page_size
) +
1246 devmode
->font_subs
* sizeof(struct font_sub
));
1247 if (plf
&& plf
->lfFaceName
[0])
1249 TRACE("lfFaceName = %s\n", debugstr_w(plf
->lfFaceName
));
1251 for (i
= 0; i
< devmode
->installed_fonts
; i
++)
1253 cur
= find_font_data(installed_font
[i
].name
);
1256 name
= (WCHAR
*)((char *)cur
->metrics
+ cur
->metrics
->dpwszFaceName
);
1257 if (wcsncmp(plf
->lfFaceName
, name
, wcslen(name
)))
1260 TRACE("Got '%s'\n", cur
->name
);
1261 fm
= get_font_metric(cur
, &tm
, &lf
);
1262 if (!(ret
= (*proc
)(&lf
.elfLogFont
, (TEXTMETRICW
*)&tm
, fm
, lp
)))
1268 TRACE("lfFaceName = NULL\n");
1270 for (i
= 0; i
< devmode
->installed_fonts
; i
++)
1272 cur
= find_font_data(installed_font
[i
].name
);
1275 name
= (WCHAR
*)((char *)cur
->metrics
+ cur
->metrics
->dpwszFaceName
);
1276 TRACE("Got '%s'\n", cur
->name
);
1277 fm
= get_font_metric(cur
, &tm
, &lf
);
1278 if (!(ret
= (*proc
)(&lf
.elfLogFont
, (TEXTMETRICW
*)&tm
, fm
, lp
)))
1285 static BOOL CDECL
get_char_width(PHYSDEV dev
, UINT first
, UINT count
, const WCHAR
*chars
, INT
*buffer
)
1287 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
1292 dev
= GET_NEXT_PHYSDEV(dev
, pGetCharWidth
);
1293 return dev
->funcs
->pGetCharWidth(dev
, first
, count
, chars
, buffer
);
1296 TRACE("U+%.4X +%u\n", first
, count
);
1298 for (i
= 0; i
< count
; ++i
)
1300 c
= chars
? chars
[i
] : first
+ i
;
1305 *buffer
= floor(uv_metrics(c
, pdev
->font
)->width
* pdev
->scale
+ 0.5);
1306 TRACE("U+%.4X: %i\n", i
, *buffer
);
1312 static BOOL CDECL
get_text_metrics(PHYSDEV dev
, TEXTMETRICW
*metrics
)
1314 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
1318 dev
= GET_NEXT_PHYSDEV(dev
, pGetTextMetrics
);
1319 return dev
->funcs
->pGetTextMetrics(dev
, metrics
);
1322 memcpy(metrics
, &pdev
->tm
, sizeof(pdev
->tm
));
1326 static BOOL CDECL
get_text_extent_ex_point(PHYSDEV dev
, const WCHAR
*str
, int count
, int *dx
)
1328 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
1334 dev
= GET_NEXT_PHYSDEV(dev
, pGetTextExtentExPoint
);
1335 return dev
->funcs
->pGetTextExtentExPoint(dev
, str
, count
, dx
);
1338 TRACE("%s %i\n", debugstr_wn(str
, count
), count
);
1340 for (i
= 0; i
< count
; ++i
)
1342 width
+= uv_metrics(str
[i
], pdev
->font
)->width
;
1343 dx
[i
] = width
* pdev
->scale
;
1348 static struct printer_info
*find_printer_info(const WCHAR
*name
)
1350 struct printer_info
*pi
;
1352 LIST_FOR_EACH_ENTRY(pi
, &printer_info_list
, struct printer_info
, entry
)
1354 if (!wcscmp(pi
->name
, name
))
1360 static PSDRV_PDEVICE
*create_physdev(HDC hdc
, const WCHAR
*device
,
1361 const DEVMODEW
*devmode
)
1363 struct printer_info
*pi
= find_printer_info(device
);
1364 PSDRV_PDEVICE
*pdev
;
1366 if (!pi
) return NULL
;
1367 if (!find_builtin_font(pi
->devmode
, NULL
, FALSE
, FALSE
))
1369 RASTERIZER_STATUS status
;
1370 if (!NtGdiGetRasterizerCaps(&status
, sizeof(status
)) ||
1371 !(status
.wFlags
& TT_AVAILABLE
) ||
1372 !(status
.wFlags
& TT_ENABLED
))
1374 MESSAGE("Disabling printer %s since it has no builtin fonts and "
1375 "there are no TrueType fonts available.\n", debugstr_w(device
));
1380 pdev
= malloc(sizeof(*pdev
));
1381 if (!pdev
) return NULL
;
1383 pdev
->devmode
= malloc(pi
->devmode
->dmPublic
.dmSize
+ pi
->devmode
->dmPublic
.dmDriverExtra
);
1390 memcpy(pdev
->devmode
, pi
->devmode
, pi
->devmode
->dmPublic
.dmSize
+
1391 pi
->devmode
->dmPublic
.dmDriverExtra
);
1393 pdev
->log_pixels_x
= pdev
->devmode
->default_resolution
;
1394 pdev
->log_pixels_y
= pdev
->devmode
->default_resolution
;
1398 dump_devmode(devmode
);
1399 merge_devmodes(pdev
->devmode
, devmode
, pi
);
1402 update_dev_caps(pdev
);
1403 NtGdiSelectFont(hdc
, GetStockObject(DEVICE_DEFAULT_FONT
));
1407 static BOOL CDECL
create_dc(PHYSDEV
*dev
, const WCHAR
*device
,
1408 const WCHAR
*output
, const DEVMODEW
*devmode
)
1410 PSDRV_PDEVICE
*pdev
;
1412 TRACE("(%s %s %p)\n", debugstr_w(device
), debugstr_w(output
), devmode
);
1414 if (!device
) return FALSE
;
1415 if (!(pdev
= create_physdev((*dev
)->hdc
, device
, devmode
))) return FALSE
;
1416 push_dc_driver(dev
, &pdev
->dev
, &psdrv_funcs
);
1420 static BOOL CDECL
create_compatible_dc(PHYSDEV orig
, PHYSDEV
*dev
)
1422 PSDRV_PDEVICE
*pdev
, *orig_dev
= get_psdrv_dev(orig
);
1424 if (!(pdev
= create_physdev((*dev
)->hdc
, orig_dev
->pi
->name
,
1425 &orig_dev
->devmode
->dmPublic
))) return FALSE
;
1426 push_dc_driver(dev
, &pdev
->dev
, &psdrv_funcs
);
1430 static BOOL CDECL
delete_dc(PHYSDEV dev
)
1432 PSDRV_PDEVICE
*pdev
= get_psdrv_dev(dev
);
1436 free(pdev
->devmode
);
1441 static const struct gdi_dc_funcs psdrv_funcs
=
1443 .pCreateCompatibleDC
= create_compatible_dc
,
1444 .pCreateDC
= create_dc
,
1445 .pDeleteDC
= delete_dc
,
1446 .pEnumFonts
= enum_fonts
,
1447 .pExtEscape
= ext_escape
,
1448 .pGetCharWidth
= get_char_width
,
1449 .pGetDeviceCaps
= get_device_caps
,
1450 .pGetTextExtentExPoint
= get_text_extent_ex_point
,
1451 .pGetTextMetrics
= get_text_metrics
,
1452 .pResetDC
= reset_dc
,
1453 .pSelectFont
= select_font
,
1454 .priority
= GDI_PRIORITY_GRAPHICS_DRV
1457 static BOOL
check_ntf_str(const char *data
, UINT64 size
, const char *str
)
1459 if (str
< data
|| str
>= data
+ size
)
1462 while (*str
&& size
)
1470 static void free_font_data(struct font_data
*font_data
)
1472 free(font_data
->name
);
1473 free(font_data
->metrics
);
1474 free(font_data
->glyphs
);
1478 static WCHAR
convert_ntf_cp(unsigned short c
, unsigned short cp
)
1480 static const WCHAR map_fff1
[256] = {
1481 0x0000, 0x02d8, 0x02c7, 0x02d9, 0x0131, 0xfb01, 0xfb02, 0x2044,
1482 0x02dd, 0x0141, 0x0142, 0x2212, 0x02db, 0x02da, 0x017d, 0x017e,
1483 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
1484 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
1485 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
1486 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
1487 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
1488 0x0038, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
1489 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
1490 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
1491 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
1492 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
1493 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
1494 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
1495 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
1496 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
1497 0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
1498 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
1499 0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
1500 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x0000, 0x0178,
1501 0x0000, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
1502 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af,
1503 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
1504 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
1505 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
1506 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
1507 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
1508 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
1509 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
1510 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
1511 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
1512 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
1519 ret
= c
< ARRAY_SIZE(map_fff1
) ? map_fff1
[c
] : 0;
1521 case 0xffff: /* Wine extension */
1527 FIXME("unrecognized character %x in %x\n", c
, cp
);
1531 static BOOL
map_glyph_to_unicode(struct font_data
*font_data
,
1532 const char *data
, UINT64 size
, const char *name
)
1534 const struct ntf_header
*header
= (const struct ntf_header
*)data
;
1535 const struct list_entry
*list_elem
;
1536 const struct glyph_set
*glyph_set
;
1537 const unsigned short *p
;
1540 list_elem
= (const struct list_entry
*)(data
+ header
->glyph_set_off
);
1541 for (i
= 0; i
< header
->glyph_set_count
; i
++)
1543 if (!check_ntf_str(data
, size
, data
+ list_elem
->name_off
))
1545 if (strcmp(data
+ list_elem
->name_off
, name
))
1550 if (list_elem
->off
+ list_elem
->size
> size
)
1553 glyph_set
= (const struct glyph_set
*)(data
+ list_elem
->off
);
1554 if (font_data
->glyph_count
> glyph_set
->glyph_count
)
1557 p
= (const unsigned short *)((const char *)glyph_set
+ glyph_set
->glyph_set_off
);
1558 if (glyph_set
->flags
& GLYPH_SET_OMIT_CP
)
1560 const struct code_page
*code_page
= (const struct code_page
*)((const char *)glyph_set
+ glyph_set
->cp_off
);
1561 unsigned short def_cp
;
1563 if (glyph_set
->cp_off
+ sizeof(*code_page
) * glyph_set
->cp_count
> list_elem
->size
)
1565 if (glyph_set
->cp_count
!= 1)
1567 if (glyph_set
->glyph_set_off
+ sizeof(short) * font_data
->glyph_count
> list_elem
->size
)
1570 def_cp
= code_page
->cp
;
1571 for (j
= 0; j
< font_data
->glyph_count
; j
++)
1573 font_data
->glyphs
[j
].wch
= convert_ntf_cp(p
[0], def_cp
);
1579 if (glyph_set
->glyph_set_off
+ sizeof(short[2]) * font_data
->glyph_count
> list_elem
->size
)
1582 for (j
= 0; j
< font_data
->glyph_count
; j
++)
1584 font_data
->glyphs
[j
].wch
= convert_ntf_cp(p
[0], p
[1]);
1594 static BOOL
add_ntf_fonts(const char *data
, int size
)
1596 const struct ntf_header
*header
= (const struct ntf_header
*)data
;
1597 const struct width_range
*width_range
;
1598 const struct list_entry
*list_elem
;
1599 const struct font_mtx
*font_mtx
;
1600 struct font_data
*font_data
;
1601 const IFIMETRICS
*metrics
;
1605 if (size
< sizeof(*header
) ||
1606 size
< header
->glyph_set_off
+ header
->glyph_set_count
* sizeof(*list_elem
) ||
1607 size
< header
->font_mtx_off
+ header
->font_mtx_count
* sizeof(*list_elem
))
1610 list_elem
= (const struct list_entry
*)(data
+ header
->font_mtx_off
);
1611 for (i
= 0; i
< header
->font_mtx_count
; i
++)
1613 name
= data
+ list_elem
->name_off
;
1614 if (!check_ntf_str(data
, size
, name
))
1616 TRACE("adding %s font\n", name
);
1618 if (list_elem
->size
+ list_elem
->off
> size
)
1620 font_mtx
= (const struct font_mtx
*)(data
+ list_elem
->off
);
1621 if (list_elem
->off
+ font_mtx
->metrics_off
+ FIELD_OFFSET(IFIMETRICS
, panose
) > size
)
1623 metrics
= (const IFIMETRICS
*)((const char *)font_mtx
+ font_mtx
->metrics_off
);
1624 if (list_elem
->off
+ font_mtx
->metrics_off
+ metrics
->cjThis
> size
)
1626 if (list_elem
->off
+ font_mtx
->width_off
+ sizeof(*width_range
) * font_mtx
->width_count
> size
)
1628 width_range
= (const struct width_range
*)((const char *)font_mtx
+ font_mtx
->width_off
);
1629 if (!check_ntf_str(data
, size
, (const char *)font_mtx
+ font_mtx
->glyph_set_name_off
))
1632 if (!font_mtx
->glyph_count
)
1638 font_data
= calloc(sizeof(*font_data
), 1);
1642 font_data
->glyph_count
= font_mtx
->glyph_count
;
1643 font_data
->name
= malloc(strlen(name
) + 1);
1644 font_data
->metrics
= malloc(metrics
->cjThis
);
1645 font_data
->glyphs
= malloc(sizeof(*font_data
->glyphs
) * font_data
->glyph_count
);
1646 if (!font_data
->name
|| !font_data
->metrics
|| !font_data
->glyphs
)
1648 free_font_data(font_data
);
1651 memcpy(font_data
->name
, name
, strlen(name
) + 1);
1652 memcpy(font_data
->metrics
, metrics
, metrics
->cjThis
);
1654 for (j
= 0; j
< font_mtx
->glyph_count
; j
++)
1655 font_data
->glyphs
[j
].width
= font_mtx
->def_width
;
1656 for (j
= 0; j
< font_mtx
->width_count
; j
++)
1658 /* Use default width */
1659 if (width_range
[j
].width
== 0x80000008)
1662 for (k
= 0; k
< width_range
[j
].count
; k
++)
1664 if (width_range
[j
].first
+ k
>= font_data
->glyph_count
)
1666 font_data
->glyphs
[width_range
[j
].first
+ k
].width
= width_range
[j
].width
;
1670 if (!map_glyph_to_unicode(font_data
, data
, size
,
1671 (const char *)font_mtx
+ font_mtx
->glyph_set_name_off
))
1673 free_font_data(font_data
);
1674 WARN("error loading %s font\n", name
);
1678 font_data
->def_glyph
= font_data
->glyphs
[0];
1680 qsort(font_data
->glyphs
, font_data
->glyph_count
,
1681 sizeof(*font_data
->glyphs
), cmp_glyph_info
);
1682 list_add_head(&fonts
, &font_data
->entry
);
1684 TRACE("%s font added\n", name
);
1690 static NTSTATUS
import_ntf(void *arg
)
1692 struct import_ntf_params
*params
= arg
;
1694 return add_ntf_fonts(params
->data
, params
->size
);
1697 static NTSTATUS
open_dc(void *arg
)
1699 UNICODE_STRING device_str
, output_str
;
1700 struct open_dc_params
*params
= arg
;
1701 struct printer_info
*pi
;
1703 pi
= find_printer_info(params
->device
);
1706 pi
= malloc(sizeof(*pi
));
1707 if (!pi
) return FALSE
;
1709 pi
->name
= params
->device
;
1710 pi
->devmode
= params
->def_devmode
;
1711 list_add_head(&printer_info_list
, &pi
->entry
);
1714 device_str
.Length
= device_str
.MaximumLength
= lstrlenW(params
->device
) + 1;
1715 device_str
.Buffer
= (WCHAR
*)params
->device
;
1718 output_str
.Length
= output_str
.MaximumLength
= lstrlenW(params
->output
) + 1;
1719 output_str
.Buffer
= (WCHAR
*)params
->output
;
1721 params
->hdc
= NtGdiOpenDCW(&device_str
, params
->devmode
, params
->output
? &output_str
: NULL
,
1722 WINE_GDI_DRIVER_VERSION
, 0, (HANDLE
)&psdrv_funcs
, NULL
, NULL
);
1726 static NTSTATUS
free_printer_info(void *arg
)
1728 struct font_data
*font
, *font_next
;
1729 struct printer_info
*pi
, *next
;
1731 LIST_FOR_EACH_ENTRY_SAFE(pi
, next
, &printer_info_list
, struct printer_info
, entry
)
1736 LIST_FOR_EACH_ENTRY_SAFE(font
, font_next
, &fonts
, struct font_data
, entry
)
1738 free_font_data(font
);
1743 const unixlib_entry_t __wine_unix_call_funcs
[] =
1750 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs
) == unix_funcs_count
);
1754 typedef ULONG PTR32
;
1756 static NTSTATUS
wow64_import_ntf(void *args
)
1762 } const *params32
= args
;
1763 struct import_ntf_params params
= { ULongToPtr(params32
->data
), params32
->size
};
1765 return import_ntf(¶ms
);
1768 static NTSTATUS
wow64_open_dc(void *args
)
1778 struct open_dc_params params
=
1780 ULongToPtr(params32
->device
),
1781 ULongToPtr(params32
->devmode
),
1782 ULongToPtr(params32
->output
),
1783 ULongToPtr(params32
->def_devmode
),
1788 ret
= open_dc(¶ms
);
1789 params32
->hdc
= PtrToUlong(params
.hdc
);
1793 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
1800 C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs
) == unix_funcs_count
);