Bug 941774 - Base widget implementation. r=roc

This commit is contained in:
Jim Mathies 2013-12-14 14:40:56 -06:00
parent d85f619b11
commit eb0464623a
3 changed files with 201 additions and 3 deletions

View File

@ -12,12 +12,15 @@
#include "nsStringGlue.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsWidgetInitData.h"
#include "nsTArray.h"
#include "nsITimer.h"
#include "nsXULAppAPI.h"
#include "mozilla/EventForwards.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "Units.h"
// forward declarations
@ -97,8 +100,8 @@ typedef void* nsNativeWidget;
#endif
#define NS_IWIDGET_IID \
{ 0x746cb189, 0x9793, 0x4e53, \
{ 0x89, 0x47, 0x78, 0x56, 0xb6, 0xcd, 0x9f, 0x71 } }
{ 0x67da44c4, 0xe21b, 0x4742, \
{ 0x9c, 0x2b, 0x26, 0xc7, 0x70, 0x21, 0xde, 0x87 } }
/*
* Window shadow styles
@ -493,7 +496,9 @@ class nsIWidget : public nsISupports {
: mLastChild(nullptr)
, mPrevSibling(nullptr)
, mOnDestroyCalled(false)
{}
{
ClearNativeTouchSequence();
}
/**
@ -1559,6 +1564,85 @@ class nsIWidget : public nsISupports {
uint32_t aModifierFlags,
uint32_t aAdditionalFlags) = 0;
/*
* TouchPointerState states for SynthesizeNativeTouchPoint. Match
* touch states in nsIDOMWindowUtils.idl.
*/
enum TouchPointerState {
// The pointer is in a hover state above the digitizer
TOUCH_HOVER = 0x01,
// The pointer is in contact with the digitizer
TOUCH_CONTACT = 0x02,
// The pointer has been removed from the digitizer detection area
TOUCH_REMOVE = 0x04,
// The pointer has been canceled. Will cancel any pending os level
// gestures that would triggered as a result of completion of the
// input sequence. This may not cancel moz platform related events
// that might get tirggered by input already delivered.
TOUCH_CANCEL = 0x08
};
/*
* Create a new or update an existing touch pointer on the digitizer.
* To trigger os level gestures, individual touch points should
* transition through a complete set of touch states which should be
* sent as individual messages.
*
* @param aPointerId The touch point id to create or update.
* @param aPointerState one or more of the touch states listed above
* @param aScreenX, aScreenY screen coords of this event
* @param aPressure 0.0 -> 1.0 float val indicating pressure
* @param aOrientation 0 -> 359 degree value indicating the
* orientation of the pointer. Use 90 for normal taps.
*/
virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
nsIntPoint aPointerScreenPoint,
double aPointerPressure,
uint32_t aPointerOrientation) = 0;
/*
* Cancels all active simulated touch input points and pending long taps.
* Native widgets should track existing points such that they can clear the
* digitizer state when this call is made.
*/
virtual nsresult ClearNativeTouchSequence();
/*
* Helper for simulating a simple tap event with one touch point. When
* aLongTap is true, simulates a native long tap with a duration equal to
* ui.click_hold_context_menus.delay. This pref is compatible with the
* apzc long tap duration. Defaults to 1.5 seconds.
*/
nsresult SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint,
bool aLongTap);
private:
class LongTapInfo
{
public:
LongTapInfo(int32_t aPointerId, nsIntPoint& aPoint,
mozilla::TimeDuration aDuration) :
mPointerId(aPointerId),
mPosition(aPoint),
mDuration(aDuration),
mStamp(mozilla::TimeStamp::Now())
{
}
int32_t mPointerId;
nsIntPoint mPosition;
mozilla::TimeDuration mDuration;
mozilla::TimeStamp mStamp;
};
static void OnLongTapTimerCallback(nsITimer* aTimer, void* aClosure);
nsAutoPtr<LongTapInfo> mLongTapTouchPoint;
nsCOMPtr<nsITimer> mLongTapTimer;
static int32_t sPointerIdCounter;
public:
/**
* Activates a native menu item at the position specified by the index
* string. The index string is a string of positive integers separated

View File

@ -70,6 +70,11 @@ nsIContent* nsBaseWidget::mLastRollup = nullptr;
// in NativeWindowTheme.
bool gDisableNativeTheme = false;
// Async pump timer during injected long touch taps
#define TOUCH_INJECT_PUMP_TIMER_MSEC 50
#define TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC 1500
int32_t nsIWidget::sPointerIdCounter = 0;
// nsBaseWidget
NS_IMPL_ISUPPORTS1(nsBaseWidget, nsIWidget)
@ -1526,7 +1531,103 @@ nsBaseWidget::GetRootAccessible()
return nullptr;
}
#endif // ACCESSIBILITY
nsresult
nsIWidget::SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint, bool aLongTap)
{
if (sPointerIdCounter > TOUCH_INJECT_MAX_POINTS) {
sPointerIdCounter = 0;
}
int pointerId = sPointerIdCounter;
sPointerIdCounter++;
nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_CONTACT,
aPointerScreenPoint, 1.0, 90);
if (NS_FAILED(rv)) {
return rv;
}
if (!aLongTap) {
nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_REMOVE,
aPointerScreenPoint, 0, 0);
return rv;
}
// initiate a long tap
int elapse = Preferences::GetInt("ui.click_hold_context_menus.delay",
TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC);
if (!mLongTapTimer) {
mLongTapTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
SynthesizeNativeTouchPoint(pointerId, TOUCH_CANCEL,
aPointerScreenPoint, 0, 0);
return NS_ERROR_UNEXPECTED;
}
// Windows requires recuring events, so we set this to a smaller window
// than the pref value.
int timeout = elapse;
if (timeout > TOUCH_INJECT_PUMP_TIMER_MSEC) {
timeout = TOUCH_INJECT_PUMP_TIMER_MSEC;
}
mLongTapTimer->InitWithFuncCallback(OnLongTapTimerCallback, this,
timeout,
nsITimer::TYPE_REPEATING_SLACK);
}
// If we already have a long tap pending, cancel it. We only allow one long
// tap to be active at a time.
if (mLongTapTouchPoint) {
SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
mLongTapTouchPoint->mPosition, 0, 0);
}
mLongTapTouchPoint = new LongTapInfo(pointerId, aPointerScreenPoint,
TimeDuration::FromMilliseconds(elapse));
return NS_OK;
}
// static
void
nsIWidget::OnLongTapTimerCallback(nsITimer* aTimer, void* aClosure)
{
nsIWidget *self = static_cast<nsIWidget *>(aClosure);
if ((self->mLongTapTouchPoint->mStamp + self->mLongTapTouchPoint->mDuration) >
TimeStamp::Now()) {
#ifdef XP_WIN
// Windows needs us to keep pumping feedback to the digitizer, so update
// the pointer id with the same position.
self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
TOUCH_CONTACT,
self->mLongTapTouchPoint->mPosition,
1.0, 90);
#endif
return;
}
// finished, remove the touch point
self->mLongTapTimer->Cancel();
self->mLongTapTimer = nullptr;
self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
TOUCH_REMOVE,
self->mLongTapTouchPoint->mPosition,
0, 0);
self->mLongTapTouchPoint = nullptr;
}
nsresult
nsIWidget::ClearNativeTouchSequence()
{
if (!mLongTapTimer) {
return NS_OK;
}
mLongTapTimer->Cancel();
mLongTapTimer = nullptr;
SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
mLongTapTouchPoint->mPosition, 0, 0);
mLongTapTouchPoint = nullptr;
return NS_OK;
}
#ifdef DEBUG
//////////////////////////////////////////////////////////////

View File

@ -41,6 +41,11 @@ namespace base {
class Thread;
}
// Windows specific constant indicating the maximum number of touch points the
// inject api will allow. This also sets the maximum numerical value for touch
// ids we can use when injecting touch points on Windows.
#define TOUCH_INJECT_MAX_POINTS 256
class nsBaseWidget;
class WidgetShutdownObserver MOZ_FINAL : public nsIObserver
@ -320,6 +325,14 @@ protected:
uint32_t aAdditionalFlags)
{ return NS_ERROR_UNEXPECTED; }
virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
nsIntPoint aPointerScreenPoint,
double aPointerPressure,
uint32_t aPointerOrientation)
{ return NS_ERROR_UNEXPECTED; }
protected:
// Stores the clip rectangles in aRects into mClipRects. Returns true
// if the new rectangles are different from the old rectangles.
bool StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects);