/* -*- 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/. */
usingnamespace mozilla; usingnamespace mozilla::gfx; usingnamespace mozilla::widget; using mozilla::PrintSettingsInitializer; using mozilla::dom::Promise;
// 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;
}
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);
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) { returnfalse;
} return !(devmode->dmFields & DM_COLOR) ||
devmode->dmColor == DMCOLOR_MONOCHROME;
}
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;
}
}
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()));
}
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;
}
// 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;
}
// 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;
}
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.