Bug 1655558 - Retrieve paper information from CUPS, and convert paperList to an async attribute. r=jwatt

This builds on top of bug 1656146 to compute the page information on a
background task, and return it via a promise.

Co-Authored-By: Erik Nordin <enordin@mozilla.com>

Differential Revision: https://phabricator.services.mozilla.com/D85865
This commit is contained in:
Emilio Cobos Álvarez 2020-08-05 01:24:49 +00:00
parent ba8d99b8aa
commit 6d5ce8f732
19 changed files with 228 additions and 310 deletions

View File

@ -8,7 +8,7 @@
SimpleTest.waitForExplicitFinish();
function run() {
async function run() {
try {
let printerList = Cc["@mozilla.org/gfx/printerlist;1"].getService(
Ci.nsIPrinterList
@ -16,10 +16,17 @@ function run() {
if (printerList.printers.length == 0) {
ok(true, "There were no printers to iterate through.");
}
printerList.printers.forEach(printer => {
for (let printer of printerList.printers) {
isnot(printer.name, null, "Printer name should never be null.");
isnot(printer.name, "", "Printer name should never be empty.");
printer.paperList.forEach(paper => {
info(printer.name);
let paperList = await printer.paperList;
for (let paper of paperList) {
paper.QueryInterface(Ci.nsIPaper);
info(`${paper.name}: ${paper.width}x${paper.height} with margin: ${paper.unwriteableMarginTop} ${paper.unwriteableMarginRight} ${paper.unwriteableMarginBottom} ${paper.unwriteableMarginLeft}`);
isnot(paper.name, null, "Paper name should never be null.");
isnot(paper.name, "", "Paper name should never be empty.");
@ -28,8 +35,20 @@ function run() {
isnot(paper.height, null, "Paper height should never be null.");
ok(paper.height > 0.0, "Paper height should be greater than zero.");
});
})
isnot(paper.unwriteableMarginTop, null, "Paper unwriteableMarginTop should never be null.");
ok(paper.unwriteableMarginTop >= 0.0, "Paper unwriteableMarginTop should be greater than or equal to zero.");
isnot(paper.unwriteableMarginBottom, null, "Paper unwriteableMarginBottom should never be null.");
ok(paper.unwriteableMarginBottom >= 0.0, "Paper unwriteableMarginBottom should be greater than or equal to zero.");
isnot(paper.unwriteableMarginLeft, null, "Paper unwriteableMarginLeft should never be null.");
ok(paper.unwriteableMarginLeft >= 0.0, "Paper unwriteableMarginLeft should be greater than or equal to zero.");
isnot(paper.unwriteableMarginRight, null, "Paper unwriteableMarginRight should never be null.");
ok(paper.unwriteableMarginRight >= 0.0, "Paper unwriteableMarginRight should be greater than or equal to zero.");
}
}
} catch (e) {
Cu.reportError(e);
}

View File

@ -47,71 +47,14 @@ static LazyLogModule sDeviceContextSpecXLog("DeviceContextSpecX");
static nsCUPSShim sCupsShim;
/**
* Retrieves the list of available paper options for a given printer name.
*/
static nsresult FillPaperListForPrinter(PMPrinter aPrinter,
nsTArray<RefPtr<nsIPaper>>& aPaperList) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
CFArrayRef pmPaperList;
aPaperList.ClearAndRetainStorage();
OSStatus status = PMPrinterGetPaperList(aPrinter, &pmPaperList);
if (status != noErr || !pmPaperList) {
return NS_ERROR_UNEXPECTED;
}
CFIndex paperCount = CFArrayGetCount(pmPaperList);
aPaperList.SetCapacity(paperCount);
for (auto i = 0; i < paperCount; ++i) {
PMPaper pmPaper =
static_cast<PMPaper>(const_cast<void*>(CFArrayGetValueAtIndex(pmPaperList, i)));
// The units for width and height are points.
double width = 0.0;
double height = 0.0;
AutoCFRelease<CFStringRef> pmPaperName(nullptr);
if (PMPaperGetWidth(pmPaper, &width) != noErr || PMPaperGetHeight(pmPaper, &height) != noErr ||
PMPaperCreateLocalizedName(pmPaper, aPrinter, pmPaperName.receive()) != noErr) {
return NS_ERROR_UNEXPECTED;
}
nsAutoString name;
nsCocoaUtils::GetStringForNSString(static_cast<NSString*>(CFStringRef(pmPaperName)), name);
PMPaperMargins unwriteableMargins;
if (PMPaperGetMargins(pmPaper, &unwriteableMargins) != noErr) {
// If we can't get unwriteable margins, just default to none.
unwriteableMargins.top = 0.0;
unwriteableMargins.bottom = 0.0;
unwriteableMargins.left = 0.0;
unwriteableMargins.right = 0.0;
}
aPaperList.AppendElement(new nsPaper(name, width, height, unwriteableMargins.top,
unwriteableMargins.bottom, unwriteableMargins.left,
unwriteableMargins.right));
}
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
static nsresult CreatePrinter(mozilla::CUPSPrinterList& aCupsPrinterList, PMPrinter aPMPrinter,
nsIPrinter** aPrinter) {
NS_ENSURE_ARG_POINTER(aPrinter);
*aPrinter = nullptr;
nsTArray<RefPtr<nsIPaper>> paperList;
nsresult rv = FillPaperListForPrinter(aPMPrinter, paperList);
NS_ENSURE_SUCCESS(rv, rv);
NSString* const printerID = static_cast<NSString*>(PMPrinterGetID(aPMPrinter));
if (cups_dest_t* const dest = aCupsPrinterList.FindPrinterByName([printerID UTF8String])) {
if (RefPtr<nsPrinterCUPS> printer =
nsPrinterCUPS::Create(sCupsShim, dest, std::move(paperList))) {
if (RefPtr<nsPrinterCUPS> printer = nsPrinterCUPS::Create(sCupsShim, dest)) {
printer.forget(aPrinter);
return NS_OK;
}

View File

@ -236,16 +236,12 @@ if CONFIG['MOZ_XUL'] and CONFIG['NS_PRINTING']:
]
UNIFIED_SOURCES += [
'nsDeviceContextSpecProxy.cpp',
'nsPaper.cpp',
'nsPrinterBase.cpp',
'nsPrintSession.cpp',
'nsPrintSettingsService.cpp',
]
# The Windows sub-directory has its own implemenation of these.
if toolkit != 'windows':
UNIFIED_SOURCES += [
'nsPaper.cpp',
]
# These will be unified for all CUPS platforms by Bug 1654678
if toolkit == 'cocoa':
UNIFIED_SOURCES += [
@ -253,6 +249,7 @@ if CONFIG['MOZ_XUL'] and CONFIG['NS_PRINTING']:
'nsCUPSShim.cpp',
'nsPrinterCUPS.cpp',
]
if toolkit == 'gtk':
UNIFIED_SOURCES += [
'nsCUPSShim.cpp',

View File

@ -49,14 +49,19 @@ bool nsCUPSShim::Init() {
if (!(CUPS_SHIM_LOAD(mCupsAddOption, cupsAddOption) &&
CUPS_SHIM_LOAD(mCupsCheckDestSupported, cupsCheckDestSupported) &&
CUPS_SHIM_LOAD(mCupsConnectDest, cupsConnectDest) &&
CUPS_SHIM_LOAD(mCupsCopyDest, cupsCopyDest) &&
CUPS_SHIM_LOAD(mCupsCopyDestInfo, cupsCopyDestInfo) &&
CUPS_SHIM_LOAD(mCupsFreeDestInfo, cupsFreeDestInfo) &&
CUPS_SHIM_LOAD(mCupsFreeDests, cupsFreeDests) &&
CUPS_SHIM_LOAD(mCupsGetDestMediaCount, cupsGetDestMediaCount) &&
CUPS_SHIM_LOAD(mCupsGetDestMediaByIndex, cupsGetDestMediaByIndex) &&
CUPS_SHIM_LOAD(mCupsGetDest, cupsGetDest) &&
CUPS_SHIM_LOAD(mCupsGetDests, cupsGetDests) &&
CUPS_SHIM_LOAD(mCupsLocalizeDestMedia, cupsLocalizeDestMedia) &&
CUPS_SHIM_LOAD(mCupsPrintFile, cupsPrintFile) &&
CUPS_SHIM_LOAD(mCupsTempFd, cupsTempFd))) {
CUPS_SHIM_LOAD(mCupsTempFd, cupsTempFd) &&
CUPS_SHIM_LOAD(mHttpClose, httpClose))) {
#ifndef MOZ_TSAN
// With TSan, we cannot unload libcups once we have loaded it because
// TSan does not support unloading libraries that are matched from its

View File

@ -35,14 +35,19 @@ class nsCUPSShim {
*/
decltype(cupsAddOption)* mCupsAddOption;
decltype(cupsCheckDestSupported)* mCupsCheckDestSupported;
decltype(cupsConnectDest)* mCupsConnectDest;
decltype(cupsCopyDest)* mCupsCopyDest;
decltype(cupsCopyDestInfo)* mCupsCopyDestInfo;
decltype(cupsFreeDestInfo)* mCupsFreeDestInfo;
decltype(cupsFreeDests)* mCupsFreeDests;
decltype(cupsGetDestMediaCount)* mCupsGetDestMediaCount;
decltype(cupsGetDestMediaByIndex)* mCupsGetDestMediaByIndex;
decltype(cupsGetDest)* mCupsGetDest;
decltype(cupsGetDests)* mCupsGetDests;
decltype(cupsLocalizeDestMedia)* mCupsLocalizeDestMedia;
decltype(cupsPrintFile)* mCupsPrintFile;
decltype(cupsTempFd)* mCupsTempFd;
decltype(httpClose)* mHttpClose;
private:
bool mInited = false;

View File

@ -15,9 +15,12 @@ interface nsIPrinter : nsISupports
readonly attribute AString name;
/**
* The list of available paper sizes.
* Returns a Promise that resolves to an array of
* nsIPaper instances with the list of available paper
* sizes.
*/
readonly attribute Array<nsIPaper> paperList;
[implicit_jscontext]
readonly attribute Promise paperList;
/**
* Returns a Promise that resolves to true or false to indicate whether this

View File

@ -9,48 +9,48 @@ NS_IMPL_ISUPPORTS(nsPaper, nsIPaper);
NS_IMETHODIMP
nsPaper::GetName(nsAString& aName) {
aName = mName;
aName = mInfo.mName;
return NS_OK;
}
NS_IMETHODIMP
nsPaper::GetWidth(double* aWidth) {
NS_ENSURE_ARG_POINTER(aWidth);
*aWidth = mWidth;
*aWidth = mInfo.mWidth;
return NS_OK;
}
NS_IMETHODIMP
nsPaper::GetHeight(double* aHeight) {
NS_ENSURE_ARG_POINTER(aHeight);
*aHeight = mHeight;
*aHeight = mInfo.mHeight;
return NS_OK;
}
NS_IMETHODIMP
nsPaper::GetUnwriteableMarginTop(double* aUnwriteableMarginTop) {
NS_ENSURE_ARG_POINTER(aUnwriteableMarginTop);
*aUnwriteableMarginTop = mUnwriteableMarginTop;
*aUnwriteableMarginTop = mInfo.mUnwriteableMarginTop;
return NS_OK;
}
NS_IMETHODIMP
nsPaper::GetUnwriteableMarginBottom(double* aUnwriteableMarginBottom) {
NS_ENSURE_ARG_POINTER(aUnwriteableMarginBottom);
*aUnwriteableMarginBottom = mUnwriteableMarginBottom;
*aUnwriteableMarginBottom = mInfo.mUnwriteableMarginBottom;
return NS_OK;
}
NS_IMETHODIMP
nsPaper::GetUnwriteableMarginLeft(double* aUnwriteableMarginLeft) {
NS_ENSURE_ARG_POINTER(aUnwriteableMarginLeft);
*aUnwriteableMarginLeft = mUnwriteableMarginLeft;
*aUnwriteableMarginLeft = mInfo.mUnwriteableMarginLeft;
return NS_OK;
}
NS_IMETHODIMP
nsPaper::GetUnwriteableMarginRight(double* aUnwriteableMarginRight) {
NS_ENSURE_ARG_POINTER(aUnwriteableMarginRight);
*aUnwriteableMarginRight = mUnwriteableMarginRight;
*aUnwriteableMarginRight = mInfo.mUnwriteableMarginRight;
return NS_OK;
}

View File

@ -6,36 +6,53 @@
#ifndef nsPaper_h__
#define nsPaper_h__
#include "mozilla/dom/ToJSValue.h"
#include "js/TypeDecls.h"
#include "nsIPaper.h"
#include "nsISupportsImpl.h"
#include "js/RootingAPI.h"
#include "nsString.h"
namespace mozilla {
// Simple struct that can be used off the main thread to hold all the info from
// an nsPaper instance.
struct PaperInfo {
const nsString mName;
const double mWidth;
const double mHeight;
const double mUnwriteableMarginTop;
const double mUnwriteableMarginRight;
const double mUnwriteableMarginBottom;
const double mUnwriteableMarginLeft;
};
} // namespace mozilla
class nsPaper final : public nsIPaper {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPAPER
nsPaper() = delete;
nsPaper(nsAString& aName, double aWidth, double aHeight,
double aUnwriteableMarginTop, double aUnwriteableMarginBottom,
double aUnwriteableMarginLeft, double aUnwriteableMarginRight)
: mName(aName),
mWidth(aWidth),
mHeight(aHeight),
mUnwriteableMarginTop(aUnwriteableMarginTop),
mUnwriteableMarginBottom(aUnwriteableMarginBottom),
mUnwriteableMarginLeft(aUnwriteableMarginLeft),
mUnwriteableMarginRight(aUnwriteableMarginRight) {}
explicit nsPaper(const mozilla::PaperInfo& aInfo) : mInfo(aInfo) {}
private:
~nsPaper() = default;
nsString mName;
double mWidth;
double mHeight;
double mUnwriteableMarginTop;
double mUnwriteableMarginBottom;
double mUnwriteableMarginLeft;
double mUnwriteableMarginRight;
const mozilla::PaperInfo mInfo;
};
namespace mozilla {
// Turns this into a JSValue by wrapping it in an nsPaper struct.
//
// FIXME: If using WebIDL dictionaries we'd get this for ~free...
MOZ_MUST_USE inline bool ToJSValue(JSContext* aCx, const PaperInfo& aInfo,
JS::MutableHandleValue aValue) {
RefPtr<nsPaper> paper = new nsPaper(aInfo);
return dom::ToJSValue(aCx, paper, aValue);
}
} // namespace mozilla
#endif /* nsPaper_h__ */

View File

@ -19,9 +19,3 @@ nsPrinter::GetName(nsAString& aName) {
aName = mName;
return NS_OK;
}
NS_IMETHODIMP
nsPrinter::GetPaperList(nsTArray<RefPtr<nsIPaper>>& aPaperList) {
aPaperList.Assign(mPaperList);
return NS_OK;
}

View File

@ -7,14 +7,15 @@
#define nsPrinter_h__
#include "nsPrinterBase.h"
#include "nsPaper.h"
#include "nsString.h"
class nsPrinter final : public nsPrinterBase {
public:
NS_IMETHOD GetName(nsAString& aName) override;
NS_IMETHOD GetPaperList(nsTArray<RefPtr<nsIPaper>>& aPaperList) override;
bool SupportsDuplex() const final { return false; }
bool SupportsColor() const final { return false; }
nsTArray<mozilla::PaperInfo> PaperList() const final { return {}; }
nsPrinter() = delete;

View File

@ -5,6 +5,7 @@
#include "nsPrinterBase.h"
#include "nsPrinter.h"
#include "nsPaper.h"
#include "mozilla/dom/Promise.h"
using namespace mozilla;
@ -84,7 +85,14 @@ NS_IMETHODIMP nsPrinterBase::GetSupportsColor(JSContext* aCx,
&nsPrinterBase::SupportsColor);
}
NS_IMPL_CYCLE_COLLECTION(nsPrinterBase, mAsyncAttributePromises, mPaperList)
NS_IMETHODIMP nsPrinterBase::GetPaperList(JSContext* aCx,
Promise** aResultPromise) {
return AsyncPromiseAttributeGetter<nsTArray<PaperInfo>>(
aCx, aResultPromise, AsyncAttribute::PaperList,
&nsPrinterBase::PaperList);
}
NS_IMPL_CYCLE_COLLECTION(nsPrinterBase, mAsyncAttributePromises)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterBase)
NS_INTERFACE_MAP_ENTRY(nsIPrinter)

View File

@ -12,16 +12,23 @@
#include "mozilla/EnumeratedArray.h"
#include "mozilla/Result.h"
namespace mozilla::dom {
namespace mozilla {
struct PaperInfo;
namespace dom {
class Promise;
}
} // namespace mozilla
class nsPrinterBase : public nsIPrinter {
public:
using Promise = mozilla::dom::Promise;
NS_IMETHOD GetSupportsDuplex(JSContext*, Promise**) final;
NS_IMETHOD GetSupportsColor(JSContext*, Promise**) final;
NS_IMETHOD GetPaperList(JSContext*, Promise**) final;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsPrinterBase)
@ -34,6 +41,7 @@ class nsPrinterBase : public nsIPrinter {
enum class AsyncAttribute {
SupportsDuplex = 0,
SupportsColor,
PaperList,
// Just a guard.
Last,
};
@ -55,9 +63,7 @@ class nsPrinterBase : public nsIPrinter {
// which thread they run on.
virtual bool SupportsDuplex() const = 0;
virtual bool SupportsColor() const = 0;
// FIXME: Temporary, should probably be moved to the async attribute stuff.
nsTArray<RefPtr<nsIPaper>> mPaperList;
virtual nsTArray<mozilla::PaperInfo> PaperList() const = 0;
private:
mozilla::EnumeratedArray<AsyncAttribute, AsyncAttribute::Last,

View File

@ -4,32 +4,33 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsPrinterCUPS.h"
#include "nsPaper.h"
#include "nsPrinterBase.h"
nsPrinterCUPS::nsPrinterCUPS(const nsCUPSShim& aShim, cups_dest_t* aPrinter,
nsTArray<RefPtr<nsIPaper>>&& aPaperList)
nsPrinterCUPS::nsPrinterCUPS(const nsCUPSShim& aShim, cups_dest_t* aPrinter)
: mShim(aShim) {
MOZ_ASSERT(aPrinter);
MOZ_ASSERT(mShim.IsInitialized());
DebugOnly<const int> numCopied = aShim.mCupsCopyDest(aPrinter, 0, &mPrinter);
MOZ_ASSERT(numCopied == 1);
mPrinterInfo = aShim.mCupsCopyDestInfo(CUPS_HTTP_DEFAULT, mPrinter);
mPaperList = std::move(aPaperList);
}
nsPrinterCUPS::~nsPrinterCUPS() {
if (mPrinterInfo) {
mShim.mCupsFreeDestInfo(mPrinterInfo);
mPrinterInfo = nullptr;
}
if (mPrinter) {
mShim.mCupsFreeDests(1, mPrinter);
mPrinter = nullptr;
}
}
// static
already_AddRefed<nsPrinterCUPS> nsPrinterCUPS::Create(
const nsCUPSShim& aShim, cups_dest_t* aPrinter,
nsTArray<RefPtr<nsIPaper>>&& aPaperList) {
return do_AddRef(new nsPrinterCUPS(aShim, aPrinter, std::move(aPaperList)));
already_AddRefed<nsPrinterCUPS> nsPrinterCUPS::Create(const nsCUPSShim& aShim,
cups_dest_t* aPrinter) {
return do_AddRef(new nsPrinterCUPS(aShim, aPrinter));
}
NS_IMETHODIMP
@ -38,12 +39,6 @@ nsPrinterCUPS::GetName(nsAString& aName) {
return NS_OK;
}
NS_IMETHODIMP
nsPrinterCUPS::GetPaperList(nsTArray<RefPtr<nsIPaper>>& aPaperList) {
aPaperList.Assign(mPaperList);
return NS_OK;
}
bool nsPrinterCUPS::SupportsDuplex() const {
return Supports(CUPS_SIDES, CUPS_SIDES_TWO_SIDED_PORTRAIT);
}
@ -55,3 +50,63 @@ bool nsPrinterCUPS::Supports(const char* option, const char* value) const {
return mShim.mCupsCheckDestSupported(CUPS_HTTP_DEFAULT, mPrinter,
mPrinterInfo, option, value);
}
nsTArray<mozilla::PaperInfo> nsPrinterCUPS::PaperList() const {
if (!mPrinterInfo) {
return {};
}
const int paperCount = mShim.mCupsGetDestMediaCount(
CUPS_HTTP_DEFAULT, mPrinter, mPrinterInfo, CUPS_MEDIA_FLAGS_DEFAULT);
// blocking call
http_t* connection = mShim.mCupsConnectDest(mPrinter, CUPS_DEST_FLAGS_NONE,
/* timeout(ms) */ 5000,
/* cancel */ nullptr,
/* resource */ nullptr,
/* resourcesize */ 0,
/* callback */ nullptr,
/* user_data */ nullptr);
if (!connection) {
return {};
}
nsTArray<mozilla::PaperInfo> paperList;
for (int i = 0; i < paperCount; ++i) {
cups_size_t info;
int getInfoSucceded = mShim.mCupsGetDestMediaByIndex(
CUPS_HTTP_DEFAULT, mPrinter, mPrinterInfo, i, CUPS_MEDIA_FLAGS_DEFAULT,
&info);
if (!getInfoSucceded) {
continue;
}
// localizedName is owned by mPrinterInfo.
// https://www.cups.org/doc/cupspm.html#cupsLocalizeDestMedia
const char* localizedName = mShim.mCupsLocalizeDestMedia(
connection, mPrinter, mPrinterInfo, CUPS_MEDIA_FLAGS_DEFAULT, &info);
if (!localizedName) {
continue;
}
// XXX Do we actually have the guarantee that this is utf-8?
NS_ConvertUTF8toUTF16 name(localizedName);
const double kPointsPerHundredthMillimeter = 0.0283465;
paperList.AppendElement(mozilla::PaperInfo{
std::move(name),
info.width * kPointsPerHundredthMillimeter,
info.length * kPointsPerHundredthMillimeter,
info.top * kPointsPerHundredthMillimeter,
info.right * kPointsPerHundredthMillimeter,
info.bottom * kPointsPerHundredthMillimeter,
info.left * kPointsPerHundredthMillimeter,
});
}
mShim.mHttpClose(connection);
return paperList;
}

View File

@ -16,24 +16,20 @@
class nsPrinterCUPS final : public nsPrinterBase {
public:
NS_IMETHOD GetName(nsAString& aName) override;
NS_IMETHOD GetPaperList(nsTArray<RefPtr<nsIPaper>>& aPaperList) override;
bool SupportsDuplex() const final;
bool SupportsColor() const final;
nsTArray<mozilla::PaperInfo> PaperList() const final;
nsPrinterCUPS() = delete;
/**
* @p aPrinter must not be null.
* @todo: Once CUPS-enumeration of paper sizes lands, we can remove the
* |aPaperList|.
*/
static already_AddRefed<nsPrinterCUPS> Create(
const nsCUPSShim& aShim, cups_dest_t* aPrinter,
nsTArray<RefPtr<nsIPaper>>&& aPaperList);
static already_AddRefed<nsPrinterCUPS> Create(const nsCUPSShim& aShim,
cups_dest_t* aPrinter);
private:
nsPrinterCUPS(const nsCUPSShim& aShim, cups_dest_t* aPrinter,
nsTArray<RefPtr<nsIPaper>>&& aPaperList);
nsPrinterCUPS(const nsCUPSShim& aShim, cups_dest_t* aPrinter);
~nsPrinterCUPS();

View File

@ -123,7 +123,6 @@ SOURCES += [
if CONFIG['NS_PRINTING']:
UNIFIED_SOURCES += [
'nsDeviceContextSpecWin.cpp',
'nsPaperWin.cpp',
'nsPrintDialogUtil.cpp',
'nsPrintDialogWin.cpp',
'nsPrinterWin.cpp',

View File

@ -1,100 +0,0 @@
/* -*- 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 "nsPaperWin.h"
#include "nsWindowsHelpers.h"
#include "WinUtils.h"
using namespace mozilla::widget;
static const wchar_t kDriverName[] = L"WINSPOOL";
nsPaperWin::nsPaperWin(WORD aId, const nsAString& aName,
const nsAString& aPrinterName, double aWidth,
double aHeight)
: mId(aId),
mName(aName),
mPrinterName(aPrinterName),
mSize(aWidth, aHeight) {}
NS_IMPL_ISUPPORTS(nsPaperWin, nsIPaper);
void nsPaperWin::EnsureUnwriteableMargin() {
if (mUnwriteableMarginRetrieved) {
return;
}
// We need a DEVMODE to set the paper size on the context.
DEVMODEW devmode = {};
devmode.dmSize = sizeof(DEVMODEW);
devmode.dmFields = DM_PAPERSIZE;
devmode.dmPaperSize = mId;
// Create an information context, so that we can get margin information.
// Note: this blocking call interacts with the driver and can be slow.
nsAutoHDC printerDc(
::CreateICW(kDriverName, mPrinterName.get(), nullptr, &devmode));
MarginDouble unWrtMarginInInches =
WinUtils::GetUnwriteableMarginsForDeviceInInches(printerDc);
mUnwriteableMargin.SizeTo(unWrtMarginInInches.top * POINTS_PER_INCH_FLOAT,
unWrtMarginInInches.right * POINTS_PER_INCH_FLOAT,
unWrtMarginInInches.bottom * POINTS_PER_INCH_FLOAT,
unWrtMarginInInches.left * POINTS_PER_INCH_FLOAT);
mUnwriteableMarginRetrieved = true;
}
NS_IMETHODIMP
nsPaperWin::GetName(nsAString& aName) {
aName = mName;
return NS_OK;
}
NS_IMETHODIMP
nsPaperWin::GetWidth(double* aWidth) {
MOZ_ASSERT(aWidth);
*aWidth = mSize.Width();
return NS_OK;
}
NS_IMETHODIMP
nsPaperWin::GetHeight(double* aHeight) {
MOZ_ASSERT(aHeight);
*aHeight = mSize.Height();
return NS_OK;
}
NS_IMETHODIMP
nsPaperWin::GetUnwriteableMarginTop(double* aUnwriteableMarginTop) {
MOZ_ASSERT(aUnwriteableMarginTop);
EnsureUnwriteableMargin();
*aUnwriteableMarginTop = mUnwriteableMargin.top;
return NS_OK;
}
NS_IMETHODIMP
nsPaperWin::GetUnwriteableMarginBottom(double* aUnwriteableMarginBottom) {
MOZ_ASSERT(aUnwriteableMarginBottom);
EnsureUnwriteableMargin();
*aUnwriteableMarginBottom = mUnwriteableMargin.bottom;
return NS_OK;
}
NS_IMETHODIMP
nsPaperWin::GetUnwriteableMarginLeft(double* aUnwriteableMarginLeft) {
MOZ_ASSERT(aUnwriteableMarginLeft);
EnsureUnwriteableMargin();
*aUnwriteableMarginLeft = mUnwriteableMargin.left;
return NS_OK;
}
NS_IMETHODIMP
nsPaperWin::GetUnwriteableMarginRight(double* aUnwriteableMarginRight) {
MOZ_ASSERT(aUnwriteableMarginRight);
EnsureUnwriteableMargin();
*aUnwriteableMarginRight = mUnwriteableMargin.right;
return NS_OK;
}

View File

@ -1,41 +0,0 @@
/* -*- 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/. */
#ifndef nsPaperWin_h_
#define nsPaperWin_h_
#include "nsIPaper.h"
#include <wtypes.h>
#include "mozilla/gfx/Rect.h"
#include "nsISupportsImpl.h"
#include "nsString.h"
class nsPaperWin final : public nsIPaper {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPAPER
nsPaperWin() = delete;
nsPaperWin(WORD aId, const nsAString& aName, const nsAString& aPrinterName,
double aWidth, double aHeight);
private:
~nsPaperWin() = default;
void EnsureUnwriteableMargin();
using SizeDouble = mozilla::gfx::SizeDouble;
using MarginDouble = mozilla::gfx::MarginDouble;
WORD mId;
nsString mName;
nsString mPrinterName;
SizeDouble mSize;
MarginDouble mUnwriteableMargin;
bool mUnwriteableMarginRetrieved = false;
};
#endif // nsPaperWin_h_

View File

@ -9,7 +9,7 @@
#include <windows.h>
#include "mozilla/Array.h"
#include "nsPaperWin.h"
#include "nsPaper.h"
using namespace mozilla;
using namespace mozilla::gfx;
@ -62,11 +62,23 @@ static nsTArray<T> GetDeviceCapabilityArray(const LPWSTR aPrinterName,
return caps;
}
nsresult nsPrinterWin::EnsurePaperList() {
if (!mPaperList.IsEmpty()) {
return NS_OK;
}
NS_IMETHODIMP
nsPrinterWin::GetName(nsAString& aName) {
aName.Assign(mName);
return NS_OK;
}
bool nsPrinterWin::SupportsDuplex() const {
return ::DeviceCapabilitiesW(mName.get(), nullptr, DC_DUPLEX, nullptr,
nullptr) == 1;
}
bool nsPrinterWin::SupportsColor() const {
return ::DeviceCapabilitiesW(mName.get(), nullptr, DC_COLORDEVICE, nullptr,
nullptr) == 1;
}
nsTArray<mozilla::PaperInfo> nsPrinterWin::PaperList() const {
// Paper names are returned in 64 long character buffers.
auto paperNames =
GetDeviceCapabilityArray<Array<wchar_t, 64>>(mName.get(), DC_PAPERNAMES);
@ -81,10 +93,12 @@ nsresult nsPrinterWin::EnsurePaperList() {
// Check that we have papers and that the array lengths match.
if (!paperNames.Length() || paperNames.Length() != paperIds.Length() ||
paperNames.Length() != paperSizes.Length()) {
return NS_ERROR_UNEXPECTED;
return {};
}
mPaperList.SetCapacity(paperNames.Length());
static const wchar_t kDriverName[] = L"WINSPOOL";
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 =
@ -98,37 +112,34 @@ nsresult nsPrinterWin::EnsurePaperList() {
continue;
}
nsAutoString paperName(paperNames[i].cbegin(), nameLength);
mPaperList.AppendElement(
new nsPaperWin(paperIds[i], paperName, mName, width, height));
WORD id = paperIds[i];
// Now get the margin info.
// We need a DEVMODE to set the paper size on the context.
DEVMODEW devmode = {};
devmode.dmSize = sizeof(DEVMODEW);
devmode.dmFields = DM_PAPERSIZE;
devmode.dmPaperSize = id;
// Create an information context, so that we can get margin information.
// Note: this blocking call interacts with the driver and can be slow.
nsAutoHDC printerDc(
::CreateICW(kDriverName, mName.get(), nullptr, &devmode));
auto marginInInches =
WinUtils::GetUnwriteableMarginsForDeviceInInches(printerDc);
nsDependentSubstring name(paperNames[i].cbegin(), nameLength);
paperList.AppendElement(mozilla::PaperInfo{
nsString(name),
width,
height,
marginInInches.top * POINTS_PER_INCH_FLOAT,
marginInInches.right * POINTS_PER_INCH_FLOAT,
marginInInches.bottom * POINTS_PER_INCH_FLOAT,
marginInInches.left * POINTS_PER_INCH_FLOAT,
});
}
return NS_OK;
}
NS_IMETHODIMP
nsPrinterWin::GetName(nsAString& aName) {
aName.Assign(mName);
return NS_OK;
}
NS_IMETHODIMP
nsPrinterWin::GetPaperList(nsTArray<RefPtr<nsIPaper>>& aPaperList) {
nsresult rv = EnsurePaperList();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
aPaperList.Assign(mPaperList);
return NS_OK;
}
bool nsPrinterWin::SupportsDuplex() const {
return ::DeviceCapabilitiesW(mName.get(), nullptr, DC_DUPLEX, nullptr,
nullptr) == 1;
}
bool nsPrinterWin::SupportsColor() const {
return ::DeviceCapabilitiesW(mName.get(), nullptr, DC_COLORDEVICE, nullptr,
nullptr) == 1;
return paperList;
}

View File

@ -11,10 +11,10 @@
class nsPrinterWin final : public nsPrinterBase {
public:
NS_IMETHOD GetName(nsAString& aName) override;
NS_IMETHOD GetPaperList(nsTArray<RefPtr<nsIPaper>>& aPaperList) override;
bool SupportsDuplex() const final;
bool SupportsColor() const final;
nsTArray<mozilla::PaperInfo> PaperList() const final;
nsPrinterWin() = delete;
static already_AddRefed<nsPrinterWin> Create(const nsAString& aName);