Do JPEG tile-based decoding.

Change-Id: I5c1b4ac3c02eb4350ef0ba9a7877b22cfd730cfb
diff --git a/core/jni/android/graphics/AutoDecodeCancel.cpp b/core/jni/android/graphics/AutoDecodeCancel.cpp
new file mode 100644
index 0000000..f0739ea
--- /dev/null
+++ b/core/jni/android/graphics/AutoDecodeCancel.cpp
@@ -0,0 +1,100 @@
+#include "AutoDecodeCancel.h"
+
+static SkMutex  gAutoDecoderCancelMutex;
+static AutoDecoderCancel* gAutoDecoderCancel;
+#ifdef SK_DEBUG
+static int gAutoDecoderCancelCount;
+#endif
+
+AutoDecoderCancel::AutoDecoderCancel(jobject joptions,
+                                       SkImageDecoder* decoder) {
+    fJOptions = joptions;
+    fDecoder = decoder;
+
+    if (NULL != joptions) {
+        SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
+
+        // Add us as the head of the list
+        fPrev = NULL;
+        fNext = gAutoDecoderCancel;
+        if (gAutoDecoderCancel) {
+            gAutoDecoderCancel->fPrev = this;
+        }
+        gAutoDecoderCancel = this;
+
+        SkDEBUGCODE(gAutoDecoderCancelCount += 1;)
+        Validate();
+    }
+}
+
+AutoDecoderCancel::~AutoDecoderCancel() {
+    if (NULL != fJOptions) {
+        SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
+
+        // take us out of the dllist
+        AutoDecoderCancel* prev = fPrev;
+        AutoDecoderCancel* next = fNext;
+
+        if (prev) {
+            SkASSERT(prev->fNext == this);
+            prev->fNext = next;
+        } else {
+            SkASSERT(gAutoDecoderCancel == this);
+            gAutoDecoderCancel = next;
+        }
+        if (next) {
+            SkASSERT(next->fPrev == this);
+            next->fPrev = prev;
+        }
+
+        SkDEBUGCODE(gAutoDecoderCancelCount -= 1;)
+        Validate();
+    }
+}
+
+bool AutoDecoderCancel::RequestCancel(jobject joptions) {
+    SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
+
+    Validate();
+
+    AutoDecoderCancel* pair = gAutoDecoderCancel;
+    while (pair != NULL) {
+        if (pair->fJOptions == joptions) {
+            pair->fDecoder->cancelDecode();
+            return true;
+        }
+        pair = pair->fNext;
+    }
+    return false;
+}
+
+#ifdef SK_DEBUG
+// can only call this inside a lock on gAutoDecoderCancelMutex
+void AutoDecoderCancel::Validate() {
+    const int gCount = gAutoDecoderCancelCount;
+
+    if (gCount == 0) {
+        SkASSERT(gAutoDecoderCancel == NULL);
+    } else {
+        SkASSERT(gCount > 0);
+
+        AutoDecoderCancel* curr = gAutoDecoderCancel;
+        SkASSERT(curr);
+        SkASSERT(curr->fPrev == NULL);
+
+        int count = 0;
+        while (curr) {
+            count += 1;
+            SkASSERT(count <= gCount);
+            if (curr->fPrev) {
+                SkASSERT(curr->fPrev->fNext == curr);
+            }
+            if (curr->fNext) {
+                SkASSERT(curr->fNext->fPrev == curr);
+            }
+            curr = curr->fNext;
+        }
+        SkASSERT(count == gCount);
+    }
+}
+#endif