Bug 703150 Cannot drag scrollbar thumb if stopPropagation() of mousedown event is called r+sr=smaug

This commit is contained in:
Masayuki Nakano 2011-11-25 10:09:58 +09:00
parent 8499f13041
commit b05d40e755
17 changed files with 275 additions and 20 deletions

View File

@ -46,8 +46,8 @@ class nsDOMAttributeMap;
class nsIContent;
#define NS_IATTRIBUTE_IID \
{ 0xf809b623, 0x5b1e, 0x4121, \
{ 0xb8, 0x9d, 0x19, 0x24, 0x7b, 0x70, 0x77, 0x08 } }
{ 0x536167ae, 0x8a9c, 0x4712, \
{ 0x8b, 0x61, 0x3, 0x43, 0xf6, 0xbc, 0x64, 0x75 } }
class nsIAttribute : public nsINode
{

View File

@ -75,8 +75,8 @@ enum nsLinkState {
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0xb651e0a7, 0x1471, 0x49cc, \
{ 0xb4, 0xe1, 0xc2, 0xca, 0x01, 0xfe, 0xb7, 0x80 } }
{ 0x3128b3a0, 0xb609, 0x44e3, \
{ 0xad, 0x91, 0xdc, 0xf1, 0x4a, 0x3f, 0xf6, 0xa0 } }
/**
* A node of content in a document's content model. This interface

View File

@ -41,7 +41,7 @@ interface nsIDOMEventListener;
interface nsIDOMBlob;
interface nsIDOMFileError;
[scriptable, builtinclass, uuid(fc316500-87c4-411e-ab75-dd62468f4174)]
[scriptable, builtinclass, uuid(d158de26-904e-4731-b42c-8b3a4d172703)]
interface nsIDOMFileReader : nsIDOMEventTarget
{
[implicit_jscontext]

View File

@ -124,8 +124,8 @@ class Element;
} // namespace mozilla
#define NS_IDOCUMENT_IID \
{ 0x184e0a3c, 0x1899, 0x417d, \
{ 0xbf, 0xf4, 0x5a, 0x15, 0xe6, 0xe8, 0xaa, 0x94 } }
{ 0x3b78f6, 0x6dc5, 0x44c6, \
{ 0xbc, 0x28, 0x60, 0x2a, 0xb2, 0x4f, 0xfb, 0x7b } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)

View File

@ -288,8 +288,8 @@ private:
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0x20d16be2, 0x3c58, 0x4099, \
{ 0xbf, 0xa6, 0xd0, 0xe7, 0x6b, 0xb1, 0x3d, 0xc5 } }
{ 0xd026d280, 0x5b25, 0x41c0, \
{ 0x92, 0xcf, 0x6, 0xf6, 0xf, 0xb, 0x9a, 0xfe } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
@ -728,6 +728,7 @@ public:
*/
NS_DECL_NSIDOMEVENTTARGET
using nsIDOMEventTarget::AddEventListener;
using nsIDOMEventTarget::AddSystemEventListener;
/**
* Adds a mutation observer to be notified when this node, or any of its

View File

@ -53,7 +53,7 @@ interface nsIDOMBlob;
#include "jsapi.h"
%}
[scriptable, builtinclass, uuid(dea238a1-240f-45f4-9f07-7769bc69eb76)]
[scriptable, builtinclass, uuid(e2b59e48-3655-4429-a94c-b4332c346ba2)]
interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget {
// event handler attributes
attribute nsIDOMEventListener onabort;
@ -64,7 +64,7 @@ interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget {
attribute nsIDOMEventListener onloadend;
};
[scriptable, builtinclass, uuid(09ff3682-7759-4441-a765-f70e1a1fabcf)]
[scriptable, builtinclass, uuid(db9357fc-edf7-42b2-aab2-c24ab19ece20)]
interface nsIXMLHttpRequestUpload : nsIXMLHttpRequestEventTarget {
// for future use
};

View File

@ -1096,6 +1096,28 @@ nsINode::AddEventListener(const nsAString& aType,
return NS_OK;
}
NS_IMETHODIMP
nsINode::AddSystemEventListener(const nsAString& aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted,
PRUint8 aOptionalArgc)
{
NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
"Won't check if this is chrome, you want to set "
"aWantsUntrusted to false or make the aWantsUntrusted "
"explicit by making aOptionalArgc non-zero.");
if (!aWantsUntrusted &&
(aOptionalArgc < 2 &&
!nsContentUtils::IsChromeDoc(OwnerDoc()))) {
aWantsUntrusted = true;
}
return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
aWantsUntrusted);
}
NS_IMETHODIMP
nsINode::RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
@ -1108,6 +1130,8 @@ nsINode::RemoveEventListener(const nsAString& aType,
return NS_OK;
}
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
nsresult
nsINode::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{

View File

@ -103,6 +103,8 @@ nsDOMEventTargetHelper::RemoveEventListener(const nsAString& aType,
return NS_OK;
}
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsDOMEventTargetHelper)
NS_IMETHODIMP
nsDOMEventTargetHelper::AddEventListener(const nsAString& aType,
nsIDOMEventListener *aListener,
@ -130,6 +132,31 @@ nsDOMEventTargetHelper::AddEventListener(const nsAString& aType,
return NS_OK;
}
NS_IMETHODIMP
nsDOMEventTargetHelper::AddSystemEventListener(const nsAString& aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted,
PRUint8 aOptionalArgc)
{
NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
"Won't check if this is chrome, you want to set "
"aWantsUntrusted to false or make the aWantsUntrusted "
"explicit by making aOptionalArgc non-zero.");
if (aOptionalArgc < 2) {
nsresult rv;
nsIScriptContext* context = GetContextForEventHandlers(&rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc =
nsContentUtils::GetDocumentFromScriptContext(context);
aWantsUntrusted = doc && !nsContentUtils::IsChromeDoc(doc);
}
return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
aWantsUntrusted);
}
NS_IMETHODIMP
nsDOMEventTargetHelper::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
{

View File

@ -318,4 +318,26 @@ protected:
static PRUint32 sCreatedCount;
};
/**
* NS_AddSystemEventListener() is a helper function for implementing
* nsIDOMEventTarget::AddSystemEventListener().
*/
inline nsresult
NS_AddSystemEventListener(nsIDOMEventTarget* aTarget,
const nsAString& aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted)
{
nsEventListenerManager* listenerManager = aTarget->GetListenerManager(true);
NS_ENSURE_STATE(listenerManager);
PRUint32 flags = NS_EVENT_FLAG_SYSTEM_EVENT;
flags |= aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
if (aWantsUntrusted) {
flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
}
listenerManager->AddEventListenerByType(aListener, aType, flags);
return NS_OK;
}
#endif // nsEventListenerManager_h__

View File

@ -7376,6 +7376,8 @@ nsGlobalWindow::RemoveEventListener(const nsAString& aType,
return NS_OK;
}
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
NS_IMETHODIMP
nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
{
@ -7429,6 +7431,32 @@ nsGlobalWindow::AddEventListener(const nsAString& aType,
return NS_OK;
}
NS_IMETHODIMP
nsGlobalWindow::AddSystemEventListener(const nsAString& aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted,
PRUint8 aOptionalArgc)
{
NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
"Won't check if this is chrome, you want to set "
"aWantsUntrusted to false or make the aWantsUntrusted "
"explicit by making optional_argc non-zero.");
if (IsOuterWindow() && mInnerWindow &&
!nsContentUtils::CanCallerAccess(mInnerWindow)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
if (!aWantsUntrusted &&
(aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
aWantsUntrusted = true;
}
return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
aWantsUntrusted);
}
nsEventListenerManager*
nsGlobalWindow::GetListenerManager(bool aCreateIfNotFound)
{

View File

@ -50,8 +50,8 @@ struct JSContext;
// 426C1B56-E38A-435E-B291-BE1557F2A0A2
#define NS_IWINDOWROOT_IID \
{ 0x426c1b56, 0xe38a, 0x435e, \
{ 0xb2, 0x91, 0xbe, 0x15, 0x57, 0xf2, 0xa0, 0xa2 } }
{ 0xc89780f2, 0x8905, 0x417f, \
{ 0xa6, 0x62, 0xf6, 0xc, 0xa6, 0xd7, 0xc, 0x91 } }
class nsPIWindowRoot : public nsIDOMEventTarget
{

View File

@ -111,6 +111,8 @@ nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* a
return NS_OK;
}
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsWindowRoot)
NS_IMETHODIMP
nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, bool *aRetVal)
{
@ -149,6 +151,22 @@ nsWindowRoot::AddEventListener(const nsAString& aType,
return NS_OK;
}
NS_IMETHODIMP
nsWindowRoot::AddSystemEventListener(const nsAString& aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted,
PRUint8 aOptionalArgc)
{
NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
"Won't check if this is chrome, you want to set "
"aWantsUntrusted to false or make the aWantsUntrusted "
"explicit by making optional_argc non-zero.");
return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
aWantsUntrusted);
}
nsEventListenerManager*
nsWindowRoot::GetListenerManager(bool aCreateIfNotFound)
{

View File

@ -38,7 +38,7 @@
interface nsIDOMEventListener;
[scriptable, function, uuid(98b6237b-9654-43de-97e0-acf4b091b4e7)]
[scriptable, function, uuid(41e88f87-42cb-4db1-8724-f5456a16c410)]
interface nsIDOMMozBatteryManager : nsIDOMEventTarget
{
readonly attribute double level;

View File

@ -69,7 +69,7 @@ interface nsIScriptContext;
interface nsIDOMEventListener;
interface nsIDOMEvent;
[scriptable, builtinclass, uuid(1797d5a4-b12a-428d-9eef-a0e13839728c)]
[scriptable, builtinclass, uuid(8e375931-298d-4d0a-9cb4-5668f0cdc5a8)]
interface nsIDOMEventTarget : nsISupports
{
/**
@ -106,6 +106,28 @@ interface nsIDOMEventTarget : nsISupports
[optional] in boolean useCapture,
[optional] in boolean wantsUntrusted);
/**
* addSystemEventListener() adds an event listener of aType to the system
* group. Typically, core code should use system group for listening to
* content (i.e., non-chrome) element's events. If core code uses
* nsIDOMEventTarget::AddEventListener for a content node, it means
* that the listener cannot listen the event when web content calls
* stopPropagation() of the event.
*
* @param aType An event name you're going to handle.
* @param aListener An event listener.
* @param aUseCapture TRUE if you want to listen the event in capturing
* phase. Otherwise, FALSE.
* @param aWantsUntrusted TRUE if you want to handle untrusted events.
* Otherwise, FALSE.
* @return NS_OK if succeed. Otherwise, NS_ERROR_*.
*/
[noscript, optional_argc] void addSystemEventListener(
in DOMString type,
in nsIDOMEventListener listener,
[optional] in boolean aUseCapture,
[optional] in boolean aWantsUntrusted);
%{C++
// non-virtual so it won't affect the vtable
nsresult AddEventListener(const nsAString& aType,
@ -122,6 +144,22 @@ interface nsIDOMEventTarget : nsISupports
{
return AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, 2);
}
// non-virtual so it won't affect the vtable
nsresult AddSystemEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
bool aUseCapture)
{
return AddSystemEventListener(aType, aListener, aUseCapture, PR_FALSE, 1);
}
// non-virtual so it won't affect the vtable
nsresult AddSystemEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
bool aUseCapture,
bool aWantsUntrusted)
{
return AddSystemEventListener(aType, aListener, aUseCapture,
aWantsUntrusted, 2);
}
%}
/**
@ -148,6 +186,15 @@ interface nsIDOMEventTarget : nsISupports
in nsIDOMEventListener listener,
[optional] in boolean useCapture);
/**
* removeSystemEventListener() should be used if you have used
* addSystemEventListener().
*/
[noscript] void removeSystemEventListener(
in DOMString type,
in nsIDOMEventListener listener,
[optional] in boolean aUseCapture);
/**
* This method allows the dispatch of events into the implementations
* event model. Events dispatched in this manner will have the same
@ -278,4 +325,20 @@ nsPIDOMEventTarget* _class::GetTargetForEventTargetChain() { return this; } \
nsresult _class::WillHandleEvent(nsEventChainPostVisitor& aVisitor) { return NS_OK; } \
JSContext* _class::GetJSContextForEventHandlers() { return nsnull; }
#define NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(aClass) \
NS_IMETHODIMP \
aClass::RemoveSystemEventListener(const nsAString& aType, \
nsIDOMEventListener *aListener, \
bool aUseCapture) \
{ \
nsEventListenerManager* listenerManager = GetListenerManager(false); \
if (!listenerManager) { \
return NS_OK; \
} \
PRUint32 flags = NS_EVENT_FLAG_SYSTEM_EVENT; \
flags |= aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; \
listenerManager->RemoveEventListenerByType(aListener, aType, flags); \
return NS_OK; \
}
%}

View File

@ -54,6 +54,7 @@
#include "nsHTMLParts.h"
#include "nsIPresShell.h"
#include "nsCSSRendering.h"
#include "nsEventListenerManager.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDocument.h"
@ -974,11 +975,12 @@ nsSliderFrame::AddListener()
}
nsIFrame* thumbFrame = mFrames.FirstChild();
if (thumbFrame) {
thumbFrame->GetContent()->
AddEventListener(NS_LITERAL_STRING("mousedown"), mMediator, false,
false);
if (!thumbFrame) {
return;
}
thumbFrame->GetContent()->
AddSystemEventListener(NS_LITERAL_STRING("mousedown"), mMediator,
false, false);
}
void
@ -991,7 +993,7 @@ nsSliderFrame::RemoveListener()
return;
thumbFrame->GetContent()->
RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMediator, false);
RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), mMediator, false);
}
NS_IMETHODIMP

View File

@ -55,6 +55,7 @@ _CHROME_FILES = \
test_bug372685.xul \
test_bug398982-1.xul \
test_bug398982-2.xul \
test_bug703150.xul \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,69 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
title="Test for Bug 703150">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=703150
-->
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<scrollbar id="scrollbar" curpos="0" maxpos="500"/>
<script class="testbody" type="application/javascript">
<![CDATA[
var scrollbar = document.getElementById("scrollbar");
var scrollbarThumb =
document.getAnonymousElementByAttribute(scrollbar, "sbattr",
"scrollbar-thumb");
function doTest()
{
function mousedownHandler(aEvent)
{
aEvent.stopPropagation();
}
window.addEventListener("mousedown", mousedownHandler, true);
// Wait for finishing reflow...
SimpleTest.executeSoon(function () {
synthesizeMouseAtCenter(scrollbarThumb, { type: "mousedown" });
is(scrollbar.getAttribute("curpos"), 0,
"scrollbar thumb has been moved already");
synthesizeMouseAtCenter(scrollbar, { type: "mousemove" });
ok(scrollbar.getAttribute("curpos") > 0,
"scrollbar thumb hasn't been dragged");
synthesizeMouseAtCenter(scrollbarThumb, { type: "mouseup" });
window.removeEventListener("mousedown", mousedownHandler, true);
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
]]>
</script>
<body id="html_body" xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=703150">Mozilla Bug 703150</a>
<p id="display"></p>
<pre id="test">
</pre>
<script>
addLoadEvent(doTest);
</script>
</body>
</window>