mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 945203. Part 4: Add nsDisplayEventRegions and build it when painting. r=mats
--HG-- extra : rebase_source : 26b71b6a18681e8fc48c6082c8df6263c1bd3739
This commit is contained in:
parent
b842ce7261
commit
67dd0d7a70
@ -22,6 +22,7 @@ DECLARE_DISPLAY_ITEM_TYPE(CHECKED_RADIOBUTTON)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(COLUMN_RULE)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(COMBOBOX_FOCUS)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(EVENT_RECEIVER)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(LAYER_EVENT_REGIONS)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(FIELDSET_BORDER_BACKGROUND)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITION)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(FORCEPAINTONSCROLL)
|
||||
|
@ -474,6 +474,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
Mode aMode, bool aBuildCaret)
|
||||
: mReferenceFrame(aReferenceFrame),
|
||||
mIgnoreScrollFrame(nullptr),
|
||||
mLayerEventRegions(nullptr),
|
||||
mCurrentTableItem(nullptr),
|
||||
mFinalTransparentRegion(nullptr),
|
||||
mCachedOffsetFrame(aReferenceFrame),
|
||||
@ -496,7 +497,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
mIsPaintingToWindow(false),
|
||||
mIsCompositingCheap(false),
|
||||
mContainsPluginItem(false),
|
||||
mContainsBlendMode(false)
|
||||
mContainsBlendMode(false),
|
||||
mAncestorHasTouchEventHandler(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplayListBuilder);
|
||||
PL_InitArenaPool(&mPool, "displayListArena", 1024,
|
||||
@ -2498,6 +2500,40 @@ nsDisplayEventReceiver::HitTest(nsDisplayListBuilder* aBuilder,
|
||||
aOutFrames->AppendElement(mFrame);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
NS_ASSERTION(aBuilder->FindReferenceFrameFor(aFrame) == aBuilder->FindReferenceFrameFor(mFrame),
|
||||
"Reference frame mismatch");
|
||||
uint8_t pointerEvents = aFrame->StyleVisibility()->mPointerEvents;
|
||||
if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) {
|
||||
return;
|
||||
}
|
||||
// XXX handle other pointerEvents values for SVG
|
||||
// XXX Do something clever here for the common case where the border box
|
||||
// is obviously entirely inside mHitRegion.
|
||||
nsRect borderBox(aBuilder->ToReferenceFrame(aFrame), aFrame->GetSize());
|
||||
const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
|
||||
bool borderBoxHasRoundedCorners =
|
||||
nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius);
|
||||
if (clip) {
|
||||
borderBox = clip->ApplyNonRoundedIntersection(borderBox);
|
||||
if (clip->GetRoundedRectCount() > 0) {
|
||||
borderBoxHasRoundedCorners = true;
|
||||
}
|
||||
}
|
||||
if (borderBoxHasRoundedCorners ||
|
||||
(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
|
||||
mMaybeHitRegion.Or(mMaybeHitRegion, borderBox);
|
||||
} else {
|
||||
mHitRegion.Or(mHitRegion, borderBox);
|
||||
}
|
||||
if (aBuilder->GetAncestorHasTouchEventHandler()) {
|
||||
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) {
|
||||
|
@ -35,6 +35,7 @@ class nsIContent;
|
||||
class nsRenderingContext;
|
||||
class nsDisplayTableItem;
|
||||
class nsISelection;
|
||||
class nsDisplayLayerEventRegions;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -296,6 +297,24 @@ public:
|
||||
bool AllowMergingAndFlattening() { return mAllowMergingAndFlattening; }
|
||||
void SetAllowMergingAndFlattening(bool aAllow) { mAllowMergingAndFlattening = aAllow; }
|
||||
|
||||
nsDisplayLayerEventRegions* GetLayerEventRegions() { return mLayerEventRegions; }
|
||||
void SetLayerEventRegions(nsDisplayLayerEventRegions* aItem)
|
||||
{
|
||||
mLayerEventRegions = aItem;
|
||||
}
|
||||
bool IsBuildingLayerEventRegions()
|
||||
{
|
||||
// Disable for now.
|
||||
return false;
|
||||
// return mMode == PAINTING;
|
||||
}
|
||||
|
||||
bool GetAncestorHasTouchEventHandler() { return mAncestorHasTouchEventHandler; }
|
||||
void SetAncestorHasTouchEventHandler(bool aValue)
|
||||
{
|
||||
mAncestorHasTouchEventHandler = aValue;
|
||||
}
|
||||
|
||||
bool SetIsCompositingCheap(bool aCompositingCheap) {
|
||||
bool temp = mIsCompositingCheap;
|
||||
mIsCompositingCheap = aCompositingCheap;
|
||||
@ -488,8 +507,11 @@ public:
|
||||
: mBuilder(aBuilder),
|
||||
mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame),
|
||||
mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame),
|
||||
mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
|
||||
mPrevCachedOffset(aBuilder->mCachedOffset),
|
||||
mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext) {
|
||||
mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
|
||||
mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler)
|
||||
{
|
||||
aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
|
||||
}
|
||||
AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
@ -497,8 +519,10 @@ public:
|
||||
: mBuilder(aBuilder),
|
||||
mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame),
|
||||
mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame),
|
||||
mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
|
||||
mPrevCachedOffset(aBuilder->mCachedOffset),
|
||||
mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext)
|
||||
mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
|
||||
mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler)
|
||||
{
|
||||
if (aForChild->IsTransformed()) {
|
||||
aBuilder->mCachedOffset = nsPoint();
|
||||
@ -514,15 +538,19 @@ public:
|
||||
~AutoBuildingDisplayList() {
|
||||
mBuilder->mCachedOffsetFrame = mPrevCachedOffsetFrame;
|
||||
mBuilder->mCachedReferenceFrame = mPrevCachedReferenceFrame;
|
||||
mBuilder->mLayerEventRegions = mPrevLayerEventRegions;
|
||||
mBuilder->mCachedOffset = mPrevCachedOffset;
|
||||
mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
|
||||
mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler;
|
||||
}
|
||||
private:
|
||||
nsDisplayListBuilder* mBuilder;
|
||||
const nsIFrame* mPrevCachedOffsetFrame;
|
||||
const nsIFrame* mPrevCachedReferenceFrame;
|
||||
nsDisplayLayerEventRegions* mPrevLayerEventRegions;
|
||||
nsPoint mPrevCachedOffset;
|
||||
bool mPrevIsAtRootOfPseudoStackingContext;
|
||||
bool mPrevAncestorHasTouchEventHandler;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -629,6 +657,7 @@ private:
|
||||
|
||||
nsIFrame* mReferenceFrame;
|
||||
nsIFrame* mIgnoreScrollFrame;
|
||||
nsDisplayLayerEventRegions* mLayerEventRegions;
|
||||
PLArenaPool mPool;
|
||||
nsCOMPtr<nsISelection> mBoundingSelection;
|
||||
nsAutoTArray<PresShellState,8> mPresShellStates;
|
||||
@ -665,6 +694,7 @@ private:
|
||||
bool mIsCompositingCheap;
|
||||
bool mContainsPluginItem;
|
||||
bool mContainsBlendMode;
|
||||
bool mAncestorHasTouchEventHandler;
|
||||
};
|
||||
|
||||
class nsDisplayItem;
|
||||
@ -2318,6 +2348,66 @@ public:
|
||||
NS_DISPLAY_DECL_NAME("EventReceiver", TYPE_EVENT_RECEIVER)
|
||||
};
|
||||
|
||||
/**
|
||||
* A display item that tracks event-sensitive regions which will be set
|
||||
* on the ContainerLayer that eventually contains this item.
|
||||
*
|
||||
* One of these is created for each stacking context and pseudo-stacking-context.
|
||||
* It accumulates regions for event targets contributed by the border-boxes of
|
||||
* frames in its (pseudo) stacking context. A nsDisplayLayerEventRegions
|
||||
* eventually contributes its regions to the ThebesLayer it is placed in by
|
||||
* FrameLayerBuilder. (We don't create a display item for every frame that
|
||||
* could be an event target (i.e. almost all frames), because that would be
|
||||
* high overhead.)
|
||||
*
|
||||
* We always make leaf layers other than ThebesLayers transparent to events.
|
||||
* For example, an event targeting a canvas or video will actually target the
|
||||
* background of that element, which is logically in the ThebesLayer behind the
|
||||
* CanvasFrame or ImageFrame. We only need to create a
|
||||
* nsDisplayLayerEventRegions when an element's background could be in front
|
||||
* of a lower z-order element with its own layer.
|
||||
*/
|
||||
class nsDisplayLayerEventRegions MOZ_FINAL : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayLayerEventRegions(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
||||
: nsDisplayItem(aBuilder, aFrame)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplayEventReceiver);
|
||||
AddFrame(aBuilder, aFrame);
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayLayerEventRegions() {
|
||||
MOZ_COUNT_DTOR(nsDisplayEventReceiver);
|
||||
}
|
||||
#endif
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE
|
||||
{
|
||||
*aSnap = false;
|
||||
return mHitRegion.GetBounds().Union(mMaybeHitRegion.GetBounds());
|
||||
}
|
||||
|
||||
NS_DISPLAY_DECL_NAME("LayerEventRegions", TYPE_LAYER_EVENT_REGIONS)
|
||||
|
||||
// Indicate that aFrame's border-box contributes to the event regions for
|
||||
// this layer. aFrame must have the same reference frame as mFrame.
|
||||
void AddFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
|
||||
|
||||
const nsRegion& HitRegion() { return mHitRegion; }
|
||||
const nsRegion& MaybeHitRegion() { return mMaybeHitRegion; }
|
||||
const nsRegion& DispatchToContentHitRegion() { return mDispatchToContentHitRegion; }
|
||||
|
||||
private:
|
||||
// Relative to aFrame's reference frame.
|
||||
// These are the points that are definitely in the hit region.
|
||||
nsRegion mHitRegion;
|
||||
// These are points that may or may not be in the hit region. Only main-thread
|
||||
// event handling can tell for sure (e.g. because complex shapes are present).
|
||||
nsRegion mMaybeHitRegion;
|
||||
// These are points that need to be dispatched to the content thread for
|
||||
// resolution. Always contained in the union of mHitRegion and mMaybeHitRegion.
|
||||
nsRegion mDispatchToContentHitRegion;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that lets you wrap a display list as a display item.
|
||||
*
|
||||
|
@ -77,6 +77,7 @@
|
||||
#include "gfxASurface.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsIFrameInlines.h"
|
||||
#include "nsEventListenerManager.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
@ -1789,6 +1790,23 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
CheckForTouchEventHandler(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
||||
{
|
||||
nsIContent* content = aFrame->GetContent();
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
nsEventListenerManager* elm = nsContentUtils::GetExistingListenerManagerForNode(content);
|
||||
if (!elm) {
|
||||
return;
|
||||
}
|
||||
if (elm->HasListenersFor(nsGkAtoms::ontouchstart) ||
|
||||
elm->HasListenersFor(nsGkAtoms::ontouchmove)) {
|
||||
aBuilder->SetAncestorHasTouchEventHandler(true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
@ -1878,6 +1896,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
|
||||
nsDisplayListBuilder::AutoInTransformSetter
|
||||
inTransformSetter(aBuilder, inTransform);
|
||||
CheckForTouchEventHandler(aBuilder, this);
|
||||
|
||||
if (usingSVGEffects) {
|
||||
dirtyRect =
|
||||
@ -1898,6 +1917,12 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
aBuilder->MarkPreserve3DFramesForDisplayList(this, aDirtyRect);
|
||||
}
|
||||
|
||||
if (aBuilder->IsBuildingLayerEventRegions()) {
|
||||
nsDisplayLayerEventRegions* eventRegions =
|
||||
new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
|
||||
aBuilder->SetLayerEventRegions(eventRegions);
|
||||
set.BorderBackground()->AppendNewToTop(eventRegions);
|
||||
}
|
||||
BuildDisplayList(aBuilder, dirtyRect, set);
|
||||
}
|
||||
|
||||
@ -2187,6 +2212,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayListBuilder::AutoBuildingDisplayList
|
||||
buildingForChild(aBuilder, child, pseudoStackingContext);
|
||||
DisplayListClipState::AutoClipMultiple clipState(aBuilder);
|
||||
CheckForTouchEventHandler(aBuilder, child);
|
||||
|
||||
if (savedOutOfFlowData) {
|
||||
clipState.SetClipForContainingBlockDescendants(
|
||||
@ -2231,6 +2257,10 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
// THIS IS THE COMMON CASE.
|
||||
// Not a pseudo or real stacking context. Do the simple thing and
|
||||
// return early.
|
||||
nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
|
||||
if (eventRegions) {
|
||||
eventRegions->AddFrame(aBuilder, child);
|
||||
}
|
||||
child->BuildDisplayList(aBuilder, dirty, aLists);
|
||||
aBuilder->DisplayCaret(child, dirty, aLists.Content());
|
||||
#ifdef DEBUG
|
||||
@ -2244,6 +2274,12 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
// stacking context's positioned descendant list, because they might be
|
||||
// z-index:non-auto
|
||||
nsDisplayListCollection pseudoStack;
|
||||
if (aBuilder->IsBuildingLayerEventRegions()) {
|
||||
nsDisplayLayerEventRegions* eventRegions =
|
||||
new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
|
||||
aBuilder->SetLayerEventRegions(eventRegions);
|
||||
pseudoStack.BorderBackground()->AppendNewToTop(eventRegions);
|
||||
}
|
||||
child->BuildDisplayList(aBuilder, dirty, pseudoStack);
|
||||
aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
|
||||
|
||||
|
@ -401,6 +401,7 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
|
||||
if (subdocRootFrame) {
|
||||
aBuilder->SetAncestorHasTouchEventHandler(false);
|
||||
subdocRootFrame->
|
||||
BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user