Skip to content

Commit d15ebf2

Browse files
committed
Enable changing properties of layer paint
Previously, to draw a layered view with a changed Paint object for the drawLayer operation, you'd have to invalidate the parent view, to get the native DisplayList to pick up the new Paint properties. This change adds API and functionality so that the developer can call setLayerPaint(), which does the proper invalidation (lightweight, doesn't cause redrawing the view). Issue #6923810 Make it easy to efficiently animate a layer's Paint Change-Id: I7fea79788d50f6d9c86dd5e5b2a4490cb95142bb
1 parent 4db5d23 commit d15ebf2

File tree

13 files changed

+189
-52
lines changed

13 files changed

+189
-52
lines changed

api/current.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25027,6 +25027,7 @@ package android.view {
2502725027
method public void setId(int);
2502825028
method public void setImportantForAccessibility(int);
2502925029
method public void setKeepScreenOn(boolean);
25030+
method public void setLayerPaint(android.graphics.Paint);
2503025031
method public void setLayerType(int, android.graphics.Paint);
2503125032
method public void setLayoutDirection(int);
2503225033
method public void setLayoutParams(android.view.ViewGroup.LayoutParams);

core/java/android/view/GLES20Canvas.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ protected void finalize() throws Throwable {
152152
static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
153153
static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
154154
static native void nSetOpaqueLayer(int layerId, boolean isOpaque);
155+
static native void nSetLayerPaint(int layerId, int nativePaint);
156+
static native void nSetLayerColorFilter(int layerId, int nativeColorFilter);
155157
static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
156158
SurfaceTexture surface);
157159
static native void nSetTextureLayerTransform(int layerId, int matrix);
@@ -394,13 +396,8 @@ void outputDisplayList(DisplayList displayList) {
394396

395397
void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
396398
final GLES20Layer glLayer = (GLES20Layer) layer;
397-
int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
398-
try {
399-
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
400-
nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
401-
} finally {
402-
if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
403-
}
399+
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
400+
nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
404401
}
405402

406403
private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);

core/java/android/view/GLES20Layer.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package android.view;
1919

2020
import android.graphics.Bitmap;
21+
import android.graphics.Paint;
2122

