Bug 350471 - Reenable pixel scrolling (two-finger touchpad), r=smaug r=smichaud sr=roc

This commit is contained in:
Markus Stange 2008-09-17 13:27:19 +02:00
Родитель e4827f616e
Коммит 32449e2eac
17 изменённых файлов: 687 добавлений и 182 удалений

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

@ -410,6 +410,7 @@ nsContentUtils::InitializeEventTable() {
{ &nsGkAtoms::onDOMFocusIn, { NS_UI_FOCUSIN, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onDOMFocusOut, { NS_UI_FOCUSOUT, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onDOMMouseScroll, { NS_MOUSE_SCROLL, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onMozMousePixelScroll, { NS_MOUSE_PIXEL_SCROLL, EventNameType_HTMLXUL }},
{ &nsGkAtoms::oninput, { NS_FORM_INPUT, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onpageshow, { NS_PAGE_SHOW, EventNameType_HTML }},
{ &nsGkAtoms::onpagehide, { NS_PAGE_HIDE, EventNameType_HTML }},

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

@ -641,6 +641,7 @@ GK_ATOM(onmousemove, "onmousemove")
GK_ATOM(onmouseout, "onmouseout")
GK_ATOM(onmouseover, "onmouseover")
GK_ATOM(onmouseup, "onmouseup")
GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll")
GK_ATOM(ononline, "ononline")
GK_ATOM(onoffline, "onoffline")
GK_ATOM(onoverflow, "onoverflow")

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

@ -70,8 +70,8 @@ static const char* const sEventNames[] = {
"DOMNodeRemovedFromDocument", "DOMNodeInsertedIntoDocument",
"DOMAttrModified", "DOMCharacterDataModified",
"DOMActivate", "DOMFocusIn", "DOMFocusOut",
"pageshow", "pagehide", "DOMMouseScroll", "offline", "online",
"copy", "cut", "paste"
"pageshow", "pagehide", "DOMMouseScroll", "MozMousePixelScroll",
"offline", "online", "copy", "cut", "paste"
#ifdef MOZ_SVG
,
"SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll",
@ -479,6 +479,8 @@ nsDOMEvent::SetEventType(const nsAString& aEventTypeArg)
} else if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
if (atom == nsGkAtoms::onDOMMouseScroll)
mEvent->message = NS_MOUSE_SCROLL;
else if (atom == nsGkAtoms::onMozMousePixelScroll)
mEvent->message = NS_MOUSE_PIXEL_SCROLL;
} else if (mEvent->eventStructType == NS_DRAG_EVENT) {
if (atom == nsGkAtoms::ondragstart)
mEvent->message = NS_DRAGDROP_START;
@ -1393,6 +1395,8 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return sEventNames[eDOMEvents_pagehide];
case NS_MOUSE_SCROLL:
return sEventNames[eDOMEvents_DOMMouseScroll];
case NS_MOUSE_PIXEL_SCROLL:
return sEventNames[eDOMEvents_MozMousePixelScroll];
case NS_OFFLINE:
return sEventNames[eDOMEvents_offline];
case NS_ONLINE:

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

@ -124,6 +124,7 @@ public:
eDOMEvents_pageshow,
eDOMEvents_pagehide,
eDOMEvents_DOMMouseScroll,
eDOMEvents_MozMousePixelScroll,
eDOMEvents_offline,
eDOMEvents_online,
eDOMEvents_copy,

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

@ -113,7 +113,7 @@
#include "nsIScrollableViewProvider.h"
#include "nsIDOMDocumentRange.h"
#include "nsIDOMDocumentEvent.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDOMMouseScrollEvent.h"
#include "nsIDOMDragEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMDocumentView.h"
@ -141,6 +141,7 @@
#include "nsServiceManagerUtils.h"
#include "nsITimer.h"
#include "nsIFontMetrics.h"
#include "nsIDragService.h"
#include "nsIDragSession.h"
@ -460,7 +461,9 @@ nsEventStateManager::nsEventStateManager()
mNormalLMouseEventInProcess(PR_FALSE),
m_haveShutdown(PR_FALSE),
mBrowseWithCaret(PR_FALSE),
mTabbedThroughDocument(PR_FALSE)
mTabbedThroughDocument(PR_FALSE),
mLastLineScrollConsumedX(PR_FALSE),
mLastLineScrollConsumedY(PR_FALSE)
{
if (sESMInstanceCount == 0) {
gUserInteractionTimerCallback = new nsUITimerCallback();
@ -1407,6 +1410,20 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
}
}
break;
case NS_MOUSE_PIXEL_SCROLL:
{
if (mCurrentFocus) {
mCurrentTargetContent = mCurrentFocus;
}
// When the last line scroll has been canceled, eat the pixel scroll event
nsMouseScrollEvent *msEvent = static_cast<nsMouseScrollEvent*>(aEvent);
if ((msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) ?
mLastLineScrollConsumedX : mLastLineScrollConsumedY) {
*aStatus = nsEventStatus_eConsumeNoDefault;
}
}
break;
case NS_QUERY_SELECTED_TEXT:
{
nsQueryContentEventHandler handler(mPresContext);
@ -2414,6 +2431,66 @@ GetParentFrameToScroll(nsPresContext* aPresContext, nsIFrame* aFrame)
return aFrame->GetParent();
}
static nsIScrollableView*
GetScrollableViewForFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
{
for (; aFrame; aFrame = GetParentFrameToScroll(aPresContext, aFrame)) {
nsIScrollableViewProvider* svp;
CallQueryInterface(aFrame, &svp);
if (svp) {
nsIScrollableView* scrollView = svp->GetScrollableView();
if (scrollView)
return scrollView;
}
}
return nsnull;
}
void
nsEventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
nsMouseScrollEvent* aEvent,
nsPresContext* aPresContext,
nsEventStatus* aStatus)
{
nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
if (!targetContent)
GetFocusedContent(getter_AddRefs(targetContent));
if (!targetContent)
return;
while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
targetContent = targetContent->GetParent();
}
nsIScrollableView* scrollView = GetScrollableViewForFrame(aPresContext, aTargetFrame);
nscoord lineHeight = 0;
if (scrollView) {
scrollView->GetLineHeight(&lineHeight);
} else {
// Fall back to the font height of the target frame.
const nsStyleFont* font = aTargetFrame->GetStyleFont();
const nsFont& f = font->mFont;
nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(f);
NS_ASSERTION(fm, "FontMetrics is null!");
if (fm)
fm->GetHeight(lineHeight);
}
PRBool isTrusted = (aEvent->flags & NS_EVENT_FLAG_TRUSTED) != 0;
nsMouseScrollEvent event(isTrusted, NS_MOUSE_PIXEL_SCROLL, nsnull);
event.refPoint = aEvent->refPoint;
event.widget = aEvent->widget;
event.time = aEvent->time;
event.isShift = aEvent->isShift;
event.isControl = aEvent->isControl;
event.isAlt = aEvent->isAlt;
event.isMeta = aEvent->isMeta;
event.scrollFlags = aEvent->scrollFlags;
event.delta = aPresContext->AppUnitsToIntCSSPixels(aEvent->delta * lineHeight);
nsEventDispatcher::Dispatch(targetContent, aPresContext, &event, nsnull, aStatus);
}
nsresult
nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
nsIFrame* aTargetFrame,
@ -2732,79 +2809,106 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
}
break;
case NS_MOUSE_SCROLL:
if (nsEventStatus_eConsumeNoDefault != *aStatus) {
case NS_MOUSE_PIXEL_SCROLL:
{
nsMouseScrollEvent *msEvent = static_cast<nsMouseScrollEvent*>(aEvent);
// Build the preference keys, based on the event properties.
nsMouseScrollEvent *msEvent = (nsMouseScrollEvent*) aEvent;
NS_NAMED_LITERAL_CSTRING(actionslot, ".action");
NS_NAMED_LITERAL_CSTRING(sysnumlinesslot, ".sysnumlines");
nsCAutoString baseKey;
GetBasePrefKeyForMouseWheel(msEvent, baseKey);
// Extract the preferences
nsCAutoString actionKey(baseKey);
actionKey.Append(actionslot);
nsCAutoString sysNumLinesKey(baseKey);
sysNumLinesKey.Append(sysnumlinesslot);
PRInt32 action = nsContentUtils::GetIntPref(actionKey.get());
PRBool useSysNumLines =
nsContentUtils::GetBoolPref(sysNumLinesKey.get());
if (useSysNumLines) {
if (msEvent->scrollFlags & nsMouseScrollEvent::kIsFullPage)
action = MOUSE_SCROLL_PAGE;
else if (msEvent->scrollFlags & nsMouseScrollEvent::kIsPixels)
action = MOUSE_SCROLL_PIXELS;
if (aEvent->message == NS_MOUSE_SCROLL) {
// Mark the subsequent pixel scrolls as valid / invalid, based on the
// observation if the previous line scroll has been canceled
if (msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) {
mLastLineScrollConsumedX = (nsEventStatus_eConsumeNoDefault == *aStatus);
} else if (msEvent->scrollFlags & nsMouseScrollEvent::kIsVertical) {
mLastLineScrollConsumedY = (nsEventStatus_eConsumeNoDefault == *aStatus);
}
if (!(msEvent->scrollFlags & nsMouseScrollEvent::kHasPixels)) {
// No generated pixel scroll event will follow.
// Create and send a pixel scroll DOM event now.
SendPixelScrollEvent(aTargetFrame, msEvent, presContext, aStatus);
}
}
switch (action) {
case MOUSE_SCROLL_N_LINES:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByLine);
}
break;
if (*aStatus != nsEventStatus_eConsumeNoDefault) {
// Build the preference keys, based on the event properties.
NS_NAMED_LITERAL_CSTRING(actionslot, ".action");
NS_NAMED_LITERAL_CSTRING(sysnumlinesslot, ".sysnumlines");
case MOUSE_SCROLL_PAGE:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByPage);
}
break;
nsCAutoString baseKey;
GetBasePrefKeyForMouseWheel(msEvent, baseKey);
case MOUSE_SCROLL_PIXELS:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByPixel);
}
break;
// Extract the preferences
nsCAutoString actionKey(baseKey);
actionKey.Append(actionslot);
case MOUSE_SCROLL_HISTORY:
{
DoScrollHistory(msEvent->delta);
}
break;
nsCAutoString sysNumLinesKey(baseKey);
sysNumLinesKey.Append(sysnumlinesslot);
case MOUSE_SCROLL_ZOOM:
{
DoScrollZoom(aTargetFrame, msEvent->delta);
}
break;
PRInt32 action = nsContentUtils::GetIntPref(actionKey.get());
PRBool useSysNumLines =
nsContentUtils::GetBoolPref(sysNumLinesKey.get());
default: // Including -1 (do nothing)
break;
if (useSysNumLines) {
if (msEvent->scrollFlags & nsMouseScrollEvent::kIsFullPage)
action = MOUSE_SCROLL_PAGE;
}
if (aEvent->message == NS_MOUSE_PIXEL_SCROLL) {
if (action == MOUSE_SCROLL_N_LINES) {
action = MOUSE_SCROLL_PIXELS;
} else {
// Do not scroll pixels when zooming
action = -1;
}
} else if (msEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) {
if (action == MOUSE_SCROLL_N_LINES) {
// We shouldn't scroll lines when a pixel scroll event will follow.
action = -1;
}
}
switch (action) {
case MOUSE_SCROLL_N_LINES:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByLine);
}
break;
case MOUSE_SCROLL_PAGE:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByPage);
}
break;
case MOUSE_SCROLL_PIXELS:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByPixel);
}
break;
case MOUSE_SCROLL_HISTORY:
{
DoScrollHistory(msEvent->delta);
}
break;
case MOUSE_SCROLL_ZOOM:
{
DoScrollZoom(aTargetFrame, msEvent->delta);
}
break;
default: // Including -1 (do nothing)
break;
}
*aStatus = nsEventStatus_eConsumeNoDefault;
}
*aStatus = nsEventStatus_eConsumeNoDefault;
}
break;
case NS_DRAGDROP_ENTER:

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

