diff options
Diffstat (limited to 'dom/events/TouchEvent.cpp')
-rw-r--r-- | dom/events/TouchEvent.cpp | 303 |
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(); +} |