From 9a45cc9183e89d1347b7bb971f97a86b42d19508 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 2 Nov 2012 23:42:59 +1300 Subject: [PATCH] Bug 796452. Add mozpasspointerevents attribute for IFRAMEs in chrome windows. r=mats --- content/base/src/nsGkAtomList.h | 1 + layout/base/nsDisplayList.cpp | 2 +- layout/base/tests/chrome/Makefile.in | 2 ++ .../chrome/passpointerevents_window.html | 27 +++++++++++++++++++ .../tests/chrome/test_passpointerevents.html | 21 +++++++++++++++ layout/generic/nsSubDocumentFrame.cpp | 22 +++++++++++++-- layout/generic/nsSubDocumentFrame.h | 6 +++++ layout/style/nsStyleStruct.h | 4 ++- layout/style/nsStyleStructInlines.h | 16 +++++++++++ 9 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 layout/base/tests/chrome/passpointerevents_window.html create mode 100644 layout/base/tests/chrome/test_passpointerevents.html diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index f82b050b417d..0cdbe4a6b49a 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -570,6 +570,7 @@ GK_ATOM(mousethrough, "mousethrough") GK_ATOM(mouseup, "mouseup") GK_ATOM(mozfullscreenchange, "mozfullscreenchange") GK_ATOM(mozfullscreenerror, "mozfullscreenerror") +GK_ATOM(mozpasspointerevents, "mozpasspointerevents") GK_ATOM(mozpointerlockchange, "mozpointerlockchange") GK_ATOM(mozpointerlockerror, "mozpointerlockerror") GK_ATOM(moz_opaque, "moz-opaque") diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 11a7e5c83d86..75ad3abc734a 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1277,7 +1277,7 @@ void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, nsIFrame *f = outFrames.ElementAt(j); // Handle the XUL 'mousethrough' feature and 'pointer-events'. if (!GetMouseThrough(f) && - f->GetStyleVisibility()->mPointerEvents != NS_STYLE_POINTER_EVENTS_NONE) { + f->GetStyleVisibility()->GetEffectivePointerEvents(f) != NS_STYLE_POINTER_EVENTS_NONE) { writeFrames->AppendElement(f); } } diff --git a/layout/base/tests/chrome/Makefile.in b/layout/base/tests/chrome/Makefile.in index ebb56809b705..311d61809873 100644 --- a/layout/base/tests/chrome/Makefile.in +++ b/layout/base/tests/chrome/Makefile.in @@ -49,6 +49,8 @@ MOCHITEST_CHROME_FILES = \ test_dialog_with_positioning.html \ dialog_with_positioning_window.xul \ blue-32x32.png \ + test_passpointerevents.html \ + passpointerevents_window.html \ $(NULL) ifdef MOZ_DEBUG diff --git a/layout/base/tests/chrome/passpointerevents_window.html b/layout/base/tests/chrome/passpointerevents_window.html new file mode 100644 index 000000000000..c3dd913a1c0f --- /dev/null +++ b/layout/base/tests/chrome/passpointerevents_window.html @@ -0,0 +1,27 @@ + + + + Test that mozpasspointerevents works + + + + + + + diff --git a/layout/base/tests/chrome/test_passpointerevents.html b/layout/base/tests/chrome/test_passpointerevents.html new file mode 100644 index 000000000000..e1ffaa03f54a --- /dev/null +++ b/layout/base/tests/chrome/test_passpointerevents.html @@ -0,0 +1,21 @@ + + + + Test that mozpasspointerevents works + + + + + + +
+
+
+ + diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index ef08a2f51c0c..74e31eec5313 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -235,6 +235,23 @@ nsSubDocumentFrame::GetSubdocumentRootFrame() return subdocView ? subdocView->GetFrame() : nullptr; } +bool +nsSubDocumentFrame::PassPointerEventsToChildren() +{ + if (GetStyleVisibility()->mPointerEvents != NS_STYLE_POINTER_EVENTS_NONE) { + return true; + } + // Limit use of mozpasspointerevents to chrome documents, because + // this could be used by the parent document to discover which parts of the + // subdocument are transparent to events (if subdocument uses + // pointer-events:none on its root element, which is admittedly unlikely) + if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozpasspointerevents) && + PresContext()->IsChrome()) { + return true; + } + return false; +} + NS_IMETHODIMP nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, @@ -243,8 +260,9 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, if (!IsVisibleForPainting(aBuilder)) return NS_OK; - if (aBuilder->IsForEventDelivery() && - GetStyleVisibility()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE) + // If mozpasspointerevents is set, then we should allow subdocument content + // to handle events even if we're pointer-events:none. + if (aBuilder->IsForEventDelivery() && !PassPointerEventsToChildren()) return NS_OK; nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists); diff --git a/layout/generic/nsSubDocumentFrame.h b/layout/generic/nsSubDocumentFrame.h index b3f724675867..2e451c315f91 100644 --- a/layout/generic/nsSubDocumentFrame.h +++ b/layout/generic/nsSubDocumentFrame.h @@ -136,6 +136,12 @@ protected: */ nsIFrame* ObtainIntrinsicSizeFrame(); + /** + * Return true if pointer event hit-testing should be allowed to target + * content in the subdocument. + */ + bool PassPointerEventsToChildren(); + nsRefPtr mFrameLoader; nsIView* mInnerView; bool mIsInline; diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 55816697ff50..5f423ead6697 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1375,7 +1375,7 @@ struct nsStyleVisibility { } uint8_t mDirection; // [inherited] see nsStyleConsts.h NS_STYLE_DIRECTION_* - uint8_t mVisible; // [inherited] + uint8_t mVisible; // [inherited] uint8_t mPointerEvents; // [inherited] see nsStyleConsts.h bool IsVisible() const { @@ -1386,6 +1386,8 @@ struct nsStyleVisibility { return ((mVisible == NS_STYLE_VISIBILITY_VISIBLE) || (mVisible == NS_STYLE_VISIBILITY_COLLAPSE)); } + + inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const; }; struct nsTimingFunction { diff --git a/layout/style/nsStyleStructInlines.h b/layout/style/nsStyleStructInlines.h index c968b79c362d..582692fc4ebf 100644 --- a/layout/style/nsStyleStructInlines.h +++ b/layout/style/nsStyleStructInlines.h @@ -142,4 +142,20 @@ nsStyleDisplay::IsAbsolutelyPositioned(const nsIFrame* aFrame) const return IsAbsolutelyPositionedStyle() && !aFrame->IsSVGText(); } +uint8_t +nsStyleVisibility::GetEffectivePointerEvents(nsIFrame* aFrame) const +{ + if (aFrame->GetContent() && !aFrame->GetContent()->GetParent()) { + // The root element has a cluster of frames associated with it + // (root scroll frame, canvas frame, the actual primary frame). Make + // those take their pointer-events value from the root element's primary + // frame. + nsIFrame* f = aFrame->GetContent()->GetPrimaryFrame(); + if (f) { + return f->GetStyleVisibility()->mPointerEvents; + } + } + return mPointerEvents; +} + #endif /* !defined(nsStyleStructInlines_h_) */