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 @@
import {assert} from 'chrome://resources/js/assert.m.js';
import {FittingType, NamedDestinationMessageData, Point} from './constants.js';
import {Size} from './viewport.js';
/**
* @typedef {{
......@@ -27,6 +28,28 @@ export class OpenPdfParamsParser {
constructor(getNamedDestinationCallback) {
/** @private {!function(string):!Promise<!NamedDestinationMessageData>} */
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 {
}
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;
}
......@@ -160,6 +202,14 @@ export class OpenPdfParamsParser {
return params;
}
/**
* Store current viewport's dimensions.
* @param {!Size} dimensions
*/
setViewportDimensions(dimensions) {
this.viewportDimensions_ = dimensions;
}
/**
* @param {string} url that needs to be parsed.
* @return {boolean} Whether the toolbar UI element should be shown.
......@@ -184,7 +234,7 @@ export class OpenPdfParamsParser {
const urlParams = this.parseUrlParams_(url);
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);
if (!Number.isNaN(pageNumber) && pageNumber > 0) {
params['page'] = pageNumber - 1;
......
......@@ -370,6 +370,8 @@ export class PDFViewerBaseElement extends PolymerElement {
const visiblePage = this.viewport_.getMostVisiblePage();
const visiblePageDimensions = this.viewport_.getPageScreenRect(visiblePage);
const size = this.viewport_.size;
this.paramsParser.setViewportDimensions(size);
this.sendScriptingMessage({
type: 'viewport',
pageX: visiblePageDimensions.x,
......@@ -426,6 +428,7 @@ export class PDFViewerBaseElement extends PolymerElement {
this.documentDimensions = documentDimensions;
this.isUserInitiatedEvent = false;
this.viewport_.setDocumentDimensions(this.documentDimensions);
this.paramsParser.setViewportDimensions(this.viewport_.size);
this.isUserInitiatedEvent = true;
}
......
......@@ -32,7 +32,7 @@ export let LayoutOptions;
export let PartialPoint;
/** @typedef {{width: number, height: number}} */
let Size;
export let Size;
/** @typedef {{x: number, y: number, width: number, height: number}} */
let ViewportRect;
......
......@@ -13,6 +13,10 @@ const tests = [
*/
function testParamsParser() {
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') {
return Promise.resolve(
{messageId: 'getNamedDestination_1', pageNumber: 26});
......@@ -40,9 +44,27 @@ const tests = [
namedDestinationView: 'XYZ,111,null,1.7',
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 {
return Promise.resolve(
{messageId: 'getNamedDestination_7', pageNumber: -1});
{messageId: 'getNamedDestination_10', pageNumber: -1});
}
});
......@@ -142,6 +164,38 @@ const tests = [
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.
paramsParser.getViewportFromUrlParams(`${url}#view=Fit`, function(params) {
chrome.test.assertEq(FittingType.FIT_TO_PAGE, params.view);
......@@ -205,6 +259,20 @@ const tests = [
chrome.test.assertEq(undefined, params.view);
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.
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