mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1389149 - Extract the logic from nsDisplayLayerEventRegions::AddFrame into a more reusable form. r=mstange
This introduces a enum bitset type that encapsulates some of the interesting properties that frames have that make it interesting for hit-testing in the compositor. This type is designed so it can be sent directly to webrender and gotten back in the hit-test. MozReview-Commit-ID: GCxV7ZaoJd1 --HG-- extra : rebase_source : a9cc5ecfc7c5baeab2f6e08cd2ee2c2a7756e20c
This commit is contained in:
parent
cb81178b8a
commit
26f0373ad0
44
gfx/src/CompositorHitTestInfo.h
Normal file
44
gfx/src/CompositorHitTestInfo.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_COMPOSITORHITTESTINFO_H_
|
||||
#define MOZILLA_GFX_COMPOSITORHITTESTINFO_H_
|
||||
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
// This set of flags is used to figure out what information a frame has
|
||||
// that is relevant to hit-testing in the compositor. The flags are
|
||||
// intentionally set up so that if all of them are 0 the item is effectively
|
||||
// invisible to hit-testing, and no information for this frame needs to be
|
||||
// sent to the compositor.
|
||||
enum class CompositorHitTestInfo : uint8_t {
|
||||
// Shortcut for checking that none of the flags are set
|
||||
eInvisibleToHitTest = 0,
|
||||
|
||||
// The frame participates in hit-testing
|
||||
eVisibleToHitTest = 1 << 0,
|
||||
// The frame requires main-thread handling for events
|
||||
eDispatchToContent = 1 << 1,
|
||||
|
||||
// The touch action flags are set up so that the default of
|
||||
// touch-action:auto on an element leaves all the flags as 0.
|
||||
eTouchActionPanXDisabled = 1 << 2,
|
||||
eTouchActionPanYDisabled = 1 << 3,
|
||||
eTouchActionPinchZoomDisabled = 1 << 4,
|
||||
eTouchActionDoubleTapZoomDisabled = 1 << 5,
|
||||
// Mask to check for all the touch-action flags at once
|
||||
eTouchActionMask = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5),
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CompositorHitTestInfo)
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_GFX_COMPOSITORHITTESTINFO_H_ */
|
@ -47,6 +47,7 @@ EXPORTS.mozilla += [
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.gfx += [
|
||||
'CompositorHitTestInfo.h',
|
||||
'TiledRegion.h',
|
||||
]
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsFrameList.h"
|
||||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsPluginFrame.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIContentInlines.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -11182,6 +11183,80 @@ nsIFrame::AddSizeOfExcludingThisForTree(nsWindowSizes& aSizes) const
|
||||
}
|
||||
}
|
||||
|
||||
CompositorHitTestInfo
|
||||
nsIFrame::GetCompositorHitTestInfo(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
CompositorHitTestInfo result = CompositorHitTestInfo::eInvisibleToHitTest;
|
||||
|
||||
if (aBuilder->IsInsidePointerEventsNoneDoc()) {
|
||||
// Somewhere up the parent document chain is a subdocument with pointer-
|
||||
// events:none set on it.
|
||||
return result;
|
||||
}
|
||||
if (!GetParent()) {
|
||||
MOZ_ASSERT(IsViewportFrame());
|
||||
// Viewport frames are never event targets, other frames, like canvas frames,
|
||||
// are the event targets for any regions viewport frames may cover.
|
||||
return result;
|
||||
}
|
||||
uint8_t pointerEvents = StyleUserInterface()->GetEffectivePointerEvents(this);
|
||||
if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) {
|
||||
return result;
|
||||
}
|
||||
if (!StyleVisibility()->IsVisible()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Anything that didn't match the above conditions is visible to hit-testing.
|
||||
result |= CompositorHitTestInfo::eVisibleToHitTest;
|
||||
|
||||
if (aBuilder->IsBuildingNonLayerizedScrollbar() ||
|
||||
aBuilder->GetAncestorHasApzAwareEventHandler()) {
|
||||
// Scrollbars may be painted into a layer below the actual layer they will
|
||||
// scroll, and therefore wheel events may be dispatched to the outer frame
|
||||
// instead of the intended scrollframe. To address this, we force a d-t-c
|
||||
// region on scrollbar frames that won't be placed in their own layer. See
|
||||
// bug 1213324 for details.
|
||||
result |= CompositorHitTestInfo::eDispatchToContent;
|
||||
} else if (IsObjectFrame()) {
|
||||
// If the frame is a plugin frame and wants to handle wheel events as
|
||||
// default action, we should add the frame to dispatch-to-content region.
|
||||
nsPluginFrame* pluginFrame = do_QueryFrame(this);
|
||||
if (pluginFrame && pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
|
||||
result |= CompositorHitTestInfo::eDispatchToContent;
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame* touchActionFrame = this;
|
||||
if (nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(this)) {
|
||||
touchActionFrame = do_QueryFrame(scrollFrame);
|
||||
}
|
||||
uint32_t touchAction = nsLayoutUtils::GetTouchActionFromFrame(touchActionFrame);
|
||||
// The CSS allows the syntax auto | none | [pan-x || pan-y] | manipulation
|
||||
// so we can eliminate some combinations of things.
|
||||
if (touchAction == NS_STYLE_TOUCH_ACTION_AUTO) {
|
||||
// nothing to do
|
||||
} else if (touchAction & NS_STYLE_TOUCH_ACTION_MANIPULATION) {
|
||||
result |= CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled;
|
||||
} else {
|
||||
if (!(touchAction & NS_STYLE_TOUCH_ACTION_PAN_X)) {
|
||||
result |= CompositorHitTestInfo::eTouchActionPanXDisabled;
|
||||
}
|
||||
if (!(touchAction & NS_STYLE_TOUCH_ACTION_PAN_Y)) {
|
||||
result |= CompositorHitTestInfo::eTouchActionPanYDisabled;
|
||||
}
|
||||
if (touchAction & NS_STYLE_TOUCH_ACTION_NONE) {
|
||||
result |= CompositorHitTestInfo::eTouchActionPinchZoomDisabled
|
||||
| CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled;
|
||||
// pan-x and pan-y disabled flags will already have been set above
|
||||
MOZ_ASSERT(result & CompositorHitTestInfo::eTouchActionPanXDisabled);
|
||||
MOZ_ASSERT(result & CompositorHitTestInfo::eTouchActionPanYDisabled);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Box layout debugging
|
||||
#ifdef DEBUG_REFLOW
|
||||
int32_t gIndent2 = 0;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "Visibility.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsStyleContextInlines.h"
|
||||
#include "mozilla/gfx/CompositorHitTestInfo.h"
|
||||
#include "mozilla/gfx/MatrixFwd.h"
|
||||
#include "nsDisplayItemTypes.h"
|
||||
|
||||
@ -4145,6 +4146,8 @@ public:
|
||||
bool BuiltBlendContainer() { return mBuiltBlendContainer; }
|
||||
void SetBuiltBlendContainer(bool aBuilt) { mBuiltBlendContainer = aBuilt; }
|
||||
|
||||
mozilla::gfx::CompositorHitTestInfo GetCompositorHitTestInfo(nsDisplayListBuilder* aBuilder);
|
||||
|
||||
protected:
|
||||
static void DestroyAnonymousContent(nsPresContext* aPresContext,
|
||||
already_AddRefed<nsIContent>&& aContent);
|
||||
|
@ -82,7 +82,6 @@
|
||||
#include "nsDOMTokenList.h"
|
||||
#include "mozilla/RuleNodeCacheConditions.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsPluginFrame.h"
|
||||
#include "nsSVGMaskFrame.h"
|
||||
#include "nsTableCellFrame.h"
|
||||
#include "nsTableColFrame.h"
|
||||
@ -4838,30 +4837,11 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
||||
{
|
||||
NS_ASSERTION(aBuilder->FindReferenceFrameFor(aFrame) == aBuilder->FindReferenceFrameFor(mFrame),
|
||||
"Reference frame mismatch");
|
||||
if (aBuilder->IsInsidePointerEventsNoneDoc()) {
|
||||
// Somewhere up the parent document chain is a subdocument with pointer-
|
||||
// events:none set on it.
|
||||
CompositorHitTestInfo hitInfo =
|
||||
aFrame->GetCompositorHitTestInfo(aBuilder);
|
||||
if (hitInfo == CompositorHitTestInfo::eInvisibleToHitTest) {
|
||||
return;
|
||||
}
|
||||
if (!aFrame->GetParent()) {
|
||||
MOZ_ASSERT(aFrame->IsViewportFrame());
|
||||
// Viewport frames are never event targets, other frames, like canvas frames,
|
||||
// are the event targets for any regions viewport frames may cover.
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t pointerEvents =
|
||||
aFrame->StyleUserInterface()->GetEffectivePointerEvents(aFrame);
|
||||
if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) {
|
||||
return;
|
||||
}
|
||||
bool simpleRegions = aFrame->HasAnyStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
|
||||
if (!simpleRegions) {
|
||||
if (!aFrame->StyleVisibility()->IsVisible()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// XXX handle other pointerEvents values for SVG
|
||||
|
||||
@ -4892,6 +4872,11 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
||||
borderBox += aBuilder->ToReferenceFrame(aFrame);
|
||||
|
||||
bool borderBoxHasRoundedCorners = false;
|
||||
|
||||
// use the NS_FRAME_SIMPLE_EVENT_REGIONS to avoid calling the slightly
|
||||
// expensive HasNonZeroCorner function if we know from a previous run that
|
||||
// the frame has zero corners.
|
||||
bool simpleRegions = aFrame->HasAnyStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
|
||||
if (!simpleRegions) {
|
||||
if (nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius)) {
|
||||
borderBoxHasRoundedCorners = true;
|
||||
@ -4917,39 +4902,25 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
||||
mHitRegion.Add(aFrame, borderBox);
|
||||
}
|
||||
|
||||
if (aBuilder->IsBuildingNonLayerizedScrollbar() ||
|
||||
aBuilder->GetAncestorHasApzAwareEventHandler())
|
||||
{
|
||||
// Scrollbars may be painted into a layer below the actual layer they will
|
||||
// scroll, and therefore wheel events may be dispatched to the outer frame
|
||||
// instead of the intended scrollframe. To address this, we force a d-t-c
|
||||
// region on scrollbar frames that won't be placed in their own layer. See
|
||||
// bug 1213324 for details.
|
||||
if (hitInfo & CompositorHitTestInfo::eDispatchToContent) {
|
||||
mDispatchToContentHitRegion.Add(aFrame, borderBox);
|
||||
} else if (aFrame->IsObjectFrame()) {
|
||||
// If the frame is a plugin frame and wants to handle wheel events as
|
||||
// default action, we should add the frame to dispatch-to-content region.
|
||||
nsPluginFrame* pluginFrame = do_QueryFrame(aFrame);
|
||||
if (pluginFrame && pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
|
||||
mDispatchToContentHitRegion.Add(aFrame, borderBox);
|
||||
}
|
||||
}
|
||||
|
||||
// Touch action region
|
||||
|
||||
nsIFrame* touchActionFrame = aFrame;
|
||||
if (scrollFrame) {
|
||||
touchActionFrame = do_QueryFrame(scrollFrame);
|
||||
}
|
||||
uint32_t touchAction = nsLayoutUtils::GetTouchActionFromFrame(touchActionFrame);
|
||||
if (touchAction != NS_STYLE_TOUCH_ACTION_AUTO) {
|
||||
if (touchAction & NS_STYLE_TOUCH_ACTION_NONE) {
|
||||
auto touchFlags = hitInfo & CompositorHitTestInfo::eTouchActionMask;
|
||||
if (touchFlags) {
|
||||
// something was disabled
|
||||
if (touchFlags == CompositorHitTestInfo::eTouchActionMask) {
|
||||
// everything was disabled, so touch-action:none
|
||||
mNoActionRegion.Add(aFrame, borderBox);
|
||||
} else {
|
||||
if ((touchAction & NS_STYLE_TOUCH_ACTION_PAN_X)) {
|
||||
if (!(hitInfo & CompositorHitTestInfo::eTouchActionPanXDisabled)) {
|
||||
// pan-x is allowed
|
||||
mHorizontalPanRegion.Add(aFrame, borderBox);
|
||||
}
|
||||
if ((touchAction & NS_STYLE_TOUCH_ACTION_PAN_Y)) {
|
||||
if (!(hitInfo & CompositorHitTestInfo::eTouchActionPanYDisabled)) {
|
||||
// pan-y is allowed
|
||||
mVerticalPanRegion.Add(aFrame, borderBox);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user