mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
2a789531dc
These changes are to make using an off screen surface behind our DrawTarget in the child easier. It still creates the real printing surface for some of the calculations, removing this will be required for future tightening of the sandbox.
844 lines
27 KiB
C++
844 lines
27 KiB
C++
/* -*- 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 "mozilla/ArrayUtils.h"
|
|
|
|
#include "nsDeviceContextSpecWin.h"
|
|
#include "prmem.h"
|
|
|
|
#include <winspool.h>
|
|
|
|
#include <tchar.h>
|
|
|
|
#include "nsAutoPtr.h"
|
|
#include "nsIWidget.h"
|
|
|
|
#include "nsTArray.h"
|
|
#include "nsIPrintSettingsWin.h"
|
|
|
|
#include "nsString.h"
|
|
#include "nsCRT.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "nsStringEnumerator.h"
|
|
|
|
#include "gfxPDFSurface.h"
|
|
#include "gfxWindowsSurface.h"
|
|
|
|
#include "nsIFileStreams.h"
|
|
#include "nsIWindowWatcher.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "mozilla/Services.h"
|
|
|
|
// For NS_CopyNativeToUnicode
|
|
#include "nsNativeCharsetUtils.h"
|
|
|
|
// File Picker
|
|
#include "nsIFile.h"
|
|
#include "nsIFilePicker.h"
|
|
#include "nsIStringBundle.h"
|
|
#define NS_ERROR_GFX_PRINTER_BUNDLE_URL "chrome://global/locale/printing.properties"
|
|
|
|
#include "mozilla/gfx/Logging.h"
|
|
|
|
#include "mozilla/Logging.h"
|
|
PRLogModuleInfo * kWidgetPrintingLogMod = PR_NewLogModule("printing-widget");
|
|
#define PR_PL(_p1) MOZ_LOG(kWidgetPrintingLogMod, mozilla::LogLevel::Debug, _p1)
|
|
|
|
using namespace mozilla;
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
|
|
// The PrinterEnumerator creates the printer info
|
|
// but the nsDeviceContextSpecWin cleans it up
|
|
// If it gets created (via the Page Setup Dialog) but the user never prints anything
|
|
// then it will never be delete, so this class takes care of that.
|
|
class GlobalPrinters {
|
|
public:
|
|
static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
|
|
~GlobalPrinters() { FreeGlobalPrinters(); }
|
|
|
|
void FreeGlobalPrinters();
|
|
|
|
bool PrintersAreAllocated() { return mPrinters != nullptr; }
|
|
LPWSTR GetItemFromList(int32_t aInx) { return mPrinters?mPrinters->ElementAt(aInx):nullptr; }
|
|
nsresult EnumeratePrinterList();
|
|
void GetDefaultPrinterName(nsString& aDefaultPrinterName);
|
|
uint32_t GetNumPrinters() { return mPrinters?mPrinters->Length():0; }
|
|
|
|
protected:
|
|
GlobalPrinters() {}
|
|
nsresult EnumerateNativePrinters();
|
|
void ReallocatePrinters();
|
|
|
|
static GlobalPrinters mGlobalPrinters;
|
|
static nsTArray<LPWSTR>* mPrinters;
|
|
};
|
|
//---------------
|
|
// static members
|
|
GlobalPrinters GlobalPrinters::mGlobalPrinters;
|
|
nsTArray<LPWSTR>* GlobalPrinters::mPrinters = nullptr;
|
|
|
|
|
|
//******************************************************
|
|
// Define native paper sizes
|
|
//******************************************************
|
|
typedef struct {
|
|
short mPaperSize; // native enum
|
|
double mWidth;
|
|
double mHeight;
|
|
bool mIsInches;
|
|
} NativePaperSizes;
|
|
|
|
// There are around 40 default print sizes defined by Windows
|
|
const NativePaperSizes kPaperSizes[] = {
|
|
{DMPAPER_LETTER, 8.5, 11.0, true},
|
|
{DMPAPER_LEGAL, 8.5, 14.0, true},
|
|
{DMPAPER_A4, 210.0, 297.0, false},
|
|
{DMPAPER_B4, 250.0, 354.0, false},
|
|
{DMPAPER_B5, 182.0, 257.0, false},
|
|
{DMPAPER_TABLOID, 11.0, 17.0, true},
|
|
{DMPAPER_LEDGER, 17.0, 11.0, true},
|
|
{DMPAPER_STATEMENT, 5.5, 8.5, true},
|
|
{DMPAPER_EXECUTIVE, 7.25, 10.5, true},
|
|
{DMPAPER_A3, 297.0, 420.0, false},
|
|
{DMPAPER_A5, 148.0, 210.0, false},
|
|
{DMPAPER_CSHEET, 17.0, 22.0, true},
|
|
{DMPAPER_DSHEET, 22.0, 34.0, true},
|
|
{DMPAPER_ESHEET, 34.0, 44.0, true},
|
|
{DMPAPER_LETTERSMALL, 8.5, 11.0, true},
|
|
{DMPAPER_A4SMALL, 210.0, 297.0, false},
|
|
{DMPAPER_FOLIO, 8.5, 13.0, true},
|
|
{DMPAPER_QUARTO, 215.0, 275.0, false},
|
|
{DMPAPER_10X14, 10.0, 14.0, true},
|
|
{DMPAPER_11X17, 11.0, 17.0, true},
|
|
{DMPAPER_NOTE, 8.5, 11.0, true},
|
|
{DMPAPER_ENV_9, 3.875, 8.875, true},
|
|
{DMPAPER_ENV_10, 40.125, 9.5, true},
|
|
{DMPAPER_ENV_11, 4.5, 10.375, true},
|
|
{DMPAPER_ENV_12, 4.75, 11.0, true},
|
|
{DMPAPER_ENV_14, 5.0, 11.5, true},
|
|
{DMPAPER_ENV_DL, 110.0, 220.0, false},
|
|
{DMPAPER_ENV_C5, 162.0, 229.0, false},
|
|
{DMPAPER_ENV_C3, 324.0, 458.0, false},
|
|
{DMPAPER_ENV_C4, 229.0, 324.0, false},
|
|
{DMPAPER_ENV_C6, 114.0, 162.0, false},
|
|
{DMPAPER_ENV_C65, 114.0, 229.0, false},
|
|
{DMPAPER_ENV_B4, 250.0, 353.0, false},
|
|
{DMPAPER_ENV_B5, 176.0, 250.0, false},
|
|
{DMPAPER_ENV_B6, 176.0, 125.0, false},
|
|
{DMPAPER_ENV_ITALY, 110.0, 230.0, false},
|
|
{DMPAPER_ENV_MONARCH, 3.875, 7.5, true},
|
|
{DMPAPER_ENV_PERSONAL, 3.625, 6.5, true},
|
|
{DMPAPER_FANFOLD_US, 14.875, 11.0, true},
|
|
{DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, true},
|
|
{DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, true},
|
|
};
|
|
const int32_t kNumPaperSizes = 41;
|
|
|
|
//----------------------------------------------------------------------------------
|
|
nsDeviceContextSpecWin::nsDeviceContextSpecWin()
|
|
{
|
|
mDriverName = nullptr;
|
|
mDeviceName = nullptr;
|
|
mDevMode = nullptr;
|
|
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin, nsIDeviceContextSpec)
|
|
|
|
nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
|
|
{
|
|
SetDeviceName(nullptr);
|
|
SetDriverName(nullptr);
|
|
SetDevMode(nullptr);
|
|
|
|
nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
|
|
if (psWin) {
|
|
psWin->SetDeviceName(nullptr);
|
|
psWin->SetDriverName(nullptr);
|
|
psWin->SetDevMode(nullptr);
|
|
}
|
|
|
|
// Free them, we won't need them for a while
|
|
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------
|
|
// helper
|
|
static char16_t * GetDefaultPrinterNameFromGlobalPrinters()
|
|
{
|
|
nsAutoString printerName;
|
|
GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
|
|
return ToNewUnicode(printerName);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
|
|
nsIPrintSettings* aPrintSettings,
|
|
bool aIsPrintPreview)
|
|
{
|
|
mPrintSettings = aPrintSettings;
|
|
|
|
nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
|
|
if (aPrintSettings) {
|
|
nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
|
|
if (psWin) {
|
|
char16_t* deviceName;
|
|
char16_t* driverName;
|
|
psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
|
|
psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
|
|
|
|
LPDEVMODEW devMode;
|
|
psWin->GetDevMode(&devMode); // creates new memory (makes a copy)
|
|
|
|
if (deviceName && driverName && devMode) {
|
|
// Scaling is special, it is one of the few
|
|
// devMode items that we control in layout
|
|
if (devMode->dmFields & DM_SCALE) {
|
|
double scale = double(devMode->dmScale) / 100.0f;
|
|
if (scale != 1.0) {
|
|
aPrintSettings->SetScaling(scale);
|
|
devMode->dmScale = 100;
|
|
}
|
|
}
|
|
|
|
SetDeviceName(deviceName);
|
|
SetDriverName(driverName);
|
|
SetDevMode(devMode);
|
|
|
|
// clean up
|
|
free(deviceName);
|
|
free(driverName);
|
|
|
|
return NS_OK;
|
|
} else {
|
|
PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
|
|
if (deviceName) free(deviceName);
|
|
if (driverName) free(driverName);
|
|
if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
|
|
}
|
|
}
|
|
} else {
|
|
PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
|
|
}
|
|
|
|
// Get the Print Name to be used
|
|
char16_t * printerName = nullptr;
|
|
if (mPrintSettings) {
|
|
mPrintSettings->GetPrinterName(&printerName);
|
|
}
|
|
|
|
// If there is no name then use the default printer
|
|
if (!printerName || (printerName && !*printerName)) {
|
|
printerName = GetDefaultPrinterNameFromGlobalPrinters();
|
|
}
|
|
|
|
NS_ASSERTION(printerName, "We have to have a printer name");
|
|
if (!printerName || !*printerName) return rv;
|
|
|
|
return GetDataFromPrinter(printerName, mPrintSettings);
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
// Helper Function - Free and reallocate the string
|
|
static void CleanAndCopyString(wchar_t*& aStr, const wchar_t* aNewStr)
|
|
{
|
|
if (aStr != nullptr) {
|
|
if (aNewStr != nullptr && wcslen(aStr) > wcslen(aNewStr)) { // reuse it if we can
|
|
wcscpy(aStr, aNewStr);
|
|
return;
|
|
} else {
|
|
PR_Free(aStr);
|
|
aStr = nullptr;
|
|
}
|
|
}
|
|
|
|
if (nullptr != aNewStr) {
|
|
aStr = (wchar_t *)PR_Malloc(sizeof(wchar_t)*(wcslen(aNewStr) + 1));
|
|
wcscpy(aStr, aNewStr);
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface **surface)
|
|
{
|
|
NS_ASSERTION(mDevMode, "DevMode can't be NULL here");
|
|
|
|
*surface = nullptr;
|
|
RefPtr<gfxASurface> newSurface;
|
|
|
|
int16_t outputFormat = 0;
|
|
if (mPrintSettings) {
|
|
mPrintSettings->GetOutputFormat(&outputFormat);
|
|
}
|
|
|
|
if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
|
|
nsXPIDLString filename;
|
|
mPrintSettings->GetToFileName(getter_Copies(filename));
|
|
|
|
double width, height;
|
|
mPrintSettings->GetEffectivePageSize(&width, &height);
|
|
if (width <= 0 || height <= 0) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// convert twips to points
|
|
width /= TWIPS_PER_POINT_FLOAT;
|
|
height /= TWIPS_PER_POINT_FLOAT;
|
|
|
|
nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
|
|
nsresult rv = file->InitWithPath(filename);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
|
|
rv = stream->Init(file, -1, -1, 0);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
newSurface = new gfxPDFSurface(stream, gfxSize(width, height));
|
|
} else {
|
|
if (mDevMode) {
|
|
NS_WARN_IF_FALSE(mDriverName, "No driver!");
|
|
HDC dc = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
|
|
if (!dc) {
|
|
gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Failed to create device context in GetSurfaceForPrinter";
|
|
return NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
|
|
}
|
|
|
|
// have this surface take over ownership of this DC
|
|
newSurface = new gfxWindowsSurface(dc, gfxWindowsSurface::FLAG_TAKE_DC | gfxWindowsSurface::FLAG_FOR_PRINTING);
|
|
if (newSurface->GetType() == (gfxSurfaceType)-1) {
|
|
gfxCriticalError() << "Invalid windows surface from " << gfx::hexa(dc);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
|
|
mPrintingSurface = newSurface;
|
|
newSurface.forget(surface);
|
|
return NS_OK;
|
|
}
|
|
|
|
float
|
|
nsDeviceContextSpecWin::GetPrintingScale()
|
|
{
|
|
MOZ_ASSERT(mPrintingSurface);
|
|
|
|
HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
|
|
int32_t OSVal = GetDeviceCaps(dc, LOGPIXELSY);
|
|
return float(OSVal) / GetDPI();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void nsDeviceContextSpecWin::SetDeviceName(char16ptr_t aDeviceName)
|
|
{
|
|
CleanAndCopyString(mDeviceName, aDeviceName);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void nsDeviceContextSpecWin::SetDriverName(char16ptr_t aDriverName)
|
|
{
|
|
CleanAndCopyString(mDriverName, aDriverName);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode)
|
|
{
|
|
if (mDevMode) {
|
|
::HeapFree(::GetProcessHeap(), 0, mDevMode);
|
|
}
|
|
|
|
mDevMode = aDevMode;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
void
|
|
nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW &aDevMode)
|
|
{
|
|
aDevMode = mDevMode;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Map an incoming size to a Windows Native enum in the DevMode
|
|
static void
|
|
MapPaperSizeToNativeEnum(LPDEVMODEW aDevMode,
|
|
int16_t aType,
|
|
double aW,
|
|
double aH)
|
|
{
|
|
|
|
#ifdef DEBUG_rods
|
|
BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
|
|
BOOL doingPaperSize = aDevMode->dmFields & DM_PAPERSIZE;
|
|
BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
|
|
BOOL doingPaperWidth = aDevMode->dmFields & DM_PAPERWIDTH;
|
|
#endif
|
|
|
|
for (int32_t i=0;i<kNumPaperSizes;i++) {
|
|
if (kPaperSizes[i].mWidth == aW && kPaperSizes[i].mHeight == aH) {
|
|
aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize;
|
|
aDevMode->dmFields &= ~DM_PAPERLENGTH;
|
|
aDevMode->dmFields &= ~DM_PAPERWIDTH;
|
|
aDevMode->dmFields |= DM_PAPERSIZE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
short width = 0;
|
|
short height = 0;
|
|
if (aType == nsIPrintSettings::kPaperSizeInches) {
|
|
width = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10);
|
|
height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10);
|
|
|
|
} else if (aType == nsIPrintSettings::kPaperSizeMillimeters) {
|
|
width = short(aW / 10.0);
|
|
height = short(aH / 10.0);
|
|
} else {
|
|
return; // don't set anything
|
|
}
|
|
|
|
// width and height is in
|
|
aDevMode->dmPaperSize = 0;
|
|
aDevMode->dmPaperWidth = width;
|
|
aDevMode->dmPaperLength = height;
|
|
|
|
aDevMode->dmFields |= DM_PAPERSIZE;
|
|
aDevMode->dmFields |= DM_PAPERLENGTH;
|
|
aDevMode->dmFields |= DM_PAPERWIDTH;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Setup Paper Size & Orientation options into the DevMode
|
|
//
|
|
static void
|
|
SetupDevModeFromSettings(LPDEVMODEW aDevMode, nsIPrintSettings* aPrintSettings)
|
|
{
|
|
// Setup paper size
|
|
if (aPrintSettings) {
|
|
int16_t type;
|
|
aPrintSettings->GetPaperSizeType(&type);
|
|
if (type == nsIPrintSettings::kPaperSizeNativeData) {
|
|
int16_t paperEnum;
|
|
aPrintSettings->GetPaperData(&paperEnum);
|
|
aDevMode->dmPaperSize = paperEnum;
|
|
aDevMode->dmFields &= ~DM_PAPERLENGTH;
|
|
aDevMode->dmFields &= ~DM_PAPERWIDTH;
|
|
aDevMode->dmFields |= DM_PAPERSIZE;
|
|
} else {
|
|
int16_t unit;
|
|
double width, height;
|
|
aPrintSettings->GetPaperSizeUnit(&unit);
|
|
aPrintSettings->GetPaperWidth(&width);
|
|
aPrintSettings->GetPaperHeight(&height);
|
|
MapPaperSizeToNativeEnum(aDevMode, unit, width, height);
|
|
}
|
|
|
|
// Setup Orientation
|
|
int32_t orientation;
|
|
aPrintSettings->GetOrientation(&orientation);
|
|
aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE;
|
|
aDevMode->dmFields |= DM_ORIENTATION;
|
|
|
|
// Setup Number of Copies
|
|
int32_t copies;
|
|
aPrintSettings->GetNumCopies(&copies);
|
|
aDevMode->dmCopies = copies;
|
|
aDevMode->dmFields |= DM_COPIES;
|
|
}
|
|
|
|
}
|
|
|
|
#define DISPLAY_LAST_ERROR
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Setup the object's data member with the selected printer's data
|
|
nsresult
|
|
nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS)
|
|
{
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
|
|
rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
|
|
if (NS_FAILED(rv)) {
|
|
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
|
|
DISPLAY_LAST_ERROR
|
|
}
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
HANDLE hPrinter = nullptr;
|
|
wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument
|
|
|
|
BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr);
|
|
if (status) {
|
|
|
|
LPDEVMODEW pDevMode;
|
|
DWORD dwNeeded, dwRet;
|
|
|
|
// Allocate a buffer of the correct size.
|
|
dwNeeded = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr, nullptr, 0);
|
|
|
|
pDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
|
|
if (!pDevMode) return NS_ERROR_FAILURE;
|
|
|
|
// Get the default DevMode for the printer and modify it for our needs.
|
|
dwRet = DocumentPropertiesW(nullptr, hPrinter, name,
|
|
pDevMode, nullptr, DM_OUT_BUFFER);
|
|
|
|
if (dwRet == IDOK && aPS) {
|
|
SetupDevModeFromSettings(pDevMode, aPS);
|
|
// Sets back the changes we made to the DevMode into the Printer Driver
|
|
dwRet = ::DocumentPropertiesW(nullptr, hPrinter, name,
|
|
pDevMode, pDevMode,
|
|
DM_IN_BUFFER | DM_OUT_BUFFER);
|
|
}
|
|
|
|
if (dwRet != IDOK) {
|
|
::HeapFree(::GetProcessHeap(), 0, pDevMode);
|
|
::ClosePrinter(hPrinter);
|
|
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", dwRet, dwRet));
|
|
DISPLAY_LAST_ERROR
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
|
|
|
|
SetDeviceName(aName);
|
|
|
|
SetDriverName(L"WINSPOOL");
|
|
|
|
::ClosePrinter(hPrinter);
|
|
rv = NS_OK;
|
|
} else {
|
|
rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
|
|
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName).get()));
|
|
DISPLAY_LAST_ERROR
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Setup Paper Size options into the DevMode
|
|
//
|
|
// When using a data member it may be a HGLOCAL or LPDEVMODE
|
|
// if it is a HGLOBAL then we need to "lock" it to get the LPDEVMODE
|
|
// and unlock it when we are done.
|
|
void
|
|
nsDeviceContextSpecWin::SetupPaperInfoFromSettings()
|
|
{
|
|
LPDEVMODEW devMode;
|
|
|
|
GetDevMode(devMode);
|
|
NS_ASSERTION(devMode, "DevMode can't be NULL here");
|
|
if (devMode) {
|
|
SetupDevModeFromSettings(devMode, mPrintSettings);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Helper Function - Free and reallocate the string
|
|
nsresult
|
|
nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings,
|
|
LPDEVMODEW aDevMode)
|
|
{
|
|
if (aPrintSettings == nullptr) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
aPrintSettings->SetIsInitializedFromPrinter(true);
|
|
|
|
BOOL doingNumCopies = aDevMode->dmFields & DM_COPIES;
|
|
BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
|
|
BOOL doingPaperSize = aDevMode->dmFields & DM_PAPERSIZE;
|
|
BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
|
|
BOOL doingPaperWidth = aDevMode->dmFields & DM_PAPERWIDTH;
|
|
|
|
if (doingOrientation) {
|
|
int32_t orientation = aDevMode->dmOrientation == DMORIENT_PORTRAIT?
|
|
int32_t(nsIPrintSettings::kPortraitOrientation):nsIPrintSettings::kLandscapeOrientation;
|
|
aPrintSettings->SetOrientation(orientation);
|
|
}
|
|
|
|
// Setup Number of Copies
|
|
if (doingNumCopies) {
|
|
aPrintSettings->SetNumCopies(int32_t(aDevMode->dmCopies));
|
|
}
|
|
|
|
if (aDevMode->dmFields & DM_SCALE) {
|
|
double scale = double(aDevMode->dmScale) / 100.0f;
|
|
if (scale != 1.0) {
|
|
aPrintSettings->SetScaling(scale);
|
|
aDevMode->dmScale = 100;
|
|
// To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
|
|
//aPrintSettings->SetShrinkToFit(false);
|
|
}
|
|
}
|
|
|
|
if (doingPaperSize) {
|
|
aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData);
|
|
aPrintSettings->SetPaperData(aDevMode->dmPaperSize);
|
|
for (int32_t i=0;i<kNumPaperSizes;i++) {
|
|
if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
|
|
aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches
|
|
?int16_t(nsIPrintSettings::kPaperSizeInches):nsIPrintSettings::kPaperSizeMillimeters);
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else if (doingPaperLength && doingPaperWidth) {
|
|
bool found = false;
|
|
for (int32_t i=0;i<kNumPaperSizes;i++) {
|
|
if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
|
|
aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined);
|
|
aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth);
|
|
aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight);
|
|
aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches
|
|
?int16_t(nsIPrintSettings::kPaperSizeInches):nsIPrintSettings::kPaperSizeMillimeters);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
} else {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
//***********************************************************
|
|
// Printer Enumerator
|
|
//***********************************************************
|
|
nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
|
|
{
|
|
}
|
|
|
|
nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
|
|
{
|
|
// Do not free printers here
|
|
// GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Return the Default Printer name
|
|
NS_IMETHODIMP
|
|
nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
|
|
|
|
*aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aPrinterName);
|
|
NS_ENSURE_ARG_POINTER(aPrintSettings);
|
|
|
|
if (!*aPrinterName) {
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
|
|
if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
devSpecWin->GetDataFromPrinter(aPrinterName);
|
|
|
|
LPDEVMODEW devmode;
|
|
devSpecWin->GetDevMode(devmode);
|
|
NS_ASSERTION(devmode, "DevMode can't be NULL here");
|
|
if (devmode) {
|
|
aPrintSettings->SetPrinterName(aPrinterName);
|
|
nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(aPrintSettings, devmode);
|
|
}
|
|
|
|
// Free them, we won't need them for a while
|
|
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Enumerate all the Printers from the global array and pass their
|
|
// names back (usually to script)
|
|
NS_IMETHODIMP
|
|
nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameList)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aPrinterNameList);
|
|
*aPrinterNameList = nullptr;
|
|
|
|
nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
|
|
if (NS_FAILED(rv)) {
|
|
PR_PL(("***** nsDeviceContextSpecWin::GetPrinterNameList - Couldn't enumerate printers!\n"));
|
|
return rv;
|
|
}
|
|
|
|
uint32_t numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
|
|
nsTArray<nsString> *printers = new nsTArray<nsString>(numPrinters);
|
|
if (!printers)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsString* names = printers->AppendElements(numPrinters);
|
|
for (uint32_t printerInx = 0; printerInx < numPrinters; ++printerInx) {
|
|
LPWSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx);
|
|
names[printerInx].Assign(name);
|
|
}
|
|
|
|
return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Display the AdvancedDocumentProperties for the selected Printer
|
|
NS_IMETHODIMP nsPrinterEnumeratorWin::DisplayPropertiesDlg(const char16_t *aPrinterName, nsIPrintSettings* aPrintSettings)
|
|
{
|
|
// Implementation removed because it is unused
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
//-- Global Printers
|
|
//----------------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// THe array hold the name and port for each printer
|
|
void
|
|
GlobalPrinters::ReallocatePrinters()
|
|
{
|
|
if (PrintersAreAllocated()) {
|
|
FreeGlobalPrinters();
|
|
}
|
|
mPrinters = new nsTArray<LPWSTR>();
|
|
NS_ASSERTION(mPrinters, "Printers Array is NULL!");
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void
|
|
GlobalPrinters::FreeGlobalPrinters()
|
|
{
|
|
if (mPrinters != nullptr) {
|
|
for (uint32_t i=0;i<mPrinters->Length();i++) {
|
|
free(mPrinters->ElementAt(i));
|
|
}
|
|
delete mPrinters;
|
|
mPrinters = nullptr;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
nsresult
|
|
GlobalPrinters::EnumerateNativePrinters()
|
|
{
|
|
nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
|
|
PR_PL(("-----------------------\n"));
|
|
PR_PL(("EnumerateNativePrinters\n"));
|
|
|
|
WCHAR szDefaultPrinterName[1024];
|
|
DWORD status = GetProfileStringW(L"devices", 0, L",",
|
|
szDefaultPrinterName,
|
|
ArrayLength(szDefaultPrinterName));
|
|
if (status > 0) {
|
|
DWORD count = 0;
|
|
LPWSTR sPtr = szDefaultPrinterName;
|
|
LPWSTR ePtr = szDefaultPrinterName + status;
|
|
LPWSTR prvPtr = sPtr;
|
|
while (sPtr < ePtr) {
|
|
if (*sPtr == 0) {
|
|
LPWSTR name = wcsdup(prvPtr);
|
|
mPrinters->AppendElement(name);
|
|
PR_PL(("Printer Name: %s\n", prvPtr));
|
|
prvPtr = sPtr+1;
|
|
count++;
|
|
}
|
|
sPtr++;
|
|
}
|
|
rv = NS_OK;
|
|
}
|
|
PR_PL(("-----------------------\n"));
|
|
return rv;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
// Uses the GetProfileString to get the default printer from the registry
|
|
void
|
|
GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName)
|
|
{
|
|
aDefaultPrinterName.Truncate();
|
|
WCHAR szDefaultPrinterName[1024];
|
|
DWORD status = GetProfileStringW(L"windows", L"device", 0,
|
|
szDefaultPrinterName,
|
|
ArrayLength(szDefaultPrinterName));
|
|
if (status > 0) {
|
|
WCHAR comma = ',';
|
|
LPWSTR sPtr = szDefaultPrinterName;
|
|
while (*sPtr != comma && *sPtr != 0)
|
|
sPtr++;
|
|
if (*sPtr == comma) {
|
|
*sPtr = 0;
|
|
}
|
|
aDefaultPrinterName = szDefaultPrinterName;
|
|
} else {
|
|
aDefaultPrinterName = EmptyString();
|
|
}
|
|
|
|
PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName.get()));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// This goes and gets the list of available printers and puts
|
|
// the default printer at the beginning of the list
|
|
nsresult
|
|
GlobalPrinters::EnumeratePrinterList()
|
|
{
|
|
// reallocate and get a new list each time it is asked for
|
|
// this deletes the list and re-allocates them
|
|
ReallocatePrinters();
|
|
|
|
// any of these could only fail with an OUT_MEMORY_ERROR
|
|
// PRINTER_ENUM_LOCAL should get the network printers on Win95
|
|
nsresult rv = EnumerateNativePrinters();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// get the name of the default printer
|
|
nsAutoString defPrinterName;
|
|
GetDefaultPrinterName(defPrinterName);
|
|
|
|
// put the default printer at the beginning of list
|
|
if (!defPrinterName.IsEmpty()) {
|
|
for (uint32_t i=0;i<mPrinters->Length();i++) {
|
|
LPWSTR name = mPrinters->ElementAt(i);
|
|
if (defPrinterName.Equals(name)) {
|
|
if (i > 0) {
|
|
LPWSTR ptr = mPrinters->ElementAt(0);
|
|
mPrinters->ElementAt(0) = name;
|
|
mPrinters->ElementAt(i) = ptr;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// make sure we at least tried to get the printers
|
|
if (!PrintersAreAllocated()) {
|
|
PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|