@ -295,6 +295,10 @@ protected:
nsIFrame* &targetOuterFrame,
nsPresContext* &presCtxOuter);
void SendPixelScrollEvent(nsIFrame* aTargetFrame,
nsMouseScrollEvent* aEvent,
nsPresContext* aPresContext,
nsEventStatus* aStatus);
typedef enum {
eScrollByPixel,
eScrollByLine,
@ -445,6 +449,10 @@ protected:
nsCOMArray<nsIDocShell> mTabbingFromDocShells;
// Unlocks pixel scrolling
PRPackedBool mLastLineScrollConsumedX;
PRPackedBool mLastLineScrollConsumedY;
#ifdef CLICK_HOLD_CONTEXT_MENUS
enum { kClickHoldDelay = 500 } ; // 500ms == 1/2 second

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

@ -51,6 +51,7 @@ _TEST_FILES = \
test_bug336682_1.html \
test_bug336682_2.xul \
test_bug336682.js \
test_bug350471.xul \
test_bug367781.html \
test_bug368835.html \
test_bug379120.html \

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

@ -0,0 +1,229 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=350471
-->
<window title="Mozilla Bug 350471"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<title>Test for Bug 350471</title>
<script type="application/javascript" src="/MochiKit/packed.js" />
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"/>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=350471">Mozilla Bug 350471</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
</body>
<vbox style="height: 150px; background: cyan; overflow: auto;" id="scrollbox">
<hbox style="height: 8000px;"><vbox style="width: 8000px;"/></hbox>
</vbox>
<script class="testbody" type="application/javascript;version=1.7"><![CDATA[
/** Test for Bug 350471 **/
// This test depends on general.smoothScroll being off.
const minLineHeight = 10, maxLineHeight = 20;
function between(x, min, max) (min <= max) ? (min <= x && x <= max) : (max <= x && x <= min);
function isbetween(x, min, max, msg) ok(between(x, min, max), msg + " - Expected " + min + " to " + max + ", got " + x);
function testEventDispatching() {
function helper(aAxis, aDelta, aKind, aShiftKey, aCtrlKey, aAltKey, aMetaKey) {
let expectedEvents = [];
let deltaUnit = "";
function listener(e) {
if (!expectedEvents.length) {
ok(false, "Received an event that I didn't expect. type: " + e.type +
", axis: " + e.axis + ", delta: " + e.delta);
return;
}
let expected = expectedEvents.shift();
["type", "shiftKey", "ctrlKey", "altKey", "metaKey"].forEach(function(field) {
is(e[field], expected[field],
"e." + field + " (" + e[field] + ") does not match expected value (" + expected[field] + ")");
});
let expectedAxis = expected.axis == "horizontal" ? e.HORIZONTAL_AXIS : e.VERTICAL_AXIS;
is(e.axis, expectedAxis,
"e.axis (" + e.axis + ") does not match expected value (" + expectedAxis + ")");
// When modifier keys are pressed, cancel the event.
// We don't want to zoom or navigate back / forward (history scroll).
if (aShiftKey || aCtrlKey || aAltKey || aMetaKey) {
e.preventDefault();
// Note: If this is a DOMMouseScroll event without hasPixels, we still
// expect a follow-up MozMousePixelScroll event.
} else {
// Only check the delta if no modifiers are pressed.
// History scroll and zoom change the deltas in nsESM::PreHandleEvent.
if (deltaUnit == (e.type == "DOMMouseScroll" ? "lines" : "pixels")) {
// no unit conversion necessary
is(e.detail, expected.delta,
"e.detail (" + e.detail + ") does not match expected value (" + expected.delta + ")");
} else if (e.type == "MozMousePixelScroll") {
// We sent a line scroll event but are receiving a pixel scroll event,
// so we need to convert the delta.
let minDelta = expected.delta * minLineHeight;
let maxDelta = expected.delta * maxLineHeight;
isbetween(e.detail, minDelta, maxDelta, "wrong pixel scroll event delta");
}
}
e.stopPropagation();
}
// Set up the expected values.
if (aKind == 0 || aKind == 1) {
expectedEvents.push({
type: "DOMMouseScroll",
axis: aAxis,
delta: aDelta,
hasPixels: (aKind == 1),
shiftKey: aShiftKey,
ctrlKey: aCtrlKey,
altKey: aAltKey,
metaKey: aMetaKey
});
}
if (aKind == 0 || aKind == 2) {
expectedEvents.push({
type: "MozMousePixelScroll",
axis: aAxis,
delta: aDelta,
shiftKey: aShiftKey,
ctrlKey: aCtrlKey,
altKey: aAltKey,
metaKey: aMetaKey
});
}
deltaUnit = aKind == 2 ? "pixels" : "lines";
document.addEventListener("DOMMouseScroll", listener, true);
document.addEventListener("MozMousePixelScroll", listener, true);
// Send the event to the documentElement.
synthesizeMouseScroll(document.documentElement, 10, 10, expectedEvents[0]);
document.removeEventListener("DOMMouseScroll", listener, true);
document.removeEventListener("MozMousePixelScroll", listener, true);
// expectedEvents should be empty now. If it's not, print errors.
expectedEvents.forEach(function(e) {
ok(false, "Didn't receive expected event: " + JSON.toString(e));
});
};
let i = 0;
[0, 1, 2].forEach(function(aKind) {
["horizontal", "vertical"].forEach(function(aAxis) {
[false, true].forEach(function(aShift) {
[false, true].forEach(function(aCtrl) {
[false, true].forEach(function(aAlt) {
[false, true].forEach(function(aMeta) {
helper(aAxis, [-5, -1, 0, 1, 5][i++ % 5], aKind, aShift, aCtrl, aAlt, aMeta);
});
});
});
});
});
});
}
function testDefaultHandling() {
let scrollbox = document.getElementById("scrollbox");
let currentTest = "";
function scrollWithPreventDefault(aEvent, aDoConsume) {
function listener(e) {
if (aDoConsume[e.type])
e.preventDefault();
}
scrollbox.addEventListener("DOMMouseScroll", listener, true);
scrollbox.addEventListener("MozMousePixelScroll", listener, true);
synthesizeMouseScroll(scrollbox, 10, 10, aEvent);
scrollbox.removeEventListener("DOMMouseScroll", listener, true);
scrollbox.removeEventListener("MozMousePixelScroll", listener, true);
}
function helper(aType, aHasPixels, aAxis, aStart, aDelta, aConsumeLine, aConsumePixel, aPositionShouldChange) {
scrollbox.scrollLeft = aStart;
scrollbox.scrollTop = aStart;
scrollWithPreventDefault({
type: aType,
axis: aAxis,
hasPixels: aHasPixels,
delta: aDelta
}, {
"DOMMouseScroll": aConsumeLine,
"MozMousePixelScroll": aConsumePixel
});
let newPos = scrollbox[aAxis == "horizontal" ? "scrollLeft" : "scrollTop"];
let newPosWrongAxis = scrollbox[aAxis == "horizontal" ? "scrollTop" : "scrollLeft"];
is(newPosWrongAxis, aStart, currentTest + " wrong axis scrolled - type: " + aType);
if (aPositionShouldChange) {
if (aType == "MozMousePixelScroll") {
// aDelta is in pixels, no conversion necessary
is(newPos, aStart + aDelta, currentTest + " wrong scroll position - type: " + aType);
} else {
// Use minLineHeight and maxLineHeight as an estimate for the conversion factor.
isbetween(newPos, aStart + aDelta * minLineHeight, aStart + aDelta * maxLineHeight,
currentTest + " wrong scroll position - type: " + aType);
}
} else {
is(newPos, aStart, currentTest + " The scroll position shouldn't have changed. - type: " + aType);
}
}
["horizontal", "vertical"].forEach(function(aAxis) {
[-5, 5].forEach(function(aDelta) {
[false, true].forEach(function(aConsumeLine) {
[false, true].forEach(function(aConsumePixel) {
let shouldScroll = !aConsumeLine && !aConsumePixel;
currentTest = "normal DOMMouseScroll: only scroll if neither line nor pixel scroll are consumed.";
helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, aConsumePixel, shouldScroll);
currentTest = "DOMMouseScroll with hasPixels: never scroll.";
helper("DOMMouseScroll", true, aAxis, 4000, aDelta, aConsumeLine, aConsumePixel, false);
currentTest = "MozMousePixelScroll (consumed: " + aConsumePixel +
") with preceding DOMMouseScroll (consumed: " + aConsumeLine +
"): " + (shouldScroll ? "scroll." : "don't scroll.");
// It shouldn't matter:
// 1. whether hasPixels is set on the preceding DOMMouseScroll event or
// 2. whether the preceding DOMMouseScroll event's MozMousePixelScroll event is consumed.
helper("DOMMouseScroll", true, aAxis, 4000, aDelta, aConsumeLine, false, false);
helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll);
helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, false, !aConsumeLine);
helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll);
helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, true, false);
helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll);
});
});
});
});
}
function runTests() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
Components.utils.import("resource://gre/modules/JSON.jsm");
testEventDispatching();
testDefaultHandling();
SimpleTest.finish();
}
window.onload = function() { setTimeout(runTests, 0); };
SimpleTest.waitForExplicitFinish();
]]></script>
</window>

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

