summaryrefslogtreecommitdiffstats
path: root/dom/events/TouchEvent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/events/TouchEvent.cpp')
-rw-r--r--dom/events/TouchEvent.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/dom/events/TouchEvent.cpp b/dom/events/TouchEvent.cpp
new file mode 100644
index 000000000..cc9684eb3
--- /dev/null
+++ b/dom/events/TouchEvent.cpp
@@ -0,0 +1,303 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/Navigator.h"
+#include "mozilla/dom/TouchEvent.h"
+#include "mozilla/dom/Touch.h"
+#include "mozilla/dom/TouchListBinding.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/TouchEvents.h"
+#include "nsContentUtils.h"
+#include "nsIDocShell.h"
+#include "mozilla/WidgetUtils.h"
+
+namespace mozilla {
+
+namespace dom {
+
+/******************************************************************************
+ * TouchList
+ *****************************************************************************/
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TouchList)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TouchList, mParent, mPoints)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TouchList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TouchList)
+
+JSObject*
+TouchList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return TouchListBinding::Wrap(aCx, this, aGivenProto);
+}
+
+// static
+bool
+TouchList::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
+{
+ return TouchEvent::PrefEnabled(aCx, aGlobal);
+}
+
+/******************************************************************************
+ * TouchEvent
+ *****************************************************************************/
+
+TouchEvent::TouchEvent(EventTarget* aOwner,
+ nsPresContext* aPresContext,
+ WidgetTouchEvent* aEvent)
+ : UIEvent(aOwner, aPresContext,
+ aEvent ? aEvent :
+ new WidgetTouchEvent(false, eVoidEvent, nullptr))
+{
+ if (aEvent) {
+ mEventIsInternal = false;
+
+ for (uint32_t i = 0; i < aEvent->mTouches.Length(); ++i) {
+ Touch* touch = aEvent->mTouches[i];
+ touch->InitializePoints(mPresContext, aEvent);
+ }
+ } else {
+ mEventIsInternal = true;
+ mEvent->mTime = PR_Now();
+ }
+}
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(TouchEvent, UIEvent,
+ mTouches,
+ mTargetTouches,
+ mChangedTouches)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TouchEvent)
+NS_INTERFACE_MAP_END_INHERITING(UIEvent)
+
+NS_IMPL_ADDREF_INHERITED(TouchEvent, UIEvent)
+NS_IMPL_RELEASE_INHERITED(TouchEvent, UIEvent)
+
+void
+TouchEvent::InitTouchEvent(const nsAString& aType,
+ bool aCanBubble,
+ bool aCancelable,
+ nsGlobalWindow* aView,
+ int32_t aDetail,
+ bool aCtrlKey,
+ bool aAltKey,
+ bool aShiftKey,
+ bool aMetaKey,
+ TouchList* aTouches,
+ TouchList* aTargetTouches,
+ TouchList* aChangedTouches)
+{
+ NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
+
+ UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
+ mEvent->AsInputEvent()->InitBasicModifiers(aCtrlKey, aAltKey,
+ aShiftKey, aMetaKey);
+ mTouches = aTouches;
+ mTargetTouches = aTargetTouches;
+ mChangedTouches = aChangedTouches;
+}
+
+TouchList*
+TouchEvent::Touches()
+{
+ if (!mTouches) {
+ WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
+ if (mEvent->mMessage == eTouchEnd || mEvent->mMessage == eTouchCancel) {
+ // for touchend events, remove any changed touches from mTouches
+ WidgetTouchEvent::AutoTouchArray unchangedTouches;
+ const WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
+ for (uint32_t i = 0; i < touches.Length(); ++i) {
+ if (!touches[i]->mChanged) {
+ unchangedTouches.AppendElement(touches[i]);
+ }
+ }
+ mTouches = new TouchList(ToSupports(this), unchangedTouches);
+ } else {
+ mTouches = new TouchList(ToSupports(this), touchEvent->mTouches);
+ }
+ }
+ return mTouches;
+}
+
+TouchList*
+TouchEvent::TargetTouches()
+{
+ if (!mTargetTouches) {
+ WidgetTouchEvent::AutoTouchArray targetTouches;
+ WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
+ const WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
+ for (uint32_t i = 0; i < touches.Length(); ++i) {
+ // for touchend/cancel events, don't append to the target list if this is a
+ // touch that is ending
+ if ((mEvent->mMessage != eTouchEnd && mEvent->mMessage != eTouchCancel) ||
+ !touches[i]->mChanged) {
+ if (touches[i]->mTarget == mEvent->mOriginalTarget) {
+ targetTouches.AppendElement(touches[i]);
+ }
+ }
+ }
+ mTargetTouches = new TouchList(ToSupports(this), targetTouches);
+ }
+ return mTargetTouches;
+}
+
+TouchList*
+TouchEvent::ChangedTouches()
+{
+ if (!mChangedTouches) {
+ WidgetTouchEvent::AutoTouchArray changedTouches;
+ WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
+ const WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
+ for (uint32_t i = 0; i < touches.Length(); ++i) {
+ if (touches[i]->mChanged) {
+ changedTouches.AppendElement(touches[i]);
+ }
+ }
+ mChangedTouches = new TouchList(ToSupports(this), changedTouches);
+ }
+ return mChangedTouches;
+}
+
+// static
+bool
+TouchEvent::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
+{
+ nsIDocShell* docShell = nullptr;
+ if (aGlobal) {
+ nsGlobalWindow* win = xpc::WindowOrNull(aGlobal);
+ if (win) {
+ docShell = win->GetDocShell();
+ }
+ }
+ return PrefEnabled(docShell);
+}
+
+// static
+bool
+TouchEvent::PrefEnabled(nsIDocShell* aDocShell)
+{
+ static bool sPrefCached = false;
+ static int32_t sPrefCacheValue = 0;
+
+ uint32_t touchEventsOverride = nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE;
+ if (aDocShell) {
+ aDocShell->GetTouchEventsOverride(&touchEventsOverride);
+ }
+
+ if (!sPrefCached) {
+ sPrefCached = true;
+ Preferences::AddIntVarCache(&sPrefCacheValue, "dom.w3c_touch_events.enabled");
+ }
+
+ bool enabled = false;
+ if (touchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_ENABLED) {
+ enabled = true;
+ } else if (touchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_DISABLED) {
+ enabled = false;
+ } else {
+ if (sPrefCacheValue == 2) {
+#if defined(MOZ_B2G) || defined(MOZ_WIDGET_ANDROID)
+ // Touch support is always enabled on B2G and android.
+ enabled = true;
+#elif defined(XP_WIN) || MOZ_WIDGET_GTK == 3
+ static bool sDidCheckTouchDeviceSupport = false;
+ static bool sIsTouchDeviceSupportPresent = false;
+ // On Windows and GTK3 we auto-detect based on device support.
+ if (!sDidCheckTouchDeviceSupport) {
+ sDidCheckTouchDeviceSupport = true;
+ sIsTouchDeviceSupportPresent = WidgetUtils::IsTouchDeviceSupportPresent();
+ }
+ enabled = sIsTouchDeviceSupportPresent;
+#else
+ enabled = false;
+#endif
+ } else {
+ enabled = !!sPrefCacheValue;
+ }
+ }
+
+ if (enabled) {
+ nsContentUtils::InitializeTouchEventTable();
+ }
+ return enabled;
+}
+
+// static
+already_AddRefed<Event>
+TouchEvent::Constructor(const GlobalObject& aGlobal,
+ const nsAString& aType,
+ const TouchEventInit& aParam,
+ ErrorResult& aRv)
+{
+ nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
+ RefPtr<TouchEvent> e = new TouchEvent(t, nullptr, nullptr);
+ bool trusted = e->Init(t);
+ RefPtr<TouchList> touches = e->CopyTouches(aParam.mTouches);
+ RefPtr<TouchList> targetTouches = e->CopyTouches(aParam.mTargetTouches);
+ RefPtr<TouchList> changedTouches = e->CopyTouches(aParam.mChangedTouches);
+ e->InitTouchEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
+ aParam.mDetail, aParam.mCtrlKey, aParam.mAltKey,
+ aParam.mShiftKey, aParam.mMetaKey, touches, targetTouches,
+ changedTouches);
+ e->SetTrusted(trusted);
+ e->SetComposed(aParam.mComposed);
+ return e.forget();
+}
+
+
+already_AddRefed<TouchList>
+TouchEvent::CopyTouches(const Sequence<OwningNonNull<Touch>>& aTouches)
+{
+ RefPtr<TouchList> list = new TouchList(GetParentObject());
+ size_t len = aTouches.Length();
+ for (size_t i = 0; i < len; ++i) {
+ list->Append(aTouches[i]);
+ }
+ return list.forget();
+}
+
+bool
+TouchEvent::AltKey()
+{
+ return mEvent->AsTouchEvent()->IsAlt();
+}
+
+bool
+TouchEvent::MetaKey()
+{
+ return mEvent->AsTouchEvent()->IsMeta();
+}
+
+bool
+TouchEvent::CtrlKey()
+{
+ return mEvent->AsTouchEvent()->IsControl();
+}
+
+bool
+TouchEvent::ShiftKey()
+{
+ return mEvent->AsTouchEvent()->IsShift();
+}
+
+} // namespace dom
+} // namespace mozilla
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+already_AddRefed<TouchEvent>
+NS_NewDOMTouchEvent(EventTarget* aOwner,
+ nsPresContext* aPresContext,
+ WidgetTouchEvent* aEvent)
+{
+ RefPtr<TouchEvent> it = new TouchEvent(aOwner, aPresContext, aEvent);
+ return it.forget();
+}