Commit 74d64c91 authored by Hui Yingst's avatar Hui Yingst Committed by Commit Bot

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

This CL adds supports for navigating to view destinations with fit type
'XYZ' (See table 151 in ISO 32000-1 standard for more details about
syntax of "XYZ"), which specifies the coordinates of the page's origin
inside the view window and the zoom factor of the page.

Bug: 55776,748852
Change-Id: I4f449f006ec9dda4be282aea75c2a6e36a35b87e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2390997Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarRebekah Potter <rbpotter@chromium.org>
Commit-Queue: Hui Yingst <nigi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810919}
parent 7247ce79
...@@ -31,6 +31,7 @@ export const FittingType = { ...@@ -31,6 +31,7 @@ export const FittingType = {
/** /**
* @typedef {{ * @typedef {{
* messageId: string, * messageId: string,
* namedDestinationView: (string|undefined),
* pageNumber: number, * pageNumber: number,
* }} * }}
*/ */
......
...@@ -10,7 +10,8 @@ import {FittingType, NamedDestinationMessageData, Point} from './constants.js'; ...@@ -10,7 +10,8 @@ import {FittingType, NamedDestinationMessageData, Point} from './constants.js';
* url: (string|undefined), * url: (string|undefined),
* zoom: (number|undefined), * zoom: (number|undefined),
* view: (!FittingType|undefined), * view: (!FittingType|undefined),
* viewPosition: (!Point|undefined) * viewPosition: (!Point|undefined),
* position: (!Object|undefined),
* }} * }}
*/ */
let OpenPdfParams; let OpenPdfParams;
...@@ -99,6 +100,42 @@ export class OpenPdfParamsParser { ...@@ -99,6 +100,42 @@ export class OpenPdfParamsParser {
return params; return params;
} }
/**
* Parse view parameters which come from nameddest.
* @param {string} paramValue view value.
* @return {!OpenPdfParams} Map with view parameters.
* @private
*/
parseNameddestViewParam_(paramValue) {
const viewModeComponents = paramValue.toLowerCase().split(',');
const viewMode = viewModeComponents[0];
const params = {};
if (viewMode === 'xyz' && viewModeComponents.length === 4) {
const x = parseFloat(viewModeComponents[1]);
const y = parseFloat(viewModeComponents[2]);
const zoom = parseFloat(viewModeComponents[3]);
// If |x|, |y| or |zoom| is NaN, the values of the current positions and
// zoom level are retained.
if (!Number.isNaN(x) && !Number.isNaN(y) && !Number.isNaN(zoom)) {
params['position'] = {x: x, y: y};
// A zoom of 0 should be treated as a zoom of null (See table 151 in ISO
// 32000-1 standard for more details about syntax of "XYZ".
if (zoom !== 0) {
params['zoom'] = zoom;
}
}
return params;
}
if (viewMode === 'fitr' && viewModeComponents.length === 5) {
// TODO(crbug.com/535978): Add support for fit type "FitR" in nameddest.
return params;
}
return this.parseViewParam_(paramValue);
}
/** /**
* Parse the parameters encoded in the fragment of a URL. * Parse the parameters encoded in the fragment of a URL.
* @param {string} url to parse * @param {string} url to parse
...@@ -173,6 +210,12 @@ export class OpenPdfParamsParser { ...@@ -173,6 +210,12 @@ export class OpenPdfParamsParser {
if (data.pageNumber !== -1) { if (data.pageNumber !== -1) {
params.page = data.pageNumber; params.page = data.pageNumber;
} }
if (data.namedDestinationView) {
Object.assign(
params,
this.parseNameddestViewParam_(
/** @type {string} */ (data.namedDestinationView)));
}
callback(params); callback(params);
}); });
} else { } else {
......
...@@ -22,9 +22,27 @@ const tests = [ ...@@ -22,9 +22,27 @@ const tests = [
} else if (destination === 'UY') { } else if (destination === 'UY') {
return Promise.resolve( return Promise.resolve(
{messageId: 'getNamedDestination_3', pageNumber: 22}); {messageId: 'getNamedDestination_3', pageNumber: 22});
} else if (destination === 'DestWithXYZ') {
return Promise.resolve({
messageId: 'getNamedDestination_4',
namedDestinationView: 'XYZ,111,222,1.7',
pageNumber: 10
});
} else if (destination === 'DestWithXYZAtZoom0') {
return Promise.resolve({
messageId: 'getNamedDestination_5',
namedDestinationView: 'XYZ,111,222,0',
pageNumber: 10
});
} else if (destination === 'DestWithXYZWithNullParameter') {
return Promise.resolve({
messageId: 'getNamedDestination_6',
namedDestinationView: 'XYZ,111,null,1.7',
pageNumber: 13
});
} else { } else {
return Promise.resolve( return Promise.resolve(
{messageId: 'getNamedDestination_4', pageNumber: -1}); {messageId: 'getNamedDestination_7', pageNumber: -1});
} }
}); });
...@@ -92,6 +110,38 @@ const tests = [ ...@@ -92,6 +110,38 @@ const tests = [
chrome.test.assertEq(200, params.position.y); chrome.test.assertEq(200, params.position.y);
}); });
// Checking #nameddest=name with a nameddest that specifies the view fit
// type is "XYZ" with multiple valid parameters.
paramsParser.getViewportFromUrlParams(
`${url}#nameddest=DestWithXYZ`, function(params) {
chrome.test.assertEq(10, params.page);
chrome.test.assertEq(1.7, params.zoom);
chrome.test.assertEq(111, params.position.x);
chrome.test.assertEq(222, params.position.y);
chrome.test.assertEq(undefined, params.viewPosition);
});
// Checking #nameddest=name with a nameddest that specifies the view fit
// type is "XYZ" with a zoom parameter of 0.
paramsParser.getViewportFromUrlParams(
`${url}#nameddest=DestWithXYZAtZoom0`, function(params) {
chrome.test.assertEq(10, params.page);
chrome.test.assertEq(undefined, params.zoom);
chrome.test.assertEq(111, params.position.x);
chrome.test.assertEq(222, params.position.y);
chrome.test.assertEq(undefined, params.viewPosition);
});
// Checking #nameddest=name with a nameddest that specifies the view fit
// type is "XYZ" and one of its parameters is null.
paramsParser.getViewportFromUrlParams(
`${url}#nameddest=DestWithXYZWithNullParameter`, function(params) {
chrome.test.assertEq(13, 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);
...@@ -142,6 +192,19 @@ const tests = [ ...@@ -142,6 +192,19 @@ 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=XYZ`, function(params) {
chrome.test.assertEq(undefined, params.view);
chrome.test.assertEq(undefined, params.viewPosition);
});
// Checking #view=[wrong parameter],[position].
paramsParser.getViewportFromUrlParams(
`${url}#view=XYZ,111,222,1.7`, 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`));
......
...@@ -211,6 +211,7 @@ constexpr char kJSGetNamedDestination[] = "namedDestination"; ...@@ -211,6 +211,7 @@ constexpr char kJSGetNamedDestination[] = "namedDestination";
// Reply with the page number of the named destination (Plugin -> Page) // Reply with the page number of the named destination (Plugin -> Page)
constexpr char kJSGetNamedDestinationReplyType[] = "getNamedDestinationReply"; constexpr char kJSGetNamedDestinationReplyType[] = "getNamedDestinationReply";
constexpr char kJSNamedDestinationPageNumber[] = "pageNumber"; constexpr char kJSNamedDestinationPageNumber[] = "pageNumber";
constexpr char kJSNamedDestinationView[] = "namedDestinationView";
// Selecting text in document (Plugin -> Page) // Selecting text in document (Plugin -> Page)
constexpr char kJSSetIsSelectingType[] = "setIsSelecting"; constexpr char kJSSetIsSelectingType[] = "setIsSelecting";
...@@ -1652,6 +1653,16 @@ void OutOfProcessInstance::HandleGetNamedDestinationMessage( ...@@ -1652,6 +1653,16 @@ void OutOfProcessInstance::HandleGetNamedDestinationMessage(
reply.Set(pp::Var(kJSNamedDestinationPageNumber), reply.Set(pp::Var(kJSNamedDestinationPageNumber),
named_destination ? static_cast<int>(named_destination->page) : -1); named_destination ? static_cast<int>(named_destination->page) : -1);
reply.Set(pp::Var(kJSMessageId), dict.Get(pp::Var(kJSMessageId)).AsString()); reply.Set(pp::Var(kJSMessageId), dict.Get(pp::Var(kJSMessageId)).AsString());
// Handle named destination view.
if (named_destination && !named_destination->view.empty()) {
std::ostringstream view_stream;
view_stream << named_destination->view;
for (unsigned long i = 0; i < named_destination->num_params; ++i)
view_stream << "," << named_destination->params[i];
reply.Set(pp::Var(kJSNamedDestinationView), view_stream.str());
}
PostMessage(reply); PostMessage(reply);
} }
......
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