Isolate Playback of SkPictures that we encoded with an older version of Skia.

There are companion changes to this in...
  external/skia
  frameworks/base

bug: 8019756
Change-Id: Ib6e015a1b0c04d1429f60929879c9f1687d51afe
diff --git a/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h b/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h
index ac838c8..5b22488 100644
--- a/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h
+++ b/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h
@@ -134,7 +134,7 @@
 
     // ViewStateSerializer friends
     friend void android::serializeLayer(LayerAndroid* layer, SkWStream* stream);
-    friend LayerAndroid* android::deserializeLayer(int version, SkStream* stream);
+    friend LayerAndroid* android::deserializeLayer(int version, SkMemoryStream* stream);
 
 protected:
     LayerAndroid* m_layer;
diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h
index 6c2e43d..dc844b3 100644
--- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h
@@ -58,7 +58,7 @@
 namespace android {
 class DrawExtra;
 void serializeLayer(WebCore::LayerAndroid* layer, SkWStream* stream);
-WebCore::LayerAndroid* deserializeLayer(int version, SkStream* stream);
+WebCore::LayerAndroid* deserializeLayer(int version, SkMemoryStream* stream);
 void cleanupImageRefs(WebCore::LayerAndroid* layer);
 }
 
@@ -256,7 +256,7 @@
 
     // ViewStateSerializer friends
     friend void android::serializeLayer(LayerAndroid* layer, SkWStream* stream);
-    friend LayerAndroid* android::deserializeLayer(int version, SkStream* stream);
+    friend LayerAndroid* android::deserializeLayer(int version, SkMemoryStream* stream);
     friend void android::cleanupImageRefs(LayerAndroid* layer);
 
     LayerType type() { return m_type; }
diff --git a/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.cpp
index bfd477e..f0e4292 100644
--- a/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.cpp
+++ b/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.cpp
@@ -8,6 +8,9 @@
 #include "InspectorCanvas.h"
 #include "SkPicture.h"
 
+#include <dlfcn.h>
+#include "SkDevice.h"
+
 namespace WebCore {
 
 PictureLayerContent::PictureLayerContent(SkPicture* picture)
@@ -98,4 +101,71 @@
     m_picture->serialize(stream);
 }
 
+
+LegacyPictureLayerContent::LegacyPictureLayerContent(SkMemoryStream* pictureStream) {
+    m_legacyPicture = NULL;
+    m_width = 0;
+    m_height = 0;
+
+    // load legacy skia lib (all functions hidden except ones defined below)
+    m_legacyLib = dlopen("libskia_legacy.so", RTLD_LAZY);
+    *reinterpret_cast<void**>(&m_createPictureProc) = dlsym(m_legacyLib, "legacy_skia_create_picture");
+    *reinterpret_cast<void**>(&m_deletePictureProc) = dlsym(m_legacyLib, "legacy_skia_delete_picture");
+    *reinterpret_cast<void**>(&m_drawPictureProc) = dlsym(m_legacyLib, "legacy_skia_draw_picture");
+
+    const char* error = dlerror();
+    if (error) {
+      SkDebugf("Unable to load legacy lib: %s", error);
+      sk_throw();
+    }
+
+    // call into library to create picture and set width and height
+    const int streamLength = pictureStream->getLength() - pictureStream->peek();
+    int bytesRead = m_createPictureProc(pictureStream->getAtPos(), streamLength,
+                                        &m_legacyPicture, &m_width, &m_height);
+    pictureStream->skip(bytesRead);
+}
+
+LegacyPictureLayerContent::~LegacyPictureLayerContent() {
+    if (m_legacyLib) {
+        if (m_legacyPicture) {
+          m_deletePictureProc(m_legacyPicture);
+        }
+        dlclose(m_legacyLib);
+    }
+}
+
+void LegacyPictureLayerContent::draw(SkCanvas* canvas) {
+    if (!m_legacyPicture) {
+      return;
+    }
+
+    // if this is an InspectorCanvas we need to at least draw something to
+    // ensure that the canvas is not discarded. (We perform a no-op text
+    // draw in order to trigger the InspectorCanvas into performing high
+    // fidelity rendering while zooming.
+    SkPaint paint;
+    canvas->drawText(NULL, 0, 0, 0, paint);
+
+    // decompose the canvas into basics
+    void* matrixStorage = malloc(canvas->getTotalMatrix().flatten(NULL));
+    void* clipStorage = malloc(canvas->getTotalClip().flatten(NULL));
+
+    canvas->getTotalMatrix().flatten(matrixStorage);
+    canvas->getTotalClip().flatten(clipStorage);
+
+    const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true);
+    bitmap.lockPixels();
+
+    // pass picture, matrix, clip, and bitmap
+    m_drawPictureProc(m_legacyPicture, matrixStorage, clipStorage,
+                      bitmap.width(), bitmap.height(), bitmap.getConfig(),
+                      bitmap.rowBytes(), bitmap.getPixels());
+
+
+    bitmap.unlockPixels();
+    free(matrixStorage);
+    free(clipStorage);
+}
+
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.h b/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.h
index e5181a5..bb004f2 100644
--- a/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.h
+++ b/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.h
@@ -27,6 +27,7 @@
 #define PictureLayerContent_h
 
 #include "LayerContent.h"
