Bug 516615, when capturing, check if the target frame's content is a descendant of the capturing content, rather than using the frame tree, r=roc,sr=smaug

This commit is contained in:
Neil Deakin 2009-09-28 10:17:01 -04:00
Родитель 03f6ef64f9
Коммит 9dcaa2e4e5
3 изменённых файлов: 73 добавлений и 41 удалений

Просмотреть файл

@ -6000,6 +6000,9 @@ PresShell::HandleEvent(nsIView *aView,
}
#endif
nsIContent* capturingContent =
NS_IS_MOUSE_EVENT(aEvent) ? GetCapturingContent() : nsnull;
nsCOMPtr<nsIDocument> retargetEventDoc;
// key and IME events must be targeted at the presshell for the focused frame
if (!sDontRetargetEvents) {
@ -6020,10 +6023,10 @@ PresShell::HandleEvent(nsIView *aView,
retargetEventDoc = do_QueryInterface(piWindow->GetExtantDocument());
if (!retargetEventDoc)
return NS_OK;
} else if (NS_IS_MOUSE_EVENT(aEvent) && GetCapturingContent()) {
} else if (capturingContent) {
// if the mouse is being captured then retarget the mouse event at the
// document that is being captured.
retargetEventDoc = gCaptureInfo.mContent->GetCurrentDoc();
retargetEventDoc = capturingContent->GetCurrentDoc();
}
if (retargetEventDoc) {
@ -6093,43 +6096,7 @@ PresShell::HandleEvent(nsIView *aView,
return NS_OK;
}
PRBool getDescendantPoint = PR_TRUE;
nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
if (NS_IS_MOUSE_EVENT(aEvent) && GetCapturingContent()) {
// if a node is capturing the mouse, get the frame for the capturing
// content and use that instead. However, if the content has no parent,
// such as the root frame, get the parent canvas frame instead. This
// ensures that positioned frames are included when hit-testing. Note
// that a check was already done above to ensure that capturingContent
// is in this presshell.
nsIContent* capturingContent = gCaptureInfo.mContent;
frame = GetPrimaryFrameFor(capturingContent);
if (frame) {
getDescendantPoint = !gCaptureInfo.mRetargetToElement;
if (!capturingContent->GetParent()) {
frame = frame->GetParent();
}
else {
// special case for <select> as it needs to capture on the dropdown list.
if (capturingContent->Tag() == nsGkAtoms::select &&
capturingContent->IsNodeOfType(nsINode::eHTML)) {
nsIFrame* childframe = frame->GetChildList(nsGkAtoms::selectPopupList).FirstChild();
if (childframe) {
frame = childframe;
}
}
// if the frame is a scrolling frame, get the inner scrolled frame instead.
nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
if (scrollFrame) {
frame = scrollFrame->GetScrolledFrame();
}
}
aView = frame->GetClosestView();
}
}
PRBool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
// if this event has no frame, we need to retarget it at a parent
@ -6182,8 +6149,28 @@ PresShell::HandleEvent(nsIView *aView,
#endif
}
PRBool captureRetarget = PR_FALSE;
if (capturingContent) {
captureRetarget = gCaptureInfo.mRetargetToElement;
// special case for <select> as it needs to capture on the dropdown list,
// so get the frame for the dropdown list instead.
if (!captureRetarget && capturingContent->Tag() == nsGkAtoms::select &&
capturingContent->IsNodeOfType(nsINode::eHTML)) {
nsIFrame* selectFrame = GetPrimaryFrameFor(capturingContent);
if (selectFrame) {
nsIFrame* childframe = selectFrame->GetChildList(nsGkAtoms::selectPopupList).FirstChild();
if (childframe) {
frame = childframe;
}
}
}
}
// Get the frame at the event point. However, don't do this if we're
// capturing and retargeting the event because the captured frame will
// be used instead below.
nsIFrame* targetFrame = nsnull;
if (getDescendantPoint) {
if (!captureRetarget) {
nsPoint eventPoint
= nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
{
@ -6197,6 +6184,24 @@ PresShell::HandleEvent(nsIView *aView,
}
}
// if a node is capturing the mouse, check if the event needs to be
// retargeted at the capturing content instead. This will be the case when
// capture retargeting is being used, no frame was found or the frame's
// content is not a descendant of the capturing content.
if (capturingContent &&
(gCaptureInfo.mRetargetToElement ||
!targetFrame || !targetFrame->GetContent() ||
!nsContentUtils::ContentIsCrossDocDescendantOf(targetFrame->GetContent(),
capturingContent))) {
// A check was already done above to ensure that capturingContent is
// in this presshell, so GetPrimaryFrameFor can just be called directly.
nsIFrame* capturingFrame = GetPrimaryFrameFor(capturingContent);
if (capturingFrame) {
targetFrame = capturingFrame;
aView = targetFrame->GetClosestView();
}
}
if (targetFrame) {
PresShell* shell =
static_cast<PresShell*>(targetFrame->PresContext()->PresShell());

Просмотреть файл

@ -1458,6 +1458,13 @@ void
nsHTMLFramesetFrame::MouseDrag(nsPresContext* aPresContext,
nsGUIEvent* aEvent)
{
// if the capture ended, reset the drag state
if (nsIPresShell::GetCapturingContent() != GetContent()) {
mDragger = nsnull;
gDragInProgress = PR_FALSE;
return;
}
PRInt32 change; // measured positive from left-to-right or top-to-bottom
nsWeakFrame weakFrame(this);
if (mDragger->mVertical) {

Просмотреть файл

@ -124,9 +124,27 @@ function runTests()
runCaptureTest(custom5);
captureRetargetMode = false;
var custom6 = document.getElementById("custom6");
synthesizeMouse(custom6, 2, 2, { type: "mousedown" });
synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
$("leftbox"), "mousemove", "setCapture only works on elements in documents");
synthesizeMouse(custom6, 2, 2, { type: "mouseup" });
var b = frames[0].document.getElementById("b");
runCaptureTest(b, selectionCallback);
frames[0].getSelection().collapseToStart();
var body = frames[0].document.body;
var fixed = frames[0].document.getElementById("fixed");
function captureOnBody() { body.setCapture() }
body.addEventListener("mousedown", captureOnBody, true);
synthesizeMouse(body, 8, 8, { type: "mousedown" }, frames[0]);
body.removeEventListener("mousedown", captureOnBody, true);
synthesizeMouseExpectEvent(fixed, 2, 2, { type: "mousemove" },
fixed, "mousemove", "setCapture on body retargets to root node", frames[0]);
synthesizeMouse(body, 8, 8, { type: "mouseup" }, frames[0]);
previousWidth = frames[1].frames[0].document.documentElement.clientWidth;
originalWidth = previousWidth;
runCaptureTest(frames[1].document.documentElement.lastChild, framesetCallback);
@ -220,16 +238,18 @@ SimpleTest.waitForFocus(runTests);
<spacer id="custom5spacer" width="5"/>
<hbox id="custom5inner" width="35" height="35"/>
</hbox>
<vbox id="custom6" width="10" height="10"
onmousedown="document.createElement('hbox').setCapture();"/>
<hbox>
<iframe width="100" height="100"
src="data:text/html,%3Cbody style%3D'font-size%3A 40pt%3B'%3E.%3Cb id%3D'b'%3EThis%3C/b%3E is some text%3C/body%3E"/>
src="data:text/html,%3Cbody style%3D'font-size%3A 40pt%3B'%3E.%3Cb id%3D'b'%3EThis%3C/b%3E is some text%3Cdiv id='fixed' style='position: fixed; left: 55px; top: 5px; width: 10px; height: 10px'%3E.%3C/div%3E%3C/body%3E"/>
<iframe width="100" height="100"
src="data:text/html,%3Cframeset cols='50%, 50%'%3E%3Cframe src='about:blank'%3E%3Cframe src='about:blank'%3E%3C/frameset%3E"/>
</hbox>
<body xmlns="http://www.w3.org/1999/xhtml">
<body id="body" xmlns="http://www.w3.org/1999/xhtml">
<p id="display"/><div id="content" style="display: none"/><pre id="test"/>
</body>