embedding/components/printingui/src/win/nsPrintDialogUtil.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /* -------------------------------------------------------------------
     7 To Build This:
     9   You need to add this to the the makefile.win in mozilla/content/base/src:
    11 	.\$(OBJDIR)\nsFlyOwnPrintDialog.obj	\
    14   And this to the makefile.win in mozilla/content/build:
    16 WIN_LIBS=                                       \
    17         winspool.lib                           \
    18         comctl32.lib                           \
    19         comdlg32.lib
    21 ---------------------------------------------------------------------- */
    23 #define NOMINMAX 1
    25 #include "plstr.h"
    26 #include <windows.h>
    27 #include <tchar.h>
    29 #include <unknwn.h>
    30 #include <commdlg.h>
    32 #include "nsIWebBrowserPrint.h"
    33 #include "nsString.h"
    34 #include "nsIServiceManager.h"
    35 #include "nsReadableUtils.h"
    36 #include "nsIPrintSettings.h"
    37 #include "nsIPrintSettingsWin.h"
    38 #include "nsIPrintOptions.h"
    40 #include "nsRect.h"
    42 #include "nsIPrefService.h"
    43 #include "nsIPrefBranch.h"
    45 #include "nsCRT.h"
    46 #include "prenv.h" /* for PR_GetEnv */
    48 #include <windows.h>
    49 #include <winspool.h> 
    51 // For Localization
    52 #include "nsIStringBundle.h"
    54 // For NS_CopyUnicodeToNative
    55 #include "nsNativeCharsetUtils.h"
    57 // This is for extending the dialog
    58 #include <dlgs.h>
    60 // Default labels for the radio buttons
    61 static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen";
    62 static const char* kTheSelectedFrameStr  = "The selected &frame";
    63 static const char* kEachFrameSeparately  = "&Each frame separately";
    66 //-----------------------------------------------
    67 // Global Data
    68 //-----------------------------------------------
    69 // Identifies which new radio btn was cliked on
    70 static UINT gFrameSelectedRadioBtn = 0;
    72 // Indicates whether the native print dialog was successfully extended
    73 static bool gDialogWasExtended     = false;
    75 #define PRINTDLG_PROPERTIES "chrome://global/locale/printdialog.properties"
    77 static HWND gParentWnd = nullptr;
    79 //******************************************************
    80 // Define native paper sizes
    81 //******************************************************
    82 typedef struct {
    83   short  mPaperSize; // native enum
    84   double mWidth;
    85   double mHeight;
    86   bool mIsInches;
    87 } NativePaperSizes;
    89 // There are around 40 default print sizes defined by Windows
    90 const NativePaperSizes kPaperSizes[] = {
    91   {DMPAPER_LETTER,    8.5,   11.0,  true},
    92   {DMPAPER_LEGAL,     8.5,   14.0,  true},
    93   {DMPAPER_A4,        210.0, 297.0, false},
    94   {DMPAPER_TABLOID,   11.0,  17.0,  true},
    95   {DMPAPER_LEDGER,    17.0,  11.0,  true},
    96   {DMPAPER_STATEMENT, 5.5,   8.5,   true},
    97   {DMPAPER_EXECUTIVE, 7.25,  10.5,  true},
    98   {DMPAPER_A3,        297.0, 420.0, false},
    99   {DMPAPER_A5,        148.0, 210.0, false},
   100   {DMPAPER_CSHEET,    17.0,  22.0,  true},  
   101   {DMPAPER_DSHEET,    22.0,  34.0,  true},  
   102   {DMPAPER_ESHEET,    34.0,  44.0,  true},  
   103   {DMPAPER_LETTERSMALL, 8.5, 11.0,  true},  
   104   {DMPAPER_A4SMALL,   210.0, 297.0, false}, 
   105   {DMPAPER_B4,        250.0, 354.0, false}, 
   106   {DMPAPER_B5,        182.0, 257.0, false},
   107   {DMPAPER_FOLIO,     8.5,   13.0,  true},
   108   {DMPAPER_QUARTO,    215.0, 275.0, false},
   109   {DMPAPER_10X14,     10.0,  14.0,  true},
   110   {DMPAPER_11X17,     11.0,  17.0,  true},
   111   {DMPAPER_NOTE,      8.5,   11.0,  true},  
   112   {DMPAPER_ENV_9,     3.875, 8.875, true},  
   113   {DMPAPER_ENV_10,    40.125, 9.5,  true},  
   114   {DMPAPER_ENV_11,    4.5,   10.375, true},  
   115   {DMPAPER_ENV_12,    4.75,  11.0,  true},  
   116   {DMPAPER_ENV_14,    5.0,   11.5,  true},  
   117   {DMPAPER_ENV_DL,    110.0, 220.0, false}, 
   118   {DMPAPER_ENV_C5,    162.0, 229.0, false}, 
   119   {DMPAPER_ENV_C3,    324.0, 458.0, false}, 
   120   {DMPAPER_ENV_C4,    229.0, 324.0, false}, 
   121   {DMPAPER_ENV_C6,    114.0, 162.0, false}, 
   122   {DMPAPER_ENV_C65,   114.0, 229.0, false}, 
   123   {DMPAPER_ENV_B4,    250.0, 353.0, false}, 
   124   {DMPAPER_ENV_B5,    176.0, 250.0, false}, 
   125   {DMPAPER_ENV_B6,    176.0, 125.0, false}, 
   126   {DMPAPER_ENV_ITALY, 110.0, 230.0, false}, 
   127   {DMPAPER_ENV_MONARCH,  3.875,  7.5, true},  
   128   {DMPAPER_ENV_PERSONAL, 3.625,  6.5, true},  
   129   {DMPAPER_FANFOLD_US,   14.875, 11.0, true},  
   130   {DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, true},  
   131   {DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, true},  
   132 };
   133 const int32_t kNumPaperSizes = 41;
   135 //----------------------------------------------------------------------------------
   136 // Map an incoming size to a Windows Native enum in the DevMode
   137 static void 
   138 MapPaperSizeToNativeEnum(LPDEVMODEW aDevMode,
   139                          int16_t   aType, 
   140                          double    aW, 
   141                          double    aH)
   142 {
   144 #ifdef DEBUG_rods
   145   BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
   146   BOOL doingPaperSize   = aDevMode->dmFields & DM_PAPERSIZE;
   147   BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
   148   BOOL doingPaperWidth  = aDevMode->dmFields & DM_PAPERWIDTH;
   149 #endif
   151   const double kThreshold = 0.05;
   152   for (int32_t i=0;i<kNumPaperSizes;i++) {
   153     double width  = kPaperSizes[i].mWidth;
   154     double height = kPaperSizes[i].mHeight;
   155     if (aW < width+kThreshold && aW > width-kThreshold && 
   156         aH < height+kThreshold && aH > height-kThreshold) {
   157       aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize;
   158       aDevMode->dmFields &= ~DM_PAPERLENGTH;
   159       aDevMode->dmFields &= ~DM_PAPERWIDTH;
   160       aDevMode->dmFields |= DM_PAPERSIZE;
   161       return;
   162     }
   163   }
   165   short width  = 0;
   166   short height = 0;
   167   if (aType == nsIPrintSettings::kPaperSizeInches) {
   168     width  = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10);
   169     height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10);
   171   } else if (aType == nsIPrintSettings::kPaperSizeMillimeters) {
   172     width  = short(aW / 10.0);
   173     height = short(aH / 10.0);
   174   } else {
   175     return; // don't set anything
   176   }
   178   // width and height is in 
   179   aDevMode->dmPaperSize   = 0;
   180   aDevMode->dmPaperWidth  = width;
   181   aDevMode->dmPaperLength = height;
   183   aDevMode->dmFields |= DM_PAPERSIZE;
   184   aDevMode->dmFields |= DM_PAPERLENGTH;
   185   aDevMode->dmFields |= DM_PAPERWIDTH;
   186 }
   188 //----------------------------------------------------------------------------------
   189 // Setup Paper Size & Orientation options into the DevMode
   190 // 
   191 static void 
   192 SetupDevModeFromSettings(LPDEVMODEW aDevMode, nsIPrintSettings* aPrintSettings)
   193 {
   194   // Setup paper size
   195   if (aPrintSettings) {
   196     int16_t type;
   197     aPrintSettings->GetPaperSizeType(&type);
   198     if (type == nsIPrintSettings::kPaperSizeNativeData) {
   199       int16_t paperEnum;
   200       aPrintSettings->GetPaperData(&paperEnum);
   201       aDevMode->dmPaperSize = paperEnum;
   202       aDevMode->dmFields &= ~DM_PAPERLENGTH;
   203       aDevMode->dmFields &= ~DM_PAPERWIDTH;
   204       aDevMode->dmFields |= DM_PAPERSIZE;
   205     } else {
   206       int16_t unit;
   207       double width, height;
   208       aPrintSettings->GetPaperSizeUnit(&unit);
   209       aPrintSettings->GetPaperWidth(&width);
   210       aPrintSettings->GetPaperHeight(&height);
   211       MapPaperSizeToNativeEnum(aDevMode, unit, width, height);
   212     }
   214     // Setup Orientation
   215     int32_t orientation;
   216     aPrintSettings->GetOrientation(&orientation);
   217     aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE;
   218     aDevMode->dmFields |= DM_ORIENTATION;
   220     // Setup Number of Copies
   221     int32_t copies;
   222     aPrintSettings->GetNumCopies(&copies);
   223     aDevMode->dmCopies = copies;
   224     aDevMode->dmFields |= DM_COPIES;
   226   }
   228 }
   230 //----------------------------------------------------------------------------------
   231 // Helper Function - Free and reallocate the string
   232 static nsresult 
   233 SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings, 
   234                             LPDEVMODEW         aDevMode)
   235 {
   236   if (aPrintSettings == nullptr) {
   237     return NS_ERROR_FAILURE;
   238   }
   240   aPrintSettings->SetIsInitializedFromPrinter(true);
   241   if (aDevMode->dmFields & DM_ORIENTATION) {
   242     int32_t orientation  = aDevMode->dmOrientation == DMORIENT_PORTRAIT?
   243                            nsIPrintSettings::kPortraitOrientation:nsIPrintSettings::kLandscapeOrientation;
   244     aPrintSettings->SetOrientation(orientation);
   245   }
   247   // Setup Number of Copies
   248   if (aDevMode->dmFields & DM_COPIES) {
   249     aPrintSettings->SetNumCopies(int32_t(aDevMode->dmCopies));
   250   }
   252   // Scaling
   253   // Since we do the scaling, grab their value and reset back to 100
   254   if (aDevMode->dmFields & DM_SCALE) {
   255     double origScale = 1.0;
   256     aPrintSettings->GetScaling(&origScale);
   257     double scale = double(aDevMode->dmScale) / 100.0f;
   258     if (origScale == 1.0 || scale != 1.0) {
   259       aPrintSettings->SetScaling(scale);
   260     }
   261     aDevMode->dmScale = 100;
   262     // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
   263     //aPrintSettings->SetShrinkToFit(false);
   264   }
   266   if (aDevMode->dmFields & DM_PAPERSIZE) {
   267     aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData);
   268     aPrintSettings->SetPaperData(aDevMode->dmPaperSize);
   269     for (int32_t i=0;i<kNumPaperSizes;i++) {
   270       if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
   271         aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters);
   272         break;
   273       }
   274     }
   276   } else if (aDevMode->dmFields & DM_PAPERLENGTH && aDevMode->dmFields & DM_PAPERWIDTH) {
   277     bool found = false;
   278     for (int32_t i=0;i<kNumPaperSizes;i++) {
   279       if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
   280         aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined);
   281         aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth);
   282         aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight);
   283         aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters);
   284         found = true;
   285         break;
   286       }
   287     }
   288     if (!found) {
   289       return NS_ERROR_FAILURE;
   290     }
   291   } else {
   292     return NS_ERROR_FAILURE;
   293   }
   294   return NS_OK;
   295 }
   297 //----------------------------------------------------------------------------------
   298 // Return localized bundle for resource strings
   299 static nsresult
   300 GetLocalizedBundle(const char * aPropFileName, nsIStringBundle** aStrBundle)
   301 {
   302   NS_ENSURE_ARG_POINTER(aPropFileName);
   303   NS_ENSURE_ARG_POINTER(aStrBundle);
   305   nsresult rv;
   306   nsCOMPtr<nsIStringBundle> bundle;
   309   // Create bundle
   310   nsCOMPtr<nsIStringBundleService> stringService = 
   311     do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
   312   if (NS_SUCCEEDED(rv) && stringService) {
   313     rv = stringService->CreateBundle(aPropFileName, aStrBundle);
   314   }
   316   return rv;
   317 }
   319 //--------------------------------------------------------
   320 // Return localized string 
   321 static nsresult
   322 GetLocalizedString(nsIStringBundle* aStrBundle, const char* aKey, nsString& oVal)
   323 {
   324   NS_ENSURE_ARG_POINTER(aStrBundle);
   325   NS_ENSURE_ARG_POINTER(aKey);
   327   // Determine default label from string bundle
   328   nsXPIDLString valUni;
   329   nsAutoString key; 
   330   key.AssignWithConversion(aKey);
   331   nsresult rv = aStrBundle->GetStringFromName(key.get(), getter_Copies(valUni));
   332   if (NS_SUCCEEDED(rv) && valUni) {
   333     oVal.Assign(valUni);
   334   } else {
   335     oVal.Truncate();
   336   }
   337   return rv;
   338 }
   340 //--------------------------------------------------------
   341 // Set a multi-byte string in the control
   342 static void SetTextOnWnd(HWND aControl, const nsString& aStr)
   343 {
   344   nsAutoCString text;
   345   if (NS_SUCCEEDED(NS_CopyUnicodeToNative(aStr, text))) {
   346     ::SetWindowText(aControl, text.get());
   347   }
   348 }
   350 //--------------------------------------------------------
   351 // Will get the control and localized string by "key"
   352 static void SetText(HWND             aParent, 
   353                     UINT             aId, 
   354                     nsIStringBundle* aStrBundle,
   355                     const char*      aKey) 
   356 {
   357   HWND wnd = GetDlgItem (aParent, aId);
   358   if (!wnd) {
   359     return;
   360   }
   361   nsAutoString str;
   362   nsresult rv = GetLocalizedString(aStrBundle, aKey, str);
   363   if (NS_SUCCEEDED(rv)) {
   364     SetTextOnWnd(wnd, str);
   365   }
   366 }
   368 //--------------------------------------------------------
   369 static void SetRadio(HWND         aParent, 
   370                      UINT         aId, 
   371                      bool         aIsSet,
   372                      bool         isEnabled = true) 
   373 {
   374   HWND wnd = ::GetDlgItem (aParent, aId);
   375   if (!wnd) {
   376     return;
   377   }
   378   if (!isEnabled) {
   379     ::EnableWindow(wnd, FALSE);
   380     return;
   381   }
   382   ::EnableWindow(wnd, TRUE);
   383   ::SendMessage(wnd, BM_SETCHECK, (WPARAM)aIsSet, (LPARAM)0);
   384 }
   386 //--------------------------------------------------------
   387 static void SetRadioOfGroup(HWND aDlg, int aRadId)
   388 {
   389   int radioIds[] = {rad4, rad5, rad6};
   390   int numRads = 3;
   392   for (int i=0;i<numRads;i++) {
   393     HWND radWnd = ::GetDlgItem(aDlg, radioIds[i]);
   394     if (radWnd != nullptr) {
   395       ::SendMessage(radWnd, BM_SETCHECK, (WPARAM)(radioIds[i] == aRadId), (LPARAM)0);
   396     }
   397   }
   398 }
   400 //--------------------------------------------------------
   401 typedef struct {
   402   const char * mKeyStr;
   403   long   mKeyId;
   404 } PropKeyInfo;
   406 // These are the control ids used in the dialog and 
   407 // defined by MS-Windows in commdlg.h
   408 static PropKeyInfo gAllPropKeys[] = {
   409     {"printFramesTitleWindows", grp3},
   410     {"asLaidOutWindows", rad4},
   411     {"selectedFrameWindows", rad5},
   412     {"separateFramesWindows", rad6},
   413     {nullptr, 0}};
   415 //--------------------------------------------------------
   416 //--------------------------------------------------------
   417 //--------------------------------------------------------
   418 //--------------------------------------------------------
   419 // Get the absolute coords of the child windows relative
   420 // to its parent window
   421 static void GetLocalRect(HWND aWnd, RECT& aRect, HWND aParent)
   422 {
   423   ::GetWindowRect(aWnd, &aRect);
   425   // MapWindowPoints converts screen coordinates to client coordinates.
   426   // It works correctly in both left-to-right and right-to-left windows.
   427   ::MapWindowPoints(nullptr, aParent, (LPPOINT)&aRect, 2);
   428 }
   430 //--------------------------------------------------------
   431 // Show or Hide the control
   432 static void Show(HWND aWnd, bool bState)
   433 {
   434   if (aWnd) {
   435     ::ShowWindow(aWnd, bState?SW_SHOW:SW_HIDE);
   436   }
   437 }
   439 //--------------------------------------------------------
   440 // Create a child window "control"
   441 static HWND CreateControl(LPCTSTR          aType,
   442                           DWORD            aStyle,
   443                           HINSTANCE        aHInst, 
   444                           HWND             aHdlg, 
   445                           int              aId, 
   446                           const nsAString& aStr, 
   447                           const nsIntRect& aRect)
   448 {
   449   nsAutoCString str;
   450   if (NS_FAILED(NS_CopyUnicodeToNative(aStr, str)))
   451     return nullptr;
   453   HWND hWnd = ::CreateWindow (aType, str.get(),
   454                               WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | aStyle,
   455                               aRect.x, aRect.y, aRect.width, aRect.height,
   456                               (HWND)aHdlg, (HMENU)(intptr_t)aId,
   457                               aHInst, nullptr);
   458   if (hWnd == nullptr) return nullptr;
   460   // get the native font for the dialog and 
   461   // set it into the new control
   462   HFONT hFont = (HFONT)::SendMessage(aHdlg, WM_GETFONT, (WPARAM)0, (LPARAM)0);
   463   if (hFont != nullptr) {
   464     ::SendMessage(hWnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0);
   465   }
   466   return hWnd;
   467 }
   469 //--------------------------------------------------------
   470 // Create a Radio Button
   471 static HWND CreateRadioBtn(HINSTANCE        aHInst, 
   472                            HWND             aHdlg, 
   473                            int              aId, 
   474                            const char*      aStr, 
   475                            const nsIntRect& aRect)
   476 {
   477   nsString cStr;
   478   cStr.AssignWithConversion(aStr);
   479   return CreateControl("BUTTON", BS_RADIOBUTTON, aHInst, aHdlg, aId, cStr, aRect);
   480 }
   482 //--------------------------------------------------------
   483 // Create a Group Box
   484 static HWND CreateGroupBox(HINSTANCE        aHInst, 
   485                            HWND             aHdlg, 
   486                            int              aId, 
   487                            const nsAString& aStr, 
   488                            const nsIntRect& aRect)
   489 {
   490   return CreateControl("BUTTON", BS_GROUPBOX, aHInst, aHdlg, aId, aStr, aRect);
   491 }
   493 //--------------------------------------------------------
   494 // Localizes and initializes the radio buttons and group
   495 static void InitializeExtendedDialog(HWND hdlg, int16_t aHowToEnableFrameUI) 
   496 {
   497   NS_ABORT_IF_FALSE(aHowToEnableFrameUI != nsIPrintSettings::kFrameEnableNone,
   498                     "should not be called");
   500   // Localize the new controls in the print dialog
   501   nsCOMPtr<nsIStringBundle> strBundle;
   502   if (NS_SUCCEEDED(GetLocalizedBundle(PRINTDLG_PROPERTIES, getter_AddRefs(strBundle)))) {
   503     int32_t i = 0;
   504     while (gAllPropKeys[i].mKeyStr != nullptr) {
   505       SetText(hdlg, gAllPropKeys[i].mKeyId, strBundle, gAllPropKeys[i].mKeyStr);
   506       i++;
   507     }
   508   }
   510   // Set up radio buttons
   511   if (aHowToEnableFrameUI == nsIPrintSettings::kFrameEnableAll) {
   512     SetRadio(hdlg, rad4, false);  
   513     SetRadio(hdlg, rad5, true); 
   514     SetRadio(hdlg, rad6, false);
   515     // set default so user doesn't have to actually press on it
   516     gFrameSelectedRadioBtn = rad5;
   518   } else { // nsIPrintSettings::kFrameEnableAsIsAndEach
   519     SetRadio(hdlg, rad4, false);  
   520     SetRadio(hdlg, rad5, false, false); 
   521     SetRadio(hdlg, rad6, true);
   522     // set default so user doesn't have to actually press on it
   523     gFrameSelectedRadioBtn = rad6;
   524   }
   525 }
   528 //--------------------------------------------------------
   529 // Special Hook Procedure for handling the print dialog messages
   530 static UINT CALLBACK PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) 
   531 {
   533   if (uiMsg == WM_COMMAND) {
   534     UINT id = LOWORD(wParam);
   535     if (id == rad4 || id == rad5 || id == rad6) {
   536       gFrameSelectedRadioBtn = id;
   537       SetRadioOfGroup(hdlg, id);
   538     }
   540   } else if (uiMsg == WM_INITDIALOG) {
   541     PRINTDLG * printDlg = (PRINTDLG *)lParam;
   542     if (printDlg == nullptr) return 0L;
   544     int16_t howToEnableFrameUI = (int16_t)printDlg->lCustData;
   545     // don't add frame options if they would be disabled anyway
   546     // because there are no frames
   547     if (howToEnableFrameUI == nsIPrintSettings::kFrameEnableNone)
   548       return TRUE;
   550     HINSTANCE hInst = (HINSTANCE)::GetWindowLongPtr(hdlg, GWLP_HINSTANCE);
   551     if (hInst == nullptr) return 0L;
   553     // Start by getting the local rects of several of the controls
   554     // so we can calculate where the new controls are
   555     HWND wnd = ::GetDlgItem(hdlg, grp1);
   556     if (wnd == nullptr) return 0L;
   557     RECT dlgRect;
   558     GetLocalRect(wnd, dlgRect, hdlg);
   560     wnd = ::GetDlgItem(hdlg, rad1); // this is the top control "All"
   561     if (wnd == nullptr) return 0L;
   562     RECT rad1Rect;
   563     GetLocalRect(wnd, rad1Rect, hdlg);
   565     wnd = ::GetDlgItem(hdlg, rad2); // this is the bottom control "Selection"
   566     if (wnd == nullptr) return 0L;
   567     RECT rad2Rect;
   568     GetLocalRect(wnd, rad2Rect, hdlg);
   570     wnd = ::GetDlgItem(hdlg, rad3); // this is the middle control "Pages"
   571     if (wnd == nullptr) return 0L;
   572     RECT rad3Rect;
   573     GetLocalRect(wnd, rad3Rect, hdlg);
   575     HWND okWnd = ::GetDlgItem(hdlg, IDOK);
   576     if (okWnd == nullptr) return 0L;
   577     RECT okRect;
   578     GetLocalRect(okWnd, okRect, hdlg);
   580     wnd = ::GetDlgItem(hdlg, grp4); // this is the "Print range" groupbox
   581     if (wnd == nullptr) return 0L;
   582     RECT prtRect;
   583     GetLocalRect(wnd, prtRect, hdlg);
   586     // calculate various different "gaps" for layout purposes
   588     int rbGap     = rad3Rect.top - rad1Rect.bottom;     // gap between radiobtns
   589     int grpBotGap = dlgRect.bottom - rad2Rect.bottom;   // gap from bottom rb to bottom of grpbox
   590     int grpGap    = dlgRect.top - prtRect.bottom ;      // gap between group boxes
   591     int top       = dlgRect.bottom + grpGap;            
   592     int radHgt    = rad1Rect.bottom - rad1Rect.top + 1; // top of new group box
   593     int y         = top+(rad1Rect.top-dlgRect.top);     // starting pos of first radio
   594     int rbWidth   = dlgRect.right - rad1Rect.left - 5;  // measure from rb left to the edge of the groupbox
   595                                                         // (5 is arbitrary)
   596     nsIntRect rect;
   598     // Create and position the radio buttons
   599     //
   600     // If any one control cannot be created then 
   601     // hide the others and bail out
   602     //
   603     rect.SetRect(rad1Rect.left, y, rbWidth,radHgt);
   604     HWND rad4Wnd = CreateRadioBtn(hInst, hdlg, rad4, kAsLaidOutOnScreenStr, rect);
   605     if (rad4Wnd == nullptr) return 0L;
   606     y += radHgt + rbGap;
   608     rect.SetRect(rad1Rect.left, y, rbWidth, radHgt);
   609     HWND rad5Wnd = CreateRadioBtn(hInst, hdlg, rad5, kTheSelectedFrameStr, rect);
   610     if (rad5Wnd == nullptr) {
   611       Show(rad4Wnd, FALSE); // hide
   612       return 0L;
   613     }
   614     y += radHgt + rbGap;
   616     rect.SetRect(rad1Rect.left, y, rbWidth, radHgt);
   617     HWND rad6Wnd = CreateRadioBtn(hInst, hdlg, rad6, kEachFrameSeparately, rect);
   618     if (rad6Wnd == nullptr) {
   619       Show(rad4Wnd, FALSE); // hide
   620       Show(rad5Wnd, FALSE); // hide
   621       return 0L;
   622     }
   623     y += radHgt + grpBotGap;
   625     // Create and position the group box
   626     rect.SetRect (dlgRect.left, top, dlgRect.right-dlgRect.left+1, y-top+1);
   627     HWND grpBoxWnd = CreateGroupBox(hInst, hdlg, grp3, NS_LITERAL_STRING("Print Frame"), rect);
   628     if (grpBoxWnd == nullptr) {
   629       Show(rad4Wnd, FALSE); // hide
   630       Show(rad5Wnd, FALSE); // hide
   631       Show(rad6Wnd, FALSE); // hide
   632       return 0L;
   633     }
   635     // Here we figure out the old height of the dlg
   636     // then figure its gap from the old grpbx to the bottom
   637     // then size the dlg
   638     RECT pr, cr; 
   639     ::GetWindowRect(hdlg, &pr);
   640     ::GetClientRect(hdlg, &cr);
   642     int dlgHgt = (cr.bottom - cr.top) + 1;
   643     int bottomGap = dlgHgt - okRect.bottom;
   644     pr.bottom += (dlgRect.bottom-dlgRect.top) + grpGap + 1 - (dlgHgt-dlgRect.bottom) + bottomGap;
   646     ::SetWindowPos(hdlg, nullptr, pr.left, pr.top, pr.right-pr.left+1, pr.bottom-pr.top+1, 
   647                    SWP_NOMOVE|SWP_NOREDRAW|SWP_NOZORDER);
   649     // figure out the new height of the dialog
   650     ::GetClientRect(hdlg, &cr);
   651     dlgHgt = (cr.bottom - cr.top) + 1;
   653     // Reposition the OK and Cancel btns
   654     int okHgt = okRect.bottom - okRect.top + 1;
   655     ::SetWindowPos(okWnd, nullptr, okRect.left, dlgHgt-bottomGap-okHgt, 0, 0, 
   656                    SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER);
   658     HWND cancelWnd = ::GetDlgItem(hdlg, IDCANCEL);
   659     if (cancelWnd == nullptr) return 0L;
   661     RECT cancelRect;
   662     GetLocalRect(cancelWnd, cancelRect, hdlg);
   663     int cancelHgt = cancelRect.bottom - cancelRect.top + 1;
   664     ::SetWindowPos(cancelWnd, nullptr, cancelRect.left, dlgHgt-bottomGap-cancelHgt, 0, 0, 
   665                    SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER);
   667     // localize and initialize the groupbox and radiobuttons
   668     InitializeExtendedDialog(hdlg, howToEnableFrameUI);
   670     // Looks like we were able to extend the dialog
   671     gDialogWasExtended = true;
   672     return TRUE;
   673   }
   674   return 0L;
   675 }
   677 //----------------------------------------------------------------------------------
   678 // Returns a Global Moveable Memory Handle to a DevMode
   679 // from the Printer by the name of aPrintName
   680 //
   681 // NOTE:
   682 //   This function assumes that aPrintName has already been converted from 
   683 //   unicode
   684 //
   685 static HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS)
   686 {
   687   HGLOBAL hGlobalDevMode = nullptr;
   689   HANDLE hPrinter = nullptr;
   690   // const cast kludge for silly Win32 api's
   691   LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get()));
   692   BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr);
   693   if (status) {
   695     LPDEVMODEW  pNewDevMode;
   696     DWORD       dwNeeded, dwRet;
   698     // Get the buffer size
   699     dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, nullptr, 0);
   700     if (dwNeeded == 0) {
   701       return nullptr;
   702     }
   704     // Allocate a buffer of the correct size.
   705     pNewDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
   706     if (!pNewDevMode) return nullptr;
   708     hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded);
   709     if (!hGlobalDevMode) {
   710       ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
   711       return nullptr;
   712     }
   714     dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, pNewDevMode, nullptr, DM_OUT_BUFFER);
   716     if (dwRet != IDOK) {
   717       ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
   718       ::GlobalFree(hGlobalDevMode);
   719       ::ClosePrinter(hPrinter);
   720       return nullptr;
   721     }
   723     // Lock memory and copy contents from DEVMODE (current printer)
   724     // to Global Memory DEVMODE
   725     LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hGlobalDevMode);
   726     if (devMode) {
   727       memcpy(devMode, pNewDevMode, dwNeeded);
   728       // Initialize values from the PrintSettings
   729       SetupDevModeFromSettings(devMode, aPS);
   731       // Sets back the changes we made to the DevMode into the Printer Driver
   732       dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER);
   733       if (dwRet != IDOK) {
   734         ::GlobalUnlock(hGlobalDevMode);
   735         ::GlobalFree(hGlobalDevMode);
   736         ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
   737         ::ClosePrinter(hPrinter);
   738         return nullptr;
   739       }
   741       ::GlobalUnlock(hGlobalDevMode);
   742     } else {
   743       ::GlobalFree(hGlobalDevMode);
   744       hGlobalDevMode = nullptr;
   745     }
   747     ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
   749     ::ClosePrinter(hPrinter);
   751   } else {
   752     return nullptr;
   753   }
   755   return hGlobalDevMode;
   756 }
   758 //------------------------------------------------------------------
   759 // helper
   760 static void GetDefaultPrinterNameFromGlobalPrinters(nsXPIDLString &printerName)
   761 {
   762   nsCOMPtr<nsIPrinterEnumerator> prtEnum = do_GetService("@mozilla.org/gfx/printerenumerator;1");
   763   if (prtEnum) {
   764     prtEnum->GetDefaultPrinterName(getter_Copies(printerName));
   765   }
   766 }
   768 // Determine whether we have a completely native dialog
   769 // or whether we cshould extend it
   770 static bool ShouldExtendPrintDialog()
   771 {
   772   nsresult rv;
   773   nsCOMPtr<nsIPrefService> prefs =
   774     do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   775   NS_ENSURE_SUCCESS(rv, true);
   776   nsCOMPtr<nsIPrefBranch> prefBranch;
   777   rv = prefs->GetBranch(nullptr, getter_AddRefs(prefBranch));
   778   NS_ENSURE_SUCCESS(rv, true);
   780   bool result;
   781   rv = prefBranch->GetBoolPref("print.extend_native_print_dialog", &result);
   782   NS_ENSURE_SUCCESS(rv, true);
   783   return result;
   784 }
   786 //------------------------------------------------------------------
   787 // Displays the native Print Dialog
   788 static nsresult 
   789 ShowNativePrintDialog(HWND              aHWnd,
   790                       nsIPrintSettings* aPrintSettings)
   791 {
   792   //NS_ENSURE_ARG_POINTER(aHWnd);
   793   NS_ENSURE_ARG_POINTER(aPrintSettings);
   795   gDialogWasExtended  = false;
   797   HGLOBAL hGlobalDevMode = nullptr;
   798   HGLOBAL hDevNames      = nullptr;
   800   // Get the Print Name to be used
   801   nsXPIDLString printerName;
   802   aPrintSettings->GetPrinterName(getter_Copies(printerName));
   804   // If there is no name then use the default printer
   805   if (printerName.IsEmpty()) {
   806     GetDefaultPrinterNameFromGlobalPrinters(printerName);
   807   } else {
   808     HANDLE hPrinter = nullptr;
   809     if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())), &hPrinter, nullptr)) {
   810       // If the last used printer is not found, we should use default printer.
   811       GetDefaultPrinterNameFromGlobalPrinters(printerName);
   812     } else {
   813       ::ClosePrinter(hPrinter);
   814     }
   815   }
   817   // Now create a DEVNAMES struct so the the dialog is initialized correctly.
   819   uint32_t len = printerName.Length();
   820   hDevNames = (HGLOBAL)::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + 
   821                                      sizeof(DEVNAMES));
   822   if (!hDevNames) {
   823     return NS_ERROR_OUT_OF_MEMORY;
   824   }
   826   DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames);
   827   if (!pDevNames) {
   828     ::GlobalFree(hDevNames);
   829     return NS_ERROR_FAILURE;
   830   }
   831   pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
   832   pDevNames->wDeviceOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
   833   pDevNames->wOutputOffset = sizeof(DEVNAMES)/sizeof(wchar_t)+len;
   834   pDevNames->wDefault      = 0;
   836   memcpy(pDevNames+1, printerName, (len + 1) * sizeof(wchar_t));
   837   ::GlobalUnlock(hDevNames);
   839   // Create a Moveable Memory Object that holds a new DevMode
   840   // from the Printer Name
   841   // The PRINTDLG.hDevMode requires that it be a moveable memory object
   842   // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled
   843   // When the user prints, it comes back in the printdlg struct and 
   844   // is used and cleaned up later
   845   hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings);
   847   // Prepare to Display the Print Dialog
   848   PRINTDLGW  prntdlg;
   849   memset(&prntdlg, 0, sizeof(PRINTDLGW));
   851   prntdlg.lStructSize = sizeof(prntdlg);
   852   prntdlg.hwndOwner   = aHWnd;
   853   prntdlg.hDevMode    = hGlobalDevMode;
   854   prntdlg.hDevNames   = hDevNames;
   855   prntdlg.hDC         = nullptr;
   856   prntdlg.Flags       = PD_ALLPAGES | PD_RETURNIC | 
   857                         PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE;
   859   // if there is a current selection then enable the "Selection" radio button
   860   int16_t howToEnableFrameUI = nsIPrintSettings::kFrameEnableNone;
   861   bool isOn;
   862   aPrintSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &isOn);
   863   if (!isOn) {
   864     prntdlg.Flags |= PD_NOSELECTION;
   865   }
   866   aPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
   868   int32_t pg = 1;
   869   aPrintSettings->GetStartPageRange(&pg);
   870   prntdlg.nFromPage           = pg;
   872   aPrintSettings->GetEndPageRange(&pg);
   873   prntdlg.nToPage             = pg;
   875   prntdlg.nMinPage            = 1;
   876   prntdlg.nMaxPage            = 0xFFFF;
   877   prntdlg.nCopies             = 1;
   878   prntdlg.lpfnSetupHook       = nullptr;
   879   prntdlg.lpSetupTemplateName = nullptr;
   880   prntdlg.hPrintTemplate      = nullptr;
   881   prntdlg.hSetupTemplate      = nullptr;
   883   prntdlg.hInstance           = nullptr;
   884   prntdlg.lpPrintTemplateName = nullptr;
   886   if (!ShouldExtendPrintDialog()) {
   887     prntdlg.lCustData         = 0;
   888     prntdlg.lpfnPrintHook     = nullptr;
   889   } else {
   890     // Set up print dialog "hook" procedure for extending the dialog
   891     prntdlg.lCustData         = (DWORD)howToEnableFrameUI;
   892     prntdlg.lpfnPrintHook     = (LPPRINTHOOKPROC)PrintHookProc;
   893     prntdlg.Flags            |= PD_ENABLEPRINTHOOK;
   894   }
   896   BOOL result = ::PrintDlgW(&prntdlg);
   898   if (TRUE == result) {
   899     // check to make sure we don't have any nullptr pointers
   900     NS_ENSURE_TRUE(aPrintSettings && prntdlg.hDevMode, NS_ERROR_FAILURE);
   902     if (prntdlg.hDevNames == nullptr) {
   903       ::GlobalFree(hGlobalDevMode);
   904       return NS_ERROR_FAILURE;
   905     }
   906     // Lock the deviceNames and check for nullptr
   907     DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames);
   908     if (devnames == nullptr) {
   909       ::GlobalFree(hGlobalDevMode);
   910       return NS_ERROR_FAILURE;
   911     }
   913     char16_t* device = &(((char16_t *)devnames)[devnames->wDeviceOffset]);
   914     char16_t* driver = &(((char16_t *)devnames)[devnames->wDriverOffset]);
   916     // Check to see if the "Print To File" control is checked
   917     // then take the name from devNames and set it in the PrintSettings
   918     //
   919     // NOTE:
   920     // As per Microsoft SDK documentation the returned value offset from
   921     // devnames->wOutputOffset is either "FILE:" or nullptr
   922     // if the "Print To File" checkbox is checked it MUST be "FILE:"
   923     // We assert as an extra safety check.
   924     if (prntdlg.Flags & PD_PRINTTOFILE) {
   925       char16ptr_t fileName = &(((wchar_t *)devnames)[devnames->wOutputOffset]);
   926       NS_ASSERTION(wcscmp(fileName, L"FILE:") == 0, "FileName must be `FILE:`");
   927       aPrintSettings->SetToFileName(fileName);
   928       aPrintSettings->SetPrintToFile(true);
   929     } else {
   930       // clear "print to file" info
   931       aPrintSettings->SetPrintToFile(false);
   932       aPrintSettings->SetToFileName(nullptr);
   933     }
   935     nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
   936     if (!psWin) {
   937       ::GlobalFree(hGlobalDevMode);
   938       return NS_ERROR_FAILURE;
   939     }
   941     // Setup local Data members
   942     psWin->SetDeviceName(device);
   943     psWin->SetDriverName(driver);
   945 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
   946     wprintf(L"printer: driver %s, device %s  flags: %d\n", driver, device, prntdlg.Flags);
   947 #endif
   948     // fill the print options with the info from the dialog
   950     aPrintSettings->SetPrinterName(device);
   952     if (prntdlg.Flags & PD_SELECTION) {
   953       aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSelection);
   955     } else if (prntdlg.Flags & PD_PAGENUMS) {
   956       aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange);
   957       aPrintSettings->SetStartPageRange(prntdlg.nFromPage);
   958       aPrintSettings->SetEndPageRange(prntdlg.nToPage);
   960     } else { // (prntdlg.Flags & PD_ALLPAGES)
   961       aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
   962     }
   964     if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
   965       // make sure the dialog got extended
   966       if (gDialogWasExtended) {
   967         // check to see about the frame radio buttons
   968         switch (gFrameSelectedRadioBtn) {
   969           case rad4: 
   970             aPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
   971             break;
   972           case rad5: 
   973             aPrintSettings->SetPrintFrameType(nsIPrintSettings::kSelectedFrame);
   974             break;
   975           case rad6: 
   976             aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
   977             break;
   978         } // switch
   979       } else {
   980         // if it didn't get extended then have it default to printing
   981         // each frame separately
   982         aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
   983       }
   984     } else {
   985       aPrintSettings->SetPrintFrameType(nsIPrintSettings::kNoFrames);
   986     }
   987     // Unlock DeviceNames
   988     ::GlobalUnlock(prntdlg.hDevNames);
   990     // Transfer the settings from the native data to the PrintSettings
   991     LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode);
   992     if (devMode == nullptr) {
   993       ::GlobalFree(hGlobalDevMode);
   994       return NS_ERROR_FAILURE;
   995     }
   996     psWin->SetDevMode(devMode); // copies DevMode
   997     SetPrintSettingsFromDevMode(aPrintSettings, devMode);
   998     ::GlobalUnlock(prntdlg.hDevMode);
  1000 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
  1001     bool    printSelection = prntdlg.Flags & PD_SELECTION;
  1002     bool    printAllPages  = prntdlg.Flags & PD_ALLPAGES;
  1003     bool    printNumPages  = prntdlg.Flags & PD_PAGENUMS;
  1004     int32_t fromPageNum    = 0;
  1005     int32_t toPageNum      = 0;
  1007     if (printNumPages) {
  1008       fromPageNum = prntdlg.nFromPage;
  1009       toPageNum   = prntdlg.nToPage;
  1011     if (printSelection) {
  1012       printf("Printing the selection\n");
  1014     } else if (printAllPages) {
  1015       printf("Printing all the pages\n");
  1017     } else {
  1018       printf("Printing from page no. %d to %d\n", fromPageNum, toPageNum);
  1020 #endif
  1022   } else {
  1023     ::SetFocus(aHWnd);
  1024     aPrintSettings->SetIsCancelled(true);
  1025     if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode);
  1026     return NS_ERROR_ABORT;
  1029   return NS_OK;
  1032 //------------------------------------------------------------------
  1033 static void 
  1034 PrepareForPrintDialog(nsIWebBrowserPrint* aWebBrowserPrint, nsIPrintSettings* aPS)
  1036   NS_ASSERTION(aWebBrowserPrint, "Can't be null");
  1037   NS_ASSERTION(aPS, "Can't be null");
  1039   bool isFramesetDocument;
  1040   bool isFramesetFrameSelected;
  1041   bool isIFrameSelected;
  1042   bool isRangeSelection;
  1044   aWebBrowserPrint->GetIsFramesetDocument(&isFramesetDocument);
  1045   aWebBrowserPrint->GetIsFramesetFrameSelected(&isFramesetFrameSelected);
  1046   aWebBrowserPrint->GetIsIFrameSelected(&isIFrameSelected);
  1047   aWebBrowserPrint->GetIsRangeSelection(&isRangeSelection);
  1049   // Setup print options for UI
  1050   if (isFramesetDocument) {
  1051     if (isFramesetFrameSelected) {
  1052       aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
  1053     } else {
  1054       aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
  1056   } else {
  1057     aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
  1060   // Now determine how to set up the Frame print UI
  1061   aPS->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isRangeSelection || isIFrameSelected);
  1065 //----------------------------------------------------------------------------------
  1066 //-- Show Print Dialog
  1067 //----------------------------------------------------------------------------------
  1068 nsresult NativeShowPrintDialog(HWND                aHWnd,
  1069                                nsIWebBrowserPrint* aWebBrowserPrint,
  1070                                nsIPrintSettings*   aPrintSettings)
  1072   PrepareForPrintDialog(aWebBrowserPrint, aPrintSettings);
  1074   nsresult rv = ShowNativePrintDialog(aHWnd, aPrintSettings);
  1075   if (aHWnd) {
  1076     ::DestroyWindow(aHWnd);
  1079   return rv;

mercurial