Commit 6a84aeac authored by Hui Yingst's avatar Hui Yingst Committed by Commit Bot

Add supports for view destinations with 'FitR' fit type.

This CL adds supports for navigating to view destinations with fit
type 'FitR' (See table 151 in ISO 32000-1 standard for more details
about syntax of "FitR"), which focus the view on a rectangular window
specified by the FitR's coordinates parameters.

Bug: 55776,535978
Change-Id: I91353e7569830ba306b9d4cc31f32bfb9622c1df
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2391735Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarHenrique Nakashima <hnakashima@chromium.org>
Commit-Queue: Hui Yingst <nigi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#813977}
parent f4c11e33
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import {assert} from 'chrome://resources/js/assert.m.js'; import {assert} from 'chrome://resources/js/assert.m.js';
import {FittingType, NamedDestinationMessageData, Point} from './constants.js'; import {FittingType, NamedDestinationMessageData, Point} from './constants.js';
import {Size} from './viewport.js';
/** /**
* @typedef {{ * @typedef {{
...@@ -27,6 +28,28 @@ export class OpenPdfParamsParser { ...@@ -27,6 +28,28 @@ export class OpenPdfParamsParser {
constructor(getNamedDestinationCallback) { constructor(getNamedDestinationCallback) {
/** @private {!function(string):!Promise<!NamedDestinationMessageData>} */ /** @private {!function(string):!Promise<!NamedDestinationMessageData>} */
this.getNamedDestinationCallback_ = getNamedDestinationCallback; this.getNamedDestinationCallback_ = getNamedDestinationCallback;
/** @private {!Size} */
this.viewportDimensions_;
}
/**
* Calculate the zoom level needed for making viewport focus on a rectangular
* area in the PDF document.
* @param {!Size} size The dimensions of the rectangular area to be focused
* on.
* @return {number} The zoom level needed for focusing on the rectangular
* area. A zoom level of 0 indicates that the zoom level cannot be
* calculated with the given information.
* @private
*/
calculateRectZoomLevel_(size) {
if (size.height === 0 || size.width === 0) {
return 0;
}
return Math.min(
this.viewportDimensions_.height / size.height,
this.viewportDimensions_.width / size.width);
} }
/** /**
...@@ -129,7 +152,26 @@ export class OpenPdfParamsParser { ...@@ -129,7 +152,26 @@ export class OpenPdfParamsParser {
} }
if (viewMode === 'fitr' && viewModeComponents.length === 5) { if (viewMode === 'fitr' && viewModeComponents.length === 5) {
// TODO(crbug.com/535978): Add support for fit type "FitR" in nameddest. assert(this.viewportDimensions_ !== undefined);
let x1 = parseFloat(viewModeComponents[1]);
let y1 = parseFloat(viewModeComponents[2]);
let x2 = parseFloat(viewModeComponents[3]);
let y2 = parseFloat(viewModeComponents[4]);
if (!Number.isNaN(x1) && !Number.isNaN(y1) && !Number.isNaN(x2) &&
!Number.isNaN(y2)) {
if (x1 > x2) {
[x1, x2] = [x2, x1];
}
if (y1 > y2) {
[y1, y2] = [y2, y1];
}
const rectSize = {width: x2 - x1, height: y2 - y1};
params['position'] = {x: x1, y: y1};
const zoom = this.calculateRectZoomLevel_(rectSize);
if (zoom !== 0) {
params['zoom'] = zoom;
}
}
return params; return params;
} }
...@@ -160,6 +202,14 @@ export class OpenPdfParamsParser { ...@@ -160,6 +202,14 @@ export class OpenPdfParamsParser {
return params; return params;
} }
/**
* Store current viewport's dimensions.
* @param {!Size} dimensions
*/
setViewportDimensions(dimensions) {
this.viewportDimensions_ = dimensions;
}
/** /**
* @param {string} url that needs to be parsed. * @param {string} url that needs to be parsed.
* @return {boolean} Whether the toolbar UI element should be shown. * @return {boolean} Whether the toolbar UI element should be shown.
...@@ -184,7 +234,7 @@ export class OpenPdfParamsParser { ...@@ -184,7 +234,7 @@ export class OpenPdfParamsParser {
const urlParams = this.parseUrlParams_(url); const urlParams = this.parseUrlParams_(url);
if (urlParams.has('page')) { if (urlParams.has('page')) {
// |pageNumber| is 1-based, but goToPage() take a zero-based page number. // |pageNumber| is 1-based, but goToPage() take a zero-based page index.
const pageNumber = parseInt(urlParams.get('page'), 10); const pageNumber = parseInt(urlParams.get('page'), 10);
if (!Number.isNaN(pageNumber) && pageNumber > 0) { if (!Number.isNaN(pageNumber) && pageNumber > 0) {
params['page'] = pageNumber - 1; params['page'] = pageNumber - 1;
......
...@@ -370,6 +370,8 @@ export class PDFViewerBaseElement extends PolymerElement { ...@@ -370,6 +370,8 @@ export class PDFViewerBaseElement extends PolymerElement {
const visiblePage = this.viewport_.getMostVisiblePage(); const visiblePage = this.viewport_.getMostVisiblePage();
const visiblePageDimensions = this.viewport_.getPageScreenRect(visiblePage); const visiblePageDimensions = this.viewport_.getPageScreenRect(visiblePage);
const size = this.viewport_.size; const size = this.viewport_.size;
this.paramsParser.setViewportDimensions(size);
this.sendScriptingMessage({ this.sendScriptingMessage({
type: 'viewport', type: 'viewport',
pageX: visiblePageDimensions.x, pageX: visiblePageDimensions.x,
...@@ -426,6 +428,7 @@ export class PDFViewerBaseElement extends PolymerElement { ...@@ -426,6 +428,7 @@ export class PDFViewerBaseElement extends PolymerElement {
this.documentDimensions = documentDimensions; this.documentDimensions = documentDimensions;
this.isUserInitiatedEvent = false; this.isUserInitiatedEvent = false;
this.viewport_.setDocumentDimensions(this.documentDimensions); this.viewport_.setDocumentDimensions(this.documentDimensions);
this.paramsParser.setViewportDimensions(this.viewport_.size);
this.isUserInitiatedEvent = true; this.isUserInitiatedEvent = true;
} }
......
...@@ -32,7 +32,7 @@ export let LayoutOptions; ...@@ -32,7 +32,7 @@ export let LayoutOptions;
export let PartialPoint; export let PartialPoint;
/** @typedef {{width: number, height: number}} */ /** @typedef {{width: number, height: number}} */
let Size; export let Size;
/** @typedef {{x: number, y: number, width: number, height: number}} */ /** @typedef {{x: number, y: number, width: number, height: number}} */
let ViewportRect; let ViewportRect;
......
...@@ -13,6 +13,10 @@ const tests = [ ...@@ -13,6 +13,10 @@ const tests = [
*/ */
function testParamsParser() { function testParamsParser() {
const paramsParser = new OpenPdfParamsParser(function(destination) { const paramsParser = new OpenPdfParamsParser(function(destination) {
// Set the dummy viewport dimensions for calculating the zoom level for
// view destination with 'FitR' type.
paramsParser.setViewportDimensions({width: 300, height: 500});
if (destination === 'RU') { if (destination === 'RU') {
return Promise.resolve( return Promise.resolve(
{messageId: 'getNamedDestination_1', pageNumber: 26}); {messageId: 'getNamedDestination_1', pageNumber: 26});
...@@ -40,9 +44,27 @@ const tests = [ ...@@ -40,9 +44,27 @@ const tests = [
namedDestinationView: 'XYZ,111,null,1.7', namedDestinationView: 'XYZ,111,null,1.7',
pageNumber: 13 pageNumber: 13
}); });
} else if (destination === 'DestWithFitR') {
return Promise.resolve({
messageId: 'getNamedDestination_7',
namedDestinationView: 'FitR,20,100,120,300',
pageNumber: 0
});
} else if (destination === 'DestWithFitRReversedCoordinates') {
return Promise.resolve({
messageId: 'getNamedDestination_8',
namedDestinationView: 'FitR,120,300,20,100',
pageNumber: 0
});
} else if (destination === 'DestWithFitRWithNull') {
return Promise.resolve({
messageId: 'getNamedDestination_9',
namedDestinationView: 'FitR,null,100,100,300',
pageNumber: 0
});
} else { } else {
return Promise.resolve( return Promise.resolve(
{messageId: 'getNamedDestination_7', pageNumber: -1}); {messageId: 'getNamedDestination_10', pageNumber: -1});
} }
}); });
...@@ -142,6 +164,38 @@ const tests = [ ...@@ -142,6 +164,38 @@ const tests = [
chrome.test.assertEq(undefined, params.viewPosition); chrome.test.assertEq(undefined, params.viewPosition);
}); });
// Checking #nameddest=name with a nameddest that specifies the view fit
// type is "FitR" with multiple valid parameters.
paramsParser.getViewportFromUrlParams(
`${url}#nameddest=DestWithFitR`, function(params) {
chrome.test.assertEq(0, params.page);
chrome.test.assertEq(2.5, params.zoom);
chrome.test.assertEq(20, params.position.x);
chrome.test.assertEq(100, params.position.y);
chrome.test.assertEq(undefined, params.viewPosition);
});
// Checking #nameddest=name with a nameddest that specifies the view fit
// type is "FitR" with multiple valid parameters.
paramsParser.getViewportFromUrlParams(
`${url}#nameddest=DestWithFitRReversedCoordinates`, function(params) {
chrome.test.assertEq(0, params.page);
chrome.test.assertEq(2.5, params.zoom);
chrome.test.assertEq(20, params.position.x);
chrome.test.assertEq(100, params.position.y);
chrome.test.assertEq(undefined, params.viewPosition);
});
// Checking #nameddest=name with a nameddest that specifies the view fit
// type is "FitR" with one NULL parameters.
paramsParser.getViewportFromUrlParams(
`${url}#nameddest=DestWithFitRWithNull`, function(params) {
chrome.test.assertEq(0, params.page);
chrome.test.assertEq(undefined, params.zoom);
chrome.test.assertEq(undefined, params.position);
chrome.test.assertEq(undefined, params.viewPosition);
});
// Checking #view=Fit. // Checking #view=Fit.
paramsParser.getViewportFromUrlParams(`${url}#view=Fit`, function(params) { paramsParser.getViewportFromUrlParams(`${url}#view=Fit`, function(params) {
chrome.test.assertEq(FittingType.FIT_TO_PAGE, params.view); chrome.test.assertEq(FittingType.FIT_TO_PAGE, params.view);
...@@ -205,6 +259,20 @@ const tests = [ ...@@ -205,6 +259,20 @@ const tests = [
chrome.test.assertEq(undefined, params.view); chrome.test.assertEq(undefined, params.view);
chrome.test.assertEq(undefined, params.viewPosition); chrome.test.assertEq(undefined, params.viewPosition);
}); });
// Checking #view=[wrong parameter].
paramsParser.getViewportFromUrlParams(`${url}#view=FitR`, function(params) {
chrome.test.assertEq(undefined, params.view);
chrome.test.assertEq(undefined, params.viewPosition);
});
// Checking #view=[wrong parameter],[position].
paramsParser.getViewportFromUrlParams(
`${url}#view=FitR,20,100,120,300`, function(params) {
chrome.test.assertEq(undefined, params.zoom);
chrome.test.assertEq(undefined, params.position);
chrome.test.assertEq(undefined, params.view);
chrome.test.assertEq(undefined, params.viewPosition);
});
// Checking #toolbar=0 to disable the toolbar. // Checking #toolbar=0 to disable the toolbar.
chrome.test.assertFalse(paramsParser.shouldShowToolbar(`${url}#toolbar=0`)); chrome.test.assertFalse(paramsParser.shouldShowToolbar(`${url}#toolbar=0`));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment