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") { ...@@ -166,6 +166,7 @@ js_library("pdf_viewer") {
"elements:viewer-pdf-sidenav", "elements:viewer-pdf-sidenav",
"elements:viewer-pdf-toolbar", "elements:viewer-pdf-toolbar",
"elements:viewer-pdf-toolbar-new", "elements:viewer-pdf-toolbar-new",
"elements:viewer-thumbnail",
"elements:viewer-zoom-toolbar", "elements:viewer-zoom-toolbar",
"//ui/webui/resources/js:assert.m", "//ui/webui/resources/js:assert.m",
"//ui/webui/resources/js:event_tracker.m", "//ui/webui/resources/js:event_tracker.m",
......
...@@ -54,6 +54,15 @@ let EmailMessageData; ...@@ -54,6 +54,15 @@ let EmailMessageData;
*/ */
export let PrintPreviewParams; export let PrintPreviewParams;
/**
* @typedef {{
* imageData: !ArrayBuffer,
* width: number,
* height: number,
* }}
*/
let ThumbnailMessageData;
/** /**
* Creates a cryptographically secure pseudorandom 128-bit token. * Creates a cryptographically secure pseudorandom 128-bit token.
* @return {string} The generated token as a hex string. * @return {string} The generated token as a hex string.
...@@ -318,6 +327,20 @@ export class PluginController extends ContentController { ...@@ -318,6 +327,20 @@ export class PluginController extends ContentController {
return this.postMessageWithReply_({type: 'getSelectedText'}); 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 */ /** @param {!PrintPreviewParams} printPreviewParams */
resetPrintPreviewMode(printPreviewParams) { resetPrintPreviewMode(printPreviewParams) {
this.postMessage_({ this.postMessage_({
......
...@@ -45,11 +45,11 @@ export class ViewerThumbnailBarElement extends PolymerElement { ...@@ -45,11 +45,11 @@ export class ViewerThumbnailBarElement extends PolymerElement {
} }
const thumbnail = /** @type {!ViewerThumbnailElement} */ (entry.target); const thumbnail = /** @type {!ViewerThumbnailElement} */ (entry.target);
if (thumbnail.hasAttribute('pending')) { if (thumbnail.isPending()) {
return; return;
} }
thumbnail.toggleAttribute('pending'); thumbnail.setPending();
this.dispatchEvent(new CustomEvent( this.dispatchEvent(new CustomEvent(
'paint-thumbnail', 'paint-thumbnail',
{detail: thumbnail, bubbles: true, composed: true})); {detail: thumbnail, bubbles: true, composed: true}));
......
...@@ -53,6 +53,16 @@ export class ViewerThumbnailElement extends PolymerElement { ...@@ -53,6 +53,16 @@ export class ViewerThumbnailElement extends PolymerElement {
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
ctx.putImageData(imageData, 0, 0); ctx.putImageData(imageData, 0, 0);
this.removeAttribute('pending');
}
/** @return {boolean} */
isPending() {
return this.hasAttribute('pending');
}
setPending() {
this.toggleAttribute('pending', true);
} }
/** @private */ /** @private */
......
...@@ -72,6 +72,9 @@ export class PDFScriptingAPI { ...@@ -72,6 +72,9 @@ export class PDFScriptingAPI {
/** @private {Function} */ /** @private {Function} */
this.selectedTextCallback_; this.selectedTextCallback_;
/** @private {Function} */
this.thumbnailCallback_;
/** @private {Function} */ /** @private {Function} */
this.keyEventCallback_; this.keyEventCallback_;
...@@ -120,6 +123,19 @@ export class PDFScriptingAPI { ...@@ -120,6 +123,19 @@ export class PDFScriptingAPI {
} }
break; 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': case 'sendKeyEvent':
if (this.keyEventCallback_) { if (this.keyEventCallback_) {
this.keyEventCallback_(DeserializeKeyEvent(event.data.keyEvent)); this.keyEventCallback_(DeserializeKeyEvent(event.data.keyEvent));
...@@ -253,6 +269,26 @@ export class PDFScriptingAPI { ...@@ -253,6 +269,26 @@ export class PDFScriptingAPI {
return true; 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 the document. May only be called after document load. */
print() { print() {
this.sendMessage_({type: 'print'}); this.sendMessage_({type: 'print'});
......
...@@ -189,8 +189,8 @@ ...@@ -189,8 +189,8 @@
<viewer-pdf-sidenav id="sidenav" <viewer-pdf-sidenav id="sidenav"
active-page="[[pageNo_]]" bookmarks="[[bookmarks_]]" active-page="[[pageNo_]]" bookmarks="[[bookmarks_]]"
doc-length="[[docLength_]]" on-change-page="onChangePage_" doc-length="[[docLength_]]" on-change-page="onChangePage_"
on-change-page-and-xy="onChangePageAndXy_" on-change-page-and-xy="onChangePageAndXy_" on-navigate="onNavigate_"
on-navigate="onNavigate_"> on-paint-thumbnail="onPaintThumbnail_">
</viewer-pdf-sidenav> </viewer-pdf-sidenav>
</div> </div>
<div id="main"> <div id="main">
......
...@@ -26,6 +26,7 @@ import {BrowserApi} from './browser_api.js'; ...@@ -26,6 +26,7 @@ import {BrowserApi} from './browser_api.js';
import {Attachment, FittingType, Point, SaveRequestType} from './constants.js'; import {Attachment, FittingType, Point, SaveRequestType} from './constants.js';
import {ViewerPdfSidenavElement} from './elements/viewer-pdf-sidenav.js'; import {ViewerPdfSidenavElement} from './elements/viewer-pdf-sidenav.js';
import {ViewerPdfToolbarNewElement} from './elements/viewer-pdf-toolbar-new.js'; import {ViewerPdfToolbarNewElement} from './elements/viewer-pdf-toolbar-new.js';
import {ViewerThumbnailElement} from './elements/viewer-thumbnail.js';
// <if expr="chromeos"> // <if expr="chromeos">
import {InkController} from './ink_controller.js'; import {InkController} from './ink_controller.js';
//</if> //</if>
...@@ -59,6 +60,15 @@ let NavigateMessageData; ...@@ -59,6 +60,15 @@ let NavigateMessageData;
*/ */
let MetadataMessageData; let MetadataMessageData;
/**
* @typedef {{
* type: string,
* messageId: string,
* page: number,
* }}
*/
let GetThumbnailMessageData;
/** /**
* @typedef {{ * @typedef {{
* hasUnsavedChanges: (boolean|undefined), * hasUnsavedChanges: (boolean|undefined),
...@@ -755,6 +765,13 @@ export class PDFViewerElement extends PDFViewerBaseElement { ...@@ -755,6 +765,13 @@ export class PDFViewerElement extends PDFViewerBaseElement {
this.pluginController.getSelectedText().then( this.pluginController.getSelectedText().then(
this.handleSelectedTextReply.bind(this)); this.handleSelectedTextReply.bind(this));
break; 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': case 'print':
this.pluginController.print(); this.pluginController.print();
break; break;
...@@ -1036,6 +1053,22 @@ export class PDFViewerElement extends PDFViewerBaseElement { ...@@ -1036,6 +1053,22 @@ export class PDFViewerElement extends PDFViewerBaseElement {
this.navigator_.navigate(e.detail.uri, disposition); 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 */ /** @private */
onSidenavToggleClick_() { onSidenavToggleClick_() {
assert(this.pdfViewerUpdateEnabled_); assert(this.pdfViewerUpdateEnabled_);
......
...@@ -42,6 +42,21 @@ const tests = [ ...@@ -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. * 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