michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/TouchEvent.h" michael@0: #include "mozilla/dom/Touch.h" michael@0: #include "mozilla/dom/TouchListBinding.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/TouchEvents.h" michael@0: #include "nsContentUtils.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: #ifdef XP_WIN michael@0: namespace widget { michael@0: extern int32_t IsTouchDeviceSupportPresent(); michael@0: } // namespace widget michael@0: #endif // #ifdef XP_WIN michael@0: michael@0: namespace dom { michael@0: michael@0: /****************************************************************************** michael@0: * TouchList michael@0: *****************************************************************************/ michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TouchList) michael@0: NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TouchList, mParent, mPoints) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(TouchList) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(TouchList) michael@0: michael@0: JSObject* michael@0: TouchList::WrapObject(JSContext* aCx) michael@0: { michael@0: return TouchListBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: TouchList::PrefEnabled(JSContext* aCx, JSObject* aGlobal) michael@0: { michael@0: return TouchEvent::PrefEnabled(aCx, aGlobal); michael@0: } michael@0: michael@0: Touch* michael@0: TouchList::IdentifiedTouch(int32_t aIdentifier) const michael@0: { michael@0: for (uint32_t i = 0; i < mPoints.Length(); ++i) { michael@0: Touch* point = mPoints[i]; michael@0: if (point && point->Identifier() == aIdentifier) { michael@0: return point; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: /****************************************************************************** michael@0: * TouchEvent michael@0: *****************************************************************************/ michael@0: michael@0: TouchEvent::TouchEvent(EventTarget* aOwner, michael@0: nsPresContext* aPresContext, michael@0: WidgetTouchEvent* aEvent) michael@0: : UIEvent(aOwner, aPresContext, michael@0: aEvent ? aEvent : new WidgetTouchEvent(false, 0, nullptr)) michael@0: { michael@0: if (aEvent) { michael@0: mEventIsInternal = false; michael@0: michael@0: for (uint32_t i = 0; i < aEvent->touches.Length(); ++i) { michael@0: Touch* touch = aEvent->touches[i]; michael@0: touch->InitializePoints(mPresContext, aEvent); michael@0: } michael@0: } else { michael@0: mEventIsInternal = true; michael@0: mEvent->time = PR_Now(); michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_INHERITED(TouchEvent, UIEvent, michael@0: mTouches, michael@0: mTargetTouches, michael@0: mChangedTouches) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TouchEvent) michael@0: NS_INTERFACE_MAP_END_INHERITING(UIEvent) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(TouchEvent, UIEvent) michael@0: NS_IMPL_RELEASE_INHERITED(TouchEvent, UIEvent) michael@0: michael@0: void michael@0: TouchEvent::InitTouchEvent(const nsAString& aType, michael@0: bool aCanBubble, michael@0: bool aCancelable, michael@0: nsIDOMWindow* aView, michael@0: int32_t aDetail, michael@0: bool aCtrlKey, michael@0: bool aAltKey, michael@0: bool aShiftKey, michael@0: bool aMetaKey, michael@0: TouchList* aTouches, michael@0: TouchList* aTargetTouches, michael@0: TouchList* aChangedTouches, michael@0: ErrorResult& aRv) michael@0: { michael@0: aRv = UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail); michael@0: if (aRv.Failed()) { michael@0: return; michael@0: } michael@0: michael@0: mEvent->AsInputEvent()->InitBasicModifiers(aCtrlKey, aAltKey, michael@0: aShiftKey, aMetaKey); michael@0: mTouches = aTouches; michael@0: mTargetTouches = aTargetTouches; michael@0: mChangedTouches = aChangedTouches; michael@0: } michael@0: michael@0: TouchList* michael@0: TouchEvent::Touches() michael@0: { michael@0: if (!mTouches) { michael@0: WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent(); michael@0: if (mEvent->message == NS_TOUCH_END || mEvent->message == NS_TOUCH_CANCEL) { michael@0: // for touchend events, remove any changed touches from the touches array michael@0: nsTArray< nsRefPtr > unchangedTouches; michael@0: const nsTArray< nsRefPtr >& touches = touchEvent->touches; michael@0: for (uint32_t i = 0; i < touches.Length(); ++i) { michael@0: if (!touches[i]->mChanged) { michael@0: unchangedTouches.AppendElement(touches[i]); michael@0: } michael@0: } michael@0: mTouches = new TouchList(ToSupports(this), unchangedTouches); michael@0: } else { michael@0: mTouches = new TouchList(ToSupports(this), touchEvent->touches); michael@0: } michael@0: } michael@0: return mTouches; michael@0: } michael@0: michael@0: TouchList* michael@0: TouchEvent::TargetTouches() michael@0: { michael@0: if (!mTargetTouches) { michael@0: nsTArray< nsRefPtr > targetTouches; michael@0: WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent(); michael@0: const nsTArray< nsRefPtr >& touches = touchEvent->touches; michael@0: for (uint32_t i = 0; i < touches.Length(); ++i) { michael@0: // for touchend/cancel events, don't append to the target list if this is a michael@0: // touch that is ending michael@0: if ((mEvent->message != NS_TOUCH_END && michael@0: mEvent->message != NS_TOUCH_CANCEL) || !touches[i]->mChanged) { michael@0: if (touches[i]->mTarget == mEvent->originalTarget) { michael@0: targetTouches.AppendElement(touches[i]); michael@0: } michael@0: } michael@0: } michael@0: mTargetTouches = new TouchList(ToSupports(this), targetTouches); michael@0: } michael@0: return mTargetTouches; michael@0: } michael@0: michael@0: TouchList* michael@0: TouchEvent::ChangedTouches() michael@0: { michael@0: if (!mChangedTouches) { michael@0: nsTArray< nsRefPtr > changedTouches; michael@0: WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent(); michael@0: const nsTArray< nsRefPtr >& touches = touchEvent->touches; michael@0: for (uint32_t i = 0; i < touches.Length(); ++i) { michael@0: if (touches[i]->mChanged) { michael@0: changedTouches.AppendElement(touches[i]); michael@0: } michael@0: } michael@0: mChangedTouches = new TouchList(ToSupports(this), changedTouches); michael@0: } michael@0: return mChangedTouches; michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: TouchEvent::PrefEnabled(JSContext* aCx, JSObject* aGlobal) michael@0: { michael@0: bool prefValue = false; michael@0: int32_t flag = 0; michael@0: if (NS_SUCCEEDED(Preferences::GetInt("dom.w3c_touch_events.enabled", michael@0: &flag))) { michael@0: if (flag == 2) { michael@0: #ifdef XP_WIN michael@0: static bool sDidCheckTouchDeviceSupport = false; michael@0: static bool sIsTouchDeviceSupportPresent = false; michael@0: // On Windows we auto-detect based on device support. michael@0: if (!sDidCheckTouchDeviceSupport) { michael@0: sDidCheckTouchDeviceSupport = true; michael@0: sIsTouchDeviceSupportPresent = widget::IsTouchDeviceSupportPresent(); michael@0: } michael@0: prefValue = sIsTouchDeviceSupportPresent; michael@0: #else michael@0: NS_WARNING("dom.w3c_touch_events.enabled=2 not implemented!"); michael@0: prefValue = false; michael@0: #endif michael@0: } else { michael@0: prefValue = !!flag; michael@0: } michael@0: } michael@0: if (prefValue) { michael@0: nsContentUtils::InitializeTouchEventTable(); michael@0: } michael@0: return prefValue; michael@0: } michael@0: michael@0: bool michael@0: TouchEvent::AltKey() michael@0: { michael@0: return mEvent->AsTouchEvent()->IsAlt(); michael@0: } michael@0: michael@0: bool michael@0: TouchEvent::MetaKey() michael@0: { michael@0: return mEvent->AsTouchEvent()->IsMeta(); michael@0: } michael@0: michael@0: bool michael@0: TouchEvent::CtrlKey() michael@0: { michael@0: return mEvent->AsTouchEvent()->IsControl(); michael@0: } michael@0: michael@0: bool michael@0: TouchEvent::ShiftKey() michael@0: { michael@0: return mEvent->AsTouchEvent()->IsShift(); michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: nsresult michael@0: NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult, michael@0: EventTarget* aOwner, michael@0: nsPresContext* aPresContext, michael@0: WidgetTouchEvent* aEvent) michael@0: { michael@0: TouchEvent* it = new TouchEvent(aOwner, aPresContext, aEvent); michael@0: NS_ADDREF(it); michael@0: *aInstancePtrResult = static_cast(it); michael@0: return NS_OK; michael@0: }