Bug 1669905 part 2: Add nsIPrintSettings APIs to handle the possibility that pages and sheets may have orthogonal orientation, in pages-per-sheet printouts. r=jfkthame

This patch does three things, all centered around these new APIs:

 (1) Add the APIs themselves -- some nsIPrintSettings methods to reason about
the sheet-orientation being potentially flipped to accomodate 2 and 6
pages-per-sheet.

 (2) Use these new APIs, where appropriate, in places where we previously used
the page-orientation to set up the platform-native print-settings objects and
print-target. Now, we'll use the *sheet* orientation instead of the page
orientation, to be sure we produce the appropriately-oriented platform-native
surfaces.  Also, for symmetry, this patch adds similar logic to the reverse
codepaths, where we update an existing nsIPrintSettings object based on a
platform-native print-settings object.

 (3) Update nsPrintJob's code that informs nsPresContext about the page-size.
This patch makes sure that this code uses the *page* size, rather than the
*sheet* size, in cases where they differ.  (The code that consumes this
nsPresContext::GetPageSize API, e.g. our CSS media-query code, really does want
the page size, not the sheet size.)

Differential Revision: https://phabricator.services.mozilla.com/D100372
This commit is contained in:
Daniel Holbert 2021-01-05 02:24:00 +00:00
Родитель 130ac8226e
Коммит 2cedf5494d
8 изменённых файлов: 116 добавлений и 16 удалений

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

@ -1823,7 +1823,19 @@ nsresult nsPrintJob::ReflowPrintObject(const UniquePtr<nsPrintObject>& aPO) {
adjSize.width, adjSize.height));
aPO->mPresShell->BeginObservingDocument();
aPO->mPresContext->SetPageSize(adjSize);
// Here, we inform nsPresContext of the page size. Note that 'adjSize' is
// *usually* the page size, but we need to check. Strictly speaking, adjSize
// is the *device output size*, which is really the dimensions of a "sheet"
// rather than a "page" (an important distinction in an N-pages-per-sheet
// scenario). For some pages-per-sheet values, the pages are orthogonal to
// the sheet; we adjust for that here by swapping the width with the height.
nsSize pageSize = adjSize;
if (printData->mPrintSettings->HasOrthogonalSheetsAndPages()) {
std::swap(pageSize.width, pageSize.height);
}
aPO->mPresContext->SetPageSize(pageSize);
int32_t p2a = aPO->mPresContext->DeviceContext()->AppUnitsPerDevPixel();
if (documentIsTopLevel && mIsCreatingPrintPreview) {

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

@ -194,7 +194,7 @@ NSPrintInfo* nsPrintSettingsX::CreateOrCopyPrintInfo(bool aWithScaling) {
NSPrintInfo* printInfo = [[NSPrintInfo sharedPrintInfo] copy];
NSSize paperSize;
if (mOrientation == kPortraitOrientation) {
if (GetSheetOrientation() == kPortraitOrientation) {
[printInfo setOrientation:NSPaperOrientationPortrait];
paperSize.width = CocoaPointsFromPaperSize(mPaperWidth);
paperSize.height = CocoaPointsFromPaperSize(mPaperHeight);
@ -309,7 +309,16 @@ NSPrintInfo* nsPrintSettingsX::CreateOrCopyPrintInfo(bool aWithScaling) {
void nsPrintSettingsX::SetPageFormatFromPrintInfo(const NSPrintInfo* aPrintInfo) {
NSSize paperSize = [aPrintInfo paperSize];
if ([aPrintInfo orientation] == NSPaperOrientationPortrait) {
const bool areSheetsOfPaperPortraitMode =
([aPrintInfo orientation] == NSPaperOrientationPortrait);
// If our MacOS print settings say that we're producing portrait-mode sheets
// of paper, then our page format must also be portrait-mode; unless we've
// got a pages-per-sheet value with orthogonal pages/sheets, in which case
// it's reversed.
const bool arePagesPortraitMode = (areSheetsOfPaperPortraitMode != HasOrthogonalSheetsAndPages());
if (arePagesPortraitMode) {
mOrientation = nsIPrintSettings::kPortraitOrientation;
SetPaperWidth(PaperSizeFromCocoaPoints(paperSize.width));
SetPaperHeight(PaperSizeFromCocoaPoints(paperSize.height));

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

@ -67,7 +67,7 @@ NS_IMPL_ISUPPORTS(nsDeviceContextSpecGTK, nsIDeviceContextSpec)
already_AddRefed<PrintTarget> nsDeviceContextSpecGTK::MakePrintTarget() {
double width, height;
mPrintSettings->GetEffectivePageSize(&width, &height);
mPrintSettings->GetEffectiveSheetSize(&width, &height);
// convert twips to points
width /= TWIPS_PER_POINT_FLOAT;
@ -117,8 +117,7 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecGTK::MakePrintTarget() {
return PrintTargetPDF::CreateOrNull(stream, size);
}
int32_t orientation;
mPrintSettings->GetOrientation(&orientation);
int32_t orientation = mPrintSettings->GetSheetOrientation();
return PrintTargetPS::CreateOrNull(
stream, size,
orientation == nsIPrintSettings::kPortraitOrientation

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

@ -71,8 +71,8 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecProxy::MakePrintTarget() {
MOZ_ASSERT(mRealDeviceContextSpec);
double width, height;
nsresult rv = mPrintSettings->GetEffectivePageSize(&width, &height);
if (NS_WARN_IF(NS_FAILED(rv)) || width <= 0 || height <= 0) {
mPrintSettings->GetEffectiveSheetSize(&width, &height);
if (width <= 0 || height <= 0) {
return nullptr;
}

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

@ -98,6 +98,41 @@ interface nsIPrintSettings : nsISupports
*/
void GetEffectivePageSize(out double aWidth, out double aHeight);
/**
* Get the printed sheet size in twips, considering both the user-specified
* orientation (portrait or landscape) *as well as* the fact that we might be
* inverting the orientation to account for 2 or 6 pages-per-sheet.
*
* This API will usually behave the same (& return the same thing) as
* GetEffectivePageSize, *except for* when we are printing with 2 or 6
* pages-per-sheet, in which case the return values (aWidth & aHeight) will
* be swapped with respect to what GetEffectivePageSize would return.
*
* Callers should use this method rather than GetEffectivePageSize when they
* really do want the size of the sheet of paper to be printed, rather than
* the possibly-"virtualized"-via-pages-per-sheet page size.
*/
[noscript, notxpcom, nostdcall] void GetEffectiveSheetSize(out double aWidth,
out double aHeight);
/**
* Get the orientation of a printed sheet. This is usually the same as the
* 'orientation' attribute (which is the orientation of individual pages),
* except when we're printing with 2 or 6 pages-per-sheet, in which case
* it'll be the opposite value.
*
* Note that this value is not independently settable. Its value is fully
* determined by the 'orientation' and 'numPagesPerSheet' attributes.
*/
[noscript, notxpcom, nostdcall] long GetSheetOrientation();
/**
* Convenience getter, which returns true IFF the sheet orientation and the
* page orientation are orthogonal. (In other words, returns true IFF we
* are printing with 2 or 6 pages-per-sheet.)
*/
[noscript, notxpcom, nostdcall] bool HasOrthogonalSheetsAndPages();
/**
* Makes a new copy
*/

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

@ -10,6 +10,7 @@
#include "nsPaper.h"
#include "nsReadableUtils.h"
#include "nsIPrintSession.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/RefPtr.h"
#define DEFAULT_MARGIN_WIDTH 0.5
@ -697,6 +698,32 @@ nsPrintSettings::GetEffectivePageSize(double* aWidth, double* aHeight) {
return NS_OK;
}
bool nsPrintSettings::HasOrthogonalSheetsAndPages() {
return mNumPagesPerSheet == 2 || mNumPagesPerSheet == 6;
}
void nsPrintSettings::GetEffectiveSheetSize(double* aWidth, double* aHeight) {
mozilla::DebugOnly<nsresult> rv = GetEffectivePageSize(aWidth, aHeight);
// Our GetEffectivePageSize impls only return NS_OK, so this should hold:
MOZ_ASSERT(NS_SUCCEEDED(rv), "Uh oh, GetEffectivePageSize failed");
if (HasOrthogonalSheetsAndPages()) {
std::swap(*aWidth, *aHeight);
}
}
int32_t nsPrintSettings::GetSheetOrientation() {
if (HasOrthogonalSheetsAndPages()) {
// Sheet orientation is rotated with respect to the page orientation.
return kLandscapeOrientation == mOrientation ? kPortraitOrientation
: kLandscapeOrientation;
}
// Sheet orientation is the same as the page orientation.
return mOrientation;
}
NS_IMETHODIMP
nsPrintSettings::SetPageRanges(const nsTArray<int32_t>& aPages) {
// Needs to be a set of (start, end) pairs.

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

@ -277,7 +277,7 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecWin::MakePrintTarget() {
mPrintSettings->GetToFileName(filename);
double width, height;
mPrintSettings->GetEffectivePageSize(&width, &height);
mPrintSettings->GetEffectiveSheetSize(&width, &height);
if (width <= 0 || height <= 0) {
return nullptr;
}

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

@ -176,9 +176,18 @@ void nsPrintSettingsWin::InitWithInitializer(
aSettings.mDevmodeWStorage.Elements())));
if (mDevMode->dmFields & DM_ORIENTATION) {
SetOrientation(mDevMode->dmOrientation == DMORIENT_PORTRAIT
? kPortraitOrientation
: kLandscapeOrientation);
const bool areSheetsOfPaperPortraitMode =
(mDevMode->dmOrientation == DMORIENT_PORTRAIT);
// If our Windows print settings say that we're producing portrait-mode
// sheets of paper, then our page format must also be portrait-mode; unless
// we've got a pages-per-sheet value with orthogonal pages/sheets, in which
// case it's reversed.
const bool arePagesPortraitMode =
(areSheetsOfPaperPortraitMode != HasOrthogonalSheetsAndPages());
SetOrientation(arePagesPortraitMode ? kPortraitOrientation
: kLandscapeOrientation);
}
if (mDevMode->dmFields & DM_COPIES) {
@ -315,9 +324,18 @@ void nsPrintSettingsWin::CopyFromNative(HDC aHdc, DEVMODEW* aDevMode) {
mIsInitedFromPrinter = true;
if (aDevMode->dmFields & DM_ORIENTATION) {
mOrientation = int32_t(aDevMode->dmOrientation == DMORIENT_PORTRAIT
? kPortraitOrientation
: kLandscapeOrientation);
const bool areSheetsOfPaperPortraitMode =
(aDevMode->dmOrientation == DMORIENT_PORTRAIT);
// If our Windows print settings say that we're producing portrait-mode
// sheets of paper, then our page format must also be portrait-mode; unless
// we've got a pages-per-sheet value with orthogonal pages/sheets, in which
// case it's reversed.
const bool arePagesPortraitMode =
(areSheetsOfPaperPortraitMode != HasOrthogonalSheetsAndPages());
mOrientation = int32_t(arePagesPortraitMode ? kLandscapeOrientation
: kPortraitOrientation);
}
if (aDevMode->dmFields & DM_COPIES) {
@ -447,7 +465,7 @@ void nsPrintSettingsWin::CopyToNative(DEVMODEW* aDevMode) {
}
// Setup Orientation
aDevMode->dmOrientation = mOrientation == kPortraitOrientation
aDevMode->dmOrientation = GetSheetOrientation() == kPortraitOrientation
? DMORIENT_PORTRAIT
: DMORIENT_LANDSCAPE;
aDevMode->dmFields |= DM_ORIENTATION;