@ -130,6 +130,7 @@ interface nsIDOMWindowUtils : nsISupports {
/** Synthesize a mouse scroll event for a window. The event types supported
* are:
* DOMMouseScroll
* MozMousePixelScroll
*
* Events are sent in coordinates offset by aX and aY from the window.
*
@ -143,7 +144,7 @@ interface nsIDOMWindowUtils : nsISupports {
* @param aButton button to synthesize
* @param aScrollFlags flag bits --- see nsMouseScrollFlags in nsGUIEvent.h
* @param aDelta the direction and amount to scroll (in lines or pixels,
* depending on whether kIsPixels is set in aScrollFlags)
* depending on the event type)
* @param aModifiers modifiers pressed, using constants defined in nsIDOMNSEvent
*/
void sendMouseScrollEvent(in AString aType,

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

@ -270,6 +270,8 @@ nsDOMWindowUtils::SendMouseScrollEvent(const nsAString& aType,
PRInt32 msg;
if (aType.EqualsLiteral("DOMMouseScroll"))
msg = NS_MOUSE_SCROLL;
else if (aType.EqualsLiteral("MozMousePixelScroll"))
msg = NS_MOUSE_PIXEL_SCROLL;
else
return NS_ERROR_UNEXPECTED;

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

@ -902,6 +902,9 @@ pref("mousewheel.transaction.timeout", 1500);
// mouse wheel scroll transaction is held even if the mouse cursor is moved.
pref("mousewheel.transaction.ignoremovedelay", 100);
// Macbook touchpad two finger pixel scrolling
pref("mousewheel.enable_pixel_scrolling", true);
// 0=lines, 1=pages, 2=history , 3=text size
pref("mousewheel.withnokey.action",0);
pref("mousewheel.withnokey.numlines",1);

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

@ -230,17 +230,18 @@ function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
* aOffsetY.
*
* aEvent is an object which may contain the properties:
* shiftKey, ctrlKey, altKey, metaKey, accessKey, button, type, axis, units, delta
* shiftKey, ctrlKey, altKey, metaKey, accessKey, button, type, axis, delta, hasPixels
*
* If the type is specified, an mouse scroll event of that type is fired. Otherwise,
* If the type is specified, a mouse scroll event of that type is fired. Otherwise,
* "DOMMouseScroll" is used.
*
* If the axis is specified, it must be one of "horizontal" or "vertical". If not specified,
* "vertical" is used.
*
* 'delta' is the amount to scroll by (can be positive or negative). It must
* be specified. 'units' is the units of 'delta', either "pixels" or "lines"; "lines"
* is the default if 'units' is ommitted.
* be specified.
*
* 'hasPixels' specifies whether kHasPixels should be set in the scrollFlags.
*
* aWindow is optional, and defaults to the current window object.
*/
@ -257,7 +258,7 @@ function synthesizeMouseScroll(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
// See nsMouseScrollFlags in nsGUIEvent.h
const kIsVertical = 0x02;
const kIsHorizontal = 0x04;
const kIsPixels = 0x08;
const kHasPixels = 0x08;
var button = aEvent.button || 0;
var modifiers = _parseModifiers(aEvent);
@ -267,10 +268,9 @@ function synthesizeMouseScroll(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
var type = aEvent.type || "DOMMouseScroll";
var axis = aEvent.axis || "vertical";
var units = aEvent.units || "lines";
var scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical;
if (units == "pixels") {
scrollFlags |= kIsPixels;
if (aEvent.hasPixels) {
scrollFlags |= kHasPixels;
}
utils.sendMouseScrollEvent(type, left + aOffsetX, top + aOffsetY, button,
scrollFlags, aEvent.delta, modifiers);

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

@ -73,59 +73,86 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=378028
<script type="application/javascript"><![CDATA[
/** Test for Bug 378028 **/
/* and for Bug 350471 **/
SimpleTest.waitForExplicitFinish();
/* There are three kinds of scroll events:
1. line scrolls without hasPixels
2. line scrolls with hasPixels
3. pixel scrolls
Listboxes and arrowscrollboxes (DOM event scrolling) should only react to
line scrolls and ignore hasPixels.
Richlistboxes ("native" scrolling) should be scrollable by kind 1 and 3.
*/
const kinds = [
{ eventType: "DOMMouseScroll", hasPixels: false, shouldScrollDOM: true, shouldScrollNative: true },
{ eventType: "DOMMouseScroll", hasPixels: true, shouldScrollDOM: true, shouldScrollNative: false },
{ eventType: "MozMousePixelScroll", hasPixels: false, shouldScrollDOM: false, shouldScrollNative: true }
];
function testListbox(id)
{
var listbox = document.getElementById(id);
function helper(aStart, aDelta)
function helper(aStart, aDelta, aKind)
{
listbox.scrollToIndex(aStart);
synthesizeMouseScroll(listbox, 10, 10,
{axis:"vertical", delta:aDelta});
is(listbox.getIndexOfFirstVisibleRow(), aStart + aDelta,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta);
{axis:"vertical", delta:aDelta, type:aKind.eventType,
hasPixels:aKind.hasPixels});
is(listbox.getIndexOfFirstVisibleRow(), aKind.shouldScrollDOM ? aStart + aDelta : aStart,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta
+ " eventType " + aKind.eventType + " hasPixels " + aKind.hasPixels);
// Check that horizontal scrolling has no effect
listbox.scrollToIndex(aStart);
synthesizeMouseScroll(listbox, 10, 10,
{axis:"horizontal", delta:aDelta});
{axis:"horizontal", delta:aDelta, type:aKind.eventType,
hasPixels:aKind.hasPixels});
is(listbox.getIndexOfFirstVisibleRow(), aStart,
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta);
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta
+ " eventType " + aKind.eventType + " hasPixels " + aKind.hasPixels);
}
helper(2, -1);
helper(2, 1);
helper(2, -2);
helper(2, 2);
kinds.forEach(function(aKind) {
helper(2, -1, aKind);
helper(2, 1, aKind);
helper(2, -2, aKind);
helper(2, 2, aKind);
});
}
function testRichListbox(id)
{
var listbox = document.getElementById(id);
function helper(aStart, aDelta, aExpected)
function helper(aStart, aDelta, aExpected, aKind)
{
listbox.scrollToIndex(aStart);
synthesizeMouseScroll(listbox, 10, 10,
{axis:"vertical", delta:aDelta});
is(listbox.getIndexOfFirstVisibleRow(), aExpected,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta);
{axis:"vertical", delta:aDelta, type:aKind.eventType,
hasPixels:aKind.hasPixels});
is(listbox.getIndexOfFirstVisibleRow(), aKind.shouldScrollNative ? aExpected : aStart,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta
+ " eventType " + aKind.eventType + " hasPixels " + aKind.hasPixels);
// Check that horizontal scrolling has no effect
listbox.scrollToIndex(aStart);
synthesizeMouseScroll(listbox, 10, 10,
{axis:"horizontal", delta:aDelta});
{axis:"horizontal", delta:aDelta, type:aKind.eventType,
hasPixels:aKind.hasPixels});
is(listbox.getIndexOfFirstVisibleRow(), aStart,
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta);
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta
+ " eventType " + aKind.eventType + " hasPixels " + aKind.hasPixels);
}
// richlistbox currently uses native XUL scrolling, so the "line"
// amounts don't necessarily correspond 1-to-1 with listbox items. So
// we just check that scrolling up/down a lot hits the first/last items
helper(2, -100, 0);
helper(2, 100, listbox.getRowCount() - listbox.getNumberOfVisibleRows());
kinds.forEach(function(aKind) {
helper(2, -100, 0, aKind);
helper(2, 100, listbox.getRowCount() - listbox.getNumberOfVisibleRows(), aKind);
});
}
function testArrowScrollbox(id)
@ -134,7 +161,7 @@ function testArrowScrollbox(id)
var scrollBoxObject = scrollbox.scrollBoxObject;
var orient = scrollbox.getAttribute("orient");
function helper(aStart, aDelta, aExpected)
function helper(aStart, aDelta, aExpected, aKind)
{
var xpos = {};
var ypos = {};
@ -142,23 +169,27 @@ function testArrowScrollbox(id)
scrollBoxObject.scrollTo(aStart, aStart);
synthesizeMouseScroll(scrollbox, 5, 5,
{axis:"vertical", delta:aDelta});
{axis:"vertical", delta:aDelta, type:aKind.eventType,
hasPixels:aKind.hasPixels});
scrollBoxObject.getPosition(xpos, ypos);
// Note, vertical mouse scrolling is allowed to scroll horizontal
// arrowscrollboxes, because many users have no horizontal mouse scroll
// capability
is(pos.value, aExpected,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta);
is(pos.value, aKind.shouldScrollDOM ? aExpected : aStart,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta
+ " eventType " + aKind.eventType + " hasPixels " + aKind.hasPixels);
scrollBoxObject.scrollTo(aStart, aStart);
synthesizeMouseScroll(scrollbox, 5, 5,
{axis:"horizontal", delta:aDelta});
{axis:"horizontal", delta:aDelta, type:aKind.eventType,
hasPixels:aKind.hasPixels});
// horizontal mouse scrolling is never allowed to scroll vertical
// arrowscrollboxes
scrollBoxObject.getPosition(xpos, ypos);
var expected = orient == "horizontal" ? aExpected : aStart;
var expected = (aKind.shouldScrollDOM && (orient == "horizontal")) ? aExpected : aStart;
is(pos.value, expected,
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta);
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta
+ " eventType " + aKind.eventType + " hasPixels " + aKind.hasPixels);
}
var scrolledWidth = {};
@ -168,8 +199,10 @@ function testArrowScrollbox(id)
var scrollMaxY = scrolledHeight.value - scrollBoxObject.height;
var scrollMax = orient == "horizontal" ? scrollMaxX : scrollMaxY;
helper(50, -100, 0);
helper(50, 100, scrollMax);
kinds.forEach(function(aKind) {
helper(50, -100, 0, aKind);
helper(50, 100, scrollMax, aKind);
});
}
function runTests()

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

