欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

BaseCanvas

程序员文章站 2024-02-26 22:45:52
...

BaseCanvas 源码:

这个类是Canvas绘图操作的基类。这里的任何修改都应该伴随着类似于RecordingCanvas的修改。

这个类的目的是在常规JNI和@FastNative JNI之间降低选择的成本,使之仅限于Canvas已经拥有的虚拟调用。

/** @hide */
public abstract class BaseCanvas {
    /** 只应在构造函数(或如果是软件Canvas.setBitmap)中分配,由NativeAllocation释放。 @hide */
    protected long mNativeCanvasWrapper;

    /** 用于确定兼容性缩放何时生效。 @hide */
    protected int mScreenDensity = Bitmap.DENSITY_NONE;

    /** @hide */
    protected int mDensity = Bitmap.DENSITY_NONE;
    private boolean mAllowHwBitmapsInSwMode = false;

    protected void throwIfCannotDraw(Bitmap bitmap) {
        if (bitmap.isRecycled()) {
            throw new RuntimeException("Canvas: trying to use a recycled bitmap " + bitmap);
        }
        if (!bitmap.isPremultiplied() && bitmap.getConfig() == Bitmap.Config.ARGB_8888 &&
                bitmap.hasAlpha()) {
            throw new RuntimeException("Canvas: trying to use a non-premultiplied bitmap "
                    + bitmap);
        }
        throwIfHwBitmapInSwMode(bitmap);
    }

    protected final static void checkRange(int length, int offset, int count) {
        if ((offset | count) < 0 || offset + count > length) {
            throw new ArrayIndexOutOfBoundsException();
        }
    }

    public boolean isHardwareAccelerated() {
        return false;
    }

	/** ***************** drawXXX方法见文章下方代码段 *****************************   */
	
    /** @hide */
    public void setHwBitmapsInSwModeEnabled(boolean enabled) {
        mAllowHwBitmapsInSwMode = enabled;
    }

    /** @hide */
    public boolean isHwBitmapsInSwModeEnabled() {
        return mAllowHwBitmapsInSwMode;
    }

    /** @hide */
    protected void onHwBitmapInSwMode() {
        if (!mAllowHwBitmapsInSwMode) {
            throw new IllegalArgumentException(
                    "Software rendering doesn't support hardware bitmaps");
        }
    }

    private void throwIfHwBitmapInSwMode(Bitmap bitmap) {
        if (!isHardwareAccelerated() && bitmap.getConfig() == Bitmap.Config.HARDWARE) {
            onHwBitmapInSwMode();
        }
    }

    private void throwIfHasHwBitmapInSwMode(Paint p) {
        if (isHardwareAccelerated() || p == null) {
            return;
        }
        throwIfHasHwBitmapInSwMode(p.getShader());
    }

    private void throwIfHasHwBitmapInSwMode(Shader shader) {
        if (shader == null) {
            return;
        }
        if (shader instanceof BitmapShader) {
            throwIfHwBitmapInSwMode(((BitmapShader) shader).mBitmap);
        }
        if (shader instanceof ComposeShader) {
            throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderA);
            throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderB);
        }
    }

	/** *****************native drawXXX()方法 见文章下方代码段*************** */
}

drawXXX() 方法,这些方法也在DisplayListCanvas中实现,以便我们可以有选择地应用于它们

draw几何图形

    public void drawArc(float left, float top, float right, float bottom, float startAngle,
            float sweepAngle, boolean useCenter, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
                useCenter, paint.getNativeInstance());
    }

    public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
            @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
                paint);
    }

    public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance());
    }

    public void drawLine(float startX, float startY, float stopX, float stopY,
            @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance());
    }

    public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,
            @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
    }

    public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        drawLines(pts, 0, pts.length, paint);
    }

    public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
    }

    public void drawOval(@NonNull RectF oval, @NonNull Paint paint) {
        if (oval == null) {
            throw new NullPointerException();
        }
        throwIfHasHwBitmapInSwMode(paint);
        drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
    }

    public void drawPoint(float x, float y, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
    }

    public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
            @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
    }

    public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        drawPoints(pts, 0, pts.length, paint);
    }

    public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
    }

    public void drawRect(@NonNull Rect r, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        drawRect(r.left, r.top, r.right, r.bottom, paint);
    }

    public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawRect(mNativeCanvasWrapper,
                rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance());
    }

    public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
            @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry,
                paint.getNativeInstance());
    }

    public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
    }

