/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsPrintSettingsWin.h" #include "mozilla/ArrayUtils.h" #include "nsCRT.h" #include "nsDeviceContextSpecWin.h" #include "nsPrintSettingsImpl.h" #include "WinUtils.h" using namespace mozilla; // Using paper sizes from wingdi.h and the units given there, plus a little // extra research for the ones it doesn't give. Looks like the list hasn't // changed since Windows 2000, so should be fairly stable now. const short kPaperSizeUnits[] = { nsIPrintSettings::kPaperSizeMillimeters, // Not Used default to mm as // DEVMODE uses tenths of mm, just // in case nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTERSMALL nsIPrintSettings::kPaperSizeInches, // DMPAPER_TABLOID nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEDGER nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEGAL nsIPrintSettings::kPaperSizeInches, // DMPAPER_STATEMENT nsIPrintSettings::kPaperSizeInches, // DMPAPER_EXECUTIVE nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4SMALL nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B4 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5 nsIPrintSettings::kPaperSizeInches, // DMPAPER_FOLIO nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_QUARTO nsIPrintSettings::kPaperSizeInches, // DMPAPER_10X14 nsIPrintSettings::kPaperSizeInches, // DMPAPER_11X17 nsIPrintSettings::kPaperSizeInches, // DMPAPER_NOTE nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_9 nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_10 nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_11 nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_12 nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_14 nsIPrintSettings::kPaperSizeInches, // DMPAPER_CSHEET nsIPrintSettings::kPaperSizeInches, // DMPAPER_DSHEET nsIPrintSettings::kPaperSizeInches, // DMPAPER_ESHEET nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_DL nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C5 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C3 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C4 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C6 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C65 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B4 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B5 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B6 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_ITALY nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_MONARCH nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_PERSONAL nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_US nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_STD_GERMAN nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_LGL_GERMAN nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ISO_B4 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JAPANESE_POSTCARD nsIPrintSettings::kPaperSizeInches, // DMPAPER_9X11 nsIPrintSettings::kPaperSizeInches, // DMPAPER_10X11 nsIPrintSettings::kPaperSizeInches, // DMPAPER_15X11 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_INVITE nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_RESERVED_48 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_RESERVED_49 nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_EXTRA nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEGAL_EXTRA nsIPrintSettings::kPaperSizeInches, // DMPAPER_TABLOID_EXTRA nsIPrintSettings::kPaperSizeInches, // DMPAPER_A4_EXTRA nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_TRANSVERSE nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_TRANSVERSE nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_EXTRA_TRANSVERSE nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A_PLUS nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B_PLUS nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_PLUS nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_PLUS nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_TRANSVERSE nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_TRANSVERSE nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_EXTRA nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_EXTRA nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_EXTRA nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A2 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_TRANSVERSE nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_EXTRA_TRANSVERSE nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_DBL_JAPANESE_POSTCARD nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A6 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU2 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU3 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU3 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU4 nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B4_JIS_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_JIS_ROTATED nsIPrintSettings:: kPaperSizeMillimeters, // DMPAPER_JAPANESE_POSTCARD_ROTATED nsIPrintSettings:: kPaperSizeMillimeters, // DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A6_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU2_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU3_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU3_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU4_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B6_JIS nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B6_JIS_ROTATED nsIPrintSettings::kPaperSizeInches, // DMPAPER_12X11 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_YOU4 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_YOU4_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P16K nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32K nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32KBIG nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_1 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_2 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_3 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_4 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_5 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_6 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_7 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_8 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_9 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_10 nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P16K_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32K_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32KBIG_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_1_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_2_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_3_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_4_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_5_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_6_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_7_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_8_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_9_ROTATED nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_10_ROTATED }; NS_IMPL_ISUPPORTS_INHERITED(nsPrintSettingsWin, nsPrintSettings, nsIPrintSettingsWin) /** --------------------------------------------------- * See documentation in nsPrintSettingsWin.h * @update */ nsPrintSettingsWin::nsPrintSettingsWin() : nsPrintSettings(), mDeviceName(nullptr), mDriverName(nullptr), mDevMode(nullptr) {} /** --------------------------------------------------- * See documentation in nsPrintSettingsWin.h * @update */ nsPrintSettingsWin::nsPrintSettingsWin(const nsPrintSettingsWin& aPS) : mDevMode(nullptr) { *this = aPS; } /* static */ void nsPrintSettingsWin::PaperSizeUnitFromDmPaperSize(short aPaperSize, int16_t& aPaperSizeUnit) { if (aPaperSize > 0 && aPaperSize < int32_t(ArrayLength(kPaperSizeUnits))) { aPaperSizeUnit = kPaperSizeUnits[aPaperSize]; } } void nsPrintSettingsWin::InitWithInitializer( const PrintSettingsInitializer& aSettings) { nsPrintSettings::InitWithInitializer(aSettings); if (aSettings.mDevmodeWStorage.Length() < sizeof(DEVMODEW)) { return; } auto* devmode = reinterpret_cast(aSettings.mDevmodeWStorage.Elements()); if (devmode->dmSize != sizeof(DEVMODEW) || devmode->dmSize + devmode->dmDriverExtra > aSettings.mDevmodeWStorage.Length()) { return; } // SetDevMode copies the DEVMODE. SetDevMode(const_cast(devmode)); if (mDevMode->dmFields & DM_SCALE) { // Since we do the scaling, grab the DEVMODE value and reset it back to 100. double scale = double(mDevMode->dmScale) / 100.0f; if (mScaling == 1.0 || scale != 1.0) { SetScaling(scale); } mDevMode->dmScale = 100; } } already_AddRefed CreatePlatformPrintSettings( const PrintSettingsInitializer& aSettings) { RefPtr settings = aSettings.mPrintSettings.get(); if (!settings) { settings = MakeRefPtr(); } settings->InitWithInitializer(aSettings); return settings.forget(); } /** --------------------------------------------------- * See documentation in nsPrintSettingsWin.h * @update */ nsPrintSettingsWin::~nsPrintSettingsWin() { if (mDevMode) ::HeapFree(::GetProcessHeap(), 0, mDevMode); } NS_IMETHODIMP nsPrintSettingsWin::SetDeviceName(const nsAString& aDeviceName) { mDeviceName = aDeviceName; return NS_OK; } NS_IMETHODIMP nsPrintSettingsWin::GetDeviceName(nsAString& aDeviceName) { aDeviceName = mDeviceName; return NS_OK; } NS_IMETHODIMP nsPrintSettingsWin::SetDriverName(const nsAString& aDriverName) { mDriverName = aDriverName; return NS_OK; } NS_IMETHODIMP nsPrintSettingsWin::GetDriverName(nsAString& aDriverName) { aDriverName = mDriverName; return NS_OK; } void nsPrintSettingsWin::CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW*& aOutDevMode) { aOutDevMode = nullptr; size_t size = aInDevMode->dmSize + aInDevMode->dmDriverExtra; aOutDevMode = (LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size); if (aOutDevMode) { memcpy(aOutDevMode, aInDevMode, size); } } NS_IMETHODIMP nsPrintSettingsWin::GetDevMode(DEVMODEW** aDevMode) { NS_ENSURE_ARG_POINTER(aDevMode); if (mDevMode) { CopyDevMode(mDevMode, *aDevMode); } else { *aDevMode = nullptr; } return NS_OK; } NS_IMETHODIMP nsPrintSettingsWin::SetDevMode(DEVMODEW* aDevMode) { if (mDevMode) { ::HeapFree(::GetProcessHeap(), 0, mDevMode); mDevMode = nullptr; } if (aDevMode) { CopyDevMode(aDevMode, mDevMode); } return NS_OK; } void nsPrintSettingsWin::InitUnwriteableMargin(HDC aHdc) { mozilla::gfx::MarginDouble margin = mozilla::widget::WinUtils::GetUnwriteableMarginsForDeviceInInches(aHdc); mUnwriteableMargin.SizeTo(NS_INCHES_TO_INT_TWIPS(margin.top), NS_INCHES_TO_INT_TWIPS(margin.right), NS_INCHES_TO_INT_TWIPS(margin.bottom), NS_INCHES_TO_INT_TWIPS(margin.left)); } void nsPrintSettingsWin::CopyFromNative(HDC aHdc, DEVMODEW* aDevMode) { MOZ_ASSERT(aHdc); MOZ_ASSERT(aDevMode); mIsInitedFromPrinter = true; if (aDevMode->dmFields & DM_ORIENTATION) { const bool areSheetsOfPaperPortraitMode = (aDevMode->dmOrientation == DMORIENT_PORTRAIT); // If our Windows print settings say that we're producing portrait-mode // sheets of paper, then our page format must also be portrait-mode; unless // we've got a pages-per-sheet value with orthogonal pages/sheets, in which // case it's reversed. const bool arePagesPortraitMode = (areSheetsOfPaperPortraitMode != HasOrthogonalSheetsAndPages()); // Record the orientation of the pages (determined above) in mOrientation: mOrientation = int32_t(arePagesPortraitMode ? kPortraitOrientation : kLandscapeOrientation); } if (aDevMode->dmFields & DM_COPIES) { mNumCopies = aDevMode->dmCopies; } if (aDevMode->dmFields & DM_DUPLEX) { switch (aDevMode->dmDuplex) { default: MOZ_FALLTHROUGH_ASSERT("bad value for dmDuplex field"); case DMDUP_SIMPLEX: mDuplex = kDuplexNone; break; case DMDUP_VERTICAL: mDuplex = kDuplexFlipOnLongEdge; break; case DMDUP_HORIZONTAL: mDuplex = kDuplexFlipOnShortEdge; break; } } // Since we do the scaling, grab their value and reset back to 100. if (aDevMode->dmFields & DM_SCALE) { double scale = double(aDevMode->dmScale) / 100.0f; if (mScaling == 1.0 || scale != 1.0) { mScaling = scale; } aDevMode->dmScale = 100; } if (aDevMode->dmFields & DM_PAPERSIZE) { mPaperId.Truncate(0); mPaperId.AppendInt(aDevMode->dmPaperSize); // If it is not a paper size we know about, the unit will remain unchanged. PaperSizeUnitFromDmPaperSize(aDevMode->dmPaperSize, mPaperSizeUnit); } if (aDevMode->dmFields & DM_COLOR) { mPrintInColor = aDevMode->dmColor == DMCOLOR_COLOR; } InitUnwriteableMargin(aHdc); int pixelsPerInchY = ::GetDeviceCaps(aHdc, LOGPIXELSY); int physicalHeight = ::GetDeviceCaps(aHdc, PHYSICALHEIGHT); double physicalHeightInch = double(physicalHeight) / pixelsPerInchY; int pixelsPerInchX = ::GetDeviceCaps(aHdc, LOGPIXELSX); int physicalWidth = ::GetDeviceCaps(aHdc, PHYSICALWIDTH); double physicalWidthInch = double(physicalWidth) / pixelsPerInchX; // Get the paper size from the device context rather than the DEVMODE, because // it is always available. double paperHeightInch = mOrientation == kPortraitOrientation ? physicalHeightInch : physicalWidthInch; mPaperHeight = mPaperSizeUnit == kPaperSizeInches ? paperHeightInch : paperHeightInch * MM_PER_INCH_FLOAT; double paperWidthInch = mOrientation == kPortraitOrientation ? physicalWidthInch : physicalHeightInch; mPaperWidth = mPaperSizeUnit == kPaperSizeInches ? paperWidthInch : paperWidthInch * MM_PER_INCH_FLOAT; // Using LOGPIXELSY to match existing code for print scaling calculations. mResolution = pixelsPerInchY; } void nsPrintSettingsWin::CopyToNative(DEVMODEW* aDevMode) { MOZ_ASSERT(aDevMode); if (!mPaperId.IsEmpty()) { aDevMode->dmPaperSize = _wtoi((const wchar_t*)mPaperId.BeginReading()); aDevMode->dmFields |= DM_PAPERSIZE; } else { aDevMode->dmPaperSize = 0; aDevMode->dmFields &= ~DM_PAPERSIZE; } aDevMode->dmFields |= DM_COLOR; aDevMode->dmColor = mPrintInColor ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME; // The length and width in DEVMODE are always in tenths of a millimeter. double tenthsOfAmmPerSizeUnit = mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT * 10.0 : 10.0; // Note: small page sizes can be required here for sticker, label and slide // printers etc. see bug 1271900. if (mPaperHeight > 0) { aDevMode->dmPaperLength = std::round(mPaperHeight * tenthsOfAmmPerSizeUnit); aDevMode->dmFields |= DM_PAPERLENGTH; } else { aDevMode->dmPaperLength = 0; aDevMode->dmFields &= ~DM_PAPERLENGTH; } if (mPaperWidth > 0) { aDevMode->dmPaperWidth = std::round(mPaperWidth * tenthsOfAmmPerSizeUnit); aDevMode->dmFields |= DM_PAPERWIDTH; } else { aDevMode->dmPaperWidth = 0; aDevMode->dmFields &= ~DM_PAPERWIDTH; } // Setup Orientation aDevMode->dmOrientation = GetSheetOrientation() == kPortraitOrientation ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE; aDevMode->dmFields |= DM_ORIENTATION; // Setup Number of Copies aDevMode->dmCopies = mNumCopies; aDevMode->dmFields |= DM_COPIES; // Setup Simplex/Duplex mode switch (mDuplex) { case kDuplexNone: aDevMode->dmDuplex = DMDUP_SIMPLEX; aDevMode->dmFields |= DM_DUPLEX; break; case kDuplexFlipOnLongEdge: aDevMode->dmDuplex = DMDUP_VERTICAL; aDevMode->dmFields |= DM_DUPLEX; break; case kDuplexFlipOnShortEdge: aDevMode->dmDuplex = DMDUP_HORIZONTAL; aDevMode->dmFields |= DM_DUPLEX; break; default: MOZ_ASSERT_UNREACHABLE("bad value for duplex option"); break; } } //------------------------------------------- nsresult nsPrintSettingsWin::_Clone(nsIPrintSettings** _retval) { RefPtr printSettings = new nsPrintSettingsWin(*this); printSettings.forget(_retval); return NS_OK; } //------------------------------------------- nsPrintSettingsWin& nsPrintSettingsWin::operator=( const nsPrintSettingsWin& rhs) { if (this == &rhs) { return *this; } ((nsPrintSettings&)*this) = rhs; // Use free because we used the native malloc to create the memory if (mDevMode) { ::HeapFree(::GetProcessHeap(), 0, mDevMode); } mDeviceName = rhs.mDeviceName; mDriverName = rhs.mDriverName; if (rhs.mDevMode) { CopyDevMode(rhs.mDevMode, mDevMode); } else { mDevMode = nullptr; } return *this; } //------------------------------------------- nsresult nsPrintSettingsWin::_Assign(nsIPrintSettings* aPS) { nsPrintSettingsWin* psWin = static_cast(aPS); *this = *psWin; return NS_OK; }