@ -1096,24 +1096,37 @@ function testtag_tree_column_reorder()
function testtag_tree_mousescroll(aTree)
{
function helper(aStart, aDelta)
/* Scroll event kinds, see test_mousescroll.xul */
const kinds = [
{ eventType: "DOMMouseScroll", hasPixels: false, shouldScrollDOM: true, shouldScrollNative: true },
{ eventType: "DOMMouseScroll", hasPixels: true, shouldScrollDOM: true, shouldScrollNative: false },
{ eventType: "MozMousePixelScroll", hasPixels: false, shouldScrollDOM: false, shouldScrollNative: true }
];
function helper(aStart, aDelta, aKind)
{
aTree.treeBoxObject.scrollToRow(aStart);
synthesizeMouseScroll(aTree.body, 1, 1,
{type:"DOMMouseScroll", axis:"vertical", delta:aDelta});
is(aTree.treeBoxObject.getFirstVisibleRow(), aStart + aDelta, "mouse-scroll vertical starting " + aStart + " delta " + aDelta);
{axis:"vertical", delta:aDelta, type:aKind.eventType,
hasPixels:aKind.hasPixels});
var expected = aKind.shouldScrollDOM ? aStart + aDelta : aStart;
is(aTree.treeBoxObject.getFirstVisibleRow(), expected, "mouse-scroll vertical starting " + aStart + " delta " + aDelta
+ " eventType " + aKind.eventType + " hasPixels " + aKind.hasPixels);
aTree.treeBoxObject.scrollToRow(aStart);
// Check that horizontal scrolling has no effect
synthesizeMouseScroll(aTree.body, 1, 1,
{type:"DOMMouseScroll", axis:"horizontal", delta:aDelta});
is(aTree.treeBoxObject.getFirstVisibleRow(), aStart, "mouse-scroll horizontal starting " + aStart + " delta " + aDelta);
{axis:"horizontal", delta:aDelta, type:aKind.eventType,
hasPixels:aKind.hasPixels});
is(aTree.treeBoxObject.getFirstVisibleRow(), aStart, "mouse-scroll horizontal starting " + aStart + " delta " + aDelta
+ " eventType " + aKind.eventType + " hasPixels " + aKind.hasPixels);
}
helper(2, -1);
helper(2, 1);
helper(2, -2);
helper(2, 2);
kinds.forEach(function(aKind) {
helper(2, -1, aKind);
helper(2, 1, aKind);
helper(2, -2, aKind);
helper(2, 2, aKind);
});
}
function synthesizeColumnDrag(aTree, aMouseDownColumnNumber, aMouseUpColumnNumber, aAfter)

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

