Bug 221706 - Use unwritable region when printing on Windows. r=jimm

Read more information from the printing device to setup the unwritable region.
Translate the printing context's coordinate system so that the point (0,0)
refers to the top-left of the physical paper instead of the top-left of the
printable region.

MozReview-Commit-ID: 9ei2FgEUDyO

--HG--
extra : rebase_source : c2e2715f47499538035101a285152eca2aba3202
This commit is contained in:
Brendan Dahl 2018-03-28 17:13:10 -07:00
Родитель 6499399d3c
Коммит 0cc1c8ec9b
10 изменённых файлов: 84 добавлений и 10 удалений

Просмотреть файл

@ -204,6 +204,7 @@ nsDeviceContext::nsDeviceContext()
mAppUnitsPerDevPixel(-1), mAppUnitsPerDevPixelAtUnitFullZoom(-1),
mAppUnitsPerPhysicalInch(-1),
mFullZoom(1.0f), mPrintingScale(1.0f),
mPrintingTranslate(gfxPoint(0, 0)),
mIsCurrentlyPrintingDoc(false)
#ifdef DEBUG
, mIsInitialized(false)
@ -276,6 +277,7 @@ nsDeviceContext::SetDPI(double* aScale)
if (mDeviceContextSpec) {
dpi = mDeviceContextSpec->GetDPI();
mPrintingScale = mDeviceContextSpec->GetPrintingScale();
mPrintingTranslate = mDeviceContextSpec->GetPrintingTranslate();
mAppUnitsPerDevPixelAtUnitFullZoom =
NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
} else {
@ -414,6 +416,7 @@ nsDeviceContext::CreateRenderingContextCommon(bool aWantReferenceContext)
MOZ_ASSERT(pContext); // already checked draw target above
gfxMatrix transform;
transform.PreTranslate(mPrintingTranslate);
if (mPrintTarget->RotateNeededForLandscape()) {
// Rotate page 90 degrees to draw landscape page on portrait paper
IntSize size = mPrintTarget->GetSize();

Просмотреть файл

@ -305,6 +305,7 @@ private:
int32_t mAppUnitsPerPhysicalInch;
float mFullZoom;
float mPrintingScale;
gfxPoint mPrintingTranslate;
RefPtr<nsFontCache> mFontCache;
nsCOMPtr<nsIWidget> mWidget;

Просмотреть файл

@ -26,14 +26,16 @@ PrintTargetWindows::PrintTargetWindows(cairo_surface_t* aCairoSurface,
/* static */ already_AddRefed<PrintTargetWindows>
PrintTargetWindows::CreateOrNull(HDC aDC)
{
// Figure out the cairo surface size - Windows we need to use the printable
// area of the page. Note: we only scale the printing using the LOGPIXELSY,
// Figure out the paper size, the actual surface size will be the printable
// area which is likely smaller, but the size here is later used to create the
// draw target where the full page size is needed.
// Note: we only scale the printing using the LOGPIXELSY,
// so we use that when calculating the surface width as well as the height.
int32_t heightDPI = ::GetDeviceCaps(aDC, LOGPIXELSY);
float width =
(::GetDeviceCaps(aDC, HORZRES) * POINTS_PER_INCH_FLOAT) / heightDPI;
(::GetDeviceCaps(aDC, PHYSICALWIDTH) * POINTS_PER_INCH_FLOAT) / heightDPI;
float height =
(::GetDeviceCaps(aDC, VERTRES) * POINTS_PER_INCH_FLOAT) / heightDPI;
(::GetDeviceCaps(aDC, PHYSICALHEIGHT) * POINTS_PER_INCH_FLOAT) / heightDPI;
IntSize size = IntSize::Truncate(width, height);
if (!Factory::CheckSurfaceSize(size)) {

Просмотреть файл

@ -133,6 +133,14 @@ nsDeviceContextSpecProxy::GetPrintingScale()
return mRealDeviceContextSpec->GetPrintingScale();
}
gfxPoint
nsDeviceContextSpecProxy::GetPrintingTranslate()
{
MOZ_ASSERT(mRealDeviceContextSpec);
return mRealDeviceContextSpec->GetPrintingTranslate();
}
NS_IMETHODIMP
nsDeviceContextSpecProxy::BeginDocument(const nsAString& aTitle,
const nsAString& aPrintToFileName,

Просмотреть файл

@ -38,6 +38,8 @@ public:
float GetPrintingScale() final;
gfxPoint GetPrintingTranslate() final;
NS_IMETHOD BeginDocument(const nsAString& aTitle,
const nsAString& aPrintToFileName,

Просмотреть файл

@ -69,6 +69,13 @@ public:
*/
virtual float GetPrintingScale() { return 1.0f; }
/**
* Override to return something other than the default.
*
* @return the point to translate the context to for printing.
*/
virtual gfxPoint GetPrintingTranslate() { return gfxPoint(0, 0); }
NS_IMETHOD BeginDocument(const nsAString& aTitle,
const nsAString& aPrintToFileName,
int32_t aStartPage,

Просмотреть файл

@ -321,6 +321,22 @@ nsDeviceContextSpecWin::GetPrintingScale()
return float(resolution) / GetDPI();
}
gfxPoint
nsDeviceContextSpecWin::GetPrintingTranslate()
{
// The underlying surface on windows is the size of the printable region. When
// the region is smaller than the actual paper size the (0, 0) coordinate
// refers top-left of that unwritable region. To instead have (0, 0) become
// the top-left of the actual paper, translate it's coordinate system by the
// unprintable region's width.
double marginTop, marginLeft;
mPrintSettings->GetUnwriteableMarginTop(&marginTop);
mPrintSettings->GetUnwriteableMarginLeft(&marginLeft);
int32_t resolution;
mPrintSettings->GetResolution(&resolution);
return gfxPoint(-marginLeft * resolution, -marginTop * resolution);
}
//----------------------------------------------------------------------------------
void nsDeviceContextSpecWin::SetDeviceName(const nsAString& aDeviceName)
{

Просмотреть файл

@ -38,6 +38,7 @@ public:
float GetDPI() final;
float GetPrintingScale() final;
gfxPoint GetPrintingTranslate() final;
void GetDriverName(nsAString& aDriverName) const { aDriverName = mDriverName; }
void GetDeviceName(nsAString& aDeviceName) const { aDeviceName = mDeviceName; }

Просмотреть файл

@ -275,6 +275,41 @@ nsPrintSettingsWin::GetEffectivePageSize(double *aWidth, double *aHeight)
return NS_OK;
}
void
nsPrintSettingsWin::InitUnwriteableMargin(HDC aHdc)
{
int32_t pixelsPerInchY = GetDeviceCaps(aHdc, LOGPIXELSY);
int32_t pixelsPerInchX = GetDeviceCaps(aHdc, LOGPIXELSX);
int32_t marginLeft = GetDeviceCaps(aHdc, PHYSICALOFFSETX);
int32_t marginTop = GetDeviceCaps(aHdc, PHYSICALOFFSETY);
double marginLeftInch = double(marginLeft) / pixelsPerInchX;
double marginTopInch = double(marginTop) / pixelsPerInchY;
int32_t printableAreaWidth = GetDeviceCaps(aHdc, HORZRES);
int32_t printableAreaHeight = GetDeviceCaps(aHdc, VERTRES);
double printableAreaWidthInch = double(printableAreaWidth) / pixelsPerInchX;
double printableAreaHeightInch = double(printableAreaHeight) / pixelsPerInchY;
int32_t physicalWidth = GetDeviceCaps(aHdc, PHYSICALWIDTH);
int32_t physicalHeight = GetDeviceCaps(aHdc, PHYSICALHEIGHT);
double physicalWidthInch = double(physicalWidth) / pixelsPerInchX;
double physicalHeightInch = double(physicalHeight) / pixelsPerInchY;
double marginBottomInch = physicalHeightInch - printableAreaHeightInch - marginTopInch;
double marginRightInch = physicalWidthInch - printableAreaWidthInch - marginLeftInch;
mUnwriteableMargin.SizeTo(
NS_INCHES_TO_INT_TWIPS(marginTopInch),
NS_INCHES_TO_INT_TWIPS(marginRightInch),
NS_INCHES_TO_INT_TWIPS(marginBottomInch),
NS_INCHES_TO_INT_TWIPS(marginLeftInch)
);
}
void
nsPrintSettingsWin::CopyFromNative(HDC aHdc, DEVMODEW* aDevMode)
{
@ -311,6 +346,8 @@ nsPrintSettingsWin::CopyFromNative(HDC aHdc, DEVMODEW* aDevMode)
mPaperData = -1;
}
InitUnwriteableMargin(aHdc);
// The length and width in DEVMODE are always in tenths of a millimeter.
double sizeUnitToTenthsOfAmm =
10L * (mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT : 1L);
@ -326,14 +363,10 @@ nsPrintSettingsWin::CopyFromNative(HDC aHdc, DEVMODEW* aDevMode)
mPaperWidth = -1l;
}
// 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.
// Note: we only scale the printing using the LOGPIXELSY, so we use that
// when calculating the surface width as well as the height.
int32_t printableWidthInDots = GetDeviceCaps(aHdc, HORZRES);
int32_t printableHeightInDots = GetDeviceCaps(aHdc, VERTRES);
int32_t printableWidthInDots = GetDeviceCaps(aHdc, PHYSICALWIDTH);
int32_t printableHeightInDots = GetDeviceCaps(aHdc, PHYSICALHEIGHT);
int32_t heightDPI = GetDeviceCaps(aHdc, LOGPIXELSY);
// Keep these values in portrait format, so we can reflect our own changes

Просмотреть файл

@ -46,6 +46,7 @@ public:
protected:
void CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW *& aOutDevMode);
void InitUnwriteableMargin(HDC aHdc);
nsString mDeviceName;
nsString mDriverName;