Loading core/jni/android/graphics/Canvas.cpp +173 −36 Original line number Diff line number Diff line Loading @@ -19,11 +19,14 @@ #include <android_runtime/AndroidRuntime.h> #include "SkCanvas.h" #include "SkClipStack.h" #include "SkDevice.h" #include "SkDeque.h" #include "SkDrawFilter.h" #include "SkGraphics.h" #include "SkPorterDuff.h" #include "SkShader.h" #include "SkTArray.h" #include "SkTemplates.h" #ifdef USE_MINIKIN Loading @@ -43,11 +46,42 @@ namespace android { class ClipCopier : public SkCanvas::ClipVisitor { public: ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { m_dstCanvas->clipRect(rect, op, antialias); } virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) { m_dstCanvas->clipRRect(rrect, op, antialias); } virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { m_dstCanvas->clipPath(path, op, antialias); } private: SkCanvas* m_dstCanvas; }; // Holds an SkCanvas reference plus additional native data. class NativeCanvasWrapper { private: struct SaveRec { int saveCount; SkCanvas::SaveFlags saveFlags; }; public: NativeCanvasWrapper(SkCanvas* canvas) : mCanvas(canvas) { } : mCanvas(canvas) , mSaveStack(NULL) { SkASSERT(canvas); } ~NativeCanvasWrapper() { delete mSaveStack; } SkCanvas* getCanvas() const { return mCanvas.get(); Loading @@ -56,28 +90,127 @@ public: void setCanvas(SkCanvas* canvas) { SkASSERT(canvas); mCanvas.reset(canvas); delete mSaveStack; mSaveStack = NULL; } private: SkAutoTUnref<SkCanvas> mCanvas; }; int save(SkCanvas::SaveFlags flags) { int count = mCanvas->save(); recordPartialSave(flags); return count; } class ClipCopier : public SkCanvas::ClipVisitor { public: ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} int saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags flags) { int count = mCanvas->saveLayer(bounds, paint, static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag)); recordPartialSave(flags); return count; } virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { m_dstCanvas->clipRect(rect, op, antialias); int saveLayerAlpha(const SkRect* bounds, U8CPU alpha, SkCanvas::SaveFlags flags) { int count = mCanvas->saveLayerAlpha(bounds, alpha, static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag)); recordPartialSave(flags); return count; } virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) { m_dstCanvas->clipRRect(rrect, op, antialias); void restore() { const SaveRec* rec = (NULL == mSaveStack) ? NULL : static_cast<SaveRec*>(mSaveStack->back()); int currentSaveCount = mCanvas->getSaveCount() - 1; SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount); if (NULL == rec || rec->saveCount != currentSaveCount) { // Fast path - no record for this frame. mCanvas->restore(); return; } virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { m_dstCanvas->clipPath(path, op, antialias); bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag); bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag); SkMatrix savedMatrix; if (preserveMatrix) { savedMatrix = mCanvas->getTotalMatrix(); } SkTArray<SkClipStack::Element> savedClips; if (preserveClip) { saveClipsForFrame(savedClips, currentSaveCount); } mCanvas->restore(); if (preserveMatrix) { mCanvas->setMatrix(savedMatrix); } if (preserveClip && !savedClips.empty()) { applyClips(savedClips); } mSaveStack->pop_back(); } private: SkCanvas* m_dstCanvas; void recordPartialSave(SkCanvas::SaveFlags flags) { // A partial save is a save operation which doesn't capture the full canvas state. // (either kMatrix_SaveFlags or kClip_SaveFlag is missing). // Mask-out non canvas state bits. flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag); if (SkCanvas::kMatrixClip_SaveFlag == flags) { // not a partial save. return; } if (NULL == mSaveStack) { mSaveStack = new SkDeque(sizeof(struct SaveRec), 8); } SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back()); // Store the save counter in the SkClipStack domain. // (0-based, equal to the number of save ops on the stack). rec->saveCount = mCanvas->getSaveCount() - 1; rec->saveFlags = flags; } void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount) { SkClipStack::Iter clipIterator(*mCanvas->getClipStack(), SkClipStack::Iter::kTop_IterStart); while (const SkClipStack::Element* elem = clipIterator.next()) { if (elem->getSaveCount() < frameSaveCount) { // done with the current frame. break; } SkASSERT(elem->getSaveCount() == frameSaveCount); clips.push_back(*elem); } } void applyClips(const SkTArray<SkClipStack::Element>& clips) { ClipCopier clipCopier(mCanvas); // The clip stack stores clips in device space. SkMatrix origMatrix = mCanvas->getTotalMatrix(); mCanvas->resetMatrix(); // We pushed the clips in reverse order. for (int i = clips.count() - 1; i >= 0; --i) { clips[i].replay(&clipCopier); } mCanvas->setMatrix(origMatrix); } SkAutoTUnref<SkCanvas> mCanvas; SkDeque* mSaveStack; // lazily allocated, tracks partial saves. }; // Returns true if the SkCanvas's clip is non-empty. Loading @@ -88,11 +221,15 @@ static jboolean hasNonEmptyClip(const SkCanvas& canvas) { class SkCanvasGlue { public: // Get the native wrapper for a given handle. static inline NativeCanvasWrapper* getNativeWrapper(jlong nativeHandle) { SkASSERT(nativeHandle); return reinterpret_cast<NativeCanvasWrapper*>(nativeHandle); } // Get the SkCanvas for a given native handle. static inline SkCanvas* getNativeCanvas(jlong nativeHandle) { SkASSERT(nativeHandle); NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(nativeHandle); NativeCanvasWrapper* wrapper = getNativeWrapper(nativeHandle); SkCanvas* canvas = wrapper->getCanvas(); SkASSERT(canvas); Loading Loading @@ -186,56 +323,56 @@ public: } static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); return static_cast<jint>(canvas->save(flags)); return static_cast<jint>(wrapper->save(flags)); } static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t, jfloat r, jfloat b, jlong paintHandle, jint flags) { SkCanvas* canvas = getNativeCanvas(canvasHandle); jlong paintHandle, jint flagsHandle) { NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); SkRect bounds; bounds.set(l, t, r, b); int result = canvas->saveLayer(&bounds, paint, static_cast<SkCanvas::SaveFlags>(flags)); return static_cast<jint>(result); return static_cast<jint>(wrapper->saveLayer(&bounds, paint, flags)); } static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t, jfloat r, jfloat b, jint alpha, jint flags) { SkCanvas* canvas = getNativeCanvas(canvasHandle); jint alpha, jint flagsHandle) { NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); SkRect bounds; bounds.set(l, t, r, b); int result = canvas->saveLayerAlpha(&bounds, alpha, static_cast<SkCanvas::SaveFlags>(flags)); return static_cast<jint>(result); return static_cast<jint>(wrapper->saveLayerAlpha(&bounds, alpha, flags)); } static void restore(JNIEnv* env, jobject, jlong canvasHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); if (canvas->getSaveCount() <= 1) { // cannot restore anymore NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); if (wrapper->getCanvas()->getSaveCount() <= 1) { // cannot restore anymore doThrowISE(env, "Underflow in restore"); return; } canvas->restore(); wrapper->restore(); } static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); return static_cast<jint>(canvas->getSaveCount()); return static_cast<jint>(getNativeCanvas(canvasHandle)->getSaveCount()); } static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount) { SkCanvas* canvas = getNativeCanvas(canvasHandle); NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); if (restoreCount < 1) { doThrowIAE(env, "Underflow in restoreToCount"); return; } canvas->restoreToCount(restoreCount); while (wrapper->getCanvas()->getSaveCount() > restoreCount) { wrapper->restore(); } } static void translate(JNIEnv*, jobject, jlong canvasHandle, Loading Loading
core/jni/android/graphics/Canvas.cpp +173 −36 Original line number Diff line number Diff line Loading @@ -19,11 +19,14 @@ #include <android_runtime/AndroidRuntime.h> #include "SkCanvas.h" #include "SkClipStack.h" #include "SkDevice.h" #include "SkDeque.h" #include "SkDrawFilter.h" #include "SkGraphics.h" #include "SkPorterDuff.h" #include "SkShader.h" #include "SkTArray.h" #include "SkTemplates.h" #ifdef USE_MINIKIN Loading @@ -43,11 +46,42 @@ namespace android { class ClipCopier : public SkCanvas::ClipVisitor { public: ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { m_dstCanvas->clipRect(rect, op, antialias); } virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) { m_dstCanvas->clipRRect(rrect, op, antialias); } virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { m_dstCanvas->clipPath(path, op, antialias); } private: SkCanvas* m_dstCanvas; }; // Holds an SkCanvas reference plus additional native data. class NativeCanvasWrapper { private: struct SaveRec { int saveCount; SkCanvas::SaveFlags saveFlags; }; public: NativeCanvasWrapper(SkCanvas* canvas) : mCanvas(canvas) { } : mCanvas(canvas) , mSaveStack(NULL) { SkASSERT(canvas); } ~NativeCanvasWrapper() { delete mSaveStack; } SkCanvas* getCanvas() const { return mCanvas.get(); Loading @@ -56,28 +90,127 @@ public: void setCanvas(SkCanvas* canvas) { SkASSERT(canvas); mCanvas.reset(canvas); delete mSaveStack; mSaveStack = NULL; } private: SkAutoTUnref<SkCanvas> mCanvas; }; int save(SkCanvas::SaveFlags flags) { int count = mCanvas->save(); recordPartialSave(flags); return count; } class ClipCopier : public SkCanvas::ClipVisitor { public: ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} int saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags flags) { int count = mCanvas->saveLayer(bounds, paint, static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag)); recordPartialSave(flags); return count; } virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { m_dstCanvas->clipRect(rect, op, antialias); int saveLayerAlpha(const SkRect* bounds, U8CPU alpha, SkCanvas::SaveFlags flags) { int count = mCanvas->saveLayerAlpha(bounds, alpha, static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag)); recordPartialSave(flags); return count; } virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) { m_dstCanvas->clipRRect(rrect, op, antialias); void restore() { const SaveRec* rec = (NULL == mSaveStack) ? NULL : static_cast<SaveRec*>(mSaveStack->back()); int currentSaveCount = mCanvas->getSaveCount() - 1; SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount); if (NULL == rec || rec->saveCount != currentSaveCount) { // Fast path - no record for this frame. mCanvas->restore(); return; } virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { m_dstCanvas->clipPath(path, op, antialias); bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag); bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag); SkMatrix savedMatrix; if (preserveMatrix) { savedMatrix = mCanvas->getTotalMatrix(); } SkTArray<SkClipStack::Element> savedClips; if (preserveClip) { saveClipsForFrame(savedClips, currentSaveCount); } mCanvas->restore(); if (preserveMatrix) { mCanvas->setMatrix(savedMatrix); } if (preserveClip && !savedClips.empty()) { applyClips(savedClips); } mSaveStack->pop_back(); } private: SkCanvas* m_dstCanvas; void recordPartialSave(SkCanvas::SaveFlags flags) { // A partial save is a save operation which doesn't capture the full canvas state. // (either kMatrix_SaveFlags or kClip_SaveFlag is missing). // Mask-out non canvas state bits. flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag); if (SkCanvas::kMatrixClip_SaveFlag == flags) { // not a partial save. return; } if (NULL == mSaveStack) { mSaveStack = new SkDeque(sizeof(struct SaveRec), 8); } SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back()); // Store the save counter in the SkClipStack domain. // (0-based, equal to the number of save ops on the stack). rec->saveCount = mCanvas->getSaveCount() - 1; rec->saveFlags = flags; } void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount) { SkClipStack::Iter clipIterator(*mCanvas->getClipStack(), SkClipStack::Iter::kTop_IterStart); while (const SkClipStack::Element* elem = clipIterator.next()) { if (elem->getSaveCount() < frameSaveCount) { // done with the current frame. break; } SkASSERT(elem->getSaveCount() == frameSaveCount); clips.push_back(*elem); } } void applyClips(const SkTArray<SkClipStack::Element>& clips) { ClipCopier clipCopier(mCanvas); // The clip stack stores clips in device space. SkMatrix origMatrix = mCanvas->getTotalMatrix(); mCanvas->resetMatrix(); // We pushed the clips in reverse order. for (int i = clips.count() - 1; i >= 0; --i) { clips[i].replay(&clipCopier); } mCanvas->setMatrix(origMatrix); } SkAutoTUnref<SkCanvas> mCanvas; SkDeque* mSaveStack; // lazily allocated, tracks partial saves. }; // Returns true if the SkCanvas's clip is non-empty. Loading @@ -88,11 +221,15 @@ static jboolean hasNonEmptyClip(const SkCanvas& canvas) { class SkCanvasGlue { public: // Get the native wrapper for a given handle. static inline NativeCanvasWrapper* getNativeWrapper(jlong nativeHandle) { SkASSERT(nativeHandle); return reinterpret_cast<NativeCanvasWrapper*>(nativeHandle); } // Get the SkCanvas for a given native handle. static inline SkCanvas* getNativeCanvas(jlong nativeHandle) { SkASSERT(nativeHandle); NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(nativeHandle); NativeCanvasWrapper* wrapper = getNativeWrapper(nativeHandle); SkCanvas* canvas = wrapper->getCanvas(); SkASSERT(canvas); Loading Loading @@ -186,56 +323,56 @@ public: } static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); return static_cast<jint>(canvas->save(flags)); return static_cast<jint>(wrapper->save(flags)); } static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t, jfloat r, jfloat b, jlong paintHandle, jint flags) { SkCanvas* canvas = getNativeCanvas(canvasHandle); jlong paintHandle, jint flagsHandle) { NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); SkRect bounds; bounds.set(l, t, r, b); int result = canvas->saveLayer(&bounds, paint, static_cast<SkCanvas::SaveFlags>(flags)); return static_cast<jint>(result); return static_cast<jint>(wrapper->saveLayer(&bounds, paint, flags)); } static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t, jfloat r, jfloat b, jint alpha, jint flags) { SkCanvas* canvas = getNativeCanvas(canvasHandle); jint alpha, jint flagsHandle) { NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); SkRect bounds; bounds.set(l, t, r, b); int result = canvas->saveLayerAlpha(&bounds, alpha, static_cast<SkCanvas::SaveFlags>(flags)); return static_cast<jint>(result); return static_cast<jint>(wrapper->saveLayerAlpha(&bounds, alpha, flags)); } static void restore(JNIEnv* env, jobject, jlong canvasHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); if (canvas->getSaveCount() <= 1) { // cannot restore anymore NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); if (wrapper->getCanvas()->getSaveCount() <= 1) { // cannot restore anymore doThrowISE(env, "Underflow in restore"); return; } canvas->restore(); wrapper->restore(); } static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); return static_cast<jint>(canvas->getSaveCount()); return static_cast<jint>(getNativeCanvas(canvasHandle)->getSaveCount()); } static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount) { SkCanvas* canvas = getNativeCanvas(canvasHandle); NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); if (restoreCount < 1) { doThrowIAE(env, "Underflow in restoreToCount"); return; } canvas->restoreToCount(restoreCount); while (wrapper->getCanvas()->getSaveCount() > restoreCount) { wrapper->restore(); } } static void translate(JNIEnv*, jobject, jlong canvasHandle, Loading