Commit d2972196 authored by Noel Gordon's avatar Noel Gordon Committed by Commit Bot

[piexwasm] Make callers handle Piex Module failure

piex-wasm assumes chrome.runtime.reload can be used to reload the page
on Module failures. Other environments (normal web pages, web workers,
NodeJS, etc) obviously can't use chrome.runtime.reload.

Remove the chrome.runtime.reload assumption: change the client code to
provide the failure handler to piex-wasm. Change image_request_task.js
RAW image client code: pass in the chrome.runtime.reload handler.

While here, add or adjust comments to image_request_task.js and change
the direct loading case to arrow function. No change in behavior.

Bug: 1132695
No-try: true
Change-Id: I6a2b641cdc036dd208f4d64deb4f0b7fdff0835f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2432705
Commit-Queue: Noel Gordon <noel@chromium.org>
Reviewed-by: default avatarTrent Apted <tapted@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811085}
parent 3f88f25e
......@@ -287,13 +287,16 @@ ImageRequestTask.prototype.getExternalThumbnail = function(url, onFailure) {
};
/**
* Downloads an image directly or for remote resources using the XmlHttpRequest.
* Loads |this.image_| with the |this.request_.url| source or the thumbnail
* image of the source.
*
* @param {function()} onSuccess Success callback.
* @param {function()} onFailure Failure callback.
* @private
*/
ImageRequestTask.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
// Load methods below set |this.image_.src|. Call revokeObjectURL(src) to
// release resources if the image src was created with createObjectURL().
this.image_.onload = function() {
URL.revokeObjectURL(this.image_.src);
onSuccess();
......@@ -303,18 +306,22 @@ ImageRequestTask.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
onFailure();
}.bind(this);
// Download data urls directly since they are not supported by XmlHttpRequest.
// Load dataURL sources directly.
const dataUrlMatches = this.request_.url.match(/^data:([^,;]*)[,;]/);
if (dataUrlMatches) {
this.image_.src = this.request_.url;
this.contentType_ = dataUrlMatches[1];
return;
}
// Load Drive source thumbnail.
const drivefsUrlMatches = this.request_.url.match(/^drivefs:(.*)/);
if (drivefsUrlMatches) {
this.getExternalThumbnail(drivefsUrlMatches[1], onFailure);
return;
}
// Load PDF source thumbnail.
if (this.request_.url.endsWith('.pdf')) {
this.getExternalThumbnail(this.request_.url, onFailure);
return;
......@@ -322,9 +329,9 @@ ImageRequestTask.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
const fileType = FileType.getTypeForName(this.request_.url);
// Load RAW images by using Piex loader instead of XHR.
// Load RAW image source thumbnail.
if (fileType.type === 'raw') {
this.piexLoader_.load(this.request_.url)
this.piexLoader_.load(this.request_.url, chrome.runtime.reload)
.then(
function(data) {
this.request_.orientation = data.orientation;
......@@ -335,13 +342,13 @@ ImageRequestTask.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
this.image_.src = URL.createObjectURL(blob);
}.bind(this),
function() {
// The error has already been logged in PiexLoader.
// PiexLoader calls console.error on errors.
onFailure();
});
return;
}
// Load video thumbnails by using video tag instead of XHR.
// Load video source thumbnail.
if (fileType.type === 'video') {
this.createVideoThumbnailUrl_(this.request_.url)
.then(function(url) {
......@@ -354,16 +361,11 @@ ImageRequestTask.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
return;
}
// Fetch the image via XHR and parse it.
const parseImage = function(contentType, blob) {
if (contentType) {
this.contentType_ = contentType;
}
this.image_.src = URL.createObjectURL(blob);
}.bind(this);
// Request raw data via XHR.
this.load(this.request_.url, parseImage, onFailure);
// Load the source directly.
this.load(this.request_.url, (contentType, blob) => {
this.image_.src = blob ? URL.createObjectURL(blob) : '!';
this.contentType_ = contentType || null;
}, onFailure);
};
/**
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
console.log('[PiexLoader] wasm mode loaded');
console.log('[PiexLoader] loaded');
/**
* Declares the piex-wasm Module interface. The Module has many interfaces
......@@ -25,33 +25,33 @@ let PiexWasmModule;
const PiexModule = window['Module'] || {};
/**
* Set true only if the wasm Module.onAbort() handler is called.
* Set true only if the Module.onAbort() handler is called.
* @type {boolean}
*/
let wasmFailed = false;
let piexFailed = false;
/**
* Installs an (Emscripten) wasm Module.onAbort handler, that records that
* the Module has failed and re-throws the error.
* Installs an (Emscripten) Module.onAbort handler. Record that the Module
* has failed and re-throw the error.
* @throws {!Error|string}
*/
PiexModule.onAbort = (error) => {
wasmFailed = true;
piexFailed = true;
throw error;
};
/**
* Module failure recovery: if wasmFailed is set via onAbort due to OOM in
* Module failure recovery: if piexFailed is set via onAbort due to OOM in
* the C++ for example, or the Module failed to load or call run, then the
* wasm Module is in a broken, non-functional state.
* Module is in a broken, non-functional state.
*
* Re-loading the page is the only reliable way to attempt to recover from
* broken Module state.
* Loading the entire page is the only reliable way to recover from broken
* Module state. Log the error, and return true to tell caller to initiate
* failure recovery steps.
*/
function wasmModuleFailed() {
if (wasmFailed || !PiexModule.calledRun) {
console.error('[PiexLoader] wasmModuleFailed');
setTimeout(chrome.runtime.reload, 0);
function piexModuleFailed() {
if (piexFailed || !PiexModule.calledRun) {
console.error('[PiexLoader] piex wasm module failed');
return true;
}
}
......@@ -106,15 +106,6 @@ function PiexLoaderResponse(data) {
this.ifd = data.ifd || null;
}
/**
* Creates a PiexLoader for reading RAW image file information.
* @constructor
* @struct
*/
function PiexLoader() {
// TODO(crbug.com/1039141): make this an ES6 class.
}
/**
* Resolves the file entry associated with DOM filesystem |url| and returns
* the file content in an ArrayBuffer.
......@@ -468,16 +459,32 @@ class ImageBuffer {
}
/**
* Starts to load RAW image.
* Creates a PiexLoader.
* @constructor
* @struct
*/
function PiexLoader() {}
/**
* Loads a RAW image. Returns the image metadata and the image thumbnail in a
* PiexLoaderResponse.
*
* piexModuleFailed() returns true if the Module is in an unrecoverable error
* state. This is rare, but possible, and the only reliable way to recover is
* to reload the page. Callback |onPiexModuleFailed| is used to indicate that
* the caller should initiate failure recovery steps.
*
* @param {string} url
* @param {!function()} onPiexModuleFailed
* @return {!Promise<!PiexLoaderResponse>}
*/
PiexLoader.prototype.load = function(url) {
PiexLoader.prototype.load = function(url, onPiexModuleFailed) {
let imageBuffer;
return readFromFileSystem(url)
.then((buffer) => {
if (wasmModuleFailed() === true) {
if (piexModuleFailed() === true) {
// Just reject here: handle in the .catch() clause below.
return Promise.reject('piex wasm module failed');
}
imageBuffer = new ImageBuffer(buffer);
......@@ -488,7 +495,8 @@ PiexLoader.prototype.load = function(url) {
return new PiexLoaderResponse(imageBuffer.preview(result));
})
.catch((error) => {
if (wasmModuleFailed() === true) {
if (piexModuleFailed() === true) {
setTimeout(onPiexModuleFailed, 0);
return Promise.reject('piex wasm module failed');
}
imageBuffer && imageBuffer.close();
......
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