drawPath

    public void drawPath(@NonNull Path path, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        if (path.isSimplePath && path.rects != null) {
            nDrawRegion(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance());
        } else {
            nDrawPath(mNativeCanvasWrapper, path.readOnlyNI(), paint.getNativeInstance());
        }
    }

drawText

    @Deprecated
    public void drawPosText(@NonNull char[] text, int index, int count,
            @NonNull @Size(multiple = 2) float[] pos,
            @NonNull Paint paint) {
        if (index < 0 || index + count > text.length || count * 2 > pos.length) {
            throw new IndexOutOfBoundsException();
        }
        throwIfHasHwBitmapInSwMode(paint);
        for (int i = 0; i < count; i++) {
            drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint);
        }
    }

    @Deprecated
    public void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos,
            @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
    }

    public void drawText(@NonNull char[] text, int index, int count, float x, float y,
            @NonNull Paint paint) {
        if ((index | count | (index + count) |
                (text.length - index - count)) < 0) {
            throw new IndexOutOfBoundsException();
        }
        throwIfHasHwBitmapInSwMode(paint);
        nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags,
                paint.getNativeInstance());
    }

    public void drawText(@NonNull CharSequence text, int start, int end, float x, float y,
            @NonNull Paint paint) {
        if ((start | end | (end - start) | (text.length() - end)) < 0) {
            throw new IndexOutOfBoundsException();
        }
        throwIfHasHwBitmapInSwMode(paint);
        if (text instanceof String || text instanceof SpannedString ||
                text instanceof SpannableString) {
            nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
                    paint.mBidiFlags, paint.getNativeInstance());
        } else if (text instanceof GraphicsOperations) {
            ((GraphicsOperations) text).drawText(this, start, end, x, y,
                    paint);
        } else {
            char[] buf = TemporaryBuffer.obtain(end - start);
            TextUtils.getChars(text, start, end, buf, 0);
            nDrawText(mNativeCanvasWrapper, buf, 0, end - start, x, y,
                    paint.mBidiFlags, paint.getNativeInstance());
            TemporaryBuffer.recycle(buf);
        }
    }

    public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
                paint.getNativeInstance());
    }

    public void drawText(@NonNull String text, int start, int end, float x, float y,
            @NonNull Paint paint) {
        if ((start | end | (end - start) | (text.length() - end)) < 0) {
            throw new IndexOutOfBoundsException();
        }
        throwIfHasHwBitmapInSwMode(paint);
        nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags,
                paint.getNativeInstance());
    }

    public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path,
            float hOffset, float vOffset, @NonNull Paint paint) {
        if (index < 0 || index + count > text.length) {
            throw new ArrayIndexOutOfBoundsException();
        }
        throwIfHasHwBitmapInSwMode(paint);
        nDrawTextOnPath(mNativeCanvasWrapper, text, index, count,
                path.readOnlyNI(), hOffset, vOffset,
                paint.mBidiFlags, paint.getNativeInstance());
    }

    public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
            float vOffset, @NonNull Paint paint) {
        if (text.length() > 0) {
            throwIfHasHwBitmapInSwMode(paint);
            nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset,
                    paint.mBidiFlags, paint.getNativeInstance());
        }
    }

    public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex,
            int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) {

        if (text == null) {
            throw new NullPointerException("text is null");
        }
        if (paint == null) {
            throw new NullPointerException("paint is null");
        }
        if ((index | count | contextIndex | contextCount | index - contextIndex
                | (contextIndex + contextCount) - (index + count)
                | text.length - (contextIndex + contextCount)) < 0) {
            throw new IndexOutOfBoundsException();
        }

        throwIfHasHwBitmapInSwMode(paint);
        nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
                x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */);
    }

    public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
            int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {

        if (text == null) {
            throw new NullPointerException("text is null");
        }
        if (paint == null) {
            throw new NullPointerException("paint is null");
        }
        if ((start | end | contextStart | contextEnd | start - contextStart | end - start
                | contextEnd - end | text.length() - contextEnd) < 0) {
            throw new IndexOutOfBoundsException();
        }

        throwIfHasHwBitmapInSwMode(paint);
        if (text instanceof String || text instanceof SpannedString ||
                text instanceof SpannableString) {
            nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart,
                    contextEnd, x, y, isRtl, paint.getNativeInstance());
        } else if (text instanceof GraphicsOperations) {
            ((GraphicsOperations) text).drawTextRun(this, start, end,
                    contextStart, contextEnd, x, y, isRtl, paint);
        } else {
            int contextLen = contextEnd - contextStart;
            int len = end - start;
            char[] buf = TemporaryBuffer.obtain(contextLen);
            TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
            long measuredTextPtr = 0;
            if (text instanceof PrecomputedText) {
                PrecomputedText mt = (PrecomputedText) text;
                int paraIndex = mt.findParaIndex(start);
                if (end <= mt.getParagraphEnd(paraIndex)) {
                    // 仅支持同一段落中的文本。
                    measuredTextPtr = mt.getMeasuredParagraph(paraIndex).getNativePtr();
                }
            }
            nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
                    0, contextLen, x, y, isRtl, paint.getNativeInstance(), measuredTextPtr);
            TemporaryBuffer.recycle(buf);
        }
    }