@ -271,6 +271,7 @@ class nsHashKey;
// Scroll events
#define NS_MOUSE_SCROLL_START 1600
#define NS_MOUSE_SCROLL (NS_MOUSE_SCROLL_START)
#define NS_MOUSE_PIXEL_SCROLL (NS_MOUSE_SCROLL_START + 1)
#define NS_SCROLLPORT_START 1700
#define NS_SCROLLPORT_UNDERFLOW (NS_SCROLLPORT_START)
@ -849,6 +850,43 @@ public:
nsTextEventReply theReply;
};
/* Mouse Scroll Events: Line Scrolling, Pixel Scrolling and Common Event Flows
*
* There are two common event flows:
* (1) Normal line scrolling:
* 1. An NS_MOUSE_SCROLL event without kHasPixels is dispatched to Gecko.
* 2. A DOMMouseScroll event is sent into the DOM.
* 3. A MozMousePixelScroll event is sent into the DOM.
* 4. If neither event has been consumed, the default handling of the
* NS_MOUSE_SCROLL event is executed.
*
* (2) Pixel scrolling:
* 1. An NS_MOUSE_SCROLL event with kHasPixels is dispatched to Gecko.
* 2. A DOMMouseScroll event is sent into the DOM.
* 3. No scrolling takes place in the default handler.
* 4. An NS_MOUSE_PIXEL_SCROLL event is dispatched to Gecko.
* 5. A MozMousePixelScroll event is sent into the DOM.
* 6. If neither the NS_MOUSE_PIXELSCROLL event nor the preceding
* NS_MOUSE_SCROLL event have been consumed, the default handler scrolls.
* 7. Steps 4.-6. are repeated for every pixel scroll that belongs to
* the announced line scroll. Once enough pixels have been sent to
* complete a line, a new NS_MOUSE_SCROLL event is sent (goto step 1.).
*
* If a DOMMouseScroll event has been preventDefaulted, the associated
* following MozMousePixelScroll events are still sent - they just don't result
* in any scrolling (their default handler isn't executed).
*
* How many pixel scrolls make up one line scroll is decided in the widget layer
* where the NS_MOUSE(_PIXEL)_SCROLL events are created.
*
* This event flow model satisfies several requirements:
* - DOMMouseScroll handlers don't need to be aware of the existence of pixel
* scrolling.
* - preventDefault on a DOMMouseScroll event results in no scrolling.
* - DOMMouseScroll events aren't polluted with a kHasPixels flag.
* - You can make use of pixel scroll DOM events (MozMousePixelScroll).
*/
class nsMouseScrollEvent : public nsMouseEvent_base
{
public:
@ -856,7 +894,15 @@ public:
kIsFullPage = 1 << 0,
kIsVertical = 1 << 1,
kIsHorizontal = 1 << 2,
kIsPixels = 1 << 3
kHasPixels = 1 << 3 // Marks line scroll events that are provided as
// a fallback for pixel scroll events.
// These scroll events are used by things that can't
// be scrolled pixel-wise, like trees. You should
// ignore them when processing pixel scroll events
// to avoid double-processing the same scroll gesture.
// When kHasPixels is set, the event is guaranteed to
// be followed up by an event that contains pixel
// scrolling information.
};
nsMouseScrollEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)

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

