Bug 868648: Make window overlay scrollbars appear/disappear when 2 fingers down/up trackpad. Credits to Markus for his help getting this right. r=mstange,masayuki,smichaud

This commit is contained in:
André Reinald
2013-08-16 23:17:40 +02:00
parent dcfbdc7f8b
commit 1e51c1ef8d
10 changed files with 405 additions and 43 deletions

View File

@@ -269,6 +269,56 @@ struct DeltaValues
double deltaY; double deltaY;
}; };
/******************************************************************/
/* nsScrollbarsForWheel */
/******************************************************************/
class nsScrollbarsForWheel {
public:
static void PrepareToScrollText(nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent);
static void SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget);
// Hide all scrollbars (both mActiveOwner's and mActivatedScrollTargets')
static void MayInactivate();
static void Inactivate();
static bool IsActive();
static void OwnWheelTransaction(bool aOwn);
protected:
static const size_t kNumberOfTargets = 4;
static const DeltaValues directions[kNumberOfTargets];
static nsWeakFrame sActiveOwner;
static nsWeakFrame sActivatedScrollTargets[kNumberOfTargets];
static bool sHadWheelStart;
static bool sOwnWheelTransaction;
/**
* These two methods are called upon NS_WHEEL_START/NS_WHEEL_STOP events
* to show/hide the right scrollbars.
*/
static void TemporarilyActivateAllPossibleScrollTargets(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent);
static void DeactivateAllTemporarilyActivatedScrollTargets();
};
const DeltaValues nsScrollbarsForWheel::directions[kNumberOfTargets] = {
DeltaValues(-1, 0), DeltaValues(+1, 0), DeltaValues(0, -1), DeltaValues(0, +1)
};
nsWeakFrame nsScrollbarsForWheel::sActiveOwner = nullptr;
nsWeakFrame nsScrollbarsForWheel::sActivatedScrollTargets[kNumberOfTargets] = {
nullptr, nullptr, nullptr, nullptr
};
bool nsScrollbarsForWheel::sHadWheelStart = false;
bool nsScrollbarsForWheel::sOwnWheelTransaction = false;
/******************************************************************/
/* nsMouseWheelTransaction */
/******************************************************************/
class nsMouseWheelTransaction { class nsMouseWheelTransaction {
public: public:
static nsIFrame* GetTargetFrame() { return sTargetFrame; } static nsIFrame* GetTargetFrame() { return sTargetFrame; }
@@ -277,11 +327,13 @@ public:
// Be careful, UpdateTransaction may fire a DOM event, therefore, the target // Be careful, UpdateTransaction may fire a DOM event, therefore, the target
// frame might be destroyed in the event handler. // frame might be destroyed in the event handler.
static bool UpdateTransaction(WheelEvent* aEvent); static bool UpdateTransaction(WheelEvent* aEvent);
static void MayEndTransaction();
static void EndTransaction(); static void EndTransaction();
static void OnEvent(WidgetEvent* aEvent); static void OnEvent(WidgetEvent* aEvent);
static void Shutdown(); static void Shutdown();
static uint32_t GetTimeoutTime(); static uint32_t GetTimeoutTime();
static void OwnScrollbars(bool aOwn);
static DeltaValues AccelerateWheelDelta(WheelEvent* aEvent, static DeltaValues AccelerateWheelDelta(WheelEvent* aEvent,
bool aAllowScrollSpeedOverride); bool aAllowScrollSpeedOverride);
@@ -299,12 +351,14 @@ protected:
static int32_t GetAccelerationFactor(); static int32_t GetAccelerationFactor();
static DeltaValues OverrideSystemScrollSpeed(WheelEvent* aEvent); static DeltaValues OverrideSystemScrollSpeed(WheelEvent* aEvent);
static double ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor); static double ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor);
static bool OutOfTime(uint32_t aBaseTime, uint32_t aThreshold);
static nsWeakFrame sTargetFrame; static nsWeakFrame sTargetFrame;
static uint32_t sTime; // in milliseconds static uint32_t sTime; // in milliseconds
static uint32_t sMouseMoved; // in milliseconds static uint32_t sMouseMoved; // in milliseconds
static nsITimer* sTimer; static nsITimer* sTimer;
static int32_t sScrollSeriesCounter; static int32_t sScrollSeriesCounter;
static bool sOwnScrollbars;
}; };
nsWeakFrame nsMouseWheelTransaction::sTargetFrame(nullptr); nsWeakFrame nsMouseWheelTransaction::sTargetFrame(nullptr);
@@ -312,13 +366,7 @@ uint32_t nsMouseWheelTransaction::sTime = 0;
uint32_t nsMouseWheelTransaction::sMouseMoved = 0; uint32_t nsMouseWheelTransaction::sMouseMoved = 0;
nsITimer* nsMouseWheelTransaction::sTimer = nullptr; nsITimer* nsMouseWheelTransaction::sTimer = nullptr;
int32_t nsMouseWheelTransaction::sScrollSeriesCounter = 0; int32_t nsMouseWheelTransaction::sScrollSeriesCounter = 0;
bool nsMouseWheelTransaction::sOwnScrollbars = false;
static bool
OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
{
uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
return (now - aBaseTime > aThreshold);
}
static bool static bool
CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection) CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
@@ -328,20 +376,33 @@ CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
} }
static bool static bool
CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDeltaX, double aDeltaY) CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDirectionX, double aDirectionY)
{ {
MOZ_ASSERT(aScrollFrame); MOZ_ASSERT(aScrollFrame);
NS_ASSERTION(aDeltaX || aDeltaY, NS_ASSERTION(aDirectionX || aDirectionY,
"One of the delta values must be non-zero at least"); "One of the delta values must be non-zero at least");
nsPoint scrollPt = aScrollFrame->GetScrollPosition(); nsPoint scrollPt = aScrollFrame->GetScrollPosition();
nsRect scrollRange = aScrollFrame->GetScrollRange(); nsRect scrollRange = aScrollFrame->GetScrollRange();
uint32_t directions = aScrollFrame->GetPerceivedScrollingDirections(); uint32_t directions = aScrollFrame->GetPerceivedScrollingDirections();
return (aDeltaX && (directions & nsIScrollableFrame::HORIZONTAL) && return (aDirectionX && (directions & nsIScrollableFrame::HORIZONTAL) &&
CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDeltaX)) || CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDirectionX)) ||
(aDeltaY && (directions & nsIScrollableFrame::VERTICAL) && (aDirectionY && (directions & nsIScrollableFrame::VERTICAL) &&
CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDeltaY)); CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDirectionY));
}
bool
nsMouseWheelTransaction::OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
{
uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
return (now - aBaseTime > aThreshold);
}
void
nsMouseWheelTransaction::OwnScrollbars(bool aOwn)
{
sOwnScrollbars = aOwn;
} }
void void
@@ -349,6 +410,9 @@ nsMouseWheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
WheelEvent* aEvent) WheelEvent* aEvent)
{ {
NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!"); NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
MOZ_ASSERT(aEvent->message == NS_WHEEL_WHEEL,
"Transaction must be started with a wheel event");
nsScrollbarsForWheel::OwnWheelTransaction(false);
sTargetFrame = aTargetFrame; sTargetFrame = aTargetFrame;
sScrollSeriesCounter = 0; sScrollSeriesCounter = 0;
if (!UpdateTransaction(aEvent)) { if (!UpdateTransaction(aEvent)) {
@@ -385,6 +449,16 @@ nsMouseWheelTransaction::UpdateTransaction(WheelEvent* aEvent)
return true; return true;
} }
void
nsMouseWheelTransaction::MayEndTransaction()
{
if (!sOwnScrollbars && nsScrollbarsForWheel::IsActive()) {
nsScrollbarsForWheel::OwnWheelTransaction(true);
} else {
EndTransaction();
}
}
void void
nsMouseWheelTransaction::EndTransaction() nsMouseWheelTransaction::EndTransaction()
{ {
@@ -392,6 +466,11 @@ nsMouseWheelTransaction::EndTransaction()
sTimer->Cancel(); sTimer->Cancel();
sTargetFrame = nullptr; sTargetFrame = nullptr;
sScrollSeriesCounter = 0; sScrollSeriesCounter = 0;
if (sOwnScrollbars) {
sOwnScrollbars = false;
nsScrollbarsForWheel::OwnWheelTransaction(false);
nsScrollbarsForWheel::Inactivate();
}
} }
void void
@@ -415,7 +494,7 @@ nsMouseWheelTransaction::OnEvent(WidgetEvent* aEvent)
OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) { OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
// Terminate the current mousewheel transaction if the mouse moved more // Terminate the current mousewheel transaction if the mouse moved more
// than ignoremovedelay milliseconds ago // than ignoremovedelay milliseconds ago
EndTransaction(); MayEndTransaction();
} }
return; return;
case NS_MOUSE_MOVE: case NS_MOUSE_MOVE:
@@ -426,7 +505,7 @@ nsMouseWheelTransaction::OnEvent(WidgetEvent* aEvent)
nsIntPoint pt = GetScreenPoint(static_cast<WidgetGUIEvent*>(aEvent)); nsIntPoint pt = GetScreenPoint(static_cast<WidgetGUIEvent*>(aEvent));
nsIntRect r = sTargetFrame->GetScreenRectExternal(); nsIntRect r = sTargetFrame->GetScreenRectExternal();
if (!r.Contains(pt)) { if (!r.Contains(pt)) {
EndTransaction(); MayEndTransaction();
return; return;
} }
@@ -475,8 +554,9 @@ nsMouseWheelTransaction::OnFailToScrollTarget()
} }
// The target frame might be destroyed in the event handler, at that time, // The target frame might be destroyed in the event handler, at that time,
// we need to finish the current transaction // we need to finish the current transaction
if (!sTargetFrame) if (!sTargetFrame) {
EndTransaction(); EndTransaction();
}
} }
void void
@@ -491,7 +571,7 @@ nsMouseWheelTransaction::OnTimeout(nsITimer* aTimer, void* aClosure)
nsIFrame* frame = sTargetFrame; nsIFrame* frame = sTargetFrame;
// We need to finish current transaction before DOM event firing. Because // We need to finish current transaction before DOM event firing. Because
// the next DOM event might create strange situation for us. // the next DOM event might create strange situation for us.
EndTransaction(); MayEndTransaction();
if (Preferences::GetBool("test.mousescroll", false)) { if (Preferences::GetBool("test.mousescroll", false)) {
// This event is used for automated tests, see bug 442774. // This event is used for automated tests, see bug 442774.
@@ -625,6 +705,127 @@ nsMouseWheelTransaction::OverrideSystemScrollSpeed(WheelEvent* aEvent)
return NS_FAILED(rv) ? DeltaValues(aEvent) : overriddenDeltaValues; return NS_FAILED(rv) ? DeltaValues(aEvent) : overriddenDeltaValues;
} }
/******************************************************************/
/* nsScrollbarsForWheel */
/******************************************************************/
void
nsScrollbarsForWheel::PrepareToScrollText(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent)
{
if (aEvent->message == NS_WHEEL_START) {
nsMouseWheelTransaction::OwnScrollbars(false);
if (!IsActive()) {
TemporarilyActivateAllPossibleScrollTargets(aESM, aTargetFrame, aEvent);
sHadWheelStart = true;
}
} else {
DeactivateAllTemporarilyActivatedScrollTargets();
}
}
void
nsScrollbarsForWheel::SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget)
{
if (!sHadWheelStart) {
return;
}
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(aScrollTarget);
if (!scrollbarOwner) {
return;
}
sHadWheelStart = false;
sActiveOwner = do_QueryFrame(aScrollTarget);
scrollbarOwner->ScrollbarActivityStarted();
}
void
nsScrollbarsForWheel::MayInactivate()
{
if (!sOwnWheelTransaction && nsMouseWheelTransaction::GetTargetFrame()) {
nsMouseWheelTransaction::OwnScrollbars(true);
} else {
Inactivate();
}
}
void
nsScrollbarsForWheel::Inactivate()
{
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sActiveOwner);
if (scrollbarOwner) {
scrollbarOwner->ScrollbarActivityStopped();
}
sActiveOwner = nullptr;
DeactivateAllTemporarilyActivatedScrollTargets();
if (sOwnWheelTransaction) {
sOwnWheelTransaction = false;
nsMouseWheelTransaction::OwnScrollbars(false);
nsMouseWheelTransaction::EndTransaction();
}
}
bool
nsScrollbarsForWheel::IsActive()
{
if (sActiveOwner) {
return true;
}
for (size_t i = 0; i < kNumberOfTargets; ++i) {
if (sActivatedScrollTargets[i]) {
return true;
}
}
return false;
}
void
nsScrollbarsForWheel::OwnWheelTransaction(bool aOwn)
{
sOwnWheelTransaction = aOwn;
}
void
nsScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent)
{
for (size_t i = 0; i < kNumberOfTargets; i++) {
const DeltaValues *dir = &directions[i];
nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
MOZ_ASSERT(!*scrollTarget, "scroll target still temporarily activated!");
nsIScrollableFrame* target =
aESM->ComputeScrollTarget(aTargetFrame, dir->deltaX, dir->deltaY, aEvent,
nsEventStateManager::COMPUTE_DEFAULT_ACTION_TARGET);
if (target) {
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(target);
if (scrollbarOwner) {
nsIFrame* targetFrame = do_QueryFrame(target);
*scrollTarget = targetFrame;
scrollbarOwner->ScrollbarActivityStarted();
}
}
}
}
void
nsScrollbarsForWheel::DeactivateAllTemporarilyActivatedScrollTargets()
{
for (size_t i = 0; i < kNumberOfTargets; i++) {
nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
if (*scrollTarget) {
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(*scrollTarget);
if (scrollbarOwner) {
scrollbarOwner->ScrollbarActivityStopped();
}
*scrollTarget = nullptr;
}
}
}
/******************************************************************/ /******************************************************************/
/* nsEventStateManager */ /* nsEventStateManager */
/******************************************************************/ /******************************************************************/
@@ -977,13 +1178,20 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
} }
break; break;
case NS_WHEEL_WHEEL: case NS_WHEEL_WHEEL:
case NS_WHEEL_START:
case NS_WHEEL_STOP:
{ {
NS_ASSERTION(aEvent->mFlags.mIsTrusted, NS_ASSERTION(aEvent->mFlags.mIsTrusted,
"Untrusted wheel event shouldn't be here"); "Untrusted wheel event shouldn't be here");
nsIContent* content = GetFocusedContent(); nsIContent* content = GetFocusedContent();
if (content) if (content) {
mCurrentTargetContent = content; mCurrentTargetContent = content;
}
if (aEvent->message != NS_WHEEL_WHEEL) {
break;
}
WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent); WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent); WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
@@ -2545,6 +2753,20 @@ nsIScrollableFrame*
nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame, nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
WheelEvent* aEvent, WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions) ComputeScrollTargetOptions aOptions)
{
return ComputeScrollTarget(aTargetFrame, aEvent->deltaX, aEvent->deltaY,
aEvent, aOptions);
}
// Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking
// for which scrollbarowners to activate when two finger down on trackpad
// and before any actual motion
nsIScrollableFrame*
nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions)
{ {
if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) { if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
// If the user recently scrolled with the mousewheel, then they probably // If the user recently scrolled with the mousewheel, then they probably
@@ -2569,14 +2791,14 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// If the event doesn't cause scroll actually, we cannot find scroll target // If the event doesn't cause scroll actually, we cannot find scroll target
// because we check if the event can cause scroll actually on each found // because we check if the event can cause scroll actually on each found
// scrollable frame. // scrollable frame.
if (!aEvent->deltaX && !aEvent->deltaY) { if (!aDirectionX && !aDirectionY) {
return nullptr; return nullptr;
} }
bool checkIfScrollableX = bool checkIfScrollableX =
aEvent->deltaX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS); aDirectionX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
bool checkIfScrollableY = bool checkIfScrollableY =
aEvent->deltaY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS); aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
nsIScrollableFrame* frameToScroll = nullptr; nsIScrollableFrame* frameToScroll = nullptr;
nsIFrame* scrollFrame = nsIFrame* scrollFrame =
@@ -2604,8 +2826,7 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// For default action, we should climb up the tree if cannot scroll it // For default action, we should climb up the tree if cannot scroll it
// by the event actually. // by the event actually.
bool canScroll = CanScrollOn(frameToScroll, bool canScroll = CanScrollOn(frameToScroll, aDirectionX, aDirectionY);
aEvent->deltaX, aEvent->deltaY);
// Comboboxes need special care. // Comboboxes need special care.
nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame); nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
if (comboBox) { if (comboBox) {
@@ -3170,25 +3391,41 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
} }
} }
break; break;
case NS_WHEEL_STOP:
{
MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
nsScrollbarsForWheel::MayInactivate();
}
break;
case NS_WHEEL_WHEEL: case NS_WHEEL_WHEEL:
case NS_WHEEL_START:
{ {
MOZ_ASSERT(aEvent->mFlags.mIsTrusted); MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
if (*aStatus == nsEventStatus_eConsumeNoDefault) { if (*aStatus == nsEventStatus_eConsumeNoDefault) {
nsScrollbarsForWheel::Inactivate();
break; break;
} }
WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent); WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) { switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) {
case WheelPrefs::ACTION_SCROLL: { case WheelPrefs::ACTION_SCROLL: {
if (!wheelEvent->deltaX && !wheelEvent->deltaY) {
break;
}
// For scrolling of default action, we should honor the mouse wheel // For scrolling of default action, we should honor the mouse wheel
// transaction. // transaction.
nsScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent);
if (aEvent->message != NS_WHEEL_WHEEL ||
(!wheelEvent->deltaX && !wheelEvent->deltaY)) {
break;
}
nsIScrollableFrame* scrollTarget = nsIScrollableFrame* scrollTarget =
ComputeScrollTarget(aTargetFrame, wheelEvent, ComputeScrollTarget(aTargetFrame, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET); COMPUTE_DEFAULT_ACTION_TARGET);
nsScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
if (!scrollTarget) { if (!scrollTarget) {
wheelEvent->mViewPortIsOverscrolled = true; wheelEvent->mViewPortIsOverscrolled = true;
} }
@@ -3200,6 +3437,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
DoScrollText(scrollTarget, wheelEvent); DoScrollText(scrollTarget, wheelEvent);
} else { } else {
nsMouseWheelTransaction::EndTransaction(); nsMouseWheelTransaction::EndTransaction();
nsScrollbarsForWheel::Inactivate();
} }
break; break;
} }

