1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/Hal.h"
7 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
8 #include "mozilla/dom/ScreenBinding.h"
10 #include "nsIDocument.h"
11 #include "nsIDocShell.h"
12 #include "nsIDocument.h"
13 #include "nsPresContext.h"
15 #include "nsIDocShellTreeItem.h"
16 #include "nsLayoutUtils.h"
17 #include "nsJSUtils.h"
18 #include "nsDeviceContext.h"
20 using namespace mozilla
;
21 using namespace mozilla::dom
;
23 /* static */ already_AddRefed
<nsScreen
>
24 nsScreen::Create(nsPIDOMWindow
* aWindow
)
28 if (!aWindow
->GetDocShell()) {
32 nsCOMPtr
<nsIScriptGlobalObject
> sgo
=
33 do_QueryInterface(static_cast<nsPIDOMWindow
*>(aWindow
));
34 NS_ENSURE_TRUE(sgo
, nullptr);
36 nsRefPtr
<nsScreen
> screen
= new nsScreen(aWindow
);
38 hal::RegisterScreenConfigurationObserver(screen
);
39 hal::ScreenConfiguration config
;
40 hal::GetCurrentScreenConfiguration(&config
);
41 screen
->mOrientation
= config
.orientation();
43 return screen
.forget();
46 nsScreen::nsScreen(nsPIDOMWindow
* aWindow
)
47 : DOMEventTargetHelper(aWindow
)
48 , mEventListener(nullptr)
54 MOZ_ASSERT(!mEventListener
);
55 hal::UnregisterScreenConfigurationObserver(this);
59 // QueryInterface implementation for nsScreen
60 NS_INTERFACE_MAP_BEGIN(nsScreen
)
61 NS_INTERFACE_MAP_ENTRY(nsIDOMScreen
)
62 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
64 NS_IMPL_ADDREF_INHERITED(nsScreen
, DOMEventTargetHelper
)
65 NS_IMPL_RELEASE_INHERITED(nsScreen
, DOMEventTargetHelper
)
68 nsScreen::GetPixelDepth(ErrorResult
& aRv
)
70 nsDeviceContext
* context
= GetDeviceContext();
73 aRv
.Throw(NS_ERROR_FAILURE
);
78 context
->GetDepth(depth
);
82 #define FORWARD_LONG_GETTER(_name) \
84 nsScreen::Get ## _name(int32_t* aOut) \
87 *aOut = Get ## _name(rv); \
88 return rv.ErrorCode(); \
91 FORWARD_LONG_GETTER(AvailWidth
)
92 FORWARD_LONG_GETTER(AvailHeight
)
93 FORWARD_LONG_GETTER(Width
)
94 FORWARD_LONG_GETTER(Height
)
96 FORWARD_LONG_GETTER(Top
)
97 FORWARD_LONG_GETTER(Left
)
98 FORWARD_LONG_GETTER(AvailTop
)
99 FORWARD_LONG_GETTER(AvailLeft
)
101 FORWARD_LONG_GETTER(PixelDepth
)
102 FORWARD_LONG_GETTER(ColorDepth
)
105 nsScreen::GetDeviceContext()
107 return nsLayoutUtils::GetDeviceContextForScreenInfo(GetOwner());
111 nsScreen::GetRect(nsRect
& aRect
)
113 nsDeviceContext
*context
= GetDeviceContext();
116 return NS_ERROR_FAILURE
;
119 context
->GetRect(aRect
);
121 aRect
.x
= nsPresContext::AppUnitsToIntCSSPixels(aRect
.x
);
122 aRect
.y
= nsPresContext::AppUnitsToIntCSSPixels(aRect
.y
);
123 aRect
.height
= nsPresContext::AppUnitsToIntCSSPixels(aRect
.height
);
124 aRect
.width
= nsPresContext::AppUnitsToIntCSSPixels(aRect
.width
);
130 nsScreen::GetAvailRect(nsRect
& aRect
)
132 nsDeviceContext
*context
= GetDeviceContext();
135 return NS_ERROR_FAILURE
;
138 context
->GetClientRect(aRect
);
140 aRect
.x
= nsPresContext::AppUnitsToIntCSSPixels(aRect
.x
);
141 aRect
.y
= nsPresContext::AppUnitsToIntCSSPixels(aRect
.y
);
142 aRect
.height
= nsPresContext::AppUnitsToIntCSSPixels(aRect
.height
);
143 aRect
.width
= nsPresContext::AppUnitsToIntCSSPixels(aRect
.width
);
149 nsScreen::Notify(const hal::ScreenConfiguration
& aConfiguration
)
151 ScreenOrientation previousOrientation
= mOrientation
;
152 mOrientation
= aConfiguration
.orientation();
154 NS_ASSERTION(mOrientation
== eScreenOrientation_PortraitPrimary
||
155 mOrientation
== eScreenOrientation_PortraitSecondary
||
156 mOrientation
== eScreenOrientation_LandscapePrimary
||
157 mOrientation
== eScreenOrientation_LandscapeSecondary
,
158 "Invalid orientation value passed to notify method!");
160 if (mOrientation
!= previousOrientation
) {
161 DispatchTrustedEvent(NS_LITERAL_STRING("mozorientationchange"));
166 nsScreen::GetMozOrientation(nsString
& aOrientation
)
168 switch (mOrientation
) {
169 case eScreenOrientation_PortraitPrimary
:
170 aOrientation
.AssignLiteral("portrait-primary");
172 case eScreenOrientation_PortraitSecondary
:
173 aOrientation
.AssignLiteral("portrait-secondary");
175 case eScreenOrientation_LandscapePrimary
:
176 aOrientation
.AssignLiteral("landscape-primary");
178 case eScreenOrientation_LandscapeSecondary
:
179 aOrientation
.AssignLiteral("landscape-secondary");
181 case eScreenOrientation_None
:
183 MOZ_CRASH("Unacceptable mOrientation value");
188 nsScreen::GetSlowMozOrientation(nsAString
& aOrientation
)
190 nsString orientation
;
191 GetMozOrientation(orientation
);
192 aOrientation
= orientation
;
196 nsScreen::LockPermission
197 nsScreen::GetLockOrientationPermission() const
199 nsCOMPtr
<nsPIDOMWindow
> owner
= GetOwner();
204 // Chrome can always lock the screen orientation.
205 nsIDocShell
* docShell
= owner
->GetDocShell();
206 if (docShell
&& docShell
->ItemType() == nsIDocShellTreeItem::typeChrome
) {
210 nsCOMPtr
<nsIDocument
> doc
= owner
->GetDoc();
211 if (!doc
|| doc
->Hidden()) {
215 // Apps can always lock the screen orientation.
216 if (doc
->NodePrincipal()->GetAppStatus() >=
217 nsIPrincipal::APP_STATUS_INSTALLED
) {
221 // Other content must be full-screen in order to lock orientation.
222 return doc
->MozFullScreen() ? FULLSCREEN_LOCK_ALLOWED
: LOCK_DENIED
;
226 nsScreen::MozLockOrientation(const nsAString
& aOrientation
, ErrorResult
& aRv
)
228 nsString
orientation(aOrientation
);
229 Sequence
<nsString
> orientations
;
230 if (!orientations
.AppendElement(orientation
)) {
231 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
234 return MozLockOrientation(orientations
, aRv
);
238 nsScreen::MozLockOrientation(const Sequence
<nsString
>& aOrientations
,
241 ScreenOrientation orientation
= eScreenOrientation_None
;
243 for (uint32_t i
= 0; i
< aOrientations
.Length(); ++i
) {
244 const nsString
& item
= aOrientations
[i
];
246 if (item
.EqualsLiteral("portrait")) {
247 orientation
|= eScreenOrientation_PortraitPrimary
|
248 eScreenOrientation_PortraitSecondary
;
249 } else if (item
.EqualsLiteral("portrait-primary")) {
250 orientation
|= eScreenOrientation_PortraitPrimary
;
251 } else if (item
.EqualsLiteral("portrait-secondary")) {
252 orientation
|= eScreenOrientation_PortraitSecondary
;
253 } else if (item
.EqualsLiteral("landscape")) {
254 orientation
|= eScreenOrientation_LandscapePrimary
|
255 eScreenOrientation_LandscapeSecondary
;
256 } else if (item
.EqualsLiteral("landscape-primary")) {
257 orientation
|= eScreenOrientation_LandscapePrimary
;
258 } else if (item
.EqualsLiteral("landscape-secondary")) {
259 orientation
|= eScreenOrientation_LandscapeSecondary
;
260 } else if (item
.EqualsLiteral("default")) {
261 orientation
|= eScreenOrientation_Default
;
263 // If we don't recognize the token, we should just return 'false'
269 switch (GetLockOrientationPermission()) {
273 return hal::LockScreenOrientation(orientation
);
274 case FULLSCREEN_LOCK_ALLOWED
: {
275 // We need to register a listener so we learn when we leave full-screen
276 // and when we will have to unlock the screen.
277 // This needs to be done before LockScreenOrientation call to make sure
278 // the locking can be unlocked.
279 nsCOMPtr
<EventTarget
> target
= do_QueryInterface(GetOwner()->GetDoc());
284 if (!hal::LockScreenOrientation(orientation
)) {
288 // We are fullscreen and lock has been accepted.
289 if (!mEventListener
) {
290 mEventListener
= new FullScreenEventListener();
293 aRv
= target
->AddSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"),
294 mEventListener
, /* useCapture = */ true);
299 // This is only for compilers that don't understand that the previous switch
300 // will always return.
301 MOZ_CRASH("unexpected lock orientation permission value");
305 nsScreen::MozUnlockOrientation()
307 hal::UnlockScreenOrientation();
309 if (!mEventListener
) {
313 // Remove event listener in case of fullscreen lock.
314 nsCOMPtr
<EventTarget
> target
= do_QueryInterface(GetOwner()->GetDoc());
316 target
->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"),
317 mEventListener
, /* useCapture */ true);
320 mEventListener
= nullptr;
324 nsScreen::IsDeviceSizePageSize()
326 nsPIDOMWindow
* owner
= GetOwner();
328 nsIDocShell
* docShell
= owner
->GetDocShell();
330 return docShell
->GetDeviceSizeIsPageSize();
338 nsScreen::WrapObject(JSContext
* aCx
)
340 return ScreenBinding::Wrap(aCx
, this);
343 NS_IMPL_ISUPPORTS(nsScreen::FullScreenEventListener
, nsIDOMEventListener
)
346 nsScreen::FullScreenEventListener::HandleEvent(nsIDOMEvent
* aEvent
)
349 nsAutoString eventType
;
350 aEvent
->GetType(eventType
);
352 MOZ_ASSERT(eventType
.EqualsLiteral("mozfullscreenchange"));
355 nsCOMPtr
<EventTarget
> target
= aEvent
->InternalDOMEvent()->GetCurrentTarget();
358 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(target
);
361 // We have to make sure that the event we got is the event sent when
362 // fullscreen is disabled because we could get one when fullscreen
363 // got enabled if the lock call is done at the same moment.
364 if (doc
->MozFullScreen()) {
368 target
->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"),
371 hal::UnlockScreenOrientation();