drawBitmap

    public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
        throwIfCannotDraw(bitmap);
        throwIfHasHwBitmapInSwMode(paint);
        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top,
                paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity,
                bitmap.mDensity);
    }

    public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
        throwIfHasHwBitmapInSwMode(paint);
        nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(),
                paint != null ? paint.getNativeInstance() : 0);
    }

    public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst,
            @Nullable Paint paint) {
        if (dst == null) {
            throw new NullPointerException();
        }
        throwIfCannotDraw(bitmap);
        throwIfHasHwBitmapInSwMode(paint);
        final long nativePaint = paint == null ? 0 : paint.getNativeInstance();

        int left, top, right, bottom;
        if (src == null) {
            left = top = 0;
            right = bitmap.getWidth();
            bottom = bitmap.getHeight();
        } else {
            left = src.left;
            right = src.right;
            top = src.top;
            bottom = src.bottom;
        }

        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
                bitmap.mDensity);
    }

    public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst,
            @Nullable Paint paint) {
        if (dst == null) {
            throw new NullPointerException();
        }
        throwIfCannotDraw(bitmap);
        throwIfHasHwBitmapInSwMode(paint);
        final long nativePaint = paint == null ? 0 : paint.getNativeInstance();

        float left, top, right, bottom;
        if (src == null) {
            left = top = 0;
            right = bitmap.getWidth();
            bottom = bitmap.getHeight();
        } else {
            left = src.left;
            right = src.right;
            top = src.top;
            bottom = src.bottom;
        }

        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
                bitmap.mDensity);
    }

    @Deprecated
    public void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y,
            int width, int height, boolean hasAlpha, @Nullable Paint paint) {
        // check for valid input
        if (width < 0) {
            throw new IllegalArgumentException("width must be >= 0");
        }
        if (height < 0) {
            throw new IllegalArgumentException("height must be >= 0");
        }
        if (Math.abs(stride) < width) {
            throw new IllegalArgumentException("abs(stride) must be >= width");
        }
        int lastScanline = offset + (height - 1) * stride;
        int length = colors.length;
        if (offset < 0 || (offset + width > length) || lastScanline < 0
                || (lastScanline + width > length)) {
            throw new ArrayIndexOutOfBoundsException();
        }
        throwIfHasHwBitmapInSwMode(paint);
        // 如果没什么可画的,就赶快避开
        if (width == 0 || height == 0) {
            return;
        }
        // 打卡到本地进行实际绘图
        nDrawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha,
                paint != null ? paint.getNativeInstance() : 0);
    }

    @Deprecated
    public void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y,
            int width, int height, boolean hasAlpha, @Nullable Paint paint) {
        // 调用通用float版本
        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height,
                hasAlpha, paint);
    }

    public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight,
            @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset,
            @Nullable Paint paint) {
        if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        throwIfHasHwBitmapInSwMode(paint);
        if (meshWidth == 0 || meshHeight == 0) {
            return;
        }
        int count = (meshWidth + 1) * (meshHeight + 1);
        // 因为每个顶点需要两个浮点数,所以要乘以2
        checkRange(verts.length, vertOffset, count * 2);
        if (colors != null) {
            // 因为每个顶点只需要一种颜色,没有乘以2
            checkRange(colors.length, colorOffset, count);
        }
        nDrawBitmapMesh(mNativeCanvasWrapper, bitmap, meshWidth, meshHeight,
                verts, vertOffset, colors, colorOffset,
                paint != null ? paint.getNativeInstance() : 0);
    }

