widget/windows/nsDeviceContextSpecWin.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/windows/nsDeviceContextSpecWin.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,829 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "mozilla/ArrayUtils.h"
    1.10 +
    1.11 +#include "nsDeviceContextSpecWin.h"
    1.12 +#include "prmem.h"
    1.13 +
    1.14 +#include <winspool.h>
    1.15 +
    1.16 +#include <tchar.h>
    1.17 +
    1.18 +#include "nsAutoPtr.h"
    1.19 +#include "nsIWidget.h"
    1.20 +
    1.21 +#include "nsTArray.h"
    1.22 +#include "nsIPrintSettingsWin.h"
    1.23 +
    1.24 +#include "nsString.h"
    1.25 +#include "nsCRT.h"
    1.26 +#include "nsIServiceManager.h"
    1.27 +#include "nsReadableUtils.h"
    1.28 +#include "nsStringEnumerator.h"
    1.29 +
    1.30 +#include "gfxPDFSurface.h"
    1.31 +#include "gfxWindowsSurface.h"
    1.32 +
    1.33 +#include "nsIFileStreams.h"
    1.34 +#include "nsIWindowWatcher.h"
    1.35 +#include "nsIDOMWindow.h"
    1.36 +#include "mozilla/Services.h"
    1.37 +
    1.38 +// For NS_CopyNativeToUnicode
    1.39 +#include "nsNativeCharsetUtils.h"
    1.40 +
    1.41 +// File Picker
    1.42 +#include "nsIFile.h"
    1.43 +#include "nsIFilePicker.h"
    1.44 +#include "nsIStringBundle.h"
    1.45 +#define NS_ERROR_GFX_PRINTER_BUNDLE_URL "chrome://global/locale/printing.properties"
    1.46 +
    1.47 +#include "prlog.h"
    1.48 +#ifdef PR_LOGGING 
    1.49 +PRLogModuleInfo * kWidgetPrintingLogMod = PR_NewLogModule("printing-widget");
    1.50 +#define PR_PL(_p1)  PR_LOG(kWidgetPrintingLogMod, PR_LOG_DEBUG, _p1)
    1.51 +#else
    1.52 +#define PR_PL(_p1)
    1.53 +#endif
    1.54 +
    1.55 +using namespace mozilla;
    1.56 +
    1.57 +//----------------------------------------------------------------------------------
    1.58 +// The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
    1.59 +// The PrinterEnumerator creates the printer info
    1.60 +// but the nsDeviceContextSpecWin cleans it up
    1.61 +// If it gets created (via the Page Setup Dialog) but the user never prints anything
    1.62 +// then it will never be delete, so this class takes care of that.
    1.63 +class GlobalPrinters {
    1.64 +public:
    1.65 +  static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
    1.66 +  ~GlobalPrinters() { FreeGlobalPrinters(); }
    1.67 +
    1.68 +  void FreeGlobalPrinters();
    1.69 +
    1.70 +  bool         PrintersAreAllocated() { return mPrinters != nullptr; }
    1.71 +  LPWSTR       GetItemFromList(int32_t aInx) { return mPrinters?mPrinters->ElementAt(aInx):nullptr; }
    1.72 +  nsresult     EnumeratePrinterList();
    1.73 +  void         GetDefaultPrinterName(nsString& aDefaultPrinterName);
    1.74 +  uint32_t     GetNumPrinters() { return mPrinters?mPrinters->Length():0; }
    1.75 +
    1.76 +protected:
    1.77 +  GlobalPrinters() {}
    1.78 +  nsresult EnumerateNativePrinters();
    1.79 +  void     ReallocatePrinters();
    1.80 +
    1.81 +  static GlobalPrinters    mGlobalPrinters;
    1.82 +  static nsTArray<LPWSTR>* mPrinters;
    1.83 +};
    1.84 +//---------------
    1.85 +// static members
    1.86 +GlobalPrinters    GlobalPrinters::mGlobalPrinters;
    1.87 +nsTArray<LPWSTR>* GlobalPrinters::mPrinters = nullptr;
    1.88 +
    1.89 +
    1.90 +//******************************************************
    1.91 +// Define native paper sizes
    1.92 +//******************************************************
    1.93 +typedef struct {
    1.94 +  short  mPaperSize; // native enum
    1.95 +  double mWidth;
    1.96 +  double mHeight;
    1.97 +  bool mIsInches;
    1.98 +} NativePaperSizes;
    1.99 +
   1.100 +// There are around 40 default print sizes defined by Windows
   1.101 +const NativePaperSizes kPaperSizes[] = {
   1.102 +  {DMPAPER_LETTER,    8.5,   11.0,  true},
   1.103 +  {DMPAPER_LEGAL,     8.5,   14.0,  true},
   1.104 +  {DMPAPER_A4,        210.0, 297.0, false},
   1.105 +  {DMPAPER_B4,        250.0, 354.0, false}, 
   1.106 +  {DMPAPER_B5,        182.0, 257.0, false},
   1.107 +  {DMPAPER_TABLOID,   11.0,  17.0,  true},
   1.108 +  {DMPAPER_LEDGER,    17.0,  11.0,  true},
   1.109 +  {DMPAPER_STATEMENT, 5.5,   8.5,   true},
   1.110 +  {DMPAPER_EXECUTIVE, 7.25,  10.5,  true},
   1.111 +  {DMPAPER_A3,        297.0, 420.0, false},
   1.112 +  {DMPAPER_A5,        148.0, 210.0, false},
   1.113 +  {DMPAPER_CSHEET,    17.0,  22.0,  true},  
   1.114 +  {DMPAPER_DSHEET,    22.0,  34.0,  true},  
   1.115 +  {DMPAPER_ESHEET,    34.0,  44.0,  true},  
   1.116 +  {DMPAPER_LETTERSMALL, 8.5, 11.0,  true},  
   1.117 +  {DMPAPER_A4SMALL,   210.0, 297.0, false}, 
   1.118 +  {DMPAPER_FOLIO,     8.5,   13.0,  true},
   1.119 +  {DMPAPER_QUARTO,    215.0, 275.0, false},
   1.120 +  {DMPAPER_10X14,     10.0,  14.0,  true},
   1.121 +  {DMPAPER_11X17,     11.0,  17.0,  true},
   1.122 +  {DMPAPER_NOTE,      8.5,   11.0,  true},  
   1.123 +  {DMPAPER_ENV_9,     3.875, 8.875, true},  
   1.124 +  {DMPAPER_ENV_10,    40.125, 9.5,  true},  
   1.125 +  {DMPAPER_ENV_11,    4.5,   10.375, true},  
   1.126 +  {DMPAPER_ENV_12,    4.75,  11.0,  true},  
   1.127 +  {DMPAPER_ENV_14,    5.0,   11.5,  true},  
   1.128 +  {DMPAPER_ENV_DL,    110.0, 220.0, false}, 
   1.129 +  {DMPAPER_ENV_C5,    162.0, 229.0, false}, 
   1.130 +  {DMPAPER_ENV_C3,    324.0, 458.0, false}, 
   1.131 +  {DMPAPER_ENV_C4,    229.0, 324.0, false}, 
   1.132 +  {DMPAPER_ENV_C6,    114.0, 162.0, false}, 
   1.133 +  {DMPAPER_ENV_C65,   114.0, 229.0, false}, 
   1.134 +  {DMPAPER_ENV_B4,    250.0, 353.0, false}, 
   1.135 +  {DMPAPER_ENV_B5,    176.0, 250.0, false}, 
   1.136 +  {DMPAPER_ENV_B6,    176.0, 125.0, false}, 
   1.137 +  {DMPAPER_ENV_ITALY, 110.0, 230.0, false}, 
   1.138 +  {DMPAPER_ENV_MONARCH,  3.875,  7.5, true},  
   1.139 +  {DMPAPER_ENV_PERSONAL, 3.625,  6.5, true},  
   1.140 +  {DMPAPER_FANFOLD_US,   14.875, 11.0, true},  
   1.141 +  {DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, true},  
   1.142 +  {DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, true},  
   1.143 +};
   1.144 +const int32_t kNumPaperSizes = 41;
   1.145 +
   1.146 +//----------------------------------------------------------------------------------
   1.147 +nsDeviceContextSpecWin::nsDeviceContextSpecWin()
   1.148 +{
   1.149 +  mDriverName    = nullptr;
   1.150 +  mDeviceName    = nullptr;
   1.151 +  mDevMode       = nullptr;
   1.152 +
   1.153 +}
   1.154 +
   1.155 +
   1.156 +//----------------------------------------------------------------------------------
   1.157 +
   1.158 +NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin, nsIDeviceContextSpec)
   1.159 +
   1.160 +nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
   1.161 +{
   1.162 +  SetDeviceName(nullptr);
   1.163 +  SetDriverName(nullptr);
   1.164 +  SetDevMode(nullptr);
   1.165 +
   1.166 +  nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
   1.167 +  if (psWin) {
   1.168 +    psWin->SetDeviceName(nullptr);
   1.169 +    psWin->SetDriverName(nullptr);
   1.170 +    psWin->SetDevMode(nullptr);
   1.171 +  }
   1.172 +
   1.173 +  // Free them, we won't need them for a while
   1.174 +  GlobalPrinters::GetInstance()->FreeGlobalPrinters();
   1.175 +}
   1.176 +
   1.177 +
   1.178 +//------------------------------------------------------------------
   1.179 +// helper
   1.180 +static char16_t * GetDefaultPrinterNameFromGlobalPrinters()
   1.181 +{
   1.182 +  nsAutoString printerName;
   1.183 +  GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
   1.184 +  return ToNewUnicode(printerName);
   1.185 +}
   1.186 +
   1.187 +//----------------------------------------------------------------------------------
   1.188 +NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
   1.189 +                                           nsIPrintSettings* aPrintSettings,
   1.190 +                                           bool aIsPrintPreview)
   1.191 +{
   1.192 +  mPrintSettings = aPrintSettings;
   1.193 +
   1.194 +  nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
   1.195 +  if (aPrintSettings) {
   1.196 +    nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
   1.197 +    if (psWin) {
   1.198 +      char16_t* deviceName;
   1.199 +      char16_t* driverName;
   1.200 +      psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
   1.201 +      psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
   1.202 +
   1.203 +      LPDEVMODEW devMode;
   1.204 +      psWin->GetDevMode(&devMode);       // creates new memory (makes a copy)
   1.205 +
   1.206 +      if (deviceName && driverName && devMode) {
   1.207 +        // Scaling is special, it is one of the few
   1.208 +        // devMode items that we control in layout
   1.209 +        if (devMode->dmFields & DM_SCALE) {
   1.210 +          double scale = double(devMode->dmScale) / 100.0f;
   1.211 +          if (scale != 1.0) {
   1.212 +            aPrintSettings->SetScaling(scale);
   1.213 +            devMode->dmScale = 100;
   1.214 +          }
   1.215 +        }
   1.216 +
   1.217 +        SetDeviceName(deviceName);
   1.218 +        SetDriverName(driverName);
   1.219 +        SetDevMode(devMode);
   1.220 +
   1.221 +        // clean up
   1.222 +        free(deviceName);
   1.223 +        free(driverName);
   1.224 +
   1.225 +        return NS_OK;
   1.226 +      } else {
   1.227 +        PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
   1.228 +        if (deviceName) free(deviceName);
   1.229 +        if (driverName) free(driverName);
   1.230 +        if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
   1.231 +      }
   1.232 +    }
   1.233 +  } else {
   1.234 +    PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
   1.235 +  }
   1.236 +
   1.237 +  // Get the Print Name to be used
   1.238 +  char16_t * printerName = nullptr;
   1.239 +  if (mPrintSettings) {
   1.240 +    mPrintSettings->GetPrinterName(&printerName);
   1.241 +  }
   1.242 +
   1.243 +  // If there is no name then use the default printer
   1.244 +  if (!printerName || (printerName && !*printerName)) {
   1.245 +    printerName = GetDefaultPrinterNameFromGlobalPrinters();
   1.246 +  }
   1.247 +
   1.248 +  NS_ASSERTION(printerName, "We have to have a printer name");
   1.249 +  if (!printerName || !*printerName) return rv;
   1.250 + 
   1.251 +  return GetDataFromPrinter(printerName, mPrintSettings);
   1.252 +}
   1.253 +
   1.254 +//----------------------------------------------------------
   1.255 +// Helper Function - Free and reallocate the string
   1.256 +static void CleanAndCopyString(wchar_t*& aStr, const wchar_t* aNewStr)
   1.257 +{
   1.258 +  if (aStr != nullptr) {
   1.259 +    if (aNewStr != nullptr && wcslen(aStr) > wcslen(aNewStr)) { // reuse it if we can
   1.260 +      wcscpy(aStr, aNewStr);
   1.261 +      return;
   1.262 +    } else {
   1.263 +      PR_Free(aStr);
   1.264 +      aStr = nullptr;
   1.265 +    }
   1.266 +  }
   1.267 +
   1.268 +  if (nullptr != aNewStr) {
   1.269 +    aStr = (wchar_t *)PR_Malloc(sizeof(wchar_t)*(wcslen(aNewStr) + 1));
   1.270 +    wcscpy(aStr, aNewStr);
   1.271 +  }
   1.272 +}
   1.273 +
   1.274 +NS_IMETHODIMP nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface **surface)
   1.275 +{
   1.276 +  NS_ASSERTION(mDevMode, "DevMode can't be NULL here");
   1.277 +
   1.278 +  nsRefPtr<gfxASurface> newSurface;
   1.279 +
   1.280 +  int16_t outputFormat = 0;
   1.281 +  if (mPrintSettings) {
   1.282 +    mPrintSettings->GetOutputFormat(&outputFormat);
   1.283 +  }
   1.284 +
   1.285 +  if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
   1.286 +    nsXPIDLString filename;
   1.287 +    mPrintSettings->GetToFileName(getter_Copies(filename));
   1.288 +
   1.289 +    double width, height;
   1.290 +    mPrintSettings->GetEffectivePageSize(&width, &height);
   1.291 +    // convert twips to points
   1.292 +    width  /= TWIPS_PER_POINT_FLOAT;
   1.293 +    height /= TWIPS_PER_POINT_FLOAT;
   1.294 +
   1.295 +    nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
   1.296 +    nsresult rv = file->InitWithPath(filename);
   1.297 +    if (NS_FAILED(rv))
   1.298 +      return rv;
   1.299 +
   1.300 +    nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
   1.301 +    rv = stream->Init(file, -1, -1, 0);
   1.302 +    if (NS_FAILED(rv))
   1.303 +      return rv;
   1.304 +
   1.305 +    newSurface = new gfxPDFSurface(stream, gfxSize(width, height));
   1.306 +  } else {
   1.307 +    if (mDevMode) {
   1.308 +      NS_WARN_IF_FALSE(mDriverName, "No driver!");
   1.309 +      HDC dc = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
   1.310 +
   1.311 +      // have this surface take over ownership of this DC
   1.312 +      newSurface = new gfxWindowsSurface(dc, gfxWindowsSurface::FLAG_TAKE_DC | gfxWindowsSurface::FLAG_FOR_PRINTING);
   1.313 +    }
   1.314 +  }
   1.315 +
   1.316 +  if (newSurface) {
   1.317 +    *surface = newSurface;
   1.318 +    NS_ADDREF(*surface);
   1.319 +    return NS_OK;
   1.320 +  }
   1.321 +
   1.322 +  *surface = nullptr;
   1.323 +  return NS_ERROR_FAILURE;
   1.324 +}
   1.325 +
   1.326 +//----------------------------------------------------------------------------------
   1.327 +void nsDeviceContextSpecWin::SetDeviceName(char16ptr_t aDeviceName)
   1.328 +{
   1.329 +  CleanAndCopyString(mDeviceName, aDeviceName);
   1.330 +}
   1.331 +
   1.332 +//----------------------------------------------------------------------------------
   1.333 +void nsDeviceContextSpecWin::SetDriverName(char16ptr_t aDriverName)
   1.334 +{
   1.335 +  CleanAndCopyString(mDriverName, aDriverName);
   1.336 +}
   1.337 +
   1.338 +//----------------------------------------------------------------------------------
   1.339 +void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode)
   1.340 +{
   1.341 +  if (mDevMode) {
   1.342 +    ::HeapFree(::GetProcessHeap(), 0, mDevMode);
   1.343 +  }
   1.344 +
   1.345 +  mDevMode = aDevMode;
   1.346 +}
   1.347 +
   1.348 +//------------------------------------------------------------------
   1.349 +void 
   1.350 +nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW &aDevMode)
   1.351 +{
   1.352 +  aDevMode = mDevMode;
   1.353 +}
   1.354 +
   1.355 +//----------------------------------------------------------------------------------
   1.356 +// Map an incoming size to a Windows Native enum in the DevMode
   1.357 +static void 
   1.358 +MapPaperSizeToNativeEnum(LPDEVMODEW aDevMode,
   1.359 +                         int16_t   aType, 
   1.360 +                         double    aW, 
   1.361 +                         double    aH)
   1.362 +{
   1.363 +
   1.364 +#ifdef DEBUG_rods
   1.365 +  BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
   1.366 +  BOOL doingPaperSize   = aDevMode->dmFields & DM_PAPERSIZE;
   1.367 +  BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
   1.368 +  BOOL doingPaperWidth  = aDevMode->dmFields & DM_PAPERWIDTH;
   1.369 +#endif
   1.370 +
   1.371 +  for (int32_t i=0;i<kNumPaperSizes;i++) {
   1.372 +    if (kPaperSizes[i].mWidth == aW && kPaperSizes[i].mHeight == aH) {
   1.373 +      aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize;
   1.374 +      aDevMode->dmFields &= ~DM_PAPERLENGTH;
   1.375 +      aDevMode->dmFields &= ~DM_PAPERWIDTH;
   1.376 +      aDevMode->dmFields |= DM_PAPERSIZE;
   1.377 +      return;
   1.378 +    }
   1.379 +  }
   1.380 +
   1.381 +  short width  = 0;
   1.382 +  short height = 0;
   1.383 +  if (aType == nsIPrintSettings::kPaperSizeInches) {
   1.384 +    width  = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10);
   1.385 +    height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10);
   1.386 +
   1.387 +  } else if (aType == nsIPrintSettings::kPaperSizeMillimeters) {
   1.388 +    width  = short(aW / 10.0);
   1.389 +    height = short(aH / 10.0);
   1.390 +  } else {
   1.391 +    return; // don't set anything
   1.392 +  }
   1.393 +
   1.394 +  // width and height is in 
   1.395 +  aDevMode->dmPaperSize   = 0;
   1.396 +  aDevMode->dmPaperWidth  = width;
   1.397 +  aDevMode->dmPaperLength = height;
   1.398 +
   1.399 +  aDevMode->dmFields |= DM_PAPERSIZE;
   1.400 +  aDevMode->dmFields |= DM_PAPERLENGTH;
   1.401 +  aDevMode->dmFields |= DM_PAPERWIDTH;
   1.402 +}
   1.403 +
   1.404 +//----------------------------------------------------------------------------------
   1.405 +// Setup Paper Size & Orientation options into the DevMode
   1.406 +// 
   1.407 +static void 
   1.408 +SetupDevModeFromSettings(LPDEVMODEW aDevMode, nsIPrintSettings* aPrintSettings)
   1.409 +{
   1.410 +  // Setup paper size
   1.411 +  if (aPrintSettings) {
   1.412 +    int16_t type;
   1.413 +    aPrintSettings->GetPaperSizeType(&type);
   1.414 +    if (type == nsIPrintSettings::kPaperSizeNativeData) {
   1.415 +      int16_t paperEnum;
   1.416 +      aPrintSettings->GetPaperData(&paperEnum);
   1.417 +      aDevMode->dmPaperSize = paperEnum;
   1.418 +      aDevMode->dmFields &= ~DM_PAPERLENGTH;
   1.419 +      aDevMode->dmFields &= ~DM_PAPERWIDTH;
   1.420 +      aDevMode->dmFields |= DM_PAPERSIZE;
   1.421 +    } else {
   1.422 +      int16_t unit;
   1.423 +      double width, height;
   1.424 +      aPrintSettings->GetPaperSizeUnit(&unit);
   1.425 +      aPrintSettings->GetPaperWidth(&width);
   1.426 +      aPrintSettings->GetPaperHeight(&height);
   1.427 +      MapPaperSizeToNativeEnum(aDevMode, unit, width, height);
   1.428 +    }
   1.429 +
   1.430 +    // Setup Orientation
   1.431 +    int32_t orientation;
   1.432 +    aPrintSettings->GetOrientation(&orientation);
   1.433 +    aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE;
   1.434 +    aDevMode->dmFields |= DM_ORIENTATION;
   1.435 +
   1.436 +    // Setup Number of Copies
   1.437 +    int32_t copies;
   1.438 +    aPrintSettings->GetNumCopies(&copies);
   1.439 +    aDevMode->dmCopies = copies;
   1.440 +    aDevMode->dmFields |= DM_COPIES;
   1.441 +  }
   1.442 +
   1.443 +}
   1.444 +
   1.445 +#define DISPLAY_LAST_ERROR 
   1.446 +
   1.447 +//----------------------------------------------------------------------------------
   1.448 +// Setup the object's data member with the selected printer's data
   1.449 +nsresult
   1.450 +nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS)
   1.451 +{
   1.452 +  nsresult rv = NS_ERROR_FAILURE;
   1.453 +
   1.454 +  if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
   1.455 +    rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
   1.456 +    if (NS_FAILED(rv)) {
   1.457 +      PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
   1.458 +      DISPLAY_LAST_ERROR
   1.459 +    }
   1.460 +    NS_ENSURE_SUCCESS(rv, rv);
   1.461 +  }
   1.462 +
   1.463 +  HANDLE hPrinter = nullptr;
   1.464 +  wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument
   1.465 +  
   1.466 +  BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr);
   1.467 +  if (status) {
   1.468 +
   1.469 +    LPDEVMODEW   pDevMode;
   1.470 +    DWORD       dwNeeded, dwRet;
   1.471 +
   1.472 +    // Allocate a buffer of the correct size.
   1.473 +    dwNeeded = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr, nullptr, 0);
   1.474 +
   1.475 +    pDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
   1.476 +    if (!pDevMode) return NS_ERROR_FAILURE;
   1.477 +
   1.478 +    // Get the default DevMode for the printer and modify it for our needs.
   1.479 +    dwRet = DocumentPropertiesW(nullptr, hPrinter, name,
   1.480 +                               pDevMode, nullptr, DM_OUT_BUFFER);
   1.481 +
   1.482 +    if (dwRet == IDOK && aPS) {
   1.483 +      SetupDevModeFromSettings(pDevMode, aPS);
   1.484 +      // Sets back the changes we made to the DevMode into the Printer Driver
   1.485 +      dwRet = ::DocumentPropertiesW(nullptr, hPrinter, name,
   1.486 +                                   pDevMode, pDevMode,
   1.487 +                                   DM_IN_BUFFER | DM_OUT_BUFFER);
   1.488 +    }
   1.489 +
   1.490 +    if (dwRet != IDOK) {
   1.491 +      ::HeapFree(::GetProcessHeap(), 0, pDevMode);
   1.492 +      ::ClosePrinter(hPrinter);
   1.493 +      PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", dwRet, dwRet));
   1.494 +      DISPLAY_LAST_ERROR
   1.495 +      return NS_ERROR_FAILURE;
   1.496 +    }
   1.497 +
   1.498 +    SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
   1.499 +
   1.500 +    SetDeviceName(aName);
   1.501 +
   1.502 +    SetDriverName(L"WINSPOOL");
   1.503 +
   1.504 +    ::ClosePrinter(hPrinter);
   1.505 +    rv = NS_OK;
   1.506 +  } else {
   1.507 +    rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
   1.508 +    PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName).get()));
   1.509 +    DISPLAY_LAST_ERROR
   1.510 +  }
   1.511 +  return rv;
   1.512 +}
   1.513 +
   1.514 +//----------------------------------------------------------------------------------
   1.515 +// Setup Paper Size options into the DevMode
   1.516 +// 
   1.517 +// When using a data member it may be a HGLOCAL or LPDEVMODE
   1.518 +// if it is a HGLOBAL then we need to "lock" it to get the LPDEVMODE
   1.519 +// and unlock it when we are done.
   1.520 +void 
   1.521 +nsDeviceContextSpecWin::SetupPaperInfoFromSettings()
   1.522 +{
   1.523 +  LPDEVMODEW devMode;
   1.524 +
   1.525 +  GetDevMode(devMode);
   1.526 +  NS_ASSERTION(devMode, "DevMode can't be NULL here");
   1.527 +  if (devMode) {
   1.528 +    SetupDevModeFromSettings(devMode, mPrintSettings);
   1.529 +  }
   1.530 +}
   1.531 +
   1.532 +//----------------------------------------------------------------------------------
   1.533 +// Helper Function - Free and reallocate the string
   1.534 +nsresult 
   1.535 +nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings, 
   1.536 +                                                    LPDEVMODEW         aDevMode)
   1.537 +{
   1.538 +  if (aPrintSettings == nullptr) {
   1.539 +    return NS_ERROR_FAILURE;
   1.540 +  }
   1.541 +  aPrintSettings->SetIsInitializedFromPrinter(true);
   1.542 +
   1.543 +  BOOL doingNumCopies   = aDevMode->dmFields & DM_COPIES;
   1.544 +  BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
   1.545 +  BOOL doingPaperSize   = aDevMode->dmFields & DM_PAPERSIZE;
   1.546 +  BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
   1.547 +  BOOL doingPaperWidth  = aDevMode->dmFields & DM_PAPERWIDTH;
   1.548 +
   1.549 +  if (doingOrientation) {
   1.550 +    int32_t orientation  = aDevMode->dmOrientation == DMORIENT_PORTRAIT?
   1.551 +      int32_t(nsIPrintSettings::kPortraitOrientation):nsIPrintSettings::kLandscapeOrientation;
   1.552 +    aPrintSettings->SetOrientation(orientation);
   1.553 +  }
   1.554 +
   1.555 +  // Setup Number of Copies
   1.556 +  if (doingNumCopies) {
   1.557 +    aPrintSettings->SetNumCopies(int32_t(aDevMode->dmCopies));
   1.558 +  }
   1.559 +
   1.560 +  if (aDevMode->dmFields & DM_SCALE) {
   1.561 +    double scale = double(aDevMode->dmScale) / 100.0f;
   1.562 +    if (scale != 1.0) {
   1.563 +      aPrintSettings->SetScaling(scale);
   1.564 +      aDevMode->dmScale = 100;
   1.565 +      // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
   1.566 +      //aPrintSettings->SetShrinkToFit(false);
   1.567 +    }
   1.568 +  }
   1.569 +
   1.570 +  if (doingPaperSize) {
   1.571 +    aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData);
   1.572 +    aPrintSettings->SetPaperData(aDevMode->dmPaperSize);
   1.573 +    for (int32_t i=0;i<kNumPaperSizes;i++) {
   1.574 +      if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
   1.575 +        aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches
   1.576 +          ?int16_t(nsIPrintSettings::kPaperSizeInches):nsIPrintSettings::kPaperSizeMillimeters);
   1.577 +        break;
   1.578 +      }
   1.579 +    }
   1.580 +
   1.581 +  } else if (doingPaperLength && doingPaperWidth) {
   1.582 +    bool found = false;
   1.583 +    for (int32_t i=0;i<kNumPaperSizes;i++) {
   1.584 +      if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
   1.585 +        aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined);
   1.586 +        aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth);
   1.587 +        aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight);
   1.588 +        aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches
   1.589 +          ?int16_t(nsIPrintSettings::kPaperSizeInches):nsIPrintSettings::kPaperSizeMillimeters);
   1.590 +        found = true;
   1.591 +        break;
   1.592 +      }
   1.593 +    }
   1.594 +    if (!found) {
   1.595 +      return NS_ERROR_FAILURE;
   1.596 +    }
   1.597 +  } else {
   1.598 +    return NS_ERROR_FAILURE;
   1.599 +  }
   1.600 +  return NS_OK;
   1.601 +}
   1.602 +
   1.603 +//***********************************************************
   1.604 +//  Printer Enumerator
   1.605 +//***********************************************************
   1.606 +nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
   1.607 +{
   1.608 +}
   1.609 +
   1.610 +nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
   1.611 +{
   1.612 +  // Do not free printers here
   1.613 +  // GlobalPrinters::GetInstance()->FreeGlobalPrinters();
   1.614 +}
   1.615 +
   1.616 +NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
   1.617 +
   1.618 +//----------------------------------------------------------------------------------
   1.619 +// Return the Default Printer name
   1.620 +/* readonly attribute wstring defaultPrinterName; */
   1.621 +NS_IMETHODIMP 
   1.622 +nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
   1.623 +{
   1.624 +  NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
   1.625 +
   1.626 +  *aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
   1.627 +
   1.628 +  return NS_OK;
   1.629 +}
   1.630 +
   1.631 +/* void initPrintSettingsFromPrinter (in wstring aPrinterName, in nsIPrintSettings aPrintSettings); */
   1.632 +NS_IMETHODIMP 
   1.633 +nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings)
   1.634 +{
   1.635 +  NS_ENSURE_ARG_POINTER(aPrinterName);
   1.636 +  NS_ENSURE_ARG_POINTER(aPrintSettings);
   1.637 +
   1.638 +  if (!*aPrinterName) {
   1.639 +    return NS_OK;
   1.640 +  }
   1.641 +
   1.642 +  nsRefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
   1.643 +  if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
   1.644 +
   1.645 +  if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
   1.646 +    return NS_ERROR_FAILURE;
   1.647 +  }
   1.648 +
   1.649 +  devSpecWin->GetDataFromPrinter(aPrinterName);
   1.650 +
   1.651 +  LPDEVMODEW devmode;
   1.652 +  devSpecWin->GetDevMode(devmode);
   1.653 +  NS_ASSERTION(devmode, "DevMode can't be NULL here");
   1.654 +  if (devmode) {
   1.655 +    aPrintSettings->SetPrinterName(aPrinterName);
   1.656 +    nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(aPrintSettings, devmode);
   1.657 +  }
   1.658 +
   1.659 +  // Free them, we won't need them for a while
   1.660 +  GlobalPrinters::GetInstance()->FreeGlobalPrinters();
   1.661 +  return NS_OK;
   1.662 +}
   1.663 +
   1.664 +
   1.665 +//----------------------------------------------------------------------------------
   1.666 +// Enumerate all the Printers from the global array and pass their
   1.667 +// names back (usually to script)
   1.668 +NS_IMETHODIMP 
   1.669 +nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameList)
   1.670 +{
   1.671 +  NS_ENSURE_ARG_POINTER(aPrinterNameList);
   1.672 +  *aPrinterNameList = nullptr;
   1.673 +
   1.674 +  nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
   1.675 +  if (NS_FAILED(rv)) {
   1.676 +    PR_PL(("***** nsDeviceContextSpecWin::GetPrinterNameList - Couldn't enumerate printers!\n"));
   1.677 +    return rv;
   1.678 +  }
   1.679 +
   1.680 +  uint32_t numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
   1.681 +  nsTArray<nsString> *printers = new nsTArray<nsString>(numPrinters);
   1.682 +  if (!printers)
   1.683 +    return NS_ERROR_OUT_OF_MEMORY;
   1.684 +
   1.685 +  uint32_t printerInx = 0;
   1.686 +  while( printerInx < numPrinters ) {
   1.687 +    LPWSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx++);
   1.688 +    printers->AppendElement(nsDependentString(name));
   1.689 +  }
   1.690 +
   1.691 +  return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
   1.692 +}
   1.693 +
   1.694 +//----------------------------------------------------------------------------------
   1.695 +// Display the AdvancedDocumentProperties for the selected Printer
   1.696 +NS_IMETHODIMP nsPrinterEnumeratorWin::DisplayPropertiesDlg(const char16_t *aPrinterName, nsIPrintSettings* aPrintSettings)
   1.697 +{
   1.698 +  // Implementation removed because it is unused
   1.699 +  return NS_OK;
   1.700 +}
   1.701 +
   1.702 +//----------------------------------------------------------------------------------
   1.703 +//-- Global Printers
   1.704 +//----------------------------------------------------------------------------------
   1.705 +
   1.706 +//----------------------------------------------------------------------------------
   1.707 +// THe array hold the name and port for each printer
   1.708 +void 
   1.709 +GlobalPrinters::ReallocatePrinters()
   1.710 +{
   1.711 +  if (PrintersAreAllocated()) {
   1.712 +    FreeGlobalPrinters();
   1.713 +  }
   1.714 +  mPrinters = new nsTArray<LPWSTR>();
   1.715 +  NS_ASSERTION(mPrinters, "Printers Array is NULL!");
   1.716 +}
   1.717 +
   1.718 +//----------------------------------------------------------------------------------
   1.719 +void 
   1.720 +GlobalPrinters::FreeGlobalPrinters()
   1.721 +{
   1.722 +  if (mPrinters != nullptr) {
   1.723 +    for (uint32_t i=0;i<mPrinters->Length();i++) {
   1.724 +      free(mPrinters->ElementAt(i));
   1.725 +    }
   1.726 +    delete mPrinters;
   1.727 +    mPrinters = nullptr;
   1.728 +  }
   1.729 +}
   1.730 +
   1.731 +//----------------------------------------------------------------------------------
   1.732 +nsresult 
   1.733 +GlobalPrinters::EnumerateNativePrinters()
   1.734 +{
   1.735 +  nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
   1.736 +  PR_PL(("-----------------------\n"));
   1.737 +  PR_PL(("EnumerateNativePrinters\n"));
   1.738 +
   1.739 +  WCHAR szDefaultPrinterName[1024];    
   1.740 +  DWORD status = GetProfileStringW(L"devices", 0, L",",
   1.741 +                                   szDefaultPrinterName,
   1.742 +                                   ArrayLength(szDefaultPrinterName));
   1.743 +  if (status > 0) {
   1.744 +    DWORD count = 0;
   1.745 +    LPWSTR sPtr   = szDefaultPrinterName;
   1.746 +    LPWSTR ePtr   = szDefaultPrinterName + status;
   1.747 +    LPWSTR prvPtr = sPtr;
   1.748 +    while (sPtr < ePtr) {
   1.749 +      if (*sPtr == 0) {
   1.750 +        LPWSTR name = wcsdup(prvPtr);
   1.751 +        mPrinters->AppendElement(name);
   1.752 +        PR_PL(("Printer Name:    %s\n", prvPtr));
   1.753 +        prvPtr = sPtr+1;
   1.754 +        count++;
   1.755 +      }
   1.756 +      sPtr++;
   1.757 +    }
   1.758 +    rv = NS_OK;
   1.759 +  }
   1.760 +  PR_PL(("-----------------------\n"));
   1.761 +  return rv;
   1.762 +}
   1.763 +
   1.764 +//------------------------------------------------------------------
   1.765 +// Uses the GetProfileString to get the default printer from the registry
   1.766 +void 
   1.767 +GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName)
   1.768 +{
   1.769 +  aDefaultPrinterName.Truncate();
   1.770 +  WCHAR szDefaultPrinterName[1024];    
   1.771 +  DWORD status = GetProfileStringW(L"windows", L"device", 0,
   1.772 +                                   szDefaultPrinterName,
   1.773 +                                   ArrayLength(szDefaultPrinterName));
   1.774 +  if (status > 0) {
   1.775 +    WCHAR comma = ',';
   1.776 +    LPWSTR sPtr = szDefaultPrinterName;
   1.777 +    while (*sPtr != comma && *sPtr != 0) 
   1.778 +      sPtr++;
   1.779 +    if (*sPtr == comma) {
   1.780 +      *sPtr = 0;
   1.781 +    }
   1.782 +    aDefaultPrinterName = szDefaultPrinterName;
   1.783 +  } else {
   1.784 +    aDefaultPrinterName = EmptyString();
   1.785 +  }
   1.786 +
   1.787 +  PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName.get()));
   1.788 +}
   1.789 +
   1.790 +//----------------------------------------------------------------------------------
   1.791 +// This goes and gets the list of available printers and puts
   1.792 +// the default printer at the beginning of the list
   1.793 +nsresult 
   1.794 +GlobalPrinters::EnumeratePrinterList()
   1.795 +{
   1.796 +  // reallocate and get a new list each time it is asked for
   1.797 +  // this deletes the list and re-allocates them
   1.798 +  ReallocatePrinters();
   1.799 +
   1.800 +  // any of these could only fail with an OUT_MEMORY_ERROR
   1.801 +  // PRINTER_ENUM_LOCAL should get the network printers on Win95
   1.802 +  nsresult rv = EnumerateNativePrinters();
   1.803 +  if (NS_FAILED(rv)) return rv;
   1.804 +
   1.805 +  // get the name of the default printer
   1.806 +  nsAutoString defPrinterName;
   1.807 +  GetDefaultPrinterName(defPrinterName);
   1.808 +
   1.809 +  // put the default printer at the beginning of list
   1.810 +  if (!defPrinterName.IsEmpty()) {
   1.811 +    for (uint32_t i=0;i<mPrinters->Length();i++) {
   1.812 +      LPWSTR name = mPrinters->ElementAt(i);
   1.813 +      if (defPrinterName.Equals(name)) {
   1.814 +        if (i > 0) {
   1.815 +          LPWSTR ptr = mPrinters->ElementAt(0);
   1.816 +          mPrinters->ElementAt(0) = name;
   1.817 +          mPrinters->ElementAt(i) = ptr;
   1.818 +        }
   1.819 +        break;
   1.820 +      }
   1.821 +    }
   1.822 +  }
   1.823 +
   1.824 +  // make sure we at least tried to get the printers
   1.825 +  if (!PrintersAreAllocated()) {
   1.826 +    PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
   1.827 +    return NS_ERROR_FAILURE;
   1.828 +  }
   1.829 +
   1.830 +  return NS_OK;
   1.831 +}
   1.832 +

mercurial