Files
palemoon27/widget/windows/nsDeviceContextSpecWin.cpp
T
roytam1 b0cbe263c6 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1238964 Part 1: Hold new printable page sizes in print nsIPrintSettingsWin. r=jimm (b5e4d012ba)
- Bug 1238964 Part 2: Move separate DEVMODE to nsIPrintSettings copying into nsPrintSettingsWin. r=jimm (cb7bb66037)
- Bug 1218029 - Adds SRICheckDataVerifier for progressing data handling. r=francois (8331afc1a7)
- Bug 1218029 - Implements progressive Unicode chars decoding in nsScriptLoader. r=djvj (2c32ca259a)
- Bug 1237201 part 1 - Use MOZ_ALWAYS_TRUE in nsScriptLoadHandler::TryDecodeRawData. r=yury (8f7496be23)
- Bug 1237201 part 2 - Handle Vector OOM in gfx/. r=jrmuizel,kats (d5e8bd3383)
- Bug 1237201 part 3 - Handle Vector OOM in StreamingLexer. r=njn (be383e35b4)
- Bug 1237201 part 4 - Handle Vector OOM in ipc/. r=billm (fe9a3bf25a)
- Bug 1237201 part 5 - Ignore Vector OOM in JSMainRuntimeCompartmentsReporter. r=njn (d0070c0636)
- Bug 1237201 part 6 - Handle Vector OOM in media/webrtc/. r=jesup (eab4e00735)
- Bug 1186491 - Splitting nsIPerformanceStats in two;r=froydnj (006b578345)
- Bug 1186491 - An API for watching slow performance alerts (xpcom-level);r=froydnj (4fcefd66f5)
- Bug 1237201 part 7 - Handle Vector OOM in nsPerformanceStats, telemetry. r=Yoric (6021b583ff)
- Bug 1237201 part 8 - Make fallible Vector methods MOZ_WARN_UNUSED_RESULT. r=jwalden (90144c2d35)
- Bug 1237201 part 9 - Fix remaining issues. r=nfroyd (25b86adb6d)
- Bug 1186491 - An API for watching slow performance alerts (js-level); r=felipe (f04d277c80)
- Bug 1200172 - AddonWatcher now discards data if the system is apparently too busy/just back from hibernation. r=mossop (66a3840b73)
- Bug 1205840 - Typo fixes in AddonWatcher.jsm. r=felipe (760df6764c)
- Bug 1186491 - Reworking AddonWatcher to use low-level performance watch API;r=mossop (81cc64263e)
- Bug 1200169 - Making the slow add-on watcher more tolerant;r=Felipe (fcf988d985)
- Bug 1157009 - Redesign about:performance. r=felipe (cacc590716)
- Bug 1189513 - Get rid of separation between e10s and non-e10s probes; r=felipe (7a6d996c93)
- Bug 1191327 - Recapitulates alerts in about:performance now. r=felipe (53ecc02da9)
- Bug 1189799 - Make sure that about:performance displays each add-on only once (front-end);r=felipe (1ee53a0410)
- Bug 1208747 - Move most of Stopwatch-related code to XPCOM-land (JS-level);r=felipe (84af14c20e)
- Bug 1229519: Fix miscellaneous parts of toolkit to pass eslint checks. r=MattN (00ce3585c5)
- Bug 1230735 - AddonWatcher.alerts is now a map;r=Felipe (81bbafbbd4)
- Bug 1241838 - Removing erroneous CPOW suffix, reworking buggy jank suffix;r=Felipe (020d6928e6)
- Bug 1175098 - Fix double-loading of PerformanceStats content script. r=mconley (fb1c499343)
- Bug 1189799 - Make sure that about:performance displays each add-on only once (back-end);r=felipe (1eac8258df)
- Bug 1221761 - Probe.prototype.release() now swallows NS_ERROR_NOT_AVAILABLE. r=felipe (ba1d0032a9)
- Bug 1142937 - AddonWatcher now communicates through nsIObserverService. r=felipe (ea2e7ccdaa)
- Bug 967873 - Test changes for async removeTab (r=Gijs) (dae5cbf835)
- more  missing parts of Bug 1132072 - Tab switch refactoring (r=mconley) (dc5e310537)
- Bug 1191460 Rebased patch and added userContextId to origin attributes. (r=tanvi,r=sicking) (723999e7fa)
- Bug 1239040 - Cleanup of DrawTargetSkia GetBitmapForSurface to use installPixels. r=jrmuizel (4016f4d734)
- Bug 1239040 - Cleanup of DrawTargetSkia Mask and MaskSurface. r=jrmuizel (908a44d47e)
- Bug 1239040 - Implement PushLayer for DrawTargetSkia. r=Bas (ae74697559)
- Bug 1246756 - part 1 - fix moz2d Skia usage for Skia m49 update. r=jrmuizel (5e4b0f41e3)
- Bug 1239040 - Allow usage of SkCanvas::getTopDevice in Skia. r=jrmuizel (19bdd2cecb)
- Bug 1239040 - Fix DrawTargetCairo/DrawTargetSkia LockBits and BorrowedXlibDrawable to work inside PushLayer. r=jrmuizel (b9ba04009b)
- Bug 1239040 - Cleanup of DrawTargetSkia CopySurface to avoid accessing bottom layer directly. r=jrmuizel (6690702507)
- Bug 1240437: Implement PushLayer and PopLayer for DrawTargetRecording. r=bas (22673a1b52)
- Bug 1220629 - Part 1: Add PushLayer/PopLayer API to DrawTarget baseclass. r=jrmuizel (c4b4315749)
- Bug 1220629 - Part 2: Prepare DrawTargetD2D1 for the possibilities of layers existing inside it. r=jrmuizel (f2a74151a8)
- Bug 1220629 - Part 3: Implement PushLayer/PopLayer API in cairo. r=jrmuizel (9a52965141)
- Bug 1220629 - Part 4: Allow gfxContext to use the native pushlayer implementations based on a pref. r=jrmuizel (f13b773ff3)
- Bug 1220629 - Part 5: Implement PushLayer/PopLayer API for Direct2D 1.1. r=jrmuizel (8a040648a2)
- Bug 1220629 - Part 6: Implement PushLayer/PopLayer API in several wrapper DT types. r=jrmuizel (cf76723216)
- Bug 1220629 - Part 7: Mark several reftests fuzzy. r=jrmuizel (a6deab2300)
- Bug 1220629 - Part 8: Enable native PushLayer/PopLayer by default on Windows and Linux. r=jrmuizel (eef18e1e3e)
- Bug 1234494 - part 1 - don't build in Skia GPU code if support is disabled, r=jrmuizel (4c74813077)
- Bug 1234494 - part 2 - disable Skia GPU support by default on certain *BSDs, r=glandium (6184133b33)
- Bug 1246756 - part 2 - update Skia moz.build for m49 update. r=jrmuizel (e0cf4ab953)
- Bug 1244454 - Fixed skia compilation on mingw. r=lsalzman (064a56e56e)
- Bug 1242044 - "layout/reftests/css-gradients/linear-zero-length-1 fails under Skia content". r=jmuizelaar (bee8f76e72)
- Bug 1242751 - fix assertion in SkLinearGradient. r=jmuizelaar (f5df5ed88f)
- Bug 1238795 - Fix SkGpuDevice::drawBitmapRect to always update clips. r=jrmuizel (05a9a6b10a)
- Bug 1230096 - fix GrAAConvexTessellator assertion. r=jrmuizel (18aef9bdcc)
- Bug 1237983 - Investigate and remove the Bagheera Client Implementation. r=gfritzsche (6de39c0e32)
- Bug 1246756 - part 3 - update Skia to m49 branch. r=jrmuizel (a02a53e368)
- Bug 1234526 - Remove services/healthreport. r=gfritzsche (bb0c567255)
- Bug 1234522 - Remove services/datareporting. r=gfritzsche (c7bfec7784)
- Bug 1211166 - Use AppConstants in SessionRecorder.jsm r=ted (4434996c34)
- Bug 1246756 - Cross compilation fixup. r=upstream (99e3e40ba1)
- Bug 1248228 - Build fix for SkOSFile_stdio on OpenBSD. r=jmuizelaar (bbb1eb7ac0)
- Bug 1250196 - Part 1: Import mozilla::Forward and mozilla::UniqePtr into the std namespace in a way that is compatible with libc++; r=lsalzman (ffeebcc133)
- Bug 1248851 part 4 - Mark UniquePtr::release() MOZ_WARN_UNUSED_RESULT. r=Waldo (f43cced74c)
- Bug 1250196 - Part 2: Rename UniquePtr::getDeleter() to get_deleter() in order to make it compatible with std::unique_ptr; r=froydnj (f8aeabfc9a)
- Bug 1248851 part 3 - Fix a potential double-free issue in indexedDB. r=sicking (4d13f5047b)
- Bug 1248851 part 2 - Remove redundant release() calls in indexedDB code. r=sicking (86d67ffad8)
- Bug 1239702 - Fix SK_ARM_HAS_NEON build config r=lsalzman (4233a57122)
- Bug 1245979 - make mfbt Function reference-counted so that it can be cheaply copied for compatibility with Skia. r=froydnj (bd69e9c07b)
- Bug 1245055 - Remove gfx/skia/Makefile.in. r=mshal (bf2c611f38)
- Bug 1232694 - fix typo in Compiler.h; r=botond (2b5abb9d2d)
- Bug 1228641 - Rename begin/size to aBegin/aSize to avoid shadow warnings; r=botond (9222809505)
- Bug 1248784 - Rename the existing AddRefTraits to ConstRemovingRefPtrTraits. r=froydnj (99d7b0ae1f)
- Bug 1248784 - Extract the AddRef/Release calls into a non-inner helper trait. r=froydnj (37243b6235)
- Bug 1248784 - Followup to add requested comment. r=froydnj DONTBUILD (0e870b586b)
- Bug 1242794 - make SkGrPixelRef::deepCopy preserve alpha type. r=jmuizelaar (0fb454c326)
- Bug 1201037 - (Linux) squash network-change events during 1000ms, r=mcmanus (087f57c44d)
- Bug 1235509 - Link monitor should not fire link change events for the refresh of the ipv6 lifetime. r=bagder (c507a319c4)
- Bug 1234548 - Don't send network change events if routes are changed. r=mcmanus, r=bagder (5cd0bc582e)
- Bug 1234548 - Remove unused variables. r=bustage (42df135fbf)
- Bug 1240515 - change allocator for addr and localaddr from malloc to new, since the smart pointer that is used uses delete operator. r=dragana (02f5d5433c)
- Bug 1241901 part 1 - Remove nsAutoPtr uses in nsNotifyAddrListener on Linux. r=bagder (f8696ad190)
- Bug 1241901 part 2 - Use intptr_t to pass bluetooth service class instead of a pointer to heap. r=shawnjohnjr (5c86a164fa)
- Bug 1241901 part 3 - Add IsMemberPointer and IsScalar type traits. r=froydnj (80747268bd)
- Bug 1243876 - fix ConvertibleTester to not cause incomplete type errors with UniquePtr and Skia. r=nfroyd (c5588dd270)
- Bug 1234736 - IonMonkey: Recover Math.imul as an int32 operation. r=h4writer (459b92c618)
- Bug 1228571 - Fix GenerateSeed to not leave seed uninitialized if reading from /dev/urandom fails. r=cpeterson (3be0a2816b)
- Bug 1233302: Don't crash if we can't open /dev/urandom; just fall back to PRMJ_Now. (d83ae5540a)
- Bug 1167248 - Call RtlGenRandom() instead of rand_s() to workaround crashes from injected third-party hooks. r=jandem (678e7a0056)
- Bug 1236619 Fix compilation failure with warnings-as-errors with some compilers. r=njn (043956881d)
- Bug 1167248 - Cross compilation fixup. (f4a34fb229)
2023-07-22 09:12:54 +08:00

