Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9feab843 authored by Romain Guy's avatar Romain Guy Committed by Android (Google) Code Review
Browse files

Merge "Refcount 9-patches and properly handle GC events"

parents 7337fb46 e3b0a011
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -9156,8 +9156,11 @@ package android.graphics {
    method public void draw(android.graphics.Canvas, android.graphics.RectF);
    method public void draw(android.graphics.Canvas, android.graphics.Rect);
    method public void draw(android.graphics.Canvas, android.graphics.Rect, android.graphics.Paint);
    method public android.graphics.Bitmap getBitmap();
    method public int getDensity();
    method public int getHeight();
    method public java.lang.String getName();
    method public android.graphics.Paint getPaint();
    method public final android.graphics.Region getTransparentRegion(android.graphics.Rect);
    method public int getWidth();
    method public final boolean hasAlpha();
+3 −3
Original line number Diff line number Diff line
@@ -781,7 +781,7 @@ class GLES20Canvas extends HardwareCanvas {
        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
        try {
            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
            nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mChunk,
            nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mNativeChunk,
                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
        } finally {
            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
@@ -796,14 +796,14 @@ class GLES20Canvas extends HardwareCanvas {
        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
        try {
            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
            nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mChunk,
            nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mNativeChunk,
                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
        } finally {
            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
        }
    }

    private static native void nDrawPatch(int renderer, int bitmap, byte[] chunks,
    private static native void nDrawPatch(int renderer, int bitmap, int chunk,
            float left, float top, float right, float bottom, int paint);

    @Override
+0 −20
Original line number Diff line number Diff line
@@ -16,9 +16,7 @@

package android.view;

import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.NinePatch;

import java.util.ArrayList;

@@ -26,12 +24,6 @@ import java.util.ArrayList;
 * An implementation of display list for OpenGL ES 2.0.
 */
class GLES20DisplayList extends DisplayList {
    // These lists ensure that any Bitmaps and DisplayLists recorded by a DisplayList are kept
    // alive as long as the DisplayList is alive.  The Bitmap and DisplayList lists
    // are populated by the GLES20RecordingCanvas during appropriate drawing calls and are
    // cleared at the start of a new drawing frame or when the view is detached from the window.
    private ArrayList<Bitmap> mBitmaps;
    private ArrayList<NinePatch> mNinePatches;
    private ArrayList<DisplayList> mChildDisplayLists;

    private GLES20RecordingCanvas mCanvas;
@@ -89,21 +81,9 @@ class GLES20DisplayList extends DisplayList {
    }

    void clearReferences() {
        if (mBitmaps != null) mBitmaps.clear();
        if (mNinePatches != null) mNinePatches.clear();
        if (mChildDisplayLists != null) mChildDisplayLists.clear();
    }

    ArrayList<Bitmap> getBitmaps() {
        if (mBitmaps == null) mBitmaps = new ArrayList<Bitmap>(5);
        return mBitmaps;
    }

    ArrayList<NinePatch> getNinePatches() {
        if (mNinePatches == null) mNinePatches = new ArrayList<NinePatch>(5);
        return mNinePatches;
    }

    ArrayList<DisplayList> getChildDisplayLists() {
        if (mChildDisplayLists == null) mChildDisplayLists = new ArrayList<DisplayList>();
        return mChildDisplayLists;
+0 −220
Original line number Diff line number Diff line
@@ -16,15 +16,7 @@

package android.view;

import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Matrix;
import android.graphics.NinePatch;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.Pools.SynchronizedPool;

/**
@@ -70,222 +62,10 @@ class GLES20RecordingCanvas extends GLES20Canvas {
        return getDisplayList(nativeDisplayList);
    }

    private void recordShaderBitmap(Paint paint) {
        if (paint != null) {
            final Shader shader = paint.getShader();
            if (shader instanceof BitmapShader) {
                mDisplayList.getBitmaps().add(((BitmapShader) shader).mBitmap);
            }
        }
    }

    @Override
    public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
        super.drawPatch(patch, dst, paint);
        mDisplayList.getBitmaps().add(patch.getBitmap());
        mDisplayList.getNinePatches().add(patch);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
        super.drawBitmap(bitmap, left, top, paint);
        mDisplayList.getBitmaps().add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
        super.drawBitmap(bitmap, matrix, paint);
        mDisplayList.getBitmaps().add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
        super.drawBitmap(bitmap, src, dst, paint);
        mDisplayList.getBitmaps().add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
        super.drawBitmap(bitmap, src, dst, paint);
        mDisplayList.getBitmaps().add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width,
            int height, boolean hasAlpha, Paint paint) {
        super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
            int height, boolean hasAlpha, Paint paint) {
        super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
            int vertOffset, int[] colors, int colorOffset, Paint paint) {
        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset,
                colors, colorOffset, paint);
        mDisplayList.getBitmaps().add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawCircle(float cx, float cy, float radius, Paint paint) {
        super.drawCircle(cx, cy, radius, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
        int status = super.drawDisplayList(displayList, dirty, flags);
        mDisplayList.getChildDisplayLists().add(displayList);
        return status;
    }

    @Override
    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
        super.drawLine(startX, startY, stopX, stopY, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawLines(float[] pts, int offset, int count, Paint paint) {
        super.drawLines(pts, offset, count, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawLines(float[] pts, Paint paint) {
        super.drawLines(pts, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawOval(RectF oval, Paint paint) {
        super.drawOval(oval, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawPaint(Paint paint) {
        super.drawPaint(paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawPath(Path path, Paint paint) {
        super.drawPath(path, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawPoint(float x, float y, Paint paint) {
        super.drawPoint(x, y, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
        super.drawPoints(pts, offset, count, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawPoints(float[] pts, Paint paint) {
        super.drawPoints(pts, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
        super.drawPosText(text, index, count, pos, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawPosText(String text, float[] pos, Paint paint) {
        super.drawPosText(text, pos, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
        super.drawRect(left, top, right, bottom, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
        super.drawRoundRect(rect, rx, ry, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
        super.drawText(text, index, count, x, y, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
        super.drawText(text, start, end, x, y, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
        super.drawText(text, start, end, x, y, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawText(String text, float x, float y, Paint paint) {
        super.drawText(text, x, y, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
            float vOffset, Paint paint) {
        super.drawTextOnPath(text, index, count, path, hOffset, vOffset, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
        super.drawTextOnPath(text, path, hOffset, vOffset, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
            float x, float y, int dir, Paint paint) {
        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawTextRun(CharSequence text, int start, int end, int contextStart,
            int contextEnd, float x, float y, int dir, Paint paint) {
        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
            int indexOffset, int indexCount, Paint paint) {
        super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors,
                colorOffset, indices, indexOffset, indexCount, paint);
        recordShaderBitmap(paint);
    }
}
+89 −99
Original line number Diff line number Diff line
@@ -21,22 +21,30 @@
#include <androidfw/ResourceTypes.h>
#include <utils/Log.h>

#include <Caches.h>

#include "SkCanvas.h"
#include "SkRegion.h"
#include "GraphicsJNI.h"

#include "JNIHelp.h"

extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
                const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
                           const SkPaint* paint, SkRegion** outRegion);
extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, const SkBitmap& bitmap,
        const android::Res_png_9patch& chunk, const SkPaint* paint, SkRegion** outRegion);

using namespace android;

/**
 * IMPORTANT NOTE: 9patch chunks can be manipuated either as an array of bytes
 * or as a Res_png_9patch instance. It is important to note that the size of the
 * array required to hold a 9patch chunk is greater than sizeof(Res_png_9patch).
 * The code below manipulates chunks as Res_png_9patch* types to draw and as
 * int8_t* to allocate and free the backing storage.
 */

class SkNinePatchGlue {
public:
    static jboolean isNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj)
    {
    static jboolean isNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj) {
        if (NULL == obj) {
            return false;
        }
@@ -45,43 +53,42 @@ public:
        }
        const jbyte* array = env->GetByteArrayElements(obj, 0);
        if (array != NULL) {
            const Res_png_9patch* chunk =
                                reinterpret_cast<const Res_png_9patch*>(array);
            const Res_png_9patch* chunk = reinterpret_cast<const Res_png_9patch*>(array);
            int8_t wasDeserialized = chunk->wasDeserialized;
            env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array),
                                          JNI_ABORT);
            env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array), JNI_ABORT);
            return wasDeserialized != -1;
        }
        return false;
    }

    static void validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj)
    {
        if (env->GetArrayLength(obj) < (int) (sizeof(Res_png_9patch))) {
    static int8_t* validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj) {
        size_t chunkSize = env->GetArrayLength(obj);
        if (chunkSize < (int) (sizeof(Res_png_9patch))) {
            jniThrowRuntimeException(env, "Array too small for chunk.");
            return;
            return NULL;
        }

        int8_t* storage = new int8_t[chunkSize];
        // This call copies the content of the jbyteArray
        env->GetByteArrayRegion(obj, 0, chunkSize, reinterpret_cast<jbyte*>(storage));
        // Deserialize in place, return the array we just allocated
        return (int8_t*) Res_png_9patch::deserialize(storage);
    }

        // XXX Also check that dimensions are correct.
    static void finalize(JNIEnv* env, jobject, int8_t* patch) {
#ifdef USE_OPENGL_RENDERER
        if (android::uirenderer::Caches::hasInstance()) {
            Res_png_9patch* p = (Res_png_9patch*) patch;
            android::uirenderer::Caches::getInstance().resourceCache.destructor(p);
            return;
        }
#endif // USE_OPENGL_RENDERER
        delete[] patch;
    }

    static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
                      jint destDensity, jint srcDensity)
    {
        size_t chunkSize = env->GetArrayLength(chunkObj);
        void* storage = alloca(chunkSize);
        env->GetByteArrayRegion(chunkObj, 0, chunkSize,
                                reinterpret_cast<jbyte*>(storage));
        if (!env->ExceptionCheck()) {
            // need to deserialize the chunk
            Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
            assert(chunkSize == chunk->serializedSize());
            // this relies on deserialization being done in place
            Res_png_9patch::deserialize(chunk);

            if (destDensity == srcDensity || destDensity == 0
                    || srcDensity == 0) {
    static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, const SkBitmap* bitmap,
            Res_png_9patch* chunk, const SkPaint* paint, jint destDensity, jint srcDensity) {
        if (destDensity == srcDensity || destDensity == 0 || srcDensity == 0) {
            ALOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
                    SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
                    SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
@@ -107,65 +114,50 @@ public:
            canvas->restore();
        }
    }
    }

    static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF,
                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
                      jint destDensity, jint srcDensity)
    {
            const SkBitmap* bitmap, Res_png_9patch* chunk, const SkPaint* paint,
            jint destDensity, jint srcDensity) {
        SkASSERT(canvas);
        SkASSERT(boundsRectF);
        SkASSERT(bitmap);
        SkASSERT(chunkObj);
        SkASSERT(chunk);
        // paint is optional

        SkRect bounds;
        GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);

        draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity);
        draw(env, canvas, bounds, bitmap, chunk, paint, destDensity, srcDensity);
    }

    static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect,
                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
                      jint destDensity, jint srcDensity)
    {
            const SkBitmap* bitmap, Res_png_9patch* chunk, const SkPaint* paint,
            jint destDensity, jint srcDensity) {
        SkASSERT(canvas);
        SkASSERT(boundsRect);
        SkASSERT(bitmap);
        SkASSERT(chunkObj);
        SkASSERT(chunk);
        // paint is optional

        SkRect bounds;
        GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
        draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity);
        draw(env, canvas, bounds, bitmap, chunk, paint, destDensity, srcDensity);
    }

    static jint getTransparentRegion(JNIEnv* env, jobject,
                    const SkBitmap* bitmap, jbyteArray chunkObj,
                    jobject boundsRect)
    {
    static jint getTransparentRegion(JNIEnv* env, jobject, const SkBitmap* bitmap,
            Res_png_9patch* chunk, jobject boundsRect) {
        SkASSERT(bitmap);
        SkASSERT(chunkObj);
        SkASSERT(chunk);
        SkASSERT(boundsRect);

        SkRect bounds;
        GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
        size_t chunkSize = env->GetArrayLength(chunkObj);
        void* storage = alloca(chunkSize);
        env->GetByteArrayRegion(chunkObj, 0, chunkSize,
                                reinterpret_cast<jbyte*>(storage));
        if (!env->ExceptionCheck()) {
            // need to deserialize the chunk
            Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
            assert(chunkSize == chunk->serializedSize());
            // this relies on deserialization being done in place
            Res_png_9patch::deserialize(chunk);

        SkRegion* region = NULL;
        NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);

        return (jint) region;
    }
        return 0;
    }

};