+#include "SkStream.h"
 
 namespace WebCore {
 
@@ -50,6 +51,34 @@
     bool m_hasText;
 };
 
+class LegacyPictureLayerContent : public LayerContent {
+public:
+    LegacyPictureLayerContent(SkMemoryStream* pictureStream);
+    ~LegacyPictureLayerContent();
+
+    virtual int width() { return m_width; }
+    virtual int height() { return m_height; }
+    virtual void setCheckForOptimisations(bool check) {}
+    virtual void checkForOptimisations() {}
+    virtual float maxZoomScale() { return 1e6; }
+    virtual void draw(SkCanvas* canvas);
+    virtual void serialize(SkWStream* stream) { }
+
+private:
+    void* m_legacyLib;
+    void* m_legacyPicture;
+    int m_width;
+    int m_height;
+
+    typedef int  (*legacy_skia_create_picture_proc)(const void*, int, void**, int*, int*);
+    typedef void (*legacy_skia_delete_picture_proc)(void*);
+    typedef void (*legacy_skia_draw_picture_proc)(void*, void*, void*, int, int, int, int, void*);
+
+    legacy_skia_create_picture_proc m_createPictureProc;
+    legacy_skia_delete_picture_proc m_deletePictureProc;
+    legacy_skia_draw_picture_proc m_drawPictureProc;
+};
+
 } // WebCore
 
 #endif // PictureLayerContent_h
diff --git a/Source/WebCore/platform/graphics/android/layers/ScrollableLayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/ScrollableLayerAndroid.h
index b3c828f..4f76274 100644
--- a/Source/WebCore/platform/graphics/android/layers/ScrollableLayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/layers/ScrollableLayerAndroid.h
@@ -64,7 +64,7 @@
     bool scrollRectIntoView(const SkIRect&);
 
     friend void android::serializeLayer(LayerAndroid* layer, SkWStream* stream);
-    friend LayerAndroid* android::deserializeLayer(int version, SkStream* stream);
+    friend LayerAndroid* android::deserializeLayer(int version, SkMemoryStream* stream);
 
 protected:
 
diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp
index 8963837..1aec3ef 100644
--- a/Source/WebKit/android/jni/ViewStateSerializer.cpp
+++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp
@@ -152,12 +152,40 @@
 static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jint version,
                                                     jobject jstream, jbyteArray jstorage)
 {
-    SkStream* stream = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
-    if (!stream)
+    SkStream* javaStream = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
+    if (!javaStream)
         return 0;
-    Color color = stream->readU32();
-    SkPicture* picture = new SkPicture(stream);
-    PictureLayerContent* content = new PictureLayerContent(picture);
+
+    // read everything into memory so that we can get the offset into the stream
+    // when necessary. This is needed for the LegacyPictureLayerContent.
+    SkDynamicMemoryWStream tempStream;
+    const int bufferSize = 256*1024; // 256KB
+    uint8_t buffer[bufferSize];
+    int bytesRead = 0;
+
+    do {
+      bytesRead = javaStream->read(buffer, bufferSize);
+      tempStream.write(buffer, bytesRead);
+    } while (bytesRead != 0);
+
+    SkMemoryStream stream;
+    stream.setData(tempStream.copyToData())->unref();
+
+    // clean up the javaStream now that we have everything in memory
+    delete javaStream;
+
+    Color color = stream.readU32();
+
+
+
+    LayerContent* content;
+    if (version == 1) {
+        content = new LegacyPictureLayerContent(&stream);
+    } else {
+        SkPicture* picture = new SkPicture(&stream);
+        content = new PictureLayerContent(picture);
+        SkSafeUnref(picture);
+    }
 
     BaseLayerAndroid* layer = new BaseLayerAndroid(content);
     layer->setBackgroundColor(color);
@@ -167,14 +195,12 @@
     layer->markAsDirty(dirtyRegion);
 
     SkSafeUnref(content);
-    SkSafeUnref(picture);
-    int childCount = stream->readS32();
+    int childCount = stream.readS32();
     for (int i = 0; i < childCount; i++) {
-        LayerAndroid* childLayer = deserializeLayer(version, stream);
+        LayerAndroid* childLayer = deserializeLayer(version, &stream);
         if (childLayer)
             layer->addChild(childLayer);
     }
-    delete stream;
     return layer;
 }
 
@@ -413,7 +439,7 @@
         serializeLayer(layer->getChild(i), stream);
 }
 
-LayerAndroid* deserializeLayer(int version, SkStream* stream)
+LayerAndroid* deserializeLayer(int version, SkMemoryStream* stream)
 {
     int type = stream->readU8();
     if (type == LTNone)
@@ -509,11 +535,16 @@
     }
     bool hasRecordingPicture = stream->readBool();
     if (hasRecordingPicture) {
-        SkPicture* picture = new SkPicture(stream);
-        PictureLayerContent* content = new PictureLayerContent(picture);
+      LayerContent* content;
+        if (version == 1) {
+            content = new LegacyPictureLayerContent(stream);
+        } else {
+            SkPicture* picture = new SkPicture(stream);
+            content = new PictureLayerContent(picture);
+            SkSafeUnref(picture);
+        }
         layer->setContent(content);
         SkSafeUnref(content);
-        SkSafeUnref(picture);
     }
     int animationCount = stream->readU32(); // TODO: Support (maybe?)
     readTransformationMatrix(stream, layer->m_transform);