From b3cca876c2e11b865cb4f83abe2c48a60b95af5b Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Fri, 8 Aug 2014 18:42:51 -0700 Subject: [PATCH] Fix ripples projecting to scrolled view bug:16873774 1) Fix projectionReceiveIndex, which could in some cases point at translate/restore ops. 2) Use background translateX / translateY for projected RenderNodes. This makes them match background position, and thus properly account for scroll. Change-Id: Idbd5700858fd67c5abea0270a1012952fe09ac22 --- libs/hwui/DisplayListRenderer.cpp | 16 ++++++++-------- libs/hwui/DisplayListRenderer.h | 10 ++++++---- libs/hwui/RenderNode.cpp | 15 ++++++++++++--- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index b210e64588310..f0a6e55345582 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -176,15 +176,15 @@ bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { status_t DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) { // dirty is an out parameter and should not be recorded, // it matters only when replaying the display list + DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform()); + int opIndex = addDrawOp(op); + mDisplayListData->addChild(op); if (renderNode->stagingProperties().isProjectionReceiver()) { // use staging property, since recording on UI thread - mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size(); + mDisplayListData->projectionReceiveIndex = opIndex; } - DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform()); - addDrawOp(op); - mDisplayListData->addChild(op); return DrawGlInfo::kStatusDone; } @@ -447,11 +447,11 @@ void DisplayListRenderer::insertTranslate() { } } -void DisplayListRenderer::addStateOp(StateOp* op) { - addOpInternal(op); +int DisplayListRenderer::addStateOp(StateOp* op) { + return addOpInternal(op); } -void DisplayListRenderer::addDrawOp(DrawOp* op) { +int DisplayListRenderer::addDrawOp(DrawOp* op) { Rect localBounds; if (op->getLocalBounds(localBounds)) { bool rejected = quickRejectConservative(localBounds.left, localBounds.top, @@ -460,7 +460,7 @@ void DisplayListRenderer::addDrawOp(DrawOp* op) { } mDisplayListData->hasDrawOps = true; - addOpInternal(op); + return addOpInternal(op); } }; // namespace uirenderer diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 1b3a48a0233bd..b5c0159fdb2e8 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -158,12 +158,14 @@ private: void insertTranslate(); LinearAllocator& alloc() { return mDisplayListData->allocator; } - void addStateOp(StateOp* op); - void addDrawOp(DrawOp* op); - void addOpInternal(DisplayListOp* op) { + + // Each method returns final index of op + int addStateOp(StateOp* op); + int addDrawOp(DrawOp* op); + int addOpInternal(DisplayListOp* op) { insertRestoreToCount(); insertTranslate(); - mDisplayListData->displayListOps.add(op); + return mDisplayListData->displayListOps.add(op); } template diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index c59b010818c32..e3732a19bc213 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -741,15 +741,24 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& const SkPath* projectionReceiverOutline = properties().getOutline().getPath(); int restoreTo = renderer.getSaveCount(); + LinearAllocator& alloc = handler.allocator(); + handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag), + PROPERTY_SAVECOUNT, properties().getClipToBounds()); + + // Transform renderer to match background we're projecting onto + // (by offsetting canvas by translationX/Y of background rendernode, since only those are set) + const DisplayListOp* op = + (mDisplayListData->displayListOps[mDisplayListData->projectionReceiveIndex]); + const DrawRenderNodeOp* backgroundOp = reinterpret_cast(op); + const RenderProperties& backgroundProps = backgroundOp->mRenderNode->properties(); + renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY()); + // If the projection reciever has an outline, we mask each of the projected rendernodes to it // Either with clipRect, or special saveLayer masking - LinearAllocator& alloc = handler.allocator(); if (projectionReceiverOutline != NULL) { const SkRect& outlineBounds = projectionReceiverOutline->getBounds(); if (projectionReceiverOutline->isRect(NULL)) { // mask to the rect outline simply with clipRect - handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); ClipRectOp* clipOp = new (alloc) ClipRectOp( outlineBounds.left(), outlineBounds.top(), outlineBounds.right(), outlineBounds.bottom(), SkRegion::kIntersect_Op);