Bumping manifests a=b2g-bump
[gecko.git] / dom / base / nsScreen.cpp
blob2dd4c5fe5f9f30bd7184f4df6c33f5a31e313f3f
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"
9 #include "nsScreen.h"
10 #include "nsIDocument.h"
11 #include "nsIDocShell.h"
12 #include "nsIDocument.h"
13 #include "nsPresContext.h"
14 #include "nsCOMPtr.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)
26 MOZ_ASSERT(aWindow);
28 if (!aWindow->GetDocShell()) {
29 return nullptr;
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)
52 nsScreen::~nsScreen()
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)
67 int32_t
68 nsScreen::GetPixelDepth(ErrorResult& aRv)
70 nsDeviceContext* context = GetDeviceContext();
72 if (!context) {
73 aRv.Throw(NS_ERROR_FAILURE);
74 return -1;
77 uint32_t depth;
78 context->GetDepth(depth);
79 return depth;
82 #define FORWARD_LONG_GETTER(_name) \
83 NS_IMETHODIMP \
84 nsScreen::Get ## _name(int32_t* aOut) \
85 { \
86 ErrorResult rv; \
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)
104 nsDeviceContext*
105 nsScreen::GetDeviceContext()
107 return nsLayoutUtils::GetDeviceContextForScreenInfo(GetOwner());
110 nsresult
111 nsScreen::GetRect(nsRect& aRect)
113 nsDeviceContext *context = GetDeviceContext();
115 if (!context) {
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);
126 return NS_OK;
129 nsresult
130 nsScreen::GetAvailRect(nsRect& aRect)
132 nsDeviceContext *context = GetDeviceContext();
134 if (!context) {
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);
145 return NS_OK;
148 void
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"));
165 void
166 nsScreen::GetMozOrientation(nsString& aOrientation)
168 switch (mOrientation) {
169 case eScreenOrientation_PortraitPrimary:
170 aOrientation.AssignLiteral("portrait-primary");
171 break;
172 case eScreenOrientation_PortraitSecondary:
173 aOrientation.AssignLiteral("portrait-secondary");
174 break;
175 case eScreenOrientation_LandscapePrimary:
176 aOrientation.AssignLiteral("landscape-primary");
177 break;
178 case eScreenOrientation_LandscapeSecondary:
179 aOrientation.AssignLiteral("landscape-secondary");
180 break;
181 case eScreenOrientation_None:
182 default:
183 MOZ_CRASH("Unacceptable mOrientation value");
187 NS_IMETHODIMP
188 nsScreen::GetSlowMozOrientation(nsAString& aOrientation)
190 nsString orientation;
191 GetMozOrientation(orientation);
192 aOrientation = orientation;
193 return NS_OK;
196 nsScreen::LockPermission
197 nsScreen::GetLockOrientationPermission() const
199 nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
200 if (!owner) {
201 return LOCK_DENIED;
204 // Chrome can always lock the screen orientation.
205 nsIDocShell* docShell = owner->GetDocShell();
206 if (docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome) {
207 return LOCK_ALLOWED;
210 nsCOMPtr<nsIDocument> doc = owner->GetDoc();
211 if (!doc || doc->Hidden()) {
212 return LOCK_DENIED;
215 // Apps can always lock the screen orientation.
216 if (doc->NodePrincipal()->GetAppStatus() >=
217 nsIPrincipal::APP_STATUS_INSTALLED) {
218 return LOCK_ALLOWED;
221 // Other content must be full-screen in order to lock orientation.
222 return doc->MozFullScreen() ? FULLSCREEN_LOCK_ALLOWED : LOCK_DENIED;
225 bool
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);
232 return false;
234 return MozLockOrientation(orientations, aRv);
237 bool
238 nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
239 ErrorResult& aRv)
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;
262 } else {
263 // If we don't recognize the token, we should just return 'false'
264 // without throwing.
265 return false;
269 switch (GetLockOrientationPermission()) {
270 case LOCK_DENIED:
271 return false;
272 case LOCK_ALLOWED:
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());
280 if (!target) {
281 return false;
284 if (!hal::LockScreenOrientation(orientation)) {
285 return false;
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);
295 return 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");
304 void
305 nsScreen::MozUnlockOrientation()
307 hal::UnlockScreenOrientation();
310 bool
311 nsScreen::IsDeviceSizePageSize()
313 nsPIDOMWindow* owner = GetOwner();
314 if (owner) {
315 nsIDocShell* docShell = owner->GetDocShell();
316 if (docShell) {
317 return docShell->GetDeviceSizeIsPageSize();
320 return false;
323 /* virtual */
324 JSObject*
325 nsScreen::WrapObject(JSContext* aCx)
327 return ScreenBinding::Wrap(aCx, this);
330 NS_IMPL_ISUPPORTS(nsScreen::FullScreenEventListener, nsIDOMEventListener)
332 NS_IMETHODIMP
333 nsScreen::FullScreenEventListener::HandleEvent(nsIDOMEvent* aEvent)
335 #ifdef DEBUG
336 nsAutoString eventType;
337 aEvent->GetType(eventType);
339 MOZ_ASSERT(eventType.EqualsLiteral("mozfullscreenchange"));
340 #endif
342 nsCOMPtr<EventTarget> target = aEvent->InternalDOMEvent()->GetCurrentTarget();
343 MOZ_ASSERT(target);
345 nsCOMPtr<nsIDocument> doc = do_QueryInterface(target);
346 MOZ_ASSERT(doc);
348 // We have to make sure that the event we got is the event sent when
349 // fullscreen is disabled because we could get one when fullscreen
350 // got enabled if the lock call is done at the same moment.
351 if (doc->MozFullScreen()) {
352 return NS_OK;
355 target->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"),
356 this, true);
358 hal::UnlockScreenOrientation();
360 return NS_OK;