Bug 1357903 - Clip event regions when combining them to a containing PaintedLayerData. r=mstange
authorBotond Ballo <botond@mozilla.com>
Fri, 28 Apr 2017 20:32:05 -0400
changeset 356822 cd70682a78180ac48568a9d2b8dcd345627d40d3
parent 356821 5c219b4312a787fc2f0384959bd94c7037e8c054
child 356823 af0de3170a13ef58dfe923b86e2c1b998793f5ab
push id31775
push userihsiao@mozilla.com
push dateMon, 08 May 2017 03:10:38 +0000
treeherdermozilla-central@22aaf8bad4df [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1357903
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1357903 - Clip event regions when combining them to a containing PaintedLayerData. r=mstange MozReview-Commit-ID: 9Z3ITH5raXl
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/painting/FrameLayerBuilder.cpp
layout/painting/FrameLayerBuilder.h
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -117,16 +117,17 @@
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/RuleNodeCacheConditions.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "RegionBuilder.h"
 #include "SVGSVGElement.h"
+#include "DisplayItemClip.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 #include "GeckoProfiler.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
@@ -8933,26 +8934,33 @@ nsLayoutUtils::GetTouchActionFromFrame(n
 
 /* static */  void
 nsLayoutUtils::TransformToAncestorAndCombineRegions(
   const nsRegion& aRegion,
   nsIFrame* aFrame,
   const nsIFrame* aAncestorFrame,
   nsRegion* aPreciseTargetDest,
   nsRegion* aImpreciseTargetDest,
-  Maybe<Matrix4x4>* aMatrixCache)
+  Maybe<Matrix4x4>* aMatrixCache,
+  const DisplayItemClip* aClip)
 {
   if (aRegion.IsEmpty()) {
     return;
   }
   bool isPrecise;
   RegionBuilder<nsRegion> transformedRegion;
   for (nsRegion::RectIterator it = aRegion.RectIter(); !it.Done(); it.Next()) {
     nsRect transformed = TransformFrameRectToAncestor(
       aFrame, it.Get(), aAncestorFrame, &isPrecise, aMatrixCache);
+    if (aClip) {
+      transformed = aClip->ApplyNonRoundedIntersection(transformed);
+      if (aClip->GetRoundedRectCount() > 0) {
+        isPrecise = false;
+      }
+    }
     transformedRegion.OrWith(transformed);
   }
   nsRegion* dest = isPrecise ? aPreciseTargetDest : aImpreciseTargetDest;
   dest->OrWith(transformedRegion.ToRegion());
 }
 
 /* static */ bool
 nsLayoutUtils::ShouldUseNoScriptSheet(nsIDocument* aDocument)
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -65,16 +65,17 @@ struct nsOverflowAreas;
 
 namespace mozilla {
 enum class CSSPseudoElementType : uint8_t;
 class EventListenerManager;
 enum class LayoutFrameType : uint8_t;
 struct IntrinsicSize;
 struct ContainerLayerParameters;
 class WritingMode;
+class DisplayItemClip;
 namespace dom {
 class CanvasRenderingContext2D;
 class DOMRectList;
 class Element;
 class HTMLImageElement;
 class HTMLCanvasElement;
 class HTMLVideoElement;
 class OffscreenCanvas;
@@ -2584,26 +2585,29 @@ public:
    * Helper method to get touch action behaviour from the frame
    */
   static uint32_t
   GetTouchActionFromFrame(nsIFrame* aFrame);
 
   /**
    * Helper method to transform |aBounds| from aFrame to aAncestorFrame,
    * and combine it with |aPreciseTargetDest| if it is axis-aligned, or
-   * combine it with |aImpreciseTargetDest| if not.
+   * combine it with |aImpreciseTargetDest| if not. The transformed rect is
+   * clipped to |aClip|; if |aClip| has rounded corners, that also causes
+   * the imprecise target to be used.
    */
   static void
   TransformToAncestorAndCombineRegions(
     const nsRegion& aRegion,
     nsIFrame* aFrame,
     const nsIFrame* aAncestorFrame,
     nsRegion* aPreciseTargetDest,
     nsRegion* aImpreciseTargetDest,
-    mozilla::Maybe<Matrix4x4>* aMatrixCache);
+    mozilla::Maybe<Matrix4x4>* aMatrixCache,
+    const mozilla::DisplayItemClip* aClip);
 
   /**
    * Populate aOutSize with the size of the content viewer corresponding
    * to the given prescontext. Return true if the size was set, false
    * otherwise.
    */
   static bool
   GetContentViewerSize(nsPresContext* aPresContext,
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -113,16 +113,18 @@ static inline MaskLayerImageCache* GetMa
     gMaskLayerImageCache = new MaskLayerImageCache();
   }
 
   return gMaskLayerImageCache;
 }
 
 FrameLayerBuilder::FrameLayerBuilder()
   : mRetainingManager(nullptr)
+  , mContainingPaintedLayer(nullptr)
+  , mInactiveLayerClip(nullptr)
   , mDetectedDOMModification(false)
   , mInvalidateAllLayers(false)
   , mInLayerTreeCompressionMode(false)
   , mContainerLayerGeneration(0)
   , mMaxContainerLayerGeneration(0)
 {
   MOZ_COUNT_CTOR(FrameLayerBuilder);
 }
@@ -1783,24 +1785,26 @@ FrameLayerBuilder::Shutdown()
   if (gMaskLayerImageCache) {
     delete gMaskLayerImageCache;
     gMaskLayerImageCache = nullptr;
   }
 }
 
 void
 FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
