Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / widget / src / windows / nsDeviceContextSpecWin.cpp
blob60a04fa5c2d012af6dc90282efc273d4945aecde
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsDeviceContextSpecWin.h"
39 #include "prmem.h"
40 #include <winspool.h>
41 #include <tchar.h>
43 #include "nsAutoPtr.h"
44 #include "nsIWidget.h"
46 #include "nsVoidArray.h"
47 #include "nsIPrintSettingsWin.h"
49 #include "nsString.h"
50 #include "nsCRT.h"
51 #include "nsIServiceManager.h"
52 #include "nsReadableUtils.h"
53 #include "nsStringEnumerator.h"
55 #include "gfxPDFSurface.h"
56 #include "gfxWindowsSurface.h"
58 #include "nsIFileStreams.h"
59 #include "nsIWindowWatcher.h"
60 #include "nsIDOMWindow.h"
62 // For NS_CopyNativeToUnicode
63 #include "nsNativeCharsetUtils.h"
65 // File Picker
66 #include "nsILocalFile.h"
67 #include "nsIFile.h"
68 #include "nsIFilePicker.h"
69 #include "nsIStringBundle.h"
70 #define NS_ERROR_GFX_PRINTER_BUNDLE_URL "chrome://global/locale/printing.properties"
72 #include "prlog.h"
73 #ifdef PR_LOGGING
74 PRLogModuleInfo * kWidgetPrintingLogMod = PR_NewLogModule("printing-widget");
75 #define PR_PL(_p1) PR_LOG(kWidgetPrintingLogMod, PR_LOG_DEBUG, _p1)
76 #else
77 #define PR_PL(_p1)
78 #endif
80 //----------------------------------------------------------------------------------
81 // The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
82 // The PrinterEnumerator creates the printer info
83 // but the nsDeviceContextSpecWin cleans it up
84 // If it gets created (via the Page Setup Dialog) but the user never prints anything
85 // then it will never be delete, so this class takes care of that.
86 class GlobalPrinters {
87 public:
88 static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
89 ~GlobalPrinters() { FreeGlobalPrinters(); }
91 void FreeGlobalPrinters();
93 PRBool PrintersAreAllocated() { return mPrinters != nsnull; }
94 LPTSTR GetItemFromList(PRInt32 aInx) { return mPrinters?(LPTSTR)mPrinters->ElementAt(aInx):nsnull; }
95 nsresult EnumeratePrinterList();
96 void GetDefaultPrinterName(LPTSTR& aDefaultPrinterName);
97 PRInt32 GetNumPrinters() { return mPrinters?mPrinters->Count():0; }
99 protected:
100 GlobalPrinters() {}
101 nsresult EnumerateNativePrinters();
102 void ReallocatePrinters();
104 static GlobalPrinters mGlobalPrinters;
105 static nsVoidArray* mPrinters;
107 //---------------
108 // static members
109 GlobalPrinters GlobalPrinters::mGlobalPrinters;
110 nsVoidArray* GlobalPrinters::mPrinters = nsnull;
113 //******************************************************
114 // Define native paper sizes
115 //******************************************************
116 typedef struct {
117 short mPaperSize; // native enum
118 double mWidth;
119 double mHeight;
120 PRBool mIsInches;
121 } NativePaperSizes;
123 // There are around 40 default print sizes defined by Windows
124 const NativePaperSizes kPaperSizes[] = {
125 {DMPAPER_LETTER, 8.5, 11.0, PR_TRUE},
126 {DMPAPER_LEGAL, 8.5, 14.0, PR_TRUE},
127 {DMPAPER_A4, 210.0, 297.0, PR_FALSE},
128 {DMPAPER_B4, 250.0, 354.0, PR_FALSE},
129 {DMPAPER_B5, 182.0, 257.0, PR_FALSE},
130 #ifndef WINCE
131 {DMPAPER_TABLOID, 11.0, 17.0, PR_TRUE},
132 {DMPAPER_LEDGER, 17.0, 11.0, PR_TRUE},
133 {DMPAPER_STATEMENT, 5.5, 8.5, PR_TRUE},
134 {DMPAPER_EXECUTIVE, 7.25, 10.5, PR_TRUE},
135 {DMPAPER_A3, 297.0, 420.0, PR_FALSE},
136 {DMPAPER_A5, 148.0, 210.0, PR_FALSE},
137 {DMPAPER_CSHEET, 17.0, 22.0, PR_TRUE},
138 {DMPAPER_DSHEET, 22.0, 34.0, PR_TRUE},
139 {DMPAPER_ESHEET, 34.0, 44.0, PR_TRUE},
140 {DMPAPER_LETTERSMALL, 8.5, 11.0, PR_TRUE},
141 {DMPAPER_A4SMALL, 210.0, 297.0, PR_FALSE},
142 {DMPAPER_FOLIO, 8.5, 13.0, PR_TRUE},
143 {DMPAPER_QUARTO, 215.0, 275.0, PR_FALSE},
144 {DMPAPER_10X14, 10.0, 14.0, PR_TRUE},
145 {DMPAPER_11X17, 11.0, 17.0, PR_TRUE},
146 {DMPAPER_NOTE, 8.5, 11.0, PR_TRUE},
147 {DMPAPER_ENV_9, 3.875, 8.875, PR_TRUE},
148 {DMPAPER_ENV_10, 40.125, 9.5, PR_TRUE},
149 {DMPAPER_ENV_11, 4.5, 10.375, PR_TRUE},
150 {DMPAPER_ENV_12, 4.75, 11.0, PR_TRUE},
151 {DMPAPER_ENV_14, 5.0, 11.5, PR_TRUE},
152 {DMPAPER_ENV_DL, 110.0, 220.0, PR_FALSE},
153 {DMPAPER_ENV_C5, 162.0, 229.0, PR_FALSE},
154 {DMPAPER_ENV_C3, 324.0, 458.0, PR_FALSE},
155 {DMPAPER_ENV_C4, 229.0, 324.0, PR_FALSE},
156 {DMPAPER_ENV_C6, 114.0, 162.0, PR_FALSE},
157 {DMPAPER_ENV_C65, 114.0, 229.0, PR_FALSE},
158 {DMPAPER_ENV_B4, 250.0, 353.0, PR_FALSE},
159 {DMPAPER_ENV_B5, 176.0, 250.0, PR_FALSE},
160 {DMPAPER_ENV_B6, 176.0, 125.0, PR_FALSE},
161 {DMPAPER_ENV_ITALY, 110.0, 230.0, PR_FALSE},
162 {DMPAPER_ENV_MONARCH, 3.875, 7.5, PR_TRUE},
163 {DMPAPER_ENV_PERSONAL, 3.625, 6.5, PR_TRUE},
164 {DMPAPER_FANFOLD_US, 14.875, 11.0, PR_TRUE},
165 {DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, PR_TRUE},
166 {DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, PR_TRUE},
167 #endif // WINCE
169 const PRInt32 kNumPaperSizes = 41;
171 //----------------------------------------------------------------------------------
172 nsDeviceContextSpecWin::nsDeviceContextSpecWin()
174 mDriverName = nsnull;
175 mDeviceName = nsnull;
176 mDevMode = NULL;
181 //----------------------------------------------------------------------------------
183 NS_IMPL_ISUPPORTS1(nsDeviceContextSpecWin, nsIDeviceContextSpec)
185 nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
187 SetDeviceName(nsnull);
188 SetDriverName(nsnull);
189 SetDevMode(NULL);
191 nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
192 if (psWin) {
193 psWin->SetDeviceName(nsnull);
194 psWin->SetDriverName(nsnull);
195 psWin->SetDevMode(NULL);
198 // Free them, we won't need them for a while
199 GlobalPrinters::GetInstance()->FreeGlobalPrinters();
203 //------------------------------------------------------------------
204 // helper
205 static PRUnichar * GetDefaultPrinterNameFromGlobalPrinters()
207 PRUnichar * printerName;
208 LPTSTR lpPrtName;
209 GlobalPrinters::GetInstance()->GetDefaultPrinterName(lpPrtName);
210 nsAutoString str;
211 NS_CopyNativeToUnicode(nsDependentCString((char *)lpPrtName), str);
212 printerName = ToNewUnicode(str);
213 free(lpPrtName);
214 return printerName;
217 //----------------------------------------------------------------
218 static nsresult
219 EnumerateNativePrinters(DWORD aWhichPrinters, LPWSTR aPrinterName, PRBool& aIsFound, PRBool& aIsFile)
221 #ifdef WINCE
222 aIsFound = PR_FALSE;
223 #else
224 DWORD dwSizeNeeded = 0;
225 DWORD dwNumItems = 0;
226 LPPRINTER_INFO_2W lpInfo = NULL;
228 // Get buffer size
229 if (::EnumPrinters ( aWhichPrinters, NULL, 2, NULL, 0, &dwSizeNeeded, &dwNumItems )) {
230 return NS_ERROR_FAILURE;
233 // allocate memory
234 lpInfo = (LPPRINTER_INFO_2W)HeapAlloc ( GetProcessHeap (), HEAP_ZERO_MEMORY, dwSizeNeeded );
235 if ( lpInfo == NULL ) {
236 return NS_ERROR_OUT_OF_MEMORY;
239 if (::EnumPrinters ( PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)lpInfo, dwSizeNeeded, &dwSizeNeeded, &dwNumItems) == 0 ) {
240 ::HeapFree(GetProcessHeap (), 0, lpInfo);
241 return NS_OK;
245 for (DWORD i = 0; i < dwNumItems; i++ ) {
246 if (wcscmp(lpInfo[i].pPrinterName, aPrinterName) == 0) {
247 aIsFound = PR_TRUE;
248 aIsFile = wcscmp(lpInfo[i].pPortName, L"FILE:") == 0;
249 break;
253 ::HeapFree(GetProcessHeap (), 0, lpInfo);
254 #endif
255 return NS_OK;
258 //----------------------------------------------------------------
259 static void
260 CheckForPrintToFileWithName(LPWSTR aPrinterName, PRBool& aIsFile)
262 PRBool isFound = PR_FALSE;
263 aIsFile = PR_FALSE;
264 #ifndef WINCE
265 nsresult rv = EnumerateNativePrinters(PRINTER_ENUM_LOCAL, aPrinterName, isFound, aIsFile);
266 if (isFound) return;
268 rv = EnumerateNativePrinters(PRINTER_ENUM_NETWORK, aPrinterName, isFound, aIsFile);
269 if (isFound) return;
271 rv = EnumerateNativePrinters(PRINTER_ENUM_SHARED, aPrinterName, isFound, aIsFile);
272 if (isFound) return;
274 rv = EnumerateNativePrinters(PRINTER_ENUM_REMOTE, aPrinterName, isFound, aIsFile);
275 if (isFound) return;
276 #endif
279 static nsresult
280 GetFileNameForPrintSettings(nsIPrintSettings* aPS)
282 // for testing
283 #ifdef DEBUG_rods
284 return NS_OK;
285 #endif
287 nsresult rv;
289 nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1", &rv);
290 NS_ENSURE_SUCCESS(rv, rv);
292 nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
293 NS_ENSURE_SUCCESS(rv, rv);
294 nsCOMPtr<nsIStringBundle> bundle;
295 rv = bundleService->CreateBundle(NS_ERROR_GFX_PRINTER_BUNDLE_URL, getter_AddRefs(bundle));
296 NS_ENSURE_SUCCESS(rv, rv);
298 nsXPIDLString title;
299 rv = bundle->GetStringFromName(NS_LITERAL_STRING("PrintToFile").get(), getter_Copies(title));
300 NS_ENSURE_SUCCESS(rv, rv);
302 nsCOMPtr<nsIWindowWatcher> wwatch =
303 (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
304 NS_ENSURE_SUCCESS(rv, rv);
306 nsCOMPtr<nsIDOMWindow> window;
307 wwatch->GetActiveWindow(getter_AddRefs(window));
309 rv = filePicker->Init(window, title, nsIFilePicker::modeSave);
310 NS_ENSURE_SUCCESS(rv, rv);
312 rv = filePicker->AppendFilters(nsIFilePicker::filterAll);
313 NS_ENSURE_SUCCESS(rv, rv);
315 PRUnichar* fileName;
316 aPS->GetToFileName(&fileName);
318 if (fileName) {
319 if (*fileName) {
320 nsAutoString leafName;
321 nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
322 if (file) {
323 rv = file->InitWithPath(nsDependentString(fileName));
324 if (NS_SUCCEEDED(rv)) {
325 file->GetLeafName(leafName);
326 filePicker->SetDisplayDirectory(file);
329 if (!leafName.IsEmpty()) {
330 rv = filePicker->SetDefaultString(leafName);
332 NS_ENSURE_SUCCESS(rv, rv);
334 nsMemory::Free(fileName);
337 PRInt16 dialogResult;
338 filePicker->Show(&dialogResult);
340 if (dialogResult == nsIFilePicker::returnCancel) {
341 return NS_ERROR_ABORT;
344 nsCOMPtr<nsILocalFile> localFile;
345 rv = filePicker->GetFile(getter_AddRefs(localFile));
346 NS_ENSURE_SUCCESS(rv, rv);
348 if (dialogResult == nsIFilePicker::returnReplace) {
349 // be extra safe and only delete when the file is really a file
350 PRBool isFile;
351 rv = localFile->IsFile(&isFile);
352 if (NS_SUCCEEDED(rv) && isFile) {
353 rv = localFile->Remove(PR_FALSE /* recursive delete */);
354 NS_ENSURE_SUCCESS(rv, rv);
358 nsAutoString unicodePath;
359 rv = localFile->GetPath(unicodePath);
360 NS_ENSURE_SUCCESS(rv,rv);
362 if (unicodePath.IsEmpty()) {
363 rv = NS_ERROR_ABORT;
366 if (NS_SUCCEEDED(rv)) aPS->SetToFileName(unicodePath.get());
368 return rv;
371 //----------------------------------------------------------------------------------
372 static nsresult
373 CheckForPrintToFile(nsIPrintSettings* aPS, LPWSTR aPrinterName, PRUnichar* aUPrinterName)
375 nsresult rv = NS_OK;
377 if (!aPrinterName && !aUPrinterName) return rv;
379 PRBool toFile;
380 CheckForPrintToFileWithName(aPrinterName?aPrinterName:aUPrinterName, toFile);
381 // Since the driver wasn't a "Print To File" Driver, check to see
382 // if the name of the file has been set to the special "FILE:"
383 if (!toFile) {
384 nsXPIDLString toFileName;
385 aPS->GetToFileName(getter_Copies(toFileName));
386 if (toFileName) {
387 if (*toFileName) {
388 if (toFileName.EqualsLiteral("FILE:")) {
389 // this skips the setting of the "print to file" info below
390 // which we don't want to do.
391 return NS_OK;
396 aPS->SetPrintToFile(toFile);
397 if (toFile) {
398 rv = GetFileNameForPrintSettings(aPS);
400 return rv;
403 //----------------------------------------------------------------------------------
404 NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
405 nsIPrintSettings* aPrintSettings,
406 PRBool aIsPrintPreview)
408 mPrintSettings = aPrintSettings;
410 nsresult rv = aIsPrintPreview ? NS_ERROR_GFX_PRINTER_PRINTPREVIEW :
411 NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
412 if (aPrintSettings) {
413 nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
414 if (psWin) {
415 PRUnichar* deviceName;
416 PRUnichar* driverName;
417 psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
418 psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
420 LPDEVMODEW devMode;
421 psWin->GetDevMode(&devMode); // creates new memory (makes a copy)
423 if (deviceName && driverName && devMode) {
424 // Scaling is special, it is one of the few
425 // devMode items that we control in layout
426 if (devMode->dmFields & DM_SCALE) {
427 double scale = double(devMode->dmScale) / 100.0f;
428 if (scale != 1.0) {
429 aPrintSettings->SetScaling(scale);
430 devMode->dmScale = 100;
434 SetDeviceName(deviceName);
435 SetDriverName(driverName);
436 SetDevMode(devMode);
438 if (!aIsPrintPreview) {
439 rv = CheckForPrintToFile(mPrintSettings, deviceName, nsnull);
440 if (NS_FAILED(rv)) {
441 nsCRT::free(deviceName);
442 nsCRT::free(driverName);
443 return NS_ERROR_FAILURE;
447 // clean up
448 nsCRT::free(deviceName);
449 nsCRT::free(driverName);
451 return NS_OK;
452 } else {
453 PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
454 if (deviceName) nsCRT::free(deviceName);
455 if (driverName) nsCRT::free(driverName);
456 if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
459 } else {
460 PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
463 LPDEVMODEW pDevMode = NULL;
464 HGLOBAL hDevNames = NULL;
466 // Get the Print Name to be used
467 PRUnichar * printerName;
468 mPrintSettings->GetPrinterName(&printerName);
470 // If there is no name then use the default printer
471 if (!printerName || (printerName && !*printerName)) {
472 printerName = GetDefaultPrinterNameFromGlobalPrinters();
475 NS_ASSERTION(printerName, "We have to have a printer name");
476 if (!printerName || !*printerName) return rv;
478 if (!aIsPrintPreview) {
479 CheckForPrintToFile(mPrintSettings, nsnull, printerName);
482 return GetDataFromPrinter(printerName, mPrintSettings);
485 //----------------------------------------------------------
486 // Helper Function - Free and reallocate the string
487 static void CleanAndCopyString(PRUnichar*& aStr, const PRUnichar* aNewStr)
489 if (aStr != nsnull) {
490 if (aNewStr != nsnull && wcslen(aStr) > wcslen(aNewStr)) { // reuse it if we can
491 wcscpy(aStr, aNewStr);
492 return;
493 } else {
494 PR_Free(aStr);
495 aStr = nsnull;
499 if (nsnull != aNewStr) {
500 aStr = (PRUnichar *)PR_Malloc(sizeof(PRUnichar)*(wcslen(aNewStr) + 1));
501 wcscpy(aStr, aNewStr);
505 NS_IMETHODIMP nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface **surface)
507 NS_ASSERTION(mDevMode, "DevMode can't be NULL here");
509 nsRefPtr<gfxASurface> newSurface;
511 PRInt16 outputFormat;
512 mPrintSettings->GetOutputFormat(&outputFormat);
514 if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
515 nsXPIDLString filename;
516 mPrintSettings->GetToFileName(getter_Copies(filename));
518 double width, height;
519 mPrintSettings->GetEffectivePageSize(&width, &height);
520 // convert twips to points
521 width /= TWIPS_PER_POINT_FLOAT;
522 height /= TWIPS_PER_POINT_FLOAT;
524 nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
525 nsresult rv = file->InitWithPath(filename);
526 if (NS_FAILED(rv))
527 return rv;
529 nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
530 rv = stream->Init(file, -1, -1, 0);
531 if (NS_FAILED(rv))
532 return rv;
534 newSurface = new gfxPDFSurface(stream, gfxSize(width, height));
535 } else {
536 if (mDevMode) {
537 HDC dc = ::CreateDCW(mDriverName, mDeviceName, NULL, mDevMode);
539 // have this surface take over ownership of this DC
540 newSurface = new gfxWindowsSurface(dc, gfxWindowsSurface::FLAG_TAKE_DC | gfxWindowsSurface::FLAG_FOR_PRINTING);
544 if (newSurface) {
545 *surface = newSurface;
546 NS_ADDREF(*surface);
547 return NS_OK;
550 *surface = nsnull;
551 return NS_ERROR_FAILURE;
554 //----------------------------------------------------------------------------------
555 void nsDeviceContextSpecWin::SetDeviceName(const PRUnichar* aDeviceName)
557 CleanAndCopyString(mDeviceName, aDeviceName);
560 //----------------------------------------------------------------------------------
561 void nsDeviceContextSpecWin::SetDriverName(const PRUnichar* aDriverName)
563 CleanAndCopyString(mDriverName, aDriverName);
566 //----------------------------------------------------------------------------------
567 void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode)
569 if (mDevMode) {
570 ::HeapFree(::GetProcessHeap(), 0, mDevMode);
573 mDevMode = aDevMode;
576 //------------------------------------------------------------------
577 void
578 nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW &aDevMode)
580 aDevMode = mDevMode;
583 //----------------------------------------------------------------------------------
584 // Map an incoming size to a Windows Native enum in the DevMode
585 static void
586 MapPaperSizeToNativeEnum(LPDEVMODEW aDevMode,
587 PRInt16 aType,
588 double aW,
589 double aH)
592 #ifdef DEBUG_rods
593 BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
594 BOOL doingPaperSize = aDevMode->dmFields & DM_PAPERSIZE;
595 BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
596 BOOL doingPaperWidth = aDevMode->dmFields & DM_PAPERWIDTH;
597 #endif
599 PRBool foundEnum = PR_FALSE;
600 for (PRInt32 i=0;i<kNumPaperSizes;i++) {
601 if (kPaperSizes[i].mWidth == aW && kPaperSizes[i].mHeight == aH) {
602 aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize;
603 aDevMode->dmFields &= ~DM_PAPERLENGTH;
604 aDevMode->dmFields &= ~DM_PAPERWIDTH;
605 aDevMode->dmFields |= DM_PAPERSIZE;
606 return;
610 short width = 0;
611 short height = 0;
612 if (aType == nsIPrintSettings::kPaperSizeInches) {
613 width = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10);
614 height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10);
616 } else if (aType == nsIPrintSettings::kPaperSizeMillimeters) {
617 width = short(aW / 10.0);
618 height = short(aH / 10.0);
619 } else {
620 return; // don't set anything
623 // width and height is in
624 aDevMode->dmPaperSize = 0;
625 aDevMode->dmPaperWidth = width;
626 aDevMode->dmPaperLength = height;
628 aDevMode->dmFields |= DM_PAPERSIZE;
629 aDevMode->dmFields |= DM_PAPERLENGTH;
630 aDevMode->dmFields |= DM_PAPERWIDTH;
633 //----------------------------------------------------------------------------------
634 // Setup Paper Size & Orientation options into the DevMode
636 static void
637 SetupDevModeFromSettings(LPDEVMODEW aDevMode, nsIPrintSettings* aPrintSettings)
639 // Setup paper size
640 if (aPrintSettings) {
641 PRInt16 type;
642 aPrintSettings->GetPaperSizeType(&type);
643 if (type == nsIPrintSettings::kPaperSizeNativeData) {
644 PRInt16 paperEnum;
645 aPrintSettings->GetPaperData(&paperEnum);
646 aDevMode->dmPaperSize = paperEnum;
647 aDevMode->dmFields &= ~DM_PAPERLENGTH;
648 aDevMode->dmFields &= ~DM_PAPERWIDTH;
649 aDevMode->dmFields |= DM_PAPERSIZE;
650 } else {
651 PRInt16 unit;
652 double width, height;
653 aPrintSettings->GetPaperSizeUnit(&unit);
654 aPrintSettings->GetPaperWidth(&width);
655 aPrintSettings->GetPaperHeight(&height);
656 MapPaperSizeToNativeEnum(aDevMode, unit, width, height);
659 // Setup Orientation
660 PRInt32 orientation;
661 aPrintSettings->GetOrientation(&orientation);
662 aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE;
663 aDevMode->dmFields |= DM_ORIENTATION;
665 // Setup Number of Copies
666 PRInt32 copies;
667 aPrintSettings->GetNumCopies(&copies);
668 aDevMode->dmCopies = copies;
669 aDevMode->dmFields |= DM_COPIES;
674 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
675 static void DisplayLastError()
677 LPVOID lpMsgBuf;
678 DWORD errCode = GetLastError();
680 FormatMessage(
681 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
682 NULL,
683 GetLastError(),
684 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
685 (LPTSTR) &lpMsgBuf,
687 NULL
690 // Display the string.
691 MessageBox( NULL, (const char *)lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
693 #define DISPLAY_LAST_ERROR DisplayLastError();
694 #else
695 #define DISPLAY_LAST_ERROR
696 #endif
698 //----------------------------------------------------------------------------------
699 // Setup the object's data member with the selected printer's data
700 nsresult
701 nsDeviceContextSpecWin::GetDataFromPrinter(const PRUnichar * aName, nsIPrintSettings* aPS)
703 #ifdef WINCE
704 return NS_ERROR_NOT_IMPLEMENTED;
705 #else
706 nsresult rv = NS_ERROR_FAILURE;
708 if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
709 rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
710 if (NS_FAILED(rv)) {
711 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
712 DISPLAY_LAST_ERROR
714 NS_ENSURE_SUCCESS(rv, rv);
717 HANDLE hPrinter = NULL;
719 BOOL status = ::OpenPrinterW((LPWSTR)(aName),
720 &hPrinter, NULL);
721 if (status) {
723 LPDEVMODEW pDevMode;
724 DWORD dwNeeded, dwRet;
726 // Allocate a buffer of the correct size.
727 dwNeeded = ::DocumentPropertiesW(NULL, hPrinter,
728 const_cast<wchar_t*>(aName),
729 NULL, NULL, 0);
731 pDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
732 if (!pDevMode) return NS_ERROR_FAILURE;
734 // Get the default DevMode for the printer and modify it for our needs.
735 dwRet = DocumentPropertiesW(NULL, hPrinter,
736 const_cast<wchar_t*>(aName),
737 pDevMode, NULL, DM_OUT_BUFFER);
739 if (dwRet == IDOK && aPS) {
740 SetupDevModeFromSettings(pDevMode, aPS);
741 // Sets back the changes we made to the DevMode into the Printer Driver
742 dwRet = ::DocumentPropertiesW(NULL, hPrinter,
743 const_cast<wchar_t*>(aName),
744 pDevMode, pDevMode,
745 DM_IN_BUFFER | DM_OUT_BUFFER);
748 if (dwRet != IDOK) {
749 ::HeapFree(::GetProcessHeap(), 0, pDevMode);
750 ::ClosePrinter(hPrinter);
751 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", dwRet, dwRet));
752 DISPLAY_LAST_ERROR
753 return NS_ERROR_FAILURE;
756 SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
758 SetDeviceName(aName);
760 SetDriverName(L"WINSPOOL");
762 ::ClosePrinter(hPrinter);
763 rv = NS_OK;
764 } else {
765 rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
766 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName).get()));
767 DISPLAY_LAST_ERROR
769 return rv;
770 #endif // WINCE
773 //----------------------------------------------------------------------------------
774 // Setup Paper Size options into the DevMode
776 // When using a data member it may be a HGLOCAL or LPDEVMODE
777 // if it is a HGLOBAL then we need to "lock" it to get the LPDEVMODE
778 // and unlock it when we are done.
779 void
780 nsDeviceContextSpecWin::SetupPaperInfoFromSettings()
782 LPDEVMODEW devMode;
784 GetDevMode(devMode);
785 NS_ASSERTION(devMode, "DevMode can't be NULL here");
786 if (devMode) {
787 SetupDevModeFromSettings(devMode, mPrintSettings);
791 //----------------------------------------------------------------------------------
792 // Helper Function - Free and reallocate the string
793 nsresult
794 nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings,
795 LPDEVMODEW aDevMode)
797 if (aPrintSettings == nsnull) {
798 return NS_ERROR_FAILURE;
800 aPrintSettings->SetIsInitializedFromPrinter(PR_TRUE);
802 BOOL doingNumCopies = aDevMode->dmFields & DM_COPIES;
803 BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
804 BOOL doingPaperSize = aDevMode->dmFields & DM_PAPERSIZE;
805 BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
806 BOOL doingPaperWidth = aDevMode->dmFields & DM_PAPERWIDTH;
808 if (doingOrientation) {
809 PRInt32 orientation = aDevMode->dmOrientation == DMORIENT_PORTRAIT?
810 nsIPrintSettings::kPortraitOrientation:nsIPrintSettings::kLandscapeOrientation;
811 aPrintSettings->SetOrientation(orientation);
814 // Setup Number of Copies
815 if (doingNumCopies) {
816 aPrintSettings->SetNumCopies(PRInt32(aDevMode->dmCopies));
819 if (aDevMode->dmFields & DM_SCALE) {
820 double scale = double(aDevMode->dmScale) / 100.0f;
821 if (scale != 1.0) {
822 aPrintSettings->SetScaling(scale);
823 aDevMode->dmScale = 100;
824 // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
825 //aPrintSettings->SetShrinkToFit(PR_FALSE);
829 if (doingPaperSize) {
830 aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData);
831 aPrintSettings->SetPaperData(aDevMode->dmPaperSize);
832 for (PRInt32 i=0;i<kNumPaperSizes;i++) {
833 if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
834 aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters);
835 break;
839 } else if (doingPaperLength && doingPaperWidth) {
840 PRBool found = PR_FALSE;
841 for (PRInt32 i=0;i<kNumPaperSizes;i++) {
842 if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
843 aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined);
844 aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth);
845 aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight);
846 aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters);
847 found = PR_TRUE;
848 break;
851 if (!found) {
852 return NS_ERROR_FAILURE;
854 } else {
855 return NS_ERROR_FAILURE;
857 return NS_OK;
860 //***********************************************************
861 // Printer Enumerator
862 //***********************************************************
863 nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
867 nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
869 // Do not free printers here
870 // GlobalPrinters::GetInstance()->FreeGlobalPrinters();
873 NS_IMPL_ISUPPORTS1(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
875 //----------------------------------------------------------------------------------
876 // Return the Default Printer name
877 /* readonly attribute wstring defaultPrinterName; */
878 NS_IMETHODIMP
879 nsPrinterEnumeratorWin::GetDefaultPrinterName(PRUnichar * *aDefaultPrinterName)
881 NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
883 *aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
885 return NS_OK;
888 /* void initPrintSettingsFromPrinter (in wstring aPrinterName, in nsIPrintSettings aPrintSettings); */
889 NS_IMETHODIMP
890 nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const PRUnichar *aPrinterName, nsIPrintSettings *aPrintSettings)
892 NS_ENSURE_ARG_POINTER(aPrinterName);
893 NS_ENSURE_ARG_POINTER(aPrintSettings);
895 if (!*aPrinterName) {
896 return NS_OK;
899 nsRefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
900 if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
902 if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
903 return NS_ERROR_FAILURE;
906 devSpecWin->GetDataFromPrinter(aPrinterName);
908 LPDEVMODEW devmode;
909 devSpecWin->GetDevMode(devmode);
910 NS_ASSERTION(devmode, "DevMode can't be NULL here");
911 if (devmode) {
912 aPrintSettings->SetPrinterName(aPrinterName);
913 nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(aPrintSettings, devmode);
916 // Free them, we won't need them for a while
917 GlobalPrinters::GetInstance()->FreeGlobalPrinters();
918 return NS_OK;
922 //----------------------------------------------------------------------------------
923 // Enumerate all the Printers from the global array and pass their
924 // names back (usually to script)
925 NS_IMETHODIMP
926 nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameList)
928 NS_ENSURE_ARG_POINTER(aPrinterNameList);
929 *aPrinterNameList = nsnull;
931 nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
932 if (NS_FAILED(rv)) {
933 PR_PL(("***** nsDeviceContextSpecWin::GetPrinterNameList - Couldn't enumerate printers!\n"));
934 return rv;
937 PRInt32 numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
938 nsStringArray *printers = new nsStringArray(numPrinters);
939 if (!printers)
940 return NS_ERROR_OUT_OF_MEMORY;
942 PRInt32 printerInx = 0;
943 while( printerInx < numPrinters ) {
944 LPTSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx++);
945 #ifdef UNICODE
946 nsDependentString newName(name);
947 #else
948 nsAutoString newName;
949 NS_CopyNativeToUnicode(nsDependentCString(name), newName);
950 #endif
951 printers->AppendString(newName);
954 return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
957 //----------------------------------------------------------------------------------
958 // Display the AdvancedDocumentProperties for the selected Printer
959 NS_IMETHODIMP nsPrinterEnumeratorWin::DisplayPropertiesDlg(const PRUnichar *aPrinterName, nsIPrintSettings* aPrintSettings)
961 // Implementation removed because it is unused
962 return NS_OK;
965 //----------------------------------------------------------------------------------
966 //-- Global Printers
967 //----------------------------------------------------------------------------------
969 //----------------------------------------------------------------------------------
970 // THe array hold the name and port for each printer
971 void
972 GlobalPrinters::ReallocatePrinters()
974 if (PrintersAreAllocated()) {
975 FreeGlobalPrinters();
977 mPrinters = new nsVoidArray();
978 NS_ASSERTION(mPrinters, "Printers Array is NULL!");
981 //----------------------------------------------------------------------------------
982 void
983 GlobalPrinters::FreeGlobalPrinters()
985 if (mPrinters != nsnull) {
986 for (int i=0;i<mPrinters->Count();i++) {
987 free((LPTSTR)mPrinters->ElementAt(i));
989 delete mPrinters;
990 mPrinters = nsnull;
994 //----------------------------------------------------------------------------------
995 nsresult
996 GlobalPrinters::EnumerateNativePrinters()
998 nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
999 #ifndef WINCE
1000 PR_PL(("-----------------------\n"));
1001 PR_PL(("EnumerateNativePrinters\n"));
1003 TCHAR szDefaultPrinterName[1024];
1004 DWORD status = GetProfileString("devices", 0, ",", szDefaultPrinterName, sizeof(szDefaultPrinterName)/sizeof(TCHAR));
1005 if (status > 0) {
1006 DWORD count = 0;
1007 LPTSTR sPtr = (LPTSTR)szDefaultPrinterName;
1008 LPTSTR ePtr = (LPTSTR)(szDefaultPrinterName+(status*sizeof(TCHAR)));
1009 LPTSTR prvPtr = sPtr;
1010 while (sPtr < ePtr) {
1011 if (*sPtr == NULL) {
1012 LPTSTR name = _tcsdup(prvPtr);
1013 mPrinters->AppendElement(name);
1014 PR_PL(("Printer Name: %s\n", prvPtr));
1015 prvPtr = sPtr+1;
1016 count++;
1018 sPtr++;
1020 rv = NS_OK;
1022 PR_PL(("-----------------------\n"));
1023 #endif
1024 return rv;
1027 //------------------------------------------------------------------
1028 // Uses the GetProfileString to get the default printer from the registry
1029 void
1030 GlobalPrinters::GetDefaultPrinterName(LPTSTR& aDefaultPrinterName)
1032 #ifndef WINCE
1033 aDefaultPrinterName = nsnull;
1034 TCHAR szDefaultPrinterName[1024];
1035 DWORD status = GetProfileString("windows", "device", 0, szDefaultPrinterName, sizeof(szDefaultPrinterName)/sizeof(TCHAR));
1036 if (status > 0) {
1037 TCHAR comma = (TCHAR)',';
1038 LPTSTR sPtr = (LPTSTR)szDefaultPrinterName;
1039 while (*sPtr != comma && *sPtr != NULL)
1040 sPtr++;
1041 if (*sPtr == comma) {
1042 *sPtr = NULL;
1044 aDefaultPrinterName = _tcsdup(szDefaultPrinterName);
1045 } else {
1046 aDefaultPrinterName = _tcsdup("");
1049 PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName));
1050 #else
1051 aDefaultPrinterName = TEXT("UNKNOWN");
1052 #endif
1055 //----------------------------------------------------------------------------------
1056 // This goes and gets the list of available printers and puts
1057 // the default printer at the beginning of the list
1058 nsresult
1059 GlobalPrinters::EnumeratePrinterList()
1061 // reallocate and get a new list each time it is asked for
1062 // this deletes the list and re-allocates them
1063 ReallocatePrinters();
1065 // any of these could only fail with an OUT_MEMORY_ERROR
1066 // PRINTER_ENUM_LOCAL should get the network printers on Win95
1067 nsresult rv = EnumerateNativePrinters();
1068 if (NS_FAILED(rv)) return rv;
1070 // get the name of the default printer
1071 LPTSTR defPrinterName;
1072 GetDefaultPrinterName(defPrinterName);
1074 // put the default printer at the beginning of list
1075 if (defPrinterName != nsnull) {
1076 for (PRInt32 i=0;i<mPrinters->Count();i++) {
1077 LPTSTR name = (LPTSTR)mPrinters->ElementAt(i);
1078 if (!_tcscmp(name, defPrinterName)) {
1079 if (i > 0) {
1080 LPTSTR ptr = (LPTSTR)mPrinters->ElementAt(0);
1081 mPrinters->ReplaceElementAt((void*)name, 0);
1082 mPrinters->ReplaceElementAt((void*)ptr, i);
1084 break;
1087 free(defPrinterName);
1090 // make sure we at least tried to get the printers
1091 if (!PrintersAreAllocated()) {
1092 PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
1093 return NS_ERROR_FAILURE;
1096 return NS_OK;