Implements WebGL support
This commit is contained in:
parent
944219ad8a
commit
f57c6935d7
@ -11,6 +11,7 @@
|
||||
<script type="text/javascript" src="../../src/display/api.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/metadata.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/webgl.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/pattern_helper.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/font_loader.js"></script>
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
<script type="text/javascript" src="../../src/display/api.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/metadata.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/webgl.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/pattern_helper.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/font_loader.js"></script>
|
||||
|
||||
|
1
make.js
1
make.js
@ -320,6 +320,7 @@ target.bundle = function(args) {
|
||||
'display/api.js',
|
||||
'display/metadata.js',
|
||||
'display/canvas.js',
|
||||
'display/webgl.js',
|
||||
'display/pattern_helper.js',
|
||||
'display/font_loader.js'
|
||||
]);
|
||||
|
@ -115,6 +115,13 @@ PDFJS.postMessageTransfers = (PDFJS.postMessageTransfers === undefined ?
|
||||
PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?
|
||||
false : PDFJS.disableCreateObjectURL);
|
||||
|
||||
/**
|
||||
* Disables WebGL usage.
|
||||
* @var {boolean}
|
||||
*/
|
||||
PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
|
||||
true : PDFJS.disableWebGL);
|
||||
|
||||
/**
|
||||
* Controls the logging level.
|
||||
* The constants from PDFJS.VERBOSITY_LEVELS should be used:
|
||||
|
@ -17,7 +17,8 @@
|
||||
/* globals ColorSpace, DeviceCmykCS, DeviceGrayCS, DeviceRgbCS, error, PDFJS,
|
||||
FONT_IDENTITY_MATRIX, Uint32ArrayView, IDENTITY_MATRIX, ImageData,
|
||||
ImageKind, isArray, isNum, TilingPattern, OPS, Promise, Util, warn,
|
||||
assert, info, shadow, TextRenderingMode, getShadingPatternFromIR */
|
||||
assert, info, shadow, TextRenderingMode, getShadingPatternFromIR,
|
||||
WebGLUtils */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -601,15 +602,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
function composeSMask(ctx, smask, layerCtx) {
|
||||
var mask = smask.canvas;
|
||||
var maskCtx = smask.context;
|
||||
var width = mask.width, height = mask.height;
|
||||
|
||||
function genericComposeSMask(maskCtx, layerCtx, width, height,
|
||||
subtype, backdrop) {
|
||||
var addBackdropFn;
|
||||
if (smask.backdrop) {
|
||||
var cs = smask.colorSpace || ColorSpace.singletons.rgb;
|
||||
var backdrop = cs.getRgb(smask.backdrop, 0);
|
||||
if (backdrop) {
|
||||
addBackdropFn = function (r0, g0, b0, bytes) {
|
||||
var length = bytes.length;
|
||||
for (var i = 3; i < length; i += 4) {
|
||||
@ -631,7 +627,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
}
|
||||
|
||||
var composeFn;
|
||||
if (smask.subtype === 'Luminosity') {
|
||||
if (subtype === 'Luminosity') {
|
||||
composeFn = function (maskDataBytes, layerDataBytes) {
|
||||
var length = maskDataBytes.length;
|
||||
for (var i = 3; i < length; i += 4) {
|
||||
@ -664,9 +660,29 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
maskCtx.putImageData(layerData, 0, row);
|
||||
}
|
||||
}
|
||||
|
||||
function composeSMask(ctx, smask, layerCtx) {
|
||||
var mask = smask.canvas;
|
||||
var maskCtx = smask.context;
|
||||
|
||||
ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY,
|
||||
smask.offsetX, smask.offsetY);
|
||||
|
||||
var backdrop;
|
||||
if (smask.backdrop) {
|
||||
var cs = smask.colorSpace || ColorSpace.singletons.rgb;
|
||||
backdrop = cs.getRgb(smask.backdrop, 0);
|
||||
}
|
||||
if (WebGLUtils.isEnabled) {
|
||||
var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask,
|
||||
{subtype: smask.subtype, backdrop: backdrop});
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
ctx.drawImage(composed, smask.offsetX, smask.offsetY);
|
||||
return;
|
||||
}
|
||||
genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height,
|
||||
smask.subtype, backdrop);
|
||||
ctx.drawImage(mask, 0, 0);
|
||||
}
|
||||
|
||||
@ -784,6 +800,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
endDrawing: function CanvasGraphics_endDrawing() {
|
||||
this.ctx.restore();
|
||||
CachedCanvases.clear();
|
||||
WebGLUtils.clear();
|
||||
|
||||
if (this.textLayer) {
|
||||
this.textLayer.endLayout();
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals CanvasGraphics, CachedCanvases, ColorSpace, Util, error, info,
|
||||
isArray, makeCssRgb */
|
||||
isArray, makeCssRgb, WebGLUtils */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -155,39 +155,59 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
|
||||
// MAX_PATTERN_SIZE is used to avoid OOM situation.
|
||||
var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
|
||||
|
||||
var boundsWidth = bounds[2] - bounds[0];
|
||||
var boundsHeight = bounds[3] - bounds[1];
|
||||
var offsetX = Math.floor(bounds[0]);
|
||||
var offsetY = Math.floor(bounds[1]);
|
||||
var boundsWidth = Math.ceil(bounds[2]) - offsetX;
|
||||
var boundsHeight = Math.ceil(bounds[3]) - offsetY;
|
||||
|
||||
var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] *
|
||||
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
|
||||
var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] *
|
||||
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
|
||||
var scaleX = width / boundsWidth;
|
||||
var scaleY = height / boundsHeight;
|
||||
|
||||
var tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
|
||||
var tmpCtx = tmpCanvas.context;
|
||||
if (backgroundColor) {
|
||||
tmpCtx.fillStyle = makeCssRgb(backgroundColor);
|
||||
tmpCtx.fillRect(0, 0, width, height);
|
||||
}
|
||||
var scaleX = boundsWidth / width;
|
||||
var scaleY = boundsHeight / height;
|
||||
|
||||
var context = {
|
||||
coords: coords,
|
||||
colors: colors,
|
||||
offsetX: -bounds[0],
|
||||
offsetY: -bounds[1],
|
||||
scaleX: scaleX,
|
||||
scaleY: scaleY
|
||||
offsetX: -offsetX,
|
||||
offsetY: -offsetY,
|
||||
scaleX: 1 / scaleX,
|
||||
scaleY: 1 / scaleY
|
||||
};
|
||||
|
||||
var data = tmpCtx.getImageData(0, 0, width, height);
|
||||
for (var i = 0; i < figures.length; i++) {
|
||||
drawFigure(data, figures[i], context);
|
||||
}
|
||||
tmpCtx.putImageData(data, 0, 0);
|
||||
var canvas;
|
||||
if (WebGLUtils.isEnabled) {
|
||||
canvas = WebGLUtils.drawFigures(width, height, backgroundColor,
|
||||
figures, context);
|
||||
|
||||
return {canvas: tmpCanvas.canvas, scaleX: 1 / scaleX, scaleY: 1 / scaleY};
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=972126
|
||||
var tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
|
||||
tmpCanvas.context.drawImage(canvas, 0, 0);
|
||||
canvas = tmpCanvas.canvas;
|
||||
} else {
|
||||
var tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
|
||||
var tmpCtx = tmpCanvas.context;
|
||||
|
||||
var data = tmpCtx.createImageData(width, height);
|
||||
if (backgroundColor) {
|
||||
var bytes = data.data;
|
||||
for (var i = 0, ii = bytes.length; i < ii; i += 4) {
|
||||
bytes[i] = backgroundColor[0];
|
||||
bytes[i + 1] = backgroundColor[1];
|
||||
bytes[i + 2] = backgroundColor[2];
|
||||
bytes[i + 3] = 255;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < figures.length; i++) {
|
||||
drawFigure(data, figures[i], context);
|
||||
}
|
||||
tmpCtx.putImageData(data, 0, 0);
|
||||
canvas = tmpCanvas.canvas;
|
||||
}
|
||||
|
||||
return {canvas: canvas, offsetX: offsetX, offsetY: offsetY,
|
||||
scaleX: scaleX, scaleY: scaleY};
|
||||
}
|
||||
return createMeshCanvas;
|
||||
})();
|
||||
@ -221,7 +241,6 @@ ShadingIRs.Mesh = {
|
||||
|
||||
// Rasterizing on the main thread since sending/queue large canvases
|
||||
// might cause OOM.
|
||||
// TODO consider using WebGL or asm.js to perform rasterization
|
||||
var temporaryPatternCanvas = createMeshCanvas(bounds, combinedScale,
|
||||
coords, colors, figures, shadingFill ? null : background);
|
||||
|
||||
@ -232,7 +251,8 @@ ShadingIRs.Mesh = {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.translate(bounds[0], bounds[1]);
|
||||
ctx.translate(temporaryPatternCanvas.offsetX,
|
||||
temporaryPatternCanvas.offsetY);
|
||||
ctx.scale(temporaryPatternCanvas.scaleX,
|
||||
temporaryPatternCanvas.scaleY);
|
||||
|
||||
|
428
src/display/webgl.js
Normal file
428
src/display/webgl.js
Normal file
@ -0,0 +1,428 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, shadow */
|
||||
/* jshint -W043 */
|
||||
|
||||
'use strict';
|
||||
|
||||
var WebGLUtils = (function WebGLUtilsClosure() {
|
||||
function loadShader(gl, code, shaderType) {
|
||||
var shader = gl.createShader(shaderType);
|
||||
gl.shaderSource(shader, code);
|
||||
gl.compileShader(shader);
|
||||
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
||||
if (!compiled) {
|
||||
var errorMsg = gl.getShaderInfoLog(shader);
|
||||
throw new Error('Error during shader compilation: ' + errorMsg);
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
function createVertexShader(gl, code) {
|
||||
return loadShader(gl, code, gl.VERTEX_SHADER);
|
||||
}
|
||||
function createFragmentShader(gl, code) {
|
||||
return loadShader(gl, code, gl.FRAGMENT_SHADER);
|
||||
}
|
||||
function createProgram(gl, shaders) {
|
||||
var program = gl.createProgram();
|
||||
for (var i = 0, ii = shaders.length; i < ii; ++i) {
|
||||
gl.attachShader(program, shaders[i]);
|
||||
}
|
||||
gl.linkProgram(program);
|
||||
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
|
||||
if (!linked) {
|
||||
var errorMsg = gl.getProgramInfoLog(program);
|
||||
throw new Error('Error during program linking: ' + errorMsg);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
function createTexture(gl, image, textureId) {
|
||||
gl.activeTexture(textureId);
|
||||
var texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
|
||||
// Set the parameters so we can render any size image.
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
|
||||
// Upload the image into the texture.
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
||||
return texture;
|
||||
}
|
||||
|
||||
var currentGL, currentCanvas;
|
||||
function generageGL() {
|
||||
if (currentGL) {
|
||||
return;
|
||||
}
|
||||
currentCanvas = document.createElement('canvas');
|
||||
currentGL = currentCanvas.getContext('webgl',
|
||||
{ premultipliedalpha: false });
|
||||
}
|
||||
|
||||
var smaskVertexShaderCode = '\
|
||||
attribute vec2 a_position; \
|
||||
attribute vec2 a_texCoord; \
|
||||
\
|
||||
uniform vec2 u_resolution; \
|
||||
\
|
||||
varying vec2 v_texCoord; \
|
||||
\
|
||||
void main() { \
|
||||
vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \
|
||||
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
|
||||
\
|
||||
v_texCoord = a_texCoord; \
|
||||
} ';
|
||||
|
||||
var smaskFragmentShaderCode = '\
|
||||
precision mediump float; \
|
||||
\
|
||||
uniform vec4 u_backdrop; \
|
||||
uniform int u_subtype; \
|
||||
uniform sampler2D u_image; \
|
||||
uniform sampler2D u_mask; \
|
||||
\
|
||||
varying vec2 v_texCoord; \
|
||||
\
|
||||
void main() { \
|
||||
vec4 imageColor = texture2D(u_image, v_texCoord); \
|
||||
vec4 maskColor = texture2D(u_mask, v_texCoord); \
|
||||
if (u_backdrop.a > 0.0) { \
|
||||
maskColor.rgb = maskColor.rgb * maskColor.a + \
|
||||
u_backdrop.rgb * (1.0 - maskColor.a); \
|
||||
} \
|
||||
float lum; \
|
||||
if (u_subtype == 0) { \
|
||||
lum = maskColor.a; \
|
||||
} else { \
|
||||
lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \
|
||||
maskColor.b * 0.11; \
|
||||
} \
|
||||
imageColor.a *= lum; \
|
||||
imageColor.rgb *= imageColor.a; \
|
||||
gl_FragColor = imageColor; \
|
||||
} ';
|
||||
|
||||
var smaskCache = null;
|
||||
|
||||
function initSmaskGL() {
|
||||
var canvas, gl;
|
||||
|
||||
generageGL();
|
||||
canvas = currentCanvas;
|
||||
currentCanvas = null;
|
||||
gl = currentGL;
|
||||
currentGL = null;
|
||||
|
||||
// setup a GLSL program
|
||||
var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
|
||||
var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
|
||||
var program = createProgram(gl, [vertexShader, fragmentShader]);
|
||||
gl.useProgram(program);
|
||||
|
||||
var cache = {};
|
||||
cache.gl = gl;
|
||||
cache.canvas = canvas;
|
||||
cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
|
||||
cache.positionLocation = gl.getAttribLocation(program, 'a_position');
|
||||
cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
|
||||
cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
|
||||
|
||||
var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
|
||||
var texLayerLocation = gl.getUniformLocation(program, 'u_image');
|
||||
var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
|
||||
|
||||
// provide texture coordinates for the rectangle.
|
||||
var texCoordBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
0.0, 0.0,
|
||||
1.0, 0.0,
|
||||
0.0, 1.0,
|
||||
0.0, 1.0,
|
||||
1.0, 0.0,
|
||||
1.0, 1.0]), gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(texCoordLocation);
|
||||
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
gl.uniform1i(texLayerLocation, 0);
|
||||
gl.uniform1i(texMaskLocation, 1);
|
||||
|
||||
smaskCache = cache;
|
||||
}
|
||||
|
||||
function composeSMask(layer, mask, properties) {
|
||||
var width = layer.width, height = layer.height;
|
||||
|
||||
if (!smaskCache) {
|
||||
initSmaskGL();
|
||||
}
|
||||
var cache = smaskCache,canvas = cache.canvas, gl = cache.gl;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.uniform2f(cache.resolutionLocation, width, height);
|
||||
|
||||
if (properties.backdrop) {
|
||||
gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
|
||||
properties.backdrop[1], properties.backdrop[2], 1);
|
||||
} else {
|
||||
gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
|
||||
}
|
||||
gl.uniform1i(cache.subtypeLocation,
|
||||
properties.subtype === 'Luminosity' ? 1 : 0);
|
||||
|
||||
// Create a textures
|
||||
var texture = createTexture(gl, layer, gl.TEXTURE0);
|
||||
var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
|
||||
|
||||
|
||||
// Create a buffer and put a single clipspace rectangle in
|
||||
// it (2 triangles)
|
||||
var buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
0, 0,
|
||||
width, 0,
|
||||
0, height,
|
||||
0, height,
|
||||
width, 0,
|
||||
width, height]), gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(cache.positionLocation);
|
||||
gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
// draw
|
||||
gl.clearColor(0, 0, 0, 0);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
|
||||
gl.flush();
|
||||
|
||||
gl.deleteTexture(texture);
|
||||
gl.deleteTexture(maskTexture);
|
||||
gl.deleteBuffer(buffer);
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
var figuresVertexShaderCode = '\
|
||||
attribute vec2 a_position; \
|
||||
attribute vec3 a_color; \
|
||||
\
|
||||
uniform vec2 u_resolution; \
|
||||
uniform vec2 u_scale; \
|
||||
uniform vec2 u_offset; \
|
||||
\
|
||||
varying vec4 v_color; \
|
||||
\
|
||||
void main() { \
|
||||
vec2 position = (a_position + u_offset) * u_scale; \
|
||||
vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \
|
||||
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
|
||||
\
|
||||
v_color = vec4(a_color / 255.0, 1.0); \
|
||||
} ';
|
||||
|
||||
var figuresFragmentShaderCode = '\
|
||||
precision mediump float; \
|
||||
\
|
||||
varying vec4 v_color; \
|
||||
\
|
||||
void main() { \
|
||||
gl_FragColor = v_color; \
|
||||
} ';
|
||||
|
||||
var figuresCache = null;
|
||||
|
||||
function initFiguresGL() {
|
||||
var canvas, gl;
|
||||
|
||||
generageGL();
|
||||
canvas = currentCanvas;
|
||||
currentCanvas = null;
|
||||
gl = currentGL;
|
||||
currentGL = null;
|
||||
|
||||
// setup a GLSL program
|
||||
var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
|
||||
var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
|
||||
var program = createProgram(gl, [vertexShader, fragmentShader]);
|
||||
gl.useProgram(program);
|
||||
|
||||
var cache = {};
|
||||
cache.gl = gl;
|
||||
cache.canvas = canvas;
|
||||
cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
|
||||
cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
|
||||
cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
|
||||
cache.positionLocation = gl.getAttribLocation(program, 'a_position');
|
||||
cache.colorLocation = gl.getAttribLocation(program, 'a_color');
|
||||
|
||||
figuresCache = cache;
|
||||
}
|
||||
|
||||
function drawFigures(width, height, backgroundColor, figures, context) {
|
||||
if (!figuresCache) {
|
||||
initFiguresGL();
|
||||
}
|
||||
var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.uniform2f(cache.resolutionLocation, width, height);
|
||||
|
||||
// count triangle points
|
||||
var count = 0;
|
||||
for (var i = 0, ii = figures.length; i < ii; i++) {
|
||||
switch (figures[i].type) {
|
||||
case 'lattice':
|
||||
var rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
|
||||
count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
|
||||
break;
|
||||
case 'triangles':
|
||||
count += figures[i].coords.length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// transfer data
|
||||
var coords = new Float32Array(count * 2);
|
||||
var colors = new Uint8Array(count * 3);
|
||||
var coordsMap = context.coords, colorsMap = context.colors;
|
||||
var pIndex = 0, cIndex = 0;
|
||||
for (var i = 0, ii = figures.length; i < ii; i++) {
|
||||
var figure = figures[i], ps = figure.coords, cs = figure.colors;
|
||||
switch (figure.type) {
|
||||
case 'lattice':
|
||||
var cols = figure.verticesPerRow;
|
||||
var rows = (ps.length / cols) | 0;
|
||||
for (var row = 1; row < rows; row++) {
|
||||
var offset = row * cols + 1;
|
||||
for (var col = 1; col < cols; col++, offset++) {
|
||||
coords[pIndex] = coordsMap[ps[offset - cols - 1]];
|
||||
coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
|
||||
coords[pIndex + 2] = coordsMap[ps[offset - cols]];
|
||||
coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
|
||||
coords[pIndex + 4] = coordsMap[ps[offset - 1]];
|
||||
coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
|
||||
colors[cIndex] = colorsMap[cs[offset - cols - 1]];
|
||||
colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
|
||||
colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
|
||||
colors[cIndex + 3] = colorsMap[cs[offset - cols]];
|
||||
colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
|
||||
colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
|
||||
colors[cIndex + 6] = colorsMap[cs[offset - 1]];
|
||||
colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
|
||||
colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
|
||||
|
||||
coords[pIndex + 6] = coords[pIndex + 2];
|
||||
coords[pIndex + 7] = coords[pIndex + 3];
|
||||
coords[pIndex + 8] = coords[pIndex + 4];
|
||||
coords[pIndex + 9] = coords[pIndex + 5];
|
||||
coords[pIndex + 10] = coordsMap[ps[offset]];
|
||||
coords[pIndex + 11] = coordsMap[ps[offset] + 1];
|
||||
colors[cIndex + 9] = colors[cIndex + 3];
|
||||
colors[cIndex + 10] = colors[cIndex + 4];
|
||||
colors[cIndex + 11] = colors[cIndex + 5];
|
||||
colors[cIndex + 12] = colors[cIndex + 6];
|
||||
colors[cIndex + 13] = colors[cIndex + 7];
|
||||
colors[cIndex + 14] = colors[cIndex + 8];
|
||||
colors[cIndex + 15] = colorsMap[cs[offset]];
|
||||
colors[cIndex + 16] = colorsMap[cs[offset] + 1];
|
||||
colors[cIndex + 17] = colorsMap[cs[offset] + 2];
|
||||
pIndex += 12;
|
||||
cIndex += 18;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'triangles':
|
||||
for (var j = 0, jj = ps.length; j < jj; j++) {
|
||||
coords[pIndex] = coordsMap[ps[j]];
|
||||
coords[pIndex + 1] = coordsMap[ps[j] + 1];
|
||||
colors[cIndex] = colorsMap[cs[i]];
|
||||
colors[cIndex + 1] = colorsMap[cs[j] + 1];
|
||||
colors[cIndex + 2] = colorsMap[cs[j] + 2];
|
||||
pIndex += 2;
|
||||
cIndex += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// draw
|
||||
if (backgroundColor) {
|
||||
gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
|
||||
backgroundColor[2] / 255, 1.0);
|
||||
} else {
|
||||
gl.clearColor(0, 0, 0, 0);
|
||||
}
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
var coordsBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(cache.positionLocation);
|
||||
gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
var colorsBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(cache.colorLocation);
|
||||
gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
|
||||
0, 0);
|
||||
|
||||
gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
|
||||
gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLES, 0, count);
|
||||
|
||||
gl.flush();
|
||||
|
||||
gl.deleteBuffer(coordsBuffer);
|
||||
gl.deleteBuffer(colorsBuffer);
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
smaskCache = null;
|
||||
figuresCache = null;
|
||||
}
|
||||
|
||||
return {
|
||||
get isEnabled() {
|
||||
if (PDFJS.disableWebGL) {
|
||||
return false;
|
||||
}
|
||||
var enabled = false;
|
||||
try {
|
||||
generageGL();
|
||||
enabled = !!currentGL;
|
||||
} catch (e) { }
|
||||
return shadow(this, 'isEnabled', enabled);
|
||||
},
|
||||
composeSMask: composeSMask,
|
||||
drawFigures: drawFigures,
|
||||
clear: cleanup
|
||||
};
|
||||
})();
|
@ -19,6 +19,7 @@
|
||||
<script type="text/javascript" src="../../src/shared/util.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/api.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/webgl.js"></script>
|
||||
<script type="text/javascript" src="../../src/core/obj.js"></script>
|
||||
<script type="text/javascript" src="../../src/shared/annotation.js"></script>
|
||||
<script type="text/javascript" src="../../src/shared/function.js"></script>
|
||||
|
@ -26,6 +26,7 @@ limitations under the License.
|
||||
<script type="text/javascript" src="/src/display/api.js"></script>
|
||||
<script type="text/javascript" src="/src/display/metadata.js"></script>
|
||||
<script type="text/javascript" src="/src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="/src/display/webgl.js"></script>
|
||||
<script type="text/javascript" src="/src/display/pattern_helper.js"></script>
|
||||
<script type="text/javascript" src="/src/display/font_loader.js"></script>
|
||||
<script type="text/javascript" src="driver.js"></script>
|
||||
|
@ -18,6 +18,7 @@
|
||||
<script type="text/javascript" src="../../src/shared/util.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/api.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="../../src/display/webgl.js"></script>
|
||||
<script type="text/javascript" src="../../src/core/obj.js"></script>
|
||||
<script type="text/javascript" src="../../src/shared/annotation.js"></script>
|
||||
<script type="text/javascript" src="../../src/shared/function.js"></script>
|
||||
|
@ -54,6 +54,7 @@ http://sourceforge.net/adobe/cmap/wiki/License/
|
||||
<script type="text/javascript" src="../src/display/api.js"></script>
|
||||
<script type="text/javascript" src="../src/display/metadata.js"></script>
|
||||
<script type="text/javascript" src="../src/display/canvas.js"></script>
|
||||
<script type="text/javascript" src="../src/display/webgl.js"></script>
|
||||
<script type="text/javascript" src="../src/display/pattern_helper.js"></script>
|
||||
<script type="text/javascript" src="../src/display/font_loader.js"></script>
|
||||
<script type="text/javascript">PDFJS.workerSrc = '../src/worker_loader.js';</script>
|
||||
|
@ -1711,6 +1711,10 @@ function webViewerLoad(evt) {
|
||||
PDFJS.disableHistory = (hashParams['disableHistory'] === 'true');
|
||||
}
|
||||
|
||||
if ('webgl' in hashParams) {
|
||||
PDFJS.disableWebGL = (hashParams['webgl'] !== 'true');
|
||||
}
|
||||
|
||||
if ('useOnlyCssZoom' in hashParams) {
|
||||
USE_ONLY_CSS_ZOOM = (hashParams['useOnlyCssZoom'] === 'true');
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user