From 59b5e1430170bdde7504d9f29ab7ffc78266778f Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 1 Nov 2017 16:32:22 +0100 Subject: [PATCH] Split the existing `WebGLUtils` in two classes, a private `WebGLUtils` and a public `WebGLContext`, and utilize the latter in the API to allow various code to access the methods of `WebGLUtils` This patch is one (small) step on the way to reduce the general dependency on a global `PDFJS` object, for PDF.js version `2.0`. --- src/display/api.js | 15 ++++++-- src/display/canvas.js | 26 ++++++++----- src/display/pattern_helper.js | 17 +++++---- src/display/webgl.js | 71 +++++++++++++++++++++++------------ 4 files changed, 86 insertions(+), 43 deletions(-) diff --git a/src/display/api.js b/src/display/api.js index bd4d404b8..d8000ab60 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -30,6 +30,7 @@ import { CanvasGraphics } from './canvas'; import globalScope from '../shared/global_scope'; import { Metadata } from './metadata'; import { PDFDataTransportStream } from './transport_stream'; +import { WebGLContext } from './webgl'; var DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536 @@ -820,6 +821,11 @@ var PDFPageProxy = (function PDFPageProxyClosure() { var renderingIntent = (params.intent === 'print' ? 'print' : 'display'); var canvasFactory = params.canvasFactory || new DOMCanvasFactory(); + let webGLContext = new WebGLContext({ + // TODO: When moving this parameter from `PDFJS` to {RenderParameters}, + // change its name to `enableWebGL` instead. + enable: !getDefaultSetting('disableWebGL'), + }); if (!this.intentStates[renderingIntent]) { this.intentStates[renderingIntent] = Object.create(null); @@ -870,7 +876,8 @@ var PDFPageProxy = (function PDFPageProxyClosure() { this.commonObjs, intentState.operatorList, this.pageNumber, - canvasFactory); + canvasFactory, + webGLContext); internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; if (!intentState.renderTasks) { intentState.renderTasks = []; @@ -2174,7 +2181,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { let canvasInRendering = new WeakMap(); function InternalRenderTask(callback, params, objs, commonObjs, operatorList, - pageNumber, canvasFactory) { + pageNumber, canvasFactory, webGLContext) { this.callback = callback; this.params = params; this.objs = objs; @@ -2183,6 +2190,8 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { this.operatorList = operatorList; this.pageNumber = pageNumber; this.canvasFactory = canvasFactory; + this.webGLContext = webGLContext; + this.running = false; this.graphicsReadyCallback = null; this.graphicsReady = false; @@ -2225,7 +2234,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { var params = this.params; this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs, this.objs, this.canvasFactory, - params.imageLayer); + this.webGLContext, params.imageLayer); this.gfx.beginDrawing({ transform: params.transform, diff --git a/src/display/canvas.js b/src/display/canvas.js index c4eb7b7a8..19863ac96 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -18,7 +18,6 @@ import { OPS, shadow, TextRenderingMode, Util, warn } from '../shared/util'; import { getShadingPatternFromIR, TilingPattern } from './pattern_helper'; -import { WebGLUtils } from './webgl'; // contexts store most of the state we need natively. // However, PDF needs a bit more state, which we store here. @@ -407,7 +406,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { var EXECUTION_STEPS = 10; function CanvasGraphics(canvasCtx, commonObjs, objs, canvasFactory, - imageLayer) { + webGLContext, imageLayer) { this.ctx = canvasCtx; this.current = new CanvasExtraState(); this.stateStack = []; @@ -418,6 +417,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.commonObjs = commonObjs; this.objs = objs; this.canvasFactory = canvasFactory; + this.webGLContext = webGLContext; this.imageLayer = imageLayer; this.groupStack = []; this.processingType3 = null; @@ -693,7 +693,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { } } - function composeSMask(ctx, smask, layerCtx) { + function composeSMask(ctx, smask, layerCtx, webGLContext) { var mask = smask.canvas; var maskCtx = smask.context; @@ -701,9 +701,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { smask.offsetX, smask.offsetY); var backdrop = smask.backdrop || null; - if (!smask.transferMap && WebGLUtils.isEnabled) { - var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask, - { subtype: smask.subtype, backdrop, }); + if (!smask.transferMap && webGLContext.isEnabled) { + let composed = webGLContext.composeSMask({ + layer: layerCtx.canvas, + mask, + properties: { + subtype: smask.subtype, + backdrop, + }, + }); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.drawImage(composed, smask.offsetX, smask.offsetY); return; @@ -851,7 +857,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { } this.cachedCanvases.clear(); - WebGLUtils.clear(); + this.webGLContext.clear(); if (this.imageLayer) { this.imageLayer.endLayout(); @@ -988,7 +994,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.groupLevel--; this.ctx = this.groupStack.pop(); - composeSMask(this.ctx, this.current.activeSMask, groupCtx); + composeSMask(this.ctx, this.current.activeSMask, groupCtx, + this.webGLContext); this.ctx.restore(); this.ctx.save(); // save is needed since SMask will be resumed. copyCtxState(groupCtx, this.ctx); @@ -1023,7 +1030,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.groupLevel--; this.ctx = this.groupStack.pop(); - composeSMask(this.ctx, this.current.activeSMask, groupCtx); + composeSMask(this.ctx, this.current.activeSMask, groupCtx, + this.webGLContext); this.ctx.restore(); copyCtxState(groupCtx, this.ctx); // Transform was changed in the SMask canvas, reflecting this change on diff --git a/src/display/pattern_helper.js b/src/display/pattern_helper.js index eb129b4fe..00fa3ce51 100644 --- a/src/display/pattern_helper.js +++ b/src/display/pattern_helper.js @@ -14,7 +14,6 @@ */ import { FormatError, info, Util } from '../shared/util'; -import { WebGLUtils } from './webgl'; var ShadingIRs = {}; @@ -145,7 +144,7 @@ var createMeshCanvas = (function createMeshCanvasClosure() { } function createMeshCanvas(bounds, combinesScale, coords, colors, figures, - backgroundColor, cachedCanvases) { + backgroundColor, cachedCanvases, webGLContext) { // we will increase scale on some weird factor to let antialiasing take // care of "rough" edges var EXPECTED_SCALE = 1.1; @@ -180,10 +179,14 @@ var createMeshCanvas = (function createMeshCanvasClosure() { var paddedHeight = height + BORDER_SIZE * 2; var canvas, tmpCanvas, i, ii; - if (WebGLUtils.isEnabled) { - canvas = WebGLUtils.drawFigures(width, height, backgroundColor, - figures, context); - + if (webGLContext.isEnabled) { + canvas = webGLContext.drawFigures({ + width, + height, + backgroundColor, + figures, + context, + }); // https://bugzilla.mozilla.org/show_bug.cgi?id=972126 tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight, false); @@ -253,7 +256,7 @@ ShadingIRs.Mesh = { // might cause OOM. var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords, colors, figures, shadingFill ? null : background, - owner.cachedCanvases); + owner.cachedCanvases, owner.webGLContext); if (!shadingFill) { ctx.setTransform.apply(ctx, owner.baseTransform); diff --git a/src/display/webgl.js b/src/display/webgl.js index 58a846ba4..33eba1ef3 100644 --- a/src/display/webgl.js +++ b/src/display/webgl.js @@ -14,9 +14,35 @@ */ /* eslint-disable no-multi-str */ -import { getDefaultSetting } from './dom_utils'; import { shadow } from '../shared/util'; +class WebGLContext { + constructor({ enable = false, }) { + this._enabled = enable === true; + } + + get isEnabled() { + let enabled = this._enabled; + if (enabled) { + enabled = WebGLUtils.tryInitGL(); + } + return shadow(this, 'isEnabled', enabled); + } + + composeSMask({ layer, mask, properties, }) { + return WebGLUtils.composeSMask(layer, mask, properties); + } + + drawFigures({ width, height, backgroundColor, figures, context, }) { + return WebGLUtils.drawFigures(width, height, backgroundColor, figures, + context); + } + + clear() { + WebGLUtils.cleanup(); + } +} + var WebGLUtils = (function WebGLUtilsClosure() { function loadShader(gl, code, shaderType) { var shader = gl.createShader(shaderType); @@ -405,37 +431,34 @@ var WebGLUtils = (function WebGLUtilsClosure() { return canvas; } - function cleanup() { - if (smaskCache && smaskCache.canvas) { - smaskCache.canvas.width = 0; - smaskCache.canvas.height = 0; - } - if (figuresCache && figuresCache.canvas) { - figuresCache.canvas.width = 0; - figuresCache.canvas.height = 0; - } - smaskCache = null; - figuresCache = null; - } - return { - get isEnabled() { - if (getDefaultSetting('disableWebGL')) { - return false; - } - var enabled = false; + tryInitGL() { try { generateGL(); - enabled = !!currentGL; - } catch (e) { } - return shadow(this, 'isEnabled', enabled); + return !!currentGL; + } catch (ex) { } + return false; }, + composeSMask, + drawFigures, - clear: cleanup, + + cleanup() { + if (smaskCache && smaskCache.canvas) { + smaskCache.canvas.width = 0; + smaskCache.canvas.height = 0; + } + if (figuresCache && figuresCache.canvas) { + figuresCache.canvas.width = 0; + figuresCache.canvas.height = 0; + } + smaskCache = null; + figuresCache = null; + }, }; })(); export { - WebGLUtils, + WebGLContext, };