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

Commit c287a77d authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

Continue to isolate graphics classes by introducing C API

This CL adds an initial C API to show how we should proceed
with limiting the symbols the graphics library will expose to the
framework.

Refactor Surface and TextureView to have no dependencies on the
graphics classes outside of the exposed C API.

Test: CtsUiRenderingTestCases
Bug: 137655431
Change-Id: Ic10aaba00388a47ca97f156fcaebc1ea7676dfb2
parent 19419ccc
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -387,10 +387,12 @@ cc_library_static {
    local_include_dirs: [
        "include",  // NEEDED FOR ANDROID RUNTIME
        "android/graphics",
        "android/graphics/apex/include",
    ],

    export_include_dirs: [
        ".",
        "android/graphics/apex/include",
    ],

    include_dirs: [
@@ -418,6 +420,8 @@ cc_library_static {
    target: {
        android: {
            srcs: [ // sources that depend on android only libraries
                "android/graphics/apex/android_canvas.cpp",

                "android_view_TextureLayer.cpp",
                "android_view_ThreadedRenderer.cpp",
                "android/graphics/BitmapRegionDecoder.cpp",
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 "android/graphics/canvas.h"

#include "GraphicsJNI.h"

#include <hwui/Canvas.h>
#include <utils/Color.h>

#include <SkBitmap.h>

using namespace android;

static inline Canvas* toCanvas(ACanvas* aCanvas) {
    return reinterpret_cast<Canvas*>(aCanvas);
}

static inline ACanvas* toACanvas(Canvas* canvas) {
    return reinterpret_cast<ACanvas*>(canvas);
}

bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat) {
    ANativeWindow_Buffer buffer { 0, 0, 0, bufferFormat, nullptr, {0} };
    const SkColorType colorType = uirenderer::ANativeWindowToImageInfo(buffer, nullptr).colorType();
    return kUnknown_SkColorType != colorType;
}

ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvasObj) {
    return toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj));
}

void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
                       int32_t /*android_dataspace_t*/ dataspace) {
    SkBitmap bitmap;
    if (buffer != nullptr && buffer->width > 0 && buffer->height > 0) {
        sk_sp<SkColorSpace> cs(uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace));
        SkImageInfo imageInfo = uirenderer::ANativeWindowToImageInfo(*buffer, cs);
        ssize_t rowBytes = buffer->stride * imageInfo.bytesPerPixel();
        bitmap.setInfo(imageInfo, rowBytes);
        bitmap.setPixels(buffer->bits);
    }

    toCanvas(canvas)->setBitmap(bitmap);
}

void ACanvas_clipRect(ACanvas* canvas, const ARect& clipRect, bool /*doAA*/) {
    //TODO update Canvas to take antialias param
    toCanvas(canvas)->clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
                               SkClipOp::kIntersect);
}

void ACanvas_clipOutRect(ACanvas* canvas, const ARect& clipRect, bool /*doAA*/) {
    //TODO update Canvas to take antialias param
    toCanvas(canvas)->clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
                               SkClipOp::kDifference);
}
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 <android/native_window.h>
#include <android/rect.h>
#include <jni.h>

__BEGIN_DECLS

/**
* Opaque handle for a native graphics canvas.
*/
typedef struct ACanvas ACanvas;

//  One of AHardwareBuffer_Format.
bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat);

/**
 * Returns a native handle to a Java android.graphics.Canvas
 *
 * @param env
 * @param canvas
 * @return ACanvas* that is only valid for the life of the jobject.
 */
ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvas);

/**
 * Updates the canvas to render into the pixels in the provided buffer
 *
 * @param canvas
 * @param buffer The buffer that will provide the backing store for this canvas.  The buffer must
 *               remain valid until the this method is called again with either another active
 *               buffer or nullptr.  If nullptr is given the canvas will release the previous buffer
 *               and set an empty backing store.
 * @param dataspace
 */
void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
                       int32_t /*android_dataspace_t*/ dataspace);

/**
 * Clips operations on the canvas to the intersection of the current clip and the provided clipRect.
 */
void ACanvas_clipRect(ACanvas* canvas, const ARect& clipRect, bool doAntiAlias = false);

/**
 * Clips operations on the canvas to the difference of the current clip and the provided clipRect.
 */
void ACanvas_clipOutRect(ACanvas* canvas, const ARect& clipRect, bool doAntiAlias = false);

__END_DECLS
#endif // ANDROID_GRAPHICS_CANVAS_H
 No newline at end of file
+18 −46
Original line number Diff line number Diff line
@@ -21,11 +21,6 @@
#include <inttypes.h>

#include "android_os_Parcel.h"
#include "android/graphics/GraphicsJNI.h"

#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_graphics_GraphicBuffer.h>

#include <binder/Parcel.h>

#include <log/log.h>
@@ -33,10 +28,10 @@
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>

#include <hwui/Bitmap.h>

#include <SkCanvas.h>
#include <SkBitmap.h>
#include <android/native_window.h>
#include <android/graphics/canvas.h>
#include <android_runtime/android_graphics_GraphicBuffer.h>
#include <private/android/AHardwareBufferHelpers.h>

#include <private/gui/ComposerService.h>

