Merge "Changes to framework for ToT Skia."
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index de46804..15dfed1 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -89,6 +89,7 @@
 	android_util_Process.cpp \
 	android_util_StringBlock.cpp \
 	android_util_XmlBlock.cpp \
+	android/graphics/AndroidPicture.cpp \
 	android/graphics/AutoDecodeCancel.cpp \
 	android/graphics/Bitmap.cpp \
 	android/graphics/BitmapFactory.cpp \
diff --git a/core/jni/android/graphics/AndroidPicture.cpp b/core/jni/android/graphics/AndroidPicture.cpp
new file mode 100644
index 0000000..5977ab2
--- /dev/null
+++ b/core/jni/android/graphics/AndroidPicture.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AndroidPicture.h"
+#include "SkCanvas.h"
+#include "SkStream.h"
+
+AndroidPicture::AndroidPicture(const AndroidPicture* src) {
+    if (NULL != src) {
+        mWidth = src->width();
+        mHeight = src->height();
+        if (NULL != src->mPicture.get()) {
+            mPicture.reset(SkRef(src->mPicture.get()));
+        } if (NULL != src->mRecorder.get()) {
+            mPicture.reset(src->makePartialCopy());
+        }
+    } else {
+        mWidth = 0;
+        mHeight = 0;
+    }
+}
+
+SkCanvas* AndroidPicture::beginRecording(int width, int height) {
+    mPicture.reset(NULL);
+    mRecorder.reset(new SkPictureRecorder);
+    mWidth = width;
+    mHeight = height;
+    return mRecorder->beginRecording(width, height, NULL, 0);
+}
+
+void AndroidPicture::endRecording() {
+    if (NULL != mRecorder.get()) {
+        mPicture.reset(mRecorder->endRecording());
+        mRecorder.reset(NULL);
+    }
+}
+
+int AndroidPicture::width() const {
+    if (NULL != mPicture.get()) {
+        SkASSERT(mPicture->width() == mWidth);
+        SkASSERT(mPicture->height() == mHeight);
+    }
+
+    return mWidth;
+}
+
+int AndroidPicture::height() const {
+    if (NULL != mPicture.get()) {
+        SkASSERT(mPicture->width() == mWidth);
+        SkASSERT(mPicture->height() == mHeight);
+    }
+
+    return mHeight;
+}
+
+AndroidPicture* AndroidPicture::CreateFromStream(SkStream* stream) {
+    AndroidPicture* newPict = new AndroidPicture;
+
+    newPict->mPicture.reset(SkPicture::CreateFromStream(stream));
+    if (NULL != newPict->mPicture.get()) {
+        newPict->mWidth = newPict->mPicture->width();
+        newPict->mHeight = newPict->mPicture->height();
+    }
+
+    return newPict;
+}
+
+void AndroidPicture::serialize(SkWStream* stream) const {
+    if (NULL != mRecorder.get()) {
+        SkAutoTDelete<SkPicture> tempPict(this->makePartialCopy());
+        tempPict->serialize(stream);
+    } else if (NULL != mPicture.get()) {
+        mPicture->serialize(stream);
+    } else {
+        SkPicture empty;
+        empty.serialize(stream);
+    }
+}
+
+void AndroidPicture::draw(SkCanvas* canvas) {
+    if (NULL != mRecorder.get()) {
+        this->endRecording();
+        SkASSERT(NULL != mPicture.get());
+    }
+    if (NULL != mPicture.get()) {
+        // TODO: remove this const_cast once pictures are immutable
+        const_cast<SkPicture*>(mPicture.get())->draw(canvas);
+    }
+}
+
+SkPicture* AndroidPicture::makePartialCopy() const {
+    SkASSERT(NULL != mRecorder.get());
+
+    SkPictureRecorder reRecorder;
+
+    SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight, NULL, 0);
+    mRecorder->partialReplay(canvas);
+    return reRecorder.endRecording();
+}
diff --git a/core/jni/android/graphics/AndroidPicture.h b/core/jni/android/graphics/AndroidPicture.h
new file mode 100644
index 0000000..f434941
--- /dev/null
+++ b/core/jni/android/graphics/AndroidPicture.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PICTURE_H
+#define ANDROID_PICTURE_H
+
+#include "SkPicture.h"
+#include "SkPictureRecorder.h"
+#include "SkRefCnt.h"
+#include "SkTemplates.h"
+
+class SkCanvas;
+class SkPicture;
+class SkPictureRecorder;
+class SkStream;
+class SkWStream;
+
+// Skia's SkPicture class has been split into an SkPictureRecorder
+// and an SkPicture. AndroidPicture recreates the functionality
+// of the old SkPicture interface by flip-flopping between the two
+// new classes.
+class AndroidPicture {
+public:
+    explicit AndroidPicture(const AndroidPicture* src = NULL);
+
+    SkCanvas* beginRecording(int width, int height);
+
+    void endRecording();
+
+    int width() const;
+
+    int height() const;
+
+    static AndroidPicture* CreateFromStream(SkStream* stream);
+
+    void serialize(SkWStream* stream) const;
+
+    void draw(SkCanvas* canvas);
+
+private:
+    int mWidth;
+    int mHeight;
+    SkAutoTUnref<const SkPicture> mPicture;
+    SkAutoTDelete<SkPictureRecorder> mRecorder;
+
+    // Make a copy of a picture that is in the midst of being recorded. The
+    // resulting picture will have balanced saves and restores.
+    SkPicture* makePartialCopy() const;
+};
+#endif // ANDROID_PICTURE_H
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 64ad223..a4337ccc 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -3,6 +3,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "GraphicsJNI.h"
+#include "AndroidPicture.h"
 
 #include "SkCanvas.h"
 #include "SkDevice.h"
