Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
16 #include "mozilla/DebugOnly.h"
18 #include <fcntl.h>
20 #include "android/log.h"
22 #include "mozilla/dom/TabParent.h"
23 #include "mozilla/Hal.h"
24 #include "mozilla/Preferences.h"
25 #include "mozilla/FileUtils.h"
26 #include "mozilla/ClearOnShutdown.h"
27 #include "Framebuffer.h"
28 #include "gfxContext.h"
29 #include "gfxPlatform.h"
30 #include "gfxUtils.h"
31 #include "GLContextProvider.h"
32 #include "GLContext.h"
33 #include "nsAutoPtr.h"
34 #include "nsAppShell.h"
35 #include "nsIdleService.h"
36 #include "nsScreenManagerGonk.h"
37 #include "nsTArray.h"
38 #include "nsWindow.h"
39 #include "nsIWidgetListener.h"
40 #include "cutils/properties.h"
41 #include "ClientLayerManager.h"
42 #include "BasicLayers.h"
43 #include "libdisplay/GonkDisplay.h"
44 #include "pixelflinger/format.h"
45 #include "mozilla/BasicEvents.h"
46 #include "mozilla/layers/APZCTreeManager.h"
47 #include "mozilla/layers/CompositorParent.h"
48 #include "ParentProcessController.h"
49 #include "nsThreadUtils.h"
50 #include "HwcComposer2D.h"
52 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
53 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args)
54 #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args)
56 #define IS_TOPLEVEL() (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)
58 using namespace mozilla;
59 using namespace mozilla::dom;
60 using namespace mozilla::hal;
61 using namespace mozilla::gl;
62 using namespace mozilla::layers;
63 using namespace mozilla::widget;
65 nsIntRect gScreenBounds;
66 static uint32_t sScreenRotation;
67 static uint32_t sPhysicalScreenRotation;
68 static nsIntRect sVirtualBounds;
70 static nsRefPtr<GLContext> sGLContext;
71 static nsTArray<nsWindow *> sTopWindows;
72 static nsWindow *gFocusedWindow = nullptr;
73 static bool sFramebufferOpen;
74 static bool sUsingOMTC;
75 static bool sUsingHwc;
76 static bool sScreenInitialized;
77 static nsRefPtr<gfxASurface> sOMTCSurface;
79 namespace {
81 static uint32_t
82 EffectiveScreenRotation()
83 {
84 return (sScreenRotation + sPhysicalScreenRotation) % (360 / 90);
85 }
87 class ScreenOnOffEvent : public nsRunnable {
88 public:
89 ScreenOnOffEvent(bool on)
90 : mIsOn(on)
91 {}
93 NS_IMETHOD Run() {
94 for (uint32_t i = 0; i < sTopWindows.Length(); i++) {
95 nsWindow *win = sTopWindows[i];
97 if (nsIWidgetListener* listener = win->GetWidgetListener()) {
98 listener->SizeModeChanged(mIsOn ? nsSizeMode_Fullscreen : nsSizeMode_Minimized);
99 }
100 }
102 // Notify observers that the screen state has just changed.
103 nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
104 if (observerService) {
105 observerService->NotifyObservers(
106 nullptr, "screen-state-changed",
107 mIsOn ? MOZ_UTF16("on") : MOZ_UTF16("off")
108 );
109 }
111 return NS_OK;
112 }
114 private:
115 bool mIsOn;
116 };
118 static StaticRefPtr<ScreenOnOffEvent> sScreenOnEvent;
119 static StaticRefPtr<ScreenOnOffEvent> sScreenOffEvent;
121 static void
122 displayEnabledCallback(bool enabled)
123 {
124 NS_DispatchToMainThread(enabled ? sScreenOnEvent : sScreenOffEvent);
125 }
127 } // anonymous namespace
129 nsWindow::nsWindow()
130 {
131 if (!sScreenInitialized) {
132 sScreenOnEvent = new ScreenOnOffEvent(true);
133 ClearOnShutdown(&sScreenOnEvent);
134 sScreenOffEvent = new ScreenOnOffEvent(false);
135 ClearOnShutdown(&sScreenOffEvent);
136 GetGonkDisplay()->OnEnabled(displayEnabledCallback);
138 nsIntSize screenSize;
139 bool gotFB = Framebuffer::GetSize(&screenSize);
140 if (!gotFB) {
141 NS_RUNTIMEABORT("Failed to get size from framebuffer, aborting...");
142 }
143 gScreenBounds = nsIntRect(nsIntPoint(0, 0), screenSize);
145 char propValue[PROPERTY_VALUE_MAX];
146 property_get("ro.sf.hwrotation", propValue, "0");
147 sPhysicalScreenRotation = atoi(propValue) / 90;
149 sVirtualBounds = gScreenBounds;
151 sScreenInitialized = true;
153 nsAppShell::NotifyScreenInitialized();
155 // This is a hack to force initialization of the compositor
156 // resources, if we're going to use omtc.
157 //
158 // NB: GetPlatform() will create the gfxPlatform, which wants
159 // to know the color depth, which asks our native window.
160 // This has to happen after other init has finished.
161 gfxPlatform::GetPlatform();
162 sUsingOMTC = ShouldUseOffMainThreadCompositing();
164 property_get("ro.display.colorfill", propValue, "0");
166 //Update sUsingHwc whenever layers.composer2d.enabled changes
167 Preferences::AddBoolVarCache(&sUsingHwc, "layers.composer2d.enabled");
169 if (sUsingOMTC) {
170 sOMTCSurface = new gfxImageSurface(gfxIntSize(1, 1),
171 gfxImageFormat::RGB24);
172 }
173 }
174 }
176 nsWindow::~nsWindow()
177 {
178 }
180 void
181 nsWindow::DoDraw(void)
182 {
183 if (!hal::GetScreenEnabled()) {
184 gDrawRequest = true;
185 return;
186 }
188 if (sTopWindows.IsEmpty()) {
189 LOG(" no window to draw, bailing");
190 return;
191 }
193 nsWindow *targetWindow = (nsWindow *)sTopWindows[0];
194 while (targetWindow->GetLastChild())
195 targetWindow = (nsWindow *)targetWindow->GetLastChild();
197 nsIWidgetListener* listener = targetWindow->GetWidgetListener();
198 if (listener) {
199 listener->WillPaintWindow(targetWindow);
200 }
202 LayerManager* lm = targetWindow->GetLayerManager();
203 if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) {
204 // No need to do anything, the compositor will handle drawing
205 } else if (mozilla::layers::LayersBackend::LAYERS_BASIC == lm->GetBackendType()) {
206 MOZ_ASSERT(sFramebufferOpen || sUsingOMTC);
207 nsRefPtr<gfxASurface> targetSurface;
209 if(sUsingOMTC)
210 targetSurface = sOMTCSurface;
211 else
212 targetSurface = Framebuffer::BackBuffer();
214 {
215 nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
216 gfxUtils::PathFromRegion(ctx, sVirtualBounds);
217 ctx->Clip();
219 // No double-buffering needed.
220 AutoLayerManagerSetup setupLayerManager(
221 targetWindow, ctx, mozilla::layers::BufferMode::BUFFER_NONE,
222 ScreenRotation(EffectiveScreenRotation()));
224 listener = targetWindow->GetWidgetListener();
225 if (listener) {
226 listener->PaintWindow(targetWindow, sVirtualBounds);
227 }
228 }
230 if (!sUsingOMTC) {
231 targetSurface->Flush();
232 Framebuffer::Present(sVirtualBounds);
233 }
234 } else {
235 NS_RUNTIMEABORT("Unexpected layer manager type");
236 }
238 listener = targetWindow->GetWidgetListener();
239 if (listener) {
240 listener->DidPaintWindow();
241 }
242 }
244 nsEventStatus
245 nsWindow::DispatchInputEvent(WidgetGUIEvent& aEvent, bool* aWasCaptured)
246 {
247 if (aWasCaptured) {
248 *aWasCaptured = false;
249 }
250 if (!gFocusedWindow) {
251 return nsEventStatus_eIgnore;
252 }
254 gFocusedWindow->UserActivity();
256 aEvent.widget = gFocusedWindow;
258 if (TabParent* capturer = TabParent::GetEventCapturer()) {
259 bool captured = capturer->TryCapture(aEvent);
260 if (aWasCaptured) {
261 *aWasCaptured = captured;
262 }
263 if (captured) {
264 return nsEventStatus_eConsumeNoDefault;
265 }
266 }
268 nsEventStatus status;
269 gFocusedWindow->DispatchEvent(&aEvent, status);
270 return status;
271 }
273 NS_IMETHODIMP
274 nsWindow::Create(nsIWidget *aParent,
275 void *aNativeParent,
276 const nsIntRect &aRect,
277 nsDeviceContext *aContext,
278 nsWidgetInitData *aInitData)
279 {
280 BaseCreate(aParent, IS_TOPLEVEL() ? sVirtualBounds : aRect,
281 aContext, aInitData);
283 mBounds = aRect;
285 mParent = (nsWindow *)aParent;
286 mVisible = false;
288 if (!aParent) {
289 mBounds = sVirtualBounds;
290 }
292 if (!IS_TOPLEVEL())
293 return NS_OK;
295 sTopWindows.AppendElement(this);
297 Resize(0, 0, sVirtualBounds.width, sVirtualBounds.height, false);
298 return NS_OK;
299 }
301 NS_IMETHODIMP
302 nsWindow::Destroy(void)
303 {
304 mOnDestroyCalled = true;
305 sTopWindows.RemoveElement(this);
306 if (this == gFocusedWindow)
307 gFocusedWindow = nullptr;
308 nsBaseWidget::OnDestroy();
309 return NS_OK;
310 }
312 NS_IMETHODIMP
313 nsWindow::Show(bool aState)
314 {
315 if (mWindowType == eWindowType_invisible)
316 return NS_OK;
318 if (mVisible == aState)
319 return NS_OK;
321 mVisible = aState;
322 if (!IS_TOPLEVEL())
323 return mParent ? mParent->Show(aState) : NS_OK;
325 if (aState) {
326 BringToTop();
327 } else {
328 for (unsigned int i = 0; i < sTopWindows.Length(); i++) {
329 nsWindow *win = sTopWindows[i];
330 if (!win->mVisible)
331 continue;
333 win->BringToTop();
334 break;
335 }
336 }
338 return NS_OK;
339 }
341 bool
342 nsWindow::IsVisible() const
343 {
344 return mVisible;
345 }
347 NS_IMETHODIMP
348 nsWindow::ConstrainPosition(bool aAllowSlop,
349 int32_t *aX,
350 int32_t *aY)
351 {
352 return NS_OK;
353 }
355 NS_IMETHODIMP
356 nsWindow::Move(double aX,
357 double aY)
358 {
359 return NS_OK;
360 }
362 NS_IMETHODIMP
363 nsWindow::Resize(double aWidth,
364 double aHeight,
365 bool aRepaint)
366 {
367 return Resize(0, 0, aWidth, aHeight, aRepaint);
368 }
370 NS_IMETHODIMP
371 nsWindow::Resize(double aX,
372 double aY,
373 double aWidth,
374 double aHeight,
375 bool aRepaint)
376 {
377 mBounds = nsIntRect(NSToIntRound(aX), NSToIntRound(aY),
378 NSToIntRound(aWidth), NSToIntRound(aHeight));
379 if (mWidgetListener)
380 mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
382 if (aRepaint)
383 Invalidate(sVirtualBounds);
385 return NS_OK;
386 }
388 NS_IMETHODIMP
389 nsWindow::Enable(bool aState)
390 {
391 return NS_OK;
392 }
394 bool
395 nsWindow::IsEnabled() const
396 {
397 return true;
398 }
400 NS_IMETHODIMP
401 nsWindow::SetFocus(bool aRaise)
402 {
403 if (aRaise)
404 BringToTop();
406 gFocusedWindow = this;
407 return NS_OK;
408 }
410 NS_IMETHODIMP
411 nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>&)
412 {
413 return NS_OK;
414 }
416 NS_IMETHODIMP
417 nsWindow::Invalidate(const nsIntRect &aRect)
418 {
419 nsWindow *top = mParent;
420 while (top && top->mParent)
421 top = top->mParent;
422 if (top != sTopWindows[0] && this != sTopWindows[0])
423 return NS_OK;
425 gDrawRequest = true;
426 mozilla::NotifyEvent();
427 return NS_OK;
428 }
430 nsIntPoint
431 nsWindow::WidgetToScreenOffset()
432 {
433 nsIntPoint p(0, 0);
434 nsWindow *w = this;
436 while (w && w->mParent) {
437 p.x += w->mBounds.x;
438 p.y += w->mBounds.y;
440 w = w->mParent;
441 }
443 return p;
444 }
446 void*
447 nsWindow::GetNativeData(uint32_t aDataType)
448 {
449 switch (aDataType) {
450 case NS_NATIVE_WINDOW:
451 return GetGonkDisplay()->GetNativeWindow();
452 }
453 return nullptr;
454 }
456 NS_IMETHODIMP
457 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
458 {
459 if (mWidgetListener)
460 aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
461 return NS_OK;
462 }
464 NS_IMETHODIMP_(void)
465 nsWindow::SetInputContext(const InputContext& aContext,
466 const InputContextAction& aAction)
467 {
468 mInputContext = aContext;
469 }
471 NS_IMETHODIMP_(InputContext)
472 nsWindow::GetInputContext()
473 {
474 // There is only one IME context on Gonk.
475 mInputContext.mNativeIMEContext = nullptr;
476 return mInputContext;
477 }
479 NS_IMETHODIMP
480 nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
481 {
482 return NS_OK;
483 }
485 NS_IMETHODIMP
486 nsWindow::MakeFullScreen(bool aFullScreen)
487 {
488 if (mWindowType != eWindowType_toplevel) {
489 // Ignore fullscreen request for non-toplevel windows.
490 NS_WARNING("MakeFullScreen() on a dialog or child widget?");
491 return nsBaseWidget::MakeFullScreen(aFullScreen);
492 }
494 if (aFullScreen) {
495 // Fullscreen is "sticky" for toplevel widgets on gonk: we
496 // must paint the entire screen, and should only have one
497 // toplevel widget, so it doesn't make sense to ever "exit"
498 // fullscreen. If we do, we can leave parts of the screen
499 // unpainted.
500 Resize(sVirtualBounds.x, sVirtualBounds.y,
501 sVirtualBounds.width, sVirtualBounds.height,
502 /*repaint*/true);
503 }
504 return NS_OK;
505 }
507 float
508 nsWindow::GetDPI()
509 {
510 return GetGonkDisplay()->xdpi;
511 }
513 double
514 nsWindow::GetDefaultScaleInternal()
515 {
516 float dpi = GetDPI();
517 // The mean pixel density for mdpi devices is 160dpi, 240dpi for hdpi,
518 // and 320dpi for xhdpi, respectively.
519 // We'll take the mid-value between these three numbers as the boundary.
520 if (dpi < 200.0) {
521 return 1.0; // mdpi devices.
522 }
523 if (dpi < 300.0) {
524 return 1.5; // hdpi devices.
525 }
526 // xhdpi devices and beyond.
527 return floor(dpi / 150.0 + 0.5);
528 }
530 LayerManager *
531 nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
532 LayersBackend aBackendHint,
533 LayerManagerPersistence aPersistence,
534 bool* aAllowRetaining)
535 {
536 if (aAllowRetaining)
537 *aAllowRetaining = true;
538 if (mLayerManager) {
539 // This layer manager might be used for painting outside of DoDraw(), so we need
540 // to set the correct rotation on it.
541 if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
542 BasicLayerManager* manager =
543 static_cast<BasicLayerManager*>(mLayerManager.get());
544 manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE,
545 ScreenRotation(EffectiveScreenRotation()));
546 } else if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
547 ClientLayerManager* manager =
548 static_cast<ClientLayerManager*>(mLayerManager.get());
549 manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE,
550 ScreenRotation(EffectiveScreenRotation()));
551 }
552 return mLayerManager;
553 }
555 // Set mUseLayersAcceleration here to make it consistent with
556 // nsBaseWidget::GetLayerManager
557 mUseLayersAcceleration = ComputeShouldAccelerate(mUseLayersAcceleration);
558 nsWindow *topWindow = sTopWindows[0];
560 if (!topWindow) {
561 LOGW(" -- no topwindow\n");
562 return nullptr;
563 }
565 if (sUsingOMTC) {
566 CreateCompositor();
567 if (mCompositorParent) {
568 uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
569 CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController());
570 CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI());
571 }
572 if (mLayerManager)
573 return mLayerManager;
574 }
576 if (mUseLayersAcceleration) {
577 DebugOnly<nsIntRect> fbBounds = gScreenBounds;
578 if (!sGLContext) {
579 sGLContext = GLContextProvider::CreateForWindow(this);
580 }
582 MOZ_ASSERT(fbBounds.value == gScreenBounds);
583 }
585 // Fall back to software rendering.
586 sFramebufferOpen = Framebuffer::Open();
587 if (sFramebufferOpen) {
588 LOG("Falling back to framebuffer software rendering");
589 } else {
590 LOGE("Failed to mmap fb(?!?), aborting ...");
591 NS_RUNTIMEABORT("Can't open GL context and can't fall back on /dev/graphics/fb0 ...");
592 }
594 mLayerManager = new ClientLayerManager(this);
595 mUseLayersAcceleration = false;
597 return mLayerManager;
598 }
600 gfxASurface *
601 nsWindow::GetThebesSurface()
602 {
603 /* This is really a dummy surface; this is only used when doing reflow, because
604 * we need a RenderingContext to measure text against.
605 */
607 // XXX this really wants to return already_AddRefed, but this only really gets used
608 // on direct assignment to a gfxASurface
609 return new gfxImageSurface(gfxIntSize(5,5), gfxImageFormat::RGB24);
610 }
612 void
613 nsWindow::BringToTop()
614 {
615 if (!sTopWindows.IsEmpty()) {
616 if (nsIWidgetListener* listener = sTopWindows[0]->GetWidgetListener())
617 listener->WindowDeactivated();
618 }
620 sTopWindows.RemoveElement(this);
621 sTopWindows.InsertElementAt(0, this);
623 if (mWidgetListener)
624 mWidgetListener->WindowActivated();
625 Invalidate(sVirtualBounds);
626 }
628 void
629 nsWindow::UserActivity()
630 {
631 if (!mIdleService) {
632 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
633 }
635 if (mIdleService) {
636 mIdleService->ResetIdleTimeOut(0);
637 }
638 }
640 uint32_t
641 nsWindow::GetGLFrameBufferFormat()
642 {
643 if (mLayerManager &&
644 mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) {
645 // We directly map the hardware fb on Gonk. The hardware fb
646 // has RGB format.
647 return LOCAL_GL_RGB;
648 }
649 return LOCAL_GL_NONE;
650 }
652 nsIntRect
653 nsWindow::GetNaturalBounds()
654 {
655 return gScreenBounds;
656 }
658 bool
659 nsWindow::NeedsPaint()
660 {
661 if (!mLayerManager) {
662 return false;
663 }
664 return nsIWidget::NeedsPaint();
665 }
667 Composer2D*
668 nsWindow::GetComposer2D()
669 {
670 if (!sUsingHwc) {
671 return nullptr;
672 }
674 if (HwcComposer2D* hwc = HwcComposer2D::GetInstance()) {
675 return hwc->Initialized() ? hwc : nullptr;
676 }
678 return nullptr;
679 }
681 // nsScreenGonk.cpp
683 nsScreenGonk::nsScreenGonk(void *nativeScreen)
684 {
685 }
687 nsScreenGonk::~nsScreenGonk()
688 {
689 }
691 NS_IMETHODIMP
692 nsScreenGonk::GetRect(int32_t *outLeft, int32_t *outTop,
693 int32_t *outWidth, int32_t *outHeight)
694 {
695 *outLeft = sVirtualBounds.x;
696 *outTop = sVirtualBounds.y;
698 *outWidth = sVirtualBounds.width;
699 *outHeight = sVirtualBounds.height;
701 return NS_OK;
702 }
704 NS_IMETHODIMP
705 nsScreenGonk::GetAvailRect(int32_t *outLeft, int32_t *outTop,
706 int32_t *outWidth, int32_t *outHeight)
707 {
708 return GetRect(outLeft, outTop, outWidth, outHeight);
709 }
711 static uint32_t
712 ColorDepth()
713 {
714 switch (GetGonkDisplay()->surfaceformat) {
715 case GGL_PIXEL_FORMAT_RGB_565:
716 return 16;
717 case GGL_PIXEL_FORMAT_RGBA_8888:
718 return 32;
719 }
720 return 24; // GGL_PIXEL_FORMAT_RGBX_8888
721 }
723 NS_IMETHODIMP
724 nsScreenGonk::GetPixelDepth(int32_t *aPixelDepth)
725 {
726 // XXX: this should actually return 32 when we're using 24-bit
727 // color, because we use RGBX.
728 *aPixelDepth = ColorDepth();
729 return NS_OK;
730 }
732 NS_IMETHODIMP
733 nsScreenGonk::GetColorDepth(int32_t *aColorDepth)
734 {
735 return GetPixelDepth(aColorDepth);
736 }
738 NS_IMETHODIMP
739 nsScreenGonk::GetRotation(uint32_t* aRotation)
740 {
741 *aRotation = sScreenRotation;
742 return NS_OK;
743 }
745 NS_IMETHODIMP
746 nsScreenGonk::SetRotation(uint32_t aRotation)
747 {
748 if (!(aRotation <= ROTATION_270_DEG))
749 return NS_ERROR_ILLEGAL_VALUE;
751 if (sScreenRotation == aRotation)
752 return NS_OK;
754 sScreenRotation = aRotation;
755 uint32_t rotation = EffectiveScreenRotation();
756 if (rotation == nsIScreen::ROTATION_90_DEG ||
757 rotation == nsIScreen::ROTATION_270_DEG) {
758 sVirtualBounds = nsIntRect(0, 0, gScreenBounds.height,
759 gScreenBounds.width);
760 } else {
761 sVirtualBounds = gScreenBounds;
762 }
764 nsAppShell::NotifyScreenRotation();
766 for (unsigned int i = 0; i < sTopWindows.Length(); i++)
767 sTopWindows[i]->Resize(sVirtualBounds.width,
768 sVirtualBounds.height,
769 true);
771 return NS_OK;
772 }
774 // NB: This isn't gonk-specific, but gonk is the only widget backend
775 // that does this calculation itself, currently.
776 static ScreenOrientation
777 ComputeOrientation(uint32_t aRotation, const nsIntSize& aScreenSize)
778 {
779 bool naturallyPortrait = (aScreenSize.height > aScreenSize.width);
780 switch (aRotation) {
781 case nsIScreen::ROTATION_0_DEG:
782 return (naturallyPortrait ? eScreenOrientation_PortraitPrimary :
783 eScreenOrientation_LandscapePrimary);
784 case nsIScreen::ROTATION_90_DEG:
785 // Arbitrarily choosing 90deg to be primary "unnatural"
786 // rotation.
787 return (naturallyPortrait ? eScreenOrientation_LandscapePrimary :
788 eScreenOrientation_PortraitPrimary);
789 case nsIScreen::ROTATION_180_DEG:
790 return (naturallyPortrait ? eScreenOrientation_PortraitSecondary :
791 eScreenOrientation_LandscapeSecondary);
792 case nsIScreen::ROTATION_270_DEG:
793 return (naturallyPortrait ? eScreenOrientation_LandscapeSecondary :
794 eScreenOrientation_PortraitSecondary);
795 default:
796 MOZ_CRASH("Gonk screen must always have a known rotation");
797 }
798 }
800 /*static*/ uint32_t
801 nsScreenGonk::GetRotation()
802 {
803 return sScreenRotation;
804 }
806 /*static*/ ScreenConfiguration
807 nsScreenGonk::GetConfiguration()
808 {
809 ScreenOrientation orientation = ComputeOrientation(sScreenRotation,
810 gScreenBounds.Size());
811 uint32_t colorDepth = ColorDepth();
812 // NB: perpetuating colorDepth == pixelDepth illusion here, for
813 // consistency.
814 return ScreenConfiguration(sVirtualBounds, orientation,
815 colorDepth, colorDepth);
816 }
818 NS_IMPL_ISUPPORTS(nsScreenManagerGonk, nsIScreenManager)
820 nsScreenManagerGonk::nsScreenManagerGonk()
821 {
822 mOneScreen = new nsScreenGonk(nullptr);
823 }
825 nsScreenManagerGonk::~nsScreenManagerGonk()
826 {
827 }
829 NS_IMETHODIMP
830 nsScreenManagerGonk::GetPrimaryScreen(nsIScreen **outScreen)
831 {
832 NS_IF_ADDREF(*outScreen = mOneScreen.get());
833 return NS_OK;
834 }
836 NS_IMETHODIMP
837 nsScreenManagerGonk::ScreenForRect(int32_t inLeft,
838 int32_t inTop,
839 int32_t inWidth,
840 int32_t inHeight,
841 nsIScreen **outScreen)
842 {
843 return GetPrimaryScreen(outScreen);
844 }
846 NS_IMETHODIMP
847 nsScreenManagerGonk::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen)
848 {
849 return GetPrimaryScreen(outScreen);
850 }
852 NS_IMETHODIMP
853 nsScreenManagerGonk::GetNumberOfScreens(uint32_t *aNumberOfScreens)
854 {
855 *aNumberOfScreens = 1;
856 return NS_OK;
857 }
859 NS_IMETHODIMP
860 nsScreenManagerGonk::GetSystemDefaultScale(float *aDefaultScale)
861 {
862 *aDefaultScale = 1.0f;
863 return NS_OK;
864 }