diff --git a/src/display/canvas.js b/src/display/canvas.js index 5f03e6418..42243541e 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -29,6 +29,9 @@ var MIN_FONT_SIZE = 16; var MAX_GROUP_SIZE = 4096; var COMPILE_TYPE3_GLYPHS = true; +var MAX_SIZE_TO_COMPILE = 1000; + +var FULL_CHUNK_HEIGHT = 16; function createScratchCanvas(width, height) { var canvas = document.createElement('canvas'); @@ -162,7 +165,7 @@ var CachedCanvases = (function CachedCanvasesClosure() { getCanvas: function CachedCanvases_getCanvas(id, width, height, trackTransform) { var canvasEntry; - if (id in cache) { + if (cache[id] !== undefined) { canvasEntry = cache[id]; canvasEntry.canvas.width = width; canvasEntry.canvas.height = height; @@ -376,6 +379,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() { // Default fore and background colors this.fillColor = '#000000'; this.strokeColor = '#000000'; + this.patternFill = false; // Note: fill alpha applies to all non-stroking operations this.fillAlpha = 1; this.strokeAlpha = 1; @@ -448,13 +452,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { // that's ok; any such pixels are ignored. var height = imgData.height, width = imgData.width; - var fullChunkHeight = 16; - var fracChunks = height / fullChunkHeight; - var fullChunks = Math.floor(fracChunks); - var totalChunks = Math.ceil(fracChunks); - var partialChunkHeight = height - fullChunks * fullChunkHeight; + var partialChunkHeight = height % FULL_CHUNK_HEIGHT; + var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; + var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; - var chunkImgData = ctx.createImageData(width, fullChunkHeight); + var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); var srcPos = 0, destPos; var src = imgData.data; var dest = chunkImgData.data; @@ -474,7 +476,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { 0xFF000000 : 0x000000FF; for (i = 0; i < totalChunks; i++) { thisChunkHeight = - (i < fullChunks) ? fullChunkHeight : partialChunkHeight; + (i < fullChunks) ? FULL_CHUNK_HEIGHT : partialChunkHeight; destPos = 0; for (j = 0; j < thisChunkHeight; j++) { var srcDiff = srcLength - srcPos; @@ -509,19 +511,19 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { dest32[destPos++] = 0; } - ctx.putImageData(chunkImgData, 0, i * fullChunkHeight); + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); } } else if (imgData.kind === ImageKind.RGBA_32BPP) { // RGBA, 32-bits per pixel. j = 0; - elemsInThisChunk = width * fullChunkHeight * 4; + elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4; for (i = 0; i < fullChunks; i++) { dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); srcPos += elemsInThisChunk; ctx.putImageData(chunkImgData, 0, j); - j += fullChunkHeight; + j += FULL_CHUNK_HEIGHT; } if (i < totalChunks) { elemsInThisChunk = width * partialChunkHeight * 4; @@ -531,11 +533,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { } else if (imgData.kind === ImageKind.RGB_24BPP) { // RGB, 24-bits per pixel. - thisChunkHeight = fullChunkHeight; + thisChunkHeight = FULL_CHUNK_HEIGHT; elemsInThisChunk = width * thisChunkHeight; for (i = 0; i < totalChunks; i++) { if (i >= fullChunks) { - thisChunkHeight =partialChunkHeight; + thisChunkHeight = partialChunkHeight; elemsInThisChunk = width * thisChunkHeight; } @@ -546,7 +548,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { dest[destPos++] = src[srcPos++]; dest[destPos++] = 255; } - ctx.putImageData(chunkImgData, 0, i * fullChunkHeight); + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); } } else { error('bad image kind: ' + imgData.kind); @@ -555,20 +557,18 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { function putBinaryImageMask(ctx, imgData) { var height = imgData.height, width = imgData.width; - var fullChunkHeight = 16; - var fracChunks = height / fullChunkHeight; - var fullChunks = Math.floor(fracChunks); - var totalChunks = Math.ceil(fracChunks); - var partialChunkHeight = height - fullChunks * fullChunkHeight; + var partialChunkHeight = height % FULL_CHUNK_HEIGHT; + var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; + var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; - var chunkImgData = ctx.createImageData(width, fullChunkHeight); + var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); var srcPos = 0; var src = imgData.data; var dest = chunkImgData.data; for (var i = 0; i < totalChunks; i++) { var thisChunkHeight = - (i < fullChunks) ? fullChunkHeight : partialChunkHeight; + (i < fullChunks) ? FULL_CHUNK_HEIGHT : partialChunkHeight; // Expand the mask so it can be used by the canvas. Any required // inversion has already been handled. @@ -585,7 +585,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { mask >>= 1; } } - ctx.putImageData(chunkImgData, 0, i * fullChunkHeight); + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); } } @@ -595,14 +595,14 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { 'globalCompositeOperation', 'font']; for (var i = 0, ii = properties.length; i < ii; i++) { var property = properties[i]; - if (property in sourceCtx) { + if (sourceCtx[property] !== undefined) { destCtx[property] = sourceCtx[property]; } } - if ('setLineDash' in sourceCtx) { + if (sourceCtx.setLineDash !== undefined) { destCtx.setLineDash(sourceCtx.getLineDash()); destCtx.lineDashOffset = sourceCtx.lineDashOffset; - } else if ('mozDash' in sourceCtx) { + } else if (sourceCtx.mozDashOffset !== undefined) { destCtx.mozDash = sourceCtx.mozDash; destCtx.mozDashOffset = sourceCtx.mozDashOffset; } @@ -829,7 +829,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, setDash: function CanvasGraphics_setDash(dashArray, dashPhase) { var ctx = this.ctx; - if ('setLineDash' in ctx) { + if (ctx.setLineDash !== undefined) { ctx.setLineDash(dashArray); ctx.lineDashOffset = dashPhase; } else { @@ -1072,10 +1072,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { consumePath = typeof consumePath !== 'undefined' ? consumePath : true; var ctx = this.ctx; var fillColor = this.current.fillColor; + var isPatternFill = this.current.patternFill; var needRestore = false; - if (fillColor && fillColor.hasOwnProperty('type') && - fillColor.type === 'Pattern') { + if (isPatternFill) { ctx.save(); ctx.fillStyle = fillColor.getPattern(ctx, this); needRestore = true; @@ -1549,6 +1549,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) { this.current.fillColor = this.getColorN_Pattern(arguments); + this.current.patternFill = true; }, setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) { var color = Util.makeCssRgb(arguments); @@ -1559,6 +1560,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { var color = Util.makeCssRgb(arguments); this.ctx.fillStyle = color; this.current.fillColor = color; + this.current.patternFill = false; }, shadingFill: function CanvasGraphics_shadingFill(patternIR) { @@ -1817,11 +1819,12 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) { var ctx = this.ctx; var width = img.width, height = img.height; + var fillColor = this.current.fillColor; + var isPatternFill = this.current.patternFill; var glyph = this.processingType3; - if (COMPILE_TYPE3_GLYPHS && glyph && !('compiled' in glyph)) { - var MAX_SIZE_TO_COMPILE = 1000; + if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) { if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) { glyph.compiled = compileType3Glyph({data: img.data, width: width, height: height}); @@ -1843,9 +1846,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { maskCtx.globalCompositeOperation = 'source-in'; - var fillColor = this.current.fillColor; - maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') && - fillColor.type === 'Pattern') ? + maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; maskCtx.fillRect(0, 0, width, height); @@ -1859,7 +1860,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { scaleY, positions) { var width = imgData.width; var height = imgData.height; - var ctx = this.ctx; + var fillColor = this.current.fillColor; + var isPatternFill = this.current.patternFill; var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height); var maskCtx = maskCanvas.context; @@ -1869,14 +1871,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { maskCtx.globalCompositeOperation = 'source-in'; - var fillColor = this.current.fillColor; - maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') && - fillColor.type === 'Pattern') ? - fillColor.getPattern(maskCtx, this) : fillColor; + maskCtx.fillStyle = isPatternFill ? + fillColor.getPattern(maskCtx, this) : fillColor; maskCtx.fillRect(0, 0, width, height); maskCtx.restore(); + var ctx = this.ctx; for (var i = 0, ii = positions.length; i < ii; i += 2) { ctx.save(); ctx.transform(scaleX, 0, 0, scaleY, positions[i], positions[i + 1]); @@ -1891,6 +1892,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { function CanvasGraphics_paintImageMaskXObjectGroup(images) { var ctx = this.ctx; + var fillColor = this.current.fillColor; + var isPatternFill = this.current.patternFill; for (var i = 0, ii = images.length; i < ii; i++) { var image = images[i]; var width = image.width, height = image.height; @@ -1903,9 +1906,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { maskCtx.globalCompositeOperation = 'source-in'; - var fillColor = this.current.fillColor; - maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') && - fillColor.type === 'Pattern') ? + maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; maskCtx.fillRect(0, 0, width, height);