@@ -345,13 +346,13 @@
     return p;
 }
 
-SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
+AndroidPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
 {
     SkASSERT(env);
     SkASSERT(picture);
     SkASSERT(env->IsInstanceOf(picture, gPicture_class));
     jlong pictureHandle = env->GetLongField(picture, gPicture_nativeInstanceID);
-    SkPicture* p = reinterpret_cast<SkPicture*>(pictureHandle);
+    AndroidPicture* p = reinterpret_cast<AndroidPicture*>(pictureHandle);
     SkASSERT(p);
     return p;
 }
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 73dd11b..2e2f920 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -14,7 +14,7 @@
 class SkBitmapRegionDecoder;
 class SkCanvas;
 class SkPaint;
-class SkPicture;
+class AndroidPicture;
 
 class GraphicsJNI {
 public:
@@ -50,7 +50,7 @@
     static SkPaint*  getNativePaint(JNIEnv*, jobject paint);
     static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint);
     static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
-    static SkPicture* getNativePicture(JNIEnv*, jobject picture);
+    static AndroidPicture* getNativePicture(JNIEnv*, jobject picture);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
     // Given the 'native' long held by the Rasterizer.java object, return a
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index a8a3dae..0683f73 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -17,9 +17,9 @@
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
+#include "AndroidPicture.h"
 
 #include "SkCanvas.h"
-#include "SkPicture.h"
 #include "SkStream.h"
 #include "SkTemplates.h"
 #include "CreateJavaOutputStreamAdaptor.h"
