summaryrefslogtreecommitdiffstats
path: root/apps/files_pdfviewer/js/pdfjs/src/canvas.js
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_pdfviewer/js/pdfjs/src/canvas.js')
-rwxr-xr-xapps/files_pdfviewer/js/pdfjs/src/canvas.js869
1 files changed, 869 insertions, 0 deletions
diff --git a/apps/files_pdfviewer/js/pdfjs/src/canvas.js b/apps/files_pdfviewer/js/pdfjs/src/canvas.js
new file mode 100755
index 00000000000..9b3ed0ba9ad
--- /dev/null
+++ b/apps/files_pdfviewer/js/pdfjs/src/canvas.js
@@ -0,0 +1,869 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+'use strict';
+
+// <canvas> contexts store most of the state we need natively.
+// However, PDF needs a bit more state, which we store here.
+
+var CanvasExtraState = (function canvasExtraState() {
+ function constructor(old) {
+ // Are soft masks and alpha values shapes or opacities?
+ this.alphaIsShape = false;
+ this.fontSize = 0;
+ this.textMatrix = IDENTITY_MATRIX;
+ this.leading = 0;
+ // Current point (in user coordinates)
+ this.x = 0;
+ this.y = 0;
+ // Start of text line (in text coordinates)
+ this.lineX = 0;
+ this.lineY = 0;
+ // Character and word spacing
+ this.charSpacing = 0;
+ this.wordSpacing = 0;
+ this.textHScale = 1;
+ // Color spaces
+ this.fillColorSpace = new DeviceGrayCS();
+ this.fillColorSpaceObj = null;
+ this.strokeColorSpace = new DeviceGrayCS();
+ this.strokeColorSpaceObj = null;
+ this.fillColorObj = null;
+ this.strokeColorObj = null;
+ // Default fore and background colors
+ this.fillColor = '#000000';
+ this.strokeColor = '#000000';
+ // Note: fill alpha applies to all non-stroking operations
+ this.fillAlpha = 1;
+ this.strokeAlpha = 1;
+
+ this.old = old;
+ }
+
+ constructor.prototype = {
+ clone: function canvasextra_clone() {
+ return Object.create(this);
+ },
+ setCurrentPoint: function canvasextra_setCurrentPoint(x, y) {
+ this.x = x;
+ this.y = y;
+ }
+ };
+ return constructor;
+})();
+
+function ScratchCanvas(width, height) {
+ var canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+ return canvas;
+}
+
+var CanvasGraphics = (function canvasGraphics() {
+ // Defines the time the executeIRQueue is going to be executing
+ // before it stops and shedules a continue of execution.
+ var kExecutionTime = 50;
+
+ // Number of IR commands to execute before checking
+ // if we execute longer then `kExecutionTime`.
+ var kExecutionTimeCheck = 500;
+
+ function constructor(canvasCtx, objs) {
+ this.ctx = canvasCtx;
+ this.current = new CanvasExtraState();
+ this.stateStack = [];
+ this.pendingClip = null;
+ this.res = null;
+ this.xobjs = null;
+ this.ScratchCanvas = ScratchCanvas;
+ this.objs = objs;
+ }
+
+ var LINE_CAP_STYLES = ['butt', 'round', 'square'];
+ var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
+ var NORMAL_CLIP = {};
+ var EO_CLIP = {};
+
+ constructor.prototype = {
+ beginDrawing: function canvasGraphicsBeginDrawing(mediaBox) {
+ var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height;
+ this.ctx.save();
+ switch (mediaBox.rotate) {
+ case 0:
+ this.ctx.transform(1, 0, 0, -1, 0, ch);
+ break;
+ case 90:
+ this.ctx.transform(0, 1, 1, 0, 0, 0);
+ break;
+ case 180:
+ this.ctx.transform(-1, 0, 0, 1, cw, 0);
+ break;
+ case 270:
+ this.ctx.transform(0, -1, -1, 0, cw, ch);
+ break;
+ }
+ this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height);
+ },
+
+ executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
+ executionStartIdx, continueCallback) {
+ var argsArray = codeIR.argsArray;
+ var fnArray = codeIR.fnArray;
+ var i = executionStartIdx || 0;
+ var argsArrayLen = argsArray.length;
+
+ var executionEndIdx;
+ var startTime = Date.now();
+
+ var objs = this.objs;
+
+ do {
+ executionEndIdx = Math.min(argsArrayLen, i + kExecutionTimeCheck);
+
+ for (i; i < executionEndIdx; i++) {
+ if (fnArray[i] !== 'dependency') {
+ this[fnArray[i]].apply(this, argsArray[i]);
+ } else {
+ var deps = argsArray[i];
+ for (var n = 0, nn = deps.length; n < nn; n++) {
+ var depObjId = deps[n];
+
+ // If the promise isn't resolved yet, add the continueCallback
+ // to the promise and bail out.
+ if (!objs.isResolved(depObjId)) {
+ objs.get(depObjId, continueCallback);
+ return i;
+ }
+ }
+ }
+ }
+
+ // If the entire IRQueue was executed, stop as were done.
+ if (i == argsArrayLen) {
+ return i;
+ }
+
+ // If the execution took longer then a certain amount of time, shedule
+ // to continue exeution after a short delay.
+ // However, this is only possible if a 'continueCallback' is passed in.
+ if (continueCallback && (Date.now() - startTime) > kExecutionTime) {
+ setTimeout(continueCallback, 0);
+ return i;
+ }
+
+ // If the IRQueue isn't executed completly yet OR the execution time
+ // was short enough, do another execution round.
+ } while (true);
+ },
+
+ endDrawing: function canvasGraphicsEndDrawing() {
+ this.ctx.restore();
+ },
+
+ // Graphics state
+ setLineWidth: function canvasGraphicsSetLineWidth(width) {
+ this.ctx.lineWidth = width;
+ },
+ setLineCap: function canvasGraphicsSetLineCap(style) {
+ this.ctx.lineCap = LINE_CAP_STYLES[style];
+ },
+ setLineJoin: function canvasGraphicsSetLineJoin(style) {
+ this.ctx.lineJoin = LINE_JOIN_STYLES[style];
+ },
+ setMiterLimit: function canvasGraphicsSetMiterLimit(limit) {
+ this.ctx.miterLimit = limit;
+ },
+ setDash: function canvasGraphicsSetDash(dashArray, dashPhase) {
+ this.ctx.mozDash = dashArray;
+ this.ctx.mozDashOffset = dashPhase;
+ },
+ setRenderingIntent: function canvasGraphicsSetRenderingIntent(intent) {
+ TODO('set rendering intent: ' + intent);
+ },
+ setFlatness: function canvasGraphicsSetFlatness(flatness) {
+ TODO('set flatness: ' + flatness);
+ },
+ setGState: function canvasGraphicsSetGState(states) {
+ for (var i = 0, ii = states.length; i < ii; i++) {
+ var state = states[i];
+ var key = state[0];
+ var value = state[1];
+
+ switch (key) {
+ case 'LW':
+ this.setLineWidth(value);
+ break;
+ case 'LC':
+ this.setLineCap(value);
+ break;
+ case 'LJ':
+ this.setLineJoin(value);
+ break;
+ case 'ML':
+ this.setMiterLimit(value);
+ break;
+ case 'D':
+ this.setDash(value[0], value[1]);
+ break;
+ case 'RI':
+ this.setRenderingIntent(value);
+ break;
+ case 'FL':
+ this.setFlatness(value);
+ break;
+ case 'Font':
+ this.setFont(state[1], state[2]);
+ break;
+ case 'CA':
+ this.current.strokeAlpha = state[1];
+ break;
+ case 'ca':
+ this.current.fillAlpha = state[1];
+ this.ctx.globalAlpha = state[1];
+ break;
+ }
+ }
+ },
+ save: function canvasGraphicsSave() {
+ this.ctx.save();
+ var old = this.current;
+ this.stateStack.push(old);
+ this.current = old.clone();
+ },
+ restore: function canvasGraphicsRestore() {
+ var prev = this.stateStack.pop();
+ if (prev) {
+ this.current = prev;
+ this.ctx.restore();
+ }
+ },
+ transform: function canvasGraphicsTransform(a, b, c, d, e, f) {
+ this.ctx.transform(a, b, c, d, e, f);
+ },
+
+ // Path
+ moveTo: function canvasGraphicsMoveTo(x, y) {
+ this.ctx.moveTo(x, y);
+ this.current.setCurrentPoint(x, y);
+ },
+ lineTo: function canvasGraphicsLineTo(x, y) {
+ this.ctx.lineTo(x, y);
+ this.current.setCurrentPoint(x, y);
+ },
+ curveTo: function canvasGraphicsCurveTo(x1, y1, x2, y2, x3, y3) {
+ this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
+ this.current.setCurrentPoint(x3, y3);
+ },
+ curveTo2: function canvasGraphicsCurveTo2(x2, y2, x3, y3) {
+ var current = this.current;
+ this.ctx.bezierCurveTo(current.x, current.y, x2, y2, x3, y3);
+ current.setCurrentPoint(x3, y3);
+ },
+ curveTo3: function canvasGraphicsCurveTo3(x1, y1, x3, y3) {
+ this.curveTo(x1, y1, x3, y3, x3, y3);
+ this.current.setCurrentPoint(x3, y3);
+ },
+ closePath: function canvasGraphicsClosePath() {
+ this.ctx.closePath();
+ },
+ rectangle: function canvasGraphicsRectangle(x, y, width, height) {
+ this.ctx.rect(x, y, width, height);
+ },
+ stroke: function canvasGraphicsStroke(consumePath) {
+ consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
+ var ctx = this.ctx;
+ var strokeColor = this.current.strokeColor;
+ // For stroke we want to temporarily change the global alpha to the
+ // stroking alpha.
+ ctx.globalAlpha = this.current.strokeAlpha;
+ if (strokeColor && strokeColor.hasOwnProperty('type') &&
+ strokeColor.type === 'Pattern') {
+ // for patterns, we transform to pattern space, calculate
+ // the pattern, call stroke, and restore to user space
+ ctx.save();
+ ctx.strokeStyle = strokeColor.getPattern(ctx);
+ ctx.stroke();
+ ctx.restore();
+ } else {
+ ctx.stroke();
+ }
+ if (consumePath)
+ this.consumePath();
+ // Restore the global alpha to the fill alpha
+ ctx.globalAlpha = this.current.fillAlpha;
+ },
+ closeStroke: function canvasGraphicsCloseStroke() {
+ this.closePath();
+ this.stroke();
+ },
+ fill: function canvasGraphicsFill(consumePath) {
+ consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
+ var ctx = this.ctx;
+ var fillColor = this.current.fillColor;
+
+ if (fillColor && fillColor.hasOwnProperty('type') &&
+ fillColor.type === 'Pattern') {
+ ctx.save();
+ ctx.fillStyle = fillColor.getPattern(ctx);
+ ctx.fill();
+ ctx.restore();
+ } else {
+ ctx.fill();
+ }
+ if (consumePath)
+ this.consumePath();
+ },
+ eoFill: function canvasGraphicsEoFill() {
+ var savedFillRule = this.setEOFillRule();
+ this.fill();
+ this.restoreFillRule(savedFillRule);
+ },
+ fillStroke: function canvasGraphicsFillStroke() {
+ this.fill(false);
+ this.stroke(false);
+
+ this.consumePath();
+ },
+ eoFillStroke: function canvasGraphicsEoFillStroke() {
+ var savedFillRule = this.setEOFillRule();
+ this.fillStroke();
+ this.restoreFillRule(savedFillRule);
+ },
+ closeFillStroke: function canvasGraphicsCloseFillStroke() {
+ this.closePath();
+ this.fillStroke();
+ },
+ closeEOFillStroke: function canvasGraphicsCloseEOFillStroke() {
+ var savedFillRule = this.setEOFillRule();
+ this.closePath();
+ this.fillStroke();
+ this.restoreFillRule(savedFillRule);
+ },
+ endPath: function canvasGraphicsEndPath() {
+ this.consumePath();
+ },
+
+ // Clipping
+ clip: function canvasGraphicsClip() {
+ this.pendingClip = NORMAL_CLIP;
+ },
+ eoClip: function canvasGraphicsEoClip() {
+ this.pendingClip = EO_CLIP;
+ },
+
+ // Text
+ beginText: function canvasGraphicsBeginText() {
+ this.current.textMatrix = IDENTITY_MATRIX;
+ this.current.x = this.current.lineX = 0;
+ this.current.y = this.current.lineY = 0;
+ },
+ endText: function canvasGraphicsEndText() {
+ },
+ setCharSpacing: function canvasGraphicsSetCharSpacing(spacing) {
+ this.current.charSpacing = spacing;
+ },
+ setWordSpacing: function canvasGraphicsSetWordSpacing(spacing) {
+ this.current.wordSpacing = spacing;
+ },
+ setHScale: function canvasGraphicsSetHScale(scale) {
+ this.current.textHScale = scale / 100;
+ },
+ setLeading: function canvasGraphicsSetLeading(leading) {
+ this.current.leading = -leading;
+ },
+ setFont: function canvasGraphicsSetFont(fontRefName, size) {
+ var fontObj = this.objs.get(fontRefName).fontObj;
+
+ if (!fontObj) {
+ throw 'Can\'t find font for ' + fontRefName;
+ }
+
+ var name = fontObj.loadedName || 'sans-serif';
+
+ this.current.font = fontObj;
+ this.current.fontSize = size;
+
+ var name = fontObj.loadedName || 'sans-serif';
+ var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
+ (fontObj.bold ? 'bold' : 'normal');
+
+ var italic = fontObj.italic ? 'italic' : 'normal';
+ var serif = fontObj.serif ? 'serif' : 'sans-serif';
+ var typeface = '"' + name + '", ' + serif;
+ var rule = italic + ' ' + bold + ' ' + size + 'px ' + typeface;
+ this.ctx.font = rule;
+ },
+ setTextRenderingMode: function canvasGraphicsSetTextRenderingMode(mode) {
+ TODO('text rendering mode: ' + mode);
+ },
+ setTextRise: function canvasGraphicsSetTextRise(rise) {
+ TODO('text rise: ' + rise);
+ },
+ moveText: function canvasGraphicsMoveText(x, y) {
+ this.current.x = this.current.lineX += x;
+ this.current.y = this.current.lineY += y;
+ },
+ setLeadingMoveText: function canvasGraphicsSetLeadingMoveText(x, y) {
+ this.setLeading(-y);
+ this.moveText(x, y);
+ },
+ setTextMatrix: function canvasGraphicsSetTextMatrix(a, b, c, d, e, f) {
+ this.current.textMatrix = [a, b, c, d, e, f];
+
+ this.current.x = this.current.lineX = 0;
+ this.current.y = this.current.lineY = 0;
+ },
+ nextLine: function canvasGraphicsNextLine() {
+ this.moveText(0, this.current.leading);
+ },
+ showText: function canvasGraphicsShowText(text) {
+ var ctx = this.ctx;
+ var current = this.current;
+ var font = current.font;
+ var glyphs = font.charsToGlyphs(text);
+ var fontSize = current.fontSize;
+ var charSpacing = current.charSpacing;
+ var wordSpacing = current.wordSpacing;
+ var textHScale = current.textHScale;
+ var glyphsLength = glyphs.length;
+ if (font.coded) {
+ ctx.save();
+ ctx.transform.apply(ctx, current.textMatrix);
+ ctx.translate(current.x, current.y);
+
+ var fontMatrix = font.fontMatrix || IDENTITY_MATRIX;
+ ctx.scale(1 / textHScale, 1);
+ for (var i = 0; i < glyphsLength; ++i) {
+
+ var glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ this.ctx.translate(wordSpacing, 0);
+ continue;
+ }
+
+ this.save();
+ ctx.scale(fontSize, fontSize);
+ ctx.transform.apply(ctx, fontMatrix);
+ this.executeIRQueue(glyph.codeIRQueue);
+ this.restore();
+
+ var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
+ var width = transformed[0] * fontSize + charSpacing;
+
+ ctx.translate(width, 0);
+ current.x += width;
+
+ }
+ ctx.restore();
+ } else {
+ ctx.save();
+ ctx.transform.apply(ctx, current.textMatrix);
+ ctx.scale(1, -1);
+ ctx.translate(current.x, -1 * current.y);
+ ctx.transform.apply(ctx, font.fontMatrix || IDENTITY_MATRIX);
+
+ ctx.scale(1 / textHScale, 1);
+
+ var width = 0;
+ for (var i = 0; i < glyphsLength; ++i) {
+ var glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ width += wordSpacing;
+ continue;
+ }
+
+ var unicode = glyph.unicode;
+ var char = (unicode >= 0x10000) ?
+ String.fromCharCode(0xD800 | ((unicode - 0x10000) >> 10),
+ 0xDC00 | (unicode & 0x3FF)) : String.fromCharCode(unicode);
+
+ ctx.fillText(char, width, 0);
+ width += glyph.width * fontSize * 0.001 + charSpacing;
+ }
+ current.x += width;
+
+ ctx.restore();
+ }
+ },
+
+ showSpacedText: function canvasGraphicsShowSpacedText(arr) {
+ var ctx = this.ctx;
+ var current = this.current;
+ var fontSize = current.fontSize;
+ var textHScale = current.textHScale;
+ var arrLength = arr.length;
+ for (var i = 0; i < arrLength; ++i) {
+ var e = arr[i];
+ if (isNum(e)) {
+ current.x -= e * 0.001 * fontSize * textHScale;
+ } else if (isString(e)) {
+ this.showText(e);
+ } else {
+ malformed('TJ array element ' + e + ' is not string or num');
+ }
+ }
+ },
+ nextLineShowText: function canvasGraphicsNextLineShowText(text) {
+ this.nextLine();
+ this.showText(text);
+ },
+ nextLineSetSpacingShowText:
+ function canvasGraphicsNextLineSetSpacingShowText(wordSpacing,
+ charSpacing,
+ text) {
+ this.setWordSpacing(wordSpacing);
+ this.setCharSpacing(charSpacing);
+ this.nextLineShowText(text);
+ },
+
+ // Type3 fonts
+ setCharWidth: function canvasGraphicsSetCharWidth(xWidth, yWidth) {
+ // We can safely ignore this since the width should be the same
+ // as the width in the Widths array.
+ },
+ setCharWidthAndBounds: function canvasGraphicsSetCharWidthAndBounds(xWidth,
+ yWidth,
+ llx,
+ lly,
+ urx,
+ ury) {
+ // TODO According to the spec we're also suppose to ignore any operators
+ // that set color or include images while processing this type3 font.
+ this.rectangle(llx, lly, urx - llx, ury - lly);
+ this.clip();
+ this.endPath();
+ },
+
+ // Color
+ setStrokeColorSpace: function canvasGraphicsSetStrokeColorSpace(raw) {
+ this.current.strokeColorSpace = ColorSpace.fromIR(raw);
+ },
+ setFillColorSpace: function canvasGraphicsSetFillColorSpace(raw) {
+ this.current.fillColorSpace = ColorSpace.fromIR(raw);
+ },
+ setStrokeColor: function canvasGraphicsSetStrokeColor(/*...*/) {
+ var cs = this.current.strokeColorSpace;
+ var color = cs.getRgb(arguments);
+ var color = Util.makeCssRgb.apply(null, cs.getRgb(arguments));
+ this.ctx.strokeStyle = color;
+ this.current.strokeColor = color;
+ },
+ getColorN_IR_Pattern: function canvasGraphicsGetColorN_IR_Pattern(IR, cs) {
+ if (IR[0] == 'TilingPattern') {
+ var args = IR[1];
+ var base = cs.base;
+ var color;
+ if (base) {
+ var baseComps = base.numComps;
+
+ color = [];
+ for (var i = 0; i < baseComps; ++i)
+ color.push(args[i]);
+
+ color = base.getRgb(color);
+ }
+ var pattern = new TilingPattern(IR, color, this.ctx, this.objs);
+ } else if (IR[0] == 'RadialAxial' || IR[0] == 'Dummy') {
+ var pattern = Pattern.shadingFromIR(this.ctx, IR);
+ } else {
+ throw 'Unkown IR type';
+ }
+ return pattern;
+ },
+ setStrokeColorN_IR: function canvasGraphicsSetStrokeColorN(/*...*/) {
+ var cs = this.current.strokeColorSpace;
+
+ if (cs.name == 'Pattern') {
+ this.current.strokeColor = this.getColorN_IR_Pattern(arguments, cs);
+ } else {
+ this.setStrokeColor.apply(this, arguments);
+ }
+ },
+ setFillColor: function canvasGraphicsSetFillColor(/*...*/) {
+ var cs = this.current.fillColorSpace;
+ var color = Util.makeCssRgb.apply(null, cs.getRgb(arguments));
+ this.ctx.fillStyle = color;
+ this.current.fillColor = color;
+ },
+ setFillColorN_IR: function canvasGraphicsSetFillColorN(/*...*/) {
+ var cs = this.current.fillColorSpace;
+
+ if (cs.name == 'Pattern') {
+ this.current.fillColor = this.getColorN_IR_Pattern(arguments, cs);
+ } else {
+ this.setFillColor.apply(this, arguments);
+ }
+ },
+ setStrokeGray: function canvasGraphicsSetStrokeGray(gray) {
+ if (!(this.current.strokeColorSpace instanceof DeviceGrayCS))
+ this.current.strokeColorSpace = new DeviceGrayCS();
+
+ var color = Util.makeCssRgb(gray, gray, gray);
+ this.ctx.strokeStyle = color;
+ this.current.strokeColor = color;
+ },
+ setFillGray: function canvasGraphicsSetFillGray(gray) {
+ if (!(this.current.fillColorSpace instanceof DeviceGrayCS))
+ this.current.fillColorSpace = new DeviceGrayCS();
+
+ var color = Util.makeCssRgb(gray, gray, gray);
+ this.ctx.fillStyle = color;
+ this.current.fillColor = color;
+ },
+ setStrokeRGBColor: function canvasGraphicsSetStrokeRGBColor(r, g, b) {
+ if (!(this.current.strokeColorSpace instanceof DeviceRgbCS))
+ this.current.strokeColorSpace = new DeviceRgbCS();
+
+ var color = Util.makeCssRgb(r, g, b);
+ this.ctx.strokeStyle = color;
+ this.current.strokeColor = color;
+ },
+ setFillRGBColor: function canvasGraphicsSetFillRGBColor(r, g, b) {
+ if (!(this.current.fillColorSpace instanceof DeviceRgbCS))
+ this.current.fillColorSpace = new DeviceRgbCS();
+
+ var color = Util.makeCssRgb(r, g, b);
+ this.ctx.fillStyle = color;
+ this.current.fillColor = color;
+ },
+ setStrokeCMYKColor: function canvasGraphicsSetStrokeCMYKColor(c, m, y, k) {
+ if (!(this.current.strokeColorSpace instanceof DeviceCmykCS))
+ this.current.strokeColorSpace = new DeviceCmykCS();
+
+ var color = Util.makeCssCmyk(c, m, y, k);
+ this.ctx.strokeStyle = color;
+ this.current.strokeColor = color;
+ },
+ setFillCMYKColor: function canvasGraphicsSetFillCMYKColor(c, m, y, k) {
+ if (!(this.current.fillColorSpace instanceof DeviceCmykCS))
+ this.current.fillColorSpace = new DeviceCmykCS();
+
+ var color = Util.makeCssCmyk(c, m, y, k);
+ this.ctx.fillStyle = color;
+ this.current.fillColor = color;
+ },
+
+ shadingFill: function canvasGraphicsShadingFill(patternIR) {
+ var ctx = this.ctx;
+
+ this.save();
+ ctx.fillStyle = Pattern.shadingFromIR(ctx, patternIR);
+
+ var inv = ctx.mozCurrentTransformInverse;
+ if (inv) {
+ var canvas = ctx.canvas;
+ var width = canvas.width;
+ var height = canvas.height;
+
+ var bl = Util.applyTransform([0, 0], inv);
+ var br = Util.applyTransform([0, width], inv);
+ var ul = Util.applyTransform([height, 0], inv);
+ var ur = Util.applyTransform([height, width], inv);
+
+ var x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
+ var y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
+ var x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
+ var y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
+
+ this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
+ } else {
+ // HACK to draw the gradient onto an infinite rectangle.
+ // PDF gradients are drawn across the entire image while
+ // Canvas only allows gradients to be drawn in a rectangle
+ // The following bug should allow us to remove this.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=664884
+
+ this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
+ }
+
+ this.restore();
+ },
+
+ // Images
+ beginInlineImage: function canvasGraphicsBeginInlineImage() {
+ error('Should not call beginInlineImage');
+ },
+ beginImageData: function canvasGraphicsBeginImageData() {
+ error('Should not call beginImageData');
+ },
+
+ paintFormXObjectBegin: function canvasGraphicsPaintFormXObjectBegin(matrix,
+ bbox) {
+ this.save();
+
+ if (matrix && isArray(matrix) && 6 == matrix.length)
+ this.transform.apply(this, matrix);
+
+ if (bbox && isArray(bbox) && 4 == bbox.length) {
+ var width = bbox[2] - bbox[0];
+ var height = bbox[3] - bbox[1];
+ this.rectangle(bbox[0], bbox[1], width, height);
+ this.clip();
+ this.endPath();
+ }
+ },
+
+ paintFormXObjectEnd: function canvasGraphicsPaintFormXObjectEnd() {
+ this.restore();
+ },
+
+ paintJpegXObject: function canvasGraphicsPaintJpegXObject(objId, w, h) {
+ var image = this.objs.get(objId);
+ if (!image) {
+ error('Dependent image isn\'t ready yet');
+ }
+
+ this.save();
+
+ var ctx = this.ctx;
+ // scale the image to the unit square
+ ctx.scale(1 / w, -1 / h);
+
+ var domImage = image.getImage();
+ ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
+ 0, -h, w, h);
+
+ this.restore();
+ },
+
+ paintImageMaskXObject: function canvasGraphicsPaintImageMaskXObject(
+ imgArray, inverseDecode, width, height) {
+ function applyStencilMask(buffer, inverseDecode) {
+ var imgArrayPos = 0;
+ var i, j, mask, buf;
+ // removing making non-masked pixels transparent
+ var bufferPos = 3; // alpha component offset
+ for (i = 0; i < height; i++) {
+ mask = 0;
+ for (j = 0; j < width; j++) {
+ if (!mask) {
+ buf = imgArray[imgArrayPos++];
+ mask = 128;
+ }
+ if (!(buf & mask) == inverseDecode) {
+ buffer[bufferPos] = 0;
+ }
+ bufferPos += 4;
+ mask >>= 1;
+ }
+ }
+ }
+
+ this.save();
+
+ var ctx = this.ctx;
+ var w = width, h = height;
+ // scale the image to the unit square
+ ctx.scale(1 / w, -1 / h);
+
+ var tmpCanvas = new this.ScratchCanvas(w, h);
+ var tmpCtx = tmpCanvas.getContext('2d');
+
+ var fillColor = this.current.fillColor;
+ tmpCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
+ fillColor.type === 'Pattern') ?
+ fillColor.getPattern(tmpCtx) : fillColor;
+ tmpCtx.fillRect(0, 0, w, h);
+
+ var imgData = tmpCtx.getImageData(0, 0, w, h);
+ var pixels = imgData.data;
+
+ applyStencilMask(pixels, inverseDecode);
+
+ tmpCtx.putImageData(imgData, 0, 0);
+ ctx.drawImage(tmpCanvas, 0, -h);
+ this.restore();
+ },
+
+ paintImageXObject: function canvasGraphicsPaintImageXObject(imgData) {
+ this.save();
+ var ctx = this.ctx;
+ var w = imgData.width;
+ var h = imgData.height;
+ // scale the image to the unit square
+ ctx.scale(1 / w, -1 / h);
+
+ var tmpCanvas = new this.ScratchCanvas(w, h);
+ var tmpCtx = tmpCanvas.getContext('2d');
+ var tmpImgData;
+
+ // Some browsers can set an UInt8Array directly as imageData, some
+ // can't. As long as we don't have proper feature detection, just
+ // copy over each pixel and set the imageData that way.
+ tmpImgData = tmpCtx.getImageData(0, 0, w, h);
+
+ // Copy over the imageData.
+ var tmpImgDataPixels = tmpImgData.data;
+ var len = tmpImgDataPixels.length;
+
+ while (len--) {
+ tmpImgDataPixels[len] = imgData.data[len];
+ }
+
+ tmpCtx.putImageData(tmpImgData, 0, 0);
+ ctx.drawImage(tmpCanvas, 0, -h);
+ this.restore();
+ },
+
+ // Marked content
+
+ markPoint: function canvasGraphicsMarkPoint(tag) {
+ TODO('Marked content');
+ },
+ markPointProps: function canvasGraphicsMarkPointProps(tag, properties) {
+ TODO('Marked content');
+ },
+ beginMarkedContent: function canvasGraphicsBeginMarkedContent(tag) {
+ TODO('Marked content');
+ },
+ beginMarkedContentProps:
+ function canvasGraphicsBeginMarkedContentProps(tag, properties) {
+ TODO('Marked content');
+ },
+ endMarkedContent: function canvasGraphicsEndMarkedContent() {
+ TODO('Marked content');
+ },
+
+ // Compatibility
+
+ beginCompat: function canvasGraphicsBeginCompat() {
+ TODO('ignore undefined operators (should we do that anyway?)');
+ },
+ endCompat: function canvasGraphicsEndCompat() {
+ TODO('stop ignoring undefined operators');
+ },
+
+ // Helper functions
+
+ consumePath: function canvasGraphicsConsumePath() {
+ if (this.pendingClip) {
+ var savedFillRule = null;
+ if (this.pendingClip == EO_CLIP)
+ savedFillRule = this.setEOFillRule();
+
+ this.ctx.clip();
+
+ this.pendingClip = null;
+ if (savedFillRule !== null)
+ this.restoreFillRule(savedFillRule);
+ }
+ this.ctx.beginPath();
+ },
+ // We generally keep the canvas context set for
+ // nonzero-winding, and just set evenodd for the operations
+ // that need them.
+ setEOFillRule: function canvasGraphicsSetEOFillRule() {
+ var savedFillRule = this.ctx.mozFillRule;
+ this.ctx.mozFillRule = 'evenodd';
+ return savedFillRule;
+ },
+ restoreFillRule: function canvasGraphicsRestoreFillRule(rule) {
+ this.ctx.mozFillRule = rule;
+ }
+ };
+
+ return constructor;
+})();
+