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

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

Merge "Properly support ALPHA_8 bitmaps in all drawBitmap() methods"

parents 5c11ef10 886b275e
Loading
Loading
Loading
Loading
+104 −64
Original line number Diff line number Diff line
@@ -1340,30 +1340,20 @@ void OpenGLRenderer::setupDrawPoint(float pointSize) {
    mDescription.pointSize = pointSize;
}

void OpenGLRenderer::setupDrawColor(int color) {
    setupDrawColor(color, (color >> 24) & 0xFF);
}

void OpenGLRenderer::setupDrawColor(int color, int alpha) {
    mColorA = alpha / 255.0f;
    // Second divide of a by 255 is an optimization, allowing us to simply multiply
    // the rgb values by a instead of also dividing by 255
    const float a = mColorA / 255.0f;
    mColorR = a * ((color >> 16) & 0xFF);
    mColorG = a * ((color >>  8) & 0xFF);
    mColorB = a * ((color      ) & 0xFF);
    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
    mColorSet = true;
    mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA);
}

void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
    mColorA = alpha / 255.0f;
    // Double-divide of a by 255 is an optimization, allowing us to simply multiply
    // the rgb values by a instead of also dividing by 255
    const float a = mColorA / 255.0f;
    mColorR = a * ((color >> 16) & 0xFF);
    mColorG = a * ((color >>  8) & 0xFF);
    mColorB = a * ((color      ) & 0xFF);
    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
    mColorSet = true;
    mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA);
}
@@ -1625,43 +1615,27 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, Sk
    SkXfermode::Mode mode;
    getAlphaAndMode(paint, &alpha, &mode);

    int color = paint != NULL ? paint->getColor() : 0;

    float x = left;
    float y = top;

    GLenum filter = GL_LINEAR;
    texture->setWrap(GL_CLAMP_TO_EDGE, true);

    bool ignoreTransform = false;
    if (mSnapshot->transform->isPureTranslate()) {
        x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
        y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
        ignoreTransform = true;
        filter = GL_NEAREST;

        texture->setFilter(GL_NEAREST, true);
    } else {
        filter = FILTER(paint);
        texture->setFilter(FILTER(paint), true);
    }

    setupDraw();
    setupDrawWithTexture(true);
    if (paint) {
        setupDrawAlpha8Color(paint->getColor(), alpha);
    }
    setupDrawColorFilter();
    setupDrawShader();
    setupDrawBlending(true, mode);
    setupDrawProgram();
    setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform);

    setupDrawTexture(texture->id);
    texture->setWrap(GL_CLAMP_TO_EDGE);
    texture->setFilter(filter);

    setupDrawPureColorUniforms();
    setupDrawColorFilterUniforms();
    setupDrawShaderUniforms();
    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);

    finishDrawTexture();
    drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
            paint != NULL, color, alpha, mode, (GLvoid*) NULL,
            (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
}

status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
@@ -1704,7 +1678,11 @@ status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint*
    // to the vertex shader. The save/restore is a bit overkill.
    save(SkCanvas::kMatrix_SaveFlag);
    concatMatrix(matrix);
    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
        drawAlphaBitmap(texture, 0.0f, 0.0f, paint);
    } else {
        drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
    }
    restore();

    return DrawGlInfo::kStatusDrew;
@@ -1722,7 +1700,11 @@ status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top,
    Texture* texture = mCaches.textureCache.getTransient(bitmap);
    const AutoTexture autoCleanup(texture);

    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
        drawAlphaBitmap(texture, left, top, paint);
    } else {
        drawTextureRect(left, top, right, bottom, texture, paint);
    }

    return DrawGlInfo::kStatusDrew;
}
@@ -1836,26 +1818,59 @@ status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap,

    texture->setWrap(GL_CLAMP_TO_EDGE, true);

    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
        const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
        const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);
    float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
    float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);

    bool scaled = scaleX != 1.0f || scaleY != 1.0f;
    // Apply a scale transform on the canvas only when a shader is in use
    // Skia handles the ratio between the dst and src rects as a scale factor
    // when a shader is set
    bool useScaleTransform = mShader && scaled;
    bool ignoreTransform = false;

    if (CC_LIKELY(mSnapshot->transform->isPureTranslate() && !useScaleTransform)) {
        float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
        float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);

        dstRight = x + (dstRight - dstLeft);
        dstBottom = y + (dstBottom - dstTop);

        GLenum filter = GL_NEAREST;
        // Enable linear filtering if the source rectangle is scaled
        if (srcRight - srcLeft != dstRight - dstLeft || srcBottom - srcTop != dstBottom - dstTop) {
            filter = FILTER(paint);
        dstLeft = x;
        dstTop = y;

        texture->setFilter(scaled ? FILTER(paint) : GL_NEAREST, true);
        ignoreTransform = true;
    } else {
        texture->setFilter(FILTER(paint), true);
    }

        texture->setFilter(filter, true);
        drawTextureMesh(x, y, x + (dstRight - dstLeft), y + (dstBottom - dstTop),
                texture->id, alpha / 255.0f, mode, texture->blend,
    if (CC_UNLIKELY(useScaleTransform)) {
        save(SkCanvas::kMatrix_SaveFlag);
        translate(dstLeft, dstTop);
        scale(scaleX, scaleY);

        dstLeft = 0.0f;
        dstTop = 0.0f;

        dstRight = srcRight - srcLeft;
        dstBottom = srcBottom - srcTop;
    }

    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
        int color = paint ? paint->getColor() : 0;
        drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
                texture->id, paint != NULL, color, alpha, mode,
                &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
                GL_TRIANGLE_STRIP, gMeshCount, false, true);
                GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
    } else {
        texture->setFilter(FILTER(paint), true);
        drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f,
                mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
                GL_TRIANGLE_STRIP, gMeshCount);
        drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
                texture->id, alpha / 255.0f, mode, texture->blend,
                &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
                GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
    }

    if (CC_UNLIKELY(useScaleTransform)) {
        restore();
    }

    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
