Bug 1238964 Part 1: Hold new printable page sizes in print nsIPrintSettingsWin. r=jimm

This also holds the resolution in the print settings, so that we can start to
remove the access to the native Windows print devices in the child process.
This commit is contained in:
Bob Owen 2016-01-22 16:05:19 +00:00
parent edd98e60dd
commit eb34bd15b9
12 changed files with 164 additions and 58 deletions

View File

@ -75,6 +75,8 @@ struct PrintData {
/* Windows-specific things */
nsString driverName;
nsString deviceName;
double printableWidthInInches;
double printableHeightInInches;
bool isFramesetDocument;
bool isFramesetFrameSelected;
bool isIFrameSelected;

View File

@ -987,13 +987,15 @@ ShowNativePrintDialog(HWND aHWnd,
// Transfer the settings from the native data to the PrintSettings
LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode);
if (devMode == nullptr) {
if (!devMode || !prntdlg.hDC) {
::GlobalFree(hGlobalDevMode);
return NS_ERROR_FAILURE;
}
psWin->SetDevMode(devMode); // copies DevMode
SetPrintSettingsFromDevMode(aPrintSettings, devMode);
::GlobalUnlock(prntdlg.hDevMode);
psWin->CopyFromNative(prntdlg.hDC);
::DeleteDC(prntdlg.hDC);
#if defined(DEBUG_rods) || defined(DEBUG_dcone)
bool printSelection = prntdlg.Flags & PD_SELECTION;

View File

@ -680,38 +680,13 @@ nsDeviceContext::CalcPrintingSize()
return (mWidth > 0 && mHeight > 0);
}
bool inPoints = true;
gfxSize size(0, 0);
switch (mPrintingSurface->GetType()) {
#ifdef XP_WIN
case gfxSurfaceType::Win32Printing:
{
inPoints = false;
HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
if (!dc)
dc = GetDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET));
size.width = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, HORZRES)/mPrintingScale, AppUnitsPerDevPixel());
size.height = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, VERTRES)/mPrintingScale, AppUnitsPerDevPixel());
mDepth = (uint32_t)::GetDeviceCaps(dc, BITSPIXEL);
if (dc != reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC())
ReleaseDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET), dc);
break;
}
#endif
default:
size = mPrintingSurface->GetSize();
}
if (inPoints) {
// For printing, CSS inches and physical inches are identical
// so it doesn't matter which we use here
mWidth = NSToCoordRound(float(size.width) * AppUnitsPerPhysicalInch() / 72);
mHeight = NSToCoordRound(float(size.height) * AppUnitsPerPhysicalInch() / 72);
} else {
mWidth = NSToIntRound(size.width);
mHeight = NSToIntRound(size.height);
}
gfxSize size = mPrintingSurface->GetSize();
// For printing, CSS inches and physical inches are identical
// so it doesn't matter which we use here
mWidth = NSToCoordRound(size.width * AppUnitsPerPhysicalInch()
/ POINTS_PER_INCH_FLOAT);
mHeight = NSToCoordRound(size.height * AppUnitsPerPhysicalInch()
/ POINTS_PER_INCH_FLOAT);
return (mWidth > 0 && mHeight > 0);
}

View File

