Add event handler for downloading attachments.
This CL adds event handlers for downloading attachments, and replace |attachmentToken| with |messageId| in |SaveAttachmentDataMessageData| since now the controller uses |messageId| to locate the resolver. Bug: 177188 Change-Id: I9f88c916d5eff997a2b03c91bf646c8dfa6a66e7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2337408 Reviewed-by: Lei Zhang <thestig@chromium.org> Reviewed-by: Rebekah Potter <rbpotter@chromium.org> Commit-Queue: Hui Yingst <nigi@chromium.org> Cr-Commit-Position: refs/heads/master@{#807665}
This commit is contained in:
chrome/browser/resources/pdf
pdf
@ -13,6 +13,15 @@ import {PartialPoint, Viewport} from './viewport.js';
|
|||||||
/** @typedef {{type: string, messageId: (string|undefined)}} */
|
/** @typedef {{type: string, messageId: (string|undefined)}} */
|
||||||
export let MessageData;
|
export let MessageData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* type: string,
|
||||||
|
* dataToSave: Array,
|
||||||
|
* messageId: string,
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
let SaveAttachmentDataMessageData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* dataToSave: Array,
|
* dataToSave: Array,
|
||||||
@ -103,6 +112,14 @@ export class ContentController {
|
|||||||
*/
|
*/
|
||||||
save(requestType) {}
|
save(requestType) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the attachment at a certain index be saved.
|
||||||
|
* @param {number} index The index of the attachment to be saved.
|
||||||
|
* @return {Promise<{type: string, dataToSave: Array, messageId: string}>}
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
saveAttachment(index) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads PDF document from `data` activates UI.
|
* Loads PDF document from `data` activates UI.
|
||||||
* @param {string} fileName
|
* @param {string} fileName
|
||||||
@ -358,6 +375,14 @@ export class PluginController extends ContentController {
|
|||||||
return resolver.promise;
|
return resolver.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
saveAttachment(index) {
|
||||||
|
return this.postMessageWithReply_({
|
||||||
|
type: 'saveAttachment',
|
||||||
|
attachmentIndex: index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
async load(fileName, data) {
|
async load(fileName, data) {
|
||||||
const url = URL.createObjectURL(new Blob([data]));
|
const url = URL.createObjectURL(new Blob([data]));
|
||||||
|
@ -95,6 +95,9 @@ export class InkController extends ContentController {
|
|||||||
return this.inkHost_.saveDocument();
|
return this.inkHost_.saveDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
saveAttachment(index) {}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
undo() {
|
undo() {
|
||||||
this.inkHost_.undo();
|
this.inkHost_.undo();
|
||||||
|
@ -874,6 +874,62 @@ export class PDFViewerElement extends PDFViewerBaseElement {
|
|||||||
this.canSerializeDocument_ = metadata.canSerializeDocument;
|
this.canSerializeDocument_ = metadata.canSerializeDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event handler for when the browser tells the PDF Viewer to perform a
|
||||||
|
* save on the attachment at a certain index. Callers of this function must
|
||||||
|
* be responsible for checking whether the attachment size is valid for
|
||||||
|
* downloading.
|
||||||
|
* @param {!CustomEvent<number>} e The event which contains the index of
|
||||||
|
* attachment to be downloaded.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async onSaveAttachment_(e) {
|
||||||
|
const index = e.detail;
|
||||||
|
const size = this.attachments_[index].size;
|
||||||
|
assert(size !== -1);
|
||||||
|
|
||||||
|
let dataArray = [];
|
||||||
|
// If the attachment size is 0, skip requesting the backend to fetch the
|
||||||
|
// attachment data.
|
||||||
|
if (size !== 0) {
|
||||||
|
const result = await this.currentController.saveAttachment(index);
|
||||||
|
|
||||||
|
// Cap the PDF attachment size at 100 MB. This cap should be kept in sync
|
||||||
|
// with and is also enforced in pdf/out_of_process_instance.cc.
|
||||||
|
const MAX_FILE_SIZE = 100 * 1000 * 1000;
|
||||||
|
const bufView = new Uint8Array(result.dataToSave);
|
||||||
|
assert(
|
||||||
|
bufView.length <= MAX_FILE_SIZE,
|
||||||
|
`File too large to be saved: ${bufView.length} bytes.`);
|
||||||
|
assert(
|
||||||
|
bufView.length === size,
|
||||||
|
`Received attachment size does not match its expected value: ${
|
||||||
|
size} bytes.`);
|
||||||
|
|
||||||
|
dataArray = [result.dataToSave];
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob(dataArray);
|
||||||
|
const fileName = this.attachments_[index].name;
|
||||||
|
chrome.fileSystem.chooseEntry(
|
||||||
|
{type: 'saveFile', suggestedName: fileName}, entry => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
if (chrome.runtime.lastError.message !== 'User cancelled') {
|
||||||
|
console.error(
|
||||||
|
'chrome.fileSystem.chooseEntry failed: ' +
|
||||||
|
chrome.runtime.lastError.message);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entry.createWriter(writer => {
|
||||||
|
writer.write(blob);
|
||||||
|
// Unblock closing the window now that the user has saved
|
||||||
|
// successfully.
|
||||||
|
chrome.mimeHandlerPrivate.setShowBeforeUnloadDialog(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event handler for when the browser tells the PDF Viewer to perform a
|
* An event handler for when the browser tells the PDF Viewer to perform a
|
||||||
* save.
|
* save.
|
||||||
@ -1009,7 +1065,7 @@ export class PDFViewerElement extends PDFViewerBaseElement {
|
|||||||
entry => {
|
entry => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
if (chrome.runtime.lastError.message !== 'User cancelled') {
|
if (chrome.runtime.lastError.message !== 'User cancelled') {
|
||||||
console.log(
|
console.error(
|
||||||
'chrome.fileSystem.chooseEntry failed: ' +
|
'chrome.fileSystem.chooseEntry failed: ' +
|
||||||
chrome.runtime.lastError.message);
|
chrome.runtime.lastError.message);
|
||||||
}
|
}
|
||||||
|
@ -132,10 +132,9 @@ constexpr char kJSPrintType[] = "print";
|
|||||||
// Save attachment (Page -> Plugin)
|
// Save attachment (Page -> Plugin)
|
||||||
constexpr char kJSSaveAttachmentType[] = "saveAttachment";
|
constexpr char kJSSaveAttachmentType[] = "saveAttachment";
|
||||||
constexpr char kJSAttachmentIndex[] = "attachmentIndex";
|
constexpr char kJSAttachmentIndex[] = "attachmentIndex";
|
||||||
constexpr char kJSAttachmentToken[] = "attachmentToken";
|
|
||||||
// Save attachment data (Plugin -> Page)
|
// Save attachment data (Plugin -> Page)
|
||||||
constexpr char kJSSaveAttachmentDataType[] = "saveAttachmentData";
|
constexpr char kJSSaveAttachmentDataType[] = "saveAttachmentData";
|
||||||
constexpr char kJSAttachmentDataToSave[] = "attachmentDataToSave";
|
constexpr char kJSAttachmentDataToSave[] = "dataToSave";
|
||||||
// Save (Page -> Plugin)
|
// Save (Page -> Plugin)
|
||||||
constexpr char kJSSaveType[] = "save";
|
constexpr char kJSSaveType[] = "save";
|
||||||
constexpr char kJSToken[] = "token";
|
constexpr char kJSToken[] = "token";
|
||||||
@ -1728,7 +1727,7 @@ void OutOfProcessInstance::HandleResetPrintPreviewModeMessage(
|
|||||||
|
|
||||||
void OutOfProcessInstance::HandleSaveAttachmentMessage(
|
void OutOfProcessInstance::HandleSaveAttachmentMessage(
|
||||||
const pp::VarDictionary& dict) {
|
const pp::VarDictionary& dict) {
|
||||||
if (!dict.Get(pp::Var(kJSAttachmentToken)).is_string() ||
|
if (!dict.Get(pp::Var(kJSMessageId)).is_string() ||
|
||||||
!dict.Get(pp::Var(kJSAttachmentIndex)).is_int() ||
|
!dict.Get(pp::Var(kJSAttachmentIndex)).is_int() ||
|
||||||
dict.Get(pp::Var(kJSAttachmentIndex)).AsInt() < 0) {
|
dict.Get(pp::Var(kJSAttachmentIndex)).AsInt() < 0) {
|
||||||
NOTREACHED();
|
NOTREACHED();
|
||||||
@ -1739,14 +1738,14 @@ void OutOfProcessInstance::HandleSaveAttachmentMessage(
|
|||||||
const std::vector<DocumentAttachmentInfo>& list =
|
const std::vector<DocumentAttachmentInfo>& list =
|
||||||
engine()->GetDocumentAttachmentInfoList();
|
engine()->GetDocumentAttachmentInfoList();
|
||||||
if (static_cast<size_t>(index) >= list.size() || !list[index].is_readable ||
|
if (static_cast<size_t>(index) >= list.size() || !list[index].is_readable ||
|
||||||
list[index].size_bytes == 0) {
|
!IsSaveDataSizeValid(list[index].size_bytes)) {
|
||||||
NOTREACHED();
|
NOTREACHED();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pp::VarDictionary message;
|
pp::VarDictionary message;
|
||||||
message.Set(kType, kJSSaveAttachmentDataType);
|
message.Set(kType, kJSSaveAttachmentDataType);
|
||||||
message.Set(kJSAttachmentToken, dict.Get(pp::Var(kJSAttachmentToken)));
|
message.Set(kJSMessageId, dict.Get(pp::Var(kJSMessageId)));
|
||||||
// This will be overwritten if the save is successful.
|
// This will be overwritten if the save is successful.
|
||||||
message.Set(kJSAttachmentDataToSave, pp::Var(pp::Var::Null()));
|
message.Set(kJSAttachmentDataToSave, pp::Var(pp::Var::Null()));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user