@@ -175,17 +167,15 @@ public:

static JNINativeMethod gNinePatchMethods[] = {
    { "isNinePatchChunk", "([B)Z",                        (void*) SkNinePatchGlue::isNinePatchChunk },
    { "validateNinePatchChunk", "(I[B)V",               (void*)SkNinePatchGlue::validateNinePatchChunk   },
    { "nativeDraw", "(ILandroid/graphics/RectF;I[BIII)V", (void*)SkNinePatchGlue::drawF   },
    { "nativeDraw", "(ILandroid/graphics/Rect;I[BIII)V",  (void*)SkNinePatchGlue::drawI   },
    { "nativeGetTransparentRegion", "(I[BLandroid/graphics/Rect;)I",
    { "validateNinePatchChunk", "(I[B)I",                 (void*) SkNinePatchGlue::validateNinePatchChunk },
    { "nativeFinalize", "(I)V",                           (void*) SkNinePatchGlue::finalize },
    { "nativeDraw", "(ILandroid/graphics/RectF;IIIII)V",  (void*) SkNinePatchGlue::drawF },
    { "nativeDraw", "(ILandroid/graphics/Rect;IIIII)V",   (void*) SkNinePatchGlue::drawI },
    { "nativeGetTransparentRegion", "(IILandroid/graphics/Rect;)I",
                                                          (void*) SkNinePatchGlue::getTransparentRegion }
};

int register_android_graphics_NinePatch(JNIEnv* env)
{
int register_android_graphics_NinePatch(JNIEnv* env) {
    return android::AndroidRuntime::registerNativeMethods(env,
                                                       "android/graphics/NinePatch",
                                                       gNinePatchMethods,
                                                       SK_ARRAY_COUNT(gNinePatchMethods));
            "android/graphics/NinePatch", gNinePatchMethods, SK_ARRAY_COUNT(gNinePatchMethods));
}
Loading