@@ -29,45 +29,41 @@
 class SkPictureGlue {
 public:
     static jlong newPicture(JNIEnv* env, jobject, jlong srcHandle) {
-        const SkPicture* src = reinterpret_cast<SkPicture*>(srcHandle);
-        if (src) {
-            return reinterpret_cast<jlong>(new SkPicture(*src));
-        } else {
-            return reinterpret_cast<jlong>(new SkPicture);
-        }
+        const AndroidPicture* src = reinterpret_cast<AndroidPicture*>(srcHandle);
+        return reinterpret_cast<jlong>(new AndroidPicture(src));
     }
 
     static jlong deserialize(JNIEnv* env, jobject, jobject jstream,
                              jbyteArray jstorage) {
-        SkPicture* picture = NULL;
+        AndroidPicture* picture = NULL;
         SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
         if (strm) {
-            picture = SkPicture::CreateFromStream(strm);
+            picture = AndroidPicture::CreateFromStream(strm);
             delete strm;
         }
         return reinterpret_cast<jlong>(picture);
     }
 
     static void killPicture(JNIEnv* env, jobject, jlong pictureHandle) {
-        SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+        AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
         SkASSERT(picture);
-        picture->unref();
+        delete picture;
     }
 
     static void draw(JNIEnv* env, jobject, jlong canvasHandle,
                             jlong pictureHandle) {
         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle);
-        SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+        AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
         SkASSERT(canvas);
         SkASSERT(picture);
         picture->draw(canvas);
     }
 
     static jboolean serialize(JNIEnv* env, jobject, jlong pictureHandle,
-                          jobject jstream, jbyteArray jstorage) {
-        SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+                              jobject jstream, jbyteArray jstorage) {
+        AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
         SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
-        
+
         if (NULL != strm) {
             picture->serialize(strm);
             delete strm;
@@ -78,19 +74,21 @@
 
     static jint getWidth(JNIEnv* env, jobject jpic) {
         NPE_CHECK_RETURN_ZERO(env, jpic);
-        int width = GraphicsJNI::getNativePicture(env, jpic)->width();
+        AndroidPicture* pict = GraphicsJNI::getNativePicture(env, jpic);
+        int width = pict->width();
         return static_cast<jint>(width);
     }
 
     static jint getHeight(JNIEnv* env, jobject jpic) {
         NPE_CHECK_RETURN_ZERO(env, jpic);
-        int height = GraphicsJNI::getNativePicture(env, jpic)->height();
+        AndroidPicture* pict = GraphicsJNI::getNativePicture(env, jpic);
+        int height = pict->height();
         return static_cast<jint>(height);
     }
 
     static jlong beginRecording(JNIEnv* env, jobject, jlong pictHandle,
-                                    jint w, jint h) {
-        SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle);
+                                jint w, jint h) {
+        AndroidPicture* pict = reinterpret_cast<AndroidPicture*>(pictHandle);
         // beginRecording does not ref its return value, it just returns it.
         SkCanvas* canvas = pict->beginRecording(w, h);
         // the java side will wrap this guy in a Canvas.java, which will call
@@ -101,7 +99,7 @@
     }
 
     static void endRecording(JNIEnv* env, jobject, jlong pictHandle) {
-        SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle);
+        AndroidPicture* pict = reinterpret_cast<AndroidPicture*>(pictHandle);
         pict->endRecording();
     }
 };
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index d54aaa8..3812c27 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -24,6 +24,7 @@
 #include "SkCanvas.h"
 #include "SkDocument.h"
 #include "SkPicture.h"
+#include "SkPictureRecorder.h"
 #include "SkStream.h"
 #include "SkRect.h"
 
@@ -32,15 +33,22 @@
 struct PageRecord {
 
     PageRecord(int width, int height, const SkRect& contentRect)
-            : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
+            : mPictureRecorder(new SkPictureRecorder())
+            , mPicture(NULL)
+            , mWidth(width)
+            , mHeight(height) {
         mContentRect = contentRect;
     }
 
     ~PageRecord() {
-        mPicture->unref();
+        delete mPictureRecorder;
+        if (NULL != mPicture) {
+            mPicture->unref();
+        }
     }
 
-    SkPicture* const mPicture;
+    SkPictureRecorder* mPictureRecorder;
+    SkPicture* mPicture;
     const int mWidth;
     const int mHeight;
     SkRect mContentRect;
@@ -62,8 +70,8 @@
         mPages.push_back(page);
         mCurrentPage = page;
 
-        SkCanvas* canvas = page->mPicture->beginRecording(
-                contentRect.width(), contentRect.height(), 0);
+        SkCanvas* canvas = page->mPictureRecorder->beginRecording(
+                contentRect.width(), contentRect.height(), NULL, 0);
 
         // We pass this canvas to Java where it is used to construct
         // a Java Canvas object which dereferences the pointer when it
@@ -75,7 +83,11 @@
 
     void finishPage() {
         assert(mCurrentPage != NULL);
-        mCurrentPage->mPicture->endRecording();
+        assert(mCurrentPage->mPictureRecorder != NULL);
+        assert(mCurrentPage->mPicture == NULL);
+        mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording();
+        delete mCurrentPage->mPictureRecorder;
+        mCurrentPage->mPictureRecorder = NULL;
         mCurrentPage = NULL;
     }
 
@@ -89,7 +101,7 @@
 
             canvas->clipRect(page->mContentRect);
             canvas->translate(page->mContentRect.left(), page->mContentRect.top());
-            canvas->drawPicture(*page->mPicture);
+            canvas->drawPicture(page->mPicture);
 
             document->endPage();
         }
@@ -97,11 +109,10 @@
     }
 
     void close() {
+        assert(NULL == mCurrentPage);
         for (unsigned i = 0; i < mPages.size(); i++) {
             delete mPages[i];
         }
-        delete mCurrentPage;
-        mCurrentPage = NULL;
     }
 
 private: