Move client code into worker_client.js. Cleanup + comments + 2-space-indention
This commit is contained in:
		
							parent
							
								
									5e02659eb7
								
							
						
					
					
						commit
						405c367ece
					
				
							
								
								
									
										399
									
								
								canvas_proxy.js
									
									
									
									
									
								
							
							
						
						
									
										399
									
								
								canvas_proxy.js
									
									
									
									
									
								
							| @ -1,260 +1,239 @@ | ||||
| // var ImageCanvasProxyCounter = 0;
 | ||||
| // function ImageCanvasProxy(width, height) {
 | ||||
| //     this.id = ImageCanvasProxyCounter++;
 | ||||
| //     this.width = width;
 | ||||
| //     this.height = height;
 | ||||
| //
 | ||||
| //     // Using `Uint8ClampedArray` seems to be the type of ImageData - at least
 | ||||
| //     // Firebug tells me so.
 | ||||
| //     this.imgData = {
 | ||||
| //         data: Uint8ClampedArray(width * height * 4)
 | ||||
| //     };
 | ||||
| // }
 | ||||
| //
 | ||||
| // ImageCanvasProxy.prototype.putImageData = function(imgData) {
 | ||||
| //     // this.ctx.putImageData(imgData, 0, 0);
 | ||||
| // }
 | ||||
| //
 | ||||
| // ImageCanvasProxy.prototype.getCanvas = function() {
 | ||||
| //     return this;
 | ||||
| // }
 | ||||
| 
 | ||||
| var JpegStreamProxyCounter = 0; | ||||
| // WebWorker Proxy for JpegStream.
 | ||||
| var JpegStreamProxy = (function() { | ||||
|     function constructor(bytes, dict) { | ||||
|         this.id = JpegStreamProxyCounter++; | ||||
|         this.dict = dict; | ||||
|   function constructor(bytes, dict) { | ||||
|     this.id = JpegStreamProxyCounter++; | ||||
|     this.dict = dict; | ||||
| 
 | ||||
|         // create DOM image.
 | ||||
|         postMessage("jpeg_stream"); | ||||
|         postMessage({ | ||||
|             id:  this.id, | ||||
|             str: bytesToString(bytes) | ||||
|         }); | ||||
|     // Tell the main thread to create an image.
 | ||||
|     postMessage("jpeg_stream"); | ||||
|     postMessage({ | ||||
|       id:  this.id, | ||||
|       str: bytesToString(bytes) | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|         // var img = new Image();
 | ||||
|         // img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes));
 | ||||
|         // this.domImage = img;
 | ||||
|   constructor.prototype = { | ||||
|     getImage: function() { | ||||
|       return this; | ||||
|     }, | ||||
|     getChar: function() { | ||||
|       error("internal error: getChar is not valid on JpegStream"); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|     constructor.prototype = { | ||||
|         getImage: function() { | ||||
|             return this; | ||||
|             // return this.domImage;
 | ||||
|         }, | ||||
|         getChar: function() { | ||||
|             error("internal error: getChar is not valid on JpegStream"); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     return constructor; | ||||
|   return constructor; | ||||
| })(); | ||||
| 
 | ||||
| // Really simple GradientProxy. There is currently only one active gradient at
 | ||||
| // the time, meaning you can't create a gradient, create a second one and then
 | ||||
| // use the first one again. As this isn't used in pdf.js right now, it's okay.
 | ||||
| function GradientProxy(stack, x0, y0, x1, y1) { | ||||
|     stack.push(["$createLinearGradient", [x0, y0, x1, y1]]); | ||||
|     this.addColorStop = function(i, rgba) { | ||||
|         stack.push(["$addColorStop", [i, rgba]]); | ||||
|     } | ||||
|   stack.push(["$createLinearGradient", [x0, y0, x1, y1]]); | ||||
|   this.addColorStop = function(i, rgba) { | ||||
|     stack.push(["$addColorStop", [i, rgba]]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Really simple PatternProxy.
 | ||||
| var patternProxyCounter = 0; | ||||
| function PatternProxy(stack, object, kind) { | ||||
|     this.id = patternProxyCounter++; | ||||
|   this.id = patternProxyCounter++; | ||||
| 
 | ||||
|     if (!(object instanceof CanvasProxy) ) { | ||||
|         throw "unkown type to createPattern"; | ||||
|     } | ||||
|     // Flush the object here to ensure it's available on the main thread.
 | ||||
|     // TODO: Make some kind of dependency management, such that the object
 | ||||
|     // gets flushed only if needed.
 | ||||
|     object.flush(); | ||||
|     stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); | ||||
|   if (!(object instanceof CanvasProxy) ) { | ||||
|     throw "unkown type to createPattern"; | ||||
|   } | ||||
| 
 | ||||
|   // Flush the object here to ensure it's available on the main thread.
 | ||||
|   // TODO: Make some kind of dependency management, such that the object
 | ||||
|   // gets flushed only if needed.
 | ||||
|   object.flush(); | ||||
|   stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); | ||||
| } | ||||
| 
 | ||||
| var canvasProxyCounter = 0; | ||||
| function CanvasProxy(width, height) { | ||||
|     this.id = canvasProxyCounter++; | ||||
|   this.id = canvasProxyCounter++; | ||||
| 
 | ||||
|     var stack = this.$stack = []; | ||||
|   // The `stack` holds the rendering calls and gets flushed to the main thead.
 | ||||
|   var stack = this.$stack = []; | ||||
| 
 | ||||
|     // Dummy context exposed.
 | ||||
|     var ctx = {}; | ||||
|     this.getContext = function(type) { | ||||
|         if (type != "2d") { | ||||
|             throw "CanvasProxy can only provide a 2d context."; | ||||
|         } | ||||
|         return ctx; | ||||
|   // Dummy context that gets exposed.
 | ||||
|   var ctx = {}; | ||||
|   this.getContext = function(type) { | ||||
|     if (type != "2d") { | ||||
|       throw "CanvasProxy can only provide a 2d context."; | ||||
|     } | ||||
|     return ctx; | ||||
|   } | ||||
| 
 | ||||
|     // Expose only the minimum of the canvas object - there is no dom to do
 | ||||
|     // more here.
 | ||||
|     this.width = width; | ||||
|     this.height = height; | ||||
|     ctx.canvas = this; | ||||
|   // Expose only the minimum of the canvas object - there is no dom to do
 | ||||
|   // more here.
 | ||||
|   this.width = width; | ||||
|   this.height = height; | ||||
|   ctx.canvas = this; | ||||
| 
 | ||||
|     var ctxFunc = [ | ||||
|         "createRadialGradient", | ||||
|         "arcTo", | ||||
|         "arc", | ||||
|         "fillText", | ||||
|         "strokeText", | ||||
|         // "drawImage",
 | ||||
|         // "getImageData",
 | ||||
|         // "putImageData",
 | ||||
|         "createImageData", | ||||
|         "drawWindow", | ||||
|         "save", | ||||
|         "restore", | ||||
|         "scale", | ||||
|         "rotate", | ||||
|         "translate", | ||||
|         "transform", | ||||
|         "setTransform", | ||||
|         // "createLinearGradient",
 | ||||
|         // "createPattern",
 | ||||
|         "clearRect", | ||||
|         "fillRect", | ||||
|         "strokeRect", | ||||
|         "beginPath", | ||||
|         "closePath", | ||||
|         "moveTo", | ||||
|         "lineTo", | ||||
|         "quadraticCurveTo", | ||||
|         "bezierCurveTo", | ||||
|         "rect", | ||||
|         "fill", | ||||
|         "stroke", | ||||
|         "clip", | ||||
|         "measureText", | ||||
|         "isPointInPath", | ||||
|   // Setup function calls to `ctx`.
 | ||||
|   var ctxFunc = [ | ||||
|   "createRadialGradient", | ||||
|   "arcTo", | ||||
|   "arc", | ||||
|   "fillText", | ||||
|   "strokeText", | ||||
|   "createImageData", | ||||
|   "drawWindow", | ||||
|   "save", | ||||
|   "restore", | ||||
|   "scale", | ||||
|   "rotate", | ||||
|   "translate", | ||||
|   "transform", | ||||
|   "setTransform", | ||||
|   "clearRect", | ||||
|   "fillRect", | ||||
|   "strokeRect", | ||||
|   "beginPath", | ||||
|   "closePath", | ||||
|   "moveTo", | ||||
|   "lineTo", | ||||
|   "quadraticCurveTo", | ||||
|   "bezierCurveTo", | ||||
|   "rect", | ||||
|   "fill", | ||||
|   "stroke", | ||||
|   "clip", | ||||
|   "measureText", | ||||
|   "isPointInPath", | ||||
| 
 | ||||
|         "$setCurrentX", | ||||
|         "$addCurrentX", | ||||
|         "$saveCurrentX", | ||||
|         "$restoreCurrentX", | ||||
|         "$showText" | ||||
|     ]; | ||||
|   // These functions are necessary to track the rendering currentX state.
 | ||||
|   // The exact values can be computed on the main thread only, as the
 | ||||
|   // worker has no idea about text width.
 | ||||
|   "$setCurrentX", | ||||
|   "$addCurrentX", | ||||
|   "$saveCurrentX", | ||||
|   "$restoreCurrentX", | ||||
|   "$showText" | ||||
|   ]; | ||||
| 
 | ||||
|     ctx.createPattern = function(object, kind) { | ||||
|         return new PatternProxy(stack, object, kind); | ||||
|   function buildFuncCall(name) { | ||||
|     return function() { | ||||
|       // console.log("funcCall", name)
 | ||||
|       stack.push([name, Array.prototype.slice.call(arguments)]); | ||||
|     } | ||||
|   } | ||||
|   var name; | ||||
|   for (var i = 0; i < ctxFunc.length; i++) { | ||||
|     name = ctxFunc[i]; | ||||
|     ctx[name] = buildFuncCall(name); | ||||
|   } | ||||
| 
 | ||||
|     ctx.createLinearGradient = function(x0, y0, x1, y1) { | ||||
|         return new GradientProxy(stack, x0, y0, x1, y1); | ||||
|     } | ||||
|   // Some function calls that need more work.
 | ||||
| 
 | ||||
|     ctx.getImageData = function(x, y, w, h) { | ||||
|         return { | ||||
|             width: w, | ||||
|             height: h, | ||||
|             data: Uint8ClampedArray(w * h * 4) | ||||
|         }; | ||||
|     } | ||||
|   ctx.createPattern = function(object, kind) { | ||||
|     return new PatternProxy(stack, object, kind); | ||||
|   } | ||||
| 
 | ||||
|     ctx.putImageData = function(data, x, y, width, height) { | ||||
|         stack.push(["$putImageData", [data, x, y, width, height]]); | ||||
|     } | ||||
|   ctx.createLinearGradient = function(x0, y0, x1, y1) { | ||||
|     return new GradientProxy(stack, x0, y0, x1, y1); | ||||
|   } | ||||
| 
 | ||||
|     ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { | ||||
|         if (image instanceof CanvasProxy) { | ||||
|             // Send the image/CanvasProxy to the main thread.
 | ||||
|             image.flush(); | ||||
|             stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]); | ||||
|         } else if(image instanceof JpegStreamProxy) { | ||||
|             stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) | ||||
|         } else { | ||||
|             throw "unkown type to drawImage"; | ||||
|         } | ||||
|     } | ||||
|   ctx.getImageData = function(x, y, w, h) { | ||||
|     return { | ||||
|       width: w, | ||||
|       height: h, | ||||
|       data: Uint8ClampedArray(w * h * 4) | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|     function buildFuncCall(name) { | ||||
|         return function() { | ||||
|             // console.log("funcCall", name)
 | ||||
|             stack.push([name, Array.prototype.slice.call(arguments)]); | ||||
|         } | ||||
|     } | ||||
|     var name; | ||||
|     for (var i = 0; i < ctxFunc.length; i++) { | ||||
|         name = ctxFunc[i]; | ||||
|         ctx[name] = buildFuncCall(name); | ||||
|     } | ||||
|   ctx.putImageData = function(data, x, y, width, height) { | ||||
|     stack.push(["$putImageData", [data, x, y, width, height]]); | ||||
|   } | ||||
| 
 | ||||
|     var ctxProp = { | ||||
|         // "canvas"
 | ||||
|         "globalAlpha": "1", | ||||
|         "globalCompositeOperation": "source-over", | ||||
|         "strokeStyle": "#000000", | ||||
|         "fillStyle": "#000000", | ||||
|         "lineWidth": "1", | ||||
|         "lineCap": "butt", | ||||
|         "lineJoin": "miter", | ||||
|         "miterLimit": "10", | ||||
|         "shadowOffsetX": "0", | ||||
|         "shadowOffsetY": "0", | ||||
|         "shadowBlur": "0", | ||||
|         "shadowColor": "rgba(0, 0, 0, 0)", | ||||
|         "font": "10px sans-serif", | ||||
|         "textAlign": "start", | ||||
|         "textBaseline": "alphabetic", | ||||
|         "mozTextStyle": "10px sans-serif", | ||||
|         "mozImageSmoothingEnabled": "true", | ||||
|         "DRAWWINDOW_DRAW_CARET": "1", | ||||
|         "DRAWWINDOW_DO_NOT_FLUSH": "2", | ||||
|         "DRAWWINDOW_DRAW_VIEW": "4", | ||||
|         "DRAWWINDOW_USE_WIDGET_LAYERS": "8", | ||||
|         "DRAWWINDOW_ASYNC_DECODE_IMAGES": "16", | ||||
|   ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { | ||||
|     if (image instanceof CanvasProxy) { | ||||
|       // Send the image/CanvasProxy to the main thread.
 | ||||
|       image.flush(); | ||||
|       stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]); | ||||
|     } else if(image instanceof JpegStreamProxy) { | ||||
|       stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) | ||||
|     } else { | ||||
|       throw "unkown type to drawImage"; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|     function buildGetter(name) { | ||||
|         return function() { | ||||
|             return ctx["$" + name]; | ||||
|         } | ||||
|   // Setup property access to `ctx`.
 | ||||
|   var ctxProp = { | ||||
|     // "canvas"
 | ||||
|     "globalAlpha": "1", | ||||
|     "globalCompositeOperation": "source-over", | ||||
|     "strokeStyle": "#000000", | ||||
|     "fillStyle": "#000000", | ||||
|     "lineWidth": "1", | ||||
|     "lineCap": "butt", | ||||
|     "lineJoin": "miter", | ||||
|     "miterLimit": "10", | ||||
|     "shadowOffsetX": "0", | ||||
|     "shadowOffsetY": "0", | ||||
|     "shadowBlur": "0", | ||||
|     "shadowColor": "rgba(0, 0, 0, 0)", | ||||
|     "font": "10px sans-serif", | ||||
|     "textAlign": "start", | ||||
|     "textBaseline": "alphabetic", | ||||
|     "mozTextStyle": "10px sans-serif", | ||||
|     "mozImageSmoothingEnabled": "true" | ||||
|   } | ||||
| 
 | ||||
|   function buildGetter(name) { | ||||
|     return function() { | ||||
|       return ctx["$" + name]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|     function buildSetter(name) { | ||||
|   function buildSetter(name) { | ||||
|     return function(value) { | ||||
|       stack.push(["$", name, value]); | ||||
|       return ctx["$" + name] = value; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   for (var name in ctxProp) { | ||||
|     ctx["$" + name] = ctxProp[name]; | ||||
|     ctx.__defineGetter__(name, buildGetter(name)); | ||||
| 
 | ||||
|     // Special treatment for `fillStyle` and `strokeStyle`: The passed style
 | ||||
|     // might be a gradient. Need to check for that.
 | ||||
|     if (name == "fillStyle" || name == "strokeStyle") { | ||||
|       function buildSetterStyle(name) { | ||||
|         return function(value) { | ||||
|           if (value instanceof GradientProxy) { | ||||
|             stack.push(["$" + name + "Gradient"]); | ||||
|           } else if (value instanceof PatternProxy) { | ||||
|             stack.push(["$" + name + "Pattern", [value.id]]); | ||||
|           } else { | ||||
|             stack.push(["$", name, value]); | ||||
|             return ctx["$" + name] = value; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       ctx.__defineSetter__(name, buildSetterStyle(name)); | ||||
|     } else { | ||||
|       ctx.__defineSetter__(name, buildSetter(name)); | ||||
|     } | ||||
| 
 | ||||
|     for (var name in ctxProp) { | ||||
|         ctx["$" + name] = ctxProp[name]; | ||||
|         ctx.__defineGetter__(name, buildGetter(name)); | ||||
| 
 | ||||
|         // Special treatment for `fillStyle` and `strokeStyle`: The passed style
 | ||||
|         // might be a gradient. Need to check for that.
 | ||||
|         if (name == "fillStyle" || name == "strokeStyle") { | ||||
|             function buildSetterStyle(name) { | ||||
|                 return function(value) { | ||||
|                     if (value instanceof GradientProxy) { | ||||
|                         stack.push(["$" + name + "Gradient"]); | ||||
|                     } else if (value instanceof PatternProxy) { | ||||
|                         stack.push(["$" + name + "Pattern", [value.id]]); | ||||
|                     } else { | ||||
|                         stack.push(["$", name, value]); | ||||
|                         return ctx["$" + name] = value; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             ctx.__defineSetter__(name, buildSetterStyle(name)); | ||||
|         } else { | ||||
|             ctx.__defineSetter__(name, buildSetter(name)); | ||||
|         } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
| * Sends the current stack of the CanvasProxy over to the main thread and | ||||
| * resets the stack. | ||||
| */ | ||||
| CanvasProxy.prototype.flush = function() { | ||||
|     postMessage("canvas_proxy_stack"); | ||||
|     postMessage({ | ||||
|         id:     this.id, | ||||
|         stack:  this.$stack, | ||||
|         width:  this.width, | ||||
|         height: this.height | ||||
|     }); | ||||
|     this.$stack.length = 0; | ||||
|   postMessage("canvas_proxy_stack"); | ||||
|   postMessage({ | ||||
|     id:     this.id, | ||||
|     stack:  this.$stack, | ||||
|     width:  this.width, | ||||
|     height: this.height | ||||
|   }); | ||||
|   this.$stack.length = 0; | ||||
| } | ||||
|  | ||||
| @ -1,295 +1,22 @@ | ||||
| <html> | ||||
|     <head> | ||||
|         <title>Simple pdf.js page viewer worker</title> | ||||
|         <script type="text/javascript" src="worker_client.js"></script> | ||||
| <script> | ||||
| 
 | ||||
| var timer = null | ||||
| function tic() { | ||||
|     timer = Date.now(); | ||||
| } | ||||
| 
 | ||||
| function toc(msg) { | ||||
|     console.log(msg + ": " + (Date.now() - timer) + "ms"); | ||||
| } | ||||
| 
 | ||||
| var myWorker = new Worker('worker.js'); | ||||
| var imagesList = {}; | ||||
| var canvasList = {}; | ||||
| var patternList = {}; | ||||
| var gradient; | ||||
| 
 | ||||
| var currentX = 0; | ||||
| var currentXStack = []; | ||||
| var special = { | ||||
|     "$setCurrentX": function(value) { | ||||
|         currentX = value; | ||||
|     }, | ||||
| 
 | ||||
|     "$addCurrentX": function(value) { | ||||
|         currentX += value; | ||||
|     }, | ||||
| 
 | ||||
|     "$saveCurrentX": function() { | ||||
|         currentXStack.push(currentX); | ||||
|     }, | ||||
| 
 | ||||
|     "$restoreCurrentX": function() { | ||||
|         currentX = currentXStack.pop(); | ||||
|     }, | ||||
| 
 | ||||
|     "$showText": function(y, text, uniText) { | ||||
|         this.translate(currentX, -1 * y); | ||||
|         this.fillText(uniText, 0, 0); | ||||
|         currentX += this.measureText(text).width; | ||||
|     }, | ||||
| 
 | ||||
|     "$putImageData": function(imageData, x, y) { | ||||
|         var imgData = this.getImageData(0, 0, imageData.width, imageData.height); | ||||
| 
 | ||||
|         // Store the .data property to avaid property lookups. | ||||
|         var imageRealData = imageData.data; | ||||
|         var imgRealData = imgData.data; | ||||
| 
 | ||||
|         // Copy over the imageData. | ||||
|         var len = imageRealData.length; | ||||
|         while (len--) | ||||
|             imgRealData[len] = imageRealData[len] | ||||
| 
 | ||||
|         this.putImageData(imgData, x, y); | ||||
|     }, | ||||
| 
 | ||||
|     "$drawImage": function(id, x, y, sx, sy, swidth, sheight) { | ||||
|         var image = imagesList[id]; | ||||
|         if (!image) { | ||||
|             throw "Image not found"; | ||||
|         } | ||||
|         this.drawImage(image, x, y, image.width, image.height, | ||||
|             sx, sy, swidth, sheight); | ||||
|     }, | ||||
| 
 | ||||
|     "$drawCanvas": function(id, x, y, sx, sy, swidth, sheight) { | ||||
|         var canvas = canvasList[id]; | ||||
|         if (!canvas) { | ||||
|             throw "Canvas not found"; | ||||
|         } | ||||
|         if (sheight != null) { | ||||
|             this.drawImage(canvas, x, y, canvas.width, canvas.height, | ||||
|                 sx, sy, swidth, sheight); | ||||
|         } else { | ||||
|             this.drawImage(canvas, x, y, canvas.width, canvas.height); | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     "$createLinearGradient": function(x0, y0, x1, y1) { | ||||
|         gradient = this.createLinearGradient(x0, y0, x1, y1); | ||||
|     }, | ||||
| 
 | ||||
|     "$createPatternFromCanvas": function(patternId, canvasId, kind) { | ||||
|         var canvas = canvasList[canvasId]; | ||||
|         if (!canvas) { | ||||
|             throw "Canvas not found"; | ||||
|         } | ||||
|         patternList[patternId] = this.createPattern(canvas, kind); | ||||
|     }, | ||||
| 
 | ||||
|     "$addColorStop": function(i, rgba) { | ||||
|         gradient.addColorStop(i, rgba); | ||||
|     }, | ||||
| 
 | ||||
|     "$fillStyleGradient": function() { | ||||
|         this.fillStyle = gradient; | ||||
|     }, | ||||
| 
 | ||||
|     "$fillStylePattern": function(id) { | ||||
|         var pattern = patternList[id]; | ||||
|         if (!pattern) { | ||||
|             throw "Pattern not found"; | ||||
|         } | ||||
|         this.fillStyle = pattern; | ||||
|     }, | ||||
| 
 | ||||
|     "$strokeStyleGradient": function() { | ||||
|         this.strokeStyle = gradient; | ||||
|     }, | ||||
| 
 | ||||
|     "$strokeStylePattern": function(id) { | ||||
|         var pattern = patternList[id]; | ||||
|         if (!pattern) { | ||||
|             throw "Pattern not found"; | ||||
|         } | ||||
|         this.strokeStyle = pattern; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| var gStack; | ||||
| function renderProxyCanvas(canvas, stack) { | ||||
|     var ctx = canvas.getContext("2d"); | ||||
|     for (var i = 0; i < stack.length; i++) { | ||||
|     // for (var i = 0; i < 1000; i++) { | ||||
|         var opp = stack[i]; | ||||
|         if (opp[0] == "$") { | ||||
|             ctx[opp[1]] = opp[2]; | ||||
|         } else if (opp[0] in special) { | ||||
|             special[opp[0]].apply(ctx, opp[1]); | ||||
|         } else { | ||||
|             ctx[opp[0]].apply(ctx, opp[1]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const WAIT = 0; | ||||
| const CANVAS_PROXY_STACK = 1; | ||||
| const LOG = 2; | ||||
| const FONT = 3; | ||||
| const PDF_NUM_PAGE = 4; | ||||
| const JPEG_STREAM = 5; | ||||
| 
 | ||||
| var onMessageState = WAIT; | ||||
| var fontStr = null; | ||||
| var first = true; | ||||
| var intervals = []; | ||||
| myWorker.onmessage = function(event) { | ||||
|     var data = event.data; | ||||
|     // console.log("onMessageRaw", data); | ||||
|     switch (onMessageState) { | ||||
|         case WAIT: | ||||
|             if (typeof data != "string") { | ||||
|                 throw "expecting to get an string"; | ||||
|             } | ||||
|             switch (data) { | ||||
|                 case "pdf_num_page": | ||||
|                     onMessageState = PDF_NUM_PAGE; | ||||
|                     return; | ||||
|                 case "log": | ||||
|                     onMessageState = LOG; | ||||
|                     return; | ||||
|                 case "canvas_proxy_stack": | ||||
|                     onMessageState = CANVAS_PROXY_STACK; | ||||
|                     return; | ||||
|                 case "font": | ||||
|                     onMessageState = FONT; | ||||
|                     return; | ||||
|                 case "jpeg_stream": | ||||
|                     onMessageState = JPEG_STREAM; | ||||
|                     return; | ||||
|                 default: | ||||
|                     throw "unkown state: " + data | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case JPEG_STREAM: | ||||
|             var img = new Image(); | ||||
|             img.src = "data:image/jpeg;base64," + window.btoa(data.str); | ||||
|             imagesList[data.id] = img; | ||||
|             console.log("got image", data.id) | ||||
|             break; | ||||
| 
 | ||||
|         case PDF_NUM_PAGE: | ||||
|             console.log(data); | ||||
|             maxPages = parseInt(data); | ||||
|             document.getElementById("numPages").innerHTML = "/" + data; | ||||
|             onMessageState = WAIT; | ||||
|             break; | ||||
| 
 | ||||
|         case FONT: | ||||
|             data = JSON.parse(data); | ||||
|             var base64 = window.btoa(data.str); | ||||
| 
 | ||||
|             // Add the @font-face rule to the document | ||||
|             var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; | ||||
|             var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; | ||||
|             var styleSheet = document.styleSheets[0]; | ||||
|             styleSheet.insertRule(rule, styleSheet.length); | ||||
| 
 | ||||
|             // Just adding the font-face to the DOM doesn't make it load. It | ||||
|             // seems it's loaded once Gecko notices it's used. Therefore, | ||||
|             // add a div on the page using the loaded font. | ||||
|             document.getElementById("fonts").innerHTML += "<div style='font-family:" + data.fontName + "'>j</div>"; | ||||
|             console.log("setup font", data.fontName); | ||||
| 
 | ||||
|             onMessageState = WAIT; | ||||
|             break; | ||||
| 
 | ||||
|         case LOG: | ||||
|             console.log.apply(console, JSON.parse(data)); | ||||
|             onMessageState = WAIT; | ||||
|             break; | ||||
| 
 | ||||
|         case CANVAS_PROXY_STACK: | ||||
|             var id = data.id; | ||||
|             var stack = data.stack; | ||||
|             gStack = stack; | ||||
| 
 | ||||
|             // Check if there is already a canvas with the given id. If not, | ||||
|             // create a new canvas. | ||||
|             if (!canvasList[id]) { | ||||
|                 var newCanvas = document.createElement("canvas"); | ||||
|                 newCanvas.width = data.width; | ||||
|                 newCanvas.height = data.height; | ||||
|                 canvasList[id] = newCanvas; | ||||
|             } | ||||
| 
 | ||||
|             // There might be fonts that need to get loaded. Shedule the | ||||
|             // rendering at the end of the event queue ensures this. | ||||
|             setTimeout(function() { | ||||
|                 if (id == 0) tic(); | ||||
|                 renderProxyCanvas(canvasList[id], stack); | ||||
|                 if (id == 0) toc("canvas rendering") | ||||
|             }, 0); | ||||
|             onMessageState = WAIT; | ||||
|             break; | ||||
|     } | ||||
| } | ||||
| // | ||||
| // myWorker.postMessage(array); | ||||
| 
 | ||||
| var currentPage = 1; | ||||
| var maxPages = 1; | ||||
| function showPage(num) { | ||||
|     ctx.save(); | ||||
|     ctx.fillStyle = "rgb(255, 255, 255)"; | ||||
|     ctx.fillRect(0, 0, canvas.width, canvas.height); | ||||
|     ctx.restore(); | ||||
|     console.log("worker: page=" + num) | ||||
|     document.getElementById('pageNumber').value = num; | ||||
|     currentPage = parseInt(num); | ||||
|     myWorker.postMessage(num); | ||||
| } | ||||
| 
 | ||||
| function open(url) { | ||||
|     document.title = url; | ||||
|     var req = new XMLHttpRequest(); | ||||
|     req.open("GET", url); | ||||
|     req.mozResponseType = req.responseType = "arraybuffer"; | ||||
|     req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; | ||||
|     req.onreadystatechange = function() { | ||||
|       if (req.readyState == 4 && req.status == req.expected) { | ||||
|         var data = req.mozResponseArrayBuffer || req.mozResponse || | ||||
|                    req.responseArrayBuffer || req.response; | ||||
|         myWorker.postMessage(data); | ||||
|         showPage("2"); | ||||
|       } | ||||
|     }; | ||||
|     req.send(null); | ||||
| } | ||||
| 
 | ||||
| function nextPage() { | ||||
|     if (currentPage == maxPages) return; | ||||
|     currentPage++; | ||||
|     showPage(currentPage); | ||||
| } | ||||
| 
 | ||||
| function prevPage() { | ||||
|     if (currentPage == 1) return; | ||||
|     currentPage--; | ||||
|     showPage(currentPage); | ||||
| } | ||||
| 
 | ||||
| var pdfDoc; | ||||
| window.onload = function() { | ||||
|     window.canvas = document.getElementById("canvas"); | ||||
|     window.ctx = canvas.getContext("2d"); | ||||
|     canvasList[0] = window.canvas; | ||||
|     open("compressed.tracemonkey-pldi-09.pdf"); | ||||
| 
 | ||||
|     pdfDoc = new WorkerPDFDoc(window.canvas); | ||||
|     pdfDoc.onChangePage = function(numPage) { | ||||
|         document.getElementById("pageNumber").value = numPage; | ||||
|     } | ||||
|     pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() { | ||||
|         document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages; | ||||
|     }) | ||||
| } | ||||
| </script> | ||||
|         <link rel="stylesheet" href="viewer.css"></link> | ||||
| @ -301,9 +28,9 @@ window.onload = function() { | ||||
|     <input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input> | ||||
|     <!-- This only opens supported PDFs from the source path... | ||||
|       -- Can we use JSONP to overcome the same-origin restrictions? --> | ||||
|       <button onclick="prevPage();">Previous</button> | ||||
|       <button onclick="nextPage();">Next</button> | ||||
|       <input type="text" id="pageNumber" onchange="showPage(this.value);" | ||||
|       <button onclick="pdfDoc.prevPage();">Previous</button> | ||||
|       <button onclick="pdfDoc.nextPage();">Next</button> | ||||
|       <input type="text" id="pageNumber" onchange="pdfDoc.showPage(this.value);" | ||||
|              value="1" size="4"></input> | ||||
|       <span id="numPages">--</span> | ||||
|       <span id="info"></span> | ||||
|  | ||||
							
								
								
									
										96
									
								
								worker.js
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								worker.js
									
									
									
									
									
								
							| @ -1,15 +1,26 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| var timer = null; | ||||
| function tic() { | ||||
|   timer = Date.now(); | ||||
| } | ||||
| 
 | ||||
| function toc(msg) { | ||||
|   log(msg + ": " + (Date.now() - timer) + "ms"); | ||||
|   timer = null; | ||||
| } | ||||
| 
 | ||||
| function log() { | ||||
|     var args = Array.prototype.slice.call(arguments); | ||||
|     postMessage("log"); | ||||
|     postMessage(JSON.stringify(args)) | ||||
|   var args = Array.prototype.slice.call(arguments); | ||||
|   postMessage("log"); | ||||
|   postMessage(JSON.stringify(args)) | ||||
| } | ||||
| 
 | ||||
| var console = { | ||||
|     log: log | ||||
|   log: log | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| importScripts("canvas_proxy.js"); | ||||
| importScripts("pdf.js"); | ||||
| importScripts("fonts.js"); | ||||
| @ -18,55 +29,50 @@ importScripts("glyphlist.js") | ||||
| // Use the JpegStreamProxy proxy.
 | ||||
| JpegStream = JpegStreamProxy; | ||||
| 
 | ||||
| var timer = null; | ||||
| function tic() { | ||||
|     timer = Date.now(); | ||||
| } | ||||
| 
 | ||||
| function toc(msg) { | ||||
|     log(msg + ": " + (Date.now() - timer) + "ms"); | ||||
|     timer = null; | ||||
| } | ||||
| 
 | ||||
| // Create the WebWorkerProxyCanvas.
 | ||||
| var canvas = new CanvasProxy(1224, 1584); | ||||
| 
 | ||||
| var pageInterval; | ||||
| // Listen for messages from the main thread.
 | ||||
| var pdfDocument = null; | ||||
| onmessage = function(event) { | ||||
|     var data = event.data; | ||||
|     if (!pdfDocument) { | ||||
|         pdfDocument = new PDFDoc(new Stream(data)); | ||||
|         postMessage("pdf_num_page"); | ||||
|         postMessage(pdfDocument.numPages) | ||||
|         return; | ||||
|     } else { | ||||
|         tic(); | ||||
|   var data = event.data; | ||||
|   // If there is no pdfDocument yet, then the sent data is the PDFDocument.
 | ||||
|   if (!pdfDocument) { | ||||
|     pdfDocument = new PDFDoc(new Stream(data)); | ||||
|     postMessage("pdf_num_page"); | ||||
|     postMessage(pdfDocument.numPages) | ||||
|     return; | ||||
|   } | ||||
|   // User requested to render a certain page.
 | ||||
|   else { | ||||
|     tic(); | ||||
| 
 | ||||
|         // Let's try to render the first page...
 | ||||
|         var page = pdfDocument.getPage(parseInt(data)); | ||||
|     // Let's try to render the first page...
 | ||||
|     var page = pdfDocument.getPage(parseInt(data)); | ||||
| 
 | ||||
|         // page.compile will collect all fonts for us, once we have loaded them
 | ||||
|         // we can trigger the actual page rendering with page.display
 | ||||
|         var fonts = []; | ||||
|         var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy); | ||||
|         page.compile(gfx, fonts); | ||||
|     // page.compile will collect all fonts for us, once we have loaded them
 | ||||
|     // we can trigger the actual page rendering with page.display
 | ||||
|     var fonts = []; | ||||
|     var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy); | ||||
|     page.compile(gfx, fonts); | ||||
| 
 | ||||
|         // Inspect fonts and translate the missing one.
 | ||||
|         var count = fonts.length; | ||||
|         for (var i = 0; i < count; i++) { | ||||
|           var font = fonts[i]; | ||||
|           if (Fonts[font.name]) { | ||||
|             fontsReady = fontsReady && !Fonts[font.name].loading; | ||||
|             continue; | ||||
|           } | ||||
|     // Inspect fonts and translate the missing one.
 | ||||
|     var count = fonts.length; | ||||
|     for (var i = 0; i < count; i++) { | ||||
|       var font = fonts[i]; | ||||
|       if (Fonts[font.name]) { | ||||
|         fontsReady = fontsReady && !Fonts[font.name].loading; | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|           // This "builds" the font and sents it over to the main thread.
 | ||||
|           new Font(font.name, font.file, font.properties); | ||||
|         } | ||||
|         toc("compiled page"); | ||||
| 
 | ||||
|         page.display(gfx); | ||||
|         canvas.flush(); | ||||
|       // This "builds" the font and sents it over to the main thread.
 | ||||
|       new Font(font.name, font.file, font.properties); | ||||
|     } | ||||
|     toc("compiled page"); | ||||
| 
 | ||||
|     tic() | ||||
|     page.display(gfx); | ||||
|     canvas.flush(); | ||||
|     toc("displayed page"); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										294
									
								
								worker_client.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								worker_client.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,294 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| function WorkerPDFDoc(canvas) { | ||||
|   var timer = null | ||||
|   function tic() { | ||||
|     timer = Date.now(); | ||||
|   } | ||||
| 
 | ||||
|   function toc(msg) { | ||||
|     console.log(msg + ": " + (Date.now() - timer) + "ms"); | ||||
|   } | ||||
| 
 | ||||
|   this.ctx = canvas.getContext("2d"); | ||||
|   this.canvas = canvas; | ||||
|   this.worker = new Worker('worker.js'); | ||||
| 
 | ||||
|   this.numPage = 1; | ||||
|   this.numPages = null; | ||||
| 
 | ||||
|   var imagesList = {}; | ||||
|   var canvasList = { | ||||
|     0: canvas | ||||
|   }; | ||||
|   var patternList = {}; | ||||
|   var gradient; | ||||
| 
 | ||||
|   var currentX = 0; | ||||
|   var currentXStack = []; | ||||
| 
 | ||||
|   var ctxSpecial = { | ||||
|     "$setCurrentX": function(value) { | ||||
|       currentX = value; | ||||
|     }, | ||||
| 
 | ||||
|     "$addCurrentX": function(value) { | ||||
|       currentX += value; | ||||
|     }, | ||||
| 
 | ||||
|     "$saveCurrentX": function() { | ||||
|       currentXStack.push(currentX); | ||||
|     }, | ||||
| 
 | ||||
|     "$restoreCurrentX": function() { | ||||
|       currentX = currentXStack.pop(); | ||||
|     }, | ||||
| 
 | ||||
|     "$showText": function(y, text, uniText) { | ||||
|       this.translate(currentX, -1 * y); | ||||
|       this.fillText(uniText, 0, 0); | ||||
|       currentX += this.measureText(text).width; | ||||
|     }, | ||||
| 
 | ||||
|     "$putImageData": function(imageData, x, y) { | ||||
|       var imgData = this.getImageData(0, 0, imageData.width, imageData.height); | ||||
| 
 | ||||
|       // Store the .data property to avaid property lookups.
 | ||||
|       var imageRealData = imageData.data; | ||||
|       var imgRealData = imgData.data; | ||||
| 
 | ||||
|       // Copy over the imageData.
 | ||||
|       var len = imageRealData.length; | ||||
|       while (len--) | ||||
|       imgRealData[len] = imageRealData[len] | ||||
| 
 | ||||
|       this.putImageData(imgData, x, y); | ||||
|     }, | ||||
| 
 | ||||
|     "$drawImage": function(id, x, y, sx, sy, swidth, sheight) { | ||||
|       var image = imagesList[id]; | ||||
|       if (!image) { | ||||
|         throw "Image not found"; | ||||
|       } | ||||
|       this.drawImage(image, x, y, image.width, image.height, | ||||
|         sx, sy, swidth, sheight); | ||||
|     }, | ||||
| 
 | ||||
|     "$drawCanvas": function(id, x, y, sx, sy, swidth, sheight) { | ||||
|       var canvas = canvasList[id]; | ||||
|       if (!canvas) { | ||||
|         throw "Canvas not found"; | ||||
|       } | ||||
|       if (sheight != null) { | ||||
|         this.drawImage(canvas, x, y, canvas.width, canvas.height, | ||||
|           sx, sy, swidth, sheight); | ||||
|       } else { | ||||
|         this.drawImage(canvas, x, y, canvas.width, canvas.height); | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     "$createLinearGradient": function(x0, y0, x1, y1) { | ||||
|       gradient = this.createLinearGradient(x0, y0, x1, y1); | ||||
|     }, | ||||
| 
 | ||||
|     "$createPatternFromCanvas": function(patternId, canvasId, kind) { | ||||
|       var canvas = canvasList[canvasId]; | ||||
|       if (!canvas) { | ||||
|         throw "Canvas not found"; | ||||
|       } | ||||
|       patternList[patternId] = this.createPattern(canvas, kind); | ||||
|     }, | ||||
| 
 | ||||
|     "$addColorStop": function(i, rgba) { | ||||
|       gradient.addColorStop(i, rgba); | ||||
|     }, | ||||
| 
 | ||||
|     "$fillStyleGradient": function() { | ||||
|       this.fillStyle = gradient; | ||||
|     }, | ||||
| 
 | ||||
|     "$fillStylePattern": function(id) { | ||||
|       var pattern = patternList[id]; | ||||
|       if (!pattern) { | ||||
|         throw "Pattern not found"; | ||||
|       } | ||||
|       this.fillStyle = pattern; | ||||
|     }, | ||||
| 
 | ||||
|     "$strokeStyleGradient": function() { | ||||
|       this.strokeStyle = gradient; | ||||
|     }, | ||||
| 
 | ||||
|     "$strokeStylePattern": function(id) { | ||||
|       var pattern = patternList[id]; | ||||
|       if (!pattern) { | ||||
|         throw "Pattern not found"; | ||||
|       } | ||||
|       this.strokeStyle = pattern; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function renderProxyCanvas(canvas, stack) { | ||||
|     var ctx = canvas.getContext("2d"); | ||||
|     for (var i = 0; i < stack.length; i++) { | ||||
|       var opp = stack[i]; | ||||
|       if (opp[0] == "$") { | ||||
|         ctx[opp[1]] = opp[2]; | ||||
|       } else if (opp[0] in ctxSpecial) { | ||||
|         ctxSpecial[opp[0]].apply(ctx, opp[1]); | ||||
|       } else { | ||||
|         ctx[opp[0]].apply(ctx, opp[1]); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|   * onMessage state machine. | ||||
|   */ | ||||
|   const WAIT = 0; | ||||
|   const CANVAS_PROXY_STACK = 1; | ||||
|   const LOG = 2; | ||||
|   const FONT = 3; | ||||
|   const PDF_NUM_PAGE = 4; | ||||
|   const JPEG_STREAM = 5; | ||||
| 
 | ||||
|   var onMessageState = WAIT; | ||||
|   this.worker.onmessage = function(event) { | ||||
|     var data = event.data; | ||||
|     // console.log("onMessageRaw", data);
 | ||||
|     switch (onMessageState) { | ||||
|       case WAIT: | ||||
|         if (typeof data != "string") { | ||||
|           throw "expecting to get an string"; | ||||
|         } | ||||
|         switch (data) { | ||||
|           case "pdf_num_page": | ||||
|             onMessageState = PDF_NUM_PAGE; | ||||
|             return; | ||||
| 
 | ||||
|           case "log": | ||||
|             onMessageState = LOG; | ||||
|             return; | ||||
| 
 | ||||
|           case "canvas_proxy_stack": | ||||
|             onMessageState = CANVAS_PROXY_STACK; | ||||
|             return; | ||||
| 
 | ||||
|           case "font": | ||||
|             onMessageState = FONT; | ||||
|             return; | ||||
| 
 | ||||
|           case "jpeg_stream": | ||||
|             onMessageState = JPEG_STREAM; | ||||
|             return; | ||||
| 
 | ||||
|           default: | ||||
|             throw "unkown state: " + data | ||||
|         } | ||||
|       break; | ||||
| 
 | ||||
|       case JPEG_STREAM: | ||||
|         var img = new Image(); | ||||
|         img.src = "data:image/jpeg;base64," + window.btoa(data.str); | ||||
|         imagesList[data.id] = img; | ||||
|         console.log("got image", data.id) | ||||
|       break; | ||||
| 
 | ||||
|       case PDF_NUM_PAGE: | ||||
|         this.numPages = parseInt(data); | ||||
|         if (this.loadCallback) { | ||||
|           this.loadCallback(); | ||||
|         } | ||||
|         onMessageState = WAIT; | ||||
|       break; | ||||
| 
 | ||||
|       case FONT: | ||||
|         data = JSON.parse(data); | ||||
|         var base64 = window.btoa(data.str); | ||||
| 
 | ||||
|         // Add the @font-face rule to the document
 | ||||
|         var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; | ||||
|         var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; | ||||
|         var styleSheet = document.styleSheets[0]; | ||||
|         styleSheet.insertRule(rule, styleSheet.length); | ||||
| 
 | ||||
|         // Just adding the font-face to the DOM doesn't make it load. It
 | ||||
|         // seems it's loaded once Gecko notices it's used. Therefore,
 | ||||
|         // add a div on the page using the loaded font.
 | ||||
|         document.getElementById("fonts").innerHTML += "<div style='font-family:" + data.fontName + "'>j</div>"; | ||||
| 
 | ||||
|         onMessageState = WAIT; | ||||
|       break; | ||||
| 
 | ||||
|       case LOG: | ||||
|         console.log.apply(console, JSON.parse(data)); | ||||
|         onMessageState = WAIT; | ||||
|       break; | ||||
| 
 | ||||
|       case CANVAS_PROXY_STACK: | ||||
|         var id = data.id; | ||||
|         var stack = data.stack; | ||||
| 
 | ||||
|         // Check if there is already a canvas with the given id. If not,
 | ||||
|         // create a new canvas.
 | ||||
|         if (!canvasList[id]) { | ||||
|           var newCanvas = document.createElement("canvas"); | ||||
|           newCanvas.width = data.width; | ||||
|           newCanvas.height = data.height; | ||||
|           canvasList[id] = newCanvas; | ||||
|         } | ||||
| 
 | ||||
|         // There might be fonts that need to get loaded. Shedule the
 | ||||
|         // rendering at the end of the event queue ensures this.
 | ||||
|         setTimeout(function() { | ||||
|           if (id == 0) tic(); | ||||
|           renderProxyCanvas(canvasList[id], stack); | ||||
|           if (id == 0) toc("canvas rendering") | ||||
|         }, 0); | ||||
|         onMessageState = WAIT; | ||||
|       break; | ||||
|     } | ||||
|   }.bind(this); | ||||
| } | ||||
| 
 | ||||
|   WorkerPDFDoc.prototype.open = function(url, callback) { | ||||
|   var req = new XMLHttpRequest(); | ||||
|   req.open("GET", url); | ||||
|   req.mozResponseType = req.responseType = "arraybuffer"; | ||||
|   req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; | ||||
|   req.onreadystatechange = function() { | ||||
|     if (req.readyState == 4 && req.status == req.expected) { | ||||
|       var data = req.mozResponseArrayBuffer || req.mozResponse || | ||||
|       req.responseArrayBuffer || req.response; | ||||
| 
 | ||||
|       this.loadCallback = callback; | ||||
|       this.worker.postMessage(data); | ||||
|       this.showPage(this.numPage); | ||||
|     } | ||||
|   }.bind(this); | ||||
|   req.send(null); | ||||
| } | ||||
| 
 | ||||
| WorkerPDFDoc.prototype.showPage = function(numPage) { | ||||
|   var ctx = this.ctx; | ||||
|   ctx.save(); | ||||
|   ctx.fillStyle = "rgb(255, 255, 255)"; | ||||
|   ctx.fillRect(0, 0, canvas.width, canvas.height); | ||||
|   ctx.restore(); | ||||
| 
 | ||||
|   this.numPage = parseInt(numPage); | ||||
|   this.worker.postMessage(numPage); | ||||
|   if (this.onChangePage) { | ||||
|     this.onChangePage(numPage); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| WorkerPDFDoc.prototype.nextPage = function() { | ||||
|   if (this.numPage == this.numPages) return; | ||||
|   this.showPage(++this.numPage); | ||||
| } | ||||
| 
 | ||||
| WorkerPDFDoc.prototype.prevPage = function() { | ||||
|   if (this.numPage == 1) return; | ||||
|   this.showPage(--this.numPage); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user