summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2019-10-15 12:24:12 +0200
committerThomas Deutschmann <whissi@gentoo.org>2020-08-13 11:26:55 +0200
commite088156d5b620e5e639580dacf85c6dc13823c74 (patch)
tree57f5c025e203279944da512166c20bc0521d8ccd /devices/gdevwpr2.c
downloadghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.gz
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.bz2
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.zip
Import Ghostscript 9.50ghostscript-9.50
Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
Diffstat (limited to 'devices/gdevwpr2.c')
-rw-r--r--devices/gdevwpr2.c1643
1 files changed, 1643 insertions, 0 deletions
diff --git a/devices/gdevwpr2.c b/devices/gdevwpr2.c
new file mode 100644
index 00000000..3f834b57
--- /dev/null
+++ b/devices/gdevwpr2.c
@@ -0,0 +1,1643 @@
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/*
+ * Microsoft Windows 3.n printer driver for Ghostscript.
+ * Original version by Russell Lang and
+ * L. Peter Deutsch, Aladdin Enterprises.
+ * Modified by rjl 1995-03-29 to use BMP printer code
+ * Modified by Pierre Arnaud 1999-02-18 (see description below)
+ * Modified by lpd 1999-04-03 for compatibility with Borland C++ 4.5.
+ * Modified by Pierre Arnaud 1999-10-03 (accept b&w printing on color printers).
+ * Modified by Pierre Arnaud 1999-11-20 (accept lower resolution)
+ * Bug fixed by Pierre Arnaud 2000-03-09 (win_pr2_put_params error when is_open)
+ * Bug fixed by Pierre Arnaud 2000-03-20 (win_pr2_set_bpp did not set anti_alias)
+ * Bug fixed by Pierre Arnaud 2000-03-22 (win_pr2_set_bpp depth was wrong)
+ * Modified by Pierre Arnaud 2000-12-12 (mainly added support for Tumble)
+ * Bug fixed by Pierre Arnaud 2000-12-18 (-dQueryUser now works from cmd line)
+ */
+
+/* This driver uses the printer default size and resolution and
+ * ignores page size and resolution set using -gWIDTHxHEIGHT and
+ * -rXxY. You must still set the correct PageSize to get the
+ * correct clipping path.
+ * The code in win_pr2_getdc() does try to set the printer page
+ * size from the PostScript PageSize, but it isn't working
+ * reliably at the moment.
+ *
+ * This driver doesn't work with some Windows printer drivers.
+ * The reason is unknown. All printers to which I have access
+ * work.
+ *
+ * rjl 1997-11-20
+ */
+
+/* Additions by Pierre Arnaud (Pierre.Arnaud@opac.ch)
+ *
+ * The driver has been extended in order to provide some run-time
+ * feed-back about the default Windows printer and to give the user
+ * the opportunity to select the printer's properties before the
+ * device gets opened (and any spooling starts).
+ *
+ * The driver returns an additional property named "UserSettings".
+ * This is a dictionary which contents are valid only after setting
+ * the QueryUser property (see below). The UserSettings dict contains
+ * the following keys:
+ *
+ * DocumentRange [begin end] (int array, can be set)
+ * Defines the range of pages in the document; [1 10] would
+ * describe a document starting at page 1 and ending at page 10.
+ *
+ * SelectedRange [begin end] (int array, can be set)
+ * Defines the pages the user wants to print.
+ *
+ * MediaSize [width height] (float array, read only)
+ * Current printer's media size.
+ *
+ * Copies n (integer, can be set)
+ * User selected number of copies.
+ *
+ * PrintCopies n (integer, read only)
+ * Number of copies which must be printed by Ghostscript itself.
+ * This is still experimental.
+ *
+ * DocumentName name (string, can be set)
+ * Name to be associated with the print job.
+ *
+ * UserChangedSettings (bool, read only)
+ * Set to 'true' if the last QueryUser operation succeeded.
+ *
+ * Paper n (integer, can be set)
+ * Windows paper selection (0 = automatic).
+ *
+ * Orient n (integer, can be set)
+ * Windows paper orientation (0 = automatic).
+ *
+ * Color n (integer, can be set)
+ * Windows color (0 = automatic, 1 = monochrome, 2 = color).
+ *
+ * MaxResolution n (integer, can be set)
+ * Maximum resolution in pixels pet inch (0 = no maximum). If
+ * the printer has a higher resolution than the maximum, trim
+ * the used resolution to the best one (dpi_chosen <= dpi_max,
+ * with dpi_chosen = dpi_printer / ratio).
+ */
+
+/* Supported printer parameters are :
+ *
+ * -dBitsPerPixel=n
+ * Override what the Window printer driver returns.
+ *
+ * -dNoCancel
+ * Don't display cancel dialog box. Useful for unattended or
+ * console EXE operation.
+ *
+ * -dQueryUser=n
+ * Query user interactively for the destination printer, before
+ * the device gets opened. This fills in the UserSettings dict
+ * and the OutputFile name properties. The following values are
+ * supported for n:
+ * 1 => show standard Print dialog
+ * 2 => show Print Setup dialog instead
+ * 3 => select default printer
+ * other, does nothing
+ *
+ * The /Duplex & /Tumble keys of the setpagedevice dict are supported
+ * if the Windows printer supports duplex printing.
+ */
+
+#include "windows_.h"
+#include "gdevprn.h"
+#include "gdevpccm.h"
+#include "string_.h"
+#include <shellapi.h>
+#include "gp_mswin.h"
+
+#include "gp.h"
+#include "gpcheck.h"
+#include "commdlg.h"
+#include "gsicc_manage.h"
+
+/* Make sure we cast to the correct structure type. */
+typedef struct gx_device_win_pr2_s gx_device_win_pr2;
+
+/* Device procedures */
+
+/* See gxdevice.h for the definitions of the procedures. */
+static dev_proc_open_device(win_pr2_open);
+static dev_proc_close_device(win_pr2_close);
+static dev_proc_print_page(win_pr2_print_page);
+static dev_proc_map_rgb_color(win_pr2_map_rgb_color);
+static dev_proc_map_color_rgb(win_pr2_map_color_rgb);
+static dev_proc_get_params(win_pr2_get_params);
+static dev_proc_put_params(win_pr2_put_params);
+
+static int win_pr2_set_bpp(gx_device * dev, int depth);
+
+static const gx_device_procs win_pr2_procs =
+prn_color_params_procs(win_pr2_open, gdev_prn_output_page, win_pr2_close,
+ win_pr2_map_rgb_color, win_pr2_map_color_rgb,
+ win_pr2_get_params, win_pr2_put_params);
+
+#define PARENT_WINDOW HWND_DESKTOP
+BOOL CALLBACK CancelDlgProc(HWND, UINT, WPARAM, LPARAM);
+BOOL CALLBACK AbortProc2(HDC, int);
+
+/* The device descriptor */
+typedef struct gx_device_win_pr2_s gx_device_win_pr2;
+struct gx_device_win_pr2_s {
+ gx_device_common;
+ gx_prn_device_common;
+ HDC hdcprn;
+ bool nocancel;
+
+ int doc_page_begin; /* first page number in document */
+ int doc_page_end; /* last page number in document */
+ int user_page_begin; /* user's choice: first page to print */
+ int user_page_end; /* user's choice: last page to print */
+ int user_copies; /* user's choice: number of copies */
+ int print_copies; /* number of times GS should print each page */
+ float user_media_size[2]; /* width/height of media selected by user */
+ char doc_name[200]; /* name of document for the spooler */
+ char paper_name[64]; /* name of selected paper format */
+ bool user_icc; /* User specified device icc profile */
+ bool user_changed_settings; /* true if user validated dialog */
+ int user_paper; /* user's choice: paper format */
+ int user_orient; /* user's choice: paper orientation */
+ int user_color; /* user's choice: color format */
+ int max_dpi; /* maximum resolution in DPI */
+ int ratio; /* stretch ratio when printing */
+ int selected_bpp; /* selected bpp, memorised by win_pr2_set_bpp */
+ bool tumble; /* tumble setting (with duplex) */
+ int query_user; /* query user (-dQueryUser) */
+
+ HANDLE win32_hdevmode; /* handle to device mode information */
+ HANDLE win32_hdevnames; /* handle to device names information */
+
+ DLGPROC lpfnAbortProc;
+ DLGPROC lpfnCancelProc;
+ HWND hDlgModeless;
+
+ bool use_old_spool_name; /* user prefers old \\spool\ name */
+ gx_device_win_pr2* original_device; /* used to detect copies */
+};
+
+gx_device_win_pr2 far_data gs_mswinpr2_device =
+{
+ prn_device_std_body(gx_device_win_pr2, win_pr2_procs, "mswinpr2",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72.0, 72.0,
+ 0, 0, 0, 0,
+ 0, win_pr2_print_page), /* depth = 0 */
+ 0, /* hdcprn */
+ 0, /* nocancel */
+ 0, /* doc_page_begin */
+ 0, /* doc_page_end */
+ 0, /* user_page_begin */
+ 0, /* user_page_end */
+ 1, /* user_copies */
+ 1, /* print_copies */
+ { 0.0, 0.0 }, /* user_media_size */
+ { 0 }, /* doc_name */
+ { 0 }, /* paper_name */
+ false, /* user_icc */
+ 0, /* user_changed_settings */
+ 0, /* user_paper */
+ 0, /* user_orient */
+ 0, /* user_color */
+ 0, /* max_dpi */
+ 0, /* ratio */
+ 0, /* selected_bpp */
+ false, /* tumble */
+ -1, /* query_user */
+ NULL, /* win32_hdevmode */
+ NULL, /* win32_hdevnames */
+ NULL, /* lpfnAbortProc */
+ NULL, /* lpfnCancelProc */
+ NULL, /* hDlgModeless */
+ false, /* use_old_spool_name */
+ NULL /* original_device */
+};
+
+/********************************************************************************/
+
+static int win_pr2_getdc(gx_device_win_pr2 * dev);
+static int win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
+static int win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
+static int win_pr2_print_setup_interaction(gx_device_win_pr2 * dev, int mode);
+static int win_pr2_write_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
+static int win_pr2_read_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
+static void win_pr2_copy_check(gx_device_win_pr2 * dev);
+
+/********************************************************************************/
+
+/* Open the win_pr2 driver */
+static int
+win_pr2_open(gx_device * dev)
+{
+ int code, code1;
+ int depth;
+ PRINTDLG pd;
+ POINT offset;
+ POINT size;
+ float m[4];
+ gp_file *pfile;
+ DOCINFO docinfo;
+ float ratio = 1.0;
+ gx_device_win_pr2 *wdev = (gx_device_win_pr2 *)dev;
+
+ win_pr2_copy_check(wdev);
+
+ /* get a HDC for the printer */
+ if ((wdev->win32_hdevmode) &&
+ (wdev->win32_hdevnames)) {
+ /* The user has already had the opportunity to choose the output */
+ /* file interactively. Just use the specified parameters. */
+
+ LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
+ LPDEVNAMES devnames = (LPDEVNAMES) GlobalLock(wdev->win32_hdevnames);
+
+ const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
+ const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
+ const char* output = (char*)(devnames)+(devnames->wOutputOffset);
+
+ wdev->hdcprn = CreateDC(driver, device, output, devmode);
+
+ GlobalUnlock(wdev->win32_hdevmode);
+ GlobalUnlock(wdev->win32_hdevnames);
+
+ if (wdev->hdcprn == NULL) {
+ return_error(gs_error_Fatal);
+ }
+
+ } else if (!win_pr2_getdc(wdev)) {
+ /* couldn't get a printer from -sOutputFile= */
+ /* Prompt with dialog box */
+
+ LPDEVMODE devmode = NULL;
+ memset(&pd, 0, sizeof(pd));
+
+ pd.lStructSize = sizeof(pd);
+ pd.hwndOwner = PARENT_WINDOW;
+ pd.Flags = PD_RETURNDC;
+ pd.nMinPage = wdev->doc_page_begin;
+ pd.nMaxPage = wdev->doc_page_end;
+ pd.nFromPage = wdev->user_page_begin;
+ pd.nToPage = wdev->user_page_end;
+ pd.nCopies = wdev->user_copies;
+
+ if (!PrintDlg(&pd)) {
+ /* device not opened - exit ghostscript */
+ return_error(gs_error_Fatal); /* exit Ghostscript cleanly */
+ }
+
+ devmode = GlobalLock(pd.hDevMode);
+ win_pr2_update_dev(wdev,devmode);
+ GlobalUnlock(pd.hDevMode);
+
+ if (wdev->win32_hdevmode)
+ GlobalFree(wdev->win32_hdevmode);
+ if (wdev->win32_hdevnames)
+ GlobalFree(wdev->win32_hdevnames);
+
+ wdev->hdcprn = pd.hDC;
+ wdev->win32_hdevmode = pd.hDevMode;
+ wdev->win32_hdevnames = pd.hDevNames;
+
+ pd.hDevMode = NULL;
+ pd.hDevNames = NULL;
+ }
+ if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_DIBTODEV)) {
+ errprintf(dev->memory, "Windows printer does not have RC_DIBTODEV\n");
+ DeleteDC(wdev->hdcprn);
+ return_error(gs_error_limitcheck);
+ }
+ /* initialise printer, install abort proc */
+ wdev->lpfnAbortProc = (DLGPROC) AbortProc2;
+ SetAbortProc(wdev->hdcprn, (ABORTPROC) wdev->lpfnAbortProc);
+
+ /*
+ * Some versions of the Windows headers include lpszDatatype and fwType,
+ * and some don't. Since we want to set these fields to zero anyway,
+ * we just start by zeroing the whole structure.
+ */
+ memset(&docinfo, 0, sizeof(docinfo));
+ docinfo.cbSize = sizeof(docinfo);
+ docinfo.lpszDocName = wdev->doc_name;
+ /*docinfo.lpszOutput = NULL;*/
+ /*docinfo.lpszDatatype = NULL;*/
+ /*docinfo.fwType = 0;*/
+
+ if (docinfo.lpszDocName[0] == 0) {
+ docinfo.lpszDocName = "Ghostscript output";
+ }
+
+ if (StartDoc(wdev->hdcprn, &docinfo) <= 0) {
+ errprintf(dev->memory,
+ "Printer StartDoc failed (error %08x)\n", GetLastError());
+ DeleteDC(wdev->hdcprn);
+ return_error(gs_error_limitcheck);
+ }
+
+ dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
+ dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
+
+ wdev->ratio = 1;
+
+ if (wdev->max_dpi > 50) {
+
+ float dpi_x = dev->x_pixels_per_inch;
+ float dpi_y = dev->y_pixels_per_inch;
+
+ while ((dev->x_pixels_per_inch > wdev->max_dpi)
+ || (dev->y_pixels_per_inch > wdev->max_dpi)) {
+ ratio += 1.0;
+ wdev->ratio ++;
+ dev->x_pixels_per_inch = dpi_x / ratio;
+ dev->y_pixels_per_inch = dpi_y / ratio;
+ }
+ }
+
+ size.x = GetDeviceCaps(wdev->hdcprn, PHYSICALWIDTH);
+ size.y = GetDeviceCaps(wdev->hdcprn, PHYSICALHEIGHT);
+ gx_device_set_width_height(dev, (int)(size.x / ratio), (int)(size.y / ratio));
+ offset.x = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETX);
+ offset.y = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETY);
+
+ /* m[] gives margins in inches */
+ m[0] /*left */ = offset.x / dev->x_pixels_per_inch / ratio;
+ m[3] /*top */ = offset.y / dev->y_pixels_per_inch / ratio;
+ m[2] /*right */ = (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES)) / dev->x_pixels_per_inch / ratio;
+ m[1] /*bottom */ = (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES)) / dev->y_pixels_per_inch / ratio;
+ gx_device_set_margins(dev, m, true);
+
+ depth = dev->color_info.depth;
+ if (depth == 0) {
+ /* Set parameters that were unknown before opening device */
+ /* Find out if the device supports color */
+ /* We recognize 1, 4 (but use only 3), 8 and 24 bit color devices */
+ depth = GetDeviceCaps(wdev->hdcprn, PLANES) * GetDeviceCaps(wdev->hdcprn, BITSPIXEL);
+ }
+ code1 = win_pr2_set_bpp(dev, depth);
+
+ /* gdev_prn_open opens a temporary file which we don't want */
+ /* so we specify the name now so we can delete it later */
+ wdev->fname[0] = '\0';
+ pfile = gp_open_scratch_file(dev->memory,
+ gp_scratch_file_name_prefix,
+ wdev->fname, "wb");
+ gp_fclose(pfile);
+ code = gdev_prn_open(dev);
+
+ /* If we subclassed the device, with a FirstPage LastPage device,
+ * update the stored pointer copy here, if we don't then this whole
+ * device stops working, not sure why.
+ */
+ if (dev->child) {
+ gx_device_win_pr2 *windev;
+
+ while (dev->child)
+ dev = dev->child;
+
+ windev = (gx_device_win_pr2 *)dev;
+
+ windev->original_device = (gx_device_win_pr2 *)dev;
+ }
+
+ if ((code < 0) && wdev->fname[0])
+ unlink(wdev->fname);
+
+ if (!wdev->nocancel) {
+ /* inform user of progress with dialog box and allow cancel */
+ wdev->lpfnCancelProc = (DLGPROC) CancelDlgProc;
+ wdev->hDlgModeless = CreateDialog(phInstance, "CancelDlgBox",
+ PARENT_WINDOW, wdev->lpfnCancelProc);
+ ShowWindow(wdev->hDlgModeless, SW_HIDE);
+ }
+ if (code1 < 0 && code >= 0) {
+ code = code1;
+ }
+
+ return code;
+};
+
+/* Close the win_pr2 driver */
+static int
+win_pr2_close(gx_device * dev)
+{
+ int code;
+ int aborted = FALSE;
+ gx_device_win_pr2 *wdev = (gx_device_win_pr2 *)dev;
+
+ win_pr2_copy_check(wdev);
+
+ /* Free resources */
+
+ if (!wdev->nocancel) {
+ if (!wdev->hDlgModeless)
+ aborted = TRUE;
+ else
+ DestroyWindow(wdev->hDlgModeless);
+ wdev->hDlgModeless = 0;
+ }
+ if (aborted)
+ AbortDoc(wdev->hdcprn);
+ else
+ EndDoc(wdev->hdcprn);
+
+ DeleteDC(wdev->hdcprn);
+
+ if (wdev->win32_hdevmode != NULL) {
+ GlobalFree(wdev->win32_hdevmode);
+ wdev->win32_hdevmode = NULL;
+ }
+ if (wdev->win32_hdevnames != NULL) {
+ GlobalFree(wdev->win32_hdevnames);
+ wdev->win32_hdevnames = NULL;
+ }
+
+ code = gdev_prn_close(dev);
+
+ /* delete unwanted temporary file */
+ if (wdev->fname[0])
+ unlink(wdev->fname);
+
+ return code;
+}
+
+/* ------ Internal routines ------ */
+
+/********************************************************************************/
+
+/* ------ Private definitions ------ */
+
+/* new win_pr2_print_page routine */
+
+/* Write BMP header to memory, then send bitmap to printer */
+/* one scan line at a time */
+static int
+win_pr2_print_page(gx_device_printer * pdev, gp_file * file)
+{
+ int raster = gdev_prn_raster(pdev);
+
+ /* BMP scan lines are padded to 32 bits. */
+ ulong bmp_raster = raster + (-raster & 3);
+ ulong bmp_raster_multi;
+ int scan_lines, yslice, lines, i;
+ int width;
+ int depth = pdev->color_info.depth;
+ byte *row;
+ int y;
+ int code = 0; /* return code */
+ MSG msg;
+ char dlgtext[32];
+ HGLOBAL hrow;
+ int ratio = ((gx_device_win_pr2 *)pdev)->ratio;
+ gx_device_win_pr2 *wdev = (gx_device_win_pr2 *)pdev;
+
+ struct bmi_s {
+ BITMAPINFOHEADER h;
+ RGBQUAD pal[256];
+ } bmi;
+
+ scan_lines = dev_print_scan_lines(pdev);
+ width = (int)(pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
+ dev_x_offset(pdev)) * pdev->x_pixels_per_inch));
+
+ yslice = 65535 / bmp_raster; /* max lines in 64k */
+ bmp_raster_multi = bmp_raster * yslice;
+ hrow = GlobalAlloc(0, bmp_raster_multi);
+ row = GlobalLock(hrow);
+ if (row == 0) /* can't allocate row buffer */
+ return_error(gs_error_VMerror);
+
+ /* Write the info header. */
+
+ bmi.h.biSize = sizeof(bmi.h);
+ bmi.h.biWidth = pdev->width; /* wdev->mdev.width; */
+ bmi.h.biHeight = yslice;
+ bmi.h.biPlanes = 1;
+ bmi.h.biBitCount = pdev->color_info.depth;
+ bmi.h.biCompression = 0;
+ bmi.h.biSizeImage = 0; /* default */
+ bmi.h.biXPelsPerMeter = 0; /* default */
+ bmi.h.biYPelsPerMeter = 0; /* default */
+
+ StartPage(wdev->hdcprn);
+
+ /* Write the palette. */
+
+ if (depth <= 8) {
+ int i;
+ gx_color_value rgb[3];
+ LPRGBQUAD pq;
+
+ bmi.h.biClrUsed = 1 << depth;
+ bmi.h.biClrImportant = 1 << depth;
+ for (i = 0; i != 1 << depth; i++) {
+ (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
+ (gx_color_index) i, rgb);
+ pq = &bmi.pal[i];
+ pq->rgbRed = gx_color_value_to_byte(rgb[0]);
+ pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
+ pq->rgbBlue = gx_color_value_to_byte(rgb[2]);
+ pq->rgbReserved = 0;
+ }
+ } else {
+ bmi.h.biClrUsed = 0;
+ bmi.h.biClrImportant = 0;
+ }
+
+ if (!wdev->nocancel) {
+ gs_sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount) + 1);
+ SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PRINTING), dlgtext);
+ ShowWindow(wdev->hDlgModeless, SW_SHOW);
+ }
+ for (y = 0; y < scan_lines;) {
+ /* copy slice to row buffer */
+ if (y > scan_lines - yslice)
+ lines = scan_lines - y;
+ else
+ lines = yslice;
+ for (i = 0; i < lines; i++)
+ gdev_prn_copy_scan_lines(pdev, y + i,
+ row + (bmp_raster * (lines - 1 - i)), raster);
+
+ if (ratio > 1) {
+ StretchDIBits(wdev->hdcprn, 0, y*ratio, pdev->width*ratio, lines*ratio,
+ 0, 0, pdev->width, lines,
+ row,
+ (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS, SRCCOPY);
+ } else {
+ SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
+ 0, 0, 0, lines,
+ row,
+ (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS);
+ }
+ y += lines;
+
+ if (!wdev->nocancel) {
+ /* inform user of progress */
+ gs_sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
+ SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE), dlgtext);
+ }
+ /* process message loop */
+ while (PeekMessage(&msg, wdev->hDlgModeless, 0, 0, PM_REMOVE)) {
+ if ((wdev->hDlgModeless == 0) || !IsDialogMessage(wdev->hDlgModeless, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ if ((!wdev->nocancel) && (wdev->hDlgModeless == 0)) {
+ /* user pressed cancel button */
+ break;
+ }
+ }
+
+ if ((!wdev->nocancel) && (wdev->hDlgModeless == 0))
+ code = gs_error_Fatal; /* exit Ghostscript cleanly */
+ else {
+ /* push out the page */
+ if (!wdev->nocancel)
+ SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE),
+ "Ejecting page...");
+ EndPage(wdev->hdcprn);
+ if (!wdev->nocancel)
+ ShowWindow(wdev->hDlgModeless, SW_HIDE);
+ }
+
+ GlobalUnlock(hrow);
+ GlobalFree(hrow);
+
+ return code;
+}
+
+/* combined color mappers */
+
+/* 24-bit color mappers (taken from gdevmem2.c). */
+/* Note that Windows expects RGB values in the order B,G,R. */
+
+/* Map a r-g-b color to a color index. */
+static gx_color_index
+win_pr2_map_rgb_color(gx_device * dev, const gx_color_value cv[])
+{
+ gx_color_value r = cv[0];
+ gx_color_value g = cv[1];
+ gx_color_value b = cv[2];
+ switch (dev->color_info.depth) {
+ case 1:
+ return gdev_prn_map_rgb_color(dev, cv);
+ case 4:
+ /* use only 8 colors */
+ return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
+ (g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
+ (b > (gx_max_color_value / 2 + 1) ? 1 : 0);
+ case 8:
+ return pc_8bit_map_rgb_color(dev, cv);
+ case 24:
+ return gx_color_value_to_byte(r) +
+ ((uint) gx_color_value_to_byte(g) << 8) +
+ ((ulong) gx_color_value_to_byte(b) << 16);
+ }
+ return 0; /* error */
+}
+
+/* Map a color index to a r-g-b color. */
+static int
+win_pr2_map_color_rgb(gx_device * dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+ switch (dev->color_info.depth) {
+ case 1:
+ gdev_prn_map_color_rgb(dev, color, prgb);
+ break;
+ case 4:
+ /* use only 8 colors */
+ prgb[0] = (color & 4) ? gx_max_color_value : 0;
+ prgb[1] = (color & 2) ? gx_max_color_value : 0;
+ prgb[2] = (color & 1) ? gx_max_color_value : 0;
+ break;
+ case 8:
+ pc_8bit_map_color_rgb(dev, color, prgb);
+ break;
+ case 24:
+ prgb[2] = gx_color_value_from_byte(color >> 16);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[0] = gx_color_value_from_byte(color & 0xff);
+ break;
+ }
+ return 0;
+}
+
+static int
+win_pr2_set_bpp(gx_device * dev, int depth)
+{
+ int code = 0;
+ gx_device_printer *pdev = (gx_device_printer *)dev;
+ gx_device_win_pr2 *wdev = (gx_device_win_pr2 *)pdev;
+
+ if (depth > 8) {
+ static const gx_device_color_info win_pr2_24color = dci_std_color(24);
+
+ dev->color_info = win_pr2_24color;
+ depth = 24;
+
+ if (!wdev->user_icc && (!wdev->icc_struct || (wdev->icc_struct &&
+ wdev->icc_struct->device_profile[gsDEFAULTPROFILE]->data_cs != gsRGB))) {
+
+ if (wdev->icc_struct) {
+ rc_decrement(wdev->icc_struct, "win_pr2_set_bpp");
+ }
+ wdev->icc_struct = gsicc_new_device_profile_array(wdev->memory);
+
+ if (wdev->icc_struct) {
+ code = gsicc_set_device_profile(dev, dev->memory,
+ (char *)DEFAULT_RGB_ICC, gsDEFAULTPROFILE);
+ }
+ else {
+ code = gs_error_VMerror;
+ }
+ }
+
+ } else if (depth >= 8) {
+ /* 8-bit (SuperVGA-style) color. */
+ /* (Uses a fixed palette of 3,3,2 bits.) */
+ static const gx_device_color_info win_pr2_8color = dci_pc_8bit;
+
+ dev->color_info = win_pr2_8color;
+ depth = 8;
+
+ if (!wdev->user_icc && (!wdev->icc_struct || (wdev->icc_struct &&
+ wdev->icc_struct->device_profile[gsDEFAULTPROFILE]->data_cs != gsRGB))) {
+
+ if (wdev->icc_struct) {
+ rc_decrement(wdev->icc_struct, "win_pr2_set_bpp");
+ }
+ wdev->icc_struct = gsicc_new_device_profile_array(wdev->memory);
+
+ if (wdev->icc_struct) {
+ code = gsicc_set_device_profile(dev, dev->memory,
+ (char *)DEFAULT_RGB_ICC, gsDEFAULTPROFILE);
+ }
+ else {
+ code = gs_error_VMerror;
+ }
+ }
+ } else if (depth >= 3) {
+ /* 3 plane printer */
+ /* suitable for impact dot matrix CMYK printers */
+ /* create 4-bit bitmap, but only use 8 colors */
+ static const gx_device_color_info win_pr2_4color = dci_values(3, 4, 1, 1, 2, 2);
+
+ dev->color_info = win_pr2_4color;
+ depth = 4;
+
+ if (!wdev->user_icc && (!wdev->icc_struct || (wdev->icc_struct &&
+ wdev->icc_struct->device_profile[gsDEFAULTPROFILE]->data_cs != gsCMYK))) {
+
+ if (wdev->icc_struct) {
+ rc_decrement(wdev->icc_struct, "win_pr2_set_bpp");
+ }
+ wdev->icc_struct = gsicc_new_device_profile_array(wdev->memory);
+
+ if (wdev->icc_struct) {
+ code = gsicc_set_device_profile(dev, dev->memory,
+ (char *)DEFAULT_CMYK_ICC, gsDEFAULTPROFILE);
+ }
+ else {
+ code = gs_error_VMerror;
+ }
+ }
+ } else { /* default is black_and_white */
+ static const gx_device_color_info win_pr2_1color = dci_std_color(1);
+
+ dev->color_info = win_pr2_1color;
+ depth = 1;
+
+ if (!wdev->user_icc && (!wdev->icc_struct || (wdev->icc_struct &&
+ wdev->icc_struct->device_profile[gsDEFAULTPROFILE]->data_cs != gsGRAY))) {
+
+ if (wdev->icc_struct) {
+ rc_decrement(wdev->icc_struct, "win_pr2_set_bpp");
+ }
+ wdev->icc_struct = gsicc_new_device_profile_array(wdev->memory);
+
+ if (wdev->icc_struct) {
+ code = gsicc_set_device_profile(dev, dev->memory,
+ (char *)DEFAULT_GRAY_ICC, gsDEFAULTPROFILE);
+ }
+ else {
+ code = gs_error_VMerror;
+ }
+ }
+ }
+
+ wdev->selected_bpp = depth;
+
+ /* copy encode/decode procedures */
+ set_dev_proc(dev, encode_color, dev_proc(dev, map_rgb_color));
+ set_dev_proc(dev, decode_color, dev_proc(dev, map_color_rgb));
+ if (depth == 1) {
+ set_dev_proc(dev, get_color_mapping_procs,
+ gx_default_DevGray_get_color_mapping_procs);
+ set_dev_proc(dev, get_color_comp_index,
+ gx_default_DevGray_get_color_comp_index);
+ }
+ else {
+ set_dev_proc(dev, get_color_mapping_procs,
+ gx_default_DevRGB_get_color_mapping_procs);
+ set_dev_proc(dev, get_color_comp_index,
+ gx_default_DevRGB_get_color_comp_index);
+ }
+ return(code);
+}
+
+/********************************************************************************/
+
+/* Get device parameters */
+int
+win_pr2_get_params(gx_device * pdev, gs_param_list * plist)
+{
+ int code = gdev_prn_get_params(pdev, plist);
+ gx_device_win_pr2 *wdev = (gx_device_win_pr2 *)pdev;
+
+ win_pr2_copy_check(wdev);
+
+ if (code >= 0)
+ code = param_write_bool(plist, "NoCancel",
+ &(wdev->nocancel));
+ if (code >= 0)
+ code = param_write_int(plist, "QueryUser",
+ &(wdev->query_user));
+ if (code >= 0)
+ code = win_pr2_write_user_settings(wdev, plist);
+
+ if ((code >= 0) && (wdev->Duplex_set > 0))
+ code = param_write_bool(plist, "Tumble",
+ &(wdev->tumble));
+
+ return code;
+}
+
+/* We implement this ourselves so that we can change BitsPerPixel */
+/* before the device is opened */
+int
+win_pr2_put_params(gx_device * pdev, gs_param_list * plist)
+{
+ int ecode = 0, code;
+ int old_bpp = pdev->color_info.depth;
+ int bpp = old_bpp;
+ gx_device_win_pr2 *wdev = (gx_device_win_pr2 *)pdev;
+ bool tumble = wdev->tumble;
+ bool nocancel = wdev->nocancel;
+ int queryuser = 0;
+ bool old_duplex = wdev->Duplex;
+ bool old_tumble = wdev->tumble;
+ int old_orient = wdev->user_orient;
+ int old_color = wdev->user_color;
+ int old_paper = wdev->user_paper;
+ int old_mx_dpi = wdev->max_dpi;
+
+ if (wdev->Duplex_set < 0) {
+ wdev->Duplex_set = 0;
+ wdev->Duplex = false;
+ wdev->tumble = false;
+ }
+
+ win_pr2_copy_check(wdev);
+
+ code = win_pr2_read_user_settings(wdev, plist);
+
+ switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
+ case 0:
+ if (pdev->is_open) {
+ if (wdev->selected_bpp == bpp) {
+ break;
+ }
+ ecode = gs_error_rangecheck;
+ } else { /* change dev->color_info is valid before device is opened */
+ code = win_pr2_set_bpp(pdev, bpp);
+ if (code < 0) {
+ ecode = code;
+ }
+ break;
+ }
+ goto bppe;
+ default:
+ ecode = code;
+ bppe:param_signal_error(plist, "BitsPerPixel", ecode);
+ case 1:
+ break;
+ }
+
+ switch (code = param_read_bool(plist, "NoCancel", &nocancel)) {
+ case 0:
+ if (pdev->is_open) {
+ if (wdev->nocancel == nocancel) {
+ break;
+ }
+ ecode = gs_error_rangecheck;
+ } else {
+ wdev->nocancel = nocancel;
+ break;
+ }
+ goto nocancele;
+ default:
+ ecode = code;
+ nocancele:param_signal_error(plist, "NoCancel", ecode);
+ case 1:
+ break;
+ }
+
+ switch (code = param_read_bool(plist, "Tumble", &tumble)) {
+ case 0:
+ wdev->tumble = tumble;
+ break;
+ default:
+ ecode = code;
+ param_signal_error(plist, "Tumble", ecode);
+ case 1:
+ break;
+ }
+
+ switch (code = param_read_int(plist, "QueryUser", &queryuser)) {
+ case 0:
+ if ((queryuser > 0) &&
+ (queryuser < 4)) {
+ win_pr2_print_setup_interaction(wdev, queryuser);
+ }
+ break;
+ default:
+ ecode = code;
+ param_signal_error(plist, "QueryUser", ecode);
+ case 1:
+ break;
+ }
+
+ /* Record if the user has specified a custom profile, so we don't replace it
+ with a default when we change color space - see win_pr2_set_bpp()
+ Here, we only want to know *if* we have a user specced profile, actually
+ setting it will be handled by gdev_prn_put_params()
+ */
+ if (!wdev->user_icc) {
+ gs_param_string icc_pro_dummy;
+
+ wdev->user_icc = param_read_string(plist, "OutputICCProfile", &icc_pro_dummy) == 0;
+ }
+
+ if (ecode >= 0)
+ ecode = gdev_prn_put_params(pdev, plist);
+
+ if (wdev->win32_hdevmode && wdev->hdcprn) {
+ if ( (old_duplex != wdev->Duplex)
+ || (old_tumble != wdev->tumble)
+ || (old_orient != wdev->user_orient)
+ || (old_color != wdev->user_color)
+ || (old_paper != wdev->user_paper)
+ || (old_mx_dpi != wdev->max_dpi) ) {
+
+ LPDEVMODE pdevmode = GlobalLock(wdev->win32_hdevmode);
+
+ if (pdevmode) {
+ win_pr2_update_win(wdev, pdevmode);
+ ResetDC(wdev->hdcprn, pdevmode);
+ GlobalUnlock(pdevmode);
+ }
+ }
+ }
+
+ return ecode;
+}
+
+/********************************************************************************/
+
+/* Get Device Context for printer */
+static int
+win_pr2_getdc(gx_device_win_pr2 * wdev)
+{
+ char *device;
+ char driverbuf[512], *dbuflast = NULL;
+ char *driver;
+ char *output;
+ char *devcap;
+ int devcapsize;
+ int devmode_size;
+
+ int i, n;
+ POINT *pp;
+ int paperindex;
+ int paperwidth, paperheight;
+ int orientation;
+ int papersize;
+ char papername[64];
+ LPDEVMODE podevmode, pidevmode;
+ HANDLE hprinter;
+
+ /* first try to derive the printer name from -sOutputFile= */
+ /* is printer if name prefixed by \\spool\ or by %printer% */
+ if (is_spool(wdev->fname)) {
+ device = wdev->fname + 8; /* skip over \\spool\ */
+ wdev->use_old_spool_name = true;
+ } else if (strncmp("%printer%",wdev->fname,9) == 0) {
+ device = wdev->fname + 9; /* skip over %printer% */
+ wdev->use_old_spool_name = false;
+ } else {
+ return FALSE;
+ }
+
+ /* now try to match the printer name against the [Devices] section */
+ {
+ wchar_t unidrvbuf[sizeof(driverbuf)];
+ wchar_t *devices;
+ wchar_t *p;
+ int devices_size = 128, returned_length = 0;
+ wchar_t *unidev = malloc(utf8_to_wchar(NULL, device)*sizeof(wchar_t));
+ if (unidev == NULL)
+ return FALSE;
+ utf8_to_wchar(unidev, device);
+ do {
+ devices = gs_malloc(wdev->memory, devices_size, 1, "win_pr2_getdc");
+ if (devices == (wchar_t *)NULL) {
+ free(unidev);
+ return FALSE;
+ }
+ returned_length = GetProfileStringW(L"Devices", NULL, L"", devices, devices_size / sizeof(wchar_t));
+ returned_length *= sizeof(wchar_t);
+ if (returned_length >= devices_size - 2 * sizeof(wchar_t)) {
+ gs_free(wdev->memory, devices, devices_size, 1, "win_pr2_getdc");
+ devices_size += 4096;
+ }
+ else
+ break;
+ } while (1);
+ p = devices;
+ while (*p) {
+ if (wcsicmp(p, unidev) == 0)
+ break;
+ p += wcslen(p) + 1;
+ }
+ if (*p == '\0')
+ p = NULL;
+ gs_free(wdev->memory, devices, devices_size, 1, "win_pr2_getdc");
+ if (p == NULL) {
+ free(unidev);
+ return FALSE; /* doesn't match an available printer */
+ }
+
+ /* the printer exists, get the remaining information from win.ini */
+ GetProfileStringW(L"Devices", unidev, L"", unidrvbuf, sizeof(unidrvbuf));
+ free(unidev);
+ i = wchar_to_utf8(NULL, unidrvbuf);
+ if (i < 0 || i > sizeof(driverbuf))
+ return FALSE;
+ wchar_to_utf8(driverbuf, unidrvbuf);
+ }
+ driver = gs_strtok(driverbuf, ",", &dbuflast);
+ output = gs_strtok(NULL, ",", &dbuflast);
+
+ if (!gp_OpenPrinter(device, &hprinter))
+ return FALSE;
+ devmode_size = DocumentProperties(NULL, hprinter, device, NULL, NULL, 0);
+ if ((podevmode = gs_malloc(wdev->memory, devmode_size, 1, "win_pr2_getdc"))
+ == (LPDEVMODE) NULL) {
+ ClosePrinter(hprinter);
+ return FALSE;
+ }
+ if ((pidevmode = gs_malloc(wdev->memory, devmode_size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
+ gs_free(wdev->memory, podevmode, devmode_size, 1, "win_pr2_getdc");
+ ClosePrinter(hprinter);
+ return FALSE;
+ }
+ DocumentProperties(NULL, hprinter, device, podevmode, NULL, DM_OUT_BUFFER);
+
+ /* now find out what paper sizes are available */
+ devcapsize = DeviceCapabilities(device, output, DC_PAPERSIZE, NULL, NULL);
+ devcapsize *= sizeof(POINT);
+ if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
+ return FALSE;
+ n = DeviceCapabilities(device, output, DC_PAPERSIZE, devcap, NULL);
+ paperwidth = (int)(wdev->MediaSize[0] * 254 / 72);
+ paperheight = (int)(wdev->MediaSize[1] * 254 / 72);
+ papername[0] = '\0';
+ papersize = 0;
+ paperindex = -1;
+ orientation = 0;
+ pp = (POINT *) devcap;
+ for (i = 0; i < n; i++, pp++) {
+ if ((pp->x < paperwidth + 20) && (pp->x > paperwidth - 20) &&
+ (pp->y < paperheight + 20) && (pp->y > paperheight - 20)) {
+ paperindex = i;
+ paperwidth = pp->x;
+ paperheight = pp->y;
+ orientation = DMORIENT_PORTRAIT;
+ break;
+ }
+ }
+ if (paperindex < 0) {
+ /* try again in landscape */
+ pp = (POINT *) devcap;
+ for (i = 0; i < n; i++, pp++) {
+ if ((pp->x < paperheight + 20) && (pp->x > paperheight - 20) &&
+ (pp->y < paperwidth + 20) && (pp->y > paperwidth - 20)) {
+ paperindex = i;
+ paperwidth = pp->x;
+ paperheight = pp->y;
+ orientation = DMORIENT_LANDSCAPE;
+ break;
+ }
+ }
+ }
+ gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
+
+ /* get the dmPaperSize */
+ devcapsize = DeviceCapabilities(device, output, DC_PAPERS, NULL, NULL);
+ devcapsize *= sizeof(WORD);
+ if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
+ return FALSE;
+ n = DeviceCapabilities(device, output, DC_PAPERS, devcap, NULL);
+ if ((paperindex >= 0) && (paperindex < n))
+ papersize = ((WORD *) devcap)[paperindex];
+ gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
+
+ /* get the paper name */
+ devcapsize = DeviceCapabilities(device, output, DC_PAPERNAMES, NULL, NULL);
+ devcapsize *= 64;
+ if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
+ return FALSE;
+ n = DeviceCapabilities(device, output, DC_PAPERNAMES, devcap, NULL);
+ if ((paperindex >= 0) && (paperindex < n))
+ strcpy(papername, devcap + paperindex * 64);
+ gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
+
+ memcpy(pidevmode, podevmode, devmode_size);
+
+ pidevmode->dmFields = 0;
+
+ wdev->paper_name[0] = 0;
+
+ if ( (wdev->user_paper)
+ && (wdev->user_paper != papersize) ) {
+ papersize = wdev->user_paper;
+ paperheight = 0;
+ paperwidth = 0;
+ papername[0] = 0;
+ }
+ if (wdev->user_orient) {
+ orientation = wdev->user_orient;
+ }
+
+ pidevmode->dmFields &= ~(DM_PAPERSIZE | DM_ORIENTATION | DM_COLOR | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_DUPLEX);
+ pidevmode->dmFields |= DM_DEFAULTSOURCE;
+ pidevmode->dmDefaultSource = 0;
+
+ if (orientation) {
+ wdev->user_orient = orientation;
+ }
+ if (papersize) {
+ wdev->user_paper = papersize;
+ strcpy (wdev->paper_name, papername);
+ }
+
+ if (paperheight && paperwidth) {
+ pidevmode->dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH);
+ pidevmode->dmPaperWidth = paperwidth;
+ pidevmode->dmPaperLength = paperheight;
+ wdev->user_media_size[0] = paperwidth / 254.0 * 72.0;
+ wdev->user_media_size[1] = paperheight / 254.0 * 72.0;
+ }
+
+ if (DeviceCapabilities(device, output, DC_DUPLEX, NULL, NULL)) {
+ wdev->Duplex_set = 1;
+ }
+
+ win_pr2_update_win(wdev, pidevmode);
+
+ /* merge the entries */
+ DocumentProperties(NULL, hprinter, device, podevmode, pidevmode, DM_IN_BUFFER | DM_OUT_BUFFER);
+ ClosePrinter(hprinter);
+
+ /* now get a DC */
+ wdev->hdcprn = CreateDC(driver, device, NULL, podevmode);
+
+ if (wdev->win32_hdevmode == NULL)
+ wdev->win32_hdevmode = GlobalAlloc(0, devmode_size);
+
+ if (wdev->win32_hdevmode) {
+ LPDEVMODE pdevmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
+ if (pdevmode) {
+ memcpy(pdevmode, podevmode, devmode_size);
+ GlobalUnlock(wdev->win32_hdevmode);
+ }
+ }
+
+ gs_free(wdev->memory, pidevmode, devmode_size, 1, "win_pr2_getdc");
+ gs_free(wdev->memory, podevmode, devmode_size, 1, "win_pr2_getdc");
+
+ if (wdev->hdcprn != (HDC) NULL)
+ return TRUE; /* success */
+
+ /* fall back to prompting user */
+ return FALSE;
+}
+
+/*
+ * Minimalist update of the wdev parameters (mainly for the
+ * UserSettings parameters).
+ */
+
+static int
+win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
+{
+ if (pdevmode == 0)
+ return FALSE;
+
+ if (pdevmode->dmFields & DM_COLOR) {
+ dev->user_color = pdevmode->dmColor;
+ }
+ if (pdevmode->dmFields & DM_ORIENTATION) {
+ dev->user_orient = pdevmode->dmOrientation;
+ }
+ if (pdevmode->dmFields & DM_PAPERSIZE) {
+ dev->user_paper = pdevmode->dmPaperSize;
+ dev->user_media_size[0] = pdevmode->dmPaperWidth / 254.0 * 72.0;
+ dev->user_media_size[1] = pdevmode->dmPaperLength / 254.0 * 72.0;
+ dev->paper_name[0] = 0; /* unknown paper size */
+ }
+ if (pdevmode->dmFields & DM_DUPLEX) {
+ dev->Duplex_set = 1;
+ dev->Duplex = pdevmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
+ dev->tumble = pdevmode->dmDuplex == DMDUP_HORIZONTAL ? true : false;
+ }
+
+ return TRUE;
+}
+
+static int
+win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
+{
+ if (dev->Duplex_set > 0) {
+ pdevmode->dmFields |= DM_DUPLEX;
+ pdevmode->dmDuplex = DMDUP_SIMPLEX;
+ if (dev->Duplex) {
+ if (dev->tumble == false) {
+ pdevmode->dmDuplex = DMDUP_VERTICAL;
+ } else {
+ pdevmode->dmDuplex = DMDUP_HORIZONTAL;
+ }
+ }
+ }
+
+ if (dev->user_color) {
+ pdevmode->dmColor = dev->user_color;
+ pdevmode->dmFields |= DM_COLOR;
+ }
+
+ if (dev->user_orient) {
+ pdevmode->dmFields |= DM_ORIENTATION;
+ pdevmode->dmOrientation = dev->user_orient;
+ }
+
+ if (dev->user_paper) {
+ pdevmode->dmFields |= DM_PAPERSIZE;
+ pdevmode->dmPaperSize = dev->user_paper;
+ }
+ return 0;
+}
+
+/********************************************************************************/
+
+#define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
+ switch ( code = pread(dict.list, (param_name = pname), &(pa)) )\
+ {\
+ case 0:\
+ if ( (pa).size != psize )\
+ ecode = gs_note_error(gs_error_rangecheck);\
+ else {
+/* The body of the processing code goes here. */
+/* If it succeeds, it should do a 'break'; */
+/* if it fails, it should set ecode and fall through. */
+#define END_ARRAY_PARAM(pa, e)\
+ }\
+ goto e;\
+ default:\
+ ecode = code;\
+e: param_signal_error(dict.list, param_name, ecode);\
+ case 1:\
+ (pa).data = 0; /* mark as not filled */\
+ }
+
+/* Put the user params from UserSettings into our */
+/* internal variables. */
+static int
+win_pr2_read_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
+{
+ gs_param_dict dict;
+ gs_param_string docn = { 0 };
+ const char* dict_name = "UserSettings";
+ const char* param_name = "";
+ int code = 0;
+ int ecode = 0;
+
+ switch (code = param_begin_read_dict(plist, dict_name, &dict, false)) {
+ default:
+ param_signal_error(plist, dict_name, code);
+ return code;
+ case 1:
+ break;
+ case 0:
+ {
+ gs_param_int_array ia;
+
+ BEGIN_ARRAY_PARAM(param_read_int_array, "DocumentRange", ia, 2, ia)
+ if ((ia.data[0] < 0) ||
+ (ia.data[1] < 0) ||
+ (ia.data[0] > ia.data[1]))
+ ecode = gs_note_error(gs_error_rangecheck);
+ wdev->doc_page_begin = ia.data[0];
+ wdev->doc_page_end = ia.data[1];
+ END_ARRAY_PARAM(ia, doc_range_error)
+
+ BEGIN_ARRAY_PARAM(param_read_int_array, "SelectedRange", ia, 2, ia)
+ if ((ia.data[0] < 0) ||
+ (ia.data[1] < 0) ||
+ (ia.data[0] > ia.data[1]))
+ ecode = gs_note_error(gs_error_rangecheck);
+ wdev->user_page_begin = ia.data[0];
+ wdev->user_page_end = ia.data[1];
+ END_ARRAY_PARAM(ia, sel_range_error)
+
+ param_read_int(dict.list, "Copies", &wdev->user_copies);
+ param_read_int(dict.list, "Paper", &wdev->user_paper);
+ param_read_int(dict.list, "Orientation", &wdev->user_orient);
+ param_read_int(dict.list, "Color", &wdev->user_color);
+ param_read_int(dict.list, "MaxResolution", &wdev->max_dpi);
+
+ switch (code = param_read_string(dict.list, (param_name = "DocumentName"), &docn)) {
+ case 0:
+ if (docn.size < sizeof(wdev->doc_name))
+ break;
+ code = gs_error_rangecheck;
+ /* fall through */
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ /* fall through */
+ case 1:
+ docn.data = 0;
+ break;
+ }
+
+ param_end_read_dict(plist, dict_name, &dict);
+
+ if (docn.data) {
+ memcpy(wdev->doc_name, docn.data, docn.size);
+ wdev->doc_name[docn.size] = 0;
+ }
+
+ wdev->print_copies = 1;
+
+ if (wdev->win32_hdevmode) {
+ LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
+ if (devmode) {
+ devmode->dmCopies = wdev->user_copies;
+ devmode->dmPaperSize = wdev->user_paper;
+ devmode->dmOrientation = wdev->user_orient;
+ devmode->dmColor = wdev->user_color;
+ GlobalUnlock(wdev->win32_hdevmode);
+ }
+ }
+ }
+ break;
+ }
+
+ return code;
+}
+
+static int
+win_pr2_write_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
+{
+ gs_param_dict dict;
+ gs_param_int_array range;
+ gs_param_float_array box;
+ gs_param_string docn;
+ gs_param_string papn;
+ int array[2];
+ const char* pname = "UserSettings";
+ int code;
+
+ dict.size = 12;
+ code = param_begin_write_dict(plist, pname, &dict, false);
+ if (code < 0) return code;
+
+ array[0] = wdev->doc_page_begin;
+ array[1] = wdev->doc_page_end;
+ range.data = array;
+ range.size = 2;
+ range.persistent = false;
+ code = param_write_int_array(dict.list, "DocumentRange", &range);
+ if (code < 0) goto error;
+
+ array[0] = wdev->user_page_begin;
+ array[1] = wdev->user_page_end;
+ range.data = array;
+ range.size = 2;
+ range.persistent = false;
+ code = param_write_int_array(dict.list, "SelectedRange", &range);
+ if (code < 0) goto error;
+
+ box.data = wdev->user_media_size;
+ box.size = 2;
+ box.persistent = false;
+ code = param_write_float_array(dict.list, "MediaSize", &box);
+ if (code < 0) goto error;
+
+ code = param_write_int(dict.list, "Copies", &wdev->user_copies);
+ if (code < 0) goto error;
+
+ code = param_write_int(dict.list, "Paper", &wdev->user_paper);
+ if (code < 0) goto error;
+
+ code = param_write_int(dict.list, "Orientation", &wdev->user_orient);
+ if (code < 0) goto error;
+
+ code = param_write_int(dict.list, "Color", &wdev->user_color);
+ if (code < 0) goto error;
+
+ code = param_write_int(dict.list, "MaxResolution", &wdev->max_dpi);
+ if (code < 0) goto error;
+
+ code = param_write_int(dict.list, "PrintCopies", &wdev->print_copies);
+ if (code < 0) goto error;
+
+ docn.data = (const byte*)wdev->doc_name;
+ docn.size = strlen(wdev->doc_name);
+ docn.persistent = false;
+
+ code = param_write_string(dict.list, "DocumentName", &docn);
+ if (code < 0) goto error;
+
+ papn.data = (const byte*)wdev->paper_name;
+ papn.size = strlen(wdev->paper_name);
+ papn.persistent = false;
+
+ code = param_write_string(dict.list, "PaperName", &papn);
+ if (code < 0) goto error;
+
+ code = param_write_bool(dict.list, "UserChangedSettings", &wdev->user_changed_settings);
+
+error:
+ param_end_write_dict(plist, pname, &dict);
+ return code;
+}
+
+/********************************************************************************/
+
+/* Show up a dialog for the user to choose a printer and a paper size.
+ * If mode == 3, then automatically select the default Windows printer
+ * instead of asking the user.
+ */
+
+static int
+win_pr2_print_setup_interaction(gx_device_win_pr2 * wdev, int mode)
+{
+ PRINTDLG pd;
+ LPDEVMODE devmode;
+ LPDEVNAMES devnames;
+
+ wdev->user_changed_settings = FALSE;
+ wdev->query_user = mode;
+
+ memset(&pd, 0, sizeof(pd));
+ pd.lStructSize = sizeof(pd);
+ pd.hwndOwner = PARENT_WINDOW;
+
+ switch (mode) {
+ case 2: pd.Flags = PD_PRINTSETUP; break;
+ case 3: pd.Flags = PD_RETURNDEFAULT; break;
+ default: pd.Flags = 0; break;
+ }
+
+ pd.Flags |= PD_USEDEVMODECOPIES;
+
+ pd.nMinPage = wdev->doc_page_begin;
+ pd.nMaxPage = wdev->doc_page_end;
+ pd.nFromPage = wdev->user_page_begin;
+ pd.nToPage = wdev->user_page_end;
+ pd.nCopies = wdev->user_copies;
+
+ /* Show the Print Setup dialog and let the user choose a printer
+ * and a paper size/orientation.
+ */
+
+ if (!PrintDlg(&pd)) return FALSE;
+
+ devmode = (LPDEVMODE) GlobalLock(pd.hDevMode);
+ devnames = (LPDEVNAMES) GlobalLock(pd.hDevNames);
+
+ wdev->user_changed_settings = TRUE;
+ if (wdev->use_old_spool_name) {
+ gs_sprintf(wdev->fname, "\\\\spool\\%s", (char*)(devnames)+(devnames->wDeviceOffset));
+ } else {
+ gs_sprintf(wdev->fname, "%%printer%%%s", (char*)(devnames)+(devnames->wDeviceOffset));
+ }
+
+ if (mode == 3) {
+ devmode->dmCopies = wdev->user_copies * wdev->print_copies;
+ pd.nCopies = 1;
+ }
+
+ wdev->user_page_begin = pd.nFromPage;
+ wdev->user_page_end = pd.nToPage;
+ wdev->user_copies = devmode->dmCopies;
+ wdev->print_copies = pd.nCopies;
+ wdev->user_media_size[0] = devmode->dmPaperWidth / 254.0 * 72.0;
+ wdev->user_media_size[1] = devmode->dmPaperLength / 254.0 * 72.0;
+ wdev->user_paper = devmode->dmPaperSize;
+ wdev->user_orient = devmode->dmOrientation;
+ wdev->user_color = devmode->dmColor;
+
+ if (devmode->dmFields & DM_DUPLEX) {
+ wdev->Duplex_set = 1;
+ wdev->Duplex = devmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
+ wdev->tumble = devmode->dmDuplex == DMDUP_HORIZONTAL ? true : false;
+ }
+
+ {
+ float xppinch = 0;
+ float yppinch = 0;
+ const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
+ const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
+ const char* output = (char*)(devnames)+(devnames->wOutputOffset);
+
+ HDC hic = CreateIC(driver, device, output, devmode);
+
+ if (hic) {
+ xppinch = (float)GetDeviceCaps(hic, LOGPIXELSX);
+ yppinch = (float)GetDeviceCaps(hic, LOGPIXELSY);
+ wdev->user_media_size[0] = GetDeviceCaps(hic, PHYSICALWIDTH) * 72.0 / xppinch;
+ wdev->user_media_size[1] = GetDeviceCaps(hic, PHYSICALHEIGHT) * 72.0 / yppinch;
+ DeleteDC(hic);
+ }
+ }
+
+ devmode = NULL;
+ devnames = NULL;
+
+ GlobalUnlock(pd.hDevMode);
+ GlobalUnlock(pd.hDevNames);
+
+ if (wdev->win32_hdevmode != NULL) {
+ GlobalFree(wdev->win32_hdevmode);
+ }
+ if (wdev->win32_hdevnames != NULL) {
+ GlobalFree(wdev->win32_hdevnames);
+ }
+
+ wdev->win32_hdevmode = pd.hDevMode;
+ wdev->win32_hdevnames = pd.hDevNames;
+
+ return TRUE;
+}
+
+/* Check that we are dealing with an original device. If this
+ * happens to be a copy made by "copydevice", we will have to
+ * copy the original's handles to the associated Win32 params.
+ */
+
+static void
+win_pr2_copy_check(gx_device_win_pr2 * wdev)
+{
+ HGLOBAL hdevmode = wdev->win32_hdevmode;
+ HGLOBAL hdevnames = wdev->win32_hdevnames;
+ DWORD devmode_len = (hdevmode) ? GlobalSize(hdevmode) : 0;
+ DWORD devnames_len = (hdevnames) ? GlobalSize(hdevnames) : 0;
+
+ if (wdev->original_device == wdev)
+ return;
+
+ /* I have, I'm afraid, no real idea what this routine is for. Its been present
+ * since the earliest incarnation of the device I can find (in 1994). It seems
+ * to me that if this check ever fails, then things will always go badly wrong,
+ * since the Windows-specific structures (eg hdcprn) will be reset. I'm not
+ * sure if these are somehow expected to be set by calling 'open' again or
+ * something. In any event this check is completely incompatible with the
+ * device subclassing, because the device is now capable of moving around in
+ * memory. So add this check to see if the device has been subclassed. If it
+ * has, don't throw away the Windows-specific structures, we need them and
+ * they certainly won't be recreated.
+ */
+ {
+ gx_device *dev = wdev->parent;
+
+ while(dev) {
+ if ((gx_device *)wdev->original_device == dev)
+ return;
+
+ dev = dev->parent;
+ }
+ }
+
+ wdev->hdcprn = NULL;
+ wdev->win32_hdevmode = NULL;
+ wdev->win32_hdevnames = NULL;
+
+ wdev->original_device = wdev;
+
+ if (devmode_len) {
+ wdev->win32_hdevmode = GlobalAlloc(0, devmode_len);
+ if (wdev->win32_hdevmode) {
+ memcpy(GlobalLock(wdev->win32_hdevmode), GlobalLock(hdevmode), devmode_len);
+ GlobalUnlock(wdev->win32_hdevmode);
+ GlobalUnlock(hdevmode);
+ }
+ }
+
+ if (devnames_len) {
+ wdev->win32_hdevnames = GlobalAlloc(0, devnames_len);
+ if (wdev->win32_hdevnames) {
+ memcpy(GlobalLock(wdev->win32_hdevnames), GlobalLock(hdevnames), devnames_len);
+ GlobalUnlock(wdev->win32_hdevnames);
+ GlobalUnlock(hdevnames);
+ }
+ }
+}
+
+/* Modeless dialog box - Cancel printing */
+BOOL CALLBACK
+CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ SetWindowText(hDlg, szAppName);
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ DestroyWindow(hDlg);
+ EndDialog(hDlg, 0);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOL CALLBACK
+AbortProc2(HDC hdcPrn, int code)
+{
+ process_interrupts(NULL);
+ if (code == SP_OUTOFDISK)
+ return (FALSE); /* cancel job */
+ return (TRUE);
+}