Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGL and misc memory optimizations #4286

Merged
merged 5 commits into from
Apr 7, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/acroforms/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
1 change: 1 addition & 0 deletions examples/helloworld/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
1 change: 1 addition & 0 deletions make.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
]);
Expand Down
61 changes: 36 additions & 25 deletions src/core/pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,38 @@ Shadings.Mesh = (function MeshClosure() {
mesh.bounds = [minX, minY, maxX, maxY];
}

function packData(mesh) {
var i, ii, j, jj;

var coords = mesh.coords;
var coordsPacked = new Float32Array(coords.length * 2);
for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
var xy = coords[i];
coordsPacked[j++] = xy[0];
coordsPacked[j++] = xy[1];
}
mesh.coords = coordsPacked;

var colors = mesh.colors;
var colorsPacked = new Uint8Array(colors.length * 3);
for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
var c = colors[i];
colorsPacked[j++] = c[0];
colorsPacked[j++] = c[1];
colorsPacked[j++] = c[2];
}
mesh.colors = colorsPacked;

var figures = mesh.figures;
for (i = 0, ii = figures.length; i < ii; i++) {
var figure = figures[i], ps = figure.coords, cs = figure.colors;
for (j = 0, jj = ps.length; j < jj; j++) {
ps[j] *= 2;
cs[j] *= 3;
}
}
}

function Mesh(stream, matrix, xref, res) {
assert(isStream(stream), 'Mesh data is not a stream');
var dict = stream.dict;
Expand Down Expand Up @@ -757,35 +789,14 @@ Shadings.Mesh = (function MeshClosure() {
}
// calculate bounds
updateBounds(this);

packData(this);
}

Mesh.prototype = {
getIR: function Mesh_getIR() {
var type = this.shadingType;
var i, ii, j;
var coords = this.coords;
var coordsPacked = new Float32Array(coords.length * 2);
for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
var xy = coords[i];
coordsPacked[j++] = xy[0];
coordsPacked[j++] = xy[1];
}
var colors = this.colors;
var colorsPacked = new Uint8Array(colors.length * 3);
for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
var c = colors[i];
colorsPacked[j++] = c[0];
colorsPacked[j++] = c[1];
colorsPacked[j++] = c[2];
}
var figures = this.figures;
var bbox = this.bbox;
var bounds = this.bounds;
var matrix = this.matrix;
var background = this.background;

return ['Mesh', type, coordsPacked, colorsPacked, figures, bounds,
matrix, bbox, background];
return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,
this.bounds, this.matrix, this.bbox, this.background];
}
};

Expand Down
7 changes: 7 additions & 0 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
68 changes: 51 additions & 17 deletions src/display/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -26,6 +27,7 @@

// Minimal font size that would be used during canvas fillText operations.
var MIN_FONT_SIZE = 16;
var MAX_GROUP_SIZE = 4096;

var COMPILE_TYPE3_GLYPHS = true;

Expand Down Expand Up @@ -600,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) {
Expand All @@ -630,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) {
Expand All @@ -651,7 +648,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}

// processing image in chunks to save memory
var chunkSize = 16;
var PIXELS_TO_PROCESS = 65536;
var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
for (var row = 0; row < height; row += chunkSize) {
var chunkHeight = Math.min(chunkSize, height - row);
var maskData = maskCtx.getImageData(0, row, width, chunkHeight);
Expand All @@ -662,9 +660,30 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {

maskCtx.putImageData(layerData, 0, row);
}
}

ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.drawImage(mask, smask.offsetX, smask.offsetY);
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);
}

var LINE_CAP_STYLES = ['butt', 'round', 'square'];
Expand Down Expand Up @@ -781,6 +800,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
endDrawing: function CanvasGraphics_endDrawing() {
this.ctx.restore();
CachedCanvases.clear();
WebGLUtils.clear();

if (this.textLayer) {
this.textLayer.endLayout();
Expand Down Expand Up @@ -904,6 +924,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.save();

var groupCtx = scratchCanvas.context;
groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);

Expand Down Expand Up @@ -1792,8 +1813,19 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
// Use ceil in case we're between sizes so we don't create canvas that is
// too small and make the canvas at least 1x1 pixels.
var drawnWidth = Math.max(Math.ceil(bounds[2] - bounds[0]), 1);
var drawnHeight = Math.max(Math.ceil(bounds[3] - bounds[1]), 1);
var offsetX = Math.floor(bounds[0]);
var offsetY = Math.floor(bounds[1]);
var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
var scaleX = 1, scaleY = 1;
if (drawnWidth > MAX_GROUP_SIZE) {
scaleX = drawnWidth / MAX_GROUP_SIZE;
drawnWidth = MAX_GROUP_SIZE;
}
if (drawnHeight > MAX_GROUP_SIZE) {
scaleY = drawnHeight / MAX_GROUP_SIZE;
drawnHeight = MAX_GROUP_SIZE;
}

var cacheId = 'groupAt' + this.groupLevel;
if (group.smask) {
Expand All @@ -1806,8 +1838,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {

// Since we created a new canvas that is just the size of the bounding box
// we have to translate the group ctx.
var offsetX = bounds[0];
var offsetY = bounds[1];
groupCtx.scale(1 / scaleX, 1 / scaleY);
groupCtx.translate(-offsetX, -offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);

Expand All @@ -1818,6 +1849,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
context: groupCtx,
offsetX: offsetX,
offsetY: offsetY,
scaleX: scaleX,
scaleY: scaleY,
subtype: group.smask.subtype,
backdrop: group.smask.backdrop,
colorSpace: group.colorSpace && ColorSpace.fromIR(group.colorSpace)
Expand All @@ -1827,6 +1860,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// right location.
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
currentCtx.translate(offsetX, offsetY);
currentCtx.scale(scaleX, scaleY);
}
// The transparency group inherits all off the current graphics state
// except the blend mode, soft mask, and alpha constants.
Expand Down
Loading