@ -99,6 +99,22 @@ extern "C" long TSMProcessRawKeyEvent(EventRef carbonEvent);
@end
// Needed to support pixel scrolling.
// See http://developer.apple.com/qa/qa2005/qa1453.html.
// kEventMouseScroll is only defined on 10.5+. Using the moz prefix avoids
// potential symbol conflicts.
// This should be changed when 10.4 support is dropped.
enum {
mozkEventMouseScroll = 11
};
// Support for pixel scroll deltas, not part of NSEvent.h
// See http://lists.apple.com/archives/cocoa-dev/2007/Feb/msg00050.html
@interface NSEvent (DeviceDelta)
- (float)deviceDeltaX;
- (float)deviceDeltaY;
@end
@interface ChildView : NSView<
#ifdef ACCESSIBILITY
mozAccessible,

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

@ -3493,77 +3493,119 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
if (!mGeckoChild)
return;
float scrollDelta;
float scrollDelta = 0;
float scrollDeltaPixels = 0;
PRBool checkPixels = PR_TRUE;
if (inAxis & nsMouseScrollEvent::kIsVertical)
scrollDelta = -[theEvent deltaY];
else if (inAxis & nsMouseScrollEvent::kIsHorizontal)
scrollDelta = -[theEvent deltaX];
else
return; // caller screwed up
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs)
prefs->GetBoolPref("mousewheel.enable_pixel_scrolling", &checkPixels);
if (scrollDelta == 0)
// No sense in firing off a Gecko event. Note that as of 10.4 Tiger,
// a single NSScrollWheel event might result in deltaX = deltaY = 0.
return;
nsMouseScrollEvent geckoEvent(PR_TRUE, NS_MOUSE_SCROLL, nsnull);
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
geckoEvent.scrollFlags |= inAxis;
// Gecko only understands how to scroll by an integer value. Using floor
// and ceil is better than truncating the fraction, especially when
// |delta| < 1.
if (scrollDelta < 0)
geckoEvent.delta = (PRInt32)floorf(scrollDelta);
else
geckoEvent.delta = (PRInt32)ceilf(scrollDelta);
nsAutoRetainCocoaObject kungFuDeathGrip(self);
mGeckoChild->DispatchWindowEvent(geckoEvent);
if (!mGeckoChild)
return;
// dispatch scroll wheel carbon event for plugins
{
EventRef theEvent;
OSStatus err = ::MacCreateEvent(NULL,
kEventClassMouse,
kEventMouseWheelMoved,
TicksToEventTime(TickCount()),
kEventAttributeUserEvent,
&theEvent);
if (err == noErr) {
EventMouseWheelAxis axis;
if (inAxis & nsMouseScrollEvent::kIsVertical)
axis = kEventMouseWheelAxisY;
else if (inAxis & nsMouseScrollEvent::kIsHorizontal)
axis = kEventMouseWheelAxisX;
SetEventParameter(theEvent,
kEventParamMouseWheelAxis,
typeMouseWheelAxis,
sizeof(EventMouseWheelAxis),
&axis);
SInt32 delta = (SInt32)-geckoEvent.delta;
SetEventParameter(theEvent,
kEventParamMouseWheelDelta,
typeLongInteger,
sizeof(SInt32),
&delta);
Point mouseLoc;
::GetGlobalMouse(&mouseLoc);
SetEventParameter(theEvent,
kEventParamMouseLocation,
typeQDPoint,
sizeof(Point),
&mouseLoc);
::SendEventToEventTarget(theEvent, GetWindowEventTarget((WindowRef)[[self window] windowRef]));
ReleaseEvent(theEvent);
EventRef theCarbonEvent = [theEvent _eventRef];
UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
// Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa
// assertion and an Objective-C NSInternalInconsistencyException if the
// underlying "Carbon" event doesn't contain pixel scrolling information.
// For these events, carbonEventKind is kEventMouseWheelMoved instead of
// kEventMouseScroll.
if (carbonEventKind != mozkEventMouseScroll)
checkPixels = PR_FALSE;
// Some scrolling devices supports pixel scrolling, e.g. a Macbook
// touchpad or a Mighty Mouse. On those devices, [event deviceDeltaX/Y]
// contains the amount of pixels to scroll.
if (inAxis & nsMouseScrollEvent::kIsVertical) {
scrollDelta = -[theEvent deltaY];
if (checkPixels && (scrollDelta == 0 || scrollDelta != floor(scrollDelta))) {
scrollDeltaPixels = -[theEvent deviceDeltaY];
}
} else if (inAxis & nsMouseScrollEvent::kIsHorizontal) {
scrollDelta = -[theEvent deltaX];
if (checkPixels && (scrollDelta == 0 || scrollDelta != floor(scrollDelta))) {
scrollDeltaPixels = -[theEvent deviceDeltaX];
}
} else {
return; // caller screwed up
}
BOOL hasPixels = (scrollDeltaPixels != 0);
if (!hasPixels && scrollDelta == 0)
// No sense in firing off a Gecko event.
return;
if (scrollDelta != 0) {
// Send the line scroll event.
nsMouseScrollEvent geckoEvent(PR_TRUE, NS_MOUSE_SCROLL, nsnull);
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
geckoEvent.scrollFlags |= inAxis;
if (hasPixels)
geckoEvent.scrollFlags |= nsMouseScrollEvent::kHasPixels;
// Gecko only understands how to scroll by an integer value. Using floor
// and ceil is better than truncating the fraction, especially when
// |delta| < 1.
if (scrollDelta < 0)
geckoEvent.delta = (PRInt32)floorf(scrollDelta);
else
geckoEvent.delta = (PRInt32)ceilf(scrollDelta);
nsAutoRetainCocoaObject kungFuDeathGrip(self);
mGeckoChild->DispatchWindowEvent(geckoEvent);
if (!mGeckoChild)
return;
// dispatch scroll wheel carbon event for plugins
{
EventRef theEvent;
OSStatus err = ::MacCreateEvent(NULL,
kEventClassMouse,
kEventMouseWheelMoved,
TicksToEventTime(TickCount()),
kEventAttributeUserEvent,
&theEvent);
if (err == noErr) {
EventMouseWheelAxis axis;
if (inAxis & nsMouseScrollEvent::kIsVertical)
axis = kEventMouseWheelAxisY;
else if (inAxis & nsMouseScrollEvent::kIsHorizontal)
axis = kEventMouseWheelAxisX;
SetEventParameter(theEvent,
kEventParamMouseWheelAxis,
typeMouseWheelAxis,
sizeof(EventMouseWheelAxis),
&axis);
SInt32 delta = (SInt32)-geckoEvent.delta;
SetEventParameter(theEvent,
kEventParamMouseWheelDelta,
typeLongInteger,
sizeof(SInt32),
&delta);
Point mouseLoc;
::GetGlobalMouse(&mouseLoc);
SetEventParameter(theEvent,
kEventParamMouseLocation,
typeQDPoint,
sizeof(Point),
&mouseLoc);
::SendEventToEventTarget(theEvent, GetWindowEventTarget((WindowRef)[[self window] windowRef]));
ReleaseEvent(theEvent);
}
}
}
if (hasPixels) {
// Send the pixel scroll event.
nsMouseScrollEvent geckoEvent(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, nsnull);
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
geckoEvent.scrollFlags |= inAxis;
geckoEvent.delta = NSToIntRound(scrollDeltaPixels);
nsAutoRetainCocoaObject kungFuDeathGrip(self);
mGeckoChild->DispatchWindowEvent(geckoEvent);
}
NS_OBJC_END_TRY_ABORT_BLOCK;