@@ -146,23 +141,8 @@ static void android_graphics_GraphicBuffer_destroy(JNIEnv* env, jobject clazz,
// Canvas management
// ----------------------------------------------------------------------------

static inline SkColorType convertPixelFormat(int32_t format) {
    switch (format) {
        case PIXEL_FORMAT_RGBA_8888:
            return kN32_SkColorType;
        case PIXEL_FORMAT_RGBX_8888:
            return kN32_SkColorType;
        case PIXEL_FORMAT_RGBA_FP16:
            return kRGBA_F16_SkColorType;
        case PIXEL_FORMAT_RGB_565:
            return kRGB_565_SkColorType;
        default:
            return kUnknown_SkColorType;
    }
}

static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
        jlong wrapperHandle, jobject canvas, jobject dirtyRect) {
        jlong wrapperHandle, jobject canvasObj, jobject dirtyRect) {

    GraphicBufferWrapper* wrapper =
                reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
@@ -191,24 +171,16 @@ static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
        return JNI_FALSE;
    }

    ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());

    SkBitmap bitmap;
    bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
                                     convertPixelFormat(buffer->getPixelFormat()),
                                     kPremul_SkAlphaType),
                   bytesCount);

    if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
        bitmap.setPixels(bits);
    } else {
        bitmap.setPixels(NULL);
    }
    ANativeWindow_Buffer nativeBuffer;
    nativeBuffer.width = buffer->getWidth();
    nativeBuffer.height = buffer->getHeight();
    nativeBuffer.stride = buffer->getStride();
    nativeBuffer.format = AHardwareBuffer_convertFromPixelFormat(buffer->getPixelFormat());
    nativeBuffer.bits = bits;

    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
    nativeCanvas->setBitmap(bitmap);
    nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom,
            SkClipOp::kIntersect);
    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
    ACanvas_setBuffer(canvas, &nativeBuffer, ADATASPACE_UNKNOWN);
    ACanvas_clipRect(canvas, {rect.left, rect.top, rect.right, rect.bottom});

    if (dirtyRect) {
        INVOKEV(dirtyRect, gRectClassInfo.set,
@@ -219,13 +191,13 @@ static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
}

static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
        jlong wrapperHandle, jobject canvas) {
        jlong wrapperHandle, jobject canvasObj) {
    // release the buffer from the canvas
    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
    ACanvas_setBuffer(canvas, nullptr, ADATASPACE_UNKNOWN);

    GraphicBufferWrapper* wrapper =
                reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
    nativeCanvas->setBitmap(SkBitmap());

    if (wrapper) {
        status_t status = wrapper->get()->unlock();
        return status == 0 ? JNI_TRUE : JNI_FALSE;
+13 −33
Original line number Diff line number Diff line
@@ -20,15 +20,16 @@

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "android_os_Parcel.h"
#include "android/graphics/GraphicsJNI.h"

#include "core_jni_helpers.h"

#include <android/graphics/canvas.h>
#include <android_runtime/android_graphics_GraphicBuffer.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/Log.h>
#include <private/android/AHardwareBufferHelpers.h>

#include "android_os_Parcel.h"
#include <binder/Parcel.h>

#include <gui/Surface.h>
@@ -39,11 +40,6 @@
#include <ui/Rect.h>
#include <ui/Region.h>

#include <SkCanvas.h>
#include <SkBitmap.h>
#include <SkImage.h>
#include <SkRegion.h>

#include <utils/misc.h>
#include <utils/Log.h>

@@ -232,37 +228,21 @@ static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
        dirtyRectPtr = &dirtyRect;
    }

    ANativeWindow_Buffer outBuffer;
    status_t err = surface->lock(&outBuffer, dirtyRectPtr);
    ANativeWindow_Buffer buffer;
    status_t err = surface->lock(&buffer, dirtyRectPtr);
    if (err < 0) {
        const char* const exception = (err == NO_MEMORY) ?
                OutOfResourcesException :
                "java/lang/IllegalArgumentException";
                OutOfResourcesException : IllegalArgumentException;
        jniThrowException(env, exception, NULL);
        return 0;
    }

    SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
                                         convertPixelFormat(outBuffer.format),
                                         outBuffer.format == PIXEL_FORMAT_RGBX_8888
                                                 ? kOpaque_SkAlphaType : kPremul_SkAlphaType);

    SkBitmap bitmap;
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    bitmap.setInfo(info, bpr);
    if (outBuffer.width > 0 && outBuffer.height > 0) {
        bitmap.setPixels(outBuffer.bits);
    } else {
        // be safe with an empty bitmap.
        bitmap.setPixels(NULL);
    }

    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
    nativeCanvas->setBitmap(bitmap);
    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
    ACanvas_setBuffer(canvas, &buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));

    if (dirtyRectPtr) {
        nativeCanvas->clipRect(dirtyRect.left, dirtyRect.top,
                dirtyRect.right, dirtyRect.bottom, SkClipOp::kIntersect);
        ACanvas_clipRect(canvas, {dirtyRect.left, dirtyRect.top,
                                  dirtyRect.right, dirtyRect.bottom});
    }

    if (dirtyRectObj) {
@@ -288,8 +268,8 @@ static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
    }

    // detach the canvas from the surface
    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
    nativeCanvas->setBitmap(SkBitmap());
    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
    ACanvas_setBuffer(canvas, nullptr, ADATASPACE_UNKNOWN);

    // unlock surface
    status_t err = surface->unlockAndPost();
Loading