From 048e40b869ac075b8b3118fe08e6aa227fb91c30 Mon Sep 17 00:00:00 2001
From: Artur Adib <arturadib@gmail.com>
Date: Tue, 14 Feb 2012 14:48:58 -0500
Subject: [PATCH 1/4] Fixes #1155

---
 src/core.js | 28 ++++++++++++++++++---------
 src/util.js | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 9 deletions(-)

diff --git a/src/core.js b/src/core.js
index ae0f97231..9a8f516d7 100644
--- a/src/core.js
+++ b/src/core.js
@@ -104,23 +104,33 @@ var Page = (function PageClosure() {
       return shadow(this, 'mediaBox', obj);
     },
     get view() {
-      var obj = this.inheritPageProp('CropBox');
+      var cropBox = this.inheritPageProp('CropBox');
       var view = {
         x: 0,
         y: 0,
         width: this.width,
         height: this.height
       };
+      if (!isArray(cropBox) || cropBox.length !== 4)
+        return shadow(this, 'cropBox', view);
+
       var mediaBox = this.mediaBox;
       var offsetX = mediaBox[0], offsetY = mediaBox[1];
-      if (isArray(obj) && obj.length == 4) {
-        var tl = this.rotatePoint(obj[0] - offsetX, obj[1] - offsetY);
-        var br = this.rotatePoint(obj[2] - offsetX, obj[3] - offsetY);
-        view.x = Math.min(tl.x, br.x);
-        view.y = Math.min(tl.y, br.y);
-        view.width = Math.abs(tl.x - br.x);
-        view.height = Math.abs(tl.y - br.y);
-      }
+
+      // From the spec, 6th ed., p.963:
+      // "The crop, bleed, trim, and art boxes should not ordinarily
+      // extend beyond the boundaries of the media box. If they do, they are
+      // effectively reduced to their intersection with the media box."
+      cropBox = Util.intersect(cropBox, mediaBox);
+      if (!cropBox)
+        return shadow(this, 'cropBox', view);
+
+      var tl = this.rotatePoint(cropBox[0] - offsetX, cropBox[1] - offsetY);
+      var br = this.rotatePoint(cropBox[2] - offsetX, cropBox[3] - offsetY);
+      view.x = Math.min(tl.x, br.x);
+      view.y = Math.min(tl.y, br.y);
+      view.width = Math.abs(tl.x - br.x);
+      view.height = Math.abs(tl.y - br.y);
 
       return shadow(this, 'cropBox', view);
     },
diff --git a/src/util.js b/src/util.js
index f00fcd1ce..93bd36b55 100644
--- a/src/util.js
+++ b/src/util.js
@@ -111,6 +111,62 @@ var Util = (function UtilClosure() {
     ];
   }
 
+  // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
+  // For coordinate systems whose origin lies in the bottom-left, this
+  // means normalization to (BL,TR) ordering. For systems with origin in the
+  // top-left, this means (TL,BR) ordering.
+  Util.normalizeRect = function normalizeRect(rect) {
+    var r = rect.slice(0); // clone rect
+    if (rect[0] > rect[2]) {
+      r[0] = rect[2];
+      r[2] = rect[0];
+    }
+    if (rect[1] > rect[3]) {
+      r[1] = rect[3];
+      r[3] = rect[1];
+    }
+    return r;
+  }
+
+  // Returns a rectangle [x1, y1, x2, y2] corresponding to the
+  // intersection of rect1 and rect2. If no intersection, returns 'false'
+  // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
+  Util.intersect = function intersect(rect1, rect2) {
+    function compare(a, b) {
+      return a - b;
+    };
+
+    // Order points along the axes
+    var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
+        orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
+        result = [];
+
+    rect1 = Util.normalizeRect(rect1);
+    rect2 = Util.normalizeRect(rect2);
+
+    // X: first and second points belong to different rectangles?
+    if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
+        (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
+      // Intersection must be between second and third points
+      result[0] = orderedX[1];
+      result[2] = orderedX[2];
+    } else {
+      return false;
+    }
+
+    // Y: first and second points belong to different rectangles?
+    if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
+        (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
+      // Intersection must be between second and third points
+      result[1] = orderedY[1];
+      result[3] = orderedY[2];
+    } else {
+      return false;
+    }
+
+    return result;
+  }
+
   Util.sign = function sign(num) {
     return num < 0 ? -1 : 1;
   };

From f1dfe880e8651b88df7aa567acfc1fce34d3e852 Mon Sep 17 00:00:00 2001
From: Artur Adib <arturadib@gmail.com>
Date: Tue, 14 Feb 2012 14:55:39 -0500
Subject: [PATCH 2/4] Adding regression test

---
 test/issue1155.pdf.link | 1 +
 test/test_manifest.json | 7 +++++++
 2 files changed, 8 insertions(+)
 create mode 100644 test/issue1155.pdf.link

diff --git a/test/issue1155.pdf.link b/test/issue1155.pdf.link
new file mode 100644
index 000000000..13df4e035
--- /dev/null
+++ b/test/issue1155.pdf.link
@@ -0,0 +1 @@
+http://www.madbad.altervista.org/_altervista_ht/2142.pdf
diff --git a/test/test_manifest.json b/test/test_manifest.json
index 3a1b5bd70..6ed413970 100644
--- a/test/test_manifest.json
+++ b/test/test_manifest.json
@@ -458,5 +458,12 @@
       "rounds": 1,
       "link": true,
       "type": "eq"
+    },
+    {  "id": "issue1155",
+      "file": "pdfs/issue1155.pdf",
+      "md5": "b732ef25c16c9c20a77e40edef5aa6fe",
+      "rounds": 1,
+      "link": true,
+      "type": "eq"
     }
 ]

From db5f43be46982e65d8c78b816dde1451da51b959 Mon Sep 17 00:00:00 2001
From: Artur Adib <arturadib@gmail.com>
Date: Tue, 14 Feb 2012 15:00:43 -0500
Subject: [PATCH 3/4] oops

---
 test/{ => pdfs}/issue1155.pdf.link | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename test/{ => pdfs}/issue1155.pdf.link (100%)

diff --git a/test/issue1155.pdf.link b/test/pdfs/issue1155.pdf.link
similarity index 100%
rename from test/issue1155.pdf.link
rename to test/pdfs/issue1155.pdf.link

From 9cf9c3622729eb85377cf94b484d832fe6311e2b Mon Sep 17 00:00:00 2001
From: Artur Adib <arturadib@gmail.com>
Date: Thu, 16 Feb 2012 12:02:18 -0500
Subject: [PATCH 4/4] Addressing reviewer comments

---
 src/core.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/core.js b/src/core.js
index 9a8f516d7..137452257 100644
--- a/src/core.js
+++ b/src/core.js
@@ -112,7 +112,7 @@ var Page = (function PageClosure() {
         height: this.height
       };
       if (!isArray(cropBox) || cropBox.length !== 4)
-        return shadow(this, 'cropBox', view);
+        return shadow(this, 'view', view);
 
       var mediaBox = this.mediaBox;
       var offsetX = mediaBox[0], offsetY = mediaBox[1];
@@ -123,7 +123,7 @@ var Page = (function PageClosure() {
       // effectively reduced to their intersection with the media box."
       cropBox = Util.intersect(cropBox, mediaBox);
       if (!cropBox)
-        return shadow(this, 'cropBox', view);
+        return shadow(this, 'view', view);
 
       var tl = this.rotatePoint(cropBox[0] - offsetX, cropBox[1] - offsetY);
       var br = this.rotatePoint(cropBox[2] - offsetX, cropBox[3] - offsetY);
@@ -132,7 +132,7 @@ var Page = (function PageClosure() {
       view.width = Math.abs(tl.x - br.x);
       view.height = Math.abs(tl.y - br.y);
 
-      return shadow(this, 'cropBox', view);
+      return shadow(this, 'view', view);
     },
     get annotations() {
       return shadow(this, 'annotations', this.inheritPageProp('Annots'));