widget/windows/nsDeviceContextSpecWin.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/ArrayUtils.h"
michael@0 7
michael@0 8 #include "nsDeviceContextSpecWin.h"
michael@0 9 #include "prmem.h"
michael@0 10
michael@0 11 #include <winspool.h>
michael@0 12
michael@0 13 #include <tchar.h>
michael@0 14
michael@0 15 #include "nsAutoPtr.h"
michael@0 16 #include "nsIWidget.h"
michael@0 17
michael@0 18 #include "nsTArray.h"
michael@0 19 #include "nsIPrintSettingsWin.h"
michael@0 20
michael@0 21 #include "nsString.h"
michael@0 22 #include "nsCRT.h"
michael@0 23 #include "nsIServiceManager.h"
michael@0 24 #include "nsReadableUtils.h"
michael@0 25 #include "nsStringEnumerator.h"
michael@0 26
michael@0 27 #include "gfxPDFSurface.h"
michael@0 28 #include "gfxWindowsSurface.h"
michael@0 29
michael@0 30 #include "nsIFileStreams.h"
michael@0 31 #include "nsIWindowWatcher.h"
michael@0 32 #include "nsIDOMWindow.h"
michael@0 33 #include "mozilla/Services.h"
michael@0 34
michael@0 35 // For NS_CopyNativeToUnicode
michael@0 36 #include "nsNativeCharsetUtils.h"
michael@0 37
michael@0 38 // File Picker
michael@0 39 #include "nsIFile.h"
michael@0 40 #include "nsIFilePicker.h"
michael@0 41 #include "nsIStringBundle.h"
michael@0 42 #define NS_ERROR_GFX_PRINTER_BUNDLE_URL "chrome://global/locale/printing.properties"
michael@0 43
michael@0 44 #include "prlog.h"
michael@0 45 #ifdef PR_LOGGING
michael@0 46 PRLogModuleInfo * kWidgetPrintingLogMod = PR_NewLogModule("printing-widget");
michael@0 47 #define PR_PL(_p1) PR_LOG(kWidgetPrintingLogMod, PR_LOG_DEBUG, _p1)
michael@0 48 #else
michael@0 49 #define PR_PL(_p1)
michael@0 50 #endif
michael@0 51
michael@0 52 using namespace mozilla;
michael@0 53
michael@0 54 //----------------------------------------------------------------------------------
michael@0 55 // The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
michael@0 56 // The PrinterEnumerator creates the printer info
michael@0 57 // but the nsDeviceContextSpecWin cleans it up
michael@0 58 // If it gets created (via the Page Setup Dialog) but the user never prints anything
michael@0 59 // then it will never be delete, so this class takes care of that.
michael@0 60 class GlobalPrinters {
michael@0 61 public:
michael@0 62 static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
michael@0 63 ~GlobalPrinters() { FreeGlobalPrinters(); }
michael@0 64
michael@0 65 void FreeGlobalPrinters();
michael@0 66
michael@0 67 bool PrintersAreAllocated() { return mPrinters != nullptr; }
michael@0 68 LPWSTR GetItemFromList(int32_t aInx) { return mPrinters?mPrinters->ElementAt(aInx):nullptr; }
michael@0 69 nsresult EnumeratePrinterList();
michael@0 70 void GetDefaultPrinterName(nsString& aDefaultPrinterName);
michael@0 71 uint32_t GetNumPrinters() { return mPrinters?mPrinters->Length():0; }
michael@0 72
michael@0 73 protected:
michael@0 74 GlobalPrinters() {}
michael@0 75 nsresult EnumerateNativePrinters();
michael@0 76 void ReallocatePrinters();
michael@0 77
michael@0 78 static GlobalPrinters mGlobalPrinters;
michael@0 79 static nsTArray<LPWSTR>* mPrinters;
michael@0 80 };
michael@0 81 //---------------
michael@0 82 // static members
michael@0 83 GlobalPrinters GlobalPrinters::mGlobalPrinters;
michael@0 84 nsTArray<LPWSTR>* GlobalPrinters::mPrinters = nullptr;
michael@0 85
michael@0 86
michael@0 87 //******************************************************
michael@0 88 // Define native paper sizes
michael@0 89 //******************************************************
michael@0 90 typedef struct {
michael@0 91 short mPaperSize; // native enum
michael@0 92 double mWidth;
michael@0 93 double mHeight;
michael@0 94 bool mIsInches;
michael@0 95 } NativePaperSizes;
michael@0 96
michael@0 97 // There are around 40 default print sizes defined by Windows
michael@0 98 const NativePaperSizes kPaperSizes[] = {
michael@0 99 {DMPAPER_LETTER, 8.5, 11.0, true},
michael@0 100 {DMPAPER_LEGAL, 8.5, 14.0, true},
michael@0 101 {DMPAPER_A4, 210.0, 297.0, false},
michael@0 102 {DMPAPER_B4, 250.0, 354.0, false},
michael@0 103 {DMPAPER_B5, 182.0, 257.0, false},
michael@0 104 {DMPAPER_TABLOID, 11.0, 17.0, true},
michael@0 105 {DMPAPER_LEDGER, 17.0, 11.0, true},
michael@0 106 {DMPAPER_STATEMENT, 5.5, 8.5, true},
michael@0 107 {DMPAPER_EXECUTIVE, 7.25, 10.5, true},
michael@0 108 {DMPAPER_A3, 297.0, 420.0, false},
michael@0 109 {DMPAPER_A5, 148.0, 210.0, false},
michael@0 110 {DMPAPER_CSHEET, 17.0, 22.0, true},
michael@0 111 {DMPAPER_DSHEET, 22.0, 34.0, true},
michael@0 112 {DMPAPER_ESHEET, 34.0, 44.0, true},
michael@0 113 {DMPAPER_LETTERSMALL, 8.5, 11.0, true},
michael@0 114 {DMPAPER_A4SMALL, 210.0, 297.0, false},
michael@0 115 {DMPAPER_FOLIO, 8.5, 13.0, true},
michael@0 116 {DMPAPER_QUARTO, 215.0, 275.0, false},
michael@0 117 {DMPAPER_10X14, 10.0, 14.0, true},
michael@0 118 {DMPAPER_11X17, 11.0, 17.0, true},
michael@0 119 {DMPAPER_NOTE, 8.5, 11.0, true},
michael@0 120 {DMPAPER_ENV_9, 3.875, 8.875, true},
michael@0 121 {DMPAPER_ENV_10, 40.125, 9.5, true},
michael@0 122 {DMPAPER_ENV_11, 4.5, 10.375, true},
michael@0 123 {DMPAPER_ENV_12, 4.75, 11.0, true},
michael@0 124 {DMPAPER_ENV_14, 5.0, 11.5, true},
michael@0 125 {DMPAPER_ENV_DL, 110.0, 220.0, false},
michael@0 126 {DMPAPER_ENV_C5, 162.0, 229.0, false},
michael@0 127 {DMPAPER_ENV_C3, 324.0, 458.0, false},
michael@0 128 {DMPAPER_ENV_C4, 229.0, 324.0, false},
michael@0 129 {DMPAPER_ENV_C6, 114.0, 162.0, false},
michael@0 130 {DMPAPER_ENV_C65, 114.0, 229.0, false},
michael@0 131 {DMPAPER_ENV_B4, 250.0, 353.0, false},
michael@0 132 {DMPAPER_ENV_B5, 176.0, 250.0, false},
michael@0 133 {DMPAPER_ENV_B6, 176.0, 125.0, false},
michael@0 134 {DMPAPER_ENV_ITALY, 110.0, 230.0, false},
michael@0 135 {DMPAPER_ENV_MONARCH, 3.875, 7.5, true},
michael@0 136 {DMPAPER_ENV_PERSONAL, 3.625, 6.5, true},
michael@0 137 {DMPAPER_FANFOLD_US, 14.875, 11.0, true},
michael@0 138 {DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, true},
michael@0 139 {DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, true},
michael@0 140 };
michael@0 141 const int32_t kNumPaperSizes = 41;
michael@0 142
michael@0 143 //----------------------------------------------------------------------------------
michael@0 144 nsDeviceContextSpecWin::nsDeviceContextSpecWin()
michael@0 145 {
michael@0 146 mDriverName = nullptr;
michael@0 147 mDeviceName = nullptr;
michael@0 148 mDevMode = nullptr;
michael@0 149
michael@0 150 }
michael@0 151
michael@0 152
michael@0 153 //----------------------------------------------------------------------------------
michael@0 154
michael@0 155 NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin, nsIDeviceContextSpec)
michael@0 156
michael@0 157 nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
michael@0 158 {
michael@0 159 SetDeviceName(nullptr);
michael@0 160 SetDriverName(nullptr);
michael@0 161 SetDevMode(nullptr);
michael@0 162
michael@0 163 nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
michael@0 164 if (psWin) {
michael@0 165 psWin->SetDeviceName(nullptr);
michael@0 166 psWin->SetDriverName(nullptr);
michael@0 167 psWin->SetDevMode(nullptr);
michael@0 168 }
michael@0 169
michael@0 170 // Free them, we won't need them for a while
michael@0 171 GlobalPrinters::GetInstance()->FreeGlobalPrinters();
michael@0 172 }
michael@0 173
michael@0 174
michael@0 175 //------------------------------------------------------------------
michael@0 176 // helper
michael@0 177 static char16_t * GetDefaultPrinterNameFromGlobalPrinters()
michael@0 178 {
michael@0 179 nsAutoString printerName;
michael@0 180 GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
michael@0 181 return ToNewUnicode(printerName);
michael@0 182 }
michael@0 183
michael@0 184 //----------------------------------------------------------------------------------
michael@0 185 NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
michael@0 186 nsIPrintSettings* aPrintSettings,
michael@0 187 bool aIsPrintPreview)
michael@0 188 {
michael@0 189 mPrintSettings = aPrintSettings;
michael@0 190
michael@0 191 nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
michael@0 192 if (aPrintSettings) {
michael@0 193 nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
michael@0 194 if (psWin) {
michael@0 195 char16_t* deviceName;
michael@0 196 char16_t* driverName;
michael@0 197 psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
michael@0 198 psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
michael@0 199
michael@0 200 LPDEVMODEW devMode;
michael@0 201 psWin->GetDevMode(&devMode); // creates new memory (makes a copy)
michael@0 202
michael@0 203 if (deviceName && driverName && devMode) {
michael@0 204 // Scaling is special, it is one of the few
michael@0 205 // devMode items that we control in layout
michael@0 206 if (devMode->dmFields & DM_SCALE) {
michael@0 207 double scale = double(devMode->dmScale) / 100.0f;
michael@0 208 if (scale != 1.0) {
michael@0 209 aPrintSettings->SetScaling(scale);
michael@0 210 devMode->dmScale = 100;
michael@0 211 }
michael@0 212 }
michael@0 213
michael@0 214 SetDeviceName(deviceName);
michael@0 215 SetDriverName(driverName);
michael@0 216 SetDevMode(devMode);
michael@0 217
michael@0 218 // clean up
michael@0 219 free(deviceName);
michael@0 220 free(driverName);
michael@0 221
michael@0 222 return NS_OK;
michael@0 223 } else {
michael@0 224 PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
michael@0 225 if (deviceName) free(deviceName);
michael@0 226 if (driverName) free(driverName);
michael@0 227 if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
michael@0 228 }
michael@0 229 }
michael@0 230 } else {
michael@0 231 PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
michael@0 232 }
michael@0 233
michael@0 234 // Get the Print Name to be used
michael@0 235 char16_t * printerName = nullptr;
michael@0 236 if (mPrintSettings) {
michael@0 237 mPrintSettings->GetPrinterName(&printerName);
michael@0 238 }
michael@0 239
michael@0 240 // If there is no name then use the default printer
michael@0 241 if (!printerName || (printerName && !*printerName)) {
michael@0 242 printerName = GetDefaultPrinterNameFromGlobalPrinters();
michael@0 243 }
michael@0 244
michael@0 245 NS_ASSERTION(printerName, "We have to have a printer name");
michael@0 246 if (!printerName || !*printerName) return rv;
michael@0 247
michael@0 248 return GetDataFromPrinter(printerName, mPrintSettings);
michael@0 249 }
michael@0 250
michael@0 251 //----------------------------------------------------------
michael@0 252 // Helper Function - Free and reallocate the string
michael@0 253 static void CleanAndCopyString(wchar_t*& aStr, const wchar_t* aNewStr)
michael@0 254 {
michael@0 255 if (aStr != nullptr) {
michael@0 256 if (aNewStr != nullptr && wcslen(aStr) > wcslen(aNewStr)) { // reuse it if we can
michael@0 257 wcscpy(aStr, aNewStr);
michael@0 258 return;
michael@0 259 } else {
michael@0 260 PR_Free(aStr);
michael@0 261 aStr = nullptr;
michael@0 262 }
michael@0 263 }
michael@0 264
michael@0 265 if (nullptr != aNewStr) {
michael@0 266 aStr = (wchar_t *)PR_Malloc(sizeof(wchar_t)*(wcslen(aNewStr) + 1));
michael@0 267 wcscpy(aStr, aNewStr);
michael@0 268 }
michael@0 269 }
michael@0 270
michael@0 271 NS_IMETHODIMP nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface **surface)
michael@0 272 {
michael@0 273 NS_ASSERTION(mDevMode, "DevMode can't be NULL here");
michael@0 274
michael@0 275 nsRefPtr<gfxASurface> newSurface;
michael@0 276
michael@0 277 int16_t outputFormat = 0;
michael@0 278 if (mPrintSettings) {
michael@0 279 mPrintSettings->GetOutputFormat(&outputFormat);
michael@0 280 }
michael@0 281
michael@0 282 if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
michael@0 283 nsXPIDLString filename;
michael@0 284 mPrintSettings->GetToFileName(getter_Copies(filename));
michael@0 285
michael@0 286 double width, height;
michael@0 287 mPrintSettings->GetEffectivePageSize(&width, &height);
michael@0 288 // convert twips to points
michael@0 289 width /= TWIPS_PER_POINT_FLOAT;
michael@0 290 height /= TWIPS_PER_POINT_FLOAT;
michael@0 291
michael@0 292 nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
michael@0 293 nsresult rv = file->InitWithPath(filename);
michael@0 294 if (NS_FAILED(rv))
michael@0 295 return rv;
michael@0 296
michael@0 297 nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
michael@0 298 rv = stream->Init(file, -1, -1, 0);
michael@0 299 if (NS_FAILED(rv))
michael@0 300 return rv;
michael@0 301
michael@0 302 newSurface = new gfxPDFSurface(stream, gfxSize(width, height));
michael@0 303 } else {
michael@0 304 if (mDevMode) {
michael@0 305 NS_WARN_IF_FALSE(mDriverName, "No driver!");
michael@0 306 HDC dc = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
michael@0 307
michael@0 308 // have this surface take over ownership of this DC
michael@0 309 newSurface = new gfxWindowsSurface(dc, gfxWindowsSurface::FLAG_TAKE_DC | gfxWindowsSurface::FLAG_FOR_PRINTING);
michael@0 310 }
michael@0 311 }
michael@0 312
michael@0 313 if (newSurface) {
michael@0 314 *surface = newSurface;
michael@0 315 NS_ADDREF(*surface);
michael@0 316 return NS_OK;
michael@0 317 }
michael@0 318
michael@0 319 *surface = nullptr;
michael@0 320 return NS_ERROR_FAILURE;
michael@0 321 }
michael@0 322
michael@0 323 //----------------------------------------------------------------------------------
michael@0 324 void nsDeviceContextSpecWin::SetDeviceName(char16ptr_t aDeviceName)
michael@0 325 {
michael@0 326 CleanAndCopyString(mDeviceName, aDeviceName);
michael@0 327 }
michael@0 328
michael@0 329 //----------------------------------------------------------------------------------
michael@0 330 void nsDeviceContextSpecWin::SetDriverName(char16ptr_t aDriverName)
michael@0 331 {
michael@0 332 CleanAndCopyString(mDriverName, aDriverName);
michael@0 333 }
michael@0 334
michael@0 335 //----------------------------------------------------------------------------------
michael@0 336 void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode)
michael@0 337 {
michael@0 338 if (mDevMode) {
michael@0 339 ::HeapFree(::GetProcessHeap(), 0, mDevMode);
michael@0 340 }
michael@0 341
michael@0 342 mDevMode = aDevMode;
michael@0 343 }
michael@0 344
michael@0 345 //------------------------------------------------------------------
michael@0 346 void
michael@0 347 nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW &aDevMode)
michael@0 348 {
michael@0 349 aDevMode = mDevMode;
michael@0 350 }
michael@0 351
michael@0 352 //----------------------------------------------------------------------------------
michael@0 353 // Map an incoming size to a Windows Native enum in the DevMode
michael@0 354 static void
michael@0 355 MapPaperSizeToNativeEnum(LPDEVMODEW aDevMode,
michael@0 356 int16_t aType,
michael@0 357 double aW,
michael@0 358 double aH)
michael@0 359 {
michael@0 360
michael@0 361 #ifdef DEBUG_rods
michael@0 362 BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
michael@0 363 BOOL doingPaperSize = aDevMode->dmFields & DM_PAPERSIZE;
michael@0 364 BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
michael@0 365 BOOL doingPaperWidth = aDevMode->dmFields & DM_PAPERWIDTH;
michael@0 366 #endif
michael@0 367
michael@0 368 for (int32_t i=0;i<kNumPaperSizes;i++) {
michael@0 369 if (kPaperSizes[i].mWidth == aW && kPaperSizes[i].mHeight == aH) {
michael@0 370 aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize;
michael@0 371 aDevMode->dmFields &= ~DM_PAPERLENGTH;
michael@0 372 aDevMode->dmFields &= ~DM_PAPERWIDTH;
michael@0 373 aDevMode->dmFields |= DM_PAPERSIZE;
michael@0 374 return;
michael@0 375 }
michael@0 376 }
michael@0 377
michael@0 378 short width = 0;
michael@0 379 short height = 0;
michael@0 380 if (aType == nsIPrintSettings::kPaperSizeInches) {
michael@0 381 width = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10);
michael@0 382 height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10);
michael@0 383
michael@0 384 } else if (aType == nsIPrintSettings::kPaperSizeMillimeters) {
michael@0 385 width = short(aW / 10.0);
michael@0 386 height = short(aH / 10.0);
michael@0 387 } else {
michael@0 388 return; // don't set anything
michael@0 389 }
michael@0 390
michael@0 391 // width and height is in
michael@0 392 aDevMode->dmPaperSize = 0;
michael@0 393 aDevMode->dmPaperWidth = width;
michael@0 394 aDevMode->dmPaperLength = height;
michael@0 395
michael@0 396 aDevMode->dmFields |= DM_PAPERSIZE;
michael@0 397 aDevMode->dmFields |= DM_PAPERLENGTH;
michael@0 398 aDevMode->dmFields |= DM_PAPERWIDTH;
michael@0 399 }
michael@0 400
michael@0 401 //----------------------------------------------------------------------------------
michael@0 402 // Setup Paper Size & Orientation options into the DevMode
michael@0 403 //
michael@0 404 static void
michael@0 405 SetupDevModeFromSettings(LPDEVMODEW aDevMode, nsIPrintSettings* aPrintSettings)
michael@0 406 {
michael@0 407 // Setup paper size
michael@0 408 if (aPrintSettings) {
michael@0 409 int16_t type;
michael@0 410 aPrintSettings->GetPaperSizeType(&type);
michael@0 411 if (type == nsIPrintSettings::kPaperSizeNativeData) {
michael@0 412 int16_t paperEnum;
michael@0 413 aPrintSettings->GetPaperData(&paperEnum);
michael@0 414 aDevMode->dmPaperSize = paperEnum;
michael@0 415 aDevMode->dmFields &= ~DM_PAPERLENGTH;
michael@0 416 aDevMode->dmFields &= ~DM_PAPERWIDTH;
michael@0 417 aDevMode->dmFields |= DM_PAPERSIZE;
michael@0 418 } else {
michael@0 419 int16_t unit;
michael@0 420 double width, height;
michael@0 421 aPrintSettings->GetPaperSizeUnit(&unit);
michael@0 422 aPrintSettings->GetPaperWidth(&width);
michael@0 423 aPrintSettings->GetPaperHeight(&height);
michael@0 424 MapPaperSizeToNativeEnum(aDevMode, unit, width, height);
michael@0 425 }
michael@0 426
michael@0 427 // Setup Orientation
michael@0 428 int32_t orientation;
michael@0 429 aPrintSettings->GetOrientation(&orientation);
michael@0 430 aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE;
michael@0 431 aDevMode->dmFields |= DM_ORIENTATION;
michael@0 432
michael@0 433 // Setup Number of Copies
michael@0 434 int32_t copies;
michael@0 435 aPrintSettings->GetNumCopies(&copies);
michael@0 436 aDevMode->dmCopies = copies;
michael@0 437 aDevMode->dmFields |= DM_COPIES;
michael@0 438 }
michael@0 439
michael@0 440 }
michael@0 441
michael@0 442 #define DISPLAY_LAST_ERROR
michael@0 443
michael@0 444 //----------------------------------------------------------------------------------
michael@0 445 // Setup the object's data member with the selected printer's data
michael@0 446 nsresult
michael@0 447 nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS)
michael@0 448 {
michael@0 449 nsresult rv = NS_ERROR_FAILURE;
michael@0 450
michael@0 451 if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
michael@0 452 rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
michael@0 453 if (NS_FAILED(rv)) {
michael@0 454 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
michael@0 455 DISPLAY_LAST_ERROR
michael@0 456 }
michael@0 457 NS_ENSURE_SUCCESS(rv, rv);
michael@0 458 }
michael@0 459
michael@0 460 HANDLE hPrinter = nullptr;
michael@0 461 wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument
michael@0 462
michael@0 463 BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr);
michael@0 464 if (status) {
michael@0 465
michael@0 466 LPDEVMODEW pDevMode;
michael@0 467 DWORD dwNeeded, dwRet;
michael@0 468
michael@0 469 // Allocate a buffer of the correct size.
michael@0 470 dwNeeded = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr, nullptr, 0);
michael@0 471
michael@0 472 pDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
michael@0 473 if (!pDevMode) return NS_ERROR_FAILURE;
michael@0 474
michael@0 475 // Get the default DevMode for the printer and modify it for our needs.
michael@0 476 dwRet = DocumentPropertiesW(nullptr, hPrinter, name,
michael@0 477 pDevMode, nullptr, DM_OUT_BUFFER);
michael@0 478
michael@0 479 if (dwRet == IDOK && aPS) {
michael@0 480 SetupDevModeFromSettings(pDevMode, aPS);
michael@0 481 // Sets back the changes we made to the DevMode into the Printer Driver
michael@0 482 dwRet = ::DocumentPropertiesW(nullptr, hPrinter, name,
michael@0 483 pDevMode, pDevMode,
michael@0 484 DM_IN_BUFFER | DM_OUT_BUFFER);
michael@0 485 }
michael@0 486
michael@0 487 if (dwRet != IDOK) {
michael@0 488 ::HeapFree(::GetProcessHeap(), 0, pDevMode);
michael@0 489 ::ClosePrinter(hPrinter);
michael@0 490 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", dwRet, dwRet));
michael@0 491 DISPLAY_LAST_ERROR
michael@0 492 return NS_ERROR_FAILURE;
michael@0 493 }
michael@0 494
michael@0 495 SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
michael@0 496
michael@0 497 SetDeviceName(aName);
michael@0 498
michael@0 499 SetDriverName(L"WINSPOOL");
michael@0 500
michael@0 501 ::ClosePrinter(hPrinter);
michael@0 502 rv = NS_OK;
michael@0 503 } else {
michael@0 504 rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
michael@0 505 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName).get()));
michael@0 506 DISPLAY_LAST_ERROR
michael@0 507 }
michael@0 508 return rv;
michael@0 509 }
michael@0 510
michael@0 511 //----------------------------------------------------------------------------------
michael@0 512 // Setup Paper Size options into the DevMode
michael@0 513 //
michael@0 514 // When using a data member it may be a HGLOCAL or LPDEVMODE
michael@0 515 // if it is a HGLOBAL then we need to "lock" it to get the LPDEVMODE
michael@0 516 // and unlock it when we are done.
michael@0 517 void
michael@0 518 nsDeviceContextSpecWin::SetupPaperInfoFromSettings()
michael@0 519 {
michael@0 520 LPDEVMODEW devMode;
michael@0 521
michael@0 522 GetDevMode(devMode);
michael@0 523 NS_ASSERTION(devMode, "DevMode can't be NULL here");
michael@0 524 if (devMode) {
michael@0 525 SetupDevModeFromSettings(devMode, mPrintSettings);
michael@0 526 }
michael@0 527 }
michael@0 528
michael@0 529 //----------------------------------------------------------------------------------
michael@0 530 // Helper Function - Free and reallocate the string
michael@0 531 nsresult
michael@0 532 nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings,
michael@0 533 LPDEVMODEW aDevMode)
michael@0 534 {
michael@0 535 if (aPrintSettings == nullptr) {
michael@0 536 return NS_ERROR_FAILURE;
michael@0 537 }
michael@0 538 aPrintSettings->SetIsInitializedFromPrinter(true);
michael@0 539
michael@0 540 BOOL doingNumCopies = aDevMode->dmFields & DM_COPIES;
michael@0 541 BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
michael@0 542 BOOL doingPaperSize = aDevMode->dmFields & DM_PAPERSIZE;
michael@0 543 BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
michael@0 544 BOOL doingPaperWidth = aDevMode->dmFields & DM_PAPERWIDTH;
michael@0 545
michael@0 546 if (doingOrientation) {
michael@0 547 int32_t orientation = aDevMode->dmOrientation == DMORIENT_PORTRAIT?
michael@0 548 int32_t(nsIPrintSettings::kPortraitOrientation):nsIPrintSettings::kLandscapeOrientation;
michael@0 549 aPrintSettings->SetOrientation(orientation);
michael@0 550 }
michael@0 551
michael@0 552 // Setup Number of Copies
michael@0 553 if (doingNumCopies) {
michael@0 554 aPrintSettings->SetNumCopies(int32_t(aDevMode->dmCopies));
michael@0 555 }
michael@0 556
michael@0 557 if (aDevMode->dmFields & DM_SCALE) {
michael@0 558 double scale = double(aDevMode->dmScale) / 100.0f;
michael@0 559 if (scale != 1.0) {
michael@0 560 aPrintSettings->SetScaling(scale);
michael@0 561 aDevMode->dmScale = 100;
michael@0 562 // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
michael@0 563 //aPrintSettings->SetShrinkToFit(false);
michael@0 564 }
michael@0 565 }
michael@0 566
michael@0 567 if (doingPaperSize) {
michael@0 568 aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData);
michael@0 569 aPrintSettings->SetPaperData(aDevMode->dmPaperSize);
michael@0 570 for (int32_t i=0;i<kNumPaperSizes;i++) {
michael@0 571 if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
michael@0 572 aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches
michael@0 573 ?int16_t(nsIPrintSettings::kPaperSizeInches):nsIPrintSettings::kPaperSizeMillimeters);
michael@0 574 break;
michael@0 575 }
michael@0 576 }
michael@0 577
michael@0 578 } else if (doingPaperLength && doingPaperWidth) {
michael@0 579 bool found = false;
michael@0 580 for (int32_t i=0;i<kNumPaperSizes;i++) {
michael@0 581 if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
michael@0 582 aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined);
michael@0 583 aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth);
michael@0 584 aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight);
michael@0 585 aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches
michael@0 586 ?int16_t(nsIPrintSettings::kPaperSizeInches):nsIPrintSettings::kPaperSizeMillimeters);
michael@0 587 found = true;
michael@0 588 break;
michael@0 589 }
michael@0 590 }
michael@0 591 if (!found) {
michael@0 592 return NS_ERROR_FAILURE;
michael@0 593 }
michael@0 594 } else {
michael@0 595 return NS_ERROR_FAILURE;
michael@0 596 }
michael@0 597 return NS_OK;
michael@0 598 }
michael@0 599
michael@0 600 //***********************************************************
michael@0 601 // Printer Enumerator
michael@0 602 //***********************************************************
michael@0 603 nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
michael@0 604 {
michael@0 605 }
michael@0 606
michael@0 607 nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
michael@0 608 {
michael@0 609 // Do not free printers here
michael@0 610 // GlobalPrinters::GetInstance()->FreeGlobalPrinters();
michael@0 611 }
michael@0 612
michael@0 613 NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
michael@0 614
michael@0 615 //----------------------------------------------------------------------------------
michael@0 616 // Return the Default Printer name
michael@0 617 /* readonly attribute wstring defaultPrinterName; */
michael@0 618 NS_IMETHODIMP
michael@0 619 nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
michael@0 620 {
michael@0 621 NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
michael@0 622
michael@0 623 *aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
michael@0 624
michael@0 625 return NS_OK;
michael@0 626 }
michael@0 627
michael@0 628 /* void initPrintSettingsFromPrinter (in wstring aPrinterName, in nsIPrintSettings aPrintSettings); */
michael@0 629 NS_IMETHODIMP
michael@0 630 nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings)
michael@0 631 {
michael@0 632 NS_ENSURE_ARG_POINTER(aPrinterName);
michael@0 633 NS_ENSURE_ARG_POINTER(aPrintSettings);
michael@0 634
michael@0 635 if (!*aPrinterName) {
michael@0 636 return NS_OK;
michael@0 637 }
michael@0 638
michael@0 639 nsRefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
michael@0 640 if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
michael@0 641
michael@0 642 if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
michael@0 643 return NS_ERROR_FAILURE;
michael@0 644 }
michael@0 645
michael@0 646 devSpecWin->GetDataFromPrinter(aPrinterName);
michael@0 647
michael@0 648 LPDEVMODEW devmode;
michael@0 649 devSpecWin->GetDevMode(devmode);
michael@0 650 NS_ASSERTION(devmode, "DevMode can't be NULL here");
michael@0 651 if (devmode) {
michael@0 652 aPrintSettings->SetPrinterName(aPrinterName);
michael@0 653 nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(aPrintSettings, devmode);
michael@0 654 }
michael@0 655
michael@0 656 // Free them, we won't need them for a while
michael@0 657 GlobalPrinters::GetInstance()->FreeGlobalPrinters();
michael@0 658 return NS_OK;
michael@0 659 }
michael@0 660
michael@0 661
michael@0 662 //----------------------------------------------------------------------------------
michael@0 663 // Enumerate all the Printers from the global array and pass their
michael@0 664 // names back (usually to script)
michael@0 665 NS_IMETHODIMP
michael@0 666 nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameList)
michael@0 667 {
michael@0 668 NS_ENSURE_ARG_POINTER(aPrinterNameList);
michael@0 669 *aPrinterNameList = nullptr;
michael@0 670
michael@0 671 nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
michael@0 672 if (NS_FAILED(rv)) {
michael@0 673 PR_PL(("***** nsDeviceContextSpecWin::GetPrinterNameList - Couldn't enumerate printers!\n"));
michael@0 674 return rv;
michael@0 675 }
michael@0 676
michael@0 677 uint32_t numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
michael@0 678 nsTArray<nsString> *printers = new nsTArray<nsString>(numPrinters);
michael@0 679 if (!printers)
michael@0 680 return NS_ERROR_OUT_OF_MEMORY;
michael@0 681
michael@0 682 uint32_t printerInx = 0;
michael@0 683 while( printerInx < numPrinters ) {
michael@0 684 LPWSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx++);
michael@0 685 printers->AppendElement(nsDependentString(name));
michael@0 686 }
michael@0 687
michael@0 688 return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
michael@0 689 }
michael@0 690
michael@0 691 //----------------------------------------------------------------------------------
michael@0 692 // Display the AdvancedDocumentProperties for the selected Printer
michael@0 693 NS_IMETHODIMP nsPrinterEnumeratorWin::DisplayPropertiesDlg(const char16_t *aPrinterName, nsIPrintSettings* aPrintSettings)
michael@0 694 {
michael@0 695 // Implementation removed because it is unused
michael@0 696 return NS_OK;
michael@0 697 }
michael@0 698
michael@0 699 //----------------------------------------------------------------------------------
michael@0 700 //-- Global Printers
michael@0 701 //----------------------------------------------------------------------------------
michael@0 702
michael@0 703 //----------------------------------------------------------------------------------
michael@0 704 // THe array hold the name and port for each printer
michael@0 705 void
michael@0 706 GlobalPrinters::ReallocatePrinters()
michael@0 707 {
michael@0 708 if (PrintersAreAllocated()) {
michael@0 709 FreeGlobalPrinters();
michael@0 710 }
michael@0 711 mPrinters = new nsTArray<LPWSTR>();
michael@0 712 NS_ASSERTION(mPrinters, "Printers Array is NULL!");
michael@0 713 }
michael@0 714
michael@0 715 //----------------------------------------------------------------------------------
michael@0 716 void
michael@0 717 GlobalPrinters::FreeGlobalPrinters()
michael@0 718 {
michael@0 719 if (mPrinters != nullptr) {
michael@0 720 for (uint32_t i=0;i<mPrinters->Length();i++) {
michael@0 721 free(mPrinters->ElementAt(i));
michael@0 722 }
michael@0 723 delete mPrinters;
michael@0 724 mPrinters = nullptr;
michael@0 725 }
michael@0 726 }
michael@0 727
michael@0 728 //----------------------------------------------------------------------------------
michael@0 729 nsresult
michael@0 730 GlobalPrinters::EnumerateNativePrinters()
michael@0 731 {
michael@0 732 nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
michael@0 733 PR_PL(("-----------------------\n"));
michael@0 734 PR_PL(("EnumerateNativePrinters\n"));
michael@0 735
michael@0 736 WCHAR szDefaultPrinterName[1024];
michael@0 737 DWORD status = GetProfileStringW(L"devices", 0, L",",
michael@0 738 szDefaultPrinterName,
michael@0 739 ArrayLength(szDefaultPrinterName));
michael@0 740 if (status > 0) {
michael@0 741 DWORD count = 0;
michael@0 742 LPWSTR sPtr = szDefaultPrinterName;
michael@0 743 LPWSTR ePtr = szDefaultPrinterName + status;
michael@0 744 LPWSTR prvPtr = sPtr;
michael@0 745 while (sPtr < ePtr) {
michael@0 746 if (*sPtr == 0) {
michael@0 747 LPWSTR name = wcsdup(prvPtr);
michael@0 748 mPrinters->AppendElement(name);
michael@0 749 PR_PL(("Printer Name: %s\n", prvPtr));
michael@0 750 prvPtr = sPtr+1;
michael@0 751 count++;
michael@0 752 }
michael@0 753 sPtr++;
michael@0 754 }
michael@0 755 rv = NS_OK;
michael@0 756 }
michael@0 757 PR_PL(("-----------------------\n"));
michael@0 758 return rv;
michael@0 759 }
michael@0 760
michael@0 761 //------------------------------------------------------------------
michael@0 762 // Uses the GetProfileString to get the default printer from the registry
michael@0 763 void
michael@0 764 GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName)
michael@0 765 {
michael@0 766 aDefaultPrinterName.Truncate();
michael@0 767 WCHAR szDefaultPrinterName[1024];
michael@0 768 DWORD status = GetProfileStringW(L"windows", L"device", 0,
michael@0 769 szDefaultPrinterName,
michael@0 770 ArrayLength(szDefaultPrinterName));
michael@0 771 if (status > 0) {
michael@0 772 WCHAR comma = ',';
michael@0 773 LPWSTR sPtr = szDefaultPrinterName;
michael@0 774 while (*sPtr != comma && *sPtr != 0)
michael@0 775 sPtr++;
michael@0 776 if (*sPtr == comma) {
michael@0 777 *sPtr = 0;
michael@0 778 }
michael@0 779 aDefaultPrinterName = szDefaultPrinterName;
michael@0 780 } else {
michael@0 781 aDefaultPrinterName = EmptyString();
michael@0 782 }
michael@0 783
michael@0 784 PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName.get()));
michael@0 785 }
michael@0 786
michael@0 787 //----------------------------------------------------------------------------------
michael@0 788 // This goes and gets the list of available printers and puts
michael@0 789 // the default printer at the beginning of the list
michael@0 790 nsresult
michael@0 791 GlobalPrinters::EnumeratePrinterList()
michael@0 792 {
michael@0 793 // reallocate and get a new list each time it is asked for
michael@0 794 // this deletes the list and re-allocates them
michael@0 795 ReallocatePrinters();
michael@0 796
michael@0 797 // any of these could only fail with an OUT_MEMORY_ERROR
michael@0 798 // PRINTER_ENUM_LOCAL should get the network printers on Win95
michael@0 799 nsresult rv = EnumerateNativePrinters();
michael@0 800 if (NS_FAILED(rv)) return rv;
michael@0 801
michael@0 802 // get the name of the default printer
michael@0 803 nsAutoString defPrinterName;
michael@0 804 GetDefaultPrinterName(defPrinterName);
michael@0 805
michael@0 806 // put the default printer at the beginning of list
michael@0 807 if (!defPrinterName.IsEmpty()) {
michael@0 808 for (uint32_t i=0;i<mPrinters->Length();i++) {
michael@0 809 LPWSTR name = mPrinters->ElementAt(i);
michael@0 810 if (defPrinterName.Equals(name)) {
michael@0 811 if (i > 0) {
michael@0 812 LPWSTR ptr = mPrinters->ElementAt(0);
michael@0 813 mPrinters->ElementAt(0) = name;
michael@0 814 mPrinters->ElementAt(i) = ptr;
michael@0 815 }
michael@0 816 break;
michael@0 817 }
michael@0 818 }
michael@0 819 }
michael@0 820
michael@0 821 // make sure we at least tried to get the printers
michael@0 822 if (!PrintersAreAllocated()) {
michael@0 823 PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
michael@0 824 return NS_ERROR_FAILURE;
michael@0 825 }
michael@0 826
michael@0 827 return NS_OK;
michael@0 828 }
michael@0 829

mercurial