Bug 796452. Add mozpasspointerevents attribute for IFRAMEs in chrome windows. r=mats

This commit is contained in:
Robert O'Callahan 2012-11-02 23:42:59 +13:00
parent 1c668a4d54
commit 9a45cc9183
9 changed files with 97 additions and 4 deletions

View File

@ -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")

View File

@ -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);
}
}

View File

@ -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

View File

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test that mozpasspointerevents works</title>
</head>
<body onload="startTest()">
<iframe id="f" style="border:none; width:200px; height:200px; pointer-events:none" mozpasspointerevents
src="data:text/html,<html style='pointer-events:none'><div style='margin:100px; width:100px; height:100px; background:yellow; pointer-events:auto'>">
</iframe>
<script type="application/javascript">
var SimpleTest = window.opener.SimpleTest;
var is = window.opener.is;
function startTest() {
var f = document.getElementById("f");
var fRect = f.getBoundingClientRect();
var e1 = document.elementFromPoint(fRect.left + 10, fRect.top + 10);
is(e1, document.body, "check point in transparent region of the iframe");
var e2 = document.elementFromPoint(fRect.left + 110, fRect.top + 110);
is(e2, f, "check point in opaque region of the iframe");
window.close();
SimpleTest.finish();
}
</script>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test that mozpasspointerevents works</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
var root = getRootDirectory(window.location.href);
window.openDialog(root + "passpointerevents_window.html", "passpointerevents",
"chrome,width=400,height=400");
</script>
</pre>
</body>
</html>

View File

@ -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);

View File

@ -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<nsFrameLoader> mFrameLoader;
nsIView* mInnerView;
bool mIsInline;

View File

@ -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 {

View File

@ -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_) */