From da845ec5e6345bff293819a22d3f4edcf0a09034 Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Wed, 13 Jul 2011 11:41:04 -0700
Subject: [PATCH 01/12] git radial gradients working

---
 pdf.js | 194 ++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 137 insertions(+), 57 deletions(-)

diff --git a/pdf.js b/pdf.js
index a4c10fef7..452304d12 100644
--- a/pdf.js
+++ b/pdf.js
@@ -3793,7 +3793,7 @@ var PartialEvaluator = (function() {
 // <canvas> contexts store most of the state we need natively.
 // However, PDF needs a bit more state, which we store here.
 var CanvasExtraState = (function() {
-  function constructor() {
+  function constructor(old) {
     // Are soft masks and alpha values shapes or opacities?
     this.alphaIsShape = false;
     this.fontSize = 0;
@@ -3810,10 +3810,70 @@ var CanvasExtraState = (function() {
     this.wordSpace = 0;
     this.textHScale = 100;
     // Color spaces
-    this.fillColorSpace = null;
-    this.strokeColorSpace = null;
+    this.fillColorSpaceObj = null;
+    this.strokeColorSpaceObj = null;
+    this.fillColorObj = null;
+    this.strokeColorObj = null;
+
+    this.old = old;
   }
   constructor.prototype = {
+    get fillColorSpace() {
+      var cs = this.fillColorSpaceObj;
+      if (cs)
+        return cs;
+
+      var old = this.old;
+      if (old)
+        return old.fillColorSpace;
+
+      return null;
+    },
+    set fillColorSpace(cs) {
+      this.fillColorSpaceObj = cs;
+    },
+    get strokeColorSpace() {
+      var cs = this.strokeColorSpaceObj;
+      if (cs)
+        return cs;
+
+      var old = this.old;
+      if (old)
+        return old.strokeColorSpace;
+
+      return null;
+    }, 
+    set strokeColorSpace(cs) {
+      this.strokeColorSpaceObj = cs;
+    },
+    get fillColor() {
+      var color = this.fillColorObj;
+      if (color)
+        return color;
+
+      var old = this.old;
+      if (old)
+        return old.fillColor;
+
+      return null;
+    },
+    set fillColor(color) {
+      this.fillColorObj = color;
+    },
+    get strokeColor() {
+      var color = this.strokeColorObj;
+      if (color)
+        return color;
+
+      var old = this.old;
+      if (old)
+        return old.strokeColor;
+
+      return null;
+    },
+    set strokeColor(color) {
+      this.strokeColorObj = color;
+    }
   };
   return constructor;
 })();
@@ -3906,8 +3966,9 @@ var CanvasGraphics = (function() {
       if (this.ctx.$saveCurrentX) {
         this.ctx.$saveCurrentX();
       }
-      this.stateStack.push(this.current);
-      this.current = new CanvasExtraState();
+      var old = this.current;
+      this.stateStack.push(old);
+      this.current = new CanvasExtraState(old);
     },
     restore: function() {
       var prev = this.stateStack.pop();
@@ -3954,7 +4015,16 @@ var CanvasGraphics = (function() {
       this.stroke();
     },
     fill: function() {
-      this.ctx.fill();
+      var ctx = this.ctx;
+      var fillColor = this.current.fillColor;
+
+      if (fillColor.type === "Pattern") {
+        this.ctx.fillStyle = fillColor.patternFn.apply(this, ctx);
+        ctx.fill();
+      } else {
+        ctx.fill();
+      }
+
       this.consumePath();
     },
     eoFill: function() {
@@ -3963,8 +4033,14 @@ var CanvasGraphics = (function() {
       this.restoreFillRule(savedFillRule);
     },
     fillStroke: function() {
-      this.ctx.fill();
-      this.ctx.stroke();
+      var ctx = this.ctx;
+      var fillCS = this.current.fillColorSpace;
+
+      if (fillCS && fillCS.name === "Pattern")
+        this.current.fillPattern(ctx); 
+
+      ctx.fill();
+      ctx.stroke();
       this.consumePath();
     },
     eoFillStroke: function() {
@@ -4143,12 +4219,12 @@ var CanvasGraphics = (function() {
           ColorSpace.parse(space, this.xref, this.res);
     },
     setStrokeColor: function(/*...*/) {
-      var cs = this.getStrokeColorSpace();
+      var cs = this.current.strokeColorSpace;
       var color = cs.getRgb(arguments);
       this.setStrokeRGBColor.apply(this, color);
     },
     setStrokeColorN: function(/*...*/) {
-      var cs = this.getStrokeColorSpace();
+      var cs = this.current.strokeColorSpace;
 
       if (cs.name == 'Pattern') {
         this.ctx.strokeStyle = this.getPattern(cs, arguments);
@@ -4157,15 +4233,19 @@ var CanvasGraphics = (function() {
       }
     },
     setFillColor: function(/*...*/) {
-      var cs = this.getFillColorSpace();
+      var cs = this.current.fillColorSpace;
       var color = cs.getRgb(arguments);
       this.setFillRGBColor.apply(this, color);
     },
     setFillColorN: function(/*...*/) {
-      var cs = this.getFillColorSpace();
+      var cs = this.current.fillColorSpace;
 
       if (cs.name == 'Pattern') {
-        this.ctx.fillStyle = this.getPattern(cs, arguments);
+        // return a set of functions which will set the pattern
+        // when fill is called
+        var pattern = this.getPattern(cs, arguments);
+        this.current.fillColor = pattern;
+        this.current.fillColor.type = "Pattern";
       } else {
         this.setFillColor.apply(this, arguments);
       }
@@ -4210,9 +4290,9 @@ var CanvasGraphics = (function() {
       this.transform.apply(this, matrix);
       var shading = this.getShading(pattern.get("Shading"));
       this.restore();
-
-      TODO('store transform so it can be applied before every fill');
       return shading;
+     // TODO('store transform so it can be applied before every fill');
+     // return shading;
     },
     getTilingPattern: function(pattern, dict, color) {
       function multiply(m, tm) {
@@ -4315,13 +4395,16 @@ var CanvasGraphics = (function() {
       this.ctx.strokeStyle = this.makeCssRgb(r, g, b);
     },
     setFillRGBColor: function(r, g, b) {
-      this.ctx.fillStyle = this.makeCssRgb(r, g, b);
+      var color = this.makeCssRgb(r, g, b);
+      this.ctx.fillStyle = color;
+      this.current.fillColor = color;
     },
     setStrokeCMYKColor: function(c, m, y, k) {
       this.ctx.strokeStyle = this.makeCssCmyk(c, m, y, k);
     },
     setFillCMYKColor: function(c, m, y, k) {
-      this.ctx.fillStyle = this.makeCssCmyk(c, m, y, k);
+      var color = (new DeviceCmykCS()).getRgb([c, m, y, k]);
+      this.setFillRGBColor.apply(this, color);
     },
 
     // Shading
@@ -4341,7 +4424,7 @@ var CanvasGraphics = (function() {
       var shadingFill = this.getShading(shading);
 
       this.save();
-      ctx.fillStyle = shadingFill;
+      ctx.fillStyle = shadingFill.patternFn.apply(this, ctx);
 
       var inv = ctx.mozCurrentTransformInverse;
       if (inv) {
@@ -4455,8 +4538,6 @@ var CanvasGraphics = (function() {
     },
     getRadialShading: function(sh, cs) {
       var coordsArr = sh.get('Coords');
-      var x0 = coordsArr[0], y0 = coordsArr[1], r0 = coordsArr[2];
-      var x1 = coordsArr[3], y1 = coordsArr[4], r1 = coordsArr[5];
 
       var t0 = 0.0, t1 = 1.0;
       if (sh.has('Domain')) {
@@ -4478,22 +4559,51 @@ var CanvasGraphics = (function() {
         error('Invalid function');
       var fn = new PDFFunction(this.xref, fnObj);
 
-      var gradient = 
-        this.ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
-
       // 10 samples seems good enough for now, but probably won't work
       // if there are sharp color changes. Ideally, we would implement
       // the spec faithfully and add lossless optimizations.
       var step = (t1 - t0) / 10;
       var diff = t1 - t0;
 
+      var colorStops = [];
       for (var i = t0; i <= t1; i += step) {
         var color = fn.func([i]);
-        var rgbColor = cs.getRgb(color);
-        gradient.addColorStop((i - t0) / diff, 
-            this.makeCssRgb.apply(this, rgbColor));
+        var rgbColor = this.makeCssRgb.apply(this, cs.getRgb(color));
+        colorStops.push([(i - t0) / diff, rgbColor]);
+      }
+
+      var patternMatrix = this.ctx.mozCurrentTransform;
+
+      return {
+        patternFn : function() {
+          var x0 = coordsArr[0], y0 = coordsArr[1], r0 = coordsArr[2];
+          var x1 = coordsArr[3], y1 = coordsArr[4], r1 = coordsArr[5];
+          
+          // if the browser supports getting the tranform matrix, convert
+          // gradient coordinates from pattern space to current user space
+          if (patternMatrix) {
+            var userMatrix = this.ctx.mozCurrentTransformInverse;
+            
+            var p = this.applyTransform(x0, y0, patternMatrix);
+            p = this.applyTransform(p[0], p[1], userMatrix);
+            x0 = p[0];
+            y0 = p[1];
+
+            var p = this.applyTransform(x1, y1, patternMatrix);
+            p = this.applyTransform(p[0], p[1], userMatrix);
+            x1 = p[0];
+            y1 = p[1];
+          }
+
+          var gradient = 
+              this.ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
+          for (var i = 0, ii = colorStops.length; i < ii; ++i) {
+            var c = colorStops[i];
+            gradient.addColorStop(c[0], c[1]);
+          }
+          return gradient;
+        }
       }
-      return gradient;
     },
 
     // Images
@@ -4645,36 +4755,6 @@ var CanvasGraphics = (function() {
       var bi = (255 * (1 - Math.min(1, y * (1 - k) + k))) | 0;
       return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
     },
-    getFillColorSpace: function() {
-      var cs = this.current.fillColorSpace;
-      if (cs)
-        return cs;
-
-      var states = this.stateStack;
-      var i = states.length - 1;
-      while (i >= 0 && !(cs = states[i].fillColorSpace))
-        --i;
-
-      if (cs)
-        return cs;
-      else
-        return new DeviceRgbCS();
-    },
-    getStrokeColorSpace: function() {
-      var cs = this.current.strokeColorSpace;
-      if (cs)
-        return cs;
-
-      var states = this.stateStack;
-      var i = states.length - 1;
-      while (i >= 0 && !(cs = states[i].strokeColorSpace))
-        --i;
-
-      if (cs)
-        return cs;
-      else
-        return new DeviceRgbCS();
-    },
     // We generally keep the canvas context set for
     // nonzero-winding, and just set evenodd for the operations
     // that need them.

From 01d5e5579c0ff7fd6d8d277752478029555ca42c Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Wed, 13 Jul 2011 11:55:54 -0700
Subject: [PATCH 02/12] Changed linear gradients

---
 pdf.js | 43 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/pdf.js b/pdf.js
index 452304d12..6f2e0710f 100644
--- a/pdf.js
+++ b/pdf.js
@@ -4496,8 +4496,6 @@ var CanvasGraphics = (function() {
     },
     getAxialShading: function(sh, cs) {
       var coordsArr = sh.get('Coords');
-      var x0 = coordsArr[0], y0 = coordsArr[1],
-          x1 = coordsArr[2], y1 = coordsArr[3];
 
       var t0 = 0.0, t1 = 1.0;
       if (sh.has('Domain')) {
@@ -4519,22 +4517,51 @@ var CanvasGraphics = (function() {
         error('Invalid function');
       var fn = new PDFFunction(this.xref, fnObj);
 
-      var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);
-
       // 10 samples seems good enough for now, but probably won't work
       // if there are sharp color changes. Ideally, we would implement
       // the spec faithfully and add lossless optimizations.
       var step = (t1 - t0) / 10;
       var diff = t1 - t0;
 
+      var colorStops = [];
       for (var i = t0; i <= t1; i += step) {
         var color = fn.func([i]);
-        var rgbColor = cs.getRgb(color);
-        gradient.addColorStop((i - t0) / diff,
-            this.makeCssRgb.apply(this, rgbColor));
+        var rgbColor = this.makeCssRgb.apply(this, cs.getRgb(color));
+        colorStops.push([(i - t0) / diff, rgbColor]);
       }
+      
+      var patternMatrix = this.ctx.mozCurrentTransform;
 
-      return gradient;
+      return {
+        patternFn : function() {
+          var x0 = coordsArr[0], y0 = coordsArr[1];
+          var x1 = coordsArr[2], y1 = coordsArr[3];
+          
+          // if the browser supports getting the tranform matrix, convert
+          // gradient coordinates from pattern space to current user space
+          if (patternMatrix) {
+            var userMatrix = this.ctx.mozCurrentTransformInverse;
+            
+            var p = this.applyTransform(x0, y0, patternMatrix);
+            p = this.applyTransform(p[0], p[1], userMatrix);
+            x0 = p[0];
+            y0 = p[1];
+
+            var p = this.applyTransform(x1, y1, patternMatrix);
+            p = this.applyTransform(p[0], p[1], userMatrix);
+            x1 = p[0];
+            y1 = p[1];
+          }
+
+          var gradient = 
+              this.ctx.createLinearGradient(x0, y0, x1, y1);
+          for (var i = 0, ii = colorStops.length; i < ii; ++i) {
+            var c = colorStops[i];
+            gradient.addColorStop(c[0], c[1]);
+          }
+          return gradient;
+        }
+      }
     },
     getRadialShading: function(sh, cs) {
       var coordsArr = sh.get('Coords');

From 7986c35213d9cd1a657eeac43ec7ae76e54e9e9b Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Wed, 13 Jul 2011 15:43:09 -0700
Subject: [PATCH 03/12] fixed gradients, need to work on tiling

---
 pdf.js | 691 ++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 387 insertions(+), 304 deletions(-)

diff --git a/pdf.js b/pdf.js
index 6f2e0710f..2af03dce8 100644
--- a/pdf.js
+++ b/pdf.js
@@ -4019,7 +4019,7 @@ var CanvasGraphics = (function() {
       var fillColor = this.current.fillColor;
 
       if (fillColor.type === "Pattern") {
-        this.ctx.fillStyle = fillColor.patternFn.apply(this, ctx);
+        this.ctx.fillStyle = fillColor.getPattern(ctx);
         ctx.fill();
       } else {
         ctx.fill();
@@ -4241,9 +4241,9 @@ var CanvasGraphics = (function() {
       var cs = this.current.fillColorSpace;
 
       if (cs.name == 'Pattern') {
-        // return a set of functions which will set the pattern
-        // when fill is called
-        var pattern = this.getPattern(cs, arguments);
+        // wait until fill to actually get the pattern
+        var pattern = Pattern.parse(cs, arguments, this.xref, this.res,
+                                    this.ctx);
         this.current.fillColor = pattern;
         this.current.fillColor.type = "Pattern";
       } else {
@@ -4251,139 +4251,12 @@ var CanvasGraphics = (function() {
       }
     },
     getPattern: function(cs, args) {
-      var length = args.length;
-      var base = cs.base;
-      if (base) {
-        var baseComps = base.numComps;
-
-        var color = [];
-        for (var i = 0; i < baseComps; ++i)
-          color.push(args[i]);
-
-        color = base.getRgb(color);
-      }
-
-      var patternName = args[length - 1];
-      if (!IsName(patternName))
-        error("Bad args to getPattern");
-
-      var xref = this.xref;
-      var patternRes = xref.fetchIfRef(this.res.get("Pattern"));
-      if (!patternRes)
-        error("Unable to find pattern resource");
-
-      var pattern = xref.fetchIfRef(patternRes.get(patternName.name));
-      var dict = IsStream(pattern) ? pattern.dict : pattern;
-
-      var types = [null, this.getTilingPattern, this.getShadingPattern];
-
-      var typeNum = dict.get("PatternType");
-      var patternFn = types[typeNum];
-      if (!patternFn)
-        error("Unhandled pattern type");
-      return patternFn.call(this, pattern, dict, color);
     },
     getShadingPattern: function(pattern, dict) {
-      var matrix = dict.get("Matrix");
-      
-      this.save();
-      this.transform.apply(this, matrix);
-      var shading = this.getShading(pattern.get("Shading"));
-      this.restore();
-      return shading;
      // TODO('store transform so it can be applied before every fill');
      // return shading;
     },
     getTilingPattern: function(pattern, dict, color) {
-      function multiply(m, tm) {
-        var a = m[0] * tm[0] + m[1] * tm[2];
-        var b = m[0] * tm[1] + m[1] * tm[3];
-        var c = m[2] * tm[0] + m[3] * tm[2];
-        var d = m[2] * tm[1] + m[3] * tm[3];
-        var e = m[4] * tm[0] + m[5] * tm[2] + tm[4];
-        var f = m[4] * tm[1] + m[5] * tm[3] + tm[5];
-        return [a, b, c, d, e, f];
-      };
-
-      this.save();
-      var ctx = this.ctx;
-
-
-      TODO('TilingType');
-
-      var matrix = dict.get('Matrix') || IDENTITY_MATRIX;
-
-      var bbox = dict.get('BBox');
-      var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
-
-      var xstep = dict.get('XStep');
-      var ystep = dict.get('YStep');
-
-      // top left corner should correspond to the top left of the bbox
-      var topLeft = this.applyTransform(x0, y0, matrix);
-      // we want the canvas to be as large as the step size
-      var botRight = this.applyTransform(x0 + xstep, y0 + ystep, matrix);
-
-      var width = botRight[0] - topLeft[0];
-      var height = botRight[1] - topLeft[1];
-
-      // TODO: hack to avoid OOM, remove then pattern code is fixed
-      if (Math.abs(width) > 8192 || Math.abs(height) > 8192) {
-        this.restore();
-        return 'hotpink';
-      }
-
-      var tmpCanvas = new this.ScratchCanvas(width, height);
-
-      // set the new canvas element context as the graphics context
-      var tmpCtx = tmpCanvas.getContext('2d');
-      var savedCtx = ctx;
-      this.ctx = tmpCtx;
-
-      var paintType = dict.get('PaintType');
-      switch (paintType) {
-      case PAINT_TYPE_COLORED:
-        tmpCtx.fillStyle = savedCtx.fillStyle;
-        tmpCtx.strokeStyle = savedCtx.strokeStyle;
-        break;
-      case PAINT_TYPE_UNCOLORED:
-        color = this.makeCssRgb.apply(this, color);
-        tmpCtx.fillStyle = color;
-        tmpCtx.strokeStyle = color;
-        break;
-      default:
-        error('Unsupported paint type');
-      }
-
-      // normalize transform matrix so each step
-      // takes up the entire tmpCanvas (need to remove white borders)
-      if (matrix[1] === 0 && matrix[2] === 0) {
-        matrix[0] = tmpCanvas.width / xstep;
-        matrix[3] = tmpCanvas.height / ystep;
-        topLeft = this.applyTransform(x0, y0, matrix);
-      }
-
-      // move the top left corner of bounding box to [0,0]
-      matrix = multiply(matrix, [1, 0, 0, 1, -topLeft[0], -topLeft[1]]);
-      
-      this.transform.apply(this, matrix);
-
-      if (bbox && IsArray(bbox) && 4 == bbox.length) {
-        this.rectangle.apply(this, bbox);
-        this.clip();
-        this.endPath();
-      }
-
-      var xref = this.xref;
-      var res = xref.fetchIfRef(dict.get('Resources'));
-      if (!pattern.code)
-        pattern.code = this.compile(pattern, xref, res, []);
-      this.execute(pattern.code, xref, res);
-
-      this.ctx = savedCtx;
-      this.restore();
-
-      return this.ctx.createPattern(tmpCanvas, 'repeat');
     },
     setStrokeGray: function(gray) {
       this.setStrokeRGBColor(gray, gray, gray);
@@ -4421,10 +4294,10 @@ var CanvasGraphics = (function() {
       if (!shading)
         error('No shading object found');
 
-      var shadingFill = this.getShading(shading);
+      var shadingFill = Pattern.parseShading(shading, null, xref, res, ctx);
 
       this.save();
-      ctx.fillStyle = shadingFill.patternFn.apply(this, ctx);
+      ctx.fillStyle = shadingFill.getPattern(ctx);
 
       var inv = ctx.mozCurrentTransformInverse;
       if (inv) {
@@ -4456,181 +4329,10 @@ var CanvasGraphics = (function() {
       this.restore();
     },
     getShading: function(shading) {
-      this.save();
-      
-      shading = this.xref.fetchIfRef(shading);
-      var dict = IsStream(shading) ? shading.dict : shading;
-
-      var bbox = dict.get('BBox');
-      if (bbox && IsArray(bbox) && 4 == bbox.length) {
-        this.rectangle.apply(this, bbox);
-        this.clip();
-        this.endPath();
-      }
-
-      var background = dict.get('Background');
-      if (background)
-        TODO('handle background colors');
-
-      var cs = dict.get('ColorSpace', 'CS');
-      cs = ColorSpace.parse(cs, this.xref, this.res);
-
-      var types = [null,
-          null,
-          this.getAxialShading,
-          this.getRadialShading];
-
-      var typeNum = dict.get('ShadingType');
-      var shadingFn = types[typeNum];
-      
-      this.restore();
-
-      // Most likely we will not implement other types of shading
-      // unless the browser supports them
-      if (!shadingFn) {
-        warn("Unknown or NYI type of shading '"+ typeNum +"'");
-        return 'hotpink';
-      }
-
-      return shadingFn.call(this, shading, cs);
     },
     getAxialShading: function(sh, cs) {
-      var coordsArr = sh.get('Coords');
-
-      var t0 = 0.0, t1 = 1.0;
-      if (sh.has('Domain')) {
-        var domainArr = sh.get('Domain');
-        t0 = domainArr[0], t1 = domainArr[1];
-      }
-
-      var extendStart = false, extendEnd = false;
-      if (sh.has('Extend')) {
-        var extendArr = sh.get('Extend');
-        extendStart = extendArr[0], extendEnd = extendArr[1];
-        TODO('Support extend');
-      }
-      var fnObj = sh.get('Function');
-      fnObj = this.xref.fetchIfRef(fnObj);
-      if (IsArray(fnObj))
-        error('No support for array of functions');
-      else if (!IsPDFFunction(fnObj))
-        error('Invalid function');
-      var fn = new PDFFunction(this.xref, fnObj);
-
-      // 10 samples seems good enough for now, but probably won't work
-      // if there are sharp color changes. Ideally, we would implement
-      // the spec faithfully and add lossless optimizations.
-      var step = (t1 - t0) / 10;
-      var diff = t1 - t0;
-
-      var colorStops = [];
-      for (var i = t0; i <= t1; i += step) {
-        var color = fn.func([i]);
-        var rgbColor = this.makeCssRgb.apply(this, cs.getRgb(color));
-        colorStops.push([(i - t0) / diff, rgbColor]);
-      }
-      
-      var patternMatrix = this.ctx.mozCurrentTransform;
-
-      return {
-        patternFn : function() {
-          var x0 = coordsArr[0], y0 = coordsArr[1];
-          var x1 = coordsArr[2], y1 = coordsArr[3];
-          
-          // if the browser supports getting the tranform matrix, convert
-          // gradient coordinates from pattern space to current user space
-          if (patternMatrix) {
-            var userMatrix = this.ctx.mozCurrentTransformInverse;
-            
-            var p = this.applyTransform(x0, y0, patternMatrix);
-            p = this.applyTransform(p[0], p[1], userMatrix);
-            x0 = p[0];
-            y0 = p[1];
-
-            var p = this.applyTransform(x1, y1, patternMatrix);
-            p = this.applyTransform(p[0], p[1], userMatrix);
-            x1 = p[0];
-            y1 = p[1];
-          }
-
-          var gradient = 
-              this.ctx.createLinearGradient(x0, y0, x1, y1);
-          for (var i = 0, ii = colorStops.length; i < ii; ++i) {
-            var c = colorStops[i];
-            gradient.addColorStop(c[0], c[1]);
-          }
-          return gradient;
-        }
-      }
     },
     getRadialShading: function(sh, cs) {
-      var coordsArr = sh.get('Coords');
-
-      var t0 = 0.0, t1 = 1.0;
-      if (sh.has('Domain')) {
-        var domainArr = sh.get('Domain');
-        t0 = domainArr[0], t1 = domainArr[1];
-      }
-
-      var extendStart = false, extendEnd = false;
-      if (sh.has('Extend')) {
-        var extendArr = sh.get('Extend');
-        extendStart = extendArr[0], extendEnd = extendArr[1];
-        TODO('Support extend');
-      }
-      var fnObj = sh.get('Function');
-      fnObj = this.xref.fetchIfRef(fnObj);
-      if (IsArray(fnObj))
-        error('No support for array of functions');
-      else if (!IsPDFFunction(fnObj))
-        error('Invalid function');
-      var fn = new PDFFunction(this.xref, fnObj);
-
-      // 10 samples seems good enough for now, but probably won't work
-      // if there are sharp color changes. Ideally, we would implement
-      // the spec faithfully and add lossless optimizations.
-      var step = (t1 - t0) / 10;
-      var diff = t1 - t0;
-
-      var colorStops = [];
-      for (var i = t0; i <= t1; i += step) {
-        var color = fn.func([i]);
-        var rgbColor = this.makeCssRgb.apply(this, cs.getRgb(color));
-        colorStops.push([(i - t0) / diff, rgbColor]);
-      }
-
-      var patternMatrix = this.ctx.mozCurrentTransform;
-
-      return {
-        patternFn : function() {
-          var x0 = coordsArr[0], y0 = coordsArr[1], r0 = coordsArr[2];
-          var x1 = coordsArr[3], y1 = coordsArr[4], r1 = coordsArr[5];
-          
-          // if the browser supports getting the tranform matrix, convert
-          // gradient coordinates from pattern space to current user space
-          if (patternMatrix) {
-            var userMatrix = this.ctx.mozCurrentTransformInverse;
-            
-            var p = this.applyTransform(x0, y0, patternMatrix);
-            p = this.applyTransform(p[0], p[1], userMatrix);
-            x0 = p[0];
-            y0 = p[1];
-
-            var p = this.applyTransform(x1, y1, patternMatrix);
-            p = this.applyTransform(p[0], p[1], userMatrix);
-            x1 = p[0];
-            y1 = p[1];
-          }
-
-          var gradient = 
-              this.ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
-          for (var i = 0, ii = colorStops.length; i < ii; ++i) {
-            var c = colorStops[i];
-            gradient.addColorStop(c[0], c[1]);
-          }
-          return gradient;
-        }
-      }
     },
 
     // Images
@@ -4832,6 +4534,8 @@ var ColorSpace = (function() {
       }
     }
 
+    if (!xref.fetchIfRef)
+      console.log("blah");
     cs = xref.fetchIfRef(cs);
 
     if (IsName(cs)) {
@@ -5154,6 +4858,385 @@ var DeviceCmykCS = (function() {
   return constructor;
 })();
 
+var Pattern = (function() {
+  // Constructor should define this.getPattern
+  function constructor() {
+    error('should not call Pattern constructor');
+  };
+
+  constructor.prototype = {
+    // Input: current Canvas context
+    // Output: the appropriate fillStyle or strokeStyle
+    getPattern: function pattern_getStyle(ctx) {
+      error('Should not call Pattern.getStyle');
+    },
+  };
+
+  constructor.parse = function pattern_parse(cs, args, xref, res, ctx) {
+    var length = args.length;
+
+    var patternName = args[length - 1];
+    if (!IsName(patternName))
+      error("Bad args to getPattern");
+
+    var patternRes = xref.fetchIfRef(res.get("Pattern"));
+    if (!patternRes)
+      error("Unable to find pattern resource");
+
+    var pattern = xref.fetchIfRef(patternRes.get(patternName.name));
+    var dict = IsStream(pattern) ? pattern.dict : pattern;
+
+    var typeNum = dict.get("PatternType");
+    
+    var matrix = dict.get('Matrix');
+    var patMatrix = ctx.mozCurrentTransform;
+    if (patMatrix) {
+      if (matrix) {
+        ctx.save();
+        ctx.transform.apply(ctx, matrix);
+        patMatrix = ctx.mozCurrentTransform;
+        ctx.restore();
+      }
+    }
+
+    switch(typeNum) {
+    case 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);
+      }
+      return new TilingPattern(pattern, dict, color);
+      break;
+    case 2:
+      var shading = xref.fetchIfRef(pattern.get('Shading'));
+      return Pattern.parseShading(shading, patMatrix, xref, res, ctx);
+    default:
+      error('Unknown type of pattern');
+    }
+  };
+
+  constructor.parseShading = function pattern_shading(shading, patMatrix,
+      xref, res, ctx) {
+
+    var dict = IsStream(shading) ? shading.dict : shading;
+
+    var bbox = dict.get('BBox');
+    var bg = dict.get('Background');
+
+    var cs = dict.get('ColorSpace', 'CS');
+    cs = ColorSpace.parse(cs, xref, res);
+
+    var type = dict.get('ShadingType');
+
+    switch (type) {
+    case 2:
+      return new AxialShading(dict, patMatrix, bbox, cs, bg, xref);
+      break;
+    case 3:
+      return new RadialShading(dict, patMatrix, bbox, cs, bg, xref);
+      break;
+    default:
+      return new DummyShading();
+    }
+  }
+  return constructor;
+})();
+
+var AxialShading = (function() {
+  function constructor(dict, patternMatrix, bbox, cs, background, xref) {
+    this.bbox = bbox;
+    this.cs = cs;
+    this.background = background;
+    this.patternMatrix = patternMatrix;
+
+    this.coordsArr = dict.get('Coords');
+
+    var t0 = 0.0, t1 = 1.0;
+    if (dict.has('Domain')) {
+      var domainArr = dict.get('Domain');
+      t0 = domainArr[0], t1 = domainArr[1];
+    }
+
+    var extendStart = false, extendEnd = false;
+    if (dict.has('Extend')) {
+      var extendArr = dict.get('Extend');
+      extendStart = extendArr[0], extendEnd = extendArr[1];
+      TODO('Support extend');
+    }
+
+    this.extendStart = extendStart;
+    this.extendEnd = extendEnd;
+
+    var fnObj = dict.get('Function');
+    fnObj = xref.fetchIfRef(fnObj);
+    if (IsArray(fnObj))
+      error('No support for array of functions');
+    else if (!IsPDFFunction(fnObj))
+      error('Invalid function');
+    var fn = new PDFFunction(xref, fnObj);
+
+    // 10 samples seems good enough for now, but probably won't work
+    // if there are sharp color changes. Ideally, we would implement
+    // the spec faithfully and add lossless optimizations.
+    var step = (t1 - t0) / 10;
+    var diff = t1 - t0;
+
+    var colorStops = [];
+    for (var i = t0; i <= t1; i += step) {
+      var color = fn.func([i]);
+      var rgbColor = this.makeCssRgb.apply(this, cs.getRgb(color));
+      colorStops.push([(i - t0) / diff, rgbColor]);
+    }
+
+    this.colorStops = colorStops;
+  };
+
+  constructor.prototype = {
+    getPattern: function(ctx) {
+      var coordsArr = this.coordsArr;
+      var x0 = coordsArr[0], y0 = coordsArr[1];
+      var x1 = coordsArr[2], y1 = coordsArr[3];
+
+      // if the browser supports getting the tranform matrix, convert
+      // gradient coordinates from pattern space to current user space
+      var patternMatrix = this.patternMatrix;
+      if (patternMatrix) {
+        var userMatrix = ctx.mozCurrentTransformInverse;
+
+        var p = this.applyTransform(x0, y0, patternMatrix);
+        p = this.applyTransform(p[0], p[1], userMatrix);
+        x0 = p[0];
+        y0 = p[1];
+
+        var p = this.applyTransform(x1, y1, patternMatrix);
+        p = this.applyTransform(p[0], p[1], userMatrix);
+        x1 = p[0];
+        y1 = p[1];
+      }
+
+      var colorStops = this.colorStops;
+      var gradient = 
+        ctx.createLinearGradient(x0, y0, x1, y1);
+      for (var i = 0, ii = colorStops.length; i < ii; ++i) {
+        var c = colorStops[i];
+        gradient.addColorStop(c[0], c[1]);
+      }
+      return gradient;
+    },
+    applyTransform: function(x0, y0, m) {
+      var xt = x0 * m[0] + y0 * m[2] + m[4];
+      var yt = x0 * m[1] + y0 * m[3] + m[5];
+      return [xt, yt];
+    },
+    makeCssRgb: function(r, g, b) {
+      var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
+      return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
+    }
+  };
+  return constructor;
+})();
+
+var RadialShading = (function() {
+  function constructor(dict, patternMatrix, bbox, cs, background, xref) {
+    this.bbox = bbox;
+    this.cs = cs;
+    this.background = background;
+    this.patternMatrix = patternMatrix;
+
+    this.coordsArr = dict.get('Coords');
+
+    var t0 = 0.0, t1 = 1.0;
+    if (dict.has('Domain')) {
+      var domainArr = dict.get('Domain');
+      t0 = domainArr[0], t1 = domainArr[1];
+    }
+
+    var extendStart = false, extendEnd = false;
+    if (dict.has('Extend')) {
+      var extendArr = dict.get('Extend');
+      extendStart = extendArr[0], extendEnd = extendArr[1];
+      TODO('Support extend');
+    }
+
+    this.extendStart = extendStart;
+    this.extendEnd = extendEnd;
+
+    var fnObj = dict.get('Function');
+    fnObj = xref.fetchIfRef(fnObj);
+    if (IsArray(fnObj))
+      error('No support for array of functions');
+    else if (!IsPDFFunction(fnObj))
+      error('Invalid function');
+    var fn = new PDFFunction(xref, fnObj);
+
+    // 10 samples seems good enough for now, but probably won't work
+    // if there are sharp color changes. Ideally, we would implement
+    // the spec faithfully and add lossless optimizations.
+    var step = (t1 - t0) / 10;
+    var diff = t1 - t0;
+
+    var colorStops = [];
+    for (var i = t0; i <= t1; i += step) {
+      var color = fn.func([i]);
+      var rgbColor = this.makeCssRgb.apply(this, cs.getRgb(color));
+      colorStops.push([(i - t0) / diff, rgbColor]);
+    }
+
+    this.colorStops = colorStops;
+  };
+
+  constructor.prototype = {
+    getPattern: function(ctx) {
+      var coordsArr = this.coordsArr;
+      var x0 = coordsArr[0], y0 = coordsArr[1], r0 = coordsArr[2];
+      var x1 = coordsArr[3], y1 = coordsArr[4], r1 = coordsArr[5];
+
+      // if the browser supports getting the tranform matrix, convert
+      // gradient coordinates from pattern space to current user space
+      var patternMatrix = this.patternMatrix;
+      if (patternMatrix) {
+        var userMatrix = ctx.mozCurrentTransformInverse;
+
+        var p = this.applyTransform(x0, y0, patternMatrix);
+        p = this.applyTransform(p[0], p[1], userMatrix);
+        x0 = p[0];
+        y0 = p[1];
+
+        var p = this.applyTransform(x1, y1, patternMatrix);
+        p = this.applyTransform(p[0], p[1], userMatrix);
+        x1 = p[0];
+        y1 = p[1];
+      }
+
+      var colorStops = this.colorStops;
+      var gradient = 
+        ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
+      for (var i = 0, ii = colorStops.length; i < ii; ++i) {
+        var c = colorStops[i];
+        gradient.addColorStop(c[0], c[1]);
+      }
+      return gradient;
+    },
+    applyTransform: function(x0, y0, m) {
+      var xt = x0 * m[0] + y0 * m[2] + m[4];
+      var yt = x0 * m[1] + y0 * m[3] + m[5];
+      return [xt, yt];
+    },
+    makeCssRgb: function(r, g, b) {
+      var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
+      return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
+    }
+  };
+
+  return constructor;
+})();
+
+var TilingPattern = (function() {
+  function constructor(tiling) {
+      function multiply(m, tm) {
+        var a = m[0] * tm[0] + m[1] * tm[2];
+        var b = m[0] * tm[1] + m[1] * tm[3];
+        var c = m[2] * tm[0] + m[3] * tm[2];
+        var d = m[2] * tm[1] + m[3] * tm[3];
+        var e = m[4] * tm[0] + m[5] * tm[2] + tm[4];
+        var f = m[4] * tm[1] + m[5] * tm[3] + tm[5];
+        return [a, b, c, d, e, f];
+      };
+
+      this.save();
+      var ctx = this.ctx;
+
+
+      TODO('TilingType');
+
+      var matrix = dict.get('Matrix') || IDENTITY_MATRIX;
+
+      var bbox = dict.get('BBox');
+      var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
+
+      var xstep = dict.get('XStep');
+      var ystep = dict.get('YStep');
+
+      // top left corner should correspond to the top left of the bbox
+      var topLeft = this.applyTransform(x0, y0, matrix);
+      // we want the canvas to be as large as the step size
+      var botRight = this.applyTransform(x0 + xstep, y0 + ystep, matrix);
+
+      var width = botRight[0] - topLeft[0];
+      var height = botRight[1] - topLeft[1];
+
+      // TODO: hack to avoid OOM, remove then pattern code is fixed
+      if (Math.abs(width) > 8192 || Math.abs(height) > 8192) {
+        this.restore();
+        return 'hotpink';
+      }
+
+      var tmpCanvas = new this.ScratchCanvas(width, height);
+
+      // set the new canvas element context as the graphics context
+      var tmpCtx = tmpCanvas.getContext('2d');
+      var savedCtx = ctx;
+      this.ctx = tmpCtx;
+
+      var paintType = dict.get('PaintType');
+      switch (paintType) {
+      case PAINT_TYPE_COLORED:
+        tmpCtx.fillStyle = savedCtx.fillStyle;
+        tmpCtx.strokeStyle = savedCtx.strokeStyle;
+        break;
+      case PAINT_TYPE_UNCOLORED:
+        color = this.makeCssRgb.apply(this, color);
+        tmpCtx.fillStyle = color;
+        tmpCtx.strokeStyle = color;
+        break;
+      default:
+        error('Unsupported paint type');
+      }
+
+      // normalize transform matrix so each step
+      // takes up the entire tmpCanvas (need to remove white borders)
+      if (matrix[1] === 0 && matrix[2] === 0) {
+        matrix[0] = tmpCanvas.width / xstep;
+        matrix[3] = tmpCanvas.height / ystep;
+        topLeft = this.applyTransform(x0, y0, matrix);
+      }
+
+      // move the top left corner of bounding box to [0,0]
+      matrix = multiply(matrix, [1, 0, 0, 1, -topLeft[0], -topLeft[1]]);
+      
+      this.transform.apply(this, matrix);
+
+      if (bbox && IsArray(bbox) && 4 == bbox.length) {
+        this.rectangle.apply(this, bbox);
+        this.clip();
+        this.endPath();
+      }
+
+      var xref = this.xref;
+      var res = xref.fetchIfRef(dict.get('Resources'));
+      if (!pattern.code)
+        pattern.code = this.compile(pattern, xref, res, []);
+      this.execute(pattern.code, xref, res);
+
+      this.ctx = savedCtx;
+      this.restore();
+
+      return this.ctx.createPattern(tmpCanvas, 'repeat');
+  };
+
+  constructor.prototype = {
+  };
+  return constructor;
+})();
+
+
 var PDFImage = (function() {
   function constructor(xref, res, image, inline) {
     this.image = image;

From 9dcac17a3e5e264011da0495fab9bcbc40c2b5b0 Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Thu, 14 Jul 2011 10:59:12 -0700
Subject: [PATCH 04/12] patterns working

---
 pdf.js | 364 ++++++++++++++++++++++-----------------------------------
 1 file changed, 141 insertions(+), 223 deletions(-)

diff --git a/pdf.js b/pdf.js
index 2af03dce8..5ce4c47bd 100644
--- a/pdf.js
+++ b/pdf.js
@@ -2969,6 +2969,7 @@ var Page = (function() {
       var fonts = [ ];
 
       this.compile(gfx, fonts);
+      fonts = []
       stats.compile = Date.now();
 
       FontLoader.bind(
@@ -3901,9 +3902,6 @@ var CanvasGraphics = (function() {
   var NORMAL_CLIP = {};
   var EO_CLIP = {};
 
-  // Used for tiling patterns
-  var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2;
-
   constructor.prototype = {
     beginDrawing: function(mediaBox) {
       var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height;
@@ -4019,11 +4017,9 @@ var CanvasGraphics = (function() {
       var fillColor = this.current.fillColor;
 
       if (fillColor.type === "Pattern") {
-        this.ctx.fillStyle = fillColor.getPattern(ctx);
-        ctx.fill();
-      } else {
-        ctx.fill();
+        ctx.fillStyle = fillColor.getPattern(ctx);
       }
+      ctx.fill();
 
       this.consumePath();
     },
@@ -4227,7 +4223,7 @@ var CanvasGraphics = (function() {
       var cs = this.current.strokeColorSpace;
 
       if (cs.name == 'Pattern') {
-        this.ctx.strokeStyle = this.getPattern(cs, arguments);
+    //    this.ctx.strokeStyle = this.getPattern(cs, arguments);
       } else {
         this.setStrokeColor.apply(this, arguments);
       }
@@ -4242,7 +4238,7 @@ var CanvasGraphics = (function() {
 
       if (cs.name == 'Pattern') {
         // wait until fill to actually get the pattern
-        var pattern = Pattern.parse(cs, arguments, this.xref, this.res,
+        var pattern = Pattern.parse(arguments, cs, this.xref, this.res,
                                     this.ctx);
         this.current.fillColor = pattern;
         this.current.fillColor.type = "Pattern";
@@ -4250,8 +4246,6 @@ var CanvasGraphics = (function() {
         this.setFillColor.apply(this, arguments);
       }
     },
-    getPattern: function(cs, args) {
-    },
     getShadingPattern: function(pattern, dict) {
      // TODO('store transform so it can be applied before every fill');
      // return shading;
@@ -4297,7 +4291,7 @@ var CanvasGraphics = (function() {
       var shadingFill = Pattern.parseShading(shading, null, xref, res, ctx);
 
       this.save();
-      ctx.fillStyle = shadingFill.getPattern(ctx);
+      ctx.fillStyle = shadingFill.getPattern();
 
       var inv = ctx.mozCurrentTransformInverse;
       if (inv) {
@@ -4328,12 +4322,6 @@ var CanvasGraphics = (function() {
 
       this.restore();
     },
-    getShading: function(shading) {
-    },
-    getAxialShading: function(sh, cs) {
-    },
-    getRadialShading: function(sh, cs) {
-    },
 
     // Images
     beginInlineImage: function() {
@@ -4534,8 +4522,6 @@ var ColorSpace = (function() {
       }
     }
 
-    if (!xref.fetchIfRef)
-      console.log("blah");
     cs = xref.fetchIfRef(cs);
 
     if (IsName(cs)) {
@@ -4872,7 +4858,7 @@ var Pattern = (function() {
     },
   };
 
-  constructor.parse = function pattern_parse(cs, args, xref, res, ctx) {
+  constructor.parse = function pattern_parse(args, cs, xref, res, ctx) {
     var length = args.length;
 
     var patternName = args[length - 1];
@@ -4885,19 +4871,7 @@ var Pattern = (function() {
 
     var pattern = xref.fetchIfRef(patternRes.get(patternName.name));
     var dict = IsStream(pattern) ? pattern.dict : pattern;
-
     var typeNum = dict.get("PatternType");
-    
-    var matrix = dict.get('Matrix');
-    var patMatrix = ctx.mozCurrentTransform;
-    if (patMatrix) {
-      if (matrix) {
-        ctx.save();
-        ctx.transform.apply(ctx, matrix);
-        patMatrix = ctx.mozCurrentTransform;
-        ctx.restore();
-      }
-    }
 
     switch(typeNum) {
     case 1:
@@ -4912,51 +4886,53 @@ var Pattern = (function() {
 
         color = base.getRgb(color);
       }
-      return new TilingPattern(pattern, dict, color);
+      return new TilingPattern(pattern, dict, color, xref, ctx);
       break;
     case 2:
-      var shading = xref.fetchIfRef(pattern.get('Shading'));
-      return Pattern.parseShading(shading, patMatrix, xref, res, ctx);
+      var shading = xref.fetchIfRef(dict.get('Shading'));
+      var matrix = dict.get('Matrix');
+      return Pattern.parseShading(shading, matrix, xref, res, ctx);
+      break;
     default:
       error('Unknown type of pattern');
     }
   };
 
-  constructor.parseShading = function pattern_shading(shading, patMatrix,
+  constructor.parseShading = function pattern_shading(shading, matrix,
       xref, res, ctx) {
 
     var dict = IsStream(shading) ? shading.dict : shading;
-
-    var bbox = dict.get('BBox');
-    var bg = dict.get('Background');
-
-    var cs = dict.get('ColorSpace', 'CS');
-    cs = ColorSpace.parse(cs, xref, res);
-
     var type = dict.get('ShadingType');
 
     switch (type) {
     case 2:
-      return new AxialShading(dict, patMatrix, bbox, cs, bg, xref);
+      return new SimpleShading(dict, matrix, xref, res, ctx);
       break;
     case 3:
-      return new RadialShading(dict, patMatrix, bbox, cs, bg, xref);
+      return new SimpleShading(dict, matrix, xref, res, ctx);
       break;
     default:
-      return new DummyShading();
+      error('Unsupported shading');
     }
   }
   return constructor;
 })();
 
-var AxialShading = (function() {
-  function constructor(dict, patternMatrix, bbox, cs, background, xref) {
-    this.bbox = bbox;
-    this.cs = cs;
-    this.background = background;
-    this.patternMatrix = patternMatrix;
-
+var SimpleShading = (function() {
+  function constructor(dict, matrix, xref, res, ctx) {
+    this.matrix = matrix;
+    var bbox = dict.get('BBox');
+    var background = dict.get('Background');
     this.coordsArr = dict.get('Coords');
+    this.shadingType = dict.get('ShadingType');
+
+    this.ctx = ctx;
+    this.curMatrix = ctx.mozCurrentTransform;
+    console.log(ctx.mozCurrentTransform);
+
+    var cs = dict.get('ColorSpace', 'CS');
+    cs = ColorSpace.parse(cs, xref, res);
+    this.cs = cs;
 
     var t0 = 0.0, t1 = 1.0;
     if (dict.has('Domain')) {
@@ -4999,40 +4975,60 @@ var AxialShading = (function() {
   };
 
   constructor.prototype = {
-    getPattern: function(ctx) {
+    getPattern: function() {
       var coordsArr = this.coordsArr;
-      var x0 = coordsArr[0], y0 = coordsArr[1];
-      var x1 = coordsArr[2], y1 = coordsArr[3];
+      var type = this.shadingType;
+      if (type == 2) {
+        var p0 = [coordsArr[0], coordsArr[1]];
+        var p1 = [coordsArr[2], coordsArr[3]];
+      } else if (type == 3) {
+        var p0 = [coordsArr[0], coordsArr[1]];
+        var p1 = [coordsArr[3], coordsArr[4]];
+        var r0 = coordsArr[2], r1 = coordsArr[5]
+      } else {
+        error()
+      }
+
+      var matrix = this.matrix;
+      if (matrix) {
+        p0 = this.applyTransform(p0, matrix);
+        p1 = this.applyTransform(p1, matrix);
+      }
 
       // if the browser supports getting the tranform matrix, convert
       // gradient coordinates from pattern space to current user space
-      var patternMatrix = this.patternMatrix;
-      if (patternMatrix) {
+      var curMatrix = this.curMatrix;
+      var ctx = this.ctx;
+      if (curMatrix) {
         var userMatrix = ctx.mozCurrentTransformInverse;
+        console.log(p0 + ',' + p1);
+        console.log(curMatrix);
+        console.log(userMatrix);
 
-        var p = this.applyTransform(x0, y0, patternMatrix);
-        p = this.applyTransform(p[0], p[1], userMatrix);
-        x0 = p[0];
-        y0 = p[1];
+        p0 = this.applyTransform(p0, curMatrix);
+        p0 = this.applyTransform(p0, userMatrix);
+        console.log(p0);
 
-        var p = this.applyTransform(x1, y1, patternMatrix);
-        p = this.applyTransform(p[0], p[1], userMatrix);
-        x1 = p[0];
-        y1 = p[1];
+        p1 = this.applyTransform(p1, curMatrix);
+        p1 = this.applyTransform(p1, userMatrix);
+        console.log(p0 + ',' + p1);
       }
 
       var colorStops = this.colorStops;
-      var gradient = 
-        ctx.createLinearGradient(x0, y0, x1, y1);
+      if (type == 2)
+        var grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
+      else if (type == 3)
+        var grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
+
       for (var i = 0, ii = colorStops.length; i < ii; ++i) {
         var c = colorStops[i];
-        gradient.addColorStop(c[0], c[1]);
+        grad.addColorStop(c[0], c[1]);
       }
-      return gradient;
+      return grad;
     },
-    applyTransform: function(x0, y0, m) {
-      var xt = x0 * m[0] + y0 * m[2] + m[4];
-      var yt = x0 * m[1] + y0 * m[3] + m[5];
+    applyTransform: function(p, m) {
+      var xt = p[0] * m[0] + p[1] * m[2] + m[4];
+      var yt = p[0] * m[1] + p[1] * m[3] + m[5];
       return [xt, yt];
     },
     makeCssRgb: function(r, g, b) {
@@ -5043,63 +5039,85 @@ var AxialShading = (function() {
   return constructor;
 })();
 
-var RadialShading = (function() {
-  function constructor(dict, patternMatrix, bbox, cs, background, xref) {
-    this.bbox = bbox;
-    this.cs = cs;
-    this.background = background;
-    this.patternMatrix = patternMatrix;
+var TilingPattern = (function() {
+  var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2;
+  
+  function constructor(pattern, dict, color, patMatrix, xref, ctx) {
+      function multiply(m, tm) {
+        var a = m[0] * tm[0] + m[1] * tm[2];
+        var b = m[0] * tm[1] + m[1] * tm[3];
+        var c = m[2] * tm[0] + m[3] * tm[2];
+        var d = m[2] * tm[1] + m[3] * tm[3];
+        var e = m[4] * tm[0] + m[5] * tm[2] + tm[4];
+        var f = m[4] * tm[1] + m[5] * tm[3] + tm[5];
+        return [a, b, c, d, e, f];
+      };
 
-    this.coordsArr = dict.get('Coords');
 
-    var t0 = 0.0, t1 = 1.0;
-    if (dict.has('Domain')) {
-      var domainArr = dict.get('Domain');
-      t0 = domainArr[0], t1 = domainArr[1];
-    }
+      TODO('TilingType');
 
-    var extendStart = false, extendEnd = false;
-    if (dict.has('Extend')) {
-      var extendArr = dict.get('Extend');
-      extendStart = extendArr[0], extendEnd = extendArr[1];
-      TODO('Support extend');
-    }
+      this.patMatrix = patMatrix;
 
-    this.extendStart = extendStart;
-    this.extendEnd = extendEnd;
+      var bbox = dict.get('BBox');
+      var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
 
-    var fnObj = dict.get('Function');
-    fnObj = xref.fetchIfRef(fnObj);
-    if (IsArray(fnObj))
-      error('No support for array of functions');
-    else if (!IsPDFFunction(fnObj))
-      error('Invalid function');
-    var fn = new PDFFunction(xref, fnObj);
+      var xstep = dict.get('XStep');
+      var ystep = dict.get('YStep');
 
-    // 10 samples seems good enough for now, but probably won't work
-    // if there are sharp color changes. Ideally, we would implement
-    // the spec faithfully and add lossless optimizations.
-    var step = (t1 - t0) / 10;
-    var diff = t1 - t0;
+      var topLeft = [x0, y0];
+      // we want the canvas to be as large as the step size
+      var botRight = [x0 + xstep, y0 + ystep]
 
-    var colorStops = [];
-    for (var i = t0; i <= t1; i += step) {
-      var color = fn.func([i]);
-      var rgbColor = this.makeCssRgb.apply(this, cs.getRgb(color));
-      colorStops.push([(i - t0) / diff, rgbColor]);
-    }
+      var width = botRight[0] - topLeft[0];
+      var height = botRight[1] - topLeft[1];
 
-    this.colorStops = colorStops;
+      // TODO: hack to avoid OOM, remove then pattern code is fixed
+      while (Math.abs(width) > 8192 || Math.abs(height) > 8192) {
+        width /= 2;
+        height /= 2;
+      }
+
+      var tmpCanvas = new ScratchCanvas(width, height);
+
+      // set the new canvas element context as the graphics context
+      var tmpCtx = tmpCanvas.getContext('2d');
+      var graphics = new CanvasGraphics(tmpCtx);
+
+      var paintType = dict.get('PaintType');
+      switch (paintType) {
+      case PAINT_TYPE_COLORED:
+        tmpCtx.fillStyle = ctx.fillStyle;
+        tmpCtx.strokeStyle = ctx.strokeStyle;
+        break;
+      case PAINT_TYPE_UNCOLORED:
+        color = this.makeCssRgb.apply(this, color);
+        tmpCtx.fillStyle = color;
+        tmpCtx.strokeStyle = color;
+        break;
+      default:
+        error('Unsupported paint type');
+      }
+
+      // transform coordinates to pattern space
+      var tmpTransform = [width / xstep, 0, 0, height / ystep, -topLeft[0], -topLeft[1]];
+      graphics.transform.apply(graphics, matrix);
+
+      if (bbox && IsArray(bbox) && 4 == bbox.length) {
+        graphics.rectangle.apply(graphics, bbox);
+        graphics.clip();
+        graphics.endPath();
+      }
+
+      var res = xref.fetchIfRef(dict.get('Resources'));
+      if (!pattern.code)
+        pattern.code = graphics.compile(pattern, xref, res, []);
+      graphics.execute(pattern.code, xref, res);
+
+      this.canvas = tmpCanvas;
   };
 
   constructor.prototype = {
-    getPattern: function(ctx) {
-      var coordsArr = this.coordsArr;
-      var x0 = coordsArr[0], y0 = coordsArr[1], r0 = coordsArr[2];
-      var x1 = coordsArr[3], y1 = coordsArr[4], r1 = coordsArr[5];
-
-      // if the browser supports getting the tranform matrix, convert
-      // gradient coordinates from pattern space to current user space
+    getPattern: function tiling_getPattern(ctx) {
       var patternMatrix = this.patternMatrix;
       if (patternMatrix) {
         var userMatrix = ctx.mozCurrentTransformInverse;
@@ -5118,11 +5136,10 @@ var RadialShading = (function() {
       var colorStops = this.colorStops;
       var gradient = 
         ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
-      for (var i = 0, ii = colorStops.length; i < ii; ++i) {
+      for (var i = 0, ii = colorStops.length; i < ii; ++i)
         var c = colorStops[i];
-        gradient.addColorStop(c[0], c[1]);
-      }
-      return gradient;
+      ctx.transform.apply
+      return ctx.createPattern(this.canvas, 'repeat');
     },
     applyTransform: function(x0, y0, m) {
       var xt = x0 * m[0] + y0 * m[2] + m[4];
@@ -5134,105 +5151,6 @@ var RadialShading = (function() {
       return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
     }
   };
-
-  return constructor;
-})();
-
-var TilingPattern = (function() {
-  function constructor(tiling) {
-      function multiply(m, tm) {
-        var a = m[0] * tm[0] + m[1] * tm[2];
-        var b = m[0] * tm[1] + m[1] * tm[3];
-        var c = m[2] * tm[0] + m[3] * tm[2];
-        var d = m[2] * tm[1] + m[3] * tm[3];
-        var e = m[4] * tm[0] + m[5] * tm[2] + tm[4];
-        var f = m[4] * tm[1] + m[5] * tm[3] + tm[5];
-        return [a, b, c, d, e, f];
-      };
-
-      this.save();
-      var ctx = this.ctx;
-
-
-      TODO('TilingType');
-
-      var matrix = dict.get('Matrix') || IDENTITY_MATRIX;
-
-      var bbox = dict.get('BBox');
-      var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
-
-      var xstep = dict.get('XStep');
-      var ystep = dict.get('YStep');
-
-      // top left corner should correspond to the top left of the bbox
-      var topLeft = this.applyTransform(x0, y0, matrix);
-      // we want the canvas to be as large as the step size
-      var botRight = this.applyTransform(x0 + xstep, y0 + ystep, matrix);
-
-      var width = botRight[0] - topLeft[0];
-      var height = botRight[1] - topLeft[1];
-
-      // TODO: hack to avoid OOM, remove then pattern code is fixed
-      if (Math.abs(width) > 8192 || Math.abs(height) > 8192) {
-        this.restore();
-        return 'hotpink';
-      }
-
-      var tmpCanvas = new this.ScratchCanvas(width, height);
-
-      // set the new canvas element context as the graphics context
-      var tmpCtx = tmpCanvas.getContext('2d');
-      var savedCtx = ctx;
-      this.ctx = tmpCtx;
-
-      var paintType = dict.get('PaintType');
-      switch (paintType) {
-      case PAINT_TYPE_COLORED:
-        tmpCtx.fillStyle = savedCtx.fillStyle;
-        tmpCtx.strokeStyle = savedCtx.strokeStyle;
-        break;
-      case PAINT_TYPE_UNCOLORED:
-        color = this.makeCssRgb.apply(this, color);
-        tmpCtx.fillStyle = color;
-        tmpCtx.strokeStyle = color;
-        break;
-      default:
-        error('Unsupported paint type');
-      }
-
-      // normalize transform matrix so each step
-      // takes up the entire tmpCanvas (need to remove white borders)
-      if (matrix[1] === 0 && matrix[2] === 0) {
-        matrix[0] = tmpCanvas.width / xstep;
-        matrix[3] = tmpCanvas.height / ystep;
-        topLeft = this.applyTransform(x0, y0, matrix);
-      }
-
-      // move the top left corner of bounding box to [0,0]
-      matrix = multiply(matrix, [1, 0, 0, 1, -topLeft[0], -topLeft[1]]);
-      
-      this.transform.apply(this, matrix);
-
-      if (bbox && IsArray(bbox) && 4 == bbox.length) {
-        this.rectangle.apply(this, bbox);
-        this.clip();
-        this.endPath();
-      }
-
-      var xref = this.xref;
-      var res = xref.fetchIfRef(dict.get('Resources'));
-      if (!pattern.code)
-        pattern.code = this.compile(pattern, xref, res, []);
-      this.execute(pattern.code, xref, res);
-
-      this.ctx = savedCtx;
-      this.restore();
-
-      return this.ctx.createPattern(tmpCanvas, 'repeat');
-  };
-
-  constructor.prototype = {
-  };
   return constructor;
 })();
 

From dc77e076c28e7abb776e9ddb6de101f95f167aeb Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Thu, 14 Jul 2011 11:50:27 -0700
Subject: [PATCH 05/12] Fixed tiling patterns

---
 pdf.js | 72 ++++++++++++++++++++++++----------------------------------
 1 file changed, 30 insertions(+), 42 deletions(-)

diff --git a/pdf.js b/pdf.js
index 5ce4c47bd..af0daeb41 100644
--- a/pdf.js
+++ b/pdf.js
@@ -2969,7 +2969,6 @@ var Page = (function() {
       var fonts = [ ];
 
       this.compile(gfx, fonts);
-      fonts = []
       stats.compile = Date.now();
 
       FontLoader.bind(
@@ -4017,9 +4016,13 @@ var CanvasGraphics = (function() {
       var fillColor = this.current.fillColor;
 
       if (fillColor.type === "Pattern") {
+        this.ctx.save();
         ctx.fillStyle = fillColor.getPattern(ctx);
+        ctx.fill();
+        this.ctx.restore();
+      } else {
+        ctx.fill();
       }
-      ctx.fill();
 
       this.consumePath();
     },
@@ -4246,12 +4249,6 @@ var CanvasGraphics = (function() {
         this.setFillColor.apply(this, arguments);
       }
     },
-    getShadingPattern: function(pattern, dict) {
-     // TODO('store transform so it can be applied before every fill');
-     // return shading;
-    },
-    getTilingPattern: function(pattern, dict, color) {
-    },
     setStrokeGray: function(gray) {
       this.setStrokeRGBColor(gray, gray, gray);
     },
@@ -4906,9 +4903,8 @@ var Pattern = (function() {
 
     switch (type) {
     case 2:
-      return new SimpleShading(dict, matrix, xref, res, ctx);
-      break;
     case 3:
+      // both radial and axial shadings are handled by simple shading
       return new SimpleShading(dict, matrix, xref, res, ctx);
       break;
     default:
@@ -4928,7 +4924,6 @@ var SimpleShading = (function() {
 
     this.ctx = ctx;
     this.curMatrix = ctx.mozCurrentTransform;
-    console.log(ctx.mozCurrentTransform);
 
     var cs = dict.get('ColorSpace', 'CS');
     cs = ColorSpace.parse(cs, xref, res);
@@ -5001,17 +4996,12 @@ var SimpleShading = (function() {
       var ctx = this.ctx;
       if (curMatrix) {
         var userMatrix = ctx.mozCurrentTransformInverse;
-        console.log(p0 + ',' + p1);
-        console.log(curMatrix);
-        console.log(userMatrix);
 
         p0 = this.applyTransform(p0, curMatrix);
         p0 = this.applyTransform(p0, userMatrix);
-        console.log(p0);
 
         p1 = this.applyTransform(p1, curMatrix);
         p1 = this.applyTransform(p1, userMatrix);
-        console.log(p0 + ',' + p1);
       }
 
       var colorStops = this.colorStops;
@@ -5042,7 +5032,7 @@ var SimpleShading = (function() {
 var TilingPattern = (function() {
   var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2;
   
-  function constructor(pattern, dict, color, patMatrix, xref, ctx) {
+  function constructor(pattern, dict, color, xref, ctx) {
       function multiply(m, tm) {
         var a = m[0] * tm[0] + m[1] * tm[2];
         var b = m[0] * tm[1] + m[1] * tm[3];
@@ -5053,10 +5043,12 @@ var TilingPattern = (function() {
         return [a, b, c, d, e, f];
       };
 
-
       TODO('TilingType');
 
-      this.patMatrix = patMatrix;
+      this.matrix = dict.get("Matrix");
+      this.curMatrix = ctx.mozCurrentTransform;
+      this.invMatrix = ctx.mozCurrentTransformInverse;
+      this.ctx = ctx;
 
       var bbox = dict.get('BBox');
       var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
@@ -5072,9 +5064,9 @@ var TilingPattern = (function() {
       var height = botRight[1] - topLeft[1];
 
       // TODO: hack to avoid OOM, remove then pattern code is fixed
-      while (Math.abs(width) > 8192 || Math.abs(height) > 8192) {
-        width /= 2;
-        height /= 2;
+      while (Math.abs(width) > 512 || Math.abs(height) > 512) {
+        width = 512;
+        height = 512;
       }
 
       var tmpCanvas = new ScratchCanvas(width, height);
@@ -5098,9 +5090,14 @@ var TilingPattern = (function() {
         error('Unsupported paint type');
       }
 
+      var scale = [width / xstep, height / ystep];
+      this.scale = scale;
+
       // transform coordinates to pattern space
-      var tmpTransform = [width / xstep, 0, 0, height / ystep, -topLeft[0], -topLeft[1]];
-      graphics.transform.apply(graphics, matrix);
+      var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
+      var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
+      graphics.transform.apply(graphics, tmpScale);
+      graphics.transform.apply(graphics, tmpTranslate);
 
       if (bbox && IsArray(bbox) && 4 == bbox.length) {
         graphics.rectangle.apply(graphics, bbox);
@@ -5118,27 +5115,18 @@ var TilingPattern = (function() {
 
   constructor.prototype = {
     getPattern: function tiling_getPattern(ctx) {
-      var patternMatrix = this.patternMatrix;
-      if (patternMatrix) {
-        var userMatrix = ctx.mozCurrentTransformInverse;
+      var matrix = this.matrix;
+      var curMatrix = this.curMatrix;
 
-        var p = this.applyTransform(x0, y0, patternMatrix);
-        p = this.applyTransform(p[0], p[1], userMatrix);
-        x0 = p[0];
-        y0 = p[1];
+      if (curMatrix)
+        ctx.setTransform.apply(ctx, curMatrix);
 
-        var p = this.applyTransform(x1, y1, patternMatrix);
-        p = this.applyTransform(p[0], p[1], userMatrix);
-        x1 = p[0];
-        y1 = p[1];
-      }
+      if (matrix)
+        ctx.transform.apply(ctx, matrix);
+
+      var scale = this.scale;
+      ctx.scale(1 / scale[0], 1 / scale[1]);
 
-      var colorStops = this.colorStops;
-      var gradient = 
-        ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
-      for (var i = 0, ii = colorStops.length; i < ii; ++i)
-        var c = colorStops[i];
-      ctx.transform.apply
       return ctx.createPattern(this.canvas, 'repeat');
     },
     applyTransform: function(x0, y0, m) {

From faa6875b80b6d9513874960ce2e8a23869c46824 Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Fri, 15 Jul 2011 09:48:40 -0700
Subject: [PATCH 06/12] cleanup, add support for stroking

---
 pdf.js | 126 +++++++++++++++++++++++++++++----------------------------
 1 file changed, 64 insertions(+), 62 deletions(-)

diff --git a/pdf.js b/pdf.js
index af0daeb41..9a5944d5e 100644
--- a/pdf.js
+++ b/pdf.js
@@ -4226,7 +4226,10 @@ var CanvasGraphics = (function() {
       var cs = this.current.strokeColorSpace;
 
       if (cs.name == 'Pattern') {
-    //    this.ctx.strokeStyle = this.getPattern(cs, arguments);
+        // wait until fill to actually get the pattern
+        var pattern = Pattern.parse(arguments, cs, this.xref, this.res,
+                                    this.ctx);
+        this.current.strokeColor = pattern;
       } else {
         this.setStrokeColor.apply(this, arguments);
       }
@@ -4243,8 +4246,9 @@ var CanvasGraphics = (function() {
         // wait until fill to actually get the pattern
         var pattern = Pattern.parse(arguments, cs, this.xref, this.res,
                                     this.ctx);
-        this.current.fillColor = pattern;
-        this.current.fillColor.type = "Pattern";
+//        this.current.fillColor = pattern;
+        this.ctx.fillStyle = pattern.getPattern();
+        this.current.fillColor = "blah";
       } else {
         this.setFillColor.apply(this, arguments);
       }
@@ -4256,19 +4260,24 @@ var CanvasGraphics = (function() {
       this.setFillRGBColor(gray, gray, gray);
     },
     setStrokeRGBColor: function(r, g, b) {
-      this.ctx.strokeStyle = this.makeCssRgb(r, g, b);
+      var color = Util.makeCssRgb(r, g, b);
+      this.ctx.strokeStyle = color;
+      this.current.fillColor = color;
     },
     setFillRGBColor: function(r, g, b) {
-      var color = this.makeCssRgb(r, g, b);
+      var color = Util.makeCssRgb(r, g, b);
       this.ctx.fillStyle = color;
       this.current.fillColor = color;
     },
     setStrokeCMYKColor: function(c, m, y, k) {
-      this.ctx.strokeStyle = this.makeCssCmyk(c, m, y, k);
+      var color = Util.makeCssCmyk(c, m, y, k);
+      this.ctx.strokeStyle = color;
+      this.current.fillColor = color;
     },
     setFillCMYKColor: function(c, m, y, k) {
-      var color = (new DeviceCmykCS()).getRgb([c, m, y, k]);
-      this.setFillRGBColor.apply(this, color);
+      var color = Util.makeCssCmyk(c, m, y, k);
+      this.ctx.fillStyle = color;
+      this.current.fillColor = color;
     },
 
     // Shading
@@ -4296,10 +4305,10 @@ var CanvasGraphics = (function() {
         var width = canvas.width;
         var height = canvas.height;
 
-        var bl = this.applyTransform(0, 0, inv);
-        var br = this.applyTransform(0, width, inv);
-        var ul = this.applyTransform(height, 0, inv);
-        var ur = this.applyTransform(height, width, inv);
+        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]);
@@ -4457,18 +4466,6 @@ var CanvasGraphics = (function() {
       }
       this.ctx.beginPath();
     },
-    makeCssRgb: function(r, g, b) {
-      var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
-      return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
-    },
-    makeCssCmyk: function(c, m, y, k) {
-      // while waiting on CSS's cmyk()...
-      // http://www.ilkeratalay.com/colorspacesfaq.php#rgb
-      var ri = (255 * (1 - Math.min(1, c * (1 - k) + k))) | 0;
-      var gi = (255 * (1 - Math.min(1, m * (1 - k) + k))) | 0;
-      var bi = (255 * (1 - Math.min(1, y * (1 - k) + k))) | 0;
-      return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
-    },
     // We generally keep the canvas context set for
     // nonzero-winding, and just set evenodd for the operations
     // that need them.
@@ -4480,16 +4477,30 @@ var CanvasGraphics = (function() {
     restoreFillRule: function(rule) {
       this.ctx.mozFillRule = rule;
     },
-    applyTransform: function(x0, y0, m) {
-      var xt = x0 * m[0] + y0 * m[2] + m[4];
-      var yt = x0 * m[1] + y0 * m[3] + m[5];
-      return [xt, yt];
-    }
   };
 
   return constructor;
 })();
 
+var Util = (function() {
+  function constructor() {};
+  constructor.makeCssRgb = function makergb(r, g, b) {
+    var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
+    return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
+  };
+  constructor.makeCssCmyk = function makecmyk(c, m, y, k) {
+    var c = (new DeviceCmykCS()).getRgb([c, m, y, k]);
+    return 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] + ')';
+  };
+  constructor.applyTransform = function apply(p, m) {
+    var xt = p[0] * m[0] + p[1] * m[2] + m[4];
+    var yt = p[0] * m[1] + p[1] * m[3] + m[5];
+    return [xt, yt];
+  };
+  
+  return constructor;
+})();
+
 var ColorSpace = (function() {
   // Constructor should define this.numComps, this.defaultColor, this.name
   function constructor() {
@@ -4884,12 +4895,10 @@ var Pattern = (function() {
         color = base.getRgb(color);
       }
       return new TilingPattern(pattern, dict, color, xref, ctx);
-      break;
     case 2:
       var shading = xref.fetchIfRef(dict.get('Shading'));
       var matrix = dict.get('Matrix');
       return Pattern.parseShading(shading, matrix, xref, res, ctx);
-      break;
     default:
       error('Unknown type of pattern');
     }
@@ -4904,23 +4913,33 @@ var Pattern = (function() {
     switch (type) {
     case 2:
     case 3:
-      // both radial and axial shadings are handled by simple shading
-      return new SimpleShading(dict, matrix, xref, res, ctx);
-      break;
+      // both radial and axial shadings are handled by RadialAxial shading
+      return new RadialAxialShading(dict, matrix, xref, res, ctx);
     default:
-      error('Unsupported shading');
+      return new DummyShading();
     }
   }
   return constructor;
 })();
 
-var SimpleShading = (function() {
+var DummyShading = (function() {
+  function constructor() {};
+  constructor.prototype = {
+    getPattern: function dummy_getpattern() {
+      return 'hotpink';
+    }
+  };
+  return constructor;
+})();
+
+var RadialAxialShading = (function() {
   function constructor(dict, matrix, xref, res, ctx) {
     this.matrix = matrix;
     var bbox = dict.get('BBox');
     var background = dict.get('Background');
     this.coordsArr = dict.get('Coords');
     this.shadingType = dict.get('ShadingType');
+    this.type = 'Pattern';
 
     this.ctx = ctx;
     this.curMatrix = ctx.mozCurrentTransform;
@@ -4962,7 +4981,7 @@ var SimpleShading = (function() {
     var colorStops = [];
     for (var i = t0; i <= t1; i += step) {
       var color = fn.func([i]);
-      var rgbColor = this.makeCssRgb.apply(this, cs.getRgb(color));
+      var rgbColor = Util.makeCssRgb.apply(this, cs.getRgb(color));
       colorStops.push([(i - t0) / diff, rgbColor]);
     }
 
@@ -4986,8 +5005,8 @@ var SimpleShading = (function() {
 
       var matrix = this.matrix;
       if (matrix) {
-        p0 = this.applyTransform(p0, matrix);
-        p1 = this.applyTransform(p1, matrix);
+        p0 = Util.applyTransform(p0, matrix);
+        p1 = Util.applyTransform(p1, matrix);
       }
 
       // if the browser supports getting the tranform matrix, convert
@@ -4997,11 +5016,11 @@ var SimpleShading = (function() {
       if (curMatrix) {
         var userMatrix = ctx.mozCurrentTransformInverse;
 
-        p0 = this.applyTransform(p0, curMatrix);
-        p0 = this.applyTransform(p0, userMatrix);
+        p0 = Util.applyTransform(p0, curMatrix);
+        p0 = Util.applyTransform(p0, userMatrix);
 
-        p1 = this.applyTransform(p1, curMatrix);
-        p1 = this.applyTransform(p1, userMatrix);
+        p1 = Util.applyTransform(p1, curMatrix);
+        p1 = Util.applyTransform(p1, userMatrix);
       }
 
       var colorStops = this.colorStops;
@@ -5015,15 +5034,6 @@ var SimpleShading = (function() {
         grad.addColorStop(c[0], c[1]);
       }
       return grad;
-    },
-    applyTransform: function(p, m) {
-      var xt = p[0] * m[0] + p[1] * m[2] + m[4];
-      var yt = p[0] * m[1] + p[1] * m[3] + m[5];
-      return [xt, yt];
-    },
-    makeCssRgb: function(r, g, b) {
-      var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
-      return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
     }
   };
   return constructor;
@@ -5049,6 +5059,7 @@ var TilingPattern = (function() {
       this.curMatrix = ctx.mozCurrentTransform;
       this.invMatrix = ctx.mozCurrentTransformInverse;
       this.ctx = ctx;
+      this.type = 'Pattern';
 
       var bbox = dict.get('BBox');
       var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
@@ -5082,7 +5093,7 @@ var TilingPattern = (function() {
         tmpCtx.strokeStyle = ctx.strokeStyle;
         break;
       case PAINT_TYPE_UNCOLORED:
-        color = this.makeCssRgb.apply(this, color);
+        color = Util.makeCssRgb.apply(this, color);
         tmpCtx.fillStyle = color;
         tmpCtx.strokeStyle = color;
         break;
@@ -5128,15 +5139,6 @@ var TilingPattern = (function() {
       ctx.scale(1 / scale[0], 1 / scale[1]);
 
       return ctx.createPattern(this.canvas, 'repeat');
-    },
-    applyTransform: function(x0, y0, m) {
-      var xt = x0 * m[0] + y0 * m[2] + m[4];
-      var yt = x0 * m[1] + y0 * m[3] + m[5];
-      return [xt, yt];
-    },
-    makeCssRgb: function(r, g, b) {
-      var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
-      return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
     }
   };
   return constructor;

From dd1d90213bfb1f714124fe722c85b30a60f60ae4 Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Fri, 15 Jul 2011 11:18:37 -0700
Subject: [PATCH 07/12] cleanup

---
 pdf.js | 55 +++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 39 insertions(+), 16 deletions(-)

diff --git a/pdf.js b/pdf.js
index 9a5944d5e..d371330ac 100644
--- a/pdf.js
+++ b/pdf.js
@@ -4004,7 +4004,17 @@ var CanvasGraphics = (function() {
       this.ctx.rect(x, y, width, height);
     },
     stroke: function() {
-      this.ctx.stroke();
+      var ctx = this.ctx;
+      var strokeColor = this.current.strokeColor;
+      if (strokeColor && strokeColor.type === "Pattern") {
+        ctx.save();
+        ctx.strokeStyle = strokeColor.getPattern(ctx);
+        ctx.stroke();
+        ctx.restore();
+      } else {
+        ctx.stroke();
+      }
+
       this.consumePath();
     },
     closeStroke: function() {
@@ -4015,11 +4025,11 @@ var CanvasGraphics = (function() {
       var ctx = this.ctx;
       var fillColor = this.current.fillColor;
 
-      if (fillColor.type === "Pattern") {
-        this.ctx.save();
+      if (fillColor && fillColor.type === "Pattern") {
+        ctx.save();
         ctx.fillStyle = fillColor.getPattern(ctx);
         ctx.fill();
-        this.ctx.restore();
+        ctx.restore();
       } else {
         ctx.fill();
       }
@@ -4033,13 +4043,27 @@ var CanvasGraphics = (function() {
     },
     fillStroke: function() {
       var ctx = this.ctx;
-      var fillCS = this.current.fillColorSpace;
 
-      if (fillCS && fillCS.name === "Pattern")
-        this.current.fillPattern(ctx); 
-
-      ctx.fill();
-      ctx.stroke();
+      var fillColor = this.current.fillColor;
+      if (fillColor && fillColor.type === "Pattern") {
+        ctx.save();
+        ctx.fillStyle = fillColor.getPattern(ctx);
+        ctx.fill();
+        ctx.restore();
+      } else {
+        ctx.fill();
+      }
+      
+      var strokeColor = this.current.strokeColor;
+      if (stokeColor && strokeColor.type === "Pattern") {
+        ctx.save();
+        ctx.strokeStyle = strokeColor.getPattern(ctx);
+        ctx.stroke();
+        ctx.restore();
+      } else {
+        ctx.stroke();
+      }
+      
       this.consumePath();
     },
     eoFillStroke: function() {
@@ -4246,9 +4270,7 @@ var CanvasGraphics = (function() {
         // wait until fill to actually get the pattern
         var pattern = Pattern.parse(arguments, cs, this.xref, this.res,
                                     this.ctx);
-//        this.current.fillColor = pattern;
-        this.ctx.fillStyle = pattern.getPattern();
-        this.current.fillColor = "blah";
+        this.current.fillColor = pattern;
       } else {
         this.setFillColor.apply(this, arguments);
       }
@@ -4262,7 +4284,7 @@ var CanvasGraphics = (function() {
     setStrokeRGBColor: function(r, g, b) {
       var color = Util.makeCssRgb(r, g, b);
       this.ctx.strokeStyle = color;
-      this.current.fillColor = color;
+      this.current.strokeColor = color;
     },
     setFillRGBColor: function(r, g, b) {
       var color = Util.makeCssRgb(r, g, b);
@@ -4272,7 +4294,7 @@ var CanvasGraphics = (function() {
     setStrokeCMYKColor: function(c, m, y, k) {
       var color = Util.makeCssCmyk(c, m, y, k);
       this.ctx.strokeStyle = color;
-      this.current.fillColor = color;
+      this.current.strokeColor = color;
     },
     setFillCMYKColor: function(c, m, y, k) {
       var color = Util.makeCssCmyk(c, m, y, k);
@@ -5125,9 +5147,10 @@ var TilingPattern = (function() {
   };
 
   constructor.prototype = {
-    getPattern: function tiling_getPattern(ctx) {
+    getPattern: function tiling_getPattern() {
       var matrix = this.matrix;
       var curMatrix = this.curMatrix;
+      var ctx = this.ctx;
 
       if (curMatrix)
         ctx.setTransform.apply(ctx, curMatrix);

From c438a8748a9ac46155d9844ea7ba19a70c4df231 Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Fri, 15 Jul 2011 11:41:39 -0700
Subject: [PATCH 08/12] fix type

---
 pdf.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pdf.js b/pdf.js
index d371330ac..fe2d38ac6 100644
--- a/pdf.js
+++ b/pdf.js
@@ -4055,7 +4055,7 @@ var CanvasGraphics = (function() {
       }
       
       var strokeColor = this.current.strokeColor;
-      if (stokeColor && strokeColor.type === "Pattern") {
+      if (strokeColor && strokeColor.type === "Pattern") {
         ctx.save();
         ctx.strokeStyle = strokeColor.getPattern(ctx);
         ctx.stroke();

From 5f4b84146f2ab2bd95ff1a620e61d87f136236df Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Fri, 15 Jul 2011 12:05:14 -0700
Subject: [PATCH 09/12] fix to Util.getCssCmyk

---
 pdf.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/pdf.js b/pdf.js
index fe2d38ac6..bf34d9398 100644
--- a/pdf.js
+++ b/pdf.js
@@ -4512,7 +4512,8 @@ var Util = (function() {
   };
   constructor.makeCssCmyk = function makecmyk(c, m, y, k) {
     var c = (new DeviceCmykCS()).getRgb([c, m, y, k]);
-    return 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] + ')';
+    var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0;
+    return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
   };
   constructor.applyTransform = function apply(p, m) {
     var xt = p[0] * m[0] + p[1] * m[2] + m[4];

From 2098d840dae1222f4e998b56d1eaa396fec67dad Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Fri, 15 Jul 2011 12:06:38 -0700
Subject: [PATCH 10/12] fix to dummyshading

---
 pdf.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pdf.js b/pdf.js
index bf34d9398..bc726ccd2 100644
--- a/pdf.js
+++ b/pdf.js
@@ -4946,7 +4946,9 @@ var Pattern = (function() {
 })();
 
 var DummyShading = (function() {
-  function constructor() {};
+  function constructor() {
+    this.type = 'Pattern';
+  };
   constructor.prototype = {
     getPattern: function dummy_getpattern() {
       return 'hotpink';

From 636b1105b028a598fb61c7a825848a702f4f1d55 Mon Sep 17 00:00:00 2001
From: sbarman <sbarman@L3CWZ5T.(none)>
Date: Mon, 18 Jul 2011 09:13:02 -0700
Subject: [PATCH 11/12] cleanup

---
 pdf.js | 73 ++++++++++++----------------------------------------------
 1 file changed, 15 insertions(+), 58 deletions(-)

diff --git a/pdf.js b/pdf.js
index bc726ccd2..bab032119 100644
--- a/pdf.js
+++ b/pdf.js
@@ -3817,62 +3817,10 @@ var CanvasExtraState = (function() {
 
     this.old = old;
   }
+
   constructor.prototype = {
-    get fillColorSpace() {
-      var cs = this.fillColorSpaceObj;
-      if (cs)
-        return cs;
-
-      var old = this.old;
-      if (old)
-        return old.fillColorSpace;
-
-      return null;
-    },
-    set fillColorSpace(cs) {
-      this.fillColorSpaceObj = cs;
-    },
-    get strokeColorSpace() {
-      var cs = this.strokeColorSpaceObj;
-      if (cs)
-        return cs;
-
-      var old = this.old;
-      if (old)
-        return old.strokeColorSpace;
-
-      return null;
-    }, 
-    set strokeColorSpace(cs) {
-      this.strokeColorSpaceObj = cs;
-    },
-    get fillColor() {
-      var color = this.fillColorObj;
-      if (color)
-        return color;
-
-      var old = this.old;
-      if (old)
-        return old.fillColor;
-
-      return null;
-    },
-    set fillColor(color) {
-      this.fillColorObj = color;
-    },
-    get strokeColor() {
-      var color = this.strokeColorObj;
-      if (color)
-        return color;
-
-      var old = this.old;
-      if (old)
-        return old.strokeColor;
-
-      return null;
-    },
-    set strokeColor(color) {
-      this.strokeColorObj = color;
+    clone: function canvasextra_clone() {
+      return Object.create(this);
     }
   };
   return constructor;
@@ -3965,7 +3913,7 @@ var CanvasGraphics = (function() {
       }
       var old = this.current;
       this.stateStack.push(old);
-      this.current = new CanvasExtraState(old);
+      this.current = old.clone();
     },
     restore: function() {
       var prev = this.stateStack.pop();
@@ -4007,6 +3955,8 @@ var CanvasGraphics = (function() {
       var ctx = this.ctx;
       var strokeColor = this.current.strokeColor;
       if (strokeColor && 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();
@@ -4250,7 +4200,9 @@ var CanvasGraphics = (function() {
       var cs = this.current.strokeColorSpace;
 
       if (cs.name == 'Pattern') {
-        // wait until fill to actually get the pattern
+        // wait until fill to actually get the pattern, since Canvas
+        // calcualtes the pattern according to the current coordinate space,
+        // not the space when the pattern is set.
         var pattern = Pattern.parse(arguments, cs, this.xref, this.res,
                                     this.ctx);
         this.current.strokeColor = pattern;
@@ -4957,6 +4909,8 @@ var DummyShading = (function() {
   return constructor;
 })();
 
+// Radial and axial shading have very similar implementations
+// If needed, the implementations can be broken into two classes
 var RadialAxialShading = (function() {
   function constructor(dict, matrix, xref, res, ctx) {
     this.matrix = matrix;
@@ -5099,7 +5053,10 @@ var TilingPattern = (function() {
       var width = botRight[0] - topLeft[0];
       var height = botRight[1] - topLeft[1];
 
-      // TODO: hack to avoid OOM, remove then pattern code is fixed
+      // TODO: hack to avoid OOM, we would idealy compute the tiling
+      // pattern to be only as large as the acual size in device space
+      // This could be computed with .mozCurrentTransform, but still 
+      // needs to be implemented
       while (Math.abs(width) > 512 || Math.abs(height) > 512) {
         width = 512;
         height = 512;

From d4157c0c7cf01d13ea49c5fdc9a2036feb70985b Mon Sep 17 00:00:00 2001
From: notmasteryet <async.processingjs@yahoo.com>
Date: Thu, 21 Jul 2011 18:47:48 -0500
Subject: [PATCH 12/12] Formatting hex number, making gjslint happy: reducing
 lines width

---
 crypto.js | 246 ++++++++++++++++++++++++++++++------------------------
 1 file changed, 139 insertions(+), 107 deletions(-)

diff --git a/crypto.js b/crypto.js
index 98f7bb4a1..652f53b2c 100644
--- a/crypto.js
+++ b/crypto.js
@@ -144,110 +144,129 @@ var NullCipher = (function() {
 
 var AES128Cipher = (function() {
   var rcon = new Uint8Array([
-    0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
-    0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
-    0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
-    0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
-    0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
-    0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
-    0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
-    0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
-    0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
-    0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
-    0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
-    0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
-    0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
-    0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
-    0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
-    0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d]);
+    0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
+    0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
+    0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+    0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+    0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+    0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,
+    0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
+    0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
+    0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
+    0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e,
+    0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
+    0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
+    0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
+    0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
+    0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
+    0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
+    0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,
+    0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
+    0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
+    0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+    0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+    0x74, 0xe8, 0xcb, 0x8d]);
 
   var s = new Uint8Array([
-    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
-    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
-    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
-    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
-    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
-    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
-    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
-    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
-    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
-    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
-    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
-    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
-    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
-    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
-    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
-    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]);
+    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
+    0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+    0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
+    0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+    0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
+    0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+    0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
+    0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+    0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
+    0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+    0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
+    0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+    0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
+    0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+    0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
+    0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+    0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
+    0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+    0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
+    0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+    0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
+    0xb0, 0x54, 0xbb, 0x16]);
 
   var inv_s = new Uint8Array([
-    0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
-    0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
-    0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
-    0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
-    0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
-    0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
-    0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
-    0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
-    0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
-    0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
-    0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
-    0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
-    0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
-    0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
-    0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
-    0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]);
+    0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
+    0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+    0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
+    0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+    0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
+    0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+    0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
+    0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+    0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
+    0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+    0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
+    0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+    0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
+    0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+    0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
+    0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+    0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
+    0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+    0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
+    0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+    0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
+    0x55, 0x21, 0x0c, 0x7d]);
 
   var mix = new Uint32Array([
-    0x0, 0xe090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a,
-    0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74,
-    0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6,
-    0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8,
-    0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2,
-    0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57,
-    0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935,
-    0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb,
-    0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x38f5fe7, 0xd8652ec, 0x1f9d45f1,
-    0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf,
-    0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0,
-    0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae,
-    0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94,
-    0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a,
-    0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08,
-    0x2fb5c203, 0x58ae132, 0xb83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d,
-    0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7,
-    0x5c72f5bc, 0x605bed5, 0x80cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9,
-    0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b,
-    0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65,
-    0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f,
-    0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb,
-    0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9,
-    0x23bfa5b2, 0x9808683, 0x7898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47,
-    0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d,
-    0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633,
-    0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a,
-    0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4,
-    0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee,
-    0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510,
-    0x4c6a881b, 0x5e719f06, 0x5078920d, 0xa0fd964, 0x406d46f, 0x161dc372,
-    0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701,
-    0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b,
-    0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75,
-    0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0xc0a67b1, 0x2036aba, 0x10187da7,
-    0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9,
-    0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3,
-    0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0xf853856,
-    0x18c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34,
-    0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca,
-    0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0,
-    0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be,
-    0x91548db5, 0x834f9aa8, 0x8d4697a3]);
+    0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
+    0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
+    0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
+    0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,
+    0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,
+    0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,
+    0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,
+    0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,
+    0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
+    0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,
+    0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,
+    0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,
+    0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,
+    0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,
+    0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,
+    0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,
+    0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,
+    0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,
+    0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,
+    0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
+    0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,
+    0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,
+    0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,
+    0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,
+    0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,
+    0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,
+    0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,
+    0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,
+    0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,
+    0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,
+    0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
+    0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,
+    0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,
+    0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,
+    0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,
+    0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,
+    0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,
+    0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,
+    0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,
+    0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,
+    0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,
+    0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
+    0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
 
   function expandKey128(cipherKey) {
     var b = 176, result = new Uint8Array(b);
     result.set(cipherKey);
     for (var j = 16, i = 1; j < b; ++i) {
       // RotWord
-      var t1 = result[j - 3], t2 = result[j - 2], t3 = result[j - 1], t4 = result[j - 4];
+      var t1 = result[j - 3], t2 = result[j - 2],
+          t3 = result[j - 1], t4 = result[j - 4];
       // SubWord
       t1 = s[t1]; t2 = s[t2]; t3 = s[t3]; t4 = s[t4];
       // Rcon
@@ -272,9 +291,12 @@ var AES128Cipher = (function() {
       state[j] ^= key[k];
     for (i = 9; i >= 1; --i) {
       // InvShiftRows
-      t = state[13]; state[13] = state[9]; state[9] = state[5]; state[5] = state[1]; state[1] = t;
-      t = state[14]; u = state[10]; state[14] = state[6]; state[10] = state[2]; state[6] = t; state[2] = u;
-      t = state[15]; u = state[11]; v = state[7]; state[15] = state[3]; state[11] = t; state[7] = u; state[3] = v;
+      t = state[13]; state[13] = state[9]; state[9] = state[5];
+      state[5] = state[1]; state[1] = t;
+      t = state[14]; u = state[10]; state[14] = state[6];
+      state[10] = state[2]; state[6] = t; state[2] = u;
+      t = state[15]; u = state[11]; v = state[7]; state[15] = state[3];
+      state[11] = t; state[7] = u; state[3] = v;
       // InvSubBytes
       for (j = 0; j < 16; ++j)
         state[j] = inv_s[state[j]];
@@ -283,8 +305,10 @@ var AES128Cipher = (function() {
         state[j] ^= key[k];
       // InvMixColumns
       for (j = 0; j < 16; j += 4) {
-        var s0 = mix[state[j]], s1 = mix[state[j + 1]], s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
-        t = s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^ (s3 >>> 24) ^ (s3 << 8);
+        var s0 = mix[state[j]], s1 = mix[state[j + 1]],
+            s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
+        t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^
+            (s3 >>> 24) ^ (s3 << 8));
         state[j] = (t >>> 24) & 0xFF;
         state[j + 1] = (t >> 16) & 0xFF;
         state[j + 2] = (t >> 8) & 0xFF;
@@ -292,9 +316,12 @@ var AES128Cipher = (function() {
       }
     }
     // InvShiftRows
-    t = state[13]; state[13] = state[9]; state[9] = state[5]; state[5] = state[1]; state[1] = t;
-    t = state[14]; u = state[10]; state[14] = state[6]; state[10] = state[2]; state[6] = t; state[2] = u;
-    t = state[15]; u = state[11]; v = state[7]; state[15] = state[3]; state[11] = t; state[7] = u; state[3] = v;
+    t = state[13]; state[13] = state[9]; state[9] = state[5];
+    state[5] = state[1]; state[1] = t;
+    t = state[14]; u = state[10]; state[14] = state[6];
+    state[10] = state[2]; state[6] = t; state[2] = u;
+    t = state[15]; u = state[11]; v = state[7]; state[15] = state[3];
+    state[11] = t; state[7] = u; state[3] = v;
     // InvSubBytes
     for (j = 0; j < 16; ++j)
       state[j] = inv_s[state[j]];
@@ -311,9 +338,9 @@ var AES128Cipher = (function() {
   }
 
   function decryptBlock2(data) {
-    var i, j, sourceLength = data.length;
-    var buffer = this.buffer, bufferLength = this.bufferPosition, iv = this.iv;
-    var result = [];
+    var i, j, sourceLength = data.length,
+        buffer = this.buffer, bufferLength = this.bufferPosition,
+        result = [], iv = this.iv;
     for (i = 0; i < sourceLength; ++i) {
       buffer[bufferLength] = data[i];
       ++bufferLength;
@@ -481,7 +508,8 @@ var CipherTransformFactory = (function() {
     var userPassword = stringToBytes(dict.get('U'));
     var flags = dict.get('P');
     var revision = dict.get('R');
-    var encryptMetadata = dict.get('EncryptMetadata') !== false; // makes true as default value
+    var encryptMetadata =
+      dict.get('EncryptMetadata') !== false; // makes true as default value
     var fileIdBytes = stringToBytes(fileId);
     var passwordBytes;
     if (password)
@@ -489,7 +517,8 @@ var CipherTransformFactory = (function() {
 
     this.encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
                                         ownerPassword, userPassword,
-                                        flags, revision, keyLength, encryptMetadata);
+                                        flags, revision,
+                                        keyLength, encryptMetadata);
     if (algorithm == 4) {
       this.cf = dict.get('CF');
       this.stmf = dict.get('StmF') || identityName;
@@ -539,14 +568,17 @@ var CipherTransformFactory = (function() {
           buildObjectKey(num, gen, key, true));
       };
     }
+    error('Unknown crypto method');
   }
 
   constructor.prototype = {
     createCipherTransform: function(num, gen) {
       if (this.algorithm == 4) {
         return new CipherTransform(
-          buildCipherConstructor(this.cf, this.stmf, num, gen, this.encryptionKey),
-          buildCipherConstructor(this.cf, this.strf, num, gen, this.encryptionKey));
+          buildCipherConstructor(this.cf, this.stmf,
+            num, gen, this.encryptionKey),
+          buildCipherConstructor(this.cf, this.strf,
+            num, gen, this.encryptionKey));
       }
       // algorithms 1 and 2
       var key = buildObjectKey(num, gen, this.encryptionKey, false);