-                        PaintedLayerData* aLayerData)
+                        PaintedLayerData* aLayerData,
+                        const DisplayItemClip* aInactiveLayerClip)
 {
   mDisplayListBuilder = aBuilder;
   mRootPresContext = aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext();
   if (mRootPresContext) {
     mInitialDOMGeneration = mRootPresContext->GetDOMGeneration();
   }
   mContainingPaintedLayer = aLayerData;
+  mInactiveLayerClip = aInactiveLayerClip;
   aManager->SetUserData(&gLayerManagerLayerBuilder, this);
 }
 
 void
 FrameLayerBuilder::FlashPaint(gfxContext *aContext)
 {
   float r = float(rand()) / RAND_MAX;
   float g = float(rand()) / RAND_MAX;
@@ -3314,69 +3318,88 @@ void ContainerState::FinishPaintedLayerD
   }
   if (data->mDisableFlattening) {
     flags |= Layer::CONTENT_DISABLE_FLATTENING;
   }
   layer->SetContentFlags(flags);
 
   PaintedLayerData* containingPaintedLayerData =
      mLayerBuilder->GetContainingPaintedLayerData();
+  // If we're building layers for an inactive layer, the event regions are
+  // clipped to the inactive layer's clip prior to being combined into the
+  // event regions of the containing PLD.
+  // For the dispatch-to-content and maybe-hit regions, rounded corners on
+  // the clip are ignored, since these are approximate regions. For the
+  // remaining regions, rounded corners in the clip cause the region to
+  // be combined into the corresponding "imprecise" region of the
+  // containing's PLD (e.g. the maybe-hit region instead of the hit region).
+  const DisplayItemClip* inactiveLayerClip = mLayerBuilder->GetInactiveLayerClip();
   if (containingPaintedLayerData) {
     if (!data->mDispatchToContentHitRegion.GetBounds().IsEmpty()) {
       nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
         mContainerReferenceFrame,
         data->mDispatchToContentHitRegion.GetBounds(),
         containingPaintedLayerData->mReferenceFrame);
+      if (inactiveLayerClip) {
+        rect = inactiveLayerClip->ApplyNonRoundedIntersection(rect);
+      }
       containingPaintedLayerData->mDispatchToContentHitRegion.Or(
         containingPaintedLayerData->mDispatchToContentHitRegion, rect);
     }
     if (!data->mMaybeHitRegion.GetBounds().IsEmpty()) {
       nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
         mContainerReferenceFrame,
         data->mMaybeHitRegion.GetBounds(),
         containingPaintedLayerData->mReferenceFrame);