draw颜色

    public void drawARGB(int a, int r, int g, int b) {
        drawColor(Color.argb(a, r, g, b));
    }

    public void drawRGB(int r, int g, int b) {
        drawColor(Color.rgb(r, g, b));
    }

    public void drawColor(@ColorInt int color) {
        nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
    }

    public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
        nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt);
    }

    public void drawPaint(@NonNull Paint paint) {
        nDrawPaint(mNativeCanvasWrapper, paint.getNativeInstance());
    }

    public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) {
        Bitmap bitmap = patch.getBitmap();
        throwIfCannotDraw(bitmap);
        throwIfHasHwBitmapInSwMode(paint);
        final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
        nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint,
                mDensity, patch.getDensity());
    }

    public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) {
        Bitmap bitmap = patch.getBitmap();
        throwIfCannotDraw(bitmap);
        throwIfHasHwBitmapInSwMode(paint);
        final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
        nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint,
                mDensity, patch.getDensity());
    }
    
    public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
            int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
            int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
            @NonNull Paint paint) {
        checkRange(verts.length, vertOffset, vertexCount);
        if (isHardwareAccelerated()) {
            return;
        }
        if (texs != null) {
            checkRange(texs.length, texOffset, vertexCount);
        }
        if (colors != null) {
            checkRange(colors.length, colorOffset, vertexCount / 2);
        }
        if (indices != null) {
            checkRange(indices.length, indexOffset, indexCount);
        }
        throwIfHasHwBitmapInSwMode(paint);
        nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts,
                vertOffset, texs, texOffset, colors, colorOffset,
                indices, indexOffset, indexCount, paint.getNativeInstance());
    }

native drawXXX()

JNI注册由android_view_Canvas.cpp处理

    private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top,
            long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity);

    private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float srcLeft,
            float srcTop,
            float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
            float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity);

    private static native void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride,
            float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero);

    private static native void nDrawColor(long nativeCanvas, int color, int mode);

    private static native void nDrawPaint(long nativeCanvas, long nativePaint);

    private static native void nDrawPoint(long canvasHandle, float x, float y, long paintHandle);

    private static native void nDrawPoints(long canvasHandle, float[] pts, int offset, int count,
            long paintHandle);

    private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX,
            float stopY, long nativePaint);

    private static native void nDrawLines(long canvasHandle, float[] pts, int offset, int count,
            long paintHandle);

    private static native void nDrawRect(long nativeCanvas, float left, float top, float right,
            float bottom, long nativePaint);

    private static native void nDrawOval(long nativeCanvas, float left, float top, float right,
            float bottom, long nativePaint);

    private static native void nDrawCircle(long nativeCanvas, float cx, float cy, float radius,
            long nativePaint);

    private static native void nDrawArc(long nativeCanvas, float left, float top, float right,
            float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint);

    private static native void nDrawRoundRect(long nativeCanvas, float left, float top, float right,
            float bottom, float rx, float ry, long nativePaint);

    private static native void nDrawPath(long nativeCanvas, long nativePath, long nativePaint);

    private static native void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint);

    private static native void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch,
            float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero,
            int screenDensity, int bitmapDensity);

    private static native void nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap,
            long nativeMatrix, long nativePaint);

    private static native void nDrawBitmapMesh(long nativeCanvas, Bitmap bitmap, int meshWidth,
            int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset,
            long nativePaint);

    private static native void nDrawVertices(long nativeCanvas, int mode, int n, float[] verts,
            int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset,
            short[] indices, int indexOffset, int indexCount, long nativePaint);

    private static native void nDrawText(long nativeCanvas, char[] text, int index, int count,
            float x, float y, int flags, long nativePaint);

    private static native void nDrawText(long nativeCanvas, String text, int start, int end,
            float x, float y, int flags, long nativePaint);

    private static native void nDrawTextRun(long nativeCanvas, String text, int start, int end,
            int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint);

    private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
            int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
            long nativePrecomputedText);

    private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
            long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint);

    private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
            float hOffset, float vOffset, int flags, long nativePaint);

推荐阅读