mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
5e2a87e682
Differential Revision: https://phabricator.services.mozilla.com/D168110
522 lines
18 KiB
C++
522 lines
18 KiB
C++
/* -*- Mode: C++; tab-width: 4; 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 "nsPrinterWin.h"
|
|
|
|
#include <algorithm>
|
|
#include <windows.h>
|
|
#include <winspool.h>
|
|
|
|
#include "mozilla/Array.h"
|
|
#include "mozilla/dom/Promise.h"
|
|
#include "nsPaper.h"
|
|
#include "nsPrintSettingsImpl.h"
|
|
#include "nsPrintSettingsWin.h"
|
|
#include "nsWindowsHelpers.h"
|
|
#include "PrintBackgroundTask.h"
|
|
#include "WinUtils.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::gfx;
|
|
using namespace mozilla::widget;
|
|
using mozilla::PrintSettingsInitializer;
|
|
using mozilla::dom::Promise;
|
|
|
|
static const double kPointsPerTenthMM = 72.0 / 254.0;
|
|
static const double kPointsPerInch = 72.0;
|
|
|
|
nsPrinterWin::nsPrinterWin(const CommonPaperInfoArray* aArray,
|
|
const nsAString& aName)
|
|
: nsPrinterBase(aArray),
|
|
mName(aName),
|
|
mDefaultDevmodeWStorage("nsPrinterWin::mDefaultDevmodeWStorage") {}
|
|
|
|
// static
|
|
already_AddRefed<nsPrinterWin> nsPrinterWin::Create(
|
|
const CommonPaperInfoArray* aArray, const nsAString& aName) {
|
|
return do_AddRef(new nsPrinterWin(aArray, aName));
|
|
}
|
|
|
|
template <class T>
|
|
static nsTArray<T> GetDeviceCapabilityArray(const LPWSTR aPrinterName,
|
|
WORD aCapabilityID,
|
|
mozilla::Mutex& aDriverMutex,
|
|
int& aCount) {
|
|
MOZ_ASSERT(aCount >= 0, "Possibly passed aCount from previous error case.");
|
|
|
|
nsTArray<T> caps;
|
|
|
|
// We only want to access printer drivers in the parent process.
|
|
if (!XRE_IsParentProcess()) {
|
|
return caps;
|
|
}
|
|
|
|
// Both the call to get the size and the call to actually populate the array
|
|
// are relatively expensive, so as sometimes the lengths of the arrays that we
|
|
// retrieve depend on each other we allow a count to be passed in to save the
|
|
// first call. As we allocate double the count anyway this should allay any
|
|
// safety worries.
|
|
if (!aCount) {
|
|
// Passing nullptr as the port here seems to work. Given that we would have
|
|
// to OpenPrinter with just the name anyway to get the port that makes
|
|
// sense. Also, the printer set-up seems to stop you from having two
|
|
// printers with the same name. Note: this (and the call below) are blocking
|
|
// calls, which could be slow.
|
|
MutexAutoLock autoLock(aDriverMutex);
|
|
aCount = ::DeviceCapabilitiesW(aPrinterName, nullptr, aCapabilityID,
|
|
nullptr, nullptr);
|
|
if (aCount <= 0) {
|
|
return caps;
|
|
}
|
|
}
|
|
|
|
// As DeviceCapabilitiesW doesn't take a size, there is a greater risk of the
|
|
// buffer being overflowed, so we over-allocate for safety.
|
|
caps.SetLength(aCount * 2);
|
|
MutexAutoLock autoLock(aDriverMutex);
|
|
int count =
|
|
::DeviceCapabilitiesW(aPrinterName, nullptr, aCapabilityID,
|
|
reinterpret_cast<LPWSTR>(caps.Elements()), nullptr);
|
|
if (count <= 0) {
|
|
caps.Clear();
|
|
return caps;
|
|
}
|
|
|
|
// We know from bug 1673708 that sometimes the final array returned is smaller
|
|
// than the required array count. Assert here to see if this is reproduced on
|
|
// test servers.
|
|
MOZ_ASSERT(count == aCount, "Different array count returned than expected.");
|
|
|
|
// Note that TruncateLength will crash if count > caps.Length().
|
|
caps.TruncateLength(count);
|
|
return caps;
|
|
}
|
|
|
|
static void DevmodeToSettingsInitializer(
|
|
const nsString& aPrinterName, const DEVMODEW* aDevmode,
|
|
mozilla::Mutex& aDriverMutex,
|
|
PrintSettingsInitializer& aSettingsInitializer) {
|
|
aSettingsInitializer.mPrinter.Assign(aPrinterName);
|
|
|
|
HDC dc;
|
|
{
|
|
MutexAutoLock autoLock(aDriverMutex);
|
|
dc = ::CreateICW(nullptr, aPrinterName.get(), nullptr, aDevmode);
|
|
}
|
|
nsAutoHDC printerDc(dc);
|
|
MOZ_ASSERT(printerDc, "CreateICW failed");
|
|
if (!printerDc) {
|
|
return;
|
|
}
|
|
|
|
if (aDevmode->dmFields & DM_PAPERSIZE) {
|
|
aSettingsInitializer.mPaperInfo.mId.Truncate();
|
|
aSettingsInitializer.mPaperInfo.mId.AppendInt(aDevmode->dmPaperSize);
|
|
// If it is not a paper size we know about, the unit will remain unchanged.
|
|
nsPrintSettingsWin::PaperSizeUnitFromDmPaperSize(
|
|
aDevmode->dmPaperSize, aSettingsInitializer.mPaperSizeUnit);
|
|
}
|
|
|
|
int pixelsPerInchY = ::GetDeviceCaps(printerDc, LOGPIXELSY);
|
|
int physicalHeight = ::GetDeviceCaps(printerDc, PHYSICALHEIGHT);
|
|
double heightInInches = double(physicalHeight) / pixelsPerInchY;
|
|
int pixelsPerInchX = ::GetDeviceCaps(printerDc, LOGPIXELSX);
|
|
int physicalWidth = ::GetDeviceCaps(printerDc, PHYSICALWIDTH);
|
|
double widthInches = double(physicalWidth) / pixelsPerInchX;
|
|
if (aDevmode->dmFields & DM_ORIENTATION &&
|
|
aDevmode->dmOrientation == DMORIENT_LANDSCAPE) {
|
|
std::swap(widthInches, heightInInches);
|
|
}
|
|
aSettingsInitializer.mPaperInfo.mSize.SizeTo(widthInches * kPointsPerInch,
|
|
heightInInches * kPointsPerInch);
|
|
|
|
gfx::MarginDouble margin =
|
|
WinUtils::GetUnwriteableMarginsForDeviceInInches(printerDc);
|
|
aSettingsInitializer.mPaperInfo.mUnwriteableMargin = Some(MarginDouble{
|
|
margin.top * kPointsPerInch, margin.right * kPointsPerInch,
|
|
margin.bottom * kPointsPerInch, margin.left * kPointsPerInch});
|
|
|
|
// Using Y to match existing code for print scaling calculations.
|
|
aSettingsInitializer.mResolution = pixelsPerInchY;
|
|
|
|
if (aDevmode->dmFields & DM_COLOR) {
|
|
// See comment for PrintSettingsInitializer.mPrintInColor
|
|
aSettingsInitializer.mPrintInColor =
|
|
aDevmode->dmColor != DMCOLOR_MONOCHROME;
|
|
}
|
|
|
|
if (aDevmode->dmFields & DM_ORIENTATION) {
|
|
aSettingsInitializer.mSheetOrientation =
|
|
int32_t(aDevmode->dmOrientation == DMORIENT_PORTRAIT
|
|
? nsPrintSettings::kPortraitOrientation
|
|
: nsPrintSettings::kLandscapeOrientation);
|
|
}
|
|
|
|
if (aDevmode->dmFields & DM_COPIES) {
|
|
aSettingsInitializer.mNumCopies = aDevmode->dmCopies;
|
|
}
|
|
|
|
if (aDevmode->dmFields & DM_DUPLEX) {
|
|
switch (aDevmode->dmDuplex) {
|
|
default:
|
|
MOZ_FALLTHROUGH_ASSERT("bad value for dmDuplex field");
|
|
case DMDUP_SIMPLEX:
|
|
aSettingsInitializer.mDuplex = nsPrintSettings::kDuplexNone;
|
|
break;
|
|
case DMDUP_VERTICAL:
|
|
aSettingsInitializer.mDuplex = nsPrintSettings::kDuplexFlipOnLongEdge;
|
|
break;
|
|
case DMDUP_HORIZONTAL:
|
|
aSettingsInitializer.mDuplex = nsPrintSettings::kDuplexFlipOnShortEdge;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsPrinterWin::GetName(nsAString& aName) {
|
|
aName.Assign(mName);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsPrinterWin::GetSystemName(nsAString& aName) {
|
|
aName.Assign(mName);
|
|
return NS_OK;
|
|
}
|
|
|
|
namespace mozilla {
|
|
template <>
|
|
void ResolveOrReject(Promise& aPromise, nsPrinterWin& aPrinter,
|
|
const PrintSettingsInitializer& aResult) {
|
|
aPromise.MaybeResolve(
|
|
RefPtr<nsIPrintSettings>(CreatePlatformPrintSettings(aResult)));
|
|
}
|
|
} // namespace mozilla
|
|
|
|
NS_IMETHODIMP nsPrinterWin::CopyFromWithValidation(
|
|
nsIPrintSettings* aSettingsToCopyFrom, JSContext* aCx,
|
|
Promise** aResultPromise) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aResultPromise);
|
|
|
|
PrintSettingsInitializer settingsInitializer =
|
|
aSettingsToCopyFrom->GetSettingsInitializer();
|
|
return PrintBackgroundTaskPromise(
|
|
*this, aCx, aResultPromise, "CopyFromWithValidation"_ns,
|
|
&nsPrinterWin::GetValidatedSettings, settingsInitializer);
|
|
}
|
|
|
|
bool nsPrinterWin::SupportsDuplex() const {
|
|
MutexAutoLock autoLock(mDriverMutex);
|
|
return ::DeviceCapabilitiesW(mName.get(), nullptr, DC_DUPLEX, nullptr,
|
|
nullptr) == 1;
|
|
}
|
|
|
|
bool nsPrinterWin::SupportsColor() const {
|
|
MutexAutoLock autoLock(mDriverMutex);
|
|
return ::DeviceCapabilitiesW(mName.get(), nullptr, DC_COLORDEVICE, nullptr,
|
|
nullptr) == 1;
|
|
}
|
|
|
|
bool nsPrinterWin::SupportsMonochrome() const {
|
|
if (!SupportsColor()) {
|
|
return true;
|
|
}
|
|
|
|
nsHPRINTER hPrinter = nullptr;
|
|
if (NS_WARN_IF(!::OpenPrinterW(mName.get(), &hPrinter, nullptr))) {
|
|
return false;
|
|
}
|
|
nsAutoPrinter autoPrinter(hPrinter);
|
|
|
|
nsTArray<uint8_t> devmodeWStorage = CopyDefaultDevmodeW();
|
|
if (devmodeWStorage.IsEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
auto* devmode = reinterpret_cast<DEVMODEW*>(devmodeWStorage.Elements());
|
|
|
|
devmode->dmFields |= DM_COLOR;
|
|
devmode->dmColor = DMCOLOR_MONOCHROME;
|
|
// Try to modify the devmode settings and see if the setting sticks.
|
|
//
|
|
// This has been the only reliable way to detect it that we've found.
|
|
MutexAutoLock autoLock(mDriverMutex);
|
|
LONG ret =
|
|
::DocumentPropertiesW(nullptr, autoPrinter.get(), mName.get(), devmode,
|
|
devmode, DM_IN_BUFFER | DM_OUT_BUFFER);
|
|
if (ret != IDOK) {
|
|
return false;
|
|
}
|
|
return !(devmode->dmFields & DM_COLOR) ||
|
|
devmode->dmColor == DMCOLOR_MONOCHROME;
|
|
}
|
|
|
|
bool nsPrinterWin::SupportsCollation() const {
|
|
MutexAutoLock autoLock(mDriverMutex);
|
|
return ::DeviceCapabilitiesW(mName.get(), nullptr, DC_COLLATE, nullptr,
|
|
nullptr) == 1;
|
|
}
|
|
|
|
nsPrinterBase::PrinterInfo nsPrinterWin::CreatePrinterInfo() const {
|
|
return PrinterInfo{PaperList(), DefaultSettings()};
|
|
}
|
|
|
|
mozilla::gfx::MarginDouble nsPrinterWin::GetMarginsForPaper(
|
|
nsString aPaperId) const {
|
|
gfx::MarginDouble margin;
|
|
|
|
nsTArray<uint8_t> devmodeWStorage = CopyDefaultDevmodeW();
|
|
if (devmodeWStorage.IsEmpty()) {
|
|
return margin;
|
|
}
|
|
|
|
auto* devmode = reinterpret_cast<DEVMODEW*>(devmodeWStorage.Elements());
|
|
|
|
devmode->dmFields = DM_PAPERSIZE;
|
|
devmode->dmPaperSize = _wtoi((const wchar_t*)aPaperId.BeginReading());
|
|
HDC dc;
|
|
{
|
|
MutexAutoLock autoLock(mDriverMutex);
|
|
dc = ::CreateICW(nullptr, mName.get(), nullptr, devmode);
|
|
}
|
|
nsAutoHDC printerDc(dc);
|
|
MOZ_ASSERT(printerDc, "CreateICW failed");
|
|
if (!printerDc) {
|
|
return margin;
|
|
}
|
|
margin = WinUtils::GetUnwriteableMarginsForDeviceInInches(printerDc);
|
|
margin.top *= kPointsPerInch;
|
|
margin.right *= kPointsPerInch;
|
|
margin.bottom *= kPointsPerInch;
|
|
margin.left *= kPointsPerInch;
|
|
|
|
return margin;
|
|
}
|
|
|
|
nsTArray<uint8_t> nsPrinterWin::CopyDefaultDevmodeW() const {
|
|
nsTArray<uint8_t> devmodeStorageW;
|
|
|
|
auto devmodeStorageWLock = mDefaultDevmodeWStorage.Lock();
|
|
if (devmodeStorageWLock->IsEmpty()) {
|
|
nsHPRINTER hPrinter = nullptr;
|
|
// OpenPrinter could fail if, for example, the printer has been removed
|
|
// or otherwise become inaccessible since it was selected.
|
|
if (NS_WARN_IF(!::OpenPrinterW(mName.get(), &hPrinter, nullptr))) {
|
|
return devmodeStorageW;
|
|
}
|
|
nsAutoPrinter autoPrinter(hPrinter);
|
|
// Allocate devmode storage of the correct size.
|
|
MutexAutoLock autoLock(mDriverMutex);
|
|
LONG bytesNeeded = ::DocumentPropertiesW(nullptr, autoPrinter.get(),
|
|
mName.get(), nullptr, nullptr, 0);
|
|
// Note that we must cast the sizeof() to a signed type so that comparison
|
|
// with the signed, potentially-negative bytesNeeded will work!
|
|
MOZ_ASSERT(bytesNeeded >= LONG(sizeof(DEVMODEW)),
|
|
"DocumentPropertiesW failed to get valid size");
|
|
if (bytesNeeded < LONG(sizeof(DEVMODEW))) {
|
|
return devmodeStorageW;
|
|
}
|
|
|
|
// Allocate extra space in case of bad drivers that return a too-small
|
|
// result from DocumentProperties.
|
|
// (See https://bugzilla.mozilla.org/show_bug.cgi?id=1664530#c5)
|
|
if (!devmodeStorageWLock->SetLength(bytesNeeded * 2, fallible)) {
|
|
return devmodeStorageW;
|
|
}
|
|
|
|
memset(devmodeStorageWLock->Elements(), 0, devmodeStorageWLock->Length());
|
|
auto* devmode =
|
|
reinterpret_cast<DEVMODEW*>(devmodeStorageWLock->Elements());
|
|
LONG ret = ::DocumentPropertiesW(nullptr, autoPrinter.get(), mName.get(),
|
|
devmode, nullptr, DM_OUT_BUFFER);
|
|
MOZ_ASSERT(ret == IDOK, "DocumentPropertiesW failed");
|
|
// Make sure that the lengths in the DEVMODEW make sense.
|
|
if (ret != IDOK || devmode->dmSize != sizeof(DEVMODEW) ||
|
|
devmode->dmSize + devmode->dmDriverExtra >
|
|
devmodeStorageWLock->Length()) {
|
|
// Clear mDefaultDevmodeWStorage to make sure we try again next time.
|
|
devmodeStorageWLock->Clear();
|
|
return devmodeStorageW;
|
|
}
|
|
}
|
|
|
|
devmodeStorageW.Assign(devmodeStorageWLock.ref());
|
|
return devmodeStorageW;
|
|
}
|
|
|
|
nsTArray<mozilla::PaperInfo> nsPrinterWin::PaperList() const {
|
|
// Paper IDs are returned as WORDs.
|
|
int requiredArrayCount = 0;
|
|
auto paperIds = GetDeviceCapabilityArray<WORD>(
|
|
mName.get(), DC_PAPERS, mDriverMutex, requiredArrayCount);
|
|
if (!paperIds.Length()) {
|
|
return {};
|
|
}
|
|
|
|
// Paper names are returned in 64 long character buffers.
|
|
auto paperNames = GetDeviceCapabilityArray<Array<wchar_t, 64>>(
|
|
mName.get(), DC_PAPERNAMES, mDriverMutex, requiredArrayCount);
|
|
// Check that we have the same number of names as IDs.
|
|
if (paperNames.Length() != paperIds.Length()) {
|
|
return {};
|
|
}
|
|
|
|
// Paper sizes are returned as POINT structs with a tenth of a millimeter as
|
|
// the unit.
|
|
auto paperSizes = GetDeviceCapabilityArray<POINT>(
|
|
mName.get(), DC_PAPERSIZE, mDriverMutex, requiredArrayCount);
|
|
// Check that we have the same number of sizes as IDs.
|
|
if (paperSizes.Length() != paperIds.Length()) {
|
|
return {};
|
|
}
|
|
|
|
nsTArray<mozilla::PaperInfo> paperList;
|
|
paperList.SetCapacity(paperNames.Length());
|
|
for (size_t i = 0; i < paperNames.Length(); ++i) {
|
|
// Paper names are null terminated unless they are 64 characters long.
|
|
auto firstNull =
|
|
std::find(paperNames[i].cbegin(), paperNames[i].cend(), L'\0');
|
|
auto nameLength = firstNull - paperNames[i].cbegin();
|
|
double width = paperSizes[i].x * kPointsPerTenthMM;
|
|
double height = paperSizes[i].y * kPointsPerTenthMM;
|
|
|
|
// Skip if no name or invalid size.
|
|
if (!nameLength || width <= 0 || height <= 0) {
|
|
continue;
|
|
}
|
|
|
|
// Windows paper IDs are 16-bit integers; we stringify them to store in the
|
|
// PaperInfo.mId field.
|
|
nsString paperIdString;
|
|
paperIdString.AppendInt(paperIds[i]);
|
|
|
|
// We don't resolve the margins eagerly because they're really expensive (on
|
|
// the order of seconds for some drivers).
|
|
nsDependentSubstring name(paperNames[i].cbegin(), nameLength);
|
|
paperList.AppendElement(mozilla::PaperInfo(paperIdString, nsString(name),
|
|
{width, height}, Nothing()));
|
|
}
|
|
|
|
return paperList;
|
|
}
|
|
|
|
PrintSettingsInitializer nsPrinterWin::DefaultSettings() const {
|
|
nsTArray<uint8_t> devmodeWStorage = CopyDefaultDevmodeW();
|
|
if (devmodeWStorage.IsEmpty()) {
|
|
return {};
|
|
}
|
|
|
|
const auto* devmode =
|
|
reinterpret_cast<const DEVMODEW*>(devmodeWStorage.Elements());
|
|
|
|
PrintSettingsInitializer settingsInitializer;
|
|
DevmodeToSettingsInitializer(mName, devmode, mDriverMutex,
|
|
settingsInitializer);
|
|
settingsInitializer.mDevmodeWStorage = std::move(devmodeWStorage);
|
|
return settingsInitializer;
|
|
}
|
|
|
|
PrintSettingsInitializer nsPrinterWin::GetValidatedSettings(
|
|
PrintSettingsInitializer aSettingsToValidate) const {
|
|
// This function validates the settings by relying on the printer driver
|
|
// rejecting any invalid settings and resetting them to valid values.
|
|
|
|
// Create a copy of the default DEVMODE for this printer.
|
|
nsTArray<uint8_t> devmodeWStorage = CopyDefaultDevmodeW();
|
|
if (devmodeWStorage.IsEmpty()) {
|
|
return aSettingsToValidate;
|
|
}
|
|
|
|
nsHPRINTER hPrinter = nullptr;
|
|
if (NS_WARN_IF(!::OpenPrinterW(mName.get(), &hPrinter, nullptr))) {
|
|
return aSettingsToValidate;
|
|
}
|
|
nsAutoPrinter autoPrinter(hPrinter);
|
|
|
|
// Copy the settings from aSettingsToValidate into our DEVMODE.
|
|
DEVMODEW* devmode = reinterpret_cast<DEVMODEW*>(devmodeWStorage.Elements());
|
|
if (!aSettingsToValidate.mPaperInfo.mId.IsEmpty()) {
|
|
devmode->dmPaperSize = _wtoi(
|
|
(const wchar_t*)aSettingsToValidate.mPaperInfo.mId.BeginReading());
|
|
devmode->dmFields |= DM_PAPERSIZE;
|
|
} else {
|
|
devmode->dmPaperSize = 0;
|
|
devmode->dmFields &= ~DM_PAPERSIZE;
|
|
}
|
|
|
|
devmode->dmFields |= DM_COLOR;
|
|
devmode->dmColor =
|
|
aSettingsToValidate.mPrintInColor ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
|
|
|
|
// Note: small page sizes can be required here for sticker, label and slide
|
|
// printers etc. see bug 1271900.
|
|
if (aSettingsToValidate.mPaperInfo.mSize.height > 0) {
|
|
devmode->dmPaperLength = std::round(
|
|
aSettingsToValidate.mPaperInfo.mSize.height / kPointsPerTenthMM);
|
|
devmode->dmFields |= DM_PAPERLENGTH;
|
|
} else {
|
|
devmode->dmPaperLength = 0;
|
|
devmode->dmFields &= ~DM_PAPERLENGTH;
|
|
}
|
|
|
|
if (aSettingsToValidate.mPaperInfo.mSize.width > 0) {
|
|
devmode->dmPaperWidth = std::round(
|
|
aSettingsToValidate.mPaperInfo.mSize.width / kPointsPerTenthMM);
|
|
devmode->dmFields |= DM_PAPERWIDTH;
|
|
} else {
|
|
devmode->dmPaperWidth = 0;
|
|
devmode->dmFields &= ~DM_PAPERWIDTH;
|
|
}
|
|
|
|
// Setup Orientation
|
|
devmode->dmOrientation = aSettingsToValidate.mSheetOrientation ==
|
|
nsPrintSettings::kPortraitOrientation
|
|
? DMORIENT_PORTRAIT
|
|
: DMORIENT_LANDSCAPE;
|
|
devmode->dmFields |= DM_ORIENTATION;
|
|
|
|
// Setup Number of Copies
|
|
devmode->dmCopies = aSettingsToValidate.mNumCopies;
|
|
devmode->dmFields |= DM_COPIES;
|
|
|
|
// Setup Simplex/Duplex mode
|
|
devmode->dmFields |= DM_DUPLEX;
|
|
switch (aSettingsToValidate.mDuplex) {
|
|
case nsPrintSettings::kDuplexNone:
|
|
devmode->dmDuplex = DMDUP_SIMPLEX;
|
|
break;
|
|
case nsPrintSettings::kDuplexFlipOnLongEdge:
|
|
devmode->dmDuplex = DMDUP_VERTICAL;
|
|
break;
|
|
case nsPrintSettings::kDuplexFlipOnShortEdge:
|
|
devmode->dmDuplex = DMDUP_HORIZONTAL;
|
|
break;
|
|
default:
|
|
MOZ_ASSERT_UNREACHABLE("bad value for duplex option");
|
|
break;
|
|
}
|
|
|
|
// Apply the settings in the DEVMODE to the printer and retrieve the updated
|
|
// DEVMODE back into the same structure.
|
|
LONG ret;
|
|
{
|
|
MutexAutoLock autoLock(mDriverMutex);
|
|
ret = ::DocumentPropertiesW(nullptr, autoPrinter.get(), mName.get(),
|
|
devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER);
|
|
}
|
|
if (ret != IDOK) {
|
|
return aSettingsToValidate;
|
|
}
|
|
|
|
// Copy the settings back from the DEVMODE into aSettingsToValidate and
|
|
// return.
|
|
DevmodeToSettingsInitializer(mName, devmode, mDriverMutex,
|
|
aSettingsToValidate);
|
|
aSettingsToValidate.mDevmodeWStorage = std::move(devmodeWStorage);
|
|
return aSettingsToValidate;
|
|
}
|