Commit 003f6f3f authored by Daniel Hosseinian's avatar Daniel Hosseinian Committed by Commit Bot

PDF Viewer Update: Paint thumbnails

Send a request to the plugin upon detecting a 'paint-thumbnail' event.
Set the thumbnail's image data upon receiving a response.

Bug: 652400
Change-Id: I3e8faa5a1cc15fbd274c9e641078d6aa8de7ec8d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2412968
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: default avatardpapad <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811481}
parent 54deb981
......@@ -166,6 +166,7 @@ js_library("pdf_viewer") {
"elements:viewer-pdf-sidenav",
"elements:viewer-pdf-toolbar",
"elements:viewer-pdf-toolbar-new",
"elements:viewer-thumbnail",
"elements:viewer-zoom-toolbar",
"//ui/webui/resources/js:assert.m",
"//ui/webui/resources/js:event_tracker.m",
......
......@@ -54,6 +54,15 @@ let EmailMessageData;
*/
export let PrintPreviewParams;
/**
* @typedef {{
* imageData: !ArrayBuffer,
* width: number,
* height: number,
* }}
*/
let ThumbnailMessageData;
/**
* Creates a cryptographically secure pseudorandom 128-bit token.
* @return {string} The generated token as a hex string.
......@@ -318,6 +327,20 @@ export class PluginController extends ContentController {
return this.postMessageWithReply_({type: 'getSelectedText'});
}
/**
* Post a thumbnail request message to the plugin.
* @param {number} page
* @return {!Promise<!ThumbnailMessageData>} A promise holding the thumbnail
* response from the plugin.
*/
requestThumbnail(page) {
return this.postMessageWithReply_({
type: 'getThumbnail',
// The plugin references pages using zero-based indices.
page: page - 1,
});
}
/** @param {!PrintPreviewParams} printPreviewParams */
resetPrintPreviewMode(printPreviewParams) {
this.postMessage_({
......
......@@ -45,11 +45,11 @@ export class ViewerThumbnailBarElement extends PolymerElement {
}
const thumbnail = /** @type {!ViewerThumbnailElement} */ (entry.target);
if (thumbnail.hasAttribute('pending')) {
if (thumbnail.isPending()) {
return;
}
thumbnail.toggleAttribute('pending');
thumbnail.setPending();
this.dispatchEvent(new CustomEvent(
'paint-thumbnail',
{detail: thumbnail, bubbles: true, composed: true}));
......
......@@ -53,6 +53,16 @@ export class ViewerThumbnailElement extends PolymerElement {
const ctx = canvas.getContext('2d');
ctx.putImageData(imageData, 0, 0);
this.removeAttribute('pending');
}
/** @return {boolean} */
isPending() {
return this.hasAttribute('pending');
}
setPending() {
this.toggleAttribute('pending', true);
}
/** @private */
......
......@@ -72,6 +72,9 @@ export class PDFScriptingAPI {
/** @private {Function} */
this.selectedTextCallback_;
/** @private {Function} */
this.thumbnailCallback_;
/** @private {Function} */
this.keyEventCallback_;
......@@ -120,6 +123,19 @@ export class PDFScriptingAPI {
}
break;
}
case 'getThumbnailReply': {
const data =
/**
* @type {{imageData: !ArrayBuffer, width: number,
* height: number}}
*/
(event.data);
if (this.thumbnailCallback_) {
this.thumbnailCallback_(data);
this.thumbnailCallback_ = null;
}
break;
}
case 'sendKeyEvent':
if (this.keyEventCallback_) {
this.keyEventCallback_(DeserializeKeyEvent(event.data.keyEvent));
......@@ -253,6 +269,26 @@ export class PDFScriptingAPI {
return true;
}
/**
* Get the thumbnail data for a page. The data will be passed to a callback.
* May only be called after document loaded.
* @param {number} page the page number.
* @param {Function} callback a callback to be called with the thumbnail data.
* @return {boolean} true if the function is successful, false if there is an
* outstanding request for thumbnail data that has not been answered.
*/
getThumbnail(page, callback) {
if (this.thumbnailCallback_) {
return false;
}
this.thumbnailCallback_ = callback;
this.sendMessage_({
type: 'getThumbnail',
page: page,
});
return true;
}
/** Print the document. May only be called after document load. */
print() {
this.sendMessage_({type: 'print'});
......
......@@ -189,8 +189,8 @@
<viewer-pdf-sidenav id="sidenav"
active-page="[[pageNo_]]" bookmarks="[[bookmarks_]]"
doc-length="[[docLength_]]" on-change-page="onChangePage_"
on-change-page-and-xy="onChangePageAndXy_"
on-navigate="onNavigate_">
on-change-page-and-xy="onChangePageAndXy_" on-navigate="onNavigate_"
on-paint-thumbnail="onPaintThumbnail_">
</viewer-pdf-sidenav>
</div>
<div id="main">
......
......@@ -26,6 +26,7 @@ import {BrowserApi} from './browser_api.js';
import {Attachment, FittingType, Point, SaveRequestType} from './constants.js';
import {ViewerPdfSidenavElement} from './elements/viewer-pdf-sidenav.js';
import {ViewerPdfToolbarNewElement} from './elements/viewer-pdf-toolbar-new.js';
import {ViewerThumbnailElement} from './elements/viewer-thumbnail.js';
// <if expr="chromeos">
import {InkController} from './ink_controller.js';
//</if>
......@@ -59,6 +60,15 @@ let NavigateMessageData;
*/
let MetadataMessageData;
/**
* @typedef {{
* type: string,
* messageId: string,
* page: number,
* }}
*/
let GetThumbnailMessageData;
/**
* @typedef {{
* hasUnsavedChanges: (boolean|undefined),
......@@ -755,6 +765,13 @@ export class PDFViewerElement extends PDFViewerBaseElement {
this.pluginController.getSelectedText().then(
this.handleSelectedTextReply.bind(this));
break;
case 'getThumbnail':
const getThumbnailData =
/** @type {GetThumbnailMessageData} */ (message.data);
const page = getThumbnailData.page;
this.pluginController.requestThumbnail(page).then(
this.sendScriptingMessage.bind(this));
break;
case 'print':
this.pluginController.print();
break;
......@@ -1036,6 +1053,22 @@ export class PDFViewerElement extends PDFViewerBaseElement {
this.navigator_.navigate(e.detail.uri, disposition);
}
/**
* @param {!CustomEvent<!ViewerThumbnailElement>} e
* @private
*/
onPaintThumbnail_(e) {
assert(this.currentController === this.pluginController);
assert(!this.annotationMode_);
const thumbnail = e.detail;
this.pluginController.requestThumbnail(thumbnail.pageNumber)
.then(response => {
const array = new Uint8ClampedArray(response.imageData);
const imageData = new ImageData(array, response.width);
thumbnail.image = imageData;
});
}
/** @private */
onSidenavToggleClick_() {
assert(this.pdfViewerUpdateEnabled_);
......
......@@ -42,6 +42,21 @@ const tests = [
});
},
function testGetThumbnail() {
const client = new PDFScriptingAPI(window, window);
client.getThumbnail(1, data => {
const expectedWidth = 108 * window.devicePixelRatio;
const expectedHeight = 140 * window.devicePixelRatio;
chrome.test.assertEq(expectedWidth, data.width);
chrome.test.assertEq(expectedHeight, data.height);
const expectedByteLength = expectedWidth * expectedHeight * 4;
chrome.test.assertEq(expectedByteLength, data.imageData.byteLength);
chrome.test.succeed();
});
},
/**
* Test that the filename is used as the title.pdf.
*/
......
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