diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 85a4767a671..82de0f3010b 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -141,7 +141,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, aCompositor ? aCompositor->RootLayerTreeId() : 0, gfx3DMatrix(), nullptr, nullptr, aIsFirstPaint, aOriginatingLayersId, - paintLogger, &apzcsToDestroy); + paintLogger, &apzcsToDestroy, nsIntRegion()); mApzcTreeLog << "[end]\n"; } @@ -160,10 +160,13 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, bool aIsFirstPaint, uint64_t aOriginatingLayersId, const APZPaintLogHelper& aPaintLogger, - nsTArray< nsRefPtr >* aApzcsToDestroy) + nsTArray< nsRefPtr >* aApzcsToDestroy, + const nsIntRegion& aObscured) { mTreeLock.AssertCurrentThreadOwns(); + gfx3DMatrix transform = gfx::To3DMatrix(aLayer->GetTransform()); + ContainerLayer* container = aLayer->AsContainerLayer(); AsyncPanZoomController* apzc = nullptr; mApzcTreeLog << aLayer->Name() << '\t'; @@ -244,9 +247,17 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, * metrics.mDevPixelsPerCSSPixel * metrics.GetParentResolution()); } - gfx3DMatrix transform = gfx::To3DMatrix(aLayer->GetTransform()); - apzc->SetLayerHitTestData(visible, aTransform, transform); + // Not sure what rounding option is the most correct here, but if we ever + // figure it out we can change this. For now I'm rounding in to minimize + // the chances of getting a complex region. + ParentLayerIntRect roundedVisible = RoundedIn(visible); + nsIntRegion unobscured; + unobscured.Sub(nsIntRect(roundedVisible.x, roundedVisible.y, + roundedVisible.width, roundedVisible.height), + aObscured); + + apzc->SetLayerHitTestData(unobscured, aTransform, transform); APZCTM_LOG("Setting rect(%f %f %f %f) as visible region for APZC %p\n", visible.x, visible.y, visible.width, visible.height, apzc); @@ -311,10 +322,28 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, aTransform = gfx3DMatrix(); } else { // Multiply child layer transforms on the left so they get applied first - aTransform = gfx::To3DMatrix(aLayer->GetTransform()) * aTransform; + aTransform = transform * aTransform; } uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId); + + nsIntRegion obscured; + if (aLayersId == childLayersId) { + // If the child layer is in the same process, transform + // aObscured from aLayer's ParentLayerPixels to aLayer's LayerPixels, + // which are the children layers' ParentLayerPixels. + // If we cross a process boundary, we assume that we can start with + // an empty obscured region because nothing in the parent process will + // obscure the child process. This may be false. However, not doing this + // definitely runs into a problematic case where the B2G notification + // bar and the keyboard get merged into a single layer that obscures + // all child processes, even though visually they do not. We'd probably + // have to check for mask layers and so on in order to properly handle + // that case. + obscured = aObscured; + obscured.Transform(transform.Inverse()); + } + // If there's no APZC at this level, any APZCs for our child layers will // have our siblings as siblings. AsyncPanZoomController* next = apzc ? nullptr : aNextSibling; @@ -322,7 +351,17 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, gfx::TreeAutoIndent indent(mApzcTreeLog); next = UpdatePanZoomControllerTree(aCompositor, child, childLayersId, aTransform, aParent, next, aIsFirstPaint, aOriginatingLayersId, - aPaintLogger, aApzcsToDestroy); + aPaintLogger, aApzcsToDestroy, obscured); + + // Each layer obscures its previous siblings, so we augment the obscured + // region as we loop backwards through the children. + nsIntRegion childRegion = child->GetVisibleRegion(); + childRegion.Transform(gfx::To3DMatrix(child->GetTransform())); + if (child->GetClipRect()) { + childRegion.AndWith(*child->GetClipRect()); + } + + obscured.OrWith(childRegion); } // Return the APZC that should be the sibling of other APZCs as we continue diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index ec7ff5bb65e..229ec2412be 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -363,7 +363,8 @@ private: bool aIsFirstPaint, uint64_t aOriginatingLayersId, const APZPaintLogHelper& aPaintLogger, - nsTArray< nsRefPtr >* aApzcsToDestroy); + nsTArray< nsRefPtr >* aApzcsToDestroy, + const nsIntRegion& aObscured); private: /* Whenever walking or mutating the tree rooted at mRootApzc, mTreeLock must be held. diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index d35ab7cca94..db09163d102 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -21,6 +21,7 @@ #include "Axis.h" #include "TaskThrottler.h" #include "gfx3DMatrix.h" +#include "nsRegion.h" #include "base/message_loop.h" @@ -941,9 +942,9 @@ private: * hit-testing to see which APZC instance should handle touch events. */ public: - void SetLayerHitTestData(const ParentLayerRect& aRect, const gfx3DMatrix& aTransformToLayer, + void SetLayerHitTestData(const nsIntRegion& aRegion, const gfx3DMatrix& aTransformToLayer, const gfx3DMatrix& aTransformForLayer) { - mVisibleRect = aRect; + mVisibleRegion = aRegion; mAncestorTransform = aTransformToLayer; mCSSTransform = aTransformForLayer; UpdateTransformScale(); @@ -958,7 +959,8 @@ public: } bool VisibleRegionContains(const ParentLayerPoint& aPoint) const { - return mVisibleRect.Contains(aPoint); + ParentLayerIntPoint point = RoundedToInt(aPoint); + return mVisibleRegion.Contains(point.x, point.y); } bool IsOverscrolled() const { @@ -969,7 +971,7 @@ private: /* This is the visible region of the layer that this APZC corresponds to, in * that layer's screen pixels (the same coordinate system in which this APZC * receives events in ReceiveInputEvent()). */ - ParentLayerRect mVisibleRect; + nsIntRegion mVisibleRegion; /* This is the cumulative CSS transform for all the layers between the parent * APZC and this one (not inclusive) */ gfx3DMatrix mAncestorTransform; diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 930ad4286cb..fa6660bed05 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -1545,15 +1545,18 @@ TEST_F(APZCTreeManagerTester, HitTesting1) { SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 1); manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, paintSequenceNumber++); EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController()); - hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko); + hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko); EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); - // expect hit point at LayerIntPoint(15, 15) - EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15))); - EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15))); + // expect hit point at LayerIntPoint(25, 25) + EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25))); + EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(25, 25))); + + // At this point, layers[4] obscures layers[3] at the point (15, 15) so + // hitting there should hit the root APZC + hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko); + EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); // Now test hit testing when we have two scrollable layers - hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko); - EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get()); SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 2); manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, paintSequenceNumber++); hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);