@@ -3094,17 +3109,15 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
    setupDrawColorFilter();
    setupDrawBlending(blend, mode, swapSrcDst);
    setupDrawProgram();
    if (!dirty) {
        setupDrawDirtyRegionsDisabled();
    }
    if (!dirty) setupDrawDirtyRegionsDisabled();
    if (!ignoreScale) {
        setupDrawModelView(left, top, right, bottom, ignoreTransform);
    } else {
        setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
    }
    setupDrawTexture(texture);
    setupDrawPureColorUniforms();
    setupDrawColorFilterUniforms();
    setupDrawTexture(texture);
    setupDrawMesh(vertices, texCoords, vbo);

    glDrawArrays(drawMode, 0, elementsCount);
@@ -3112,6 +3125,33 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
    finishDrawTexture();
}

void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
        GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
        bool ignoreTransform, bool dirty) {

    setupDraw();
    setupDrawWithTexture(true);
    if (hasColor) {
        setupDrawAlpha8Color(color, alpha);
    }
    setupDrawColorFilter();
    setupDrawShader();
    setupDrawBlending(true, mode);
    setupDrawProgram();
    if (!dirty) setupDrawDirtyRegionsDisabled();
    setupDrawModelView(left, top, right, bottom, ignoreTransform);
    setupDrawTexture(texture);
    setupDrawPureColorUniforms();
    setupDrawColorFilterUniforms();
    setupDrawShaderUniforms();
    setupDrawMesh(vertices, texCoords);

    glDrawArrays(drawMode, 0, elementsCount);

    finishDrawTexture();
}

void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
        ProgramDescription& description, bool swapSrcDst) {
    blend = blend || mode != SkXfermode::kSrcOver_Mode;
+5 −1
Original line number Diff line number Diff line
@@ -596,6 +596,11 @@ private:
            bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
            bool ignoreScale = false, bool dirty = true);

    void drawAlpha8TextureMesh(float left, float top, float right, float bottom,
            GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
            GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
            bool ignoreTransform, bool dirty = true);

    /**
     * Draws text underline and strike-through if needed.
     *
@@ -700,7 +705,6 @@ private:
    void setupDrawAA();
    void setupDrawVertexShape();
    void setupDrawPoint(float pointSize);
    void setupDrawColor(int color);
    void setupDrawColor(int color, int alpha);
    void setupDrawColor(float r, float g, float b, float a);
    void setupDrawAlpha8Color(int color, int alpha);
+9 −0
Original line number Diff line number Diff line
@@ -32,6 +32,15 @@

        <meta-data android:name="android.graphics.renderThread" android:value="true" />

        <activity
                android:name="Alpha8BitmapActivity"
                android:label="_Alpha8Bitmap">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
                android:name="MipMapActivity"
                android:label="_MipMap">
+24.9 KiB
Loading image diff...
+97 −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.
 */

package com.android.test.hwui;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.Bundle;
import android.view.View;

@SuppressWarnings({"UnusedDeclaration"})
public class Alpha8BitmapActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new BitmapsView(this));
    }

    static class BitmapsView extends View {
        private Paint mBitmapPaint;
        private final Bitmap mBitmap1;
        private final float[] mVertices;

        BitmapsView(Context c) {
            super(c);

            Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.spot_mask);
            mBitmap1 = Bitmap.createBitmap(texture.getWidth(), texture.getHeight(),
                    Bitmap.Config.ALPHA_8);
            Canvas canvas = new Canvas(mBitmap1);
            canvas.drawBitmap(texture, 0.0f, 0.0f, null);

            texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
            BitmapShader shader = new BitmapShader(texture,
                    Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

            final float width = texture.getWidth() / 3.0f;
            final float height = texture.getHeight() / 3.0f;

            mVertices = new float[] {
                    0.0f, 0.0f, width, 0.0f, width * 2, 0.0f, width * 3, 0.0f,
                    0.0f, height, width, height, width * 2, height, width * 4, height,
                    0.0f, height * 2, width, height * 2, width * 2, height * 2, width * 3, height * 2,
                    0.0f, height * 4, width, height * 4, width * 2, height * 4, width * 4, height * 4,
            };

            mBitmapPaint = new Paint();
            mBitmapPaint.setFilterBitmap(true);
            mBitmapPaint.setShader(shader);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            canvas.drawColor(0xffffffff);
            canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint);

            Matrix matrix = new Matrix();
            matrix.setScale(2.0f, 2.0f);
            matrix.postTranslate(0.0f, mBitmap1.getHeight());
            canvas.drawBitmap(mBitmap1, matrix, mBitmapPaint);

            Rect src = new Rect(0, 0, mBitmap1.getWidth() / 2, mBitmap1.getHeight() / 2);
            Rect dst = new Rect(0, mBitmap1.getHeight() * 3, mBitmap1.getWidth(),
                    mBitmap1.getHeight() * 4);
            canvas.drawBitmap(mBitmap1, src, dst, mBitmapPaint);

            canvas.translate(0.0f, mBitmap1.getHeight() * 4);
            canvas.drawBitmapMesh(mBitmap1, 3, 3, mVertices, 0, null, 0, mBitmapPaint);

            invalidate();
        }
    }
}