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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/embedding/components/printingui/src/win/nsPrintDialogUtil.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1081 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/* -------------------------------------------------------------------
    1.10 +To Build This:
    1.11 +
    1.12 +  You need to add this to the the makefile.win in mozilla/content/base/src:
    1.13 +
    1.14 +	.\$(OBJDIR)\nsFlyOwnPrintDialog.obj	\
    1.15 +
    1.16 +
    1.17 +  And this to the makefile.win in mozilla/content/build:
    1.18 +
    1.19 +WIN_LIBS=                                       \
    1.20 +        winspool.lib                           \
    1.21 +        comctl32.lib                           \
    1.22 +        comdlg32.lib
    1.23 +
    1.24 +---------------------------------------------------------------------- */
    1.25 +
    1.26 +#define NOMINMAX 1
    1.27 +
    1.28 +#include "plstr.h"
    1.29 +#include <windows.h>
    1.30 +#include <tchar.h>
    1.31 +
    1.32 +#include <unknwn.h>
    1.33 +#include <commdlg.h>
    1.34 +
    1.35 +#include "nsIWebBrowserPrint.h"
    1.36 +#include "nsString.h"
    1.37 +#include "nsIServiceManager.h"
    1.38 +#include "nsReadableUtils.h"
    1.39 +#include "nsIPrintSettings.h"
    1.40 +#include "nsIPrintSettingsWin.h"
    1.41 +#include "nsIPrintOptions.h"
    1.42 +
    1.43 +#include "nsRect.h"
    1.44 +
    1.45 +#include "nsIPrefService.h"
    1.46 +#include "nsIPrefBranch.h"
    1.47 +
    1.48 +#include "nsCRT.h"
    1.49 +#include "prenv.h" /* for PR_GetEnv */
    1.50 +
    1.51 +#include <windows.h>
    1.52 +#include <winspool.h> 
    1.53 +
    1.54 +// For Localization
    1.55 +#include "nsIStringBundle.h"
    1.56 +
    1.57 +// For NS_CopyUnicodeToNative
    1.58 +#include "nsNativeCharsetUtils.h"
    1.59 +
    1.60 +// This is for extending the dialog
    1.61 +#include <dlgs.h>
    1.62 +
    1.63 +// Default labels for the radio buttons
    1.64 +static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen";
    1.65 +static const char* kTheSelectedFrameStr  = "The selected &frame";
    1.66 +static const char* kEachFrameSeparately  = "&Each frame separately";
    1.67 +
    1.68 +
    1.69 +//-----------------------------------------------
    1.70 +// Global Data
    1.71 +//-----------------------------------------------
    1.72 +// Identifies which new radio btn was cliked on
    1.73 +static UINT gFrameSelectedRadioBtn = 0;
    1.74 +
    1.75 +// Indicates whether the native print dialog was successfully extended
    1.76 +static bool gDialogWasExtended     = false;
    1.77 +
    1.78 +#define PRINTDLG_PROPERTIES "chrome://global/locale/printdialog.properties"
    1.79 +
    1.80 +static HWND gParentWnd = nullptr;
    1.81 +
    1.82 +//******************************************************
    1.83 +// Define native paper sizes
    1.84 +//******************************************************
    1.85 +typedef struct {
    1.86 +  short  mPaperSize; // native enum
    1.87 +  double mWidth;
    1.88 +  double mHeight;
    1.89 +  bool mIsInches;
    1.90 +} NativePaperSizes;
    1.91 +
    1.92 +// There are around 40 default print sizes defined by Windows
    1.93 +const NativePaperSizes kPaperSizes[] = {
    1.94 +  {DMPAPER_LETTER,    8.5,   11.0,  true},
    1.95 +  {DMPAPER_LEGAL,     8.5,   14.0,  true},
    1.96 +  {DMPAPER_A4,        210.0, 297.0, false},
    1.97 +  {DMPAPER_TABLOID,   11.0,  17.0,  true},
    1.98 +  {DMPAPER_LEDGER,    17.0,  11.0,  true},
    1.99 +  {DMPAPER_STATEMENT, 5.5,   8.5,   true},
   1.100 +  {DMPAPER_EXECUTIVE, 7.25,  10.5,  true},
   1.101 +  {DMPAPER_A3,        297.0, 420.0, false},
   1.102 +  {DMPAPER_A5,        148.0, 210.0, false},
   1.103 +  {DMPAPER_CSHEET,    17.0,  22.0,  true},  
   1.104 +  {DMPAPER_DSHEET,    22.0,  34.0,  true},  
   1.105 +  {DMPAPER_ESHEET,    34.0,  44.0,  true},  
   1.106 +  {DMPAPER_LETTERSMALL, 8.5, 11.0,  true},  
   1.107 +  {DMPAPER_A4SMALL,   210.0, 297.0, false}, 
   1.108 +  {DMPAPER_B4,        250.0, 354.0, false}, 
   1.109 +  {DMPAPER_B5,        182.0, 257.0, false},
   1.110 +  {DMPAPER_FOLIO,     8.5,   13.0,  true},
   1.111 +  {DMPAPER_QUARTO,    215.0, 275.0, false},
   1.112 +  {DMPAPER_10X14,     10.0,  14.0,  true},
   1.113 +  {DMPAPER_11X17,     11.0,  17.0,  true},
   1.114 +  {DMPAPER_NOTE,      8.5,   11.0,  true},  
   1.115 +  {DMPAPER_ENV_9,     3.875, 8.875, true},  
   1.116 +  {DMPAPER_ENV_10,    40.125, 9.5,  true},  
   1.117 +  {DMPAPER_ENV_11,    4.5,   10.375, true},  
   1.118 +  {DMPAPER_ENV_12,    4.75,  11.0,  true},  
   1.119 +  {DMPAPER_ENV_14,    5.0,   11.5,  true},  
   1.120 +  {DMPAPER_ENV_DL,    110.0, 220.0, false}, 
   1.121 +  {DMPAPER_ENV_C5,    162.0, 229.0, false}, 
   1.122 +  {DMPAPER_ENV_C3,    324.0, 458.0, false}, 
   1.123 +  {DMPAPER_ENV_C4,    229.0, 324.0, false}, 
   1.124 +  {DMPAPER_ENV_C6,    114.0, 162.0, false}, 
   1.125 +  {DMPAPER_ENV_C65,   114.0, 229.0, false}, 
   1.126 +  {DMPAPER_ENV_B4,    250.0, 353.0, false}, 
   1.127 +  {DMPAPER_ENV_B5,    176.0, 250.0, false}, 
   1.128 +  {DMPAPER_ENV_B6,    176.0, 125.0, false}, 
   1.129 +  {DMPAPER_ENV_ITALY, 110.0, 230.0, false}, 
   1.130 +  {DMPAPER_ENV_MONARCH,  3.875,  7.5, true},  
   1.131 +  {DMPAPER_ENV_PERSONAL, 3.625,  6.5, true},  
   1.132 +  {DMPAPER_FANFOLD_US,   14.875, 11.0, true},  
   1.133 +  {DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, true},  
   1.134 +  {DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, true},  
   1.135 +};
   1.136 +const int32_t kNumPaperSizes = 41;
   1.137 +
   1.138 +//----------------------------------------------------------------------------------
   1.139 +// Map an incoming size to a Windows Native enum in the DevMode
   1.140 +static void 
   1.141 +MapPaperSizeToNativeEnum(LPDEVMODEW aDevMode,
   1.142 +                         int16_t   aType, 
   1.143 +                         double    aW, 
   1.144 +                         double    aH)
   1.145 +{
   1.146 +
   1.147 +#ifdef DEBUG_rods
   1.148 +  BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
   1.149 +  BOOL doingPaperSize   = aDevMode->dmFields & DM_PAPERSIZE;
   1.150 +  BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
   1.151 +  BOOL doingPaperWidth  = aDevMode->dmFields & DM_PAPERWIDTH;
   1.152 +#endif
   1.153 +
   1.154 +  const double kThreshold = 0.05;
   1.155 +  for (int32_t i=0;i<kNumPaperSizes;i++) {
   1.156 +    double width  = kPaperSizes[i].mWidth;
   1.157 +    double height = kPaperSizes[i].mHeight;
   1.158 +    if (aW < width+kThreshold && aW > width-kThreshold && 
   1.159 +        aH < height+kThreshold && aH > height-kThreshold) {
   1.160 +      aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize;
   1.161 +      aDevMode->dmFields &= ~DM_PAPERLENGTH;
   1.162 +      aDevMode->dmFields &= ~DM_PAPERWIDTH;
   1.163 +      aDevMode->dmFields |= DM_PAPERSIZE;
   1.164 +      return;
   1.165 +    }
   1.166 +  }
   1.167 +
   1.168 +  short width  = 0;
   1.169 +  short height = 0;
   1.170 +  if (aType == nsIPrintSettings::kPaperSizeInches) {
   1.171 +    width  = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10);
   1.172 +    height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10);
   1.173 +
   1.174 +  } else if (aType == nsIPrintSettings::kPaperSizeMillimeters) {
   1.175 +    width  = short(aW / 10.0);
   1.176 +    height = short(aH / 10.0);
   1.177 +  } else {
   1.178 +    return; // don't set anything
   1.179 +  }
   1.180 +
   1.181 +  // width and height is in 
   1.182 +  aDevMode->dmPaperSize   = 0;
   1.183 +  aDevMode->dmPaperWidth  = width;
   1.184 +  aDevMode->dmPaperLength = height;
   1.185 +
   1.186 +  aDevMode->dmFields |= DM_PAPERSIZE;
   1.187 +  aDevMode->dmFields |= DM_PAPERLENGTH;
   1.188 +  aDevMode->dmFields |= DM_PAPERWIDTH;
   1.189 +}
   1.190 +
   1.191 +//----------------------------------------------------------------------------------
   1.192 +// Setup Paper Size & Orientation options into the DevMode
   1.193 +// 
   1.194 +static void 
   1.195 +SetupDevModeFromSettings(LPDEVMODEW aDevMode, nsIPrintSettings* aPrintSettings)
   1.196 +{
   1.197 +  // Setup paper size
   1.198 +  if (aPrintSettings) {
   1.199 +    int16_t type;
   1.200 +    aPrintSettings->GetPaperSizeType(&type);
   1.201 +    if (type == nsIPrintSettings::kPaperSizeNativeData) {
   1.202 +      int16_t paperEnum;
   1.203 +      aPrintSettings->GetPaperData(&paperEnum);
   1.204 +      aDevMode->dmPaperSize = paperEnum;
   1.205 +      aDevMode->dmFields &= ~DM_PAPERLENGTH;
   1.206 +      aDevMode->dmFields &= ~DM_PAPERWIDTH;
   1.207 +      aDevMode->dmFields |= DM_PAPERSIZE;
   1.208 +    } else {
   1.209 +      int16_t unit;
   1.210 +      double width, height;
   1.211 +      aPrintSettings->GetPaperSizeUnit(&unit);
   1.212 +      aPrintSettings->GetPaperWidth(&width);
   1.213 +      aPrintSettings->GetPaperHeight(&height);
   1.214 +      MapPaperSizeToNativeEnum(aDevMode, unit, width, height);
   1.215 +    }
   1.216 +
   1.217 +    // Setup Orientation
   1.218 +    int32_t orientation;
   1.219 +    aPrintSettings->GetOrientation(&orientation);
   1.220 +    aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE;
   1.221 +    aDevMode->dmFields |= DM_ORIENTATION;
   1.222 +
   1.223 +    // Setup Number of Copies
   1.224 +    int32_t copies;
   1.225 +    aPrintSettings->GetNumCopies(&copies);
   1.226 +    aDevMode->dmCopies = copies;
   1.227 +    aDevMode->dmFields |= DM_COPIES;
   1.228 +
   1.229 +  }
   1.230 +
   1.231 +}
   1.232 +
   1.233 +//----------------------------------------------------------------------------------
   1.234 +// Helper Function - Free and reallocate the string
   1.235 +static nsresult 
   1.236 +SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings, 
   1.237 +                            LPDEVMODEW         aDevMode)
   1.238 +{
   1.239 +  if (aPrintSettings == nullptr) {
   1.240 +    return NS_ERROR_FAILURE;
   1.241 +  }
   1.242 +
   1.243 +  aPrintSettings->SetIsInitializedFromPrinter(true);
   1.244 +  if (aDevMode->dmFields & DM_ORIENTATION) {
   1.245 +    int32_t orientation  = aDevMode->dmOrientation == DMORIENT_PORTRAIT?
   1.246 +                           nsIPrintSettings::kPortraitOrientation:nsIPrintSettings::kLandscapeOrientation;
   1.247 +    aPrintSettings->SetOrientation(orientation);
   1.248 +  }
   1.249 +
   1.250 +  // Setup Number of Copies
   1.251 +  if (aDevMode->dmFields & DM_COPIES) {
   1.252 +    aPrintSettings->SetNumCopies(int32_t(aDevMode->dmCopies));
   1.253 +  }
   1.254 +
   1.255 +  // Scaling
   1.256 +  // Since we do the scaling, grab their value and reset back to 100
   1.257 +  if (aDevMode->dmFields & DM_SCALE) {
   1.258 +    double origScale = 1.0;
   1.259 +    aPrintSettings->GetScaling(&origScale);
   1.260 +    double scale = double(aDevMode->dmScale) / 100.0f;
   1.261 +    if (origScale == 1.0 || scale != 1.0) {
   1.262 +      aPrintSettings->SetScaling(scale);
   1.263 +    }
   1.264 +    aDevMode->dmScale = 100;
   1.265 +    // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
   1.266 +    //aPrintSettings->SetShrinkToFit(false);
   1.267 +  }
   1.268 +
   1.269 +  if (aDevMode->dmFields & DM_PAPERSIZE) {
   1.270 +    aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData);
   1.271 +    aPrintSettings->SetPaperData(aDevMode->dmPaperSize);
   1.272 +    for (int32_t i=0;i<kNumPaperSizes;i++) {
   1.273 +      if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
   1.274 +        aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters);
   1.275 +        break;
   1.276 +      }
   1.277 +    }
   1.278 +
   1.279 +  } else if (aDevMode->dmFields & DM_PAPERLENGTH && aDevMode->dmFields & DM_PAPERWIDTH) {
   1.280 +    bool found = false;
   1.281 +    for (int32_t i=0;i<kNumPaperSizes;i++) {
   1.282 +      if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
   1.283 +        aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined);
   1.284 +        aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth);
   1.285 +        aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight);
   1.286 +        aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters);
   1.287 +        found = true;
   1.288 +        break;
   1.289 +      }
   1.290 +    }
   1.291 +    if (!found) {
   1.292 +      return NS_ERROR_FAILURE;
   1.293 +    }
   1.294 +  } else {
   1.295 +    return NS_ERROR_FAILURE;
   1.296 +  }
   1.297 +  return NS_OK;
   1.298 +}
   1.299 +
   1.300 +//----------------------------------------------------------------------------------
   1.301 +// Return localized bundle for resource strings
   1.302 +static nsresult
   1.303 +GetLocalizedBundle(const char * aPropFileName, nsIStringBundle** aStrBundle)
   1.304 +{
   1.305 +  NS_ENSURE_ARG_POINTER(aPropFileName);
   1.306 +  NS_ENSURE_ARG_POINTER(aStrBundle);
   1.307 +
   1.308 +  nsresult rv;
   1.309 +  nsCOMPtr<nsIStringBundle> bundle;
   1.310 +  
   1.311 +
   1.312 +  // Create bundle
   1.313 +  nsCOMPtr<nsIStringBundleService> stringService = 
   1.314 +    do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
   1.315 +  if (NS_SUCCEEDED(rv) && stringService) {
   1.316 +    rv = stringService->CreateBundle(aPropFileName, aStrBundle);
   1.317 +  }
   1.318 +  
   1.319 +  return rv;
   1.320 +}
   1.321 +
   1.322 +//--------------------------------------------------------
   1.323 +// Return localized string 
   1.324 +static nsresult
   1.325 +GetLocalizedString(nsIStringBundle* aStrBundle, const char* aKey, nsString& oVal)
   1.326 +{
   1.327 +  NS_ENSURE_ARG_POINTER(aStrBundle);
   1.328 +  NS_ENSURE_ARG_POINTER(aKey);
   1.329 +
   1.330 +  // Determine default label from string bundle
   1.331 +  nsXPIDLString valUni;
   1.332 +  nsAutoString key; 
   1.333 +  key.AssignWithConversion(aKey);
   1.334 +  nsresult rv = aStrBundle->GetStringFromName(key.get(), getter_Copies(valUni));
   1.335 +  if (NS_SUCCEEDED(rv) && valUni) {
   1.336 +    oVal.Assign(valUni);
   1.337 +  } else {
   1.338 +    oVal.Truncate();
   1.339 +  }
   1.340 +  return rv;
   1.341 +}
   1.342 +
   1.343 +//--------------------------------------------------------
   1.344 +// Set a multi-byte string in the control
   1.345 +static void SetTextOnWnd(HWND aControl, const nsString& aStr)
   1.346 +{
   1.347 +  nsAutoCString text;
   1.348 +  if (NS_SUCCEEDED(NS_CopyUnicodeToNative(aStr, text))) {
   1.349 +    ::SetWindowText(aControl, text.get());
   1.350 +  }
   1.351 +}
   1.352 +
   1.353 +//--------------------------------------------------------
   1.354 +// Will get the control and localized string by "key"
   1.355 +static void SetText(HWND             aParent, 
   1.356 +                    UINT             aId, 
   1.357 +                    nsIStringBundle* aStrBundle,
   1.358 +                    const char*      aKey) 
   1.359 +{
   1.360 +  HWND wnd = GetDlgItem (aParent, aId);
   1.361 +  if (!wnd) {
   1.362 +    return;
   1.363 +  }
   1.364 +  nsAutoString str;
   1.365 +  nsresult rv = GetLocalizedString(aStrBundle, aKey, str);
   1.366 +  if (NS_SUCCEEDED(rv)) {
   1.367 +    SetTextOnWnd(wnd, str);
   1.368 +  }
   1.369 +}
   1.370 +
   1.371 +//--------------------------------------------------------
   1.372 +static void SetRadio(HWND         aParent, 
   1.373 +                     UINT         aId, 
   1.374 +                     bool         aIsSet,
   1.375 +                     bool         isEnabled = true) 
   1.376 +{
   1.377 +  HWND wnd = ::GetDlgItem (aParent, aId);
   1.378 +  if (!wnd) {
   1.379 +    return;
   1.380 +  }
   1.381 +  if (!isEnabled) {
   1.382 +    ::EnableWindow(wnd, FALSE);
   1.383 +    return;
   1.384 +  }
   1.385 +  ::EnableWindow(wnd, TRUE);
   1.386 +  ::SendMessage(wnd, BM_SETCHECK, (WPARAM)aIsSet, (LPARAM)0);
   1.387 +}
   1.388 +
   1.389 +//--------------------------------------------------------
   1.390 +static void SetRadioOfGroup(HWND aDlg, int aRadId)
   1.391 +{
   1.392 +  int radioIds[] = {rad4, rad5, rad6};
   1.393 +  int numRads = 3;
   1.394 +
   1.395 +  for (int i=0;i<numRads;i++) {
   1.396 +    HWND radWnd = ::GetDlgItem(aDlg, radioIds[i]);
   1.397 +    if (radWnd != nullptr) {
   1.398 +      ::SendMessage(radWnd, BM_SETCHECK, (WPARAM)(radioIds[i] == aRadId), (LPARAM)0);
   1.399 +    }
   1.400 +  }
   1.401 +}
   1.402 +
   1.403 +//--------------------------------------------------------
   1.404 +typedef struct {
   1.405 +  const char * mKeyStr;
   1.406 +  long   mKeyId;
   1.407 +} PropKeyInfo;
   1.408 +
   1.409 +// These are the control ids used in the dialog and 
   1.410 +// defined by MS-Windows in commdlg.h
   1.411 +static PropKeyInfo gAllPropKeys[] = {
   1.412 +    {"printFramesTitleWindows", grp3},
   1.413 +    {"asLaidOutWindows", rad4},
   1.414 +    {"selectedFrameWindows", rad5},
   1.415 +    {"separateFramesWindows", rad6},
   1.416 +    {nullptr, 0}};
   1.417 +
   1.418 +//--------------------------------------------------------
   1.419 +//--------------------------------------------------------
   1.420 +//--------------------------------------------------------
   1.421 +//--------------------------------------------------------
   1.422 +// Get the absolute coords of the child windows relative
   1.423 +// to its parent window
   1.424 +static void GetLocalRect(HWND aWnd, RECT& aRect, HWND aParent)
   1.425 +{
   1.426 +  ::GetWindowRect(aWnd, &aRect);
   1.427 +
   1.428 +  // MapWindowPoints converts screen coordinates to client coordinates.
   1.429 +  // It works correctly in both left-to-right and right-to-left windows.
   1.430 +  ::MapWindowPoints(nullptr, aParent, (LPPOINT)&aRect, 2);
   1.431 +}
   1.432 +
   1.433 +//--------------------------------------------------------
   1.434 +// Show or Hide the control
   1.435 +static void Show(HWND aWnd, bool bState)
   1.436 +{
   1.437 +  if (aWnd) {
   1.438 +    ::ShowWindow(aWnd, bState?SW_SHOW:SW_HIDE);
   1.439 +  }
   1.440 +}
   1.441 +
   1.442 +//--------------------------------------------------------
   1.443 +// Create a child window "control"
   1.444 +static HWND CreateControl(LPCTSTR          aType,
   1.445 +                          DWORD            aStyle,
   1.446 +                          HINSTANCE        aHInst, 
   1.447 +                          HWND             aHdlg, 
   1.448 +                          int              aId, 
   1.449 +                          const nsAString& aStr, 
   1.450 +                          const nsIntRect& aRect)
   1.451 +{
   1.452 +  nsAutoCString str;
   1.453 +  if (NS_FAILED(NS_CopyUnicodeToNative(aStr, str)))
   1.454 +    return nullptr;
   1.455 +
   1.456 +  HWND hWnd = ::CreateWindow (aType, str.get(),
   1.457 +                              WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | aStyle,
   1.458 +                              aRect.x, aRect.y, aRect.width, aRect.height,
   1.459 +                              (HWND)aHdlg, (HMENU)(intptr_t)aId,
   1.460 +                              aHInst, nullptr);
   1.461 +  if (hWnd == nullptr) return nullptr;
   1.462 +
   1.463 +  // get the native font for the dialog and 
   1.464 +  // set it into the new control
   1.465 +  HFONT hFont = (HFONT)::SendMessage(aHdlg, WM_GETFONT, (WPARAM)0, (LPARAM)0);
   1.466 +  if (hFont != nullptr) {
   1.467 +    ::SendMessage(hWnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0);
   1.468 +  }
   1.469 +  return hWnd;
   1.470 +}
   1.471 +
   1.472 +//--------------------------------------------------------
   1.473 +// Create a Radio Button
   1.474 +static HWND CreateRadioBtn(HINSTANCE        aHInst, 
   1.475 +                           HWND             aHdlg, 
   1.476 +                           int              aId, 
   1.477 +                           const char*      aStr, 
   1.478 +                           const nsIntRect& aRect)
   1.479 +{
   1.480 +  nsString cStr;
   1.481 +  cStr.AssignWithConversion(aStr);
   1.482 +  return CreateControl("BUTTON", BS_RADIOBUTTON, aHInst, aHdlg, aId, cStr, aRect);
   1.483 +}
   1.484 +
   1.485 +//--------------------------------------------------------
   1.486 +// Create a Group Box
   1.487 +static HWND CreateGroupBox(HINSTANCE        aHInst, 
   1.488 +                           HWND             aHdlg, 
   1.489 +                           int              aId, 
   1.490 +                           const nsAString& aStr, 
   1.491 +                           const nsIntRect& aRect)
   1.492 +{
   1.493 +  return CreateControl("BUTTON", BS_GROUPBOX, aHInst, aHdlg, aId, aStr, aRect);
   1.494 +}
   1.495 +
   1.496 +//--------------------------------------------------------
   1.497 +// Localizes and initializes the radio buttons and group
   1.498 +static void InitializeExtendedDialog(HWND hdlg, int16_t aHowToEnableFrameUI) 
   1.499 +{
   1.500 +  NS_ABORT_IF_FALSE(aHowToEnableFrameUI != nsIPrintSettings::kFrameEnableNone,
   1.501 +                    "should not be called");
   1.502 +
   1.503 +  // Localize the new controls in the print dialog
   1.504 +  nsCOMPtr<nsIStringBundle> strBundle;
   1.505 +  if (NS_SUCCEEDED(GetLocalizedBundle(PRINTDLG_PROPERTIES, getter_AddRefs(strBundle)))) {
   1.506 +    int32_t i = 0;
   1.507 +    while (gAllPropKeys[i].mKeyStr != nullptr) {
   1.508 +      SetText(hdlg, gAllPropKeys[i].mKeyId, strBundle, gAllPropKeys[i].mKeyStr);
   1.509 +      i++;
   1.510 +    }
   1.511 +  }
   1.512 +
   1.513 +  // Set up radio buttons
   1.514 +  if (aHowToEnableFrameUI == nsIPrintSettings::kFrameEnableAll) {
   1.515 +    SetRadio(hdlg, rad4, false);  
   1.516 +    SetRadio(hdlg, rad5, true); 
   1.517 +    SetRadio(hdlg, rad6, false);
   1.518 +    // set default so user doesn't have to actually press on it
   1.519 +    gFrameSelectedRadioBtn = rad5;
   1.520 +
   1.521 +  } else { // nsIPrintSettings::kFrameEnableAsIsAndEach
   1.522 +    SetRadio(hdlg, rad4, false);  
   1.523 +    SetRadio(hdlg, rad5, false, false); 
   1.524 +    SetRadio(hdlg, rad6, true);
   1.525 +    // set default so user doesn't have to actually press on it
   1.526 +    gFrameSelectedRadioBtn = rad6;
   1.527 +  }
   1.528 +}
   1.529 +
   1.530 +
   1.531 +//--------------------------------------------------------
   1.532 +// Special Hook Procedure for handling the print dialog messages
   1.533 +static UINT CALLBACK PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) 
   1.534 +{
   1.535 +
   1.536 +  if (uiMsg == WM_COMMAND) {
   1.537 +    UINT id = LOWORD(wParam);
   1.538 +    if (id == rad4 || id == rad5 || id == rad6) {
   1.539 +      gFrameSelectedRadioBtn = id;
   1.540 +      SetRadioOfGroup(hdlg, id);
   1.541 +    }
   1.542 +
   1.543 +  } else if (uiMsg == WM_INITDIALOG) {
   1.544 +    PRINTDLG * printDlg = (PRINTDLG *)lParam;
   1.545 +    if (printDlg == nullptr) return 0L;
   1.546 +
   1.547 +    int16_t howToEnableFrameUI = (int16_t)printDlg->lCustData;
   1.548 +    // don't add frame options if they would be disabled anyway
   1.549 +    // because there are no frames
   1.550 +    if (howToEnableFrameUI == nsIPrintSettings::kFrameEnableNone)
   1.551 +      return TRUE;
   1.552 +
   1.553 +    HINSTANCE hInst = (HINSTANCE)::GetWindowLongPtr(hdlg, GWLP_HINSTANCE);
   1.554 +    if (hInst == nullptr) return 0L;
   1.555 +
   1.556 +    // Start by getting the local rects of several of the controls
   1.557 +    // so we can calculate where the new controls are
   1.558 +    HWND wnd = ::GetDlgItem(hdlg, grp1);
   1.559 +    if (wnd == nullptr) return 0L;
   1.560 +    RECT dlgRect;
   1.561 +    GetLocalRect(wnd, dlgRect, hdlg);
   1.562 +
   1.563 +    wnd = ::GetDlgItem(hdlg, rad1); // this is the top control "All"
   1.564 +    if (wnd == nullptr) return 0L;
   1.565 +    RECT rad1Rect;
   1.566 +    GetLocalRect(wnd, rad1Rect, hdlg);
   1.567 +
   1.568 +    wnd = ::GetDlgItem(hdlg, rad2); // this is the bottom control "Selection"
   1.569 +    if (wnd == nullptr) return 0L;
   1.570 +    RECT rad2Rect;
   1.571 +    GetLocalRect(wnd, rad2Rect, hdlg);
   1.572 +
   1.573 +    wnd = ::GetDlgItem(hdlg, rad3); // this is the middle control "Pages"
   1.574 +    if (wnd == nullptr) return 0L;
   1.575 +    RECT rad3Rect;
   1.576 +    GetLocalRect(wnd, rad3Rect, hdlg);
   1.577 +
   1.578 +    HWND okWnd = ::GetDlgItem(hdlg, IDOK);
   1.579 +    if (okWnd == nullptr) return 0L;
   1.580 +    RECT okRect;
   1.581 +    GetLocalRect(okWnd, okRect, hdlg);
   1.582 +
   1.583 +    wnd = ::GetDlgItem(hdlg, grp4); // this is the "Print range" groupbox
   1.584 +    if (wnd == nullptr) return 0L;
   1.585 +    RECT prtRect;
   1.586 +    GetLocalRect(wnd, prtRect, hdlg);
   1.587 +
   1.588 +
   1.589 +    // calculate various different "gaps" for layout purposes
   1.590 +
   1.591 +    int rbGap     = rad3Rect.top - rad1Rect.bottom;     // gap between radiobtns
   1.592 +    int grpBotGap = dlgRect.bottom - rad2Rect.bottom;   // gap from bottom rb to bottom of grpbox
   1.593 +    int grpGap    = dlgRect.top - prtRect.bottom ;      // gap between group boxes
   1.594 +    int top       = dlgRect.bottom + grpGap;            
   1.595 +    int radHgt    = rad1Rect.bottom - rad1Rect.top + 1; // top of new group box
   1.596 +    int y         = top+(rad1Rect.top-dlgRect.top);     // starting pos of first radio
   1.597 +    int rbWidth   = dlgRect.right - rad1Rect.left - 5;  // measure from rb left to the edge of the groupbox
   1.598 +                                                        // (5 is arbitrary)
   1.599 +    nsIntRect rect;
   1.600 +
   1.601 +    // Create and position the radio buttons
   1.602 +    //
   1.603 +    // If any one control cannot be created then 
   1.604 +    // hide the others and bail out
   1.605 +    //
   1.606 +    rect.SetRect(rad1Rect.left, y, rbWidth,radHgt);
   1.607 +    HWND rad4Wnd = CreateRadioBtn(hInst, hdlg, rad4, kAsLaidOutOnScreenStr, rect);
   1.608 +    if (rad4Wnd == nullptr) return 0L;
   1.609 +    y += radHgt + rbGap;
   1.610 +
   1.611 +    rect.SetRect(rad1Rect.left, y, rbWidth, radHgt);
   1.612 +    HWND rad5Wnd = CreateRadioBtn(hInst, hdlg, rad5, kTheSelectedFrameStr, rect);
   1.613 +    if (rad5Wnd == nullptr) {
   1.614 +      Show(rad4Wnd, FALSE); // hide
   1.615 +      return 0L;
   1.616 +    }
   1.617 +    y += radHgt + rbGap;
   1.618 +
   1.619 +    rect.SetRect(rad1Rect.left, y, rbWidth, radHgt);
   1.620 +    HWND rad6Wnd = CreateRadioBtn(hInst, hdlg, rad6, kEachFrameSeparately, rect);
   1.621 +    if (rad6Wnd == nullptr) {
   1.622 +      Show(rad4Wnd, FALSE); // hide
   1.623 +      Show(rad5Wnd, FALSE); // hide
   1.624 +      return 0L;
   1.625 +    }
   1.626 +    y += radHgt + grpBotGap;
   1.627 +
   1.628 +    // Create and position the group box
   1.629 +    rect.SetRect (dlgRect.left, top, dlgRect.right-dlgRect.left+1, y-top+1);
   1.630 +    HWND grpBoxWnd = CreateGroupBox(hInst, hdlg, grp3, NS_LITERAL_STRING("Print Frame"), rect);
   1.631 +    if (grpBoxWnd == nullptr) {
   1.632 +      Show(rad4Wnd, FALSE); // hide
   1.633 +      Show(rad5Wnd, FALSE); // hide
   1.634 +      Show(rad6Wnd, FALSE); // hide
   1.635 +      return 0L;
   1.636 +    }
   1.637 +
   1.638 +    // Here we figure out the old height of the dlg
   1.639 +    // then figure its gap from the old grpbx to the bottom
   1.640 +    // then size the dlg
   1.641 +    RECT pr, cr; 
   1.642 +    ::GetWindowRect(hdlg, &pr);
   1.643 +    ::GetClientRect(hdlg, &cr);
   1.644 +
   1.645 +    int dlgHgt = (cr.bottom - cr.top) + 1;
   1.646 +    int bottomGap = dlgHgt - okRect.bottom;
   1.647 +    pr.bottom += (dlgRect.bottom-dlgRect.top) + grpGap + 1 - (dlgHgt-dlgRect.bottom) + bottomGap;
   1.648 +
   1.649 +    ::SetWindowPos(hdlg, nullptr, pr.left, pr.top, pr.right-pr.left+1, pr.bottom-pr.top+1, 
   1.650 +                   SWP_NOMOVE|SWP_NOREDRAW|SWP_NOZORDER);
   1.651 +
   1.652 +    // figure out the new height of the dialog
   1.653 +    ::GetClientRect(hdlg, &cr);
   1.654 +    dlgHgt = (cr.bottom - cr.top) + 1;
   1.655 + 
   1.656 +    // Reposition the OK and Cancel btns
   1.657 +    int okHgt = okRect.bottom - okRect.top + 1;
   1.658 +    ::SetWindowPos(okWnd, nullptr, okRect.left, dlgHgt-bottomGap-okHgt, 0, 0, 
   1.659 +                   SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER);
   1.660 +
   1.661 +    HWND cancelWnd = ::GetDlgItem(hdlg, IDCANCEL);
   1.662 +    if (cancelWnd == nullptr) return 0L;
   1.663 +
   1.664 +    RECT cancelRect;
   1.665 +    GetLocalRect(cancelWnd, cancelRect, hdlg);
   1.666 +    int cancelHgt = cancelRect.bottom - cancelRect.top + 1;
   1.667 +    ::SetWindowPos(cancelWnd, nullptr, cancelRect.left, dlgHgt-bottomGap-cancelHgt, 0, 0, 
   1.668 +                   SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER);
   1.669 +
   1.670 +    // localize and initialize the groupbox and radiobuttons
   1.671 +    InitializeExtendedDialog(hdlg, howToEnableFrameUI);
   1.672 +
   1.673 +    // Looks like we were able to extend the dialog
   1.674 +    gDialogWasExtended = true;
   1.675 +    return TRUE;
   1.676 +  }
   1.677 +  return 0L;
   1.678 +}
   1.679 +
   1.680 +//----------------------------------------------------------------------------------
   1.681 +// Returns a Global Moveable Memory Handle to a DevMode
   1.682 +// from the Printer by the name of aPrintName
   1.683 +//
   1.684 +// NOTE:
   1.685 +//   This function assumes that aPrintName has already been converted from 
   1.686 +//   unicode
   1.687 +//
   1.688 +static HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS)
   1.689 +{
   1.690 +  HGLOBAL hGlobalDevMode = nullptr;
   1.691 +
   1.692 +  HANDLE hPrinter = nullptr;
   1.693 +  // const cast kludge for silly Win32 api's
   1.694 +  LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get()));
   1.695 +  BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr);
   1.696 +  if (status) {
   1.697 +
   1.698 +    LPDEVMODEW  pNewDevMode;
   1.699 +    DWORD       dwNeeded, dwRet;
   1.700 +
   1.701 +    // Get the buffer size
   1.702 +    dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, nullptr, 0);
   1.703 +    if (dwNeeded == 0) {
   1.704 +      return nullptr;
   1.705 +    }
   1.706 +
   1.707 +    // Allocate a buffer of the correct size.
   1.708 +    pNewDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
   1.709 +    if (!pNewDevMode) return nullptr;
   1.710 +
   1.711 +    hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded);
   1.712 +    if (!hGlobalDevMode) {
   1.713 +      ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
   1.714 +      return nullptr;
   1.715 +    }
   1.716 +
   1.717 +    dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, pNewDevMode, nullptr, DM_OUT_BUFFER);
   1.718 +
   1.719 +    if (dwRet != IDOK) {
   1.720 +      ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
   1.721 +      ::GlobalFree(hGlobalDevMode);
   1.722 +      ::ClosePrinter(hPrinter);
   1.723 +      return nullptr;
   1.724 +    }
   1.725 +
   1.726 +    // Lock memory and copy contents from DEVMODE (current printer)
   1.727 +    // to Global Memory DEVMODE
   1.728 +    LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hGlobalDevMode);
   1.729 +    if (devMode) {
   1.730 +      memcpy(devMode, pNewDevMode, dwNeeded);
   1.731 +      // Initialize values from the PrintSettings
   1.732 +      SetupDevModeFromSettings(devMode, aPS);
   1.733 +
   1.734 +      // Sets back the changes we made to the DevMode into the Printer Driver
   1.735 +      dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER);
   1.736 +      if (dwRet != IDOK) {
   1.737 +        ::GlobalUnlock(hGlobalDevMode);
   1.738 +        ::GlobalFree(hGlobalDevMode);
   1.739 +        ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
   1.740 +        ::ClosePrinter(hPrinter);
   1.741 +        return nullptr;
   1.742 +      }
   1.743 +
   1.744 +      ::GlobalUnlock(hGlobalDevMode);
   1.745 +    } else {
   1.746 +      ::GlobalFree(hGlobalDevMode);
   1.747 +      hGlobalDevMode = nullptr;
   1.748 +    }
   1.749 +
   1.750 +    ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
   1.751 +
   1.752 +    ::ClosePrinter(hPrinter);
   1.753 +
   1.754 +  } else {
   1.755 +    return nullptr;
   1.756 +  }
   1.757 +
   1.758 +  return hGlobalDevMode;
   1.759 +}
   1.760 +
   1.761 +//------------------------------------------------------------------
   1.762 +// helper
   1.763 +static void GetDefaultPrinterNameFromGlobalPrinters(nsXPIDLString &printerName)
   1.764 +{
   1.765 +  nsCOMPtr<nsIPrinterEnumerator> prtEnum = do_GetService("@mozilla.org/gfx/printerenumerator;1");
   1.766 +  if (prtEnum) {
   1.767 +    prtEnum->GetDefaultPrinterName(getter_Copies(printerName));
   1.768 +  }
   1.769 +}
   1.770 +
   1.771 +// Determine whether we have a completely native dialog
   1.772 +// or whether we cshould extend it
   1.773 +static bool ShouldExtendPrintDialog()
   1.774 +{
   1.775 +  nsresult rv;
   1.776 +  nsCOMPtr<nsIPrefService> prefs =
   1.777 +    do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   1.778 +  NS_ENSURE_SUCCESS(rv, true);
   1.779 +  nsCOMPtr<nsIPrefBranch> prefBranch;
   1.780 +  rv = prefs->GetBranch(nullptr, getter_AddRefs(prefBranch));
   1.781 +  NS_ENSURE_SUCCESS(rv, true);
   1.782 +
   1.783 +  bool result;
   1.784 +  rv = prefBranch->GetBoolPref("print.extend_native_print_dialog", &result);
   1.785 +  NS_ENSURE_SUCCESS(rv, true);
   1.786 +  return result;
   1.787 +}
   1.788 +
   1.789 +//------------------------------------------------------------------
   1.790 +// Displays the native Print Dialog
   1.791 +static nsresult 
   1.792 +ShowNativePrintDialog(HWND              aHWnd,
   1.793 +                      nsIPrintSettings* aPrintSettings)
   1.794 +{
   1.795 +  //NS_ENSURE_ARG_POINTER(aHWnd);
   1.796 +  NS_ENSURE_ARG_POINTER(aPrintSettings);
   1.797 +
   1.798 +  gDialogWasExtended  = false;
   1.799 +
   1.800 +  HGLOBAL hGlobalDevMode = nullptr;
   1.801 +  HGLOBAL hDevNames      = nullptr;
   1.802 +
   1.803 +  // Get the Print Name to be used
   1.804 +  nsXPIDLString printerName;
   1.805 +  aPrintSettings->GetPrinterName(getter_Copies(printerName));
   1.806 +
   1.807 +  // If there is no name then use the default printer
   1.808 +  if (printerName.IsEmpty()) {
   1.809 +    GetDefaultPrinterNameFromGlobalPrinters(printerName);
   1.810 +  } else {
   1.811 +    HANDLE hPrinter = nullptr;
   1.812 +    if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())), &hPrinter, nullptr)) {
   1.813 +      // If the last used printer is not found, we should use default printer.
   1.814 +      GetDefaultPrinterNameFromGlobalPrinters(printerName);
   1.815 +    } else {
   1.816 +      ::ClosePrinter(hPrinter);
   1.817 +    }
   1.818 +  }
   1.819 +
   1.820 +  // Now create a DEVNAMES struct so the the dialog is initialized correctly.
   1.821 +
   1.822 +  uint32_t len = printerName.Length();
   1.823 +  hDevNames = (HGLOBAL)::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + 
   1.824 +                                     sizeof(DEVNAMES));
   1.825 +  if (!hDevNames) {
   1.826 +    return NS_ERROR_OUT_OF_MEMORY;
   1.827 +  }
   1.828 +
   1.829 +  DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames);
   1.830 +  if (!pDevNames) {
   1.831 +    ::GlobalFree(hDevNames);
   1.832 +    return NS_ERROR_FAILURE;
   1.833 +  }
   1.834 +  pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
   1.835 +  pDevNames->wDeviceOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
   1.836 +  pDevNames->wOutputOffset = sizeof(DEVNAMES)/sizeof(wchar_t)+len;
   1.837 +  pDevNames->wDefault      = 0;
   1.838 +
   1.839 +  memcpy(pDevNames+1, printerName, (len + 1) * sizeof(wchar_t));
   1.840 +  ::GlobalUnlock(hDevNames);
   1.841 +
   1.842 +  // Create a Moveable Memory Object that holds a new DevMode
   1.843 +  // from the Printer Name
   1.844 +  // The PRINTDLG.hDevMode requires that it be a moveable memory object
   1.845 +  // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled
   1.846 +  // When the user prints, it comes back in the printdlg struct and 
   1.847 +  // is used and cleaned up later
   1.848 +  hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings);
   1.849 +
   1.850 +  // Prepare to Display the Print Dialog
   1.851 +  PRINTDLGW  prntdlg;
   1.852 +  memset(&prntdlg, 0, sizeof(PRINTDLGW));
   1.853 +
   1.854 +  prntdlg.lStructSize = sizeof(prntdlg);
   1.855 +  prntdlg.hwndOwner   = aHWnd;
   1.856 +  prntdlg.hDevMode    = hGlobalDevMode;
   1.857 +  prntdlg.hDevNames   = hDevNames;
   1.858 +  prntdlg.hDC         = nullptr;
   1.859 +  prntdlg.Flags       = PD_ALLPAGES | PD_RETURNIC | 
   1.860 +                        PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE;
   1.861 +
   1.862 +  // if there is a current selection then enable the "Selection" radio button
   1.863 +  int16_t howToEnableFrameUI = nsIPrintSettings::kFrameEnableNone;
   1.864 +  bool isOn;
   1.865 +  aPrintSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &isOn);
   1.866 +  if (!isOn) {
   1.867 +    prntdlg.Flags |= PD_NOSELECTION;
   1.868 +  }
   1.869 +  aPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
   1.870 +
   1.871 +  int32_t pg = 1;
   1.872 +  aPrintSettings->GetStartPageRange(&pg);
   1.873 +  prntdlg.nFromPage           = pg;
   1.874 +  
   1.875 +  aPrintSettings->GetEndPageRange(&pg);
   1.876 +  prntdlg.nToPage             = pg;
   1.877 +
   1.878 +  prntdlg.nMinPage            = 1;
   1.879 +  prntdlg.nMaxPage            = 0xFFFF;
   1.880 +  prntdlg.nCopies             = 1;
   1.881 +  prntdlg.lpfnSetupHook       = nullptr;
   1.882 +  prntdlg.lpSetupTemplateName = nullptr;
   1.883 +  prntdlg.hPrintTemplate      = nullptr;
   1.884 +  prntdlg.hSetupTemplate      = nullptr;
   1.885 +
   1.886 +  prntdlg.hInstance           = nullptr;
   1.887 +  prntdlg.lpPrintTemplateName = nullptr;
   1.888 +
   1.889 +  if (!ShouldExtendPrintDialog()) {
   1.890 +    prntdlg.lCustData         = 0;
   1.891 +    prntdlg.lpfnPrintHook     = nullptr;
   1.892 +  } else {
   1.893 +    // Set up print dialog "hook" procedure for extending the dialog
   1.894 +    prntdlg.lCustData         = (DWORD)howToEnableFrameUI;
   1.895 +    prntdlg.lpfnPrintHook     = (LPPRINTHOOKPROC)PrintHookProc;
   1.896 +    prntdlg.Flags            |= PD_ENABLEPRINTHOOK;
   1.897 +  }
   1.898 +
   1.899 +  BOOL result = ::PrintDlgW(&prntdlg);
   1.900 +
   1.901 +  if (TRUE == result) {
   1.902 +    // check to make sure we don't have any nullptr pointers
   1.903 +    NS_ENSURE_TRUE(aPrintSettings && prntdlg.hDevMode, NS_ERROR_FAILURE);
   1.904 +
   1.905 +    if (prntdlg.hDevNames == nullptr) {
   1.906 +      ::GlobalFree(hGlobalDevMode);
   1.907 +      return NS_ERROR_FAILURE;
   1.908 +    }
   1.909 +    // Lock the deviceNames and check for nullptr
   1.910 +    DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames);
   1.911 +    if (devnames == nullptr) {
   1.912 +      ::GlobalFree(hGlobalDevMode);
   1.913 +      return NS_ERROR_FAILURE;
   1.914 +    }
   1.915 +
   1.916 +    char16_t* device = &(((char16_t *)devnames)[devnames->wDeviceOffset]);
   1.917 +    char16_t* driver = &(((char16_t *)devnames)[devnames->wDriverOffset]);
   1.918 +
   1.919 +    // Check to see if the "Print To File" control is checked
   1.920 +    // then take the name from devNames and set it in the PrintSettings
   1.921 +    //
   1.922 +    // NOTE:
   1.923 +    // As per Microsoft SDK documentation the returned value offset from
   1.924 +    // devnames->wOutputOffset is either "FILE:" or nullptr
   1.925 +    // if the "Print To File" checkbox is checked it MUST be "FILE:"
   1.926 +    // We assert as an extra safety check.
   1.927 +    if (prntdlg.Flags & PD_PRINTTOFILE) {
   1.928 +      char16ptr_t fileName = &(((wchar_t *)devnames)[devnames->wOutputOffset]);
   1.929 +      NS_ASSERTION(wcscmp(fileName, L"FILE:") == 0, "FileName must be `FILE:`");
   1.930 +      aPrintSettings->SetToFileName(fileName);
   1.931 +      aPrintSettings->SetPrintToFile(true);
   1.932 +    } else {
   1.933 +      // clear "print to file" info
   1.934 +      aPrintSettings->SetPrintToFile(false);
   1.935 +      aPrintSettings->SetToFileName(nullptr);
   1.936 +    }
   1.937 +
   1.938 +    nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
   1.939 +    if (!psWin) {
   1.940 +      ::GlobalFree(hGlobalDevMode);
   1.941 +      return NS_ERROR_FAILURE;
   1.942 +    }
   1.943 +
   1.944 +    // Setup local Data members
   1.945 +    psWin->SetDeviceName(device);
   1.946 +    psWin->SetDriverName(driver);
   1.947 +
   1.948 +#if defined(DEBUG_rods) || defined(DEBUG_dcone)
   1.949 +    wprintf(L"printer: driver %s, device %s  flags: %d\n", driver, device, prntdlg.Flags);
   1.950 +#endif
   1.951 +    // fill the print options with the info from the dialog
   1.952 +
   1.953 +    aPrintSettings->SetPrinterName(device);
   1.954 +
   1.955 +    if (prntdlg.Flags & PD_SELECTION) {
   1.956 +      aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSelection);
   1.957 +
   1.958 +    } else if (prntdlg.Flags & PD_PAGENUMS) {
   1.959 +      aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange);
   1.960 +      aPrintSettings->SetStartPageRange(prntdlg.nFromPage);
   1.961 +      aPrintSettings->SetEndPageRange(prntdlg.nToPage);
   1.962 +
   1.963 +    } else { // (prntdlg.Flags & PD_ALLPAGES)
   1.964 +      aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
   1.965 +    }
   1.966 +
   1.967 +    if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
   1.968 +      // make sure the dialog got extended
   1.969 +      if (gDialogWasExtended) {
   1.970 +        // check to see about the frame radio buttons
   1.971 +        switch (gFrameSelectedRadioBtn) {
   1.972 +          case rad4: 
   1.973 +            aPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
   1.974 +            break;
   1.975 +          case rad5: 
   1.976 +            aPrintSettings->SetPrintFrameType(nsIPrintSettings::kSelectedFrame);
   1.977 +            break;
   1.978 +          case rad6: 
   1.979 +            aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
   1.980 +            break;
   1.981 +        } // switch
   1.982 +      } else {
   1.983 +        // if it didn't get extended then have it default to printing
   1.984 +        // each frame separately
   1.985 +        aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
   1.986 +      }
   1.987 +    } else {
   1.988 +      aPrintSettings->SetPrintFrameType(nsIPrintSettings::kNoFrames);
   1.989 +    }
   1.990 +    // Unlock DeviceNames
   1.991 +    ::GlobalUnlock(prntdlg.hDevNames);
   1.992 +
   1.993 +    // Transfer the settings from the native data to the PrintSettings
   1.994 +    LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode);
   1.995 +    if (devMode == nullptr) {
   1.996 +      ::GlobalFree(hGlobalDevMode);
   1.997 +      return NS_ERROR_FAILURE;
   1.998 +    }
   1.999 +    psWin->SetDevMode(devMode); // copies DevMode
  1.1000 +    SetPrintSettingsFromDevMode(aPrintSettings, devMode);
  1.1001 +    ::GlobalUnlock(prntdlg.hDevMode);
  1.1002 +
  1.1003 +#if defined(DEBUG_rods) || defined(DEBUG_dcone)
  1.1004 +    bool    printSelection = prntdlg.Flags & PD_SELECTION;
  1.1005 +    bool    printAllPages  = prntdlg.Flags & PD_ALLPAGES;
  1.1006 +    bool    printNumPages  = prntdlg.Flags & PD_PAGENUMS;
  1.1007 +    int32_t fromPageNum    = 0;
  1.1008 +    int32_t toPageNum      = 0;
  1.1009 +
  1.1010 +    if (printNumPages) {
  1.1011 +      fromPageNum = prntdlg.nFromPage;
  1.1012 +      toPageNum   = prntdlg.nToPage;
  1.1013 +    } 
  1.1014 +    if (printSelection) {
  1.1015 +      printf("Printing the selection\n");
  1.1016 +
  1.1017 +    } else if (printAllPages) {
  1.1018 +      printf("Printing all the pages\n");
  1.1019 +
  1.1020 +    } else {
  1.1021 +      printf("Printing from page no. %d to %d\n", fromPageNum, toPageNum);
  1.1022 +    }
  1.1023 +#endif
  1.1024 +    
  1.1025 +  } else {
  1.1026 +    ::SetFocus(aHWnd);
  1.1027 +    aPrintSettings->SetIsCancelled(true);
  1.1028 +    if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode);
  1.1029 +    return NS_ERROR_ABORT;
  1.1030 +  }
  1.1031 +
  1.1032 +  return NS_OK;
  1.1033 +}
  1.1034 +
  1.1035 +//------------------------------------------------------------------
  1.1036 +static void 
  1.1037 +PrepareForPrintDialog(nsIWebBrowserPrint* aWebBrowserPrint, nsIPrintSettings* aPS)
  1.1038 +{
  1.1039 +  NS_ASSERTION(aWebBrowserPrint, "Can't be null");
  1.1040 +  NS_ASSERTION(aPS, "Can't be null");
  1.1041 +
  1.1042 +  bool isFramesetDocument;
  1.1043 +  bool isFramesetFrameSelected;
  1.1044 +  bool isIFrameSelected;
  1.1045 +  bool isRangeSelection;
  1.1046 +
  1.1047 +  aWebBrowserPrint->GetIsFramesetDocument(&isFramesetDocument);
  1.1048 +  aWebBrowserPrint->GetIsFramesetFrameSelected(&isFramesetFrameSelected);
  1.1049 +  aWebBrowserPrint->GetIsIFrameSelected(&isIFrameSelected);
  1.1050 +  aWebBrowserPrint->GetIsRangeSelection(&isRangeSelection);
  1.1051 +
  1.1052 +  // Setup print options for UI
  1.1053 +  if (isFramesetDocument) {
  1.1054 +    if (isFramesetFrameSelected) {
  1.1055 +      aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
  1.1056 +    } else {
  1.1057 +      aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
  1.1058 +    }
  1.1059 +  } else {
  1.1060 +    aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
  1.1061 +  }
  1.1062 +
  1.1063 +  // Now determine how to set up the Frame print UI
  1.1064 +  aPS->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isRangeSelection || isIFrameSelected);
  1.1065 +
  1.1066 +}
  1.1067 +
  1.1068 +//----------------------------------------------------------------------------------
  1.1069 +//-- Show Print Dialog
  1.1070 +//----------------------------------------------------------------------------------
  1.1071 +nsresult NativeShowPrintDialog(HWND                aHWnd,
  1.1072 +                               nsIWebBrowserPrint* aWebBrowserPrint,
  1.1073 +                               nsIPrintSettings*   aPrintSettings)
  1.1074 +{
  1.1075 +  PrepareForPrintDialog(aWebBrowserPrint, aPrintSettings);
  1.1076 +
  1.1077 +  nsresult rv = ShowNativePrintDialog(aHWnd, aPrintSettings);
  1.1078 +  if (aHWnd) {
  1.1079 +    ::DestroyWindow(aHWnd);
  1.1080 +  }
  1.1081 +
  1.1082 +  return rv;
  1.1083 +}
  1.1084 +

mercurial