1 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "android/log.h"
17 #include "GLContext.h"
20 #include "mozilla/MouseEvents.h"
21 #include "mozilla/TouchEvents.h"
22 #include "mozilla/Hal.h"
23 #include "libdisplay/BootAnimation.h"
24 #include "libdisplay/GonkDisplay.h"
25 #include "nsScreenManagerGonk.h"
26 #include "nsThreadUtils.h"
27 #include "HwcComposer2D.h"
28 #include "VsyncSource.h"
30 #include "mozilla/ClearOnShutdown.h"
31 #include "mozilla/layers/CompositorBridgeParent.h"
32 #include "mozilla/layers/CompositorThread.h"
33 #include "mozilla/Services.h"
34 #include "mozilla/ProcessPriorityManager.h"
35 #include "nsIdleService.h"
36 #include "nsIObserverService.h"
37 #include "nsAppShell.h"
38 #include "nsProxyRelease.h"
40 #include "pixelflinger/format.h"
41 #include "nsIDisplayInfo.h"
43 #if ANDROID_VERSION >= 17
44 #include "libdisplay/DisplaySurface.h"
47 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "nsScreenGonk" , ## args)
48 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "nsScreenGonk", ## args)
49 #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "nsScreenGonk", ## args)
51 using namespace mozilla
;
52 using namespace mozilla::hal
;
53 using namespace mozilla::gfx
;
54 using namespace mozilla::gl
;
55 using namespace mozilla::layers
;
56 using namespace mozilla::dom
;
60 class ScreenOnOffEvent
: public mozilla::Runnable
{
62 ScreenOnOffEvent(bool on
)
67 // Notify observers that the screen state has just changed.
68 nsCOMPtr
<nsIObserverService
> observerService
= mozilla::services::GetObserverService();
69 if (observerService
) {
70 observerService
->NotifyObservers(
71 nullptr, "screen-state-changed",
72 mIsOn
? MOZ_UTF16("on") : MOZ_UTF16("off")
76 RefPtr
<nsScreenGonk
> screen
= nsScreenManagerGonk::GetPrimaryScreen();
77 const nsTArray
<nsWindow
*>& windows
= screen
->GetTopWindows();
79 for (uint32_t i
= 0; i
< windows
.Length(); i
++) {
80 nsWindow
*win
= windows
[i
];
82 if (nsIWidgetListener
* listener
= win
->GetWidgetListener()) {
83 listener
->SizeModeChanged(mIsOn
? nsSizeMode_Fullscreen
: nsSizeMode_Minimized
);
95 displayEnabledCallback(bool enabled
)
97 RefPtr
<nsScreenManagerGonk
> screenManager
= nsScreenManagerGonk::GetInstance();
98 screenManager
->DisplayEnabled(enabled
);
104 SurfaceFormatToColorDepth(int32_t aSurfaceFormat
)
106 switch (aSurfaceFormat
) {
107 case GGL_PIXEL_FORMAT_RGB_565
:
109 case GGL_PIXEL_FORMAT_RGBA_8888
:
112 return 24; // GGL_PIXEL_FORMAT_RGBX_8888
117 nsScreenGonk::nsScreenGonk(uint32_t aId
,
118 GonkDisplay::DisplayType aDisplayType
,
119 const GonkDisplay::NativeData
& aNativeData
,
120 NotifyDisplayChangedEvent aEventVisibility
)
122 , mEventVisibility(aEventVisibility
)
123 , mNativeWindow(aNativeData
.mNativeWindow
)
124 , mDpi(aNativeData
.mXdpi
)
125 , mScreenRotation(nsIScreen::ROTATION_0_DEG
)
126 , mPhysicalScreenRotation(nsIScreen::ROTATION_0_DEG
)
127 #if ANDROID_VERSION >= 17
128 , mDisplaySurface(aNativeData
.mDisplaySurface
)
130 , mIsMirroring(false)
131 , mDisplayType(aDisplayType
)
132 , mEGLDisplay(EGL_NO_DISPLAY
)
133 , mEGLSurface(EGL_NO_SURFACE
)
134 , mGLContext(nullptr)
135 , mFramebuffer(nullptr)
136 , mMappedBuffer(nullptr)
138 if (mNativeWindow
->query(mNativeWindow
.get(), NATIVE_WINDOW_WIDTH
, &mVirtualBounds
.width
) ||
139 mNativeWindow
->query(mNativeWindow
.get(), NATIVE_WINDOW_HEIGHT
, &mVirtualBounds
.height
) ||
140 mNativeWindow
->query(mNativeWindow
.get(), NATIVE_WINDOW_FORMAT
, &mSurfaceFormat
)) {
141 NS_RUNTIMEABORT("Failed to get native window size, aborting...");
144 mNaturalBounds
= mVirtualBounds
;
146 if (IsPrimaryScreen()) {
147 char propValue
[PROPERTY_VALUE_MAX
];
148 property_get("ro.sf.hwrotation", propValue
, "0");
149 mPhysicalScreenRotation
= atoi(propValue
) / 90;
152 mColorDepth
= SurfaceFormatToColorDepth(mSurfaceFormat
);
156 ReleaseGLContextSync(mozilla::gl::GLContext
* aGLContext
) {
157 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
158 aGLContext
->Release();
161 nsScreenGonk::~nsScreenGonk()
163 // Release GLContext on compositor thread
165 CompositorThreadHolder::Loop()->PostTask(
166 NewRunnableFunction(&ReleaseGLContextSync
,
167 mGLContext
.forget().take()));
168 mGLContext
= nullptr;
173 nsScreenGonk::IsPrimaryScreen()
175 return mDisplayType
== GonkDisplay::DISPLAY_PRIMARY
;
179 nsScreenGonk::GetId(uint32_t *outId
)
186 nsScreenGonk::GetId()
191 NotifyDisplayChangedEvent
192 nsScreenGonk::GetEventVisibility()
194 return mEventVisibility
;
198 nsScreenGonk::GetRect(int32_t *outLeft
, int32_t *outTop
,
199 int32_t *outWidth
, int32_t *outHeight
)
201 *outLeft
= mVirtualBounds
.x
;
202 *outTop
= mVirtualBounds
.y
;
204 *outWidth
= mVirtualBounds
.width
;
205 *outHeight
= mVirtualBounds
.height
;
211 nsScreenGonk::GetRect()
213 return mVirtualBounds
;
217 nsScreenGonk::GetAvailRect(int32_t *outLeft
, int32_t *outTop
,
218 int32_t *outWidth
, int32_t *outHeight
)
220 return GetRect(outLeft
, outTop
, outWidth
, outHeight
);
224 nsScreenGonk::GetPixelDepth(int32_t *aPixelDepth
)
226 // XXX: this should actually return 32 when we're using 24-bit
227 // color, because we use RGBX.
228 *aPixelDepth
= mColorDepth
;
233 nsScreenGonk::GetColorDepth(int32_t *aColorDepth
)
235 *aColorDepth
= mColorDepth
;
240 nsScreenGonk::GetRotation(uint32_t* aRotation
)
242 *aRotation
= mScreenRotation
;
247 nsScreenGonk::GetDpi()
253 nsScreenGonk::GetSurfaceFormat()
255 return mSurfaceFormat
;
259 nsScreenGonk::GetNativeWindow()
261 return mNativeWindow
.get();
265 nsScreenGonk::SetRotation(uint32_t aRotation
)
267 if (!(aRotation
<= ROTATION_270_DEG
)) {
268 return NS_ERROR_ILLEGAL_VALUE
;
271 if (mScreenRotation
== aRotation
) {
275 mScreenRotation
= aRotation
;
276 uint32_t rotation
= EffectiveScreenRotation();
277 if (rotation
== nsIScreen::ROTATION_90_DEG
||
278 rotation
== nsIScreen::ROTATION_270_DEG
) {
279 mVirtualBounds
= LayoutDeviceIntRect(0, 0,
280 mNaturalBounds
.height
,
281 mNaturalBounds
.width
);
283 mVirtualBounds
= mNaturalBounds
;
286 nsAppShell::NotifyScreenRotation();
288 for (unsigned int i
= 0; i
< mTopWindows
.Length(); i
++) {
289 mTopWindows
[i
]->Resize(mVirtualBounds
.width
,
290 mVirtualBounds
.height
,
298 nsScreenGonk::GetNaturalBounds()
300 return mNaturalBounds
;
304 nsScreenGonk::EffectiveScreenRotation()
306 return (mScreenRotation
+ mPhysicalScreenRotation
) % (360 / 90);
309 // NB: This isn't gonk-specific, but gonk is the only widget backend
310 // that does this calculation itself, currently.
311 static ScreenOrientationInternal
312 ComputeOrientation(uint32_t aRotation
, const LayoutDeviceIntSize
& aScreenSize
)
314 bool naturallyPortrait
= (aScreenSize
.height
> aScreenSize
.width
);
316 case nsIScreen::ROTATION_0_DEG
:
317 return (naturallyPortrait
? eScreenOrientation_PortraitPrimary
:
318 eScreenOrientation_LandscapePrimary
);
319 case nsIScreen::ROTATION_90_DEG
:
320 // Arbitrarily choosing 90deg to be primary "unnatural"
322 return (naturallyPortrait
? eScreenOrientation_LandscapePrimary
:
323 eScreenOrientation_PortraitPrimary
);
324 case nsIScreen::ROTATION_180_DEG
:
325 return (naturallyPortrait
? eScreenOrientation_PortraitSecondary
:
326 eScreenOrientation_LandscapeSecondary
);
327 case nsIScreen::ROTATION_270_DEG
:
328 return (naturallyPortrait
? eScreenOrientation_LandscapeSecondary
:
329 eScreenOrientation_PortraitSecondary
);
331 MOZ_CRASH("Gonk screen must always have a known rotation");
336 RotationToAngle(uint32_t aRotation
)
338 uint16_t angle
= 90 * aRotation
;
339 MOZ_ASSERT(angle
== 0 || angle
== 90 || angle
== 180 || angle
== 270);
344 nsScreenGonk::GetConfiguration()
346 ScreenOrientationInternal orientation
=
347 ComputeOrientation(mScreenRotation
, mNaturalBounds
.Size());
349 // NB: perpetuating colorDepth == pixelDepth illusion here, for
351 return ScreenConfiguration(mVirtualBounds
.ToUnknownRect(), orientation
,
352 RotationToAngle(mScreenRotation
),
353 mColorDepth
, mColorDepth
);
357 nsScreenGonk::RegisterWindow(nsWindow
* aWindow
)
359 mTopWindows
.AppendElement(aWindow
);
363 nsScreenGonk::UnregisterWindow(nsWindow
* aWindow
)
365 mTopWindows
.RemoveElement(aWindow
);
369 nsScreenGonk::BringToTop(nsWindow
* aWindow
)
371 mTopWindows
.RemoveElement(aWindow
);
372 mTopWindows
.InsertElementAt(0, aWindow
);
375 static gralloc_module_t
const*
378 hw_module_t
const *module
;
379 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID
, &module
)) {
382 return reinterpret_cast<gralloc_module_t
const*>(module
);
386 HalFormatToSurfaceFormat(int aHalFormat
)
388 switch (aHalFormat
) {
389 case HAL_PIXEL_FORMAT_RGBA_8888
:
391 return SurfaceFormat::B8G8R8A8
;
392 case HAL_PIXEL_FORMAT_RGBX_8888
:
394 return SurfaceFormat::B8G8R8X8
;
395 case HAL_PIXEL_FORMAT_BGRA_8888
:
396 return SurfaceFormat::B8G8R8A8
;
397 case HAL_PIXEL_FORMAT_RGB_565
:
398 return SurfaceFormat::R5G6B5_UINT16
;
400 MOZ_CRASH("Unhandled HAL pixel format");
401 return SurfaceFormat::UNKNOWN
; // not reached
406 NeedsRBSwap(int aHalFormat
)
408 switch (aHalFormat
) {
409 case HAL_PIXEL_FORMAT_RGBA_8888
:
411 case HAL_PIXEL_FORMAT_RGBX_8888
:
413 case HAL_PIXEL_FORMAT_BGRA_8888
:
415 case HAL_PIXEL_FORMAT_RGB_565
:
418 MOZ_CRASH("Unhandled HAL pixel format");
419 return false; // not reached
423 already_AddRefed
<DrawTarget
>
424 nsScreenGonk::StartRemoteDrawing()
426 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
427 MOZ_ASSERT(!mFramebuffer
);
428 MOZ_ASSERT(!mMappedBuffer
);
430 mFramebuffer
= DequeueBuffer();
431 int width
= mFramebuffer
->width
, height
= mFramebuffer
->height
;
432 if (gralloc_module()->lock(gralloc_module(), mFramebuffer
->handle
,
433 GRALLOC_USAGE_SW_READ_NEVER
|
434 GRALLOC_USAGE_SW_WRITE_OFTEN
|
437 reinterpret_cast<void**>(&mMappedBuffer
))) {
441 SurfaceFormat format
= HalFormatToSurfaceFormat(GetSurfaceFormat());
442 mFramebufferTarget
= Factory::CreateDrawTargetForData(
445 IntSize(width
, height
),
446 mFramebuffer
->stride
* gfx::BytesPerPixel(format
),
448 if (!mFramebufferTarget
) {
449 MOZ_CRASH("nsWindow::StartRemoteDrawing failed in CreateDrawTargetForData");
452 mBackBuffer
->GetSize() != mFramebufferTarget
->GetSize() ||
453 mBackBuffer
->GetFormat() != mFramebufferTarget
->GetFormat()) {
454 mBackBuffer
= mFramebufferTarget
->CreateSimilarDrawTarget(
455 mFramebufferTarget
->GetSize(), mFramebufferTarget
->GetFormat());
457 RefPtr
<DrawTarget
> buffer(mBackBuffer
);
458 return buffer
.forget();
462 nsScreenGonk::EndRemoteDrawing()
464 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
466 if (mFramebufferTarget
&& mFramebuffer
) {
467 IntSize size
= mFramebufferTarget
->GetSize();
468 Rect
rect(0, 0, size
.width
, size
.height
);
469 RefPtr
<SourceSurface
> source
= mBackBuffer
->Snapshot();
470 mFramebufferTarget
->DrawSurface(source
, rect
, rect
);
472 // Convert from BGR to RGB
473 // XXX this is a temporary solution. It consumes extra cpu cycles,
474 // it should not be used on product device.
475 if (NeedsRBSwap(GetSurfaceFormat())) {
476 LOGE("Very slow composition path, it should not be used on product!!!");
477 SurfaceFormat format
= HalFormatToSurfaceFormat(GetSurfaceFormat());
478 gfxUtils::ConvertBGRAtoRGBA(
480 mFramebuffer
->stride
* mFramebuffer
->height
* gfx::BytesPerPixel(format
));
484 MOZ_ASSERT(mFramebuffer
);
485 gralloc_module()->unlock(gralloc_module(), mFramebuffer
->handle
);
486 mMappedBuffer
= nullptr;
489 QueueBuffer(mFramebuffer
);
491 mFramebuffer
= nullptr;
492 mFramebufferTarget
= nullptr;
496 nsScreenGonk::DequeueBuffer()
498 ANativeWindowBuffer
* buf
= nullptr;
499 #if ANDROID_VERSION >= 17
501 mNativeWindow
->dequeueBuffer(mNativeWindow
.get(), &buf
, &fenceFd
);
502 android::sp
<android::Fence
> fence(new android::Fence(fenceFd
));
503 #if ANDROID_VERSION == 17
504 fence
->waitForever(1000, "nsScreenGonk_DequeueBuffer");
505 // 1000 is what Android uses. It is a warning timeout in ms.
506 // This timeout was removed in ANDROID_VERSION 18.
508 fence
->waitForever("nsScreenGonk_DequeueBuffer");
511 mNativeWindow
->dequeueBuffer(mNativeWindow
.get(), &buf
);
517 nsScreenGonk::QueueBuffer(ANativeWindowBuffer
* buf
)
519 #if ANDROID_VERSION >= 17
520 int ret
= mNativeWindow
->queueBuffer(mNativeWindow
.get(), buf
, -1);
523 int ret
= mNativeWindow
->queueBuffer(mNativeWindow
.get(), buf
);
529 nsScreenGonk::MakeSnapshot(ANativeWindowBuffer
* aBuffer
)
531 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
534 layers::CompositorBridgeParent
* compositorParent
= mCompositorBridgeParent
;
535 if (!compositorParent
) {
536 return NS_ERROR_FAILURE
;
539 int width
= aBuffer
->width
, height
= aBuffer
->height
;
540 uint8_t* mappedBuffer
= nullptr;
541 if (gralloc_module()->lock(gralloc_module(), aBuffer
->handle
,
542 GRALLOC_USAGE_SW_READ_OFTEN
|
543 GRALLOC_USAGE_SW_WRITE_OFTEN
,
545 reinterpret_cast<void**>(&mappedBuffer
))) {
546 return NS_ERROR_FAILURE
;
549 SurfaceFormat format
= HalFormatToSurfaceFormat(GetSurfaceFormat());
550 RefPtr
<DrawTarget
> mTarget
=
551 Factory::CreateDrawTargetForData(
554 IntSize(width
, height
),
555 aBuffer
->stride
* gfx::BytesPerPixel(format
),
558 return NS_ERROR_FAILURE
;
561 gfx::IntRect rect
= GetRect().ToUnknownRect();
562 compositorParent
->ForceComposeToTarget(mTarget
, &rect
);
564 // Convert from BGR to RGB
565 // XXX this is a temporary solution. It consumes extra cpu cycles,
566 if (NeedsRBSwap(GetSurfaceFormat())) {
567 LOGE("Slow path of making Snapshot!!!");
568 SurfaceFormat format
= HalFormatToSurfaceFormat(GetSurfaceFormat());
569 gfxUtils::ConvertBGRAtoRGBA(
571 aBuffer
->stride
* aBuffer
->height
* gfx::BytesPerPixel(format
));
572 mappedBuffer
= nullptr;
574 gralloc_module()->unlock(gralloc_module(), aBuffer
->handle
);
579 nsScreenGonk::SetCompositorBridgeParent(layers::CompositorBridgeParent
* aCompositorBridgeParent
)
581 MOZ_ASSERT(NS_IsMainThread());
582 mCompositorBridgeParent
= aCompositorBridgeParent
;
585 #if ANDROID_VERSION >= 17
586 android::DisplaySurface
*
587 nsScreenGonk::GetDisplaySurface()
589 return mDisplaySurface
.get();
593 nsScreenGonk::GetPrevDispAcquireFd()
595 if (!mDisplaySurface
.get()) {
598 return mDisplaySurface
->GetPrevDispAcquireFd();
602 GonkDisplay::DisplayType
603 nsScreenGonk::GetDisplayType()
609 nsScreenGonk::SetEGLInfo(hwc_display_t aDisplay
,
610 hwc_surface_t aSurface
,
611 gl::GLContext
* aGLContext
)
613 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
614 mEGLDisplay
= aDisplay
;
615 mEGLSurface
= aSurface
;
616 mGLContext
= aGLContext
;
620 nsScreenGonk::GetEGLDisplay()
622 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
627 nsScreenGonk::GetEGLSurface()
629 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
633 already_AddRefed
<mozilla::gl::GLContext
>
634 nsScreenGonk::GetGLContext()
636 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
637 RefPtr
<mozilla::gl::GLContext
>glContext
= mGLContext
;
638 return glContext
.forget();
642 UpdateMirroringWidgetSync(nsMainThreadPtrHandle
<nsScreenGonk
>&& aScreen
, nsWindow
* aWindow
)
644 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
645 already_AddRefed
<nsWindow
> window(aWindow
);
646 aScreen
->UpdateMirroringWidget(window
);
650 nsScreenGonk::EnableMirroring()
652 MOZ_ASSERT(NS_IsMainThread());
653 MOZ_ASSERT(!IsPrimaryScreen());
655 RefPtr
<nsScreenGonk
> primaryScreen
= nsScreenManagerGonk::GetPrimaryScreen();
656 NS_ENSURE_TRUE(primaryScreen
, false);
658 bool ret
= primaryScreen
->SetMirroringScreen(this);
659 NS_ENSURE_TRUE(ret
, false);
661 // Create a widget for mirroring
662 nsWidgetInitData initData
;
663 initData
.mScreenId
= mId
;
664 RefPtr
<nsWindow
> window
= new nsWindow();
665 window
->Create(nullptr, nullptr, mNaturalBounds
, &initData
);
666 MOZ_ASSERT(static_cast<nsWindow
*>(window
)->GetScreen() == this);
668 // Update mMirroringWidget on compositor thread
669 nsMainThreadPtrHandle
<nsScreenGonk
> primary
=
670 nsMainThreadPtrHandle
<nsScreenGonk
>(new nsMainThreadPtrHolder
<nsScreenGonk
>(primaryScreen
, false));
671 CompositorThreadHolder::Loop()->PostTask(
672 NewRunnableFunction(&UpdateMirroringWidgetSync
,
674 window
.forget().take()));
681 nsScreenGonk::DisableMirroring()
683 MOZ_ASSERT(NS_IsMainThread());
684 MOZ_ASSERT(!IsPrimaryScreen());
686 mIsMirroring
= false;
687 RefPtr
<nsScreenGonk
> primaryScreen
= nsScreenManagerGonk::GetPrimaryScreen();
688 NS_ENSURE_TRUE(primaryScreen
, false);
690 bool ret
= primaryScreen
->ClearMirroringScreen(this);
691 NS_ENSURE_TRUE(ret
, false);
693 // Update mMirroringWidget on compositor thread
694 nsMainThreadPtrHandle
<nsScreenGonk
> primary
=
695 nsMainThreadPtrHandle
<nsScreenGonk
>(new nsMainThreadPtrHolder
<nsScreenGonk
>(primaryScreen
, false));
696 CompositorThreadHolder::Loop()->PostTask(
697 NewRunnableFunction(&UpdateMirroringWidgetSync
,
704 nsScreenGonk::SetMirroringScreen(nsScreenGonk
* aScreen
)
706 MOZ_ASSERT(NS_IsMainThread());
707 MOZ_ASSERT(IsPrimaryScreen());
709 if (mMirroringScreen
) {
712 mMirroringScreen
= aScreen
;
717 nsScreenGonk::ClearMirroringScreen(nsScreenGonk
* aScreen
)
719 MOZ_ASSERT(NS_IsMainThread());
720 MOZ_ASSERT(IsPrimaryScreen());
722 if (mMirroringScreen
!= aScreen
) {
725 mMirroringScreen
= nullptr;
730 nsScreenGonk::UpdateMirroringWidget(already_AddRefed
<nsWindow
>& aWindow
)
732 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
733 MOZ_ASSERT(IsPrimaryScreen());
735 if (mMirroringWidget
) {
736 nsCOMPtr
<nsIWidget
> widget
= mMirroringWidget
.forget();
737 NS_ReleaseOnMainThread(widget
.forget());
739 mMirroringWidget
= aWindow
;
743 nsScreenGonk::GetMirroringWidget()
745 MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
746 MOZ_ASSERT(IsPrimaryScreen());
748 return mMirroringWidget
;
751 NS_IMPL_ISUPPORTS(nsScreenManagerGonk
, nsIScreenManager
)
753 nsScreenManagerGonk::nsScreenManagerGonk()
754 : mInitialized(false)
755 #if ANDROID_VERSION >= 19
756 , mDisplayEnabled(false)
761 nsScreenManagerGonk::~nsScreenManagerGonk()
765 static StaticRefPtr
<nsScreenManagerGonk
> sScreenManagerGonk
;
767 /* static */ already_AddRefed
<nsScreenManagerGonk
>
768 nsScreenManagerGonk::GetInstance()
770 MOZ_ASSERT(NS_IsMainThread());
772 // Avoid creating nsScreenManagerGonk from content process.
773 if (!XRE_IsParentProcess()) {
774 MOZ_CRASH("Non-chrome processes should not get here.");
777 // Avoid creating multiple nsScreenManagerGonk instance inside main process.
778 if (!sScreenManagerGonk
) {
779 sScreenManagerGonk
= new nsScreenManagerGonk();
780 ClearOnShutdown(&sScreenManagerGonk
);
783 RefPtr
<nsScreenManagerGonk
> screenMgr
= sScreenManagerGonk
.get();
784 return screenMgr
.forget();
787 /* static */ already_AddRefed
< nsScreenGonk
>
788 nsScreenManagerGonk::GetPrimaryScreen()
790 MOZ_ASSERT(NS_IsMainThread());
792 RefPtr
<nsScreenManagerGonk
> manager
= nsScreenManagerGonk::GetInstance();
793 nsCOMPtr
<nsIScreen
> screen
;
794 manager
->GetPrimaryScreen(getter_AddRefs(screen
));
796 return already_AddRefed
<nsScreenGonk
>(
797 static_cast<nsScreenGonk
*>(screen
.forget().take()));
801 nsScreenManagerGonk::Initialize()
807 mScreenOnEvent
= new ScreenOnOffEvent(true);
808 mScreenOffEvent
= new ScreenOnOffEvent(false);
809 GetGonkDisplay()->OnEnabled(displayEnabledCallback
);
811 AddScreen(GonkDisplay::DISPLAY_PRIMARY
);
813 nsAppShell::NotifyScreenInitialized();
818 nsScreenManagerGonk::DisplayEnabled(bool aEnabled
)
820 MOZ_ASSERT(NS_IsMainThread());
822 #if ANDROID_VERSION >= 19
824 * This function could be called before |mCompositorVsyncScheduler| is set.
825 * To avoid this issue, keep the value stored in |mDisplayEnabled|.
827 mDisplayEnabled
= aEnabled
;
828 if (mCompositorVsyncScheduler
) {
829 mCompositorVsyncScheduler
->SetDisplay(mDisplayEnabled
);
833 VsyncControl(aEnabled
);
834 NS_DispatchToMainThread(aEnabled
? mScreenOnEvent
: mScreenOffEvent
);
838 nsScreenManagerGonk::GetPrimaryScreen(nsIScreen
**outScreen
)
840 NS_IF_ADDREF(*outScreen
= mScreens
[0].get());
845 nsScreenManagerGonk::ScreenForId(uint32_t aId
,
846 nsIScreen
**outScreen
)
848 for (size_t i
= 0; i
< mScreens
.Length(); i
++) {
849 if (mScreens
[i
]->GetId() == aId
) {
850 NS_IF_ADDREF(*outScreen
= mScreens
[i
].get());
855 *outScreen
= nullptr;
860 nsScreenManagerGonk::ScreenForRect(int32_t inLeft
,
864 nsIScreen
**outScreen
)
866 // Since all screens have independent coordinate system, we could
867 // only return the primary screen no matter what rect is given.
868 return GetPrimaryScreen(outScreen
);
872 nsScreenManagerGonk::ScreenForNativeWidget(void *aWidget
, nsIScreen
**outScreen
)
874 for (size_t i
= 0; i
< mScreens
.Length(); i
++) {
875 if (aWidget
== mScreens
[i
]->GetNativeWindow()) {
876 NS_IF_ADDREF(*outScreen
= mScreens
[i
].get());
881 *outScreen
= nullptr;
886 nsScreenManagerGonk::GetNumberOfScreens(uint32_t *aNumberOfScreens
)
888 *aNumberOfScreens
= mScreens
.Length();
893 nsScreenManagerGonk::GetSystemDefaultScale(float *aDefaultScale
)
895 *aDefaultScale
= 1.0f
;
900 nsScreenManagerGonk::VsyncControl(bool aEnabled
)
902 if (!NS_IsMainThread()) {
903 NS_DispatchToMainThread(
904 NS_NewRunnableMethodWithArgs
<bool>(this,
905 &nsScreenManagerGonk::VsyncControl
,
910 MOZ_ASSERT(NS_IsMainThread());
911 VsyncSource::Display
&display
= gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay();
913 display
.EnableVsync();
915 display
.DisableVsync();
920 nsScreenManagerGonk::GetIdFromType(GonkDisplay::DisplayType aDisplayType
)
922 // This is the only place where we make the assumption that
923 // display type is equivalent to screen id.
925 // Bug 1138287 will address the conversion from type to id.
930 nsScreenManagerGonk::IsScreenConnected(uint32_t aId
)
932 for (size_t i
= 0; i
< mScreens
.Length(); ++i
) {
933 if (mScreens
[i
]->GetId() == aId
) {
943 // A concrete class as a subject for 'display-changed' observer event.
944 class DisplayInfo
: public nsIDisplayInfo
{
948 DisplayInfo(uint32_t aId
, bool aConnected
)
950 , mConnected(aConnected
)
954 NS_IMETHODIMP
GetId(int32_t *aId
)
960 NS_IMETHODIMP
GetConnected(bool *aConnected
)
962 *aConnected
= mConnected
;
967 virtual ~DisplayInfo() {}
973 NS_IMPL_ISUPPORTS(DisplayInfo
, nsIDisplayInfo
, nsISupports
)
975 class NotifyTask
: public mozilla::Runnable
{
977 NotifyTask(uint32_t aId
, bool aConnected
)
978 : mDisplayInfo(new DisplayInfo(aId
, aConnected
))
984 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
986 os
->NotifyObservers(mDisplayInfo
, "display-changed", nullptr);
992 RefPtr
<DisplayInfo
> mDisplayInfo
;
996 NotifyDisplayChange(uint32_t aId
, bool aConnected
)
998 NS_DispatchToMainThread(new NotifyTask(aId
, aConnected
));
1001 } // end of unnamed namespace.
1004 nsScreenManagerGonk::AddScreen(GonkDisplay::DisplayType aDisplayType
,
1005 android::IGraphicBufferProducer
* aSink
,
1006 NotifyDisplayChangedEvent aEventVisibility
)
1008 MOZ_ASSERT(NS_IsMainThread());
1010 NS_ENSURE_TRUE(aDisplayType
< GonkDisplay::DisplayType::NUM_DISPLAY_TYPES
,
1013 uint32_t id
= GetIdFromType(aDisplayType
);
1014 NS_ENSURE_TRUE(!IsScreenConnected(id
), NS_ERROR_FAILURE
);
1016 GonkDisplay::NativeData nativeData
=
1017 GetGonkDisplay()->GetNativeData(aDisplayType
, aSink
);
1018 nsScreenGonk
* screen
= new nsScreenGonk(id
,
1022 mScreens
.AppendElement(screen
);
1024 if (aEventVisibility
== NotifyDisplayChangedEvent::Observable
) {
1025 NotifyDisplayChange(id
, true);
1028 // By default, non primary screen does mirroring.
1029 if (aDisplayType
!= GonkDisplay::DISPLAY_PRIMARY
&&
1030 gfxPrefs::ScreenMirroringEnabled()) {
1031 screen
->EnableMirroring();
1038 nsScreenManagerGonk::RemoveScreen(GonkDisplay::DisplayType aDisplayType
)
1040 MOZ_ASSERT(NS_IsMainThread());
1042 NS_ENSURE_TRUE(aDisplayType
< GonkDisplay::DisplayType::NUM_DISPLAY_TYPES
,
1045 NotifyDisplayChangedEvent eventVisibility
= NotifyDisplayChangedEvent::Observable
;
1046 uint32_t screenId
= GetIdFromType(aDisplayType
);
1047 NS_ENSURE_TRUE(IsScreenConnected(screenId
), NS_ERROR_FAILURE
);
1049 for (size_t i
= 0; i
< mScreens
.Length(); i
++) {
1050 if (mScreens
[i
]->GetId() == screenId
) {
1051 if (mScreens
[i
]->IsMirroring()) {
1052 mScreens
[i
]->DisableMirroring();
1054 eventVisibility
= mScreens
[i
]->GetEventVisibility();
1055 mScreens
.RemoveElementAt(i
);
1060 if (eventVisibility
== NotifyDisplayChangedEvent::Observable
) {
1061 NotifyDisplayChange(screenId
, false);
1066 #if ANDROID_VERSION >= 19
1068 nsScreenManagerGonk::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler
*aObserver
)
1070 MOZ_ASSERT(NS_IsMainThread());
1072 // We assume on b2g that there is only 1 CompositorBridgeParent
1073 MOZ_ASSERT(mCompositorVsyncScheduler
== nullptr);
1074 MOZ_ASSERT(aObserver
);
1075 mCompositorVsyncScheduler
= aObserver
;
1076 mCompositorVsyncScheduler
->SetDisplay(mDisplayEnabled
);