diff options
author | Derek Sollenberger <djsollen@google.com> | 2014-06-23 14:13:53 -0400 |
---|---|---|
committer | Derek Sollenberger <djsollen@google.com> | 2014-07-15 15:08:29 +0000 |
commit | f5d6c555c3430f6e423952ba3ab024380e550bba (patch) | |
tree | 82498fc05b05c01c5b38e8fa75253931a9b12d15 /core/jni | |
parent | a7cf5597e382eda396224bf2db84528ddbfba36c (diff) | |
download | frameworks_base-f5d6c555c3430f6e423952ba3ab024380e550bba.zip frameworks_base-f5d6c555c3430f6e423952ba3ab024380e550bba.tar.gz frameworks_base-f5d6c555c3430f6e423952ba3ab024380e550bba.tar.bz2 |
Separate Canvas JNI code from the implementation. DO NOT MERGE
This introduces Canvas.h which is a pure virtual interface that
is intended to be used by both Skia and HWUI implementation. To help
stage this transition this CL only introduces the interface and Skia
implementation. The interface is not intended to be final and will
undoubtedly go through iterations in both style and location as we
look to introduce the HWUI implementation.
BUG:15672762
Change-Id: Idefadede356f688edb8eb09b4a02aa01b4077f62
Diffstat (limited to 'core/jni')
-rw-r--r-- | core/jni/Android.mk | 3 | ||||
-rw-r--r-- | core/jni/android/graphics/Camera.cpp | 5 | ||||
-rw-r--r-- | core/jni/android/graphics/Canvas.cpp | 1330 | ||||
-rw-r--r-- | core/jni/android/graphics/Canvas.h | 137 | ||||
-rw-r--r-- | core/jni/android/graphics/Graphics.cpp | 3 | ||||
-rw-r--r-- | core/jni/android/graphics/GraphicsJNI.h | 1 | ||||
-rw-r--r-- | core/jni/android/graphics/NinePatch.cpp | 5 | ||||
-rw-r--r-- | core/jni/android/graphics/Picture.cpp | 11 | ||||
-rw-r--r-- | core/jni/android/graphics/Picture.h | 9 | ||||
-rw-r--r-- | core/jni/android/graphics/SkiaCanvas.cpp | 773 | ||||
-rw-r--r-- | core/jni/android/graphics/pdf/PdfDocument.cpp | 7 | ||||
-rw-r--r-- | core/jni/android_graphics_Canvas.cpp | 653 | ||||
-rw-r--r-- | core/jni/android_graphics_Picture.cpp | 9 |
13 files changed, 1589 insertions, 1357 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 0e22174..f65aab5 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -90,12 +90,12 @@ LOCAL_SRC_FILES:= \ android_util_Process.cpp \ android_util_StringBlock.cpp \ android_util_XmlBlock.cpp \ + android_graphics_Canvas.cpp \ android_graphics_Picture.cpp \ android/graphics/AutoDecodeCancel.cpp \ android/graphics/Bitmap.cpp \ android/graphics/BitmapFactory.cpp \ android/graphics/Camera.cpp \ - android/graphics/Canvas.cpp \ android/graphics/CanvasProperty.cpp \ android/graphics/ColorFilter.cpp \ android/graphics/DrawFilter.cpp \ @@ -122,6 +122,7 @@ LOCAL_SRC_FILES:= \ android/graphics/Rasterizer.cpp \ android/graphics/Region.cpp \ android/graphics/Shader.cpp \ + android/graphics/SkiaCanvas.cpp \ android/graphics/SurfaceTexture.cpp \ android/graphics/Typeface.cpp \ android/graphics/TypefaceImpl.cpp \ diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp index d17f46c..9f832b0 100644 --- a/core/jni/android/graphics/Camera.cpp +++ b/core/jni/android/graphics/Camera.cpp @@ -3,6 +3,7 @@ #include "SkCamera.h" +#include "Canvas.h" #include "GraphicsJNI.h" static jfieldID gNativeInstanceFieldID; @@ -95,10 +96,10 @@ static void Camera_getMatrix(JNIEnv* env, jobject obj, jlong matrixHandle) { } static void Camera_applyToCanvas(JNIEnv* env, jobject obj, jlong canvasHandle) { - SkCanvas* native_canvas = GraphicsJNI::getNativeCanvas(canvasHandle); + SkCanvas* canvas = reinterpret_cast<android::Canvas*>(canvasHandle)->getSkCanvas(); jlong viewHandle = env->GetLongField(obj, gNativeInstanceFieldID); Sk3DView* v = reinterpret_cast<Sk3DView*>(viewHandle); - v->applyToCanvas((SkCanvas*)native_canvas); + v->applyToCanvas(canvas); } static jfloat Camera_dotWithNormal(JNIEnv* env, jobject obj, diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp deleted file mode 100644 index 6254f3d..0000000 --- a/core/jni/android/graphics/Canvas.cpp +++ /dev/null @@ -1,1330 +0,0 @@ -/* - * Copyright (C) 2006-2007 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 "jni.h" -#include "GraphicsJNI.h" -#include <android_runtime/AndroidRuntime.h> - -#include "SkCanvas.h" -#include "SkClipStack.h" -#include "SkDevice.h" -#include "SkDeque.h" -#include "SkDrawFilter.h" -#include "SkGraphics.h" -#include <SkImageInfo.h> -#include "SkPorterDuff.h" -#include "SkShader.h" -#include "SkTArray.h" -#include "SkTemplates.h" - -#include <minikin/Layout.h> -#include "MinikinSkia.h" -#include "MinikinUtils.h" - -#include "TypefaceImpl.h" - -#include "unicode/ubidi.h" -#include "unicode/ushape.h" - -#include <utils/Log.h> - -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) - , mSaveStack(NULL) { - SkASSERT(canvas); - } - - ~NativeCanvasWrapper() { - delete mSaveStack; - } - - SkCanvas* getCanvas() const { - return mCanvas.get(); - } - - void setCanvas(SkCanvas* canvas) { - SkASSERT(canvas); - mCanvas.reset(canvas); - - delete mSaveStack; - mSaveStack = NULL; - } - - int save(SkCanvas::SaveFlags flags) { - int count = mCanvas->save(); - recordPartialSave(flags); - return count; - } - - 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; - } - - 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; - } - - 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; - } - - 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: - 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. -static jboolean hasNonEmptyClip(const SkCanvas& canvas) { - bool emptyClip = canvas.isClipEmpty(); - return emptyClip ? JNI_FALSE : JNI_TRUE; -} - -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) { - NativeCanvasWrapper* wrapper = getNativeWrapper(nativeHandle); - SkCanvas* canvas = wrapper->getCanvas(); - SkASSERT(canvas); - - return canvas; - } - - // Construct an SkCanvas from the bitmap. - static SkCanvas* createCanvas(SkBitmap* bitmap) { - if (bitmap) { - return SkNEW_ARGS(SkCanvas, (*bitmap)); - } - - // Create an empty bitmap device to prevent callers from crashing - // if they attempt to draw into this canvas. - SkBitmap emptyBitmap; - return new SkCanvas(emptyBitmap); - } - - // Copy the canvas matrix & clip state. - static void copyCanvasState(SkCanvas* srcCanvas, SkCanvas* dstCanvas) { - if (srcCanvas && dstCanvas) { - dstCanvas->setMatrix(srcCanvas->getTotalMatrix()); - if (NULL != srcCanvas->getDevice() && NULL != dstCanvas->getDevice()) { - ClipCopier copier(dstCanvas); - srcCanvas->replayClips(&copier); - } - } - } - - // Native JNI handlers - static void finalizer(JNIEnv* env, jobject clazz, jlong nativeHandle) { - NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(nativeHandle); - delete wrapper; - } - - // Native wrapper constructor used by Canvas(Bitmap) - static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) { - // No check - 0 is a valid bitmapHandle. - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); - SkCanvas* canvas = createCanvas(bitmap); - - return reinterpret_cast<jlong>(new NativeCanvasWrapper(canvas)); - } - - // Native wrapper constructor used by Canvas(native_canvas) - static jlong initCanvas(JNIEnv* env, jobject, jlong canvasHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); - return reinterpret_cast<jlong>(new NativeCanvasWrapper(canvas)); - } - - // Set the given bitmap as the new draw target (wrapped in a new SkCanvas), - // optionally copying canvas matrix & clip state. - static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, - jboolean copyState) { - NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(canvasHandle); - SkCanvas* newCanvas = createCanvas(reinterpret_cast<SkBitmap*>(bitmapHandle)); - NPE_CHECK_RETURN_VOID(env, newCanvas); - - if (copyState == JNI_TRUE) { - copyCanvasState(wrapper->getCanvas(), newCanvas); - } - - // setCanvas() unrefs the old canvas. - wrapper->setCanvas(newCanvas); - } - - static void freeCaches(JNIEnv* env, jobject) { - SkGraphics::PurgeFontCache(); - } - - static void freeTextLayoutCaches(JNIEnv* env, jobject) { - Layout::purgeCaches(); - } - - static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - bool result = canvas->getDevice()->accessBitmap(false).isOpaque(); - return result ? JNI_TRUE : JNI_FALSE; - } - - static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - int width = canvas->getDevice()->accessBitmap(false).width(); - return static_cast<jint>(width); - } - - static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - int height = canvas->getDevice()->accessBitmap(false).height(); - return static_cast<jint>(height); - } - - static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) { - NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); - SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); - 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 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); - 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 flagsHandle) { - NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); - SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); - SkRect bounds; - bounds.set(l, t, r, b); - return static_cast<jint>(wrapper->saveLayerAlpha(&bounds, alpha, flags)); - } - - static void restore(JNIEnv* env, jobject, jlong canvasHandle) { - NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); - if (wrapper->getCanvas()->getSaveCount() <= 1) { // cannot restore anymore - doThrowISE(env, "Underflow in restore"); - return; - } - wrapper->restore(); - } - - static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) { - return static_cast<jint>(getNativeCanvas(canvasHandle)->getSaveCount()); - } - - static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, - jint restoreCount) { - NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); - if (restoreCount < 1) { - doThrowIAE(env, "Underflow in restoreToCount"); - return; - } - - while (wrapper->getCanvas()->getSaveCount() > restoreCount) { - wrapper->restore(); - } - } - - static void translate(JNIEnv*, jobject, jlong canvasHandle, - jfloat dx, jfloat dy) { - getNativeCanvas(canvasHandle)->translate(dx, dy); - } - - static void scale__FF(JNIEnv*, jobject, jlong canvasHandle, - jfloat sx, jfloat sy) { - getNativeCanvas(canvasHandle)->scale(sx, sy); - } - - static void rotate__F(JNIEnv*, jobject, jlong canvasHandle, - jfloat degrees) { - getNativeCanvas(canvasHandle)->rotate(degrees); - } - - static void skew__FF(JNIEnv*, jobject, jlong canvasHandle, - jfloat sx, jfloat sy) { - getNativeCanvas(canvasHandle)->skew(sx, sy); - } - - static void concat(JNIEnv* env, jobject, jlong canvasHandle, - jlong matrixHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); - canvas->concat(*matrix); - } - - static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, - jlong matrixHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); - if (NULL == matrix) { - canvas->resetMatrix(); - } else { - canvas->setMatrix(*matrix); - } - } - - static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, - jfloat left, jfloat top, jfloat right, - jfloat bottom, jint op) { - SkRect r; - r.set(left, top, right, bottom); - SkCanvas* c = getNativeCanvas(canvasHandle); - c->clipRect(r, static_cast<SkRegion::Op>(op)); - return hasNonEmptyClip(*c); - } - - static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, - jlong pathHandle, jint op) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - canvas->clipPath(*reinterpret_cast<SkPath*>(pathHandle), - static_cast<SkRegion::Op>(op)); - return hasNonEmptyClip(*canvas); - } - - static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, - jlong deviceRgnHandle, jint op) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle); - SkPath rgnPath; - if (deviceRgn->getBoundaryPath(&rgnPath)) { - // The region is specified in device space. - SkMatrix savedMatrix = canvas->getTotalMatrix(); - canvas->resetMatrix(); - canvas->clipPath(rgnPath, static_cast<SkRegion::Op>(op)); - canvas->setMatrix(savedMatrix); - } else { - canvas->clipRect(SkRect::MakeEmpty(), static_cast<SkRegion::Op>(op)); - } - return hasNonEmptyClip(*canvas); - } - - static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, - jlong filterHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - canvas->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle)); - } - - static jboolean quickReject__Path(JNIEnv* env, jobject, jlong canvasHandle, - jlong pathHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - bool result = canvas->quickReject(*reinterpret_cast<SkPath*>(pathHandle)); - return result ? JNI_TRUE : JNI_FALSE; - } - - static jboolean quickReject__FFFF(JNIEnv* env, jobject, jlong canvasHandle, - jfloat left, jfloat top, jfloat right, - jfloat bottom) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkRect r; - r.set(left, top, right, bottom); - bool result = canvas->quickReject(r); - return result ? JNI_TRUE : JNI_FALSE; - } - - static void drawRGB(JNIEnv* env, jobject, jlong canvasHandle, - jint r, jint g, jint b) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - canvas->drawARGB(0xFF, r, g, b); - } - - static void drawARGB(JNIEnv* env, jobject, jlong canvasHandle, - jint a, jint r, jint g, jint b) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - canvas->drawARGB(a, r, g, b); - } - - static void drawColor__I(JNIEnv* env, jobject, jlong canvasHandle, - jint color) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - canvas->drawColor(color); - } - - static void drawColor__II(JNIEnv* env, jobject, jlong canvasHandle, - jint color, jint modeHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle); - canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode)); - } - - static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, - jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - canvas->drawPaint(*paint); - } - - static void doPoints(JNIEnv* env, jlong canvasHandle, - jfloatArray jptsArray, jint offset, jint count, - jlong paintHandle, jint modeHandle) { - NPE_CHECK_RETURN_VOID(env, jptsArray); - SkCanvas::PointMode mode = static_cast<SkCanvas::PointMode>(modeHandle); - SkCanvas* canvas = getNativeCanvas(canvasHandle); - const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - - AutoJavaFloatArray autoPts(env, jptsArray); - float* floats = autoPts.ptr(); - const int length = autoPts.length(); - - if ((offset | count) < 0 || offset + count > length) { - doThrowAIOOBE(env); - return; - } - - // now convert the floats into SkPoints - count >>= 1; // now it is the number of points - SkAutoSTMalloc<32, SkPoint> storage(count); - SkPoint* pts = storage.get(); - const float* src = floats + offset; - for (int i = 0; i < count; i++) { - pts[i].set(src[0], src[1]); - src += 2; - } - canvas->drawPoints(mode, count, pts, *paint); - } - - static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, - jfloatArray jptsArray, jint offset, - jint count, jlong paintHandle) { - doPoints(env, canvasHandle, jptsArray, offset, count, paintHandle, - SkCanvas::kPoints_PointMode); - } - - static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, - jfloatArray jptsArray, jint offset, jint count, - jlong paintHandle) { - doPoints(env, canvasHandle, jptsArray, offset, count, paintHandle, - SkCanvas::kLines_PointMode); - } - - static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y, - jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - canvas->drawPoint(x, y, *paint); - } - - static void drawLine__FFFFPaint(JNIEnv* env, jobject, jlong canvasHandle, - jfloat startX, jfloat startY, jfloat stopX, - jfloat stopY, jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - canvas->drawLine(startX, startY, stopX, stopY, *paint); - } - - static void drawRect__FFFFPaint(JNIEnv* env, jobject, jlong canvasHandle, - jfloat left, jfloat top, jfloat right, - jfloat bottom, jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - canvas->drawRectCoords(left, top, right, bottom, *paint); - } - - static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, - jfloat right, jfloat bottom, jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); - canvas->drawOval(oval, *paint); - } - - static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, - jfloat cy, jfloat radius, jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - canvas->drawCircle(cx, cy, radius, *paint); - } - - static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, - jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, jboolean useCenter, - jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); - canvas->drawArc(oval, startAngle, sweepAngle, useCenter, *paint); - } - - static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, - jfloat left, jfloat top, jfloat right, jfloat bottom, jfloat rx, jfloat ry, - jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - canvas->drawRoundRect(rect, rx, ry, *paint); - } - - static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle, - jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPath* path = reinterpret_cast<SkPath*>(pathHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - canvas->drawPath(*path, *paint); - } - - static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas, - jlong canvasHandle, jlong bitmapHandle, - jfloat left, jfloat top, - jlong paintHandle, jint canvasDensity, - jint screenDensity, jint bitmapDensity) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - - if (canvasDensity == bitmapDensity || canvasDensity == 0 - || bitmapDensity == 0) { - if (screenDensity != 0 && screenDensity != bitmapDensity) { - SkPaint filteredPaint; - if (paint) { - filteredPaint = *paint; - } - filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); - canvas->drawBitmap(*bitmap, left, top, &filteredPaint); - } else { - canvas->drawBitmap(*bitmap, left, top, paint); - } - } else { - canvas->save(); - SkScalar scale = canvasDensity / (float)bitmapDensity; - canvas->translate(left, top); - canvas->scale(scale, scale); - - SkPaint filteredPaint; - if (paint) { - filteredPaint = *paint; - } - filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); - - canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint); - - canvas->restore(); - } - } - - static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap, - jobject srcIRect, const SkRect& dst, SkPaint* paint, - jint screenDensity, jint bitmapDensity) { - SkIRect src, *srcPtr = NULL; - - if (NULL != srcIRect) { - GraphicsJNI::jrect_to_irect(env, srcIRect, &src); - srcPtr = &src; - } - - if (screenDensity != 0 && screenDensity != bitmapDensity) { - SkPaint filteredPaint; - if (paint) { - filteredPaint = *paint; - } - filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); - canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint); - } else { - canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint); - } - } - - static void drawBitmapRF(JNIEnv* env, jobject, jlong canvasHandle, - jlong bitmapHandle, jobject srcIRect, - jobject dstRectF, jlong paintHandle, - jint screenDensity, jint bitmapDensity) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect dst; - GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst); - doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint, - screenDensity, bitmapDensity); - } - - static void drawBitmapRR(JNIEnv* env, jobject, jlong canvasHandle, - jlong bitmapHandle, jobject srcIRect, - jobject dstRect, jlong paintHandle, - jint screenDensity, jint bitmapDensity) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect dst; - GraphicsJNI::jrect_to_rect(env, dstRect, &dst); - doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint, - screenDensity, bitmapDensity); - } - - static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle, - jintArray jcolors, jint offset, jint stride, - jfloat x, jfloat y, jint width, jint height, - jboolean hasAlpha, jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will - // correct the alphaType to kOpaque_SkAlphaType. - SkImageInfo info = SkImageInfo::Make(width, height, - hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType, - kPremul_SkAlphaType); - SkBitmap bitmap; - if (!bitmap.allocPixels(info)) { - return; - } - - if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, - 0, 0, width, height, bitmap)) { - return; - } - - canvas->drawBitmap(bitmap, x, y, paint); - } - - static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, - jlong bitmapHandle, jlong matrixHandle, - jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); - const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); - const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - canvas->drawBitmapMatrix(*bitmap, *matrix, paint); - } - - static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, - jlong bitmapHandle, jint meshWidth, jint meshHeight, - jfloatArray jverts, jint vertIndex, jintArray jcolors, - jint colorIndex, jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); - const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - - const int ptCount = (meshWidth + 1) * (meshHeight + 1); - const int indexCount = meshWidth * meshHeight * 6; - - AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1)); - AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount); - - /* Our temp storage holds 2 or 3 arrays. - texture points [ptCount * sizeof(SkPoint)] - optionally vertex points [ptCount * sizeof(SkPoint)] if we need a - copy to convert from float to fixed - indices [ptCount * sizeof(uint16_t)] - */ - ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] - storageSize += indexCount * sizeof(uint16_t); // indices[] - - SkAutoMalloc storage(storageSize); - SkPoint* texs = (SkPoint*)storage.get(); - SkPoint* verts; - uint16_t* indices; -#ifdef SK_SCALAR_IS_FLOAT - verts = (SkPoint*)(vertA.ptr() + vertIndex); - indices = (uint16_t*)(texs + ptCount); -#else - SkASSERT(false); -#endif - - // cons up texture coordinates and indices - { - const SkScalar w = SkIntToScalar(bitmap->width()); - const SkScalar h = SkIntToScalar(bitmap->height()); - const SkScalar dx = w / meshWidth; - const SkScalar dy = h / meshHeight; - - SkPoint* texsPtr = texs; - SkScalar y = 0; - for (int i = 0; i <= meshHeight; i++) { - if (i == meshHeight) { - y = h; // to ensure numerically we hit h exactly - } - SkScalar x = 0; - for (int j = 0; j < meshWidth; j++) { - texsPtr->set(x, y); - texsPtr += 1; - x += dx; - } - texsPtr->set(w, y); - texsPtr += 1; - y += dy; - } - SkASSERT(texsPtr - texs == ptCount); - } - - // cons up indices - { - uint16_t* indexPtr = indices; - int index = 0; - for (int i = 0; i < meshHeight; i++) { - for (int j = 0; j < meshWidth; j++) { - // lower-left triangle - *indexPtr++ = index; - *indexPtr++ = index + meshWidth + 1; - *indexPtr++ = index + meshWidth + 2; - // upper-right triangle - *indexPtr++ = index; - *indexPtr++ = index + meshWidth + 2; - *indexPtr++ = index + 1; - // bump to the next cell - index += 1; - } - // bump to the next row - index += 1; - } - SkASSERT(indexPtr - indices == indexCount); - SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); - } - - // double-check that we have legal indices -#ifdef SK_DEBUG - { - for (int i = 0; i < indexCount; i++) { - SkASSERT((unsigned)indices[i] < (unsigned)ptCount); - } - } -#endif - - // cons-up a shader for the bitmap - SkPaint tmpPaint; - if (paint) { - tmpPaint = *paint; - } - SkShader* shader = SkShader::CreateBitmapShader(*bitmap, - SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - SkSafeUnref(tmpPaint.setShader(shader)); - - canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts, - texs, (const SkColor*)colorA.ptr(), NULL, indices, - indexCount, tmpPaint); - } - - static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle, - jint modeHandle, jint vertexCount, - jfloatArray jverts, jint vertIndex, - jfloatArray jtexs, jint texIndex, - jintArray jcolors, jint colorIndex, - jshortArray jindices, jint indexIndex, - jint indexCount, jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle); - const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - - AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); - AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); - AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); - AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); - - const int ptCount = vertexCount >> 1; - - SkPoint* verts; - SkPoint* texs = NULL; -#ifdef SK_SCALAR_IS_FLOAT - verts = (SkPoint*)(vertA.ptr() + vertIndex); - if (jtexs != NULL) { - texs = (SkPoint*)(texA.ptr() + texIndex); - } -#else - SkASSERT(false); -#endif - - const SkColor* colors = NULL; - const uint16_t* indices = NULL; - if (jcolors != NULL) { - colors = (const SkColor*)(colorA.ptr() + colorIndex); - } - if (jindices != NULL) { - indices = (const uint16_t*)(indexA.ptr() + indexIndex); - } - - canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL, - indices, indexCount, *paint); - } - - - static void drawText___CIIFFIPaintTypeface(JNIEnv* env, jobject, jlong canvasHandle, - jcharArray text, jint index, jint count, - jfloat x, jfloat y, jint bidiFlags, - jlong paintHandle, jlong typefaceHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); - jchar* textArray = env->GetCharArrayElements(text, NULL); - drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, bidiFlags, paint, typeface); - env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); - } - - static void drawText__StringIIFFIPaintTypeface(JNIEnv* env, jobject, - jlong canvasHandle, jstring text, - jint start, jint end, - jfloat x, jfloat y, jint bidiFlags, - jlong paintHandle, jlong typefaceHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); - const jchar* textArray = env->GetStringChars(text, NULL); - drawTextWithGlyphs(canvas, textArray, start, end, x, y, bidiFlags, paint, typeface); - env->ReleaseStringChars(text, textArray); - } - - class DrawTextFunctor { - public: - DrawTextFunctor(const Layout& layout, SkCanvas* canvas, jfloat x, jfloat y, SkPaint* paint, - uint16_t* glyphs, SkPoint* pos) - : layout(layout), canvas(canvas), x(x), y(y), paint(paint), glyphs(glyphs), - pos(pos) { } - - void operator()(size_t start, size_t end) { - for (size_t i = start; i < end; i++) { - glyphs[i] = layout.getGlyphId(i); - pos[i].fX = x + layout.getX(i); - pos[i].fY = y + layout.getY(i); - } - canvas->drawPosText(glyphs + start, (end - start) << 1, pos + start, *paint); - } - private: - const Layout& layout; - SkCanvas* canvas; - jfloat x; - jfloat y; - SkPaint* paint; - uint16_t* glyphs; - SkPoint* pos; - }; - - static void drawGlyphsToSkia(SkCanvas* canvas, SkPaint* paint, const Layout& layout, float x, float y) { - size_t nGlyphs = layout.nGlyphs(); - uint16_t* glyphs = new uint16_t[nGlyphs]; - SkPoint* pos = new SkPoint[nGlyphs]; - - x += MinikinUtils::xOffsetForTextAlign(paint, layout); - SkPaint::Align align = paint->getTextAlign(); - paint->setTextAlign(SkPaint::kLeft_Align); - paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); - DrawTextFunctor f(layout, canvas, x, y, paint, glyphs, pos); - MinikinUtils::forFontRun(layout, paint, f); - doDrawTextDecorations(canvas, x, y, layout.getAdvance(), paint); - paint->setTextAlign(align); - delete[] glyphs; - delete[] pos; - } - - static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, - int start, int end, - jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { - - jint count = end - start; - drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, bidiFlags, paint, - typeface); - } - - static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, - int start, int count, int contextCount, - jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { - - Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(textArray, start, count, contextCount, css); - drawGlyphsToSkia(canvas, paint, layout, x, y); - } - -// Same values used by Skia -#define kStdStrikeThru_Offset (-6.0f / 21.0f) -#define kStdUnderline_Offset (1.0f / 9.0f) -#define kStdUnderline_Thickness (1.0f / 18.0f) - - static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, - SkPaint* paint) { - uint32_t flags; - SkDrawFilter* drawFilter = canvas->getDrawFilter(); - if (drawFilter) { - SkPaint paintCopy(*paint); - drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); - flags = paintCopy.getFlags(); - } else { - flags = paint->getFlags(); - } - if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { - SkScalar left = x; - SkScalar right = x + length; - float textSize = paint->getTextSize(); - float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); - if (flags & SkPaint::kUnderlineText_Flag) { - SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; - SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; - canvas->drawRectCoords(left, top, right, bottom, *paint); - } - if (flags & SkPaint::kStrikeThruText_Flag) { - SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; - SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; - canvas->drawRectCoords(left, top, right, bottom, *paint); - } - } - } - - static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray, - int index, int count, jfloat x, jfloat y, SkPaint* paint) { - SkPoint* posPtr = new SkPoint[count]; - for (int indx = 0; indx < count; indx++) { - posPtr[indx].fX = x + posArray[indx * 2]; - posPtr[indx].fY = y + posArray[indx * 2 + 1]; - } - canvas->drawPosText(glyphArray, count << 1, posPtr, *paint); - delete[] posPtr; - } - - static void drawTextRun___CIIIIFFZPaintTypeface( - JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, - jint count, jint contextIndex, jint contextCount, - jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); - - int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; - jchar* chars = env->GetCharArrayElements(text, NULL); - drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex, - count, contextCount, x, y, bidiFlags, paint, typeface); - env->ReleaseCharArrayElements(text, chars, JNI_ABORT); - } - - static void drawTextRun__StringIIIIFFZPaintTypeface( - JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, jint start, - jint end, jint contextStart, jint contextEnd, - jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); - - int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; - jint count = end - start; - jint contextCount = contextEnd - contextStart; - const jchar* chars = env->GetStringChars(text, NULL); - drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart, - count, contextCount, x, y, bidiFlags, paint, typeface); - env->ReleaseStringChars(text, chars); - } - - static void drawPosText___CII_FPaint(JNIEnv* env, jobject, jlong canvasHandle, - jcharArray text, jint index, jint count, - jfloatArray pos, jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL; - jsize textCount = text ? env->GetArrayLength(text) : NULL; - float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; - int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; - SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; - int indx; - for (indx = 0; indx < posCount; indx++) { - posPtr[indx].fX = posArray[indx << 1]; - posPtr[indx].fY = posArray[(indx << 1) + 1]; - } - - SkPaint::TextEncoding encoding = paint->getTextEncoding(); - paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); - canvas->drawPosText(textArray + index, count << 1, posPtr, *paint); - paint->setTextEncoding(encoding); - - if (text) { - env->ReleaseCharArrayElements(text, textArray, 0); - } - if (pos) { - env->ReleaseFloatArrayElements(pos, posArray, 0); - } - delete[] posPtr; - } - - static void drawPosText__String_FPaint(JNIEnv* env, jobject, - jlong canvasHandle, jstring text, - jfloatArray pos, - jlong paintHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; - int byteLength = text ? env->GetStringLength(text) : 0; - float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; - int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; - SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; - - for (int indx = 0; indx < posCount; indx++) { - posPtr[indx].fX = posArray[indx << 1]; - posPtr[indx].fY = posArray[(indx << 1) + 1]; - } - - SkPaint::TextEncoding encoding = paint->getTextEncoding(); - paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); - canvas->drawPosText(text_, byteLength << 1, posPtr, *paint); - paint->setTextEncoding(encoding); - - if (text) { - env->ReleaseStringChars(text, (const jchar*) text_); - } - if (pos) { - env->ReleaseFloatArrayElements(pos, posArray, 0); - } - delete[] posPtr; - } - - class DrawTextOnPathFunctor { - public: - DrawTextOnPathFunctor(const Layout& layout, SkCanvas* canvas, float hOffset, - float vOffset, SkPaint* paint, SkPath* path) - : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset), - paint(paint), path(path) { - } - void operator()(size_t start, size_t end) { - uint16_t glyphs[1]; - for (size_t i = start; i < end; i++) { - glyphs[0] = layout.getGlyphId(i); - float x = hOffset + layout.getX(i); - float y = vOffset + layout.getY(i); - canvas->drawTextOnPathHV(glyphs, sizeof(glyphs), *path, x, y, *paint); - } - } - private: - const Layout& layout; - SkCanvas* canvas; - float hOffset; - float vOffset; - SkPaint* paint; - SkPath* path; - }; - - static void doDrawTextOnPath(SkPaint* paint, const jchar* text, int count, int bidiFlags, - float hOffset, float vOffset, SkPath* path, SkCanvas* canvas, TypefaceImpl* typeface) { - Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(text, 0, count, count, css); - hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path); - // Set align to left for drawing, as we don't want individual - // glyphs centered or right-aligned; the offset above takes - // care of all alignment. - SkPaint::Align align = paint->getTextAlign(); - paint->setTextAlign(SkPaint::kLeft_Align); - - DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paint, path); - MinikinUtils::forFontRun(layout, paint, f); - paint->setTextAlign(align); - } - - static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject, - jlong canvasHandle, jcharArray text, jint index, jint count, - jlong pathHandle, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle, - jlong typefaceHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPath* path = reinterpret_cast<SkPath*>(pathHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); - - jchar* textArray = env->GetCharArrayElements(text, NULL); - doDrawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset, - path, canvas, typeface); - env->ReleaseCharArrayElements(text, textArray, 0); - } - - static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject, - jlong canvasHandle, jstring text, jlong pathHandle, - jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle, - jlong typefaceHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkPath* path = reinterpret_cast<SkPath*>(pathHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); - - const jchar* text_ = env->GetStringChars(text, NULL); - int count = env->GetStringLength(text); - doDrawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset, - path, canvas, typeface); - env->ReleaseStringChars(text, text_); - } - - - // This function is a mirror of SkCanvas::getClipBounds except that it does - // not outset the edge of the clip to account for anti-aliasing. There is - // a skia bug to investigate pushing this logic into back into skia. - // (see https://code.google.com/p/skia/issues/detail?id=1303) - static bool getHardClipBounds(SkCanvas* canvas, SkRect* bounds) { - SkIRect ibounds; - if (!canvas->getClipDeviceBounds(&ibounds)) { - return false; - } - - SkMatrix inverse; - // if we can't invert the CTM, we can't return local clip bounds - if (!canvas->getTotalMatrix().invert(&inverse)) { - if (bounds) { - bounds->setEmpty(); - } - return false; - } - - if (NULL != bounds) { - SkRect r = SkRect::Make(ibounds); - inverse.mapRect(bounds, r); - } - return true; - } - - static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, - jobject bounds) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkRect r; - SkIRect ir; - bool result = getHardClipBounds(canvas, &r); - - if (!result) { - r.setEmpty(); - } - r.round(&ir); - - (void)GraphicsJNI::irect_to_jrect(ir, env, bounds); - return result ? JNI_TRUE : JNI_FALSE; - } - - static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, - jlong matrixHandle) { - SkCanvas* canvas = getNativeCanvas(canvasHandle); - SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); - *matrix = canvas->getTotalMatrix(); - } -}; - -static JNINativeMethod gCanvasMethods[] = { - {"finalizer", "(J)V", (void*) SkCanvasGlue::finalizer}, - {"initRaster", "(J)J", (void*) SkCanvasGlue::initRaster}, - {"initCanvas", "(J)J", (void*) SkCanvasGlue::initCanvas}, - {"native_setBitmap", "(JJZ)V", (void*) SkCanvasGlue::setBitmap}, - {"native_isOpaque","(J)Z", (void*) SkCanvasGlue::isOpaque}, - {"native_getWidth","(J)I", (void*) SkCanvasGlue::getWidth}, - {"native_getHeight","(J)I", (void*) SkCanvasGlue::getHeight}, - {"native_save","(JI)I", (void*) SkCanvasGlue::save}, - {"native_saveLayer","(JFFFFJI)I", (void*) SkCanvasGlue::saveLayer}, - {"native_saveLayerAlpha","(JFFFFII)I", (void*) SkCanvasGlue::saveLayerAlpha}, - {"native_restore","(J)V", (void*) SkCanvasGlue::restore}, - {"native_getSaveCount","(J)I", (void*) SkCanvasGlue::getSaveCount}, - {"native_restoreToCount","(JI)V", (void*) SkCanvasGlue::restoreToCount}, - {"native_translate","(JFF)V", (void*) SkCanvasGlue::translate}, - {"native_scale","(JFF)V", (void*) SkCanvasGlue::scale__FF}, - {"native_rotate","(JF)V", (void*) SkCanvasGlue::rotate__F}, - {"native_skew","(JFF)V", (void*) SkCanvasGlue::skew__FF}, - {"native_concat","(JJ)V", (void*) SkCanvasGlue::concat}, - {"native_setMatrix","(JJ)V", (void*) SkCanvasGlue::setMatrix}, - {"native_clipRect","(JFFFFI)Z", (void*) SkCanvasGlue::clipRect}, - {"native_clipPath","(JJI)Z", (void*) SkCanvasGlue::clipPath}, - {"native_clipRegion","(JJI)Z", (void*) SkCanvasGlue::clipRegion}, - {"nativeSetDrawFilter", "(JJ)V", (void*) SkCanvasGlue::setDrawFilter}, - {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", - (void*) SkCanvasGlue::getClipBounds}, - {"native_getCTM", "(JJ)V", (void*)SkCanvasGlue::getCTM}, - {"native_quickReject","(JJ)Z", (void*) SkCanvasGlue::quickReject__Path}, - {"native_quickReject","(JFFFF)Z", (void*)SkCanvasGlue::quickReject__FFFF}, - {"native_drawRGB","(JIII)V", (void*) SkCanvasGlue::drawRGB}, - {"native_drawARGB","(JIIII)V", (void*) SkCanvasGlue::drawARGB}, - {"native_drawColor","(JI)V", (void*) SkCanvasGlue::drawColor__I}, - {"native_drawColor","(JII)V", (void*) SkCanvasGlue::drawColor__II}, - {"native_drawPaint","(JJ)V", (void*) SkCanvasGlue::drawPaint}, - {"native_drawPoint", "(JFFJ)V", (void*) SkCanvasGlue::drawPoint}, - {"native_drawPoints", "(J[FIIJ)V", (void*) SkCanvasGlue::drawPoints}, - {"native_drawLines", "(J[FIIJ)V", (void*) SkCanvasGlue::drawLines}, - {"native_drawLine","(JFFFFJ)V", (void*) SkCanvasGlue::drawLine__FFFFPaint}, - {"native_drawRect","(JFFFFJ)V", (void*) SkCanvasGlue::drawRect__FFFFPaint}, - {"native_drawOval","(JFFFFJ)V", (void*) SkCanvasGlue::drawOval}, - {"native_drawCircle","(JFFFJ)V", (void*) SkCanvasGlue::drawCircle}, - {"native_drawArc","(JFFFFFFZJ)V", (void*) SkCanvasGlue::drawArc}, - {"native_drawRoundRect","(JFFFFFFJ)V", - (void*) SkCanvasGlue::drawRoundRect}, - {"native_drawPath","(JJJ)V", (void*) SkCanvasGlue::drawPath}, - {"native_drawBitmap","(JJFFJIII)V", - (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint}, - {"native_drawBitmap","(JJLandroid/graphics/Rect;Landroid/graphics/RectF;JII)V", - (void*) SkCanvasGlue::drawBitmapRF}, - {"native_drawBitmap","(JJLandroid/graphics/Rect;Landroid/graphics/Rect;JII)V", - (void*) SkCanvasGlue::drawBitmapRR}, - {"native_drawBitmap", "(J[IIIFFIIZJ)V", - (void*)SkCanvasGlue::drawBitmapArray}, - {"nativeDrawBitmapMatrix", "(JJJJ)V", - (void*)SkCanvasGlue::drawBitmapMatrix}, - {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", - (void*)SkCanvasGlue::drawBitmapMesh}, - {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", - (void*)SkCanvasGlue::drawVertices}, - {"native_drawText","(J[CIIFFIJJ)V", - (void*) SkCanvasGlue::drawText___CIIFFIPaintTypeface}, - {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", - (void*) SkCanvasGlue::drawText__StringIIFFIPaintTypeface}, - {"native_drawTextRun","(J[CIIIIFFZJJ)V", - (void*) SkCanvasGlue::drawTextRun___CIIIIFFZPaintTypeface}, - {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", - (void*) SkCanvasGlue::drawTextRun__StringIIIIFFZPaintTypeface}, - {"native_drawTextOnPath","(J[CIIJFFIJJ)V", - (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint}, - {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", - (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, - - {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}, - - {"freeTextLayoutCaches", "()V", (void*) SkCanvasGlue::freeTextLayoutCaches} -}; - -/////////////////////////////////////////////////////////////////////////////// - -#include <android_runtime/AndroidRuntime.h> - -#define REG(env, name, array) \ - result = android::AndroidRuntime::registerNativeMethods(env, name, array, \ - SK_ARRAY_COUNT(array)); \ - if (result < 0) return result - -int register_android_graphics_Canvas(JNIEnv* env) { - int result; - - REG(env, "android/graphics/Canvas", gCanvasMethods); - - return result; -} - -} // namespace android - -// GraphicsJNI helper for external clients. -// We keep the implementation here to avoid exposing NativeCanvasWrapper -// externally. -SkCanvas* GraphicsJNI::getNativeCanvas(jlong nativeHandle) { - return android::SkCanvasGlue::getNativeCanvas(nativeHandle); -} diff --git a/core/jni/android/graphics/Canvas.h b/core/jni/android/graphics/Canvas.h new file mode 100644 index 0000000..710845d --- /dev/null +++ b/core/jni/android/graphics/Canvas.h @@ -0,0 +1,137 @@ +/* + * 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_GRAPHICS_CANVAS_H +#define ANDROID_GRAPHICS_CANVAS_H + +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkMatrix.h" + +namespace android { + +// TODO: move this further up the stack so that all interaction with minikin +// happens prior to calling into this interface +class TypefaceImpl; + +class Canvas { +public: + virtual ~Canvas() {}; + + static Canvas* create_canvas(SkBitmap* bitmap); + static Canvas* create_canvas(SkCanvas* skiaCanvas); + + // TODO: enable HWUI to either create similar canvas wrapper or subclass + // directly from Canvas + //static Canvas* create_canvas(uirenderer::Renderer* renderer); + + // TODO: this is a temporary affordance until all necessary logic can be + // moved within this interface! Further, the return value should + // NOT be unref'd and is valid until this canvas is destroyed or a + // new bitmap is set. + virtual SkCanvas* getSkCanvas() = 0; + + virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0; + + virtual bool isOpaque() = 0; + virtual int width() = 0; + virtual int height() = 0; + +// ---------------------------------------------------------------------------- +// Canvas state operations +// ---------------------------------------------------------------------------- + // Save (layer) + virtual int getSaveCount() const = 0; + virtual int save(SkCanvas::SaveFlags flags) = 0; + virtual void restore() = 0; + virtual void restoreToCount(int saveCount) = 0; + + virtual int saveLayer(float left, float top, float right, float bottom, + const SkPaint* paint, SkCanvas::SaveFlags flags) = 0; + virtual int saveLayerAlpha(float left, float top, float right, float bottom, + int alpha, SkCanvas::SaveFlags flags) = 0; + + // Matrix + virtual void getMatrix(SkMatrix* outMatrix) const = 0; + virtual void setMatrix(const SkMatrix& matrix) = 0; + + virtual void concat(const SkMatrix& matrix) = 0; + virtual void rotate(float degrees) = 0; + virtual void scale(float sx, float sy) = 0; + virtual void skew(float sx, float sy) = 0; + virtual void translate(float dx, float dy) = 0; + + // clip + virtual bool getClipBounds(SkRect* outRect) const = 0; + virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0; + virtual bool quickRejectPath(const SkPath& path) const = 0; + + virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0; + virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0; + virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0; + + // filters + virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0; + +// ---------------------------------------------------------------------------- +// Canvas draw operations +// ---------------------------------------------------------------------------- + virtual void drawColor(int color, SkXfermode::Mode mode) = 0; + virtual void drawPaint(const SkPaint& paint) = 0; + + // Geometry + virtual void drawPoint(float x, float y, const SkPaint& paint) = 0; + virtual void drawPoints(const float* points, int count, const SkPaint& paint) = 0; + virtual void drawLine(float startX, float startY, float stopX, float stopY, + const SkPaint& paint) = 0; + virtual void drawLines(const float* points, int count, const SkPaint& paint) = 0; + virtual void drawRect(float left, float top, float right, float bottom, + const SkPaint& paint) = 0; + virtual void drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, const SkPaint& paint) = 0; + virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0; + virtual void drawOval(float left, float top, float right, float bottom, + const SkPaint& paint) = 0; + virtual void drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0; + virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0; + virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, + const float* verts, const float* tex, const int* colors, + const uint16_t* indices, int indexCount, const SkPaint& paint) = 0; + + // Bitmap-based + virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, + const SkPaint* paint) = 0; + virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, + const SkPaint* paint) = 0; + virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint) = 0; + virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, + const float* vertices, const int* colors, const SkPaint* paint) = 0; + + // Text + virtual void drawText(const char* text, int start, int count, int contextCount, + float x, float y, int bidiFlags, const SkPaint& paint, + TypefaceImpl* typeface) = 0; + virtual void drawPosText(const char* text, const float* positions, int count, int posCount, + const SkPaint& paint) = 0; + virtual void drawTextOnPath(const char* text, int count, const SkPath& path, + float hOffset, float vOffset, const SkPaint& paint) = 0; +}; + +}; // namespace android +#endif // ANDROID_GRAPHICS_CANVAS_H diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 5cc2b95..74be577 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -4,6 +4,7 @@ #include "JNIHelp.h" #include "GraphicsJNI.h" +#include "Canvas.h" #include "SkCanvas.h" #include "SkDevice.h" #include "SkMath.h" @@ -364,7 +365,7 @@ SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) { SkASSERT(canvas); SkASSERT(env->IsInstanceOf(canvas, gCanvas_class)); jlong canvasHandle = env->GetLongField(canvas, gCanvas_nativeInstanceID); - SkCanvas* c = getNativeCanvas(canvasHandle); + SkCanvas* c = reinterpret_cast<android::Canvas*>(canvasHandle)->getSkCanvas(); SkASSERT(c); return c; } diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 8150edf..28a6edb 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -47,7 +47,6 @@ public: static SkPoint* jpointf_to_point(JNIEnv*, jobject jpointf, SkPoint* point); static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); - static SkCanvas* getNativeCanvas(jlong nativeHandle); static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas); static SkPaint* getNativePaint(JNIEnv*, jobject paint); static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint); diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp index ab5bdb0..e82e8a6 100644 --- a/core/jni/android/graphics/NinePatch.cpp +++ b/core/jni/android/graphics/NinePatch.cpp @@ -23,6 +23,7 @@ #include <Caches.h> +#include "Canvas.h" #include "SkCanvas.h" #include "SkRegion.h" #include "GraphicsJNI.h" @@ -119,7 +120,7 @@ public: static void drawF(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRectF, jlong bitmapHandle, jlong chunkHandle, jlong paintHandle, jint destDensity, jint srcDensity) { - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle); + SkCanvas* canvas = reinterpret_cast<Canvas*>(canvasHandle)->getSkCanvas(); const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle); const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); @@ -138,7 +139,7 @@ public: static void drawI(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRect, jlong bitmapHandle, jlong chunkHandle, jlong paintHandle, jint destDensity, jint srcDensity) { - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle); + SkCanvas* canvas = reinterpret_cast<Canvas*>(canvasHandle)->getSkCanvas(); const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle); const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp index bc0c25f..d214575 100644 --- a/core/jni/android/graphics/Picture.cpp +++ b/core/jni/android/graphics/Picture.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ +#include "Canvas.h" #include "Picture.h" -#include "SkCanvas.h" #include "SkStream.h" namespace android { @@ -36,12 +36,13 @@ Picture::Picture(const Picture* src) { } } -SkCanvas* Picture::beginRecording(int width, int height) { +Canvas* Picture::beginRecording(int width, int height) { mPicture.reset(NULL); mRecorder.reset(new SkPictureRecorder); mWidth = width; mHeight = height; - return mRecorder->beginRecording(width, height, NULL, 0); + SkCanvas* canvas = mRecorder->beginRecording(width, height, NULL, 0); + return Canvas::create_canvas(canvas); } void Picture::endRecording() { @@ -93,14 +94,14 @@ void Picture::serialize(SkWStream* stream) const { } } -void Picture::draw(SkCanvas* canvas) { +void Picture::draw(Canvas* 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); + const_cast<SkPicture*>(mPicture.get())->draw(canvas->getSkCanvas()); } } diff --git a/core/jni/android/graphics/Picture.h b/core/jni/android/graphics/Picture.h index abb0403..a2e5d4a 100644 --- a/core/jni/android/graphics/Picture.h +++ b/core/jni/android/graphics/Picture.h @@ -22,14 +22,13 @@ #include "SkRefCnt.h" #include "SkTemplates.h" -class SkCanvas; -class SkPicture; -class SkPictureRecorder; class SkStream; class SkWStream; namespace android { +class Canvas; + // 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 @@ -38,7 +37,7 @@ class Picture { public: explicit Picture(const Picture* src = NULL); - SkCanvas* beginRecording(int width, int height); + Canvas* beginRecording(int width, int height); void endRecording(); @@ -50,7 +49,7 @@ public: void serialize(SkWStream* stream) const; - void draw(SkCanvas* canvas); + void draw(Canvas* canvas); private: int mWidth; diff --git a/core/jni/android/graphics/SkiaCanvas.cpp b/core/jni/android/graphics/SkiaCanvas.cpp new file mode 100644 index 0000000..5e93313 --- /dev/null +++ b/core/jni/android/graphics/SkiaCanvas.cpp @@ -0,0 +1,773 @@ +/* + * 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 "jni.h" +#include "Canvas.h" +#include "GraphicsJNI.h" +#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" + +#include <minikin/Layout.h> +#include "MinikinSkia.h" +#include "MinikinUtils.h" + +#include "TypefaceImpl.h" + +#include "unicode/ubidi.h" +#include "unicode/ushape.h" + +#include <utils/Log.h> + +namespace android { + +// Holds an SkCanvas reference plus additional native data. +class SkiaCanvas : public Canvas { +public: + SkiaCanvas(SkBitmap* bitmap); + + SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) { + SkASSERT(canvas); + } + + virtual SkCanvas* getSkCanvas() { + return mCanvas.get(); + } + + virtual void setBitmap(SkBitmap* bitmap, bool copyState); + + virtual bool isOpaque(); + virtual int width(); + virtual int height(); + + virtual int getSaveCount() const; + virtual int save(SkCanvas::SaveFlags flags); + virtual void restore(); + virtual void restoreToCount(int saveCount); + + virtual int saveLayer(float left, float top, float right, float bottom, + const SkPaint* paint, SkCanvas::SaveFlags flags); + virtual int saveLayerAlpha(float left, float top, float right, float bottom, + int alpha, SkCanvas::SaveFlags flags); + + virtual void getMatrix(SkMatrix* outMatrix) const; + virtual void setMatrix(const SkMatrix& matrix); + virtual void concat(const SkMatrix& matrix); + virtual void rotate(float degrees); + virtual void scale(float sx, float sy); + virtual void skew(float sx, float sy); + virtual void translate(float dx, float dy); + + virtual bool getClipBounds(SkRect* outRect) const; + virtual bool quickRejectRect(float left, float top, float right, float bottom) const; + virtual bool quickRejectPath(const SkPath& path) const; + virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); + virtual bool clipPath(const SkPath* path, SkRegion::Op op); + virtual bool clipRegion(const SkRegion* region, SkRegion::Op op); + + virtual void setDrawFilter(SkDrawFilter* drawFilter); + + virtual void drawColor(int color, SkXfermode::Mode mode); + virtual void drawPaint(const SkPaint& paint); + + virtual void drawPoint(float x, float y, const SkPaint& paint); + virtual void drawPoints(const float* points, int count, const SkPaint& paint); + virtual void drawLine(float startX, float startY, float stopX, float stopY, + const SkPaint& paint); + virtual void drawLines(const float* points, int count, const SkPaint& paint); + virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint); + virtual void drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, const SkPaint& paint); + virtual void drawCircle(float x, float y, float radius, const SkPaint& paint); + virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint); + virtual void drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint); + virtual void drawPath(const SkPath& path, const SkPaint& paint); + virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, + const float* verts, const float* tex, const int* colors, + const uint16_t* indices, int indexCount, const SkPaint& paint); + + virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint); + virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint); + virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint); + virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, + const float* vertices, const int* colors, const SkPaint* paint); + + virtual void drawText(const char* text, int start, int count, int contextCount, + float x, float y, int bidiFlags, const SkPaint& paint, TypefaceImpl* typeface); + virtual void drawPosText(const char* text, const float* positions, int count, int posCount, + const SkPaint& paint); + virtual void drawTextOnPath(const char* text, int count, const SkPath& path, + float hOffset, float vOffset, const SkPaint& paint); + +private: + struct SaveRec { + int saveCount; + SkCanvas::SaveFlags saveFlags; + }; + + void recordPartialSave(SkCanvas::SaveFlags flags); + void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount); + void applyClips(const SkTArray<SkClipStack::Element>& clips); + + void drawPoints(const float* points, int count, const SkPaint& paint, + SkCanvas::PointMode mode); + void drawTextDecorations(float x, float y, float length, const SkPaint& paint); + + SkAutoTUnref<SkCanvas> mCanvas; + SkAutoTDelete<SkDeque> mSaveStack; // lazily allocated, tracks partial saves. +}; + +// Construct an SkCanvas from the bitmap. +static SkCanvas* createCanvas(SkBitmap* bitmap) { + if (bitmap) { + return SkNEW_ARGS(SkCanvas, (*bitmap)); + } + + // Create an empty bitmap device to prevent callers from crashing + // if they attempt to draw into this canvas. + SkBitmap emptyBitmap; + return new SkCanvas(emptyBitmap); +} + +Canvas* Canvas::create_canvas(SkBitmap* bitmap) { + return new SkiaCanvas(bitmap); +} + +Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) { + return new SkiaCanvas(skiaCanvas); +} + +SkiaCanvas::SkiaCanvas(SkBitmap* bitmap) { + mCanvas.reset(createCanvas(bitmap)); +} + +// ---------------------------------------------------------------------------- +// Canvas state operations: Replace Bitmap +// ---------------------------------------------------------------------------- + +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; +}; + +void SkiaCanvas::setBitmap(SkBitmap* bitmap, bool copyState) { + SkCanvas* newCanvas = createCanvas(bitmap); + SkASSERT(newCanvas); + + if (copyState) { + // Copy the canvas matrix & clip state. + newCanvas->setMatrix(mCanvas->getTotalMatrix()); + if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) { + ClipCopier copier(newCanvas); + mCanvas->replayClips(&copier); + } + } + + // unrefs the existing canvas + mCanvas.reset(newCanvas); + + // clean up the old save stack + mSaveStack.reset(NULL); +} + +// ---------------------------------------------------------------------------- +// Canvas state operations +// ---------------------------------------------------------------------------- + +bool SkiaCanvas::isOpaque() { + return mCanvas->getDevice()->accessBitmap(false).isOpaque(); +} + +int SkiaCanvas::width() { + return mCanvas->getBaseLayerSize().width(); +} + +int SkiaCanvas::height() { + return mCanvas->getBaseLayerSize().height(); +} + +// ---------------------------------------------------------------------------- +// Canvas state operations: Save (layer) +// ---------------------------------------------------------------------------- + +int SkiaCanvas::getSaveCount() const { + return mCanvas->getSaveCount(); +} + +int SkiaCanvas::save(SkCanvas::SaveFlags flags) { + int count = mCanvas->save(); + recordPartialSave(flags); + return count; +} + +void SkiaCanvas::restore() { + const SaveRec* rec = (NULL == mSaveStack.get()) + ? 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; + } + + 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(); +} + +void SkiaCanvas::restoreToCount(int restoreCount) { + while (mCanvas->getSaveCount() > restoreCount) { + this->restore(); + } +} + +int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, + const SkPaint* paint, SkCanvas::SaveFlags flags) { + SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); + int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag); + recordPartialSave(flags); + return count; +} + +int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, + int alpha, SkCanvas::SaveFlags flags) { + SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); + int count = mCanvas->saveLayerAlpha(&bounds, alpha, flags | SkCanvas::kMatrixClip_SaveFlag); + recordPartialSave(flags); + return count; +} + +// ---------------------------------------------------------------------------- +// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags) +// ---------------------------------------------------------------------------- + +void SkiaCanvas::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.get()) { + mSaveStack.reset(SkNEW_ARGS(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 SkiaCanvas::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 SkiaCanvas::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); +} + +// ---------------------------------------------------------------------------- +// Canvas state operations: Matrix +// ---------------------------------------------------------------------------- + +void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const { + *outMatrix = mCanvas->getTotalMatrix(); +} + +void SkiaCanvas::setMatrix(const SkMatrix& matrix) { + mCanvas->setMatrix(matrix); +} + +void SkiaCanvas::concat(const SkMatrix& matrix) { + mCanvas->concat(matrix); +} + +void SkiaCanvas::rotate(float degrees) { + mCanvas->rotate(degrees); +} + +void SkiaCanvas::scale(float sx, float sy) { + mCanvas->scale(sx, sy); +} + +void SkiaCanvas::skew(float sx, float sy) { + mCanvas->skew(sx, sy); +} + +void SkiaCanvas::translate(float dx, float dy) { + mCanvas->translate(dx, dy); +} + +// ---------------------------------------------------------------------------- +// Canvas state operations: Clips +// ---------------------------------------------------------------------------- + +// This function is a mirror of SkCanvas::getClipBounds except that it does +// not outset the edge of the clip to account for anti-aliasing. There is +// a skia bug to investigate pushing this logic into back into skia. +// (see https://code.google.com/p/skia/issues/detail?id=1303) +bool SkiaCanvas::getClipBounds(SkRect* outRect) const { + SkIRect ibounds; + if (!mCanvas->getClipDeviceBounds(&ibounds)) { + return false; + } + + SkMatrix inverse; + // if we can't invert the CTM, we can't return local clip bounds + if (!mCanvas->getTotalMatrix().invert(&inverse)) { + if (outRect) { + outRect->setEmpty(); + } + return false; + } + + if (NULL != outRect) { + SkRect r = SkRect::Make(ibounds); + inverse.mapRect(outRect, r); + } + return true; +} + +bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const { + SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); + return mCanvas->quickReject(bounds); +} + +bool SkiaCanvas::quickRejectPath(const SkPath& path) const { + return mCanvas->quickReject(path); +} + +bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { + SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); + mCanvas->clipRect(rect, op); + return mCanvas->isClipEmpty(); +} + +bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) { + mCanvas->clipPath(*path, op); + return mCanvas->isClipEmpty(); +} + +bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) { + SkPath rgnPath; + if (region->getBoundaryPath(&rgnPath)) { + // The region is specified in device space. + SkMatrix savedMatrix = mCanvas->getTotalMatrix(); + mCanvas->resetMatrix(); + mCanvas->clipPath(rgnPath, op); + mCanvas->setMatrix(savedMatrix); + } else { + mCanvas->clipRect(SkRect::MakeEmpty(), op); + } + return mCanvas->isClipEmpty(); +} + +// ---------------------------------------------------------------------------- +// Canvas state operations: Filters +// ---------------------------------------------------------------------------- + +void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) { + mCanvas->setDrawFilter(drawFilter); +} + +// ---------------------------------------------------------------------------- +// Canvas draw operations +// ---------------------------------------------------------------------------- + +void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) { + mCanvas->drawColor(color, mode); +} + +void SkiaCanvas::drawPaint(const SkPaint& paint) { + mCanvas->drawPaint(paint); +} + +// ---------------------------------------------------------------------------- +// Canvas draw operations: Geometry +// ---------------------------------------------------------------------------- + +void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint, + SkCanvas::PointMode mode) { + // convert the floats into SkPoints + count >>= 1; // now it is the number of points + SkAutoSTMalloc<32, SkPoint> storage(count); + SkPoint* pts = storage.get(); + for (int i = 0; i < count; i++) { + pts[i].set(points[0], points[1]); + points += 2; + } + mCanvas->drawPoints(mode, count, pts, paint); +} + + +void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) { + mCanvas->drawPoint(x, y, paint); +} + +void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { + this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode); +} + +void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, + const SkPaint& paint) { + mCanvas->drawLine(startX, startY, stopX, stopY, paint); +} + +void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) { + this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode); +} + +void SkiaCanvas::drawRect(float left, float top, float right, float bottom, + const SkPaint& paint) { + mCanvas->drawRectCoords(left, top, right, bottom, paint); + +} + +void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, const SkPaint& paint) { + SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); + mCanvas->drawRoundRect(rect, rx, ry, paint); +} + +void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { + mCanvas->drawCircle(x, y, radius, paint); +} + +void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { + SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); + mCanvas->drawOval(oval, paint); +} + +void SkiaCanvas::drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) { + SkRect arc = SkRect::MakeLTRB(left, top, right, bottom); + mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint); +} + +void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) { + mCanvas->drawPath(path, paint); +} + +void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, + const float* verts, const float* texs, const int* colors, + const uint16_t* indices, int indexCount, const SkPaint& paint) { +#ifndef SK_SCALAR_IS_FLOAT + SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); +#endif + const int ptCount = vertexCount >> 1; + mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs, + (SkColor*)colors, NULL, indices, indexCount, paint); +} + +// ---------------------------------------------------------------------------- +// Canvas draw operations: Bitmaps +// ---------------------------------------------------------------------------- + +void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) { + mCanvas->drawBitmap(bitmap, left, top, paint); +} + +void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { + mCanvas->drawBitmapMatrix(bitmap, matrix, paint); +} + +void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint) { + SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); + SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); + mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint); +} + +void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, + const float* vertices, const int* colors, const SkPaint* paint) { + + const int ptCount = (meshWidth + 1) * (meshHeight + 1); + const int indexCount = meshWidth * meshHeight * 6; + + /* Our temp storage holds 2 or 3 arrays. + texture points [ptCount * sizeof(SkPoint)] + optionally vertex points [ptCount * sizeof(SkPoint)] if we need a + copy to convert from float to fixed + indices [ptCount * sizeof(uint16_t)] + */ + ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] + storageSize += indexCount * sizeof(uint16_t); // indices[] + + +#ifndef SK_SCALAR_IS_FLOAT + SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); +#endif + SkAutoMalloc storage(storageSize); + SkPoint* texs = (SkPoint*)storage.get(); + uint16_t* indices = (uint16_t*)(texs + ptCount); + + // cons up texture coordinates and indices + { + const SkScalar w = SkIntToScalar(bitmap.width()); + const SkScalar h = SkIntToScalar(bitmap.height()); + const SkScalar dx = w / meshWidth; + const SkScalar dy = h / meshHeight; + + SkPoint* texsPtr = texs; + SkScalar y = 0; + for (int i = 0; i <= meshHeight; i++) { + if (i == meshHeight) { + y = h; // to ensure numerically we hit h exactly + } + SkScalar x = 0; + for (int j = 0; j < meshWidth; j++) { + texsPtr->set(x, y); + texsPtr += 1; + x += dx; + } + texsPtr->set(w, y); + texsPtr += 1; + y += dy; + } + SkASSERT(texsPtr - texs == ptCount); + } + + // cons up indices + { + uint16_t* indexPtr = indices; + int index = 0; + for (int i = 0; i < meshHeight; i++) { + for (int j = 0; j < meshWidth; j++) { + // lower-left triangle + *indexPtr++ = index; + *indexPtr++ = index + meshWidth + 1; + *indexPtr++ = index + meshWidth + 2; + // upper-right triangle + *indexPtr++ = index; + *indexPtr++ = index + meshWidth + 2; + *indexPtr++ = index + 1; + // bump to the next cell + index += 1; + } + // bump to the next row + index += 1; + } + SkASSERT(indexPtr - indices == indexCount); + SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); + } + + // double-check that we have legal indices +#ifdef SK_DEBUG + { + for (int i = 0; i < indexCount; i++) { + SkASSERT((unsigned)indices[i] < (unsigned)ptCount); + } + } +#endif + + // cons-up a shader for the bitmap + SkPaint tmpPaint; + if (paint) { + tmpPaint = *paint; + } + SkShader* shader = SkShader::CreateBitmapShader(bitmap, + SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode); + SkSafeUnref(tmpPaint.setShader(shader)); + + mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices, + texs, (const SkColor*)colors, NULL, indices, + indexCount, tmpPaint); +} + +// ---------------------------------------------------------------------------- +// Canvas draw operations: Text +// ---------------------------------------------------------------------------- + +class DrawTextFunctor { +public: + DrawTextFunctor(const Layout& layout, SkCanvas* canvas, float x, float y, SkPaint* paint, + uint16_t* glyphs, SkPoint* pos) + : layout(layout), canvas(canvas), x(x), y(y), paint(paint), glyphs(glyphs), + pos(pos) { } + + void operator()(size_t start, size_t end) { + for (size_t i = start; i < end; i++) { + glyphs[i] = layout.getGlyphId(i); + pos[i].fX = x + layout.getX(i); + pos[i].fY = y + layout.getY(i); + } + canvas->drawPosText(glyphs + start, (end - start) << 1, pos + start, *paint); + } +private: + const Layout& layout; + SkCanvas* canvas; + float x; + float y; + SkPaint* paint; + uint16_t* glyphs; + SkPoint* pos; +}; + +void SkiaCanvas::drawText(const char* text, int start, int count, int contextCount, + float x, float y, int bidiFlags, const SkPaint& paint, TypefaceImpl* typeface) { + Layout layout; + std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface); + layout.doLayout((uint16_t*)text, start, count, contextCount, css); + + size_t nGlyphs = layout.nGlyphs(); + uint16_t* glyphs = new uint16_t[nGlyphs]; + SkPoint* pos = new SkPoint[nGlyphs]; + + SkPaint paintCopy(paint); + x += MinikinUtils::xOffsetForTextAlign(&paintCopy, layout); + paintCopy.setTextAlign(SkPaint::kLeft_Align); + paintCopy.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + + DrawTextFunctor f(layout, mCanvas, x, y, &paintCopy, glyphs, pos); + MinikinUtils::forFontRun(layout, &paintCopy, f); + drawTextDecorations(x, y, layout.getAdvance(), paintCopy); + + delete[] glyphs; + delete[] pos; +} + +// Same values used by Skia +#define kStdStrikeThru_Offset (-6.0f / 21.0f) +#define kStdUnderline_Offset (1.0f / 9.0f) +#define kStdUnderline_Thickness (1.0f / 18.0f) + +void SkiaCanvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { + uint32_t flags; + SkDrawFilter* drawFilter = mCanvas->getDrawFilter(); + if (drawFilter) { + SkPaint paintCopy(paint); + drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); + flags = paintCopy.getFlags(); + } else { + flags = paint.getFlags(); + } + if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { + SkScalar left = x; + SkScalar right = x + length; + float textSize = paint.getTextSize(); + float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); + if (flags & SkPaint::kUnderlineText_Flag) { + SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; + SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; + mCanvas->drawRectCoords(left, top, right, bottom, paint); + } + if (flags & SkPaint::kStrikeThruText_Flag) { + SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; + SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; + mCanvas->drawRectCoords(left, top, right, bottom, paint); + } + } +} + +void SkiaCanvas::drawPosText(const char* text, const float* positions, int count, int posCount, + const SkPaint& paint) { + SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; + int indx; + for (indx = 0; indx < posCount; indx++) { + posPtr[indx].fX = positions[indx << 1]; + posPtr[indx].fY = positions[(indx << 1) + 1]; + } + + SkPaint paintCopy(paint); + paintCopy.setTextEncoding(SkPaint::kUTF16_TextEncoding); + mCanvas->drawPosText(text, count, posPtr, paintCopy); + + delete[] posPtr; +} + +void SkiaCanvas::drawTextOnPath(const char* text, int count, const SkPath& path, + float hOffset, float vOffset, const SkPaint& paint) { + mCanvas->drawTextOnPathHV(text, count, path, hOffset, vOffset, paint); +} + +} // namespace android diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp index 3812c27..9436a47 100644 --- a/core/jni/android/graphics/pdf/PdfDocument.cpp +++ b/core/jni/android/graphics/pdf/PdfDocument.cpp @@ -19,9 +19,9 @@ #include <android_runtime/AndroidRuntime.h> #include <vector> +#include "Canvas.h" #include "CreateJavaOutputStreamAdaptor.h" -#include "SkCanvas.h" #include "SkDocument.h" #include "SkPicture.h" #include "SkPictureRecorder.h" @@ -132,8 +132,9 @@ static jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr, jint pageWidth, jint pageHeight, jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) { PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); - return reinterpret_cast<jlong>(document->startPage(pageWidth, pageHeight, - contentLeft, contentTop, contentRight, contentBottom)); + SkCanvas* canvas = document->startPage(pageWidth, pageHeight, + contentLeft, contentTop, contentRight, contentBottom); + return reinterpret_cast<jlong>(Canvas::create_canvas(canvas)); } static void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) { diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp new file mode 100644 index 0000000..fd96a90 --- /dev/null +++ b/core/jni/android_graphics_Canvas.cpp @@ -0,0 +1,653 @@ +/* + * 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 "jni.h" +#include "GraphicsJNI.h" +#include <android_runtime/AndroidRuntime.h> + +#include "Canvas.h" +#include "SkGraphics.h" +#include "SkPorterDuff.h" +#include "TypefaceImpl.h" + +#include <minikin/Layout.h> +#include "MinikinSkia.h" +#include "MinikinUtils.h" + +namespace android { + +namespace CanvasJNI { + +static Canvas* get_canvas(jlong canvasHandle) { + return reinterpret_cast<Canvas*>(canvasHandle); +} + +static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) { + delete get_canvas(canvasHandle); +} + +// Native wrapper constructor used by Canvas(Bitmap) +static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap)); +} + +// Set the given bitmap as the new draw target (wrapped in a new SkCanvas), +// optionally copying canvas matrix & clip state. +static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, + jboolean copyState) { + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + get_canvas(canvasHandle)->setBitmap(bitmap, copyState); +} + +static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) { + return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE; +} + +static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) { + return static_cast<jint>(get_canvas(canvasHandle)->width()); +} + +static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) { + return static_cast<jint>(get_canvas(canvasHandle)->height()); +} + +static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) { + return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount()); +} + +static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) { + SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); + return static_cast<jint>(get_canvas(canvasHandle)->save(flags)); +} + +static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t, + jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); + return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags)); +} + +static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t, + jfloat r, jfloat b, jint alpha, jint flagsHandle) { + SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); + return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags)); +} + +static void restore(JNIEnv* env, jobject, jlong canvasHandle) { + Canvas* canvas = get_canvas(canvasHandle); + if (canvas->getSaveCount() <= 1) { // cannot restore anymore + doThrowISE(env, "Underflow in restore"); + return; + } + canvas->restore(); +} + +static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount) { + Canvas* canvas = get_canvas(canvasHandle); + if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) { + doThrowIAE(env, "Underflow in restoreToCount"); + return; + } + canvas->restoreToCount(restoreCount); +} + +static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { + SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); + get_canvas(canvasHandle)->getMatrix(matrix); +} + +static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { + const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); + get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I()); +} + +static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { + const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); + get_canvas(canvasHandle)->concat(*matrix); +} + +static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) { + get_canvas(canvasHandle)->rotate(degrees); +} + +static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) { + get_canvas(canvasHandle)->scale(sx, sy); +} + +static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) { + get_canvas(canvasHandle)->skew(sx, sy); +} + +static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) { + get_canvas(canvasHandle)->translate(dx, dy); +} + +static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) { + SkRect r; + SkIRect ir; + bool result = get_canvas(canvasHandle)->getClipBounds(&r); + + if (!result) { + r.setEmpty(); + } + r.round(&ir); + + (void)GraphicsJNI::irect_to_jrect(ir, env, bounds); + return result ? JNI_TRUE : JNI_FALSE; +} + +static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle, + jfloat left, jfloat top, jfloat right, jfloat bottom) { + bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom); + return result ? JNI_TRUE : JNI_FALSE; +} + +static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) { + SkPath* path = reinterpret_cast<SkPath*>(pathHandle); + bool result = get_canvas(canvasHandle)->quickRejectPath(*path); + return result ? JNI_TRUE : JNI_FALSE; +} + +static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t, + jfloat r, jfloat b, jint opHandle) { + SkRegion::Op op = static_cast<SkRegion::Op>(opHandle); + bool emptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, op); + return emptyClip ? JNI_FALSE : JNI_TRUE; +} + +static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle, + jint opHandle) { + SkPath* path = reinterpret_cast<SkPath*>(pathHandle); + SkRegion::Op op = static_cast<SkRegion::Op>(opHandle); + bool emptyClip = get_canvas(canvasHandle)->clipPath(path, op); + return emptyClip ? JNI_FALSE : JNI_TRUE; +} + +static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle, + jint opHandle) { + SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle); + SkRegion::Op op = static_cast<SkRegion::Op>(opHandle); + bool emptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, op); + return emptyClip ? JNI_FALSE : JNI_TRUE; +} + +static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) { + SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle); + get_canvas(canvasHandle)->drawColor(color, SkPorterDuff::ToXfermodeMode(mode)); +} + +static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawPaint(*paint); +} + +static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y, + jlong paintHandle) { + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawPoint(x, y, *paint); +} + +static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray, + jint offset, jint count, jlong paintHandle) { + NPE_CHECK_RETURN_VOID(env, jptsArray); + AutoJavaFloatArray autoPts(env, jptsArray); + float* floats = autoPts.ptr(); + const int length = autoPts.length(); + + if ((offset | count) < 0 || offset + count > length) { + doThrowAIOOBE(env); + return; + } + + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint); +} + +static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY, + jfloat stopX, jfloat stopY, jlong paintHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint); +} + +static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray, + jint offset, jint count, jlong paintHandle) { + NPE_CHECK_RETURN_VOID(env, jptsArray); + AutoJavaFloatArray autoPts(env, jptsArray); + float* floats = autoPts.ptr(); + const int length = autoPts.length(); + + if ((offset | count) < 0 || offset + count > length) { + doThrowAIOOBE(env); + return; + } + + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint); +} + +static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jlong paintHandle) { + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint); +} + +static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) { + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint); +} + +static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy, + jfloat radius, jlong paintHandle) { + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint); +} + +static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jlong paintHandle) { + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint); +} + +static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, + jboolean useCenter, jlong paintHandle) { + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle, + useCenter, *paint); +} + +static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle, + jlong paintHandle) { + const SkPath* path = reinterpret_cast<SkPath*>(pathHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawPath(*path, *paint); +} + +static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle, + jint modeHandle, jint vertexCount, + jfloatArray jverts, jint vertIndex, + jfloatArray jtexs, jint texIndex, + jintArray jcolors, jint colorIndex, + jshortArray jindices, jint indexIndex, + jint indexCount, jlong paintHandle) { + AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); + AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); + AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); + AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); + + const float* verts = vertA.ptr() + vertIndex; + const float* texs = texA.ptr() + vertIndex; + const int* colors = NULL; + const uint16_t* indices = NULL; + + if (jcolors != NULL) { + colors = colorA.ptr() + colorIndex; + } + if (jindices != NULL) { + indices = (const uint16_t*)(indexA.ptr() + indexIndex); + } + + SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors, + indices, indexCount, *paint); +} + +static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jlong bitmapHandle, + jfloat left, jfloat top, jlong paintHandle, jint canvasDensity, + jint screenDensity, jint bitmapDensity) { + Canvas* canvas = get_canvas(canvasHandle); + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + + if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) { + if (screenDensity != 0 && screenDensity != bitmapDensity) { + SkPaint filteredPaint; + if (paint) { + filteredPaint = *paint; + } + filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); + canvas->drawBitmap(*bitmap, left, top, &filteredPaint); + } else { + canvas->drawBitmap(*bitmap, left, top, paint); + } + } else { + canvas->save(SkCanvas::kMatrixClip_SaveFlag); + SkScalar scale = canvasDensity / (float)bitmapDensity; + canvas->translate(left, top); + canvas->scale(scale, scale); + + SkPaint filteredPaint; + if (paint) { + filteredPaint = *paint; + } + filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); + + canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint); + canvas->restore(); + } +} + +static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, + jlong matrixHandle, jlong paintHandle) { + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawBitmap(*bitmap, *matrix, paint); +} + +static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, + float srcLeft, float srcTop, float srcRight, float srcBottom, + float dstLeft, float dstTop, float dstRight, float dstBottom, + jlong paintHandle, jint screenDensity, jint bitmapDensity) { + Canvas* canvas = get_canvas(canvasHandle); + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + + if (screenDensity != 0 && screenDensity != bitmapDensity) { + SkPaint filteredPaint; + if (paint) { + filteredPaint = *paint; + } + filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); + canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom, + dstLeft, dstTop, dstRight, dstBottom, &filteredPaint); + } else { + canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom, + dstLeft, dstTop, dstRight, dstBottom, paint); + } +} + +static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle, + jintArray jcolors, jint offset, jint stride, + jfloat x, jfloat y, jint width, jint height, + jboolean hasAlpha, jlong paintHandle) { + // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will + // correct the alphaType to kOpaque_SkAlphaType. + SkImageInfo info = SkImageInfo::Make(width, height, + hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType, + kPremul_SkAlphaType); + SkBitmap bitmap; + if (!bitmap.allocPixels(info)) { + return; + } + + if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) { + return; + } + + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint); +} + +static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, + jint meshWidth, jint meshHeight, jfloatArray jverts, + jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) { + const int ptCount = (meshWidth + 1) * (meshHeight + 1); + AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1)); + AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount); + + const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + get_canvas(canvasHandle)->drawBitmapMesh(*bitmap, meshWidth, meshHeight, + vertA.ptr(), colorA.ptr(), paint); +} + +static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, + jint index, jint count, jfloat x, jfloat y, jint bidiFlags, + jlong paintHandle, jlong typefaceHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + jchar* jchars = env->GetCharArrayElements(text, NULL); + const char* textArray = reinterpret_cast<const char*>(jchars) + index; + get_canvas(canvasHandle)->drawText(textArray, 0, count, count, x, y, bidiFlags, *paint, typeface); + env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); +} + +static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, + jint start, jint end, jfloat x, jfloat y, jint bidiFlags, + jlong paintHandle, jlong typefaceHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + const int count = end - start; + const jchar* jchars = env->GetStringChars(text, NULL); + const char* textArray = reinterpret_cast<const char*>(jchars) + start; + get_canvas(canvasHandle)->drawText(textArray, 0, count, count, x, y, bidiFlags, *paint, typeface); + env->ReleaseStringChars(text, jchars); +} + +static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, + jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y, + jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + + const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; + jchar* jchars = env->GetCharArrayElements(text, NULL); + const char* textArray = reinterpret_cast<const char*>(jchars) + contextIndex; + get_canvas(canvasHandle)->drawText(textArray, index - contextIndex, count, contextCount, + x, y, bidiFlags, *paint, typeface); + env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); +} + +static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, + jint start, jint end, jint contextStart, jint contextEnd, + jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, + jlong typefaceHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; + jint count = end - start; + jint contextCount = contextEnd - contextStart; + const jchar* jchars = env->GetStringChars(text, NULL); + const char* textArray = reinterpret_cast<const char*>(jchars) + contextStart; + get_canvas(canvasHandle)->drawText(textArray, start - contextStart, count, contextCount, + x, y, bidiFlags, *paint, typeface); + env->ReleaseStringChars(text, jchars); +} + +static void drawPosTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, + jint index, jint count, jfloatArray pos, jlong paintHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + jchar* jchars = text ? env->GetCharArrayElements(text, NULL) : NULL; + float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; + int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; + + const char* textArray = reinterpret_cast<const char*>(jchars) + index; + get_canvas(canvasHandle)->drawPosText(textArray, posArray, count << 1, posCount, *paint); + + if (text) { + env->ReleaseCharArrayElements(text, jchars, 0); + } + if (pos) { + env->ReleaseFloatArrayElements(pos, posArray, 0); + } +} + + +static void drawPosTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, + jfloatArray pos, jlong paintHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + const jchar* jchars = text ? env->GetStringChars(text, NULL) : NULL; + int byteLength = text ? env->GetStringLength(text) : 0; + float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; + int posCount = pos ? env->GetArrayLength(pos) >> 1: 0; + + const char* textArray = reinterpret_cast<const char*>(jchars); + get_canvas(canvasHandle)->drawPosText(textArray , posArray, byteLength << 1, posCount, *paint); + + if (text) { + env->ReleaseStringChars(text, jchars); + } + if (pos) { + env->ReleaseFloatArrayElements(pos, posArray, 0); + } +} + +class DrawTextOnPathFunctor { +public: + DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset, + float vOffset, const SkPaint& paint, const SkPath& path) + : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset), + paint(paint), path(path) { + } + void operator()(size_t start, size_t end) { + uint16_t glyphs[1]; + for (size_t i = start; i < end; i++) { + glyphs[0] = layout.getGlyphId(i); + float x = hOffset + layout.getX(i); + float y = vOffset + layout.getY(i); + canvas->drawTextOnPath((const char*) glyphs, 1, path, x, y, paint); + } + } +private: + const Layout& layout; + Canvas* canvas; + float hOffset; + float vOffset; + const SkPaint& paint; + const SkPath& path; +}; + +static void drawTextOnPath(Canvas* canvas, const char* text, int count, int bidiFlags, + const SkPath& path, float hOffset, float vOffset, + const SkPaint& paint, TypefaceImpl* typeface) { + SkPaint paintCopy(paint); + Layout layout; + std::string css = MinikinUtils::setLayoutProperties(&layout, &paintCopy, bidiFlags, typeface); + layout.doLayout((uint16_t*)text, 0, count, count, css); + hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); + + // Set align to left for drawing, as we don't want individual + // glyphs centered or right-aligned; the offset above takes + // care of all alignment. + paintCopy.setTextAlign(SkPaint::kLeft_Align); + + DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path); + MinikinUtils::forFontRun(layout, &paintCopy, f); +} + +static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, + jint index, jint count, jlong pathHandle, jfloat hOffset, + jfloat vOffset, jint bidiFlags, jlong paintHandle, + jlong typefaceHandle) { + SkPath* path = reinterpret_cast<SkPath*>(pathHandle); + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + + jchar* jchars = env->GetCharArrayElements(text, NULL); + const char* textArray = reinterpret_cast<const char*>(jchars); + + drawTextOnPath(get_canvas(canvasHandle), textArray + index, count, bidiFlags, *path, + hOffset, vOffset, *paint, typeface); + + env->ReleaseCharArrayElements(text, jchars, 0); +} + +static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text, + jlong pathHandle, jfloat hOffset, jfloat vOffset, + jint bidiFlags, jlong paintHandle, jlong typefaceHandle) { + SkPath* path = reinterpret_cast<SkPath*>(pathHandle); + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + + const jchar* jchars = env->GetStringChars(text, NULL); + const char* textArray = reinterpret_cast<const char*>(jchars); + int count = env->GetStringLength(text); + + drawTextOnPath(get_canvas(canvasHandle), textArray, count, bidiFlags, *path, + hOffset, vOffset, *paint, typeface); + + env->ReleaseStringChars(text, jchars); +} + +static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) { + get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle)); +} + +static void freeCaches(JNIEnv* env, jobject) { + SkGraphics::PurgeFontCache(); +} + +static void freeTextLayoutCaches(JNIEnv* env, jobject) { + Layout::purgeCaches(); +} + +}; // namespace CanvasJNI + +static JNINativeMethod gMethods[] = { + {"finalizer", "(J)V", (void*) CanvasJNI::finalizer}, + {"initRaster", "(J)J", (void*) CanvasJNI::initRaster}, + {"native_setBitmap", "(JJZ)V", (void*) CanvasJNI::setBitmap}, + {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque}, + {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth}, + {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight}, + {"native_save","(JI)I", (void*) CanvasJNI::save}, + {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer}, + {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha}, + {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount}, + {"native_restore","(J)V", (void*) CanvasJNI::restore}, + {"native_restoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount}, + {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM}, + {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix}, + {"native_concat","(JJ)V", (void*) CanvasJNI::concat}, + {"native_rotate","(JF)V", (void*) CanvasJNI::rotate}, + {"native_scale","(JFF)V", (void*) CanvasJNI::scale}, + {"native_skew","(JFF)V", (void*) CanvasJNI::skew}, + {"native_translate","(JFF)V", (void*) CanvasJNI::translate}, + {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds}, + {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath}, + {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect}, + {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect}, + {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath}, + {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion}, + {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor}, + {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint}, + {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint}, + {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints}, + {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine}, + {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines}, + {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect}, + {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect}, + {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle}, + {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval}, + {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc}, + {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath}, + {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices}, + {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap}, + {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix}, + {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect}, + {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray}, + {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh}, + {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars}, + {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString}, + {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars}, + {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString}, + {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars}, + {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString}, + {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter}, + {"freeCaches", "()V", (void*) CanvasJNI::freeCaches}, + {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches} +}; + +int register_android_graphics_Canvas(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, "android/graphics/Canvas", gMethods, NELEM(gMethods)); +} + +}; // namespace android diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp index f827907..eb8f6dd 100644 --- a/core/jni/android_graphics_Picture.cpp +++ b/core/jni/android_graphics_Picture.cpp @@ -51,7 +51,7 @@ static void android_graphics_Picture_killPicture(JNIEnv* env, jobject, jlong pic static void android_graphics_Picture_draw(JNIEnv* env, jobject, jlong canvasHandle, jlong pictureHandle) { - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasHandle); Picture* picture = reinterpret_cast<Picture*>(pictureHandle); SkASSERT(canvas); SkASSERT(picture); @@ -84,12 +84,7 @@ static jint android_graphics_Picture_getHeight(JNIEnv* env, jobject, jlong pictu static jlong android_graphics_Picture_beginRecording(JNIEnv* env, jobject, jlong pictHandle, jint w, jint h) { Picture* pict = reinterpret_cast<Picture*>(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 - // unref in its finalizer, so we have to ref it here, so that both that - // Canvas.java and our picture can both be owners - canvas->ref(); + Canvas* canvas = pict->beginRecording(w, h); return reinterpret_cast<jlong>(canvas); } |