diff --git a/layout/base/tests/chrome/test_printer_default_settings.html b/layout/base/tests/chrome/test_printer_default_settings.html index 89e644577977..8fa6ed27b041 100644 --- a/layout/base/tests/chrome/test_printer_default_settings.html +++ b/layout/base/tests/chrome/test_printer_default_settings.html @@ -26,6 +26,7 @@ async function run() { settings.QueryInterface(Ci.nsIPrintSettings); is(typeof settings.printerName, "string", "Printer name should be a string."); + is(settings.printerName, printer.name, "Print settings' printer should match the printer that created them."); console.log(typeof settings.paperWidth); is(typeof settings.paperName, "string", "Paper name should never be null."); @@ -44,6 +45,8 @@ async function run() { ok(settings.marginBottom >= 0.0, "Paper margins should be greater than or equal to zero."); ok(settings.marginLeft >= 0.0, "Paper margins should be greater than or equal to zero."); + is(settings.printInColor, await printer.supportsColor, "Print settings' color mode should match the printer's color support."); + ok(settings.isInitializedFromPrinter, "Print settings were initialized from printer"); ok(!settings.isInitializedFromPrefs); } diff --git a/widget/nsPrintSettingsImpl.cpp b/widget/nsPrintSettingsImpl.cpp index 174368a03ded..fc4675f01d64 100644 --- a/widget/nsPrintSettingsImpl.cpp +++ b/widget/nsPrintSettingsImpl.cpp @@ -66,6 +66,7 @@ void nsPrintSettings::InitWithInitializer( SetPrinterName(aSettings.mPrinter); SetPrintInColor(aSettings.mPrintInColor); + SetResolution(aSettings.mResolution); SetPaperName(aSettings.mPaperInfo.mName); SetPaperWidth(aSettings.mPaperInfo.mSize.Width() * kInchesPerPoint); SetPaperHeight(aSettings.mPaperInfo.mSize.Height() * kInchesPerPoint); diff --git a/widget/nsPrintSettingsImpl.h b/widget/nsPrintSettingsImpl.h index a296a9b0c786..4248cdbc0ea3 100644 --- a/widget/nsPrintSettingsImpl.h +++ b/widget/nsPrintSettingsImpl.h @@ -29,6 +29,10 @@ struct PrintSettingsInitializer { nsString mPrinter; PaperInfo mPaperInfo; bool mPrintInColor = false; + int mResolution = 0; +#ifdef XP_WIN + nsTArray mDevmodeWStorage; +#endif }; } // namespace mozilla @@ -47,7 +51,7 @@ class nsPrintSettings : public nsIPrintSettings { * This is specifically not a constructor so that we can ensure that the * relevant setters are dynamically dispatched to derived classes. */ - void InitWithInitializer(const PrintSettingsInitializer& aSettings); + virtual void InitWithInitializer(const PrintSettingsInitializer& aSettings); nsPrintSettings& operator=(const nsPrintSettings& rhs); diff --git a/widget/windows/nsPrintSettingsWin.cpp b/widget/windows/nsPrintSettingsWin.cpp index 4095e50211f3..16687c3500ec 100644 --- a/widget/windows/nsPrintSettingsWin.cpp +++ b/widget/windows/nsPrintSettingsWin.cpp @@ -7,8 +7,11 @@ #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. @@ -160,37 +163,76 @@ nsPrintSettingsWin::nsPrintSettingsWin(const nsPrintSettingsWin& aPS) *this = aPS; } +void nsPrintSettingsWin::InitWithInitializer( + const PrintSettingsInitializer& aSettings) { + nsPrintSettings::InitWithInitializer(aSettings); + + if (aSettings.mDevmodeWStorage.Length() < sizeof(DEVMODEW)) { + MOZ_DIAGNOSTIC_ASSERT(false, "Why did nsPrinterWin::DefaultSettings fail?"); + return; + } + + const DEVMODEW* devmode = + reinterpret_cast(aSettings.mDevmodeWStorage.Elements()); + + if (devmode->dmFields & DM_ORIENTATION) { + SetOrientation(devmode->dmOrientation == DMORIENT_PORTRAIT + ? kPortraitOrientation + : kLandscapeOrientation); + } + + if (devmode->dmFields & DM_COPIES) { + SetNumCopies(devmode->dmCopies); + } + + if (devmode->dmFields & DM_SCALE) { + double scale = double(devmode->dmScale) / 100.0f; + if (mScaling == 1.0 || scale != 1.0) { + SetScaling(scale); + } + } + + if (devmode->dmFields & DM_PAPERSIZE) { + SetPaperData(devmode->dmPaperSize); + if (devmode->dmPaperSize > 0 && + devmode->dmPaperSize < int32_t(mozilla::ArrayLength(kPaperSizeUnits))) { + SetPaperSizeUnit(kPaperSizeUnits[mPaperData]); + } + } else { + SetPaperData(-1); + } + + // Set the paper sizes to match the unit. + double pointsToSizeUnit = + mPaperSizeUnit == kPaperSizeInches ? 1.0 / 72.0 : 25.4 / 72.0; + SetPaperWidth(aSettings.mPaperInfo.mSize.width * pointsToSizeUnit); + SetPaperHeight(aSettings.mPaperInfo.mSize.height * pointsToSizeUnit); + + double printableWidthInPoints = aSettings.mPaperInfo.mSize.width; + double printableHeightInPoints = aSettings.mPaperInfo.mSize.height; + if (aSettings.mPaperInfo.mUnwriteableMargin.isSome()) { + const auto& margin = aSettings.mPaperInfo.mUnwriteableMargin.value(); + printableWidthInPoints -= (margin.top + margin.bottom); + printableHeightInPoints -= (margin.left + margin.right); + } + + // Keep these values in portrait format, so we can reflect our own changes + // to mOrientation. + if (mOrientation == kPortraitOrientation) { + mPrintableWidthInInches = printableWidthInPoints / POINTS_PER_INCH_FLOAT; + mPrintableHeightInInches = printableHeightInPoints / POINTS_PER_INCH_FLOAT; + } else { + mPrintableHeightInInches = printableWidthInPoints / POINTS_PER_INCH_FLOAT; + mPrintableWidthInInches = printableHeightInPoints / POINTS_PER_INCH_FLOAT; + } + + SetDevMode(const_cast(devmode)); // copies devmode +} + already_AddRefed CreatePlatformPrintSettings( const PrintSettingsInitializer& aSettings) { auto settings = MakeRefPtr(); settings->InitWithInitializer(aSettings); - - // When printing to PDF on Windows there is no associated printer driver. - int16_t outputFormat; - settings->GetOutputFormat(&outputFormat); - if (outputFormat == nsIPrintSettings::kOutputFormatPDF) { - return settings.forget(); - } - - RefPtr devSpecWin = new nsDeviceContextSpecWin(); - - nsString name; - settings->GetPrinterName(name); - devSpecWin->GetDataFromPrinter(name); - - LPDEVMODEW devmode; - devSpecWin->GetDevMode(devmode); - if (NS_WARN_IF(!devmode)) { - return settings.forget(); - } - - // TODO(nordzilla, 1658299) - // We need to get information from the device as well. - // See InitPrintSettingsFromPrinter call to CreateICW and the code - // below it. The issue is that we can't do it here. It needs to - // happen async, off the main thread, similar to the code that - // populates the PrintSettingsInitializer argument. - return settings.forget(); } diff --git a/widget/windows/nsPrintSettingsWin.h b/widget/windows/nsPrintSettingsWin.h index eed35e38da8e..a36d826e3b40 100644 --- a/widget/windows/nsPrintSettingsWin.h +++ b/widget/windows/nsPrintSettingsWin.h @@ -23,7 +23,8 @@ class nsPrintSettingsWin : public nsPrintSettings, public nsIPrintSettingsWin { nsPrintSettingsWin(); nsPrintSettingsWin(const nsPrintSettingsWin& aPS); - explicit nsPrintSettingsWin(const PrintSettingsInitializer&); + + void InitWithInitializer(const PrintSettingsInitializer& aSettings) final; /** * Makes a new copy diff --git a/widget/windows/nsPrinterWin.cpp b/widget/windows/nsPrinterWin.cpp index 6d4a02a0ccc0..9c24e5cd5472 100644 --- a/widget/windows/nsPrinterWin.cpp +++ b/widget/windows/nsPrinterWin.cpp @@ -7,15 +7,19 @@ #include #include +#include #include "mozilla/Array.h" #include "nsPaper.h" +#include "nsPrintSettingsImpl.h" +#include "nsWindowsHelpers.h" +#include "WinUtils.h" using namespace mozilla; using namespace mozilla::gfx; +using namespace mozilla::widget; -static const float kTenthMMToPoint = - (POINTS_PER_INCH_FLOAT / MM_PER_INCH_FLOAT) / 10; +static const double kTenthMMToPoint = 72.0 / 254.0; nsPrinterWin::nsPrinterWin(const nsAString& aName) : mName(aName) {} @@ -24,12 +28,57 @@ already_AddRefed nsPrinterWin::Create(const nsAString& aName) { return do_AddRef(new nsPrinterWin(aName)); } -// TODO(nordzilla, 165829) This needs to be implemented for windows. -// It should basically collect the same information as -// nsPrinterListWin::InitPrintSettingsFromPrinter. PrintSettingsInitializer nsPrinterWin::DefaultSettings() const { - PrintSettingsInitializer settings; - return settings; + nsAutoPrinter autoPrinter(nsHPRINTER(nullptr)); + BOOL status = ::OpenPrinterW(mName.get(), &autoPrinter.get(), nullptr); + if (NS_WARN_IF(!status)) { + return PrintSettingsInitializer(); + } + + // Allocate devmode storage of the correct size. + LONG bytesNeeded = ::DocumentPropertiesW(nullptr, autoPrinter.get(), + mName.get(), nullptr, nullptr, 0); + if (NS_WARN_IF(bytesNeeded < 0)) { + return PrintSettingsInitializer(); + } + + nsTArray devmodeWStorage(bytesNeeded); + devmodeWStorage.SetLength(bytesNeeded); + DEVMODEW* devmode = reinterpret_cast(devmodeWStorage.Elements()); + LONG ret = ::DocumentPropertiesW(nullptr, autoPrinter.get(), mName.get(), + devmode, nullptr, DM_OUT_BUFFER); + if (NS_WARN_IF(ret != IDOK)) { + return PrintSettingsInitializer(); + } + + nsAutoHDC printerDc(::CreateICW(nullptr, mName.get(), nullptr, devmode)); + if (NS_WARN_IF(!printerDc)) { + return PrintSettingsInitializer(); + } + + nsString paperName; + SizeDouble paperSize; + for (auto paperInfo : PaperList()) { + if (paperInfo.mPaperId == devmode->dmPaperSize) { + paperName.Assign(paperInfo.mName); + paperSize = paperInfo.mSize; + break; + } + } + + auto margin = WinUtils::GetUnwriteableMarginsForDeviceInInches(printerDc); + margin.top *= POINTS_PER_INCH_FLOAT; + margin.right *= POINTS_PER_INCH_FLOAT; + margin.bottom *= POINTS_PER_INCH_FLOAT; + margin.left *= POINTS_PER_INCH_FLOAT; + + // Using Y to match existing code for print scaling calculations. + int resolution = GetDeviceCaps(printerDc, LOGPIXELSY); + + return PrintSettingsInitializer{mName, + PaperInfo(paperName, paperSize, Some(margin)), + devmode->dmColor == DMCOLOR_COLOR, resolution, + std::move(devmodeWStorage)}; } template