Skip to content

Commit

Permalink
[api-minor] Add a getDocument option to disable ImageDecoder usage
Browse files Browse the repository at this point in the history
This allows end-users to forcibly disable `ImageDecoder`, even if the browser appears to support it (similar to the pre-existing option for `OffscreenCanvas`).
  • Loading branch information
Snuffleupagus committed Nov 12, 2024
1 parent fe5967c commit a93a7d1
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 31 deletions.
12 changes: 4 additions & 8 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import { getGlyphsUnicode } from "./glyphlist.js";
import { getMetrics } from "./metrics.js";
import { getUnicodeForGlyph } from "./unicode.js";
import { ImageResizer } from "./image_resizer.js";
import { JpegStream } from "./jpeg_stream.js";
import { MurmurHash3_64 } from "../shared/murmurhash3.js";
import { OperatorList } from "./operator_list.js";
import { PDFImage } from "./image.js";
Expand Down Expand Up @@ -233,14 +234,9 @@ class PartialEvaluator {

this._regionalImageCache = new RegionalImageCache();
this._fetchBuiltInCMapBound = this.fetchBuiltInCMap.bind(this);
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
ImageResizer.setMaxArea(this.options.canvasMaxAreaInBytes);
} else {
ImageResizer.setOptions({
isChrome: this.options.isChrome,
maxArea: this.options.canvasMaxAreaInBytes,
});
}

ImageResizer.setOptions(this.options);
JpegStream.setOptions(this.options);
}

/**
Expand Down
31 changes: 14 additions & 17 deletions src/core/image_resizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,20 @@ const MAX_ERROR = 128;
class ImageResizer {
static #goodSquareLength = MIN_IMAGE_DIM;

static #isChrome = false;
static #isImageDecoderSupported = FeatureTest.isImageDecoderSupported;

constructor(imgData, isMask) {
this._imgData = imgData;
this._isMask = isMask;
}

static get canUseImageDecoder() {
// TODO: remove the isChrome, once Chrome doesn't crash anymore with
// issue6741.pdf.
// https://issues.chromium.org/issues/374807001.
return shadow(
this,
"canUseImageDecoder",
this.#isChrome || typeof ImageDecoder === "undefined"
? Promise.resolve(false)
: ImageDecoder.isTypeSupported("image/bmp")
this.#isImageDecoderSupported
? ImageDecoder.isTypeSupported("image/bmp")
: Promise.resolve(false)
);
}

Expand Down Expand Up @@ -121,19 +118,19 @@ class ImageResizer {
}
}

static setMaxArea(area) {
static setOptions({
isChrome = false,
isImageDecoderSupported = false,
maxArea = -1,
}) {
if (!this._hasMaxArea) {
// Divide by 4 to have the value in pixels.
this.MAX_AREA = area >> 2;
this.MAX_AREA = maxArea >> 2;
}
}

static setOptions(opts) {
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
throw new Error("Not implemented: setOptions");
}
this.setMaxArea(opts.maxArea ?? -1);
this.#isChrome = opts.isChrome ?? false;
// TODO: remove the isChrome, once Chrome doesn't crash anymore with
// issue6741.pdf.
// https://issues.chromium.org/issues/374807001.
this.#isImageDecoderSupported = isImageDecoderSupported && !isChrome;
}

static _areGoodDims(width, height) {
Expand Down
14 changes: 10 additions & 4 deletions src/core/jpeg_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* limitations under the License.
*/

import { shadow, warn } from "../shared/util.js";
import { FeatureTest, shadow, warn } from "../shared/util.js";
import { DecodeStream } from "./decode_stream.js";
import { Dict } from "./primitives.js";
import { JpegImage } from "./jpg.js";
Expand All @@ -23,6 +23,8 @@ import { JpegImage } from "./jpg.js";
* like all the other DecodeStreams.
*/
class JpegStream extends DecodeStream {
static #isImageDecoderSupported = FeatureTest.isImageDecoderSupported;

constructor(stream, maybeLength, params) {
super(maybeLength);

Expand All @@ -36,12 +38,16 @@ class JpegStream extends DecodeStream {
return shadow(
this,
"canUseImageDecoder",
typeof ImageDecoder === "undefined"
? Promise.resolve(false)
: ImageDecoder.isTypeSupported("image/jpeg")
this.#isImageDecoderSupported
? ImageDecoder.isTypeSupported("image/jpeg")
: Promise.resolve(false)
);
}

static setOptions({ isImageDecoderSupported = false }) {
this.#isImageDecoderSupported = isImageDecoderSupported;
}

get bytes() {
// If `this.maybeLength` is null, we'll get the entire stream.
return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
Expand Down
6 changes: 4 additions & 2 deletions src/core/pdf_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ class BasePdfManager {
this._password = args.password;
this.enableXfa = args.enableXfa;

// Check `OffscreenCanvas` support once, rather than repeatedly throughout
// the worker-thread code.
// Check `OffscreenCanvas` and `ImageDecoder` support once,
// rather than repeatedly throughout the worker-thread code.
args.evaluatorOptions.isOffscreenCanvasSupported &&=
FeatureTest.isOffscreenCanvasSupported;
args.evaluatorOptions.isImageDecoderSupported &&=
FeatureTest.isImageDecoderSupported;
this.evaluatorOptions = Object.freeze(args.evaluatorOptions);
}

Expand Down
9 changes: 9 additions & 0 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ const DefaultStandardFontDataFactory =
* `OffscreenCanvas` in the worker. Primarily used to improve performance of
* image conversion/rendering.
* The default value is `true` in web environments and `false` in Node.js.
* @property {boolean} [isImageDecoderSupported] - Determines if we can use
* `ImageDecoder` in the worker. Primarily used to improve performance of
* image conversion/rendering.
* The default value is `true` in web environments and `false` in Node.js.
* @property {boolean} [isChrome] - Determines if we can use bmp ImageDecoder.
* NOTE: Temporary option until [https://issues.chromium.org/issues/374807001]
* is fixed.
Expand Down Expand Up @@ -284,6 +288,10 @@ function getDocument(src = {}) {
typeof src.isOffscreenCanvasSupported === "boolean"
? src.isOffscreenCanvasSupported
: !isNodeJS;
const isImageDecoderSupported =
typeof src.isImageDecoderSupported === "boolean"
? src.isImageDecoderSupported
: !isNodeJS;
const isChrome =
typeof src.isChrome === "boolean"
? src.isChrome
Expand Down Expand Up @@ -395,6 +403,7 @@ function getDocument(src = {}) {
ignoreErrors,
isEvalSupported,
isOffscreenCanvasSupported,
isImageDecoderSupported,
isChrome,
canvasMaxAreaInBytes,
fontExtraProperties,
Expand Down
8 changes: 8 additions & 0 deletions src/shared/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,14 @@ class FeatureTest {
);
}

static get isImageDecoderSupported() {
return shadow(
this,
"isImageDecoderSupported",
typeof ImageDecoder !== "undefined"
);
}

static get platform() {
if (
(typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) ||
Expand Down

0 comments on commit a93a7d1

Please sign in to comment.