629 lines
19 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;
static const wchar_t kDriverName[] = L"WINSPOOL";
//----------------------------------------------------------------------------------
// 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;
struct AutoFreeGlobalPrinters
{
~AutoFreeGlobalPrinters() {
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
}
};
//----------------------------------------------------------------------------------
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;
}
}
}
newSurface.forget(surface);
return NS_OK;
}
float
nsDeviceContextSpecWin::GetPrintingScale()
{
MOZ_ASSERT(mPrintSettings);
int32_t resolution;
mPrintSettings->GetResolution(&resolution);
return float(resolution) / 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;
}
#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) {
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
MOZ_ASSERT(psWin);
psWin->CopyToNative(pDevMode);
// 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(kDriverName);
::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;
}
//***********************************************************
// 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;
}
AutoFreeGlobalPrinters autoFreeGlobalPrinters;
devSpecWin->GetDataFromPrinter(aPrinterName);
LPDEVMODEW devmode;
devSpecWin->GetDevMode(devmode);
if (NS_WARN_IF(!devmode)) {
return NS_ERROR_FAILURE;
}
aPrintSettings->SetPrinterName(aPrinterName);
// We need to get information from the device as well.
HDC dc = ::CreateICW(kDriverName, aPrinterName, nullptr, devmode);
if (NS_WARN_IF(!dc)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPrintSettings);
MOZ_ASSERT(psWin);
psWin->CopyFromNative(dc, devmode);
::DeleteDC(dc);
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;
}