Clip TouchFeedbackDrawable effect to receiver Outline
Projected RenderNodes are now wrapped with a ClipRect or masked
SaveLayer, so that they are clipped to the outline of the projection
receiver surface.
Change-Id: I1d4afc1bb5d638d650bc0b1dac51a498f216773e
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f37487f..1f5389c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -704,11 +704,11 @@
///////////////////////////////////////////////////////////////////////////////
int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags) {
+ const SkPaint* paint, int flags, const SkPath* convexMask) {
const int count = saveSnapshot(flags);
if (!currentSnapshot()->isIgnored()) {
- createLayer(left, top, right, bottom, paint, flags);
+ createLayer(left, top, right, bottom, paint, flags, convexMask);
}
return count;
@@ -782,7 +782,6 @@
return count;
}
-
/**
* Layers are viewed by Skia are slightly different than layers in image editing
* programs (for instance.) When a layer is created, previously created layers
@@ -835,7 +834,7 @@
* something actually gets drawn are the layers regions cleared.
*/
bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags) {
+ const SkPaint* paint, int flags, const SkPath* convexMask) {
LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
@@ -865,6 +864,7 @@
layer->setBlend(true);
layer->setDirty(false);
+ layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
// Save the layer in the snapshot
mSnapshot->flags |= Snapshot::kFlagIsLayer;
@@ -1013,6 +1013,7 @@
dirtyClip();
// Failing to add the layer to the cache should happen only if the layer is too large
+ layer->setConvexMask(NULL);
if (!mCaches.layerCache.put(layer)) {
LAYER_LOGD("Deleting layer");
Caches::getInstance().resourceCache.decrementRefcount(layer);
@@ -1122,6 +1123,38 @@
#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
+ if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
+
+ if (layer->getConvexMask()) {
+ save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+
+ // clip to the area of the layer the mask can be larger
+ clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
+
+ SkiaShader* oldShader = mDrawModifiers.mShader;
+
+ // create LayerShader to map SaveLayer content into subsequent draw
+ SkMatrix shaderMatrix;
+ shaderMatrix.setTranslate(rect.left, rect.bottom);
+ shaderMatrix.preScale(1, -1);
+ SkiaLayerShader layerShader(layer, &shaderMatrix);
+ mDrawModifiers.mShader = &layerShader;
+
+ // Since the drawing primitive is defined in local drawing space,
+ // we don't need to modify the draw matrix
+ const SkPath* maskPath = layer->getConvexMask();
+ DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
+
+ mDrawModifiers.mShader = oldShader;
+ restore();
+
+ return;
+ }
+
if (layer->region.isRect()) {
layer->setRegionAsRect();
@@ -1131,88 +1164,87 @@
return;
}
- if (CC_LIKELY(!layer->region.isEmpty())) {
- size_t count;
- const android::Rect* rects;
- Region safeRegion;
- if (CC_LIKELY(hasRectToRectTransform())) {
- rects = layer->region.getArray(&count);
- } else {
- safeRegion = Region::createTJunctionFreeRegion(layer->region);
- rects = safeRegion.getArray(&count);
- }
+ // standard Region based draw
+ size_t count;
+ const android::Rect* rects;
+ Region safeRegion;
+ if (CC_LIKELY(hasRectToRectTransform())) {
+ rects = layer->region.getArray(&count);
+ } else {
+ safeRegion = Region::createTJunctionFreeRegion(layer->region);
+ rects = safeRegion.getArray(&count);
+ }
- const float alpha = getLayerAlpha(layer);
- const float texX = 1.0f / float(layer->getWidth());
- const float texY = 1.0f / float(layer->getHeight());
- const float height = rect.getHeight();
+ const float alpha = getLayerAlpha(layer);
+ const float texX = 1.0f / float(layer->getWidth());
+ const float texY = 1.0f / float(layer->getHeight());
+ const float height = rect.getHeight();
- setupDraw();
+ setupDraw();
- // We must get (and therefore bind) the region mesh buffer
- // after we setup drawing in case we need to mess with the
- // stencil buffer in setupDraw()
- TextureVertex* mesh = mCaches.getRegionMesh();
- uint32_t numQuads = 0;
+ // We must get (and therefore bind) the region mesh buffer
+ // after we setup drawing in case we need to mess with the
+ // stencil buffer in setupDraw()
+ TextureVertex* mesh = mCaches.getRegionMesh();
+ uint32_t numQuads = 0;
- setupDrawWithTexture();
- setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter(layer->getColorFilter());
- setupDrawBlending(layer);
- setupDrawProgram();
- setupDrawDirtyRegionsDisabled();
- setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms(layer->getColorFilter());
- setupDrawTexture(layer->getTexture());
- if (currentTransform()->isPureTranslate()) {
- const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
- const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
+ setupDrawWithTexture();
+ setupDrawColor(alpha, alpha, alpha, alpha);
+ setupDrawColorFilter(layer->getColorFilter());
+ setupDrawBlending(layer);
+ setupDrawProgram();
+ setupDrawDirtyRegionsDisabled();
+ setupDrawPureColorUniforms();
+ setupDrawColorFilterUniforms(layer->getColorFilter());
+ setupDrawTexture(layer->getTexture());
+ if (currentTransform()->isPureTranslate()) {
+ const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
- layer->setFilter(GL_NEAREST);
- setupDrawModelView(kModelViewMode_Translate, false,
- x, y, x + rect.getWidth(), y + rect.getHeight(), true);
- } else {
- layer->setFilter(GL_LINEAR);
- setupDrawModelView(kModelViewMode_Translate, false,
- rect.left, rect.top, rect.right, rect.bottom);
- }
- setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
+ layer->setFilter(GL_NEAREST);
+ setupDrawModelView(kModelViewMode_Translate, false,
+ x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR);
+ setupDrawModelView(kModelViewMode_Translate, false,
+ rect.left, rect.top, rect.right, rect.bottom);
+ }
+ setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
- for (size_t i = 0; i < count; i++) {
- const android::Rect* r = &rects[i];
+ for (size_t i = 0; i < count; i++) {
+ const android::Rect* r = &rects[i];
- const float u1 = r->left * texX;
- const float v1 = (height - r->top) * texY;
- const float u2 = r->right * texX;
- const float v2 = (height - r->bottom) * texY;
+ const float u1 = r->left * texX;
+ const float v1 = (height - r->top) * texY;
+ const float u2 = r->right * texX;
+ const float v2 = (height - r->bottom) * texY;
- // TODO: Reject quads outside of the clip
- TextureVertex::set(mesh++, r->left, r->top, u1, v1);
- TextureVertex::set(mesh++, r->right, r->top, u2, v1);
- TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
- TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+ // TODO: Reject quads outside of the clip
+ TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+ TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+ TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+ TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
- numQuads++;
+ numQuads++;
- if (numQuads >= gMaxNumberOfQuads) {
- DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
- GL_UNSIGNED_SHORT, NULL));
- numQuads = 0;
- mesh = mCaches.getRegionMesh();
- }
- }
-
- if (numQuads > 0) {
+ if (numQuads >= gMaxNumberOfQuads) {
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
GL_UNSIGNED_SHORT, NULL));
+ numQuads = 0;
+ mesh = mCaches.getRegionMesh();
}
+ }
+
+ if (numQuads > 0) {
+ DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
+ GL_UNSIGNED_SHORT, NULL));
+ }
#if DEBUG_LAYERS_AS_REGIONS
- drawRegionRectsDebug(layer->region);
+ drawRegionRectsDebug(layer->region);
#endif
- layer->region.clear();
- }
+ layer->region.clear();
}
#if DEBUG_LAYERS_AS_REGIONS
@@ -2926,7 +2958,7 @@
if (layer->isTextureLayer()) {
transform = &layer->getTransform();
if (!transform->isIdentity()) {
- save(0);
+ save(SkCanvas::kMatrix_SaveFlag);
concatMatrix(*transform);
}
}