2223
/**
2324
* An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
@@ -42,6 +43,15 @@ public int getLayer() {
4243
return mLayer;
4344
}
4445

46+
@Override
47+
void setLayerPaint(Paint paint) {
48+
if (paint != null) {
49+
GLES20Canvas.nSetLayerPaint(mLayer, paint.mNativePaint);
50+
GLES20Canvas.nSetLayerColorFilter(mLayer, paint.getColorFilter() != null ?
51+
paint.getColorFilter().nativeColorFilter : 0);
52+
}
53+
}
54+
4555
@Override
4656
boolean copyInto(Bitmap bitmap) {
4757
return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);

core/java/android/view/HardwareLayer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import android.graphics.Bitmap;
2020
import android.graphics.Canvas;
2121
import android.graphics.Matrix;
22+
import android.graphics.Paint;
2223
import android.graphics.Rect;
2324

2425
/**
@@ -61,6 +62,14 @@ abstract class HardwareLayer {
6162
mOpaque = isOpaque;
6263
}
6364

65+
/**
66+
* Update the paint used when drawing this layer.
67+
*
68+
* @param paint The paint used when the layer is drawn into the destination canvas.
69+
* @see View#setLayerPaint(android.graphics.Paint)
70+
*/
71+
void setLayerPaint(Paint paint) {}
72+
6473
/**
6574
* Returns the minimum width of the layer.
6675
*

core/java/android/view/TextureView.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
367367
if (mListener != null && !mUpdateSurface) {
368368
mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
369369
}
370+
mLayer.setLayerPaint(mLayerPaint);
370371
}
371372

372373
if (mUpdateSurface) {

core/java/android/view/View.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11932,13 +11932,13 @@ public boolean isDuplicateParentStateEnabled() {
1193211932
* {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
1193311933
* this view's alpha value. Calling {@link #setAlpha(float)} is therefore
1193411934
* equivalent to setting a hardware layer on this view and providing a paint with
11935-
* the desired alpha value.<p>
11935+
* the desired alpha value.</p>
1193611936
*
1193711937
* <p>Refer to the documentation of {@link #LAYER_TYPE_NONE disabled},
1193811938
* {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware}
1193911939
* for more information on when and how to use layers.</p>
1194011940
*
11941-
* @param layerType The ype of layer to use with this view, must be one of
11941+
* @param layerType The type of layer to use with this view, must be one of
1194211942
* {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
1194311943
* {@link #LAYER_TYPE_HARDWARE}
1194411944
* @param paint The paint used to compose the layer. This argument is optional
@@ -11989,6 +11989,50 @@ public void setLayerType(int layerType, Paint paint) {
1198911989
invalidate(true);
1199011990
}
1199111991

11992+
/**
11993+
* Updates the {@link Paint} object used with the current layer (used only if the current
11994+
* layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint
11995+
* provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time
11996+
* the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to
11997+
* ensure that the view gets redrawn immediately.
11998+
*
11999+
* <p>A layer is associated with an optional {@link android.graphics.Paint}
12000+
* instance that controls how the layer is composed on screen. The following
12001+
* properties of the paint are taken into account when composing the layer:</p>
12002+
* <ul>
12003+
* <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li>
12004+
* <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li>
12005+
* <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
12006+
* </ul>
12007+
*
12008+
* <p>If this view has an alpha value set to < 1.0 by calling
12009+
* {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
12010+
* this view's alpha value. Calling {@link #setAlpha(float)} is therefore
12011+
* equivalent to setting a hardware layer on this view and providing a paint with
12012+
* the desired alpha value.</p>
12013+
*
12014+
* @param paint The paint used to compose the layer. This argument is optional
12015+
* and can be null. It is ignored when the layer type is
12016+
* {@link #LAYER_TYPE_NONE}
12017+
*
12018+
* @see #setLayerType(int, android.graphics.Paint)
12019+
*/
12020+
public void setLayerPaint(Paint paint) {
12021+
int layerType = getLayerType();
12022+
if (layerType != LAYER_TYPE_NONE) {
12023+
mLayerPaint = paint == null ? new Paint() : paint;
12024+
if (layerType == LAYER_TYPE_HARDWARE) {
12025+
HardwareLayer layer = getHardwareLayer();
12026+
if (layer != null) {
12027+
layer.setLayerPaint(paint);
12028+
}
12029+
invalidateViewProperty(false, false);
12030+
} else {
12031+
invalidate();
12032+
}
12033+
}
12034+
}
12035+
1199212036
/**
1199312037
* Indicates whether this view has a static layer. A view with layer type
1199412038
* {@link #LAYER_TYPE_NONE} is a static layer. Other types of layers are
@@ -12101,6 +12145,7 @@ HardwareLayer getHardwareLayer() {
1210112145
if (!mHardwareLayer.isValid()) {
1210212146
return null;
1210312147
}
12148+
mHardwareLayer.setLayerPaint(mLayerPaint);
1210412149

1210512150
mHardwareLayer.redraw(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect);
1210612151
mLocalDirtyRect.setEmpty();

core/jni/android_view_GLES20Canvas.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,20 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
776776
env->ReleaseIntArrayElements(layerInfo, storage, 0);
777777
}
778778

779+
static void android_view_GLES20Canvas_setLayerPaint(JNIEnv* env, jobject clazz,
780+
Layer* layer, SkPaint* paint) {
781+
if (layer) {
782+
layer->setPaint(paint);
783+
}
784+
}
785+
786+
static void android_view_GLES20Canvas_setLayerColorFilter(JNIEnv* env, jobject clazz,
787+
Layer* layer, SkiaColorFilter* colorFilter) {
788+
if (layer) {
789+
layer->setColorFilter(colorFilter);
790+
}
791+
}
792+
779793
static void android_view_GLES20Canvas_setOpaqueLayer(JNIEnv* env, jobject clazz,
780794
Layer* layer, jboolean isOpaque) {
781795
if (layer) {
@@ -979,6 +993,8 @@ static JNINativeMethod gMethods[] = {
979993
{ "nCreateLayerRenderer", "(I)I", (void*) android_view_GLES20Canvas_createLayerRenderer },
980994
{ "nCreateLayer", "(IIZ[I)I", (void*) android_view_GLES20Canvas_createLayer },
981995
{ "nResizeLayer", "(III[I)V" , (void*) android_view_GLES20Canvas_resizeLayer },
996+
{ "nSetLayerPaint", "(II)V", (void*) android_view_GLES20Canvas_setLayerPaint },
997+
{ "nSetLayerColorFilter", "(II)V", (void*) android_view_GLES20Canvas_setLayerColorFilter },
982998
{ "nSetOpaqueLayer", "(IZ)V", (void*) android_view_GLES20Canvas_setOpaqueLayer },
983999
{ "nCreateTextureLayer", "(Z[I)I", (void*) android_view_GLES20Canvas_createTextureLayer },
9841000
{ "nUpdateTextureLayer", "(IIIZLandroid/graphics/SurfaceTexture;)V",

libs/hwui/Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
1616
Dither.cpp \
1717
FboCache.cpp \
1818
GradientCache.cpp \
19+
Layer.cpp \
1920
LayerCache.cpp \
2021
LayerRenderer.cpp \
2122
Matrix.cpp \

libs/hwui/DisplayListRenderer.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,29 +1004,39 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
10041004
}
10051005
break;
10061006
case DrawLayer: {
1007+
int oldAlpha = -1;
10071008
Layer* layer = (Layer*) getInt();
10081009
float x = getFloat();
10091010
float y = getFloat();
10101011
SkPaint* paint = getPaint(renderer);
1011-
if (mCaching) {
1012-
paint->setAlpha(mMultipliedAlpha);
1012+
if (mCaching && mMultipliedAlpha < 255) {
1013+
oldAlpha = layer->getAlpha();
1014+
layer->setAlpha(mMultipliedAlpha);
10131015
}
10141016
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
10151017
layer, x, y, paint);
10161018
drawGlStatus |= renderer.drawLayer(layer, x, y, paint);
1019+
if (oldAlpha >= 0) {
1020+
layer->setAlpha(oldAlpha);
1021+
}
10171022
}
10181023
break;
10191024
case DrawBitmap: {
1025+
int oldAlpha = -1;
10201026
SkBitmap* bitmap = getBitmap();
10211027
float x = getFloat();
10221028
float y = getFloat();
10231029
SkPaint* paint = getPaint(renderer);
1024-
if (mCaching) {
1030+
if (mCaching && mMultipliedAlpha < 255) {
1031+
oldAlpha = paint->getAlpha();
10251032
paint->setAlpha(mMultipliedAlpha);
10261033
}
10271034
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
10281035
bitmap, x, y, paint);
10291036
drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint);
1037+
if (oldAlpha >= 0) {
1038+
paint->setAlpha(oldAlpha);
1039+
}
10301040
}
10311041
break;
10321042
case DrawBitmapMatrix: {

libs/hwui/Layer.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (C) 2012 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#define LOG_TAG "OpenGLRenderer"
18+
19+
#include <utils/Log.h>
20+
21+
#include "Layer.h"
22+
#include "OpenGLRenderer.h"
23+
#include "Caches.h"
24+
25+
namespace android {
26+
namespace uirenderer {
27+
28+
Layer::~Layer() {
29+
if (mesh) delete mesh;
30+
if (meshIndices) delete meshIndices;
31+
if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
32+
}
33+
34+
void Layer::setPaint(SkPaint* paint) {
35+
OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
36+
}
37+
38+
void Layer::setColorFilter(SkiaColorFilter* filter) {
39+
if (colorFilter) {
40+
Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
41+
}
42+
colorFilter = filter;
43+
if (colorFilter) {
44+
Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
45+
}
46+
}
47+
48+
49+
50+
}; // namespace uirenderer
51+
}; // namespace android

0 commit comments

Comments
 (0)