View File

@@ -46,6 +46,7 @@ class nsEventStateManager : public nsSupportsWeakReference,
public nsIObserver public nsIObserver
{ {
friend class nsMouseWheelTransaction; friend class nsMouseWheelTransaction;
friend class nsScrollbarsForWheel;
public: public:
typedef mozilla::TimeStamp TimeStamp; typedef mozilla::TimeStamp TimeStamp;
@@ -557,6 +558,12 @@ protected:
mozilla::WheelEvent* aEvent, mozilla::WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions); ComputeScrollTargetOptions aOptions);
nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
mozilla::WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
/** /**
* GetScrollAmount() returns the scroll amount in app uints of one line or * GetScrollAmount() returns the scroll amount in app uints of one line or
* one page. If the wheel event scrolls a page, returns the page width and * one page. If the wheel event scrolls a page, returns the page width and

View File

@@ -77,6 +77,22 @@ nsHTMLScrollFrame::nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aCont
{ {
} }
void
nsHTMLScrollFrame::ScrollbarActivityStarted() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStarted();
}
}
void
nsHTMLScrollFrame::ScrollbarActivityStopped() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStopped();
}
}
nsresult nsresult
nsHTMLScrollFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements) nsHTMLScrollFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
{ {
@@ -902,6 +918,22 @@ nsXULScrollFrame::nsXULScrollFrame(nsIPresShell* aShell, nsStyleContext* aContex
mInner.mClipAllDescendants = aClipAllDescendants; mInner.mClipAllDescendants = aClipAllDescendants;
} }
void
nsXULScrollFrame::ScrollbarActivityStarted() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStarted();
}
}
void
nsXULScrollFrame::ScrollbarActivityStopped() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStopped();
}
}
nsMargin nsMargin
nsGfxScrollFrameInner::GetDesiredScrollbarSizes(nsBoxLayoutState* aState) nsGfxScrollFrameInner::GetDesiredScrollbarSizes(nsBoxLayoutState* aState)
{ {

View File

@@ -520,6 +520,9 @@ public:
return mInner.GetScrollbarBox(aVertical); return mInner.GetScrollbarBox(aVertical);
} }
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
// nsIScrollableFrame // nsIScrollableFrame
virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE { virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE {
return mInner.GetScrolledFrame(); return mInner.GetScrolledFrame();
@@ -810,6 +813,9 @@ public:
return mInner.GetScrollbarBox(aVertical); return mInner.GetScrollbarBox(aVertical);
} }
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
// nsIScrollableFrame // nsIScrollableFrame
virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE { virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE {
return mInner.GetScrolledFrame(); return mInner.GetScrolledFrame();

View File

@@ -23,6 +23,13 @@ public:
* if there is no such box. * if there is no such box.
*/ */
virtual nsIFrame* GetScrollbarBox(bool aVertical) = 0; virtual nsIFrame* GetScrollbarBox(bool aVertical) = 0;
/**
* Show or hide scrollbars on 2 fingers touch.
* Subclasses should call their ScrollbarActivity's corresponding methods.
*/
virtual void ScrollbarActivityStarted() const = 0;
virtual void ScrollbarActivityStopped() const = 0;
}; };
#endif #endif

