wineps: Don't include gdi_driver.h from PE module.
[wine.git] / dlls / wineps.drv / unixlib.c
blob26b1232f63e26f43dbc1621044bf3591df1eb9b0
1 /*
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
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <math.h>
31 #include "windef.h"
32 #include "winbase.h"
34 #include "ntf.h"
35 #include "unixlib.h"
36 #include "ntgdi.h"
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;
55 struct glyph_info
57 WCHAR wch;
58 int width;
61 struct font_data
63 struct list entry;
65 char *name;
66 IFIMETRICS *metrics;
67 int glyph_count;
68 struct glyph_info *glyphs;
69 struct glyph_info def_glyph;
72 static struct list fonts = LIST_INIT(fonts);
74 struct printer_info
76 struct list entry;
77 const WCHAR *name;
78 const PSDRV_DEVMODE *devmode;
81 static struct list printer_info_list = LIST_INIT(printer_info_list);
83 struct band_info
85 BOOL graphics_flag;
86 BOOL text_flag;
87 RECT graphics_rect;
90 typedef struct
92 struct gdi_physdev dev;
93 PSDRV_DEVMODE *devmode;
94 const struct printer_info *pi;
96 /* builtin font info */
97 BOOL builtin;
98 SIZE size;
99 const struct font_data *font;
100 float scale;
101 TEXTMETRICW tm;
102 int escapement;
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 */
107 int vert_res;
108 int horz_size;
109 int vert_size;
110 int log_pixels_x;
111 int log_pixels_y;
112 } PSDRV_PDEVICE;
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)
122 LONGLONG ret;
124 if (!c) return -1;
126 /* We want to deal with a positive divisor to simplify the logic. */
127 if (c < 0)
129 a = -a;
130 c = -c;
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;
136 else
137 ret = (((LONGLONG)a * b) - (c / 2)) / c;
139 if (ret > 2147483647 || ret < -2147483647) return -1;
140 return ret;
143 static void dump_fields(int fields)
145 int add_space = 0;
147 #define CHECK_FIELD(flag) \
148 do \
150 if (fields & flag) \
152 if (add_space++) TRACE(" "); \
153 TRACE(#flag); \
154 fields &= ~flag; \
157 while (0)
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);
165 CHECK_FIELD(DM_NUP);
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);
189 TRACE("\n");
190 #undef CHECK_FIELD
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);
230 switch(cap)
232 case DRIVERVERSION:
233 return 0;
234 case TECHNOLOGY:
235 return DT_RASPRINTER;
236 case HORZSIZE:
237 return muldiv(pdev->horz_size, 100, pdev->devmode->dmPublic.dmScale);
238 case VERTSIZE:
239 return muldiv(pdev->vert_size, 100, pdev->devmode->dmPublic.dmScale);
240 case HORZRES:
241 return pdev->horz_res;
242 case VERTRES:
243 return pdev->vert_res;
244 case BITSPIXEL:
245 /* Although Windows returns 1 for monochrome printers, we want
246 CreateCompatibleBitmap to provide something other than 1 bpp */
247 return 32;
248 case NUMPENS:
249 return 10;
250 case NUMFONTS:
251 return 39;
252 case NUMCOLORS:
253 return -1;
254 case PDEVICESIZE:
255 return sizeof(PSDRV_PDEVICE);
256 case TEXTCAPS:
257 return TC_CR_ANY | TC_VA_ABLE; /* psdrv 0x59f7 */
258 case RASTERCAPS:
259 return (RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT | RC_DIBTODEV |
260 RC_STRETCHBLT | RC_STRETCHDIB); /* psdrv 0x6e99 */
261 case ASPECTX:
262 return pdev->log_pixels_x;
263 case ASPECTY:
264 return pdev->log_pixels_y;
265 case LOGPIXELSX:
266 return muldiv(pdev->log_pixels_x, pdev->devmode->dmPublic.dmScale, 100);
267 case LOGPIXELSY:
268 return muldiv(pdev->log_pixels_y, pdev->devmode->dmPublic.dmScale, 100);
269 case NUMRESERVED:
270 return 0;
271 case COLORRES:
272 return 0;
273 case PHYSICALWIDTH:
274 return (pdev->devmode->dmPublic.dmOrientation == DMORIENT_LANDSCAPE) ?
275 pdev->page_size.cy : pdev->page_size.cx;
276 case PHYSICALHEIGHT:
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;
284 else
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;
294 else
295 return pdev->imageable_area.left;
297 return pdev->page_size.cy - pdev->imageable_area.top;
299 default:
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,
311 const DEVMODEW *dm)
313 const struct input_slot *slot = (const struct input_slot *)pi->devmode->data;
314 int i;
316 for (i = 0; i < pi->devmode->input_slots; i++)
318 if (slot[i].win_bin == dm->dmDefaultSource)
319 return slot + i;
321 return NULL;
324 static const struct page_size *find_pagesize(const struct printer_info *pi,
325 const DEVMODEW *dm)
327 const struct page_size *page;
328 int i;
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)
336 return page + i;
338 return NULL;
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 ?
352 "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);
362 if (page)
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;
378 else
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",
388 dm2->dmPaperLength,
389 dm2->dmPaperWidth);
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
397 this case */
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);
419 if (slot)
420 dm1->dmPublic.dmDefaultSource = dm2->dmDefaultSource;
421 else
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;
474 int i;
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;
497 break;
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;
508 else
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);
518 if (!page)
520 FIXME("Can't find page\n");
521 SetRectEmpty(&pdev->imageable_area);
522 pdev->page_size.cx = 0;
523 pdev->page_size.cy = 0;
525 else
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;
544 } else {
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;
561 } else {
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);
580 if (devmode)
582 merge_devmodes(pdev->devmode, devmode, pdev->pi);
583 update_dev_caps(pdev);
585 return TRUE;
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)
605 wch |= 0xf000;
607 key.wch = wch;
608 needle = bsearch(&key, font->glyphs, font->glyph_count, sizeof(*font->glyphs), cmp_glyph_info);
609 if (!needle)
611 WARN("No glyph for U+%.4X in '%s'\n", wch, font->name);
612 needle = font->glyphs;
614 return needle;
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);
623 switch (escape)
625 case QUERYESCSUPPORT:
626 if (input_size < sizeof(SHORT))
628 WARN("input_size < sizeof(SHORT) (=%d) for QUERYESCSUPPORT\n", input_size);
629 return 0;
631 else
633 DWORD num = (input_size < sizeof(DWORD)) ? *(const USHORT *)input : *(const DWORD *)input;
634 TRACE("QUERYESCSUPPORT for %d\n", (int)num);
636 switch (num)
638 case NEXTBAND:
639 /*case BANDINFO:*/
640 case SETCOPYCOUNT:
641 case GETTECHNOLOGY:
642 case SETLINECAP:
643 case SETLINEJOIN:
644 case SETMITERLIMIT:
645 case SETCHARSET:
646 case EXT_DEVICE_CAPS:
647 case SET_BOUNDS:
648 case EPSPRINTING:
649 case POSTSCRIPT_DATA:
650 case PASSTHROUGH:
651 case POSTSCRIPT_PASSTHROUGH:
652 case POSTSCRIPT_IGNORE:
653 case BEGIN_PATH:
654 case CLIP_TO_PATH:
655 case END_PATH:
656 /*case DRAWPATTERNRECT:*/
658 /* PageMaker checks for it */
659 case DOWNLOADHEADER:
661 /* PageMaker doesn't check for DOWNLOADFACE and GETFACENAME but
662 * uses them, they are supposed to be supported by any PS printer.
664 case DOWNLOADFACE:
666 /* PageMaker checks for these as a part of process of detecting
667 * a "fully compatible" PS printer, but doesn't actually use them.
669 case OPENCHANNEL:
670 case CLOSECHANNEL:
671 return TRUE;
673 /* Windows PS driver reports 0, but still supports this escape */
674 case GETFACENAME:
675 return FALSE; /* suppress the FIXME below */
677 default:
678 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", (int)num);
679 return FALSE;
683 case OPENCHANNEL:
684 FIXME("OPENCHANNEL: stub\n");
685 return 1;
687 case CLOSECHANNEL:
688 FIXME("CLOSECHANNEL: stub\n");
689 return 1;
691 case DOWNLOADHEADER:
692 FIXME("DOWNLOADHEADER: stub\n");
693 /* should return name of the downloaded procset */
694 *(char *)output = 0;
695 return 1;
697 case GETFACENAME:
698 FIXME("GETFACENAME: stub\n");
699 lstrcpynA(output, "Courier", output_size);
700 return 1;
702 case DOWNLOADFACE:
703 FIXME("DOWNLOADFACE: stub\n");
704 return 1;
706 case MFCOMMENT:
708 FIXME("MFCOMMENT(%p, %d)\n", input, input_size);
709 return 1;
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);
719 return 1;
721 case BANDINFO:
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));
728 *obi = *ibi;
729 return 1;
732 case SETCOPYCOUNT:
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);
739 return 0;
741 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
742 *ActualCopies = 1;
743 return 1;
746 case GETTECHNOLOGY:
748 LPSTR p = output;
749 strcpy(p, "PostScript");
750 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
751 return 1;
754 case SETLINECAP:
756 INT newCap = *(const INT *)input;
757 if (input_size != sizeof(INT))
759 WARN("input_size != sizeof(INT) (=%d) for SETLINECAP\n", input_size);
760 return 0;
762 TRACE("SETLINECAP %d\n", newCap);
763 return 0;
766 case SETLINEJOIN:
768 INT newJoin = *(const INT *)input;
769 if (input_size != sizeof(INT))
771 WARN("input_size != sizeof(INT) (=%d) for SETLINEJOIN\n", input_size);
772 return 0;
774 TRACE("SETLINEJOIN %d\n", newJoin);
775 return 0;
778 case SETMITERLIMIT:
780 INT newLimit = *(const INT *)input;
781 if (input_size != sizeof(INT))
783 WARN("input_size != sizeof(INT) (=%d) for SETMITERLIMIT\n", input_size);
784 return 0;
786 TRACE("SETMITERLIMIT %d\n", newLimit);
787 return 0;
790 case SETCHARSET:
791 /* Undocumented escape used by winword6.
792 Switches between ANSI and a special charset.
793 If *lpInData == 1 we require that
794 0x91 is quoteleft
795 0x92 is quoteright
796 0x93 is quotedblleft
797 0x94 is quotedblright
798 0x95 is bullet
799 0x96 is endash
800 0x97 is emdash
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...
807 return 1;
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);
815 return 0;
817 TRACE("EXT_DEVICE_CAPS %d\n", cap);
818 return 0;
821 case SET_BOUNDS:
823 const RECT *r = input;
824 if (input_size != sizeof(RECT))
826 WARN("input_size != sizeof(RECT) (=%d) for SET_BOUNDS\n", input_size);
827 return 0;
829 TRACE("SET_BOUNDS %s\n", wine_dbgstr_rect(r));
830 return 0;
833 case EPSPRINTING:
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
838 * for now.
840 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
841 return 1;
844 case POSTSCRIPT_DATA:
845 case PASSTHROUGH:
846 case POSTSCRIPT_PASSTHROUGH:
847 return 1;
849 case POSTSCRIPT_IGNORE:
850 return 1;
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);
859 return 1;
861 case BEGIN_PATH:
862 return 1;
864 case END_PATH:
865 return 1;
867 case CLIP_TO_PATH:
868 return 1;
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;
878 return 1;
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;
886 if (!pdev->builtin)
887 return 0;
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;
892 return 1;
895 default:
896 FIXME("Unimplemented code %d\n", escape);
897 return 0;
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;
911 float scale;
912 SIZE size;
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 */
963 tm->tmOverhang = 0;
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);
976 if (pdev)
978 pdev->scale = scale;
979 pdev->size = size;
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)
991 int i;
992 for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
994 if (i != DEFAULT_PALETTE && font == GetStockObject(i)) return TRUE;
996 return FALSE;
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))
1006 return font;
1008 return NULL;
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;
1017 const WCHAR *name;
1018 int i;
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);
1028 if (!cur) continue;
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)
1035 return cur;
1036 if (facename && !wcscmp(facename, name) && it == cur_it && bd == cur_bd)
1037 return cur;
1038 if (facename && wcscmp(facename, name))
1039 continue;
1041 if (!best || (best_it != it && cur_it == it) ||
1042 (best_it != it && best_bd != bd && cur_bd == bd))
1044 best = cur;
1045 best_it = cur_it;
1046 best_bd = cur_bd;
1050 return best;
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;
1057 LONG height;
1059 TRACE("Trying to find facename %s\n", debugstr_w(plf->lfFaceName));
1061 if (plf->lfItalic)
1062 it = TRUE;
1063 if (plf->lfWeight > 550)
1064 bd = TRUE;
1066 /* Look for a matching font family */
1067 font_data = find_builtin_font(pdev->devmode, plf->lfFaceName, it, bd);
1068 if (!font_data)
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 */
1083 if (!font_data)
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;
1090 pdev->font = NULL;
1091 pdev->font = font_data;
1093 height = plf->lfHeight;
1094 /* stock fonts ignore the mapping mode */
1095 if (!is_stock_font(hfont))
1097 POINT pts[2];
1098 pts[0].x = pts[0].y = pts[1].x = 0;
1099 pts[1].y = height;
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;
1108 return TRUE;
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;
1116 HFONT ret;
1117 LOGFONTW lf;
1118 BOOL subst = FALSE;
1119 int i;
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,
1127 (int)lf.lfWeight);
1129 if (lf.lfFaceName[0] == '\0')
1131 switch(lf.lfPitchAndFamily & 0xf0)
1133 case FF_DONTCARE:
1134 break;
1135 case FF_ROMAN:
1136 case FF_SCRIPT:
1137 wcscpy(lf.lfFaceName, timesW);
1138 break;
1139 case FF_SWISS:
1140 wcscpy(lf.lfFaceName, helveticaW);
1141 break;
1142 case FF_MODERN:
1143 wcscpy(lf.lfFaceName, courierW);
1144 break;
1145 case FF_DECORATIVE:
1146 wcscpy(lf.lfFaceName, symbolW);
1147 break;
1151 if (lf.lfFaceName[0] == '\0')
1153 switch(lf.lfPitchAndFamily & 0x0f)
1155 case VARIABLE_PITCH:
1156 wcscpy(lf.lfFaceName, timesW);
1157 break;
1158 default:
1159 wcscpy(lf.lfFaceName, courierW);
1160 break;
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);
1177 subst = TRUE;
1179 else
1181 WARN("Facename %s is too long; ignoring substitution\n",
1182 debugstr_w(font_sub[i].sub));
1184 break;
1188 pdev->escapement = lf.lfEscapement;
1190 if (!subst && ((ret = next->funcs->pSelectFont(next, hfont, aa_flags))))
1192 pdev->builtin = FALSE;
1193 return ret;
1196 select_builtin_font(pdev, hfont, &lf);
1197 next->funcs->pSelectFont(next, 0, aa_flags); /* tell next driver that we selected a device font */
1198 return hfont;
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;
1232 ENUMLOGFONTEXW lf;
1233 NEWTEXTMETRICEXW tm;
1234 const WCHAR *name;
1235 BOOL ret;
1236 UINT fm;
1237 int i;
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);
1254 if (!cur) continue;
1256 name = (WCHAR *)((char *)cur->metrics + cur->metrics->dpwszFaceName);
1257 if (wcsncmp(plf->lfFaceName, name, wcslen(name)))
1258 continue;
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)))
1263 break;
1266 else
1268 TRACE("lfFaceName = NULL\n");
1270 for (i = 0; i < devmode->installed_fonts; i++)
1272 cur = find_font_data(installed_font[i].name);
1273 if (!cur) continue;
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)))
1279 break;
1282 return ret;
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);
1288 UINT i, c;
1290 if (!pdev->builtin)
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;
1302 if (c > 0xffff)
1303 return FALSE;
1305 *buffer = floor(uv_metrics(c, pdev->font)->width * pdev->scale + 0.5);
1306 TRACE("U+%.4X: %i\n", i, *buffer);
1307 ++buffer;
1309 return TRUE;
1312 static BOOL CDECL get_text_metrics(PHYSDEV dev, TEXTMETRICW *metrics)
1314 PSDRV_PDEVICE *pdev = get_psdrv_dev(dev);
1316 if (!pdev->builtin)
1318 dev = GET_NEXT_PHYSDEV(dev, pGetTextMetrics);
1319 return dev->funcs->pGetTextMetrics(dev, metrics);
1322 memcpy(metrics, &pdev->tm, sizeof(pdev->tm));
1323 return TRUE;
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);
1329 int i;
1330 float width = 0.0;
1332 if (!pdev->builtin)
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;
1345 return TRUE;
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))
1355 return pi;
1357 return NULL;
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));
1376 return FALSE;
1380 pdev = malloc(sizeof(*pdev));
1381 if (!pdev) return NULL;
1383 pdev->devmode = malloc(pi->devmode->dmPublic.dmSize + pi->devmode->dmPublic.dmDriverExtra);
1384 if (!pdev->devmode)
1386 free(pdev);
1387 return NULL;
1390 memcpy(pdev->devmode, pi->devmode, pi->devmode->dmPublic.dmSize +
1391 pi->devmode->dmPublic.dmDriverExtra);
1392 pdev->pi = pi;
1393 pdev->log_pixels_x = pdev->devmode->default_resolution;
1394 pdev->log_pixels_y = pdev->devmode->default_resolution;
1396 if (devmode)
1398 dump_devmode(devmode);
1399 merge_devmodes(pdev->devmode, devmode, pi);
1402 update_dev_caps(pdev);
1403 NtGdiSelectFont(hdc, GetStockObject(DEVICE_DEFAULT_FONT));
1404 return pdev;
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);
1417 return TRUE;
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);
1427 return TRUE;
1430 static BOOL CDECL delete_dc(PHYSDEV dev)
1432 PSDRV_PDEVICE *pdev = get_psdrv_dev(dev);
1434 TRACE("\n");
1436 free(pdev->devmode);
1437 free(pdev);
1438 return TRUE;
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)
1460 return FALSE;
1461 size -= str - data;
1462 while (*str && size)
1464 size--;
1465 str++;
1467 return size != 0;
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);
1475 free(font_data);
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,
1514 WCHAR ret = 0;
1516 switch (cp)
1518 case 0xfff1:
1519 ret = c < ARRAY_SIZE(map_fff1) ? map_fff1[c] : 0;
1520 break;
1521 case 0xffff: /* Wine extension */
1522 ret = c;
1523 break;
1526 if (!ret && c)
1527 FIXME("unrecognized character %x in %x\n", c, cp);
1528 return ret;
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;
1538 int i, j;
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))
1544 return FALSE;
1545 if (strcmp(data + list_elem->name_off, name))
1547 list_elem++;
1548 continue;
1550 if (list_elem->off + list_elem->size > size)
1551 return FALSE;
1553 glyph_set = (const struct glyph_set *)(data + list_elem->off);
1554 if (font_data->glyph_count > glyph_set->glyph_count)
1555 return FALSE;
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)
1564 return FALSE;
1565 if (glyph_set->cp_count != 1)
1566 return FALSE;
1567 if (glyph_set->glyph_set_off + sizeof(short) * font_data->glyph_count > list_elem->size)
1568 return FALSE;
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);
1574 p++;
1577 else
1579 if (glyph_set->glyph_set_off + sizeof(short[2]) * font_data->glyph_count > list_elem->size)
1580 return FALSE;
1582 for (j = 0; j < font_data->glyph_count; j++)
1584 font_data->glyphs[j].wch = convert_ntf_cp(p[0], p[1]);
1585 p += 2;
1588 return TRUE;
1591 return FALSE;
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;
1602 const char *name;
1603 int i, j, k;
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))
1608 return FALSE;
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))
1615 return FALSE;
1616 TRACE("adding %s font\n", name);
1618 if (list_elem->size + list_elem->off > size)
1619 return FALSE;
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)
1622 return FALSE;
1623 metrics = (const IFIMETRICS *)((const char *)font_mtx + font_mtx->metrics_off);
1624 if (list_elem->off + font_mtx->metrics_off + metrics->cjThis > size)
1625 return FALSE;
1626 if (list_elem->off + font_mtx->width_off + sizeof(*width_range) * font_mtx->width_count > size)
1627 return FALSE;
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))
1630 return FALSE;
1632 if (!font_mtx->glyph_count)
1634 list_elem++;
1635 continue;
1638 font_data = calloc(sizeof(*font_data), 1);
1639 if (!font_data)
1640 return FALSE;
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);
1649 return FALSE;
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)
1660 continue;
1662 for (k = 0; k < width_range[j].count; k++)
1664 if (width_range[j].first + k >= font_data->glyph_count)
1665 break;
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);
1675 list_elem++;
1676 continue;
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);
1683 list_elem++;
1684 TRACE("%s font added\n", name);
1687 return TRUE;
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);
1704 if (!pi)
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;
1716 if (params->output)
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);
1723 return TRUE;
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)
1733 free(pi);
1736 LIST_FOR_EACH_ENTRY_SAFE(font, font_next, &fonts, struct font_data, entry)
1738 free_font_data(font);
1740 return 0;
1743 const unixlib_entry_t __wine_unix_call_funcs[] =
1745 free_printer_info,
1746 import_ntf,
1747 open_dc,
1750 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count);
1752 #ifdef _WIN64
1754 typedef ULONG PTR32;
1756 static NTSTATUS wow64_import_ntf(void *args)
1758 struct
1760 PTR32 data;
1761 int size;
1762 } const *params32 = args;
1763 struct import_ntf_params params = { ULongToPtr(params32->data), params32->size };
1765 return import_ntf(&params);
1768 static NTSTATUS wow64_open_dc(void *args)
1770 struct
1772 PTR32 device;
1773 PTR32 devmode;
1774 PTR32 output;
1775 PTR32 def_devmode;
1776 PTR32 hdc;
1777 } *params32 = args;
1778 struct open_dc_params params =
1780 ULongToPtr(params32->device),
1781 ULongToPtr(params32->devmode),
1782 ULongToPtr(params32->output),
1783 ULongToPtr(params32->def_devmode),
1786 NTSTATUS ret;
1788 ret = open_dc(&params);
1789 params32->hdc = PtrToUlong(params.hdc);
1790 return ret;
1793 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
1795 free_printer_info,
1796 wow64_import_ntf,
1797 wow64_open_dc,
1800 C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count);
1802 #endif /* _WIN64 */