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

Commit c0ac193b authored by Romain Guy's avatar Romain Guy
Browse files

Add support for linear gradients.

Change-Id: Id15329da065045b3f06fdaed615f33cd57608496
parent 9d339c13
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -633,7 +633,7 @@ class GLES20Canvas extends Canvas {
            } else if (shader instanceof LinearGradient) {
                final LinearGradient ls = (LinearGradient) shader;
                nSetupLinearShader(mRenderer, ls.native_instance, ls.bounds, ls.colors,
                        ls.positions, ls.tileMode, ls.mLocalMatrix);
                        ls.positions, ls.count, ls.tileMode, ls.mLocalMatrix);
                return true;
            } else if (shader instanceof RadialGradient) {
                // TODO: Implement
@@ -645,7 +645,7 @@ class GLES20Canvas extends Canvas {
    }

    private native void nSetupLinearShader(int renderer, int shader, int bounds,
            int colors, int positions, int tileMode, int localMatrix);
            int colors, int positions, int count, int tileMode, int localMatrix);
    private native void nSetupBitmapShader(int renderer, int shader, int bitmap,
            int tileX, int tileY, int matrix);
    private native void nResetShader(int renderer);
+4 −4
Original line number Diff line number Diff line
@@ -240,9 +240,9 @@ static void android_view_GLES20Canvas_setupBitmapShader(JNIEnv* env, jobject can

static void android_view_GLES20Canvas_setupLinearShader(JNIEnv* env, jobject canvas,
        OpenGLRenderer* renderer, SkShader* shader, float* bounds, uint32_t* colors,
        float* positions, SkShader::TileMode tileMode, SkMatrix* matrix) {
    renderer->setupLinearGradientShader(shader, bounds, colors, positions, tileMode,
            matrix, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
        float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix) {
    renderer->setupLinearGradientShader(shader, bounds, colors, positions, count,
            tileMode, matrix, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
}

// ----------------------------------------------------------------------------
@@ -286,7 +286,7 @@ static JNINativeMethod gMethods[] = {

    {   "nResetShader",       "(I)V",            (void*) android_view_GLES20Canvas_resetShader },
    {   "nSetupBitmapShader", "(IIIIII)V",       (void*) android_view_GLES20Canvas_setupBitmapShader },
    {   "nSetupLinearShader", "(IIIIIII)V",      (void*) android_view_GLES20Canvas_setupLinearShader },
    {   "nSetupLinearShader", "(IIIIIIII)V",     (void*) android_view_GLES20Canvas_setupLinearShader },

    {   "nGetClipBounds",     "(ILandroid/graphics/Rect;)Z",
            (void*) android_view_GLES20Canvas_getClipBounds },
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
	GradientCache.cpp \
	LayerCache.cpp \
	Matrix.cpp \
	OpenGLRenderer.cpp \
+160 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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.
 */

#define LOG_TAG "OpenGLRenderer"

#include <GLES2/gl2.h>

#include <SkCanvas.h>
#include <SkGradientShader.h>

#include "GradientCache.h"

namespace android {
namespace uirenderer {

///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////

GradientCache::GradientCache(uint32_t maxByteSize):
        mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity),
        mSize(0), mMaxSize(maxByteSize) {
    mCache.setOnEntryRemovedListener(this);
}

GradientCache::~GradientCache() {
    mCache.clear();
}

///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////

uint32_t GradientCache::getSize() {
    return mSize;
}

uint32_t GradientCache::getMaxSize() {
    return mMaxSize;
}

void GradientCache::setMaxSize(uint32_t maxSize) {
    mMaxSize = maxSize;
    while (mSize > mMaxSize) {
        mCache.removeOldest();
    }
}

///////////////////////////////////////////////////////////////////////////////
// Callbacks
///////////////////////////////////////////////////////////////////////////////

void GradientCache::operator()(SkShader*& shader, Texture*& texture) {
    if (shader) {
        const uint32_t size = texture->width * texture->height * 4;
        mSize -= size;
    }

    if (texture) {
        glDeleteTextures(1, &texture->id);
        delete texture;
    }
}

///////////////////////////////////////////////////////////////////////////////
// Caching
///////////////////////////////////////////////////////////////////////////////

Texture* GradientCache::get(SkShader* shader) {
    Texture* texture = mCache.get(shader);
    return texture;
}

void GradientCache::remove(SkShader* shader) {
    mCache.remove(shader);
}

void GradientCache::clear() {
    mCache.clear();
}

Texture* GradientCache::addLinearGradient(SkShader* shader, float* bounds, uint32_t* colors,
        float* positions, int count, SkShader::TileMode tileMode) {
    SkBitmap bitmap;
    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1024, 1);
    bitmap.allocPixels();
    bitmap.eraseColor(0);

    SkCanvas canvas(bitmap);

    SkPoint points[2];
    points[0].set(0.0f, 0.0f);
    points[1].set(bitmap.width(), 0.0f);

    SkShader* localShader = SkGradientShader::CreateLinear(points,
            reinterpret_cast<const SkColor*>(colors), positions, count, tileMode);

    SkPaint p;
    p.setStyle(SkPaint::kStrokeAndFill_Style);
    p.setShader(localShader)->unref();

    canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 1.0f, p);

    // Asume the cache is always big enough
    const uint32_t size = bitmap.rowBytes() * bitmap.height();
    while (mSize + size > mMaxSize) {
        mCache.removeOldest();
    }

    Texture* texture = new Texture;
    generateTexture(&bitmap, texture);

    mSize += size;
    mCache.put(shader, texture);

    return texture;
}

void GradientCache::generateTexture(SkBitmap* bitmap, Texture* texture) {
    SkAutoLockPixels autoLock(*bitmap);
    if (!bitmap->readyToDraw()) {
        LOGE("Cannot generate texture from shader");
        return;
    }

    texture->generation = bitmap->getGenerationID();
    texture->width = bitmap->width();
    texture->height = bitmap->height();

    glGenTextures(1, &texture->id);

    glBindTexture(GL_TEXTURE_2D, texture->id);
    glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());

    texture->blend = !bitmap->isOpaque();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0,
            GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

}; // namespace uirenderer
}; // namespace android
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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_UI_GRADIENT_CACHE_H
#define ANDROID_UI_GRADIENT_CACHE_H

#include <SkShader.h>

#include "Texture.h"
#include "GenerationCache.h"

namespace android {
namespace uirenderer {

/**
 * A simple LRU gradient cache. The cache has a maximum size expressed in bytes.
 * Any texture added to the cache causing the cache to grow beyond the maximum
 * allowed size will also cause the oldest texture to be kicked out.
 */
class GradientCache: public OnEntryRemoved<SkShader*, Texture*> {
public:
    GradientCache(uint32_t maxByteSize);
    ~GradientCache();

    /**
     * Used as a callback when an entry is removed from the cache.
     * Do not invoke directly.
     */
    void operator()(SkShader*& shader, Texture*& texture);

    /**
     * Adds a new linear gradient to the cache. The generated texture is
     * returned.
     */
    Texture* addLinearGradient(SkShader* shader, float* bounds, uint32_t* colors,
            float* positions, int count, SkShader::TileMode tileMode);
    /**
     * Returns the texture associated with the specified shader.
     */
    Texture* get(SkShader* shader);
    /**
     * Removes the texture associated with the specified shader. Returns NULL
     * if the texture cannot be found. Upon remove the texture is freed.
     */
    void remove(SkShader* shader);
    /**
     * Clears the cache. This causes all textures to be deleted.
     */
    void clear();

    /**
     * Sets the maximum size of the cache in bytes.
     */
    void setMaxSize(uint32_t maxSize);
    /**
     * Returns the maximum size of the cache in bytes.
     */
    uint32_t getMaxSize();
    /**
     * Returns the current size of the cache in bytes.
     */
    uint32_t getSize();

private:
    void generateTexture(SkBitmap* bitmap, Texture* texture);

    GenerationCache<SkShader*, Texture*> mCache;

    uint32_t mSize;
    uint32_t mMaxSize;
}; // class GradientCache

}; // namespace uirenderer
}; // namespace android

#endif // ANDROID_UI_GRADIENT_CACHE_H
Loading