diff --git a/core/jni/Android.mk b/core/jni/Android.mk index de468045fce34..15dfed1bc76bc 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -89,6 +89,7 @@ LOCAL_SRC_FILES:= \ 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 0000000000000..5977ab263a994 --- /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 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(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 0000000000000..f434941c4381f --- /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 mPicture; + SkAutoTDelete 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 64ad22309609b..a4337cccbcb5b 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 @@ android::TypefaceImpl* GraphicsJNI::getNativeTypeface(JNIEnv* env, jobject paint 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(pictureHandle); + AndroidPicture* p = reinterpret_cast(pictureHandle); SkASSERT(p); return p; } diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 73dd11bb0788c..2e2f920eb3389 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 @@ public: 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 a8a3daed224e5..0683f7386de87 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 +#include "AndroidPicture.h" #include "SkCanvas.h" -#include "SkPicture.h" #include "SkStream.h" #include "SkTemplates.h" #include "CreateJavaOutputStreamAdaptor.h" @@ -29,45 +29,41 @@ namespace android { class SkPictureGlue { public: static jlong newPicture(JNIEnv* env, jobject, jlong srcHandle) { - const SkPicture* src = reinterpret_cast(srcHandle); - if (src) { - return reinterpret_cast(new SkPicture(*src)); - } else { - return reinterpret_cast(new SkPicture); - } + const AndroidPicture* src = reinterpret_cast(srcHandle); + return reinterpret_cast(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(picture); } static void killPicture(JNIEnv* env, jobject, jlong pictureHandle) { - SkPicture* picture = reinterpret_cast(pictureHandle); + AndroidPicture* picture = reinterpret_cast(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(pictureHandle); + AndroidPicture* picture = reinterpret_cast(pictureHandle); SkASSERT(canvas); SkASSERT(picture); picture->draw(canvas); } static jboolean serialize(JNIEnv* env, jobject, jlong pictureHandle, - jobject jstream, jbyteArray jstorage) { - SkPicture* picture = reinterpret_cast(pictureHandle); + jobject jstream, jbyteArray jstorage) { + AndroidPicture* picture = reinterpret_cast(pictureHandle); SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); - + if (NULL != strm) { picture->serialize(strm); delete strm; @@ -78,19 +74,21 @@ public: 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(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(height); } static jlong beginRecording(JNIEnv* env, jobject, jlong pictHandle, - jint w, jint h) { - SkPicture* pict = reinterpret_cast(pictHandle); + jint w, jint h) { + AndroidPicture* pict = reinterpret_cast(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 @@ public: } static void endRecording(JNIEnv* env, jobject, jlong pictHandle) { - SkPicture* pict = reinterpret_cast(pictHandle); + AndroidPicture* pict = reinterpret_cast(pictHandle); pict->endRecording(); } }; diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp index d54aaa8cbfadb..3812c277347b5 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 @@ namespace android { 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: } void close() { + assert(NULL == mCurrentPage); for (unsigned i = 0; i < mPages.size(); i++) { delete mPages[i]; } - delete mCurrentPage; - mCurrentPage = NULL; } private: