Bug 1657550 - Rewrite nsDocumentViewer::PrintPreviewScrollToPage. r=emilio

This change consists of;

1) Use switch statement for the given PrintPreview Navigation type.
2) Simply iterate over the children of nsPageSequenceFrame for
   PRINTPREVIEW_GOTO_PAGENUM
3) Use GetCurrentSheetFrameAndPageNumber for PRINTPREVIEW_PREV_PAGE and
   PRINTPREVIEW_NEXT_PAGE so that it should now match
   printPreviewCurrentPageNumber
   (that means the edge case where the current scroll position is in
    the gap between pages has been fixed by this change)
4) Scroll to the position where the target frame is positioned at the center of
   the print preview scroll port in the cases of PRINTPREVIEW_PREV_PAGE,
   PRINTPREVIEW_NEXT_PAGE and PRINTPREVIEW_GOTO_PAGENUM

4) is a bit debatable but it can be now easily modified by changing
ComputeScrollPositionFrameAtCenter later if it turns out the current way is not
reasonable.

Differential Revision: https://phabricator.services.mozilla.com/D87548
This commit is contained in:
Hiroyuki Ikezoe 2020-08-19 22:50:54 +00:00
Родитель 1f301a0a87
Коммит 50f539d050
2 изменённых файлов: 134 добавлений и 61 удалений

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

@ -3318,6 +3318,39 @@ nsresult nsDocumentViewer::PrintPreviewScrollToPageForOldUI(int16_t aType,
return NS_OK;
}
static const nsIFrame* GetTargetPageFrame(int32_t aTargetPageNum,
nsPageSequenceFrame* aSequenceFrame) {
MOZ_ASSERT(aTargetPageNum > 0 &&
aTargetPageNum < aSequenceFrame->PrincipalChildList().GetLength());
int32_t pageNum = 1;
for (const nsIFrame* sheetFrame : aSequenceFrame->PrincipalChildList()) {
if (pageNum == aTargetPageNum) {
return sheetFrame;
}
pageNum++;
}
MOZ_ASSERT_UNREACHABLE("Should have found the target frame");
return nullptr;
}
// Calculate the scroll position where the center of |aFrame| is positioned at
// the center of |aScrollable|'s scroll port for the print preview.
// So what we do for that is;
// 1) Calculate the position of the center of |aFrame| in the print preview
// coordinates.
// 2) Reduce the half height of the scroll port from the result of 1.
static nscoord ScrollPositionForFrame(
const nsIFrame* aFrame, nsIScrollableFrame* aScrollable,
float aPreviewScale) {
// Note that even if the computed scroll position is out of the range of
// the scroll port, it gets clamped in nsIScrollableFrame::ScrollTo.
return nscoord(aPreviewScale * aFrame->GetRect().Center().y -
float(aScrollable->GetScrollPortRect().height) / 2.0f);
}
//----------------------------------------------------------------------
NS_IMETHODIMP
nsDocumentViewer::PrintPreviewScrollToPage(int16_t aType, int32_t aPageNum) {
@ -3332,78 +3365,63 @@ nsDocumentViewer::PrintPreviewScrollToPage(int16_t aType, int32_t aPageNum) {
mPrintJob->GetPrintPreviewPresShell()->GetRootScrollFrameAsScrollable();
if (!sf) return NS_OK;
// Figure where we are currently scrolled to
nsPoint currentScrollPosition = sf->GetScrollPosition();
// Check to see if we can short circut scrolling to the top
if (aType == nsIWebBrowserPrint::PRINTPREVIEW_HOME ||
(aType == nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM &&
aPageNum == 1)) {
sf->ScrollTo(nsPoint(currentScrollPosition.x, 0), ScrollMode::Instant);
return NS_OK;
}
// If it is "End" then just scroll to the `scrollTopMax` position.
if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) {
sf->ScrollTo(nsPoint(currentScrollPosition.x, sf->GetScrollRange().YMost()),
ScrollMode::Instant);
return NS_OK;
}
// in PP mPrtPreview->mPrintObject->mSeqFrame is null
auto [seqFrame, pageCount] = mPrintJob->GetSeqFrameAndCountPages();
Unused << pageCount;
if (!seqFrame) {
return NS_ERROR_FAILURE;
}
int32_t pageNum = 1;
nsIFrame* fndPageFrame = nullptr;
nsIFrame* currentPage = nullptr;
float previewScale = seqFrame->GetPrintPreviewScale();
// Now, locate the current page we are on and
// and the page of the page number
for (nsIFrame* sheetFrame : seqFrame->PrincipalChildList()) {
nsRect sheetRect = sheetFrame->GetRect();
if (sheetRect.Contains(sheetRect.x, currentScrollPosition.y)) {
currentPage = sheetFrame;
}
if (pageNum == aPageNum) {
fndPageFrame = sheetFrame;
nsPoint dest = sf->GetScrollPosition();
switch (aType) {
case nsIWebBrowserPrint::PRINTPREVIEW_HOME:
dest.y = 0;
break;
case nsIWebBrowserPrint::PRINTPREVIEW_END:
dest.y = sf->GetScrollRange().YMost();
break;
case nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE:
case nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE: {
auto [currentFrame, currentPageNumber] =
GetCurrentSheetFrameAndPageNumber();
Unused << currentPageNumber;
if (!currentFrame) {
return NS_OK;
}
const nsIFrame* targetFrame = nullptr;
if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) {
targetFrame = currentFrame->GetPrevInFlow();
} else {
targetFrame = currentFrame->GetNextInFlow();
}
if (!targetFrame) {
return NS_OK;
}
dest.y = ScrollPositionForFrame(targetFrame, sf, previewScale);
break;
}
pageNum++;
case nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM: {
if (aPageNum < 0 || aPageNum > pageCount) {
return NS_ERROR_INVALID_ARG;
}
const nsIFrame* targetFrame = GetTargetPageFrame(aPageNum, seqFrame);
MOZ_ASSERT(targetFrame);
dest.y = ScrollPositionForFrame(targetFrame, sf, previewScale);
break;
}
default:
return NS_ERROR_INVALID_ARG;
break;
}
if (aType == nsIWebBrowserPrint::PRINTPREVIEW_PREV_PAGE) {
if (currentPage) {
fndPageFrame = currentPage->GetPrevInFlow();
if (!fndPageFrame) {
return NS_OK;
}
} else {
return NS_OK;
}
} else if (aType == nsIWebBrowserPrint::PRINTPREVIEW_NEXT_PAGE) {
if (currentPage) {
fndPageFrame = currentPage->GetNextInFlow();
if (!fndPageFrame) {
return NS_OK;
}
} else {
return NS_OK;
}
} else { // If we get here we are doing "GoTo"
if (aPageNum < 0 || aPageNum > pageCount) {
return NS_OK;
}
}
sf->ScrollTo(dest, ScrollMode::Instant);
if (fndPageFrame) {
nscoord newYPosn = nscoord(seqFrame->GetPrintPreviewScale() *
fndPageFrame->GetPosition().y);
sf->ScrollTo(nsPoint(currentScrollPosition.x, newYPosn),
ScrollMode::Instant);
}
return NS_OK;
}

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

@ -581,6 +581,61 @@ async function runTest20() {
async function runTest21() {
await compareFiles("data:text/html,<audio controls>", "data:text/html,<audio controls >"); // Shouldn't crash.
requestAnimationFrame(() => setTimeout(runTest22));
}
async function runTest22() {
// Similar to above runtTest20 but more specific for the logic to choose
// the current page in the new print preview UI so this test works only
// in the new print preview.
if (SpecialPowers.getBoolPref("print.tab_modal.enabled")) {
frameElts[0].contentDocument.body.innerHTML =
'<style>div { page-break-after: always; max-height: 2in; }</style>' +
'<div>1</div>' +
'<div>2</div>' +
'<div>3</div>' +
'<div>4</div>' +
'<div>5</div>' +
'<div>6</div>' +
'<div>7</div>' +
'<div>8</div>' +
'<div>9</div>' +
'<div>10</div>';
await printpreview({ settings: { paperHeight: 3 } });
const initialCurrentPageNumber = gWbp.printPreviewCurrentPageNumber;
// NOTE: In the cases the page hight is less than the half height of the
// print preview scroll port height, the initial current page number will
// not be 1.
ok(initialCurrentPageNumber >= 1,
"The initial current page number should be equal to or greater than 1");
const totalPageNumber = gWbp.printPreviewNumPages;
for (let n = initialCurrentPageNumber;
n <= totalPageNumber - initialCurrentPageNumber;
n++) {
// Scroll to the given page number and check the current page number.
gWbp.printPreviewScrollToPage(
Ci.nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM, n);
is(gWbp.printPreviewCurrentPageNumber, n,
`The current page number should be ${n}`);
}
// Scroll to the end of the scroll region.
gWbp.printPreviewScrollToPage(Ci.nsIWebBrowserPrint.PRINTPREVIEW_END, 0);
// Same as the initial current page number case, the last page might not
// be the current page if the page height is less than the half of the scroll
// port.
is(gWbp.printPreviewCurrentPageNumber,
totalPageNumber + 1 - initialCurrentPageNumber,
`The current page number should be ${totalPageNumber + 1 - initialCurrentPageNumber}`);
exitprintpreview();
}
finish();
}