+      if (inactiveLayerClip) {
+        rect = inactiveLayerClip->ApplyNonRoundedIntersection(rect);
+      }
       containingPaintedLayerData->mMaybeHitRegion.Or(
         containingPaintedLayerData->mMaybeHitRegion, rect);
       containingPaintedLayerData->mMaybeHitRegion.SimplifyOutward(8);
     }
     Maybe<Matrix4x4> matrixCache;
     nsLayoutUtils::TransformToAncestorAndCombineRegions(
       data->mHitRegion,
       mContainerReferenceFrame,
       containingPaintedLayerData->mReferenceFrame,
       &containingPaintedLayerData->mHitRegion,
       &containingPaintedLayerData->mMaybeHitRegion,
-      &matrixCache);
+      &matrixCache,
+      inactiveLayerClip);
     // See the comment in nsDisplayList::AddFrame, where the touch action regions
     // are handled. The same thing applies here.
     bool alreadyHadRegions =
         !containingPaintedLayerData->mNoActionRegion.IsEmpty() ||
         !containingPaintedLayerData->mHorizontalPanRegion.IsEmpty() ||
         !containingPaintedLayerData->mVerticalPanRegion.IsEmpty();
     nsLayoutUtils::TransformToAncestorAndCombineRegions(
       data->mNoActionRegion,
       mContainerReferenceFrame,
       containingPaintedLayerData->mReferenceFrame,
       &containingPaintedLayerData->mNoActionRegion,
       &containingPaintedLayerData->mDispatchToContentHitRegion,
-      &matrixCache);
+      &matrixCache,
+      inactiveLayerClip);
     nsLayoutUtils::TransformToAncestorAndCombineRegions(
       data->mHorizontalPanRegion,
       mContainerReferenceFrame,
       containingPaintedLayerData->mReferenceFrame,
       &containingPaintedLayerData->mHorizontalPanRegion,
       &containingPaintedLayerData->mDispatchToContentHitRegion,
-      &matrixCache);
+      &matrixCache,
+      inactiveLayerClip);
     nsLayoutUtils::TransformToAncestorAndCombineRegions(
       data->mVerticalPanRegion,
       mContainerReferenceFrame,
       containingPaintedLayerData->mReferenceFrame,
       &containingPaintedLayerData->mVerticalPanRegion,
       &containingPaintedLayerData->mDispatchToContentHitRegion,
-      &matrixCache);
+      &matrixCache,
+      inactiveLayerClip);
     if (alreadyHadRegions) {
       containingPaintedLayerData->mDispatchToContentHitRegion.OrWith(
         containingPaintedLayerData->CombinedTouchActionRegion());
     }
   } else {
     EventRegions regions;
     regions.mHitRegion = ScaleRegionToOutsidePixels(data->mHitRegion);
     regions.mNoActionRegion = ScaleRegionToOutsidePixels(data->mNoActionRegion);
@@ -4659,17 +4682,17 @@ FrameLayerBuilder::AddPaintedDisplayItem
   if (entry) {
     entry->mContainerLayerFrame = aContainerState.GetContainerFrame();
     if (entry->mContainerLayerGeneration == 0) {
       entry->mContainerLayerGeneration = mContainerLayerGeneration;
     }
     if (tempManager) {
       FLB_LOG_PAINTED_LAYER_DECISION(aLayerData, "Creating nested FLB for item %p\n", aItem);
       FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
-      layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData);
+      layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData, &aClip);
 
       tempManager->BeginTransaction();
       if (mRetainingManager) {
         layerBuilder->DidBeginRetainedLayerTransaction(tempManager);
       }
 
       UniquePtr<LayerProperties> props(LayerProperties::CloneFrom(tempManager->GetRoot()));
       RefPtr<Layer> tmpLayer =
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -194,17 +194,18 @@ public:
   typedef layers::EventRegions EventRegions;
 
   FrameLayerBuilder();
   ~FrameLayerBuilder();
 
   static void Shutdown();
 
   void Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
-            PaintedLayerData* aLayerData = nullptr);
+            PaintedLayerData* aLayerData = nullptr,
+            const DisplayItemClip* aInactiveLayerClip = nullptr);
 
   /**
    * Call this to notify that we have just started a transaction on the
    * retained layer manager aManager.
    */
   void DidBeginRetainedLayerTransaction(LayerManager* aManager);
 
   /**
@@ -688,16 +689,21 @@ public:
     return mPaintedLayerItems.GetEntry(aLayer);
   }
 
   PaintedLayerData* GetContainingPaintedLayerData()
   {
     return mContainingPaintedLayer;
   }
 
+  const DisplayItemClip* GetInactiveLayerClip() const
+  {
+    return mInactiveLayerClip;
+  }
+
   bool IsBuildingRetainedLayers()
   {
     return !mContainingPaintedLayer && mRetainingManager;
   }
 
   /**
    * Attempt to build the most compressed layer tree possible, even if it means
    * throwing away existing retained buffers.
@@ -737,16 +743,22 @@ protected:
 
   /**
    * When building layers for an inactive layer, this is where the
    * inactive layer will be placed.
    */
   PaintedLayerData*                   mContainingPaintedLayer;
 
   /**
+   * When building layers for an inactive layer, this stores the clip
+   * of the display item that built the inactive layer.
+   */
+  const DisplayItemClip*              mInactiveLayerClip;
+
+  /**
    * Saved generation counter so we can detect DOM changes.
    */
   uint32_t                            mInitialDOMGeneration;
   /**
    * Set to true if we have detected and reported DOM modification during
    * the current paint.
    */
   bool                                mDetectedDOMModification;