Bug 1357903 - Clip event regions when combining them to a containing PaintedLayerData. r=mstange
MozReview-Commit-ID: 9Z3ITH5raXl
--- 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 FrameType : 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;
@@ -2581,26 +2582,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);
}
@@ -1786,24 +1788,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;
@@ -3321,69 +3325,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);
@@ -4668,17 +4691,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;