Commit 118c536c authored by dstockwell's avatar dstockwell Committed by Commit Bot

pdf: Notify ink component about viewport changes in annotation mode

Bug: 902646
Change-Id: I397bc8d7043ce3a911bfdd5139381f4cae7599bf
Reviewed-on: https://chromium-review.googlesource.com/c/1393123
Commit-Queue: dstockwell <dstockwell@chromium.org>
Reviewed-by: default avatardsinclair <dsinclair@chromium.org>
Cr-Commit-Position: refs/heads/master@{#619571}
parent 0e988a8c
...@@ -14,4 +14,9 @@ js_library("viewer-ink-host") { ...@@ -14,4 +14,9 @@ js_library("viewer-ink-host") {
deps = [ deps = [
"//chrome/browser/resources/pdf/ink:ink_api", "//chrome/browser/resources/pdf/ink:ink_api",
] ]
externs_list = [
# TODO(dstockwell): Once viewport can be typechecked this can be replaced
# by a dep on viewport.
"externs.js",
]
} }
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
class Viewport {
/** @return {{width: number, height: number}} */
getDocumentDimensions() {}
}
/** @type {Object} */
Viewport.PAGE_SHADOW;
/** @type {number} */
Viewport.PAGE_SHADOW.top;
/** @type {number} */
Viewport.PAGE_SHADOW.left;
\ No newline at end of file
...@@ -28,9 +28,10 @@ Polymer({ ...@@ -28,9 +28,10 @@ Polymer({
* *
* @param {string} fileName The name of the PDF file. * @param {string} fileName The name of the PDF file.
* @param {ArrayBuffer} data The contents of the PDF document. * @param {ArrayBuffer} data The contents of the PDF document.
* @param {Viewport} viewport
* @return {!Promise} void value. * @return {!Promise} void value.
*/ */
load: async function(fileName, data) { load: async function(fileName, data, viewport) {
this.fileName_ = fileName; this.fileName_ = fileName;
this.state_ = State.LOADING; this.state_ = State.LOADING;
this.$.frame.src = 'ink/index.html'; this.$.frame.src = 'ink/index.html';
...@@ -38,9 +39,37 @@ Polymer({ ...@@ -38,9 +39,37 @@ Polymer({
this.ink_ = await this.$.frame.contentWindow.initInk(); this.ink_ = await this.$.frame.contentWindow.initInk();
this.ink_.setPDF(data); this.ink_.setPDF(data);
this.state_ = State.ACTIVE; this.state_ = State.ACTIVE;
this.viewportChanged(viewport);
this.style.visibility = 'visible'; this.style.visibility = 'visible';
}, },
viewportChanged: function(viewport) {
if (this.state_ != State.ACTIVE) {
return;
}
const pos = viewport.position;
const size = viewport.size;
const zoom = viewport.zoom;
const documentWidth = viewport.getDocumentDimensions(zoom).width * zoom;
// Adjust for page shadows.
const y = pos.y - Viewport.PAGE_SHADOW.top * zoom;
let x = pos.x - Viewport.PAGE_SHADOW.left * zoom;
// Center the document if the width is smaller than the viewport.
if (documentWidth < size.width) {
x += (documentWidth - size.width) / 2;
}
// Invert the Y-axis and convert Pixels to Points.
const pixelsToPoints = 72 / 96;
const scale = pixelsToPoints / zoom;
const camera = {
top: (-y) * scale,
left: (x) * scale,
right: (x + size.width) * scale,
bottom: (-y - size.height) * scale,
};
this.ink_.setCamera(camera);
},
/** /**
* @return {!Promise<{fileName: string, dataToSave: ArrayBuffer}>} * @return {!Promise<{fileName: string, dataToSave: ArrayBuffer}>}
* The serialized PDF document including any annotations that were made. * The serialized PDF document including any annotations that were made.
......
...@@ -7,7 +7,10 @@ ...@@ -7,7 +7,10 @@
* across an IFrame boundary. * across an IFrame boundary.
*/ */
class InkAPI { class InkAPI {
constructor() { constructor(embed) {
/** @type {*} */
this.embed_ = embed;
/** @type {ArrayBuffer} */ /** @type {ArrayBuffer} */
this.buffer_ = null; this.buffer_ = null;
} }
...@@ -25,12 +28,17 @@ class InkAPI { ...@@ -25,12 +28,17 @@ class InkAPI {
getPDF() { getPDF() {
return this.buffer_; return this.buffer_;
} }
setCamera(camera) {
this.embed_.setCamera(camera);
}
} }
/** /**
* @return {InkAPI} * @return {InkAPI}
*/ */
window.initInk = function() { window.initInk = function() {
// TODO(dstockwell): Create Ink embed and pass to InkAPI. // TODO(dstockwell): Create real Ink embed and pass to InkAPI.
return new InkAPI(); const embed = {setCamera() {}};
return new InkAPI(embed);
}; };
\ No newline at end of file
...@@ -827,6 +827,8 @@ PDFViewer.prototype = { ...@@ -827,6 +827,8 @@ PDFViewer.prototype = {
} }
} }
this.currentController_.viewportChanged();
const visiblePageDimensions = this.viewport_.getPageScreenRect(visiblePage); const visiblePageDimensions = this.viewport_.getPageScreenRect(visiblePage);
const size = this.viewport_.size; const size = this.viewport_.size;
this.sendScriptingMessage_({ this.sendScriptingMessage_({
...@@ -1141,6 +1143,11 @@ class ContentController { ...@@ -1141,6 +1143,11 @@ class ContentController {
*/ */
afterZoom() {} afterZoom() {}
/**
* Handles a change to the viewport.
*/
viewportChanged() {}
/** /**
* Rotates the document 90 degrees in the clockwise direction. * Rotates the document 90 degrees in the clockwise direction.
* @abstract * @abstract
...@@ -1213,6 +1220,11 @@ class InkController extends ContentController { ...@@ -1213,6 +1220,11 @@ class InkController extends ContentController {
// TODO(dstockwell): implement printing // TODO(dstockwell): implement printing
} }
/** @override */
viewportChanged() {
this.inkHost_.viewportChanged(this.viewport_);
}
/** @override */ /** @override */
save(requireResult) { save(requireResult) {
return this.inkHost_.saveDocument(); return this.inkHost_.saveDocument();
...@@ -1224,7 +1236,7 @@ class InkController extends ContentController { ...@@ -1224,7 +1236,7 @@ class InkController extends ContentController {
this.inkHost_ = document.createElement('viewer-ink-host'); this.inkHost_ = document.createElement('viewer-ink-host');
document.body.appendChild(this.inkHost_); document.body.appendChild(this.inkHost_);
} }
return this.inkHost_.load(filename, data); return this.inkHost_.load(filename, data, this.viewport_);
} }
/** @override */ /** @override */
......
...@@ -254,6 +254,18 @@ Viewport.prototype = { ...@@ -254,6 +254,18 @@ Viewport.prototype = {
}; };
}, },
/**
* Returns the document dimensions.
*
* @return {Point} A dictionary with the 'width'/'height' of the document.
*/
getDocumentDimensions: function() {
return {
width: this.documentDimensions_.width,
height: this.documentDimensions_.height
};
},
/** /**
* Returns true if the document needs scrollbars at the given zoom level. * Returns true if the document needs scrollbars at the given zoom level.
* *
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
function animationFrame() {
return new Promise(resolve => requestAnimationFrame(resolve));
}
function contentElement() { function contentElement() {
return document.elementFromPoint(innerWidth / 2, innerHeight / 2); return document.elementFromPoint(innerWidth / 2, innerHeight / 2);
...@@ -39,5 +42,39 @@ chrome.test.runTests([ ...@@ -39,5 +42,39 @@ chrome.test.runTests([
await viewer.loaded; await viewer.loaded;
chrome.test.assertEq('EMBED', contentElement().tagName); chrome.test.assertEq('EMBED', contentElement().tagName);
}); });
},
function testViewportToCameraConversion() {
testAsync(async () => {
// Enter annotation mode.
$('toolbar').toggleAnnotation();
await viewer.loaded;
const inkHost = contentElement();
const cameras = [];
inkHost.ink_.setCamera = camera => cameras.push(camera);
viewer.viewport_.setZoom(1);
viewer.viewport_.setZoom(2);
chrome.test.assertEq(2, cameras.length);
window.scrollTo(100, 100);
await animationFrame();
chrome.test.assertEq(3, cameras.length);
const expectations = [
{top: 44.25, left: -106.5, right: 718.5, bottom: -442.5},
{top: 23.25, left: -3.75, right: 408.75, bottom: -220.125},
{top: -14.25, left: 33.75, right: 446.25, bottom: -257.625},
];
for (const expectation of expectations) {
const actual = cameras.shift();
chrome.test.assertEq(expectation.top, actual.top);
chrome.test.assertEq(expectation.left, actual.left);
chrome.test.assertEq(expectation.bottom, actual.bottom);
chrome.test.assertEq(expectation.right, actual.right);
}
});
} }
]); ]);
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