@ -310,6 +310,15 @@ gfxWindowsSurface::EndPage()
const mozilla::gfx::IntSize
gfxWindowsSurface::GetSize() const
{
if (mForPrinting) {
// On Windows we need to use the printable area of the page.
float width = (::GetDeviceCaps(mDC, HORZRES) * POINTS_PER_INCH_FLOAT)
/ ::GetDeviceCaps(mDC, LOGPIXELSX);
float height = (::GetDeviceCaps(mDC, VERTRES) * POINTS_PER_INCH_FLOAT)
/ ::GetDeviceCaps(mDC, LOGPIXELSY);
return mozilla::gfx::IntSize(width, height);
}
if (!mSurfaceValid) {
NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?");
return mozilla::gfx::IntSize(-1, -1);

View File

@ -67,15 +67,8 @@ nsDeviceContextSpecProxy::GetSurfaceForPrinter(gfxASurface** aSurface)
MOZ_ASSERT(aSurface);
MOZ_ASSERT(mRealDeviceContextSpec);
// The real device context may need to have created a real printing surface
// even though we're not using it directly.
nsresult rv = mRealDeviceContextSpec->GetSurfaceForPrinter(aSurface);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
double width, height;
rv = mPrintSettings->GetEffectivePageSize(&width, &height);
nsresult rv = mPrintSettings->GetEffectivePageSize(&width, &height);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -13,11 +13,12 @@
* Native types
*/
[ptr] native nsDevMode(DEVMODEW);
native nsHdc(HDC);
/**
* Simplified PrintSettings for Windows interface
*/
[scriptable, uuid(f13b225d-473e-4372-b11f-b6dff9fe0c5b)]
[scriptable, uuid(57c22cc1-311f-44c3-bb49-4d1cf411a3b5)]
interface nsIPrintSettingsWin : nsISupports
{
@ -39,4 +40,22 @@ interface nsIPrintSettingsWin : nsISupports
[noscript] attribute nsDevMode devMode;
/**
* On Windows we use the printable width and height for the printing surface.
* We don't want to have to create native print device contexts in the content
* process, so we need to store these in the settings.
* Storing in Inches is most convenient as they are retrieved from the device
* using fields which are in pixels and pixels per inch.
* Note these are stored in portrait format to ensure that we can take account
* of our own changes to the orientation print setting.
*/
[noscript] attribute double printableWidthInInches;
[noscript] attribute double printableHeightInInches;
/**
* Copy relevant print settings from native Windows device.
*
* @param hdc HDC to copy from
*/
[notxpcom] void copyFromNative(in nsHdc hdc);
};

View File

@ -214,6 +214,8 @@ nsPrintOptions::SerializeToPrintData(nsIPrintSettings* aSettings,
// assertions).
// data->driverName() default-initializes
// data->deviceName() default-initializes
data->printableWidthInInches() = 0;
data->printableHeightInInches() = 0;
data->isFramesetDocument() = false;
data->isFramesetFrameSelected() = false;
data->isIFrameSelected() = false;

View File

@ -49,6 +49,8 @@ PRLogModuleInfo * kWidgetPrintingLogMod = PR_NewLogModule("printing-widget");
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
@ -81,6 +83,13 @@ protected:
GlobalPrinters GlobalPrinters::mGlobalPrinters;
nsTArray<LPWSTR>* GlobalPrinters::mPrinters = nullptr;
struct AutoFreeGlobalPrinters
{
~AutoFreeGlobalPrinters() {
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
}
};
//******************************************************
// Define native paper sizes
@ -321,7 +330,6 @@ NS_IMETHODIMP nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface **surface
}
}
mPrintingSurface = newSurface;
newSurface.forget(surface);
return NS_OK;
}
@ -329,11 +337,11 @@ NS_IMETHODIMP nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface **surface
float
nsDeviceContextSpecWin::GetPrintingScale()
{
MOZ_ASSERT(mPrintingSurface);
MOZ_ASSERT(mPrintSettings);
HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
int32_t OSVal = GetDeviceCaps(dc, LOGPIXELSY);
return float(OSVal) / GetDPI();
int32_t resolution;
mPrintSettings->GetResolution(&resolution);
return float(resolution) / GetDPI();
}
//----------------------------------------------------------------------------------
@ -512,7 +520,7 @@ nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings*
SetDeviceName(aName);
SetDriverName(L"WINSPOOL");
SetDriverName(kDriverName);
::ClosePrinter(hPrinter);
rv = NS_OK;
@ -657,18 +665,30 @@ nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterNam
return NS_ERROR_FAILURE;
}
AutoFreeGlobalPrinters autoFreeGlobalPrinters;
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);
if (NS_WARN_IF(!devmode)) {
return NS_ERROR_FAILURE;
}
// Free them, we won't need them for a while
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
aPrintSettings->SetPrinterName(aPrinterName);
nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(aPrintSettings, devmode);
// 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);
::DeleteDC(dc);
return NS_OK;
}

View File

@ -69,7 +69,6 @@ protected:
LPDEVMODEW mDevMode;
nsCOMPtr<nsIPrintSettings> mPrintSettings;
RefPtr<gfxASurface> mPrintingSurface;
};

View File

@ -67,10 +67,12 @@ nsPrintOptionsWin::SerializeToPrintData(nsIPrintSettings* aSettings,
free(deviceName);
free(driverName);
// When creating the print dialog on Windows, the parent creates a DEVMODE
// which is used to convey print settings to the Windows printing backend.
// We don't, therefore, want or care about DEVMODEs sent up from the child.
// When creating the print dialog on Windows, we only need to send certain
// print settings information from the parent to the child not vice versa.
if (XRE_IsParentProcess()) {
psWin->GetPrintableWidthInInches(&data->printableWidthInInches());
psWin->GetPrintableHeightInInches(&data->printableHeightInInches());
// A DEVMODE can actually be of arbitrary size. If it turns out that it'll
// make our IPC message larger than the limit, then we'll error out.
LPDEVMODEW devModeRaw;
@ -118,6 +120,9 @@ nsPrintOptionsWin::DeserializeToPrintSettings(const PrintData& data,
psWin->SetDeviceName(data.deviceName().get());
psWin->SetDriverName(data.driverName().get());
psWin->SetPrintableWidthInInches(data.printableWidthInInches());
psWin->SetPrintableHeightInInches(data.printableHeightInInches());
nsXPIDLString printerName;
settings->GetPrinterName(getter_Copies(printerName));

View File

@ -111,6 +111,82 @@ NS_IMETHODIMP nsPrintSettingsWin::SetDevMode(DEVMODEW * aDevMode)
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::GetPrintableWidthInInches(double* aPrintableWidthInInches)
{
MOZ_ASSERT(aPrintableWidthInInches);
*aPrintableWidthInInches = mPrintableWidthInInches;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::SetPrintableWidthInInches(double aPrintableWidthInInches)
{
mPrintableWidthInInches = aPrintableWidthInInches;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::GetPrintableHeightInInches(double* aPrintableHeightInInches)
{
MOZ_ASSERT(aPrintableHeightInInches);
*aPrintableHeightInInches = mPrintableHeightInInches;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::SetPrintableHeightInInches(double aPrintableHeightInInches)
{
mPrintableHeightInInches = aPrintableHeightInInches;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsWin::GetEffectivePageSize(double *aWidth, double *aHeight)
{
// If printable page size not set, fall back to nsPrintSettings.
if (mPrintableWidthInInches == 0l || mPrintableHeightInInches == 0l) {
return nsPrintSettings::GetEffectivePageSize(aWidth, aHeight);
}
if (mOrientation == kPortraitOrientation) {
*aWidth = NS_INCHES_TO_TWIPS(mPrintableWidthInInches);
*aHeight = NS_INCHES_TO_TWIPS(mPrintableHeightInInches);
} else {
*aHeight = NS_INCHES_TO_TWIPS(mPrintableWidthInInches);
*aWidth = NS_INCHES_TO_TWIPS(mPrintableHeightInInches);
}
return NS_OK;
}
void
nsPrintSettingsWin::CopyFromNative(HDC aHdc)
{
MOZ_ASSERT(aHdc);
// On Windows we currently create a surface using the printable area of the
// page and don't set the unwriteable [sic] margins. Using the unwriteable
// margins doesn't appear to work on Windows, but I am not sure if this is a
// bug elsewhere in our code or a Windows quirk.
int32_t printableWidthInDots = GetDeviceCaps(aHdc, HORZRES);
int32_t printableHeightInDots = GetDeviceCaps(aHdc, VERTRES);
int32_t widthDPI = GetDeviceCaps(aHdc, LOGPIXELSX);
int32_t heightDPI = GetDeviceCaps(aHdc, LOGPIXELSY);
// Keep these values in portrait format, so we can reflect our own changes
// to mOrientation.
if (mOrientation == kPortraitOrientation) {
mPrintableWidthInInches = double(printableWidthInDots) / widthDPI;
mPrintableHeightInInches = double(printableHeightInDots) / heightDPI;
} else {
mPrintableHeightInInches = double(printableWidthInDots) / widthDPI;
mPrintableWidthInInches = double(printableHeightInDots) / heightDPI;
}
// Using Y to match existing code, X DPI should be the same for printing.
mResolution = heightDPI;
}
//-------------------------------------------
nsresult
nsPrintSettingsWin::_Clone(nsIPrintSettings **_retval)

View File

@ -42,12 +42,16 @@ public:
*/
nsPrintSettingsWin& operator=(const nsPrintSettingsWin& rhs);
NS_IMETHOD GetEffectivePageSize(double *aWidth, double *aHeight) override;
protected:
void CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW *& aOutDevMode);
wchar_t* mDeviceName;
wchar_t* mDriverName;
LPDEVMODEW mDevMode;
double mPrintableWidthInInches = 0l;
double mPrintableHeightInInches = 0l;
};