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)}} */
|
||||
export let MessageData;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* type: string,
|
||||
* dataToSave: Array,
|
||||
* messageId: string,
|
||||
* }}
|
||||
*/
|
||||
let SaveAttachmentDataMessageData;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* dataToSave: Array,
|
||||
@ -103,6 +112,14 @@ export class ContentController {
|
||||
*/
|
||||
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.
|
||||
* @param {string} fileName
|
||||
@ -358,6 +375,14 @@ export class PluginController extends ContentController {
|
||||
return resolver.promise;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
saveAttachment(index) {
|
||||
return this.postMessageWithReply_({
|
||||
type: 'saveAttachment',
|
||||
attachmentIndex: index,
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async load(fileName, data) {
|
||||
const url = URL.createObjectURL(new Blob([data]));
|
||||
|
@ -95,6 +95,9 @@ export class InkController extends ContentController {
|
||||
return this.inkHost_.saveDocument();
|
||||
}
|
||||
|
||||
/** @override */
|
||||
saveAttachment(index) {}
|
||||
|
||||
/** @override */
|
||||
undo() {
|
||||
this.inkHost_.undo();
|
||||
|
@ -874,6 +874,62 @@ export class PDFViewerElement extends PDFViewerBaseElement {
|
||||
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
|
||||
* save.
|
||||
@ -1009,7 +1065,7 @@ export class PDFViewerElement extends PDFViewerBaseElement {
|
||||
entry => {
|
||||
if (chrome.runtime.lastError) {
|
||||
if (chrome.runtime.lastError.message !== 'User cancelled') {
|
||||
console.log(
|
||||
console.error(
|
||||
'chrome.fileSystem.chooseEntry failed: ' +
|
||||
chrome.runtime.lastError.message);
|
||||
}
|
||||
|
@ -132,10 +132,9 @@ constexpr char kJSPrintType[] = "print";
|
||||
// Save attachment (Page -> Plugin)
|
||||
constexpr char kJSSaveAttachmentType[] = "saveAttachment";
|
||||
constexpr char kJSAttachmentIndex[] = "attachmentIndex";
|
||||
constexpr char kJSAttachmentToken[] = "attachmentToken";
|
||||
// Save attachment data (Plugin -> Page)
|
||||
constexpr char kJSSaveAttachmentDataType[] = "saveAttachmentData";
|
||||
constexpr char kJSAttachmentDataToSave[] = "attachmentDataToSave";
|
||||
constexpr char kJSAttachmentDataToSave[] = "dataToSave";
|
||||
// Save (Page -> Plugin)
|
||||
constexpr char kJSSaveType[] = "save";
|
||||
constexpr char kJSToken[] = "token";
|
||||
@ -1728,7 +1727,7 @@ void OutOfProcessInstance::HandleResetPrintPreviewModeMessage(
|
||||
|
||||
void OutOfProcessInstance::HandleSaveAttachmentMessage(
|
||||
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)).AsInt() < 0) {
|
||||
NOTREACHED();
|
||||
@ -1739,14 +1738,14 @@ void OutOfProcessInstance::HandleSaveAttachmentMessage(
|
||||
const std::vector<DocumentAttachmentInfo>& list =
|
||||
engine()->GetDocumentAttachmentInfoList();
|
||||
if (static_cast<size_t>(index) >= list.size() || !list[index].is_readable ||
|
||||
list[index].size_bytes == 0) {
|
||||
!IsSaveDataSizeValid(list[index].size_bytes)) {
|
||||
NOTREACHED();
|
||||
return;
|
||||
}
|
||||
|
||||
pp::VarDictionary message;
|
||||
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.
|
||||
message.Set(kJSAttachmentDataToSave, pp::Var(pp::Var::Null()));
|
||||
|
||||
|
Reference in New Issue
Block a user