From 1799f33cbcc8de690b6ae33d2a87a4f2cc034ab9 Mon Sep 17 00:00:00 2001 From: William Chen Date: Fri, 23 Oct 2015 21:37:28 -0700 Subject: [PATCH] Bug 920734 - Part 1: Implement window.orientation and window.onorientationchange. r=baku --- dom/base/WindowOrientationObserver.cpp | 55 ++++++++++++++++++++++ dom/base/WindowOrientationObserver.h | 35 ++++++++++++++ dom/base/moz.build | 2 + dom/base/nsGkAtomList.h | 1 + dom/base/nsGlobalWindow.cpp | 41 ++++++++++++++++ dom/base/nsGlobalWindow.h | 16 +++++++ dom/base/nsPIDOMWindow.h | 5 ++ dom/base/test/mochitest.ini | 2 + dom/base/test/test_window_orientation.html | 33 +++++++++++++ dom/events/EventListenerManager.cpp | 17 +++++++ dom/events/EventNameList.h | 6 +++ dom/webidl/Window.webidl | 8 ++++ widget/EventMessageList.h | 3 ++ 13 files changed, 224 insertions(+) create mode 100644 dom/base/WindowOrientationObserver.cpp create mode 100644 dom/base/WindowOrientationObserver.h create mode 100644 dom/base/test/test_window_orientation.html diff --git a/dom/base/WindowOrientationObserver.cpp b/dom/base/WindowOrientationObserver.cpp new file mode 100644 index 0000000000000..d7ce628448e7b --- /dev/null +++ b/dom/base/WindowOrientationObserver.cpp @@ -0,0 +1,55 @@ +/* -*- 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 "WindowOrientationObserver.h" + +#include "nsGlobalWindow.h" +#include "mozilla/Hal.h" + +/** + * This class is used by nsGlobalWindow to implement window.orientation + * and window.onorientationchange. This class is defined in its own file + * because Hal.h pulls in windows.h and can't be included from + * nsGlobalWindow.cpp + */ +WindowOrientationObserver::WindowOrientationObserver( + nsGlobalWindow* aGlobalWindow) + : mWindow(aGlobalWindow) +{ + MOZ_ASSERT(aGlobalWindow && aGlobalWindow->IsInnerWindow()); + hal::RegisterScreenConfigurationObserver(this); + + hal::ScreenConfiguration config; + hal::GetCurrentScreenConfiguration(&config); + mAngle = config.angle(); +} + +WindowOrientationObserver::~WindowOrientationObserver() +{ + hal::UnregisterScreenConfigurationObserver(this); +} + +void +WindowOrientationObserver::Notify( + const mozilla::hal::ScreenConfiguration& aConfiguration) +{ + uint16_t currentAngle = aConfiguration.angle(); + if (mAngle != currentAngle && mWindow->IsCurrentInnerWindow()) { + mAngle = currentAngle; + mWindow->GetOuterWindow()->DispatchCustomEvent(NS_LITERAL_STRING("orientationchange")); + } +} + +/* static */ int16_t +WindowOrientationObserver::OrientationAngle() +{ + hal::ScreenConfiguration config; + hal::GetCurrentScreenConfiguration(&config); + int16_t angle = static_cast(config.angle()); + // config.angle() returns 0, 90, 180 or 270. + // window.orientation returns -90, 0, 90 or 180. + return angle <= 180 ? angle : angle - 360; +} diff --git a/dom/base/WindowOrientationObserver.h b/dom/base/WindowOrientationObserver.h new file mode 100644 index 0000000000000..b544f202bae5d --- /dev/null +++ b/dom/base/WindowOrientationObserver.h @@ -0,0 +1,35 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_WindowOrientationObserver_h +#define mozilla_dom_WindowOrientationObserver_h + +#include "mozilla/HalScreenConfiguration.h" + +class nsGlobalWindow; + +namespace mozilla { +namespace dom { + +class WindowOrientationObserver final : + public mozilla::hal::ScreenConfigurationObserver +{ +public: + explicit WindowOrientationObserver(nsGlobalWindow* aGlobalWindow); + ~WindowOrientationObserver(); + void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration) override; + static int16_t OrientationAngle(); + +private: + // Weak pointer, instance is owned by mWindow. + nsGlobalWindow* MOZ_NON_OWNING_REF mWindow; + uint16_t mAngle; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_WindowOrientationObserver_h diff --git a/dom/base/moz.build b/dom/base/moz.build index aaac5f087bad4..d5f6edc857b24 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -209,6 +209,7 @@ EXPORTS.mozilla.dom += [ 'URL.h', 'URLSearchParams.h', 'WebSocket.h', + 'WindowOrientationObserver.h', ] UNIFIED_SOURCES += [ @@ -355,6 +356,7 @@ UNIFIED_SOURCES += [ 'URLSearchParams.cpp', 'WebSocket.cpp', 'WindowNamedPropertiesHandler.cpp', + 'WindowOrientationObserver.cpp', ] if CONFIG['MOZ_WEBRTC']: diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 8f5febab1e9d8..5ebbdc26ec7cf 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -847,6 +847,7 @@ GK_ATOM(onobsolete, "onobsolete") GK_ATOM(ononline, "ononline") GK_ATOM(onoffline, "onoffline") GK_ATOM(onopen, "onopen") +GK_ATOM(onorientationchange, "onorientationchange") GK_ATOM(onotastatuschange, "onotastatuschange") GK_ATOM(onoverflow, "onoverflow") GK_ATOM(onoverflowchanged, "onoverflowchanged") diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 53fea93f68259..fc271b304ac4c 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -20,6 +20,9 @@ #include "mozilla/dom/DOMStorage.h" #include "mozilla/dom/StorageEvent.h" #include "mozilla/dom/StorageEventBinding.h" +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) +#include "mozilla/dom/WindowOrientationObserver.h" +#endif #include "nsDOMOfflineResourceList.h" #include "nsError.h" #include "nsIIdleService.h" @@ -1527,6 +1530,10 @@ nsGlobalWindow::CleanUp() mSpeechSynthesis = nullptr; #endif +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + mOrientationChangeObserver = nullptr; +#endif + ClearControllers(); mOpener = nullptr; // Forces Release @@ -1641,6 +1648,10 @@ nsGlobalWindow::FreeInnerObjects() mScreen = nullptr; } +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + mOrientationChangeObserver = nullptr; +#endif + if (mDoc) { // Remember the document's principal and URI. mDocumentPrincipal = mDoc->NodePrincipal(); @@ -13654,6 +13665,27 @@ nsGlobalWindow::DisableDeviceSensor(uint32_t aType) } } +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) +void +nsGlobalWindow::EnableOrientationChangeListener() +{ + MOZ_ASSERT(IsInnerWindow()); + + if (!mOrientationChangeObserver) { + mOrientationChangeObserver = + new WindowOrientationObserver(this); + } +} + +void +nsGlobalWindow::DisableOrientationChangeListener() +{ + MOZ_ASSERT(IsInnerWindow()); + + mOrientationChangeObserver = nullptr; +} +#endif + void nsGlobalWindow::SetHasGamepadEventListener(bool aHasGamepad/* = true*/) { @@ -14501,6 +14533,15 @@ nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal) return xpc::WindowOrNull(aGlobal)->IsModalContentWindow(); } + +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) +int16_t +nsGlobalWindow::Orientation() const +{ + return WindowOrientationObserver::OrientationAngle(); +} +#endif + NS_IMETHODIMP nsGlobalWindow::GetConsole(JSContext* aCx, JS::MutableHandle aConsole) diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 41d617c17ea8a..80b6596282585 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -118,6 +118,9 @@ class RequestOrUSVString; class Selection; class SpeechSynthesis; class WakeLock; +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) +class WindowOrientationObserver; +#endif namespace cache { class CacheStorage; } // namespace cache @@ -656,6 +659,11 @@ class nsGlobalWindow : public mozilla::dom::EventTarget, virtual void EnableDeviceSensor(uint32_t aType) override; virtual void DisableDeviceSensor(uint32_t aType) override; +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + virtual void EnableOrientationChangeListener() override; + virtual void DisableOrientationChangeListener() override; +#endif + virtual void EnableTimeChangeNotifications() override; virtual void DisableTimeChangeNotifications() override; @@ -907,6 +915,10 @@ class nsGlobalWindow : public mozilla::dom::EventTarget, mozilla::dom::Navigator* GetNavigator(mozilla::ErrorResult& aError); nsIDOMOfflineResourceList* GetApplicationCache(mozilla::ErrorResult& aError); +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + int16_t Orientation() const; +#endif + mozilla::dom::Console* GetConsole(mozilla::ErrorResult& aRv); void GetSidebar(mozilla::dom::OwningExternalOrWindowProxy& aResult, @@ -1822,6 +1834,10 @@ class nsGlobalWindow : public mozilla::dom::EventTarget, nsTArray mEnabledSensors; +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + nsAutoPtr mOrientationChangeObserver; +#endif + #ifdef MOZ_WEBSPEECH // mSpeechSynthesis is only used on inner windows. RefPtr mSpeechSynthesis; diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index f17740967aa91..d40a85d74bc48 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -635,6 +635,11 @@ class nsPIDOMWindow : public nsIDOMWindowInternal */ virtual void DisableDeviceSensor(uint32_t aType) = 0; +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + virtual void EnableOrientationChangeListener() = 0; + virtual void DisableOrientationChangeListener() = 0; +#endif + virtual void EnableTimeChangeNotifications() = 0; virtual void DisableTimeChangeNotifications() = 0; diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 94fb3f2520916..eeda01a5608a9 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -359,6 +359,8 @@ skip-if = buildapp == 'mulet' [test_window_extensible.html] [test_window_indexing.html] [test_window_named_frame_enumeration.html] +[test_window_orientation.html] +skip-if = toolkit != 'gonk' [test_writable-replaceable.html] [test_navigatorPrefOverride.html] [test_EventSource_redirects.html] diff --git a/dom/base/test/test_window_orientation.html b/dom/base/test/test_window_orientation.html new file mode 100644 index 0000000000000..4921a95cd325a --- /dev/null +++ b/dom/base/test/test_window_orientation.html @@ -0,0 +1,33 @@ + + +Test for window.orientation + + + +
+ diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index f2e73cb844b68..ceb06b355707e 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -325,6 +325,10 @@ EventListenerManager::AddEventListenerInternal( EnableDevice(eDeviceLight); } else if (aTypeAtom == nsGkAtoms::ondevicemotion) { EnableDevice(eDeviceMotion); +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + } else if (aTypeAtom == nsGkAtoms::onorientationchange) { + EnableDevice(eOrientationChange); +#endif #ifdef MOZ_B2G } else if (aTypeAtom == nsGkAtoms::onmoztimechange) { nsCOMPtr window = GetTargetAsInnerWindow(); @@ -431,6 +435,9 @@ EventListenerManager::IsDeviceType(EventMessage aEventMessage) case eDeviceLight: case eDeviceProximity: case eUserProximity: +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + case eOrientationChange: +#endif return true; default: break; @@ -462,6 +469,11 @@ EventListenerManager::EnableDevice(EventMessage aEventMessage) window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION); window->EnableDeviceSensor(SENSOR_GYROSCOPE); break; +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + case eOrientationChange: + window->EnableOrientationChangeListener(); + break; +#endif default: NS_WARNING("Enabling an unknown device sensor."); break; @@ -492,6 +504,11 @@ EventListenerManager::DisableDevice(EventMessage aEventMessage) case eDeviceLight: window->DisableDeviceSensor(SENSOR_LIGHT); break; +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) + case eOrientationChange: + window->DisableOrientationChangeListener(); + break; +#endif default: NS_WARNING("Disabling an unknown device sensor."); break; diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 9de9673d3d610..f047b1b3d94e3 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -507,6 +507,12 @@ WINDOW_EVENT(online, eOnline, EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly, eBasicEventClass) +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) +WINDOW_EVENT(orientationchange, + eOrientationChange, + EventNameType_HTMLBodyOrFramesetOnly, + eBasicEventClass) +#endif WINDOW_EVENT(pagehide, ePageHide, EventNameType_HTMLBodyOrFramesetOnly, diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 348d00743b313..e6c4b693fd3ca 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -398,6 +398,14 @@ Window implements TouchEventHandlers; Window implements OnErrorEventHandlerForWindow; +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) +// https://compat.spec.whatwg.org/#windoworientation-interface +partial interface Window { + readonly attribute short orientation; + attribute EventHandler onorientationchange; +}; +#endif + // ConsoleAPI partial interface Window { [Replaceable, GetterThrows] diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 813675a8e3486..48e6c81e94ef2 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -342,6 +342,9 @@ NS_EVENT_MESSAGE(eDeviceMotion) NS_EVENT_MESSAGE(eDeviceProximity) NS_EVENT_MESSAGE(eUserProximity) NS_EVENT_MESSAGE(eDeviceLight) +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) +NS_EVENT_MESSAGE(eOrientationChange) +#endif NS_EVENT_MESSAGE(eShow)