View File

@@ -4495,6 +4495,22 @@ nsTreeBodyFrame::PostScrollEvent()
} }
} }
void
nsTreeBodyFrame::ScrollbarActivityStarted() const
{
if (mScrollbarActivity) {
mScrollbarActivity->ActivityStarted();
}
}
void
nsTreeBodyFrame::ScrollbarActivityStopped() const
{
if (mScrollbarActivity) {
mScrollbarActivity->ActivityStopped();
}
}
void void
nsTreeBodyFrame::DetachImageListeners() nsTreeBodyFrame::DetachImageListeners()
{ {

View File

@@ -465,6 +465,9 @@ protected:
void PostScrollEvent(); void PostScrollEvent();
void FireScrollEvent(); void FireScrollEvent();
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
/** /**
* Clear the pointer to this frame for all nsTreeImageListeners that were * Clear the pointer to this frame for all nsTreeImageListeners that were
* created by this frame. * created by this frame.

View File

@@ -429,6 +429,8 @@ enum nsEventStructType
#define NS_WHEEL_EVENT_START 5400 #define NS_WHEEL_EVENT_START 5400
#define NS_WHEEL_WHEEL (NS_WHEEL_EVENT_START) #define NS_WHEEL_WHEEL (NS_WHEEL_EVENT_START)
#define NS_WHEEL_START (NS_WHEEL_EVENT_START + 1)
#define NS_WHEEL_STOP (NS_WHEEL_EVENT_START + 2)
//System time is changed //System time is changed
#define NS_MOZ_TIME_CHANGE_EVENT 5500 #define NS_MOZ_TIME_CHANGE_EVENT 5500

View File

@@ -205,6 +205,12 @@ typedef NSInteger NSEventGestureAxis;
#endif // #ifdef __LP64__ #endif // #ifdef __LP64__
#endif // #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 #endif // #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
#if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
enum {
NSEventPhaseMayBegin = 0x1 << 5
};
#endif // #if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
// Undocumented scrollPhase flag that lets us discern between real scrolls and // Undocumented scrollPhase flag that lets us discern between real scrolls and
// automatically firing momentum scroll events. // automatically firing momentum scroll events.
@interface NSEvent (ScrollPhase) @interface NSEvent (ScrollPhase)
@@ -252,6 +258,11 @@ typedef NSInteger NSEventGestureAxis;
BOOL mPendingFullDisplay; BOOL mPendingFullDisplay;
BOOL mPendingDisplay; BOOL mPendingDisplay;
// WheelStart/Stop events should always come in pairs. This BOOL records the
// last received event so that, when we receive one of the events, we make sure
// to send its pair event first, in case we didn't yet for any reason.
BOOL mExpectingWheelStop;
// Holds our drag service across multiple drag calls. The reference to the // Holds our drag service across multiple drag calls. The reference to the
// service is obtained when the mouse enters the view and is released when // service is obtained when the mouse enters the view and is released when
// the mouse exits or there is a drop. This prevents us from having to // the mouse exits or there is a drop. This prevents us from having to
@@ -355,6 +366,8 @@ typedef NSInteger NSEventGestureAxis;
- (void)rotateWithEvent:(NSEvent *)anEvent; - (void)rotateWithEvent:(NSEvent *)anEvent;
- (void)endGestureWithEvent:(NSEvent *)anEvent; - (void)endGestureWithEvent:(NSEvent *)anEvent;
- (void)scrollWheel:(NSEvent *)anEvent;
// Helper function for Lion smart magnify events // Helper function for Lion smart magnify events
+ (BOOL)isLionSmartMagnifyEvent:(NSEvent*)anEvent; + (BOOL)isLionSmartMagnifyEvent:(NSEvent*)anEvent;

View File

@@ -140,6 +140,8 @@ uint32_t nsChildView::sLastInputEventCount = 0;
- (void)forceRefreshOpenGL; - (void)forceRefreshOpenGL;
// set up a gecko mouse event based on a cocoa mouse event // set up a gecko mouse event based on a cocoa mouse event
- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetWheelEvent*)outWheelEvent;
- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent - (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetInputEvent*)outGeckoEvent; toGeckoEvent:(WidgetInputEvent*)outGeckoEvent;
@@ -2777,6 +2779,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
#endif #endif
mPendingDisplay = NO; mPendingDisplay = NO;
mBlockedLastMouseDown = NO; mBlockedLastMouseDown = NO;
mExpectingWheelStop = NO;
mLastMouseDownEvent = nil; mLastMouseDownEvent = nil;
mClickThroughMouseDownEvent = nil; mClickThroughMouseDownEvent = nil;
@@ -4752,6 +4755,22 @@ static int32_t RoundUp(double aDouble)
static_cast<int32_t>(ceil(aDouble)); static_cast<int32_t>(ceil(aDouble));
} }
- (void)sendWheelStartOrStop:(uint32_t)msg forEvent:(NSEvent *)theEvent
{
WidgetWheelEvent wheelEvent(true, msg, mGeckoChild);
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
mExpectingWheelStop = (msg == NS_WHEEL_START);
mGeckoChild->DispatchWindowEvent(wheelEvent);
}
- (void)sendWheelCondition:(BOOL)condition first:(uint32_t)first second:(uint32_t)second forEvent:(NSEvent *)theEvent
{
if (mExpectingWheelStop == condition) {
[self sendWheelStartOrStop:first forEvent:theEvent];
}
[self sendWheelStartOrStop:second forEvent:theEvent];
}
- (void)scrollWheel:(NSEvent*)theEvent - (void)scrollWheel:(NSEvent*)theEvent
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@@ -4768,25 +4787,23 @@ static int32_t RoundUp(double aDouble)
return; return;
} }
WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild); if (nsCocoaFeatures::OnLionOrLater()) {
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&wheelEvent]; NSEventPhase phase = [theEvent phase];
wheelEvent.deltaMode = // Fire NS_WHEEL_START/STOP events when 2 fingers touch/release the touchpad.
Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ? if (phase & NSEventPhaseMayBegin) {
nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE; [self sendWheelCondition:YES first:NS_WHEEL_STOP second:NS_WHEEL_START forEvent:theEvent];
return;
}
// Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa if (phase & (NSEventPhaseEnded | NSEventPhaseCancelled)) {
// assertion and an Objective-C NSInternalInconsistencyException if the [self sendWheelCondition:NO first:NS_WHEEL_START second:NS_WHEEL_STOP forEvent:theEvent];
// underlying "Carbon" event doesn't contain pixel scrolling information. return;
// For these events, carbonEventKind is kEventMouseWheelMoved instead of
// kEventMouseScroll.
if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
EventRef theCarbonEvent = [theEvent _eventRef];
UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
if (carbonEventKind != kEventMouseScroll) {
wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
} }
} }
WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]); wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]);
wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]); wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]);
@@ -4817,8 +4834,6 @@ static int32_t RoundUp(double aDouble)
return; return;
} }
wheelEvent.isMomentum = nsCocoaUtils::IsMomentumScrollEvent(theEvent);
NPCocoaEvent cocoaEvent; NPCocoaEvent cocoaEvent;
ChildViewMouseTracker::AttachPluginEvent(wheelEvent, self, theEvent, ChildViewMouseTracker::AttachPluginEvent(wheelEvent, self, theEvent,
NPCocoaEventScrollWheel, NPCocoaEventScrollWheel,
@@ -4907,6 +4922,29 @@ static int32_t RoundUp(double aDouble)
NS_OBJC_END_TRY_ABORT_BLOCK_NIL; NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
} }
- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetWheelEvent*)outWheelEvent
{
[self convertCocoaMouseEvent:aMouseEvent toGeckoEvent:outWheelEvent];
outWheelEvent->deltaMode =
Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ?
nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE;
// 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 (outWheelEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
EventRef theCarbonEvent = [aMouseEvent _eventRef];
UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
if (carbonEventKind != kEventMouseScroll) {
outWheelEvent->deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
}
}
outWheelEvent->isMomentum = nsCocoaUtils::IsMomentumScrollEvent(aMouseEvent);
}
- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent - (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetInputEvent*)outGeckoEvent toGeckoEvent:(WidgetInputEvent*)outGeckoEvent
{ {