michael@0: /* Copyright 2012 Mozilla Foundation and Mozilla contributors michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: michael@0: #include michael@0: michael@0: #include "android/log.h" michael@0: michael@0: #include "mozilla/dom/TabParent.h" michael@0: #include "mozilla/Hal.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/FileUtils.h" michael@0: #include "mozilla/ClearOnShutdown.h" michael@0: #include "Framebuffer.h" michael@0: #include "gfxContext.h" michael@0: #include "gfxPlatform.h" michael@0: #include "gfxUtils.h" michael@0: #include "GLContextProvider.h" michael@0: #include "GLContext.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsAppShell.h" michael@0: #include "nsIdleService.h" michael@0: #include "nsScreenManagerGonk.h" michael@0: #include "nsTArray.h" michael@0: #include "nsWindow.h" michael@0: #include "nsIWidgetListener.h" michael@0: #include "cutils/properties.h" michael@0: #include "ClientLayerManager.h" michael@0: #include "BasicLayers.h" michael@0: #include "libdisplay/GonkDisplay.h" michael@0: #include "pixelflinger/format.h" michael@0: #include "mozilla/BasicEvents.h" michael@0: #include "mozilla/layers/APZCTreeManager.h" michael@0: #include "mozilla/layers/CompositorParent.h" michael@0: #include "ParentProcessController.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "HwcComposer2D.h" michael@0: michael@0: #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) michael@0: #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args) michael@0: #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args) michael@0: michael@0: #define IS_TOPLEVEL() (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::hal; michael@0: using namespace mozilla::gl; michael@0: using namespace mozilla::layers; michael@0: using namespace mozilla::widget; michael@0: michael@0: nsIntRect gScreenBounds; michael@0: static uint32_t sScreenRotation; michael@0: static uint32_t sPhysicalScreenRotation; michael@0: static nsIntRect sVirtualBounds; michael@0: michael@0: static nsRefPtr sGLContext; michael@0: static nsTArray sTopWindows; michael@0: static nsWindow *gFocusedWindow = nullptr; michael@0: static bool sFramebufferOpen; michael@0: static bool sUsingOMTC; michael@0: static bool sUsingHwc; michael@0: static bool sScreenInitialized; michael@0: static nsRefPtr sOMTCSurface; michael@0: michael@0: namespace { michael@0: michael@0: static uint32_t michael@0: EffectiveScreenRotation() michael@0: { michael@0: return (sScreenRotation + sPhysicalScreenRotation) % (360 / 90); michael@0: } michael@0: michael@0: class ScreenOnOffEvent : public nsRunnable { michael@0: public: michael@0: ScreenOnOffEvent(bool on) michael@0: : mIsOn(on) michael@0: {} michael@0: michael@0: NS_IMETHOD Run() { michael@0: for (uint32_t i = 0; i < sTopWindows.Length(); i++) { michael@0: nsWindow *win = sTopWindows[i]; michael@0: michael@0: if (nsIWidgetListener* listener = win->GetWidgetListener()) { michael@0: listener->SizeModeChanged(mIsOn ? nsSizeMode_Fullscreen : nsSizeMode_Minimized); michael@0: } michael@0: } michael@0: michael@0: // Notify observers that the screen state has just changed. michael@0: nsCOMPtr observerService = mozilla::services::GetObserverService(); michael@0: if (observerService) { michael@0: observerService->NotifyObservers( michael@0: nullptr, "screen-state-changed", michael@0: mIsOn ? MOZ_UTF16("on") : MOZ_UTF16("off") michael@0: ); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: bool mIsOn; michael@0: }; michael@0: michael@0: static StaticRefPtr sScreenOnEvent; michael@0: static StaticRefPtr sScreenOffEvent; michael@0: michael@0: static void michael@0: displayEnabledCallback(bool enabled) michael@0: { michael@0: NS_DispatchToMainThread(enabled ? sScreenOnEvent : sScreenOffEvent); michael@0: } michael@0: michael@0: } // anonymous namespace michael@0: michael@0: nsWindow::nsWindow() michael@0: { michael@0: if (!sScreenInitialized) { michael@0: sScreenOnEvent = new ScreenOnOffEvent(true); michael@0: ClearOnShutdown(&sScreenOnEvent); michael@0: sScreenOffEvent = new ScreenOnOffEvent(false); michael@0: ClearOnShutdown(&sScreenOffEvent); michael@0: GetGonkDisplay()->OnEnabled(displayEnabledCallback); michael@0: michael@0: nsIntSize screenSize; michael@0: bool gotFB = Framebuffer::GetSize(&screenSize); michael@0: if (!gotFB) { michael@0: NS_RUNTIMEABORT("Failed to get size from framebuffer, aborting..."); michael@0: } michael@0: gScreenBounds = nsIntRect(nsIntPoint(0, 0), screenSize); michael@0: michael@0: char propValue[PROPERTY_VALUE_MAX]; michael@0: property_get("ro.sf.hwrotation", propValue, "0"); michael@0: sPhysicalScreenRotation = atoi(propValue) / 90; michael@0: michael@0: sVirtualBounds = gScreenBounds; michael@0: michael@0: sScreenInitialized = true; michael@0: michael@0: nsAppShell::NotifyScreenInitialized(); michael@0: michael@0: // This is a hack to force initialization of the compositor michael@0: // resources, if we're going to use omtc. michael@0: // michael@0: // NB: GetPlatform() will create the gfxPlatform, which wants michael@0: // to know the color depth, which asks our native window. michael@0: // This has to happen after other init has finished. michael@0: gfxPlatform::GetPlatform(); michael@0: sUsingOMTC = ShouldUseOffMainThreadCompositing(); michael@0: michael@0: property_get("ro.display.colorfill", propValue, "0"); michael@0: michael@0: //Update sUsingHwc whenever layers.composer2d.enabled changes michael@0: Preferences::AddBoolVarCache(&sUsingHwc, "layers.composer2d.enabled"); michael@0: michael@0: if (sUsingOMTC) { michael@0: sOMTCSurface = new gfxImageSurface(gfxIntSize(1, 1), michael@0: gfxImageFormat::RGB24); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsWindow::~nsWindow() michael@0: { michael@0: } michael@0: michael@0: void michael@0: nsWindow::DoDraw(void) michael@0: { michael@0: if (!hal::GetScreenEnabled()) { michael@0: gDrawRequest = true; michael@0: return; michael@0: } michael@0: michael@0: if (sTopWindows.IsEmpty()) { michael@0: LOG(" no window to draw, bailing"); michael@0: return; michael@0: } michael@0: michael@0: nsWindow *targetWindow = (nsWindow *)sTopWindows[0]; michael@0: while (targetWindow->GetLastChild()) michael@0: targetWindow = (nsWindow *)targetWindow->GetLastChild(); michael@0: michael@0: nsIWidgetListener* listener = targetWindow->GetWidgetListener(); michael@0: if (listener) { michael@0: listener->WillPaintWindow(targetWindow); michael@0: } michael@0: michael@0: LayerManager* lm = targetWindow->GetLayerManager(); michael@0: if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) { michael@0: // No need to do anything, the compositor will handle drawing michael@0: } else if (mozilla::layers::LayersBackend::LAYERS_BASIC == lm->GetBackendType()) { michael@0: MOZ_ASSERT(sFramebufferOpen || sUsingOMTC); michael@0: nsRefPtr targetSurface; michael@0: michael@0: if(sUsingOMTC) michael@0: targetSurface = sOMTCSurface; michael@0: else michael@0: targetSurface = Framebuffer::BackBuffer(); michael@0: michael@0: { michael@0: nsRefPtr ctx = new gfxContext(targetSurface); michael@0: gfxUtils::PathFromRegion(ctx, sVirtualBounds); michael@0: ctx->Clip(); michael@0: michael@0: // No double-buffering needed. michael@0: AutoLayerManagerSetup setupLayerManager( michael@0: targetWindow, ctx, mozilla::layers::BufferMode::BUFFER_NONE, michael@0: ScreenRotation(EffectiveScreenRotation())); michael@0: michael@0: listener = targetWindow->GetWidgetListener(); michael@0: if (listener) { michael@0: listener->PaintWindow(targetWindow, sVirtualBounds); michael@0: } michael@0: } michael@0: michael@0: if (!sUsingOMTC) { michael@0: targetSurface->Flush(); michael@0: Framebuffer::Present(sVirtualBounds); michael@0: } michael@0: } else { michael@0: NS_RUNTIMEABORT("Unexpected layer manager type"); michael@0: } michael@0: michael@0: listener = targetWindow->GetWidgetListener(); michael@0: if (listener) { michael@0: listener->DidPaintWindow(); michael@0: } michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::DispatchInputEvent(WidgetGUIEvent& aEvent, bool* aWasCaptured) michael@0: { michael@0: if (aWasCaptured) { michael@0: *aWasCaptured = false; michael@0: } michael@0: if (!gFocusedWindow) { michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: gFocusedWindow->UserActivity(); michael@0: michael@0: aEvent.widget = gFocusedWindow; michael@0: michael@0: if (TabParent* capturer = TabParent::GetEventCapturer()) { michael@0: bool captured = capturer->TryCapture(aEvent); michael@0: if (aWasCaptured) { michael@0: *aWasCaptured = captured; michael@0: } michael@0: if (captured) { michael@0: return nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: } michael@0: michael@0: nsEventStatus status; michael@0: gFocusedWindow->DispatchEvent(&aEvent, status); michael@0: return status; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Create(nsIWidget *aParent, michael@0: void *aNativeParent, michael@0: const nsIntRect &aRect, michael@0: nsDeviceContext *aContext, michael@0: nsWidgetInitData *aInitData) michael@0: { michael@0: BaseCreate(aParent, IS_TOPLEVEL() ? sVirtualBounds : aRect, michael@0: aContext, aInitData); michael@0: michael@0: mBounds = aRect; michael@0: michael@0: mParent = (nsWindow *)aParent; michael@0: mVisible = false; michael@0: michael@0: if (!aParent) { michael@0: mBounds = sVirtualBounds; michael@0: } michael@0: michael@0: if (!IS_TOPLEVEL()) michael@0: return NS_OK; michael@0: michael@0: sTopWindows.AppendElement(this); michael@0: michael@0: Resize(0, 0, sVirtualBounds.width, sVirtualBounds.height, false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Destroy(void) michael@0: { michael@0: mOnDestroyCalled = true; michael@0: sTopWindows.RemoveElement(this); michael@0: if (this == gFocusedWindow) michael@0: gFocusedWindow = nullptr; michael@0: nsBaseWidget::OnDestroy(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Show(bool aState) michael@0: { michael@0: if (mWindowType == eWindowType_invisible) michael@0: return NS_OK; michael@0: michael@0: if (mVisible == aState) michael@0: return NS_OK; michael@0: michael@0: mVisible = aState; michael@0: if (!IS_TOPLEVEL()) michael@0: return mParent ? mParent->Show(aState) : NS_OK; michael@0: michael@0: if (aState) { michael@0: BringToTop(); michael@0: } else { michael@0: for (unsigned int i = 0; i < sTopWindows.Length(); i++) { michael@0: nsWindow *win = sTopWindows[i]; michael@0: if (!win->mVisible) michael@0: continue; michael@0: michael@0: win->BringToTop(); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsWindow::IsVisible() const michael@0: { michael@0: return mVisible; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::ConstrainPosition(bool aAllowSlop, michael@0: int32_t *aX, michael@0: int32_t *aY) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Move(double aX, michael@0: double aY) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Resize(double aWidth, michael@0: double aHeight, michael@0: bool aRepaint) michael@0: { michael@0: return Resize(0, 0, aWidth, aHeight, aRepaint); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Resize(double aX, michael@0: double aY, michael@0: double aWidth, michael@0: double aHeight, michael@0: bool aRepaint) michael@0: { michael@0: mBounds = nsIntRect(NSToIntRound(aX), NSToIntRound(aY), michael@0: NSToIntRound(aWidth), NSToIntRound(aHeight)); michael@0: if (mWidgetListener) michael@0: mWidgetListener->WindowResized(this, mBounds.width, mBounds.height); michael@0: michael@0: if (aRepaint) michael@0: Invalidate(sVirtualBounds); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Enable(bool aState) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsWindow::IsEnabled() const michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetFocus(bool aRaise) michael@0: { michael@0: if (aRaise) michael@0: BringToTop(); michael@0: michael@0: gFocusedWindow = this; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::ConfigureChildren(const nsTArray&) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Invalidate(const nsIntRect &aRect) michael@0: { michael@0: nsWindow *top = mParent; michael@0: while (top && top->mParent) michael@0: top = top->mParent; michael@0: if (top != sTopWindows[0] && this != sTopWindows[0]) michael@0: return NS_OK; michael@0: michael@0: gDrawRequest = true; michael@0: mozilla::NotifyEvent(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIntPoint michael@0: nsWindow::WidgetToScreenOffset() michael@0: { michael@0: nsIntPoint p(0, 0); michael@0: nsWindow *w = this; michael@0: michael@0: while (w && w->mParent) { michael@0: p.x += w->mBounds.x; michael@0: p.y += w->mBounds.y; michael@0: michael@0: w = w->mParent; michael@0: } michael@0: michael@0: return p; michael@0: } michael@0: michael@0: void* michael@0: nsWindow::GetNativeData(uint32_t aDataType) michael@0: { michael@0: switch (aDataType) { michael@0: case NS_NATIVE_WINDOW: michael@0: return GetGonkDisplay()->GetNativeWindow(); michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) michael@0: { michael@0: if (mWidgetListener) michael@0: aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(void) michael@0: nsWindow::SetInputContext(const InputContext& aContext, michael@0: const InputContextAction& aAction) michael@0: { michael@0: mInputContext = aContext; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(InputContext) michael@0: nsWindow::GetInputContext() michael@0: { michael@0: // There is only one IME context on Gonk. michael@0: mInputContext.mNativeIMEContext = nullptr; michael@0: return mInputContext; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::MakeFullScreen(bool aFullScreen) michael@0: { michael@0: if (mWindowType != eWindowType_toplevel) { michael@0: // Ignore fullscreen request for non-toplevel windows. michael@0: NS_WARNING("MakeFullScreen() on a dialog or child widget?"); michael@0: return nsBaseWidget::MakeFullScreen(aFullScreen); michael@0: } michael@0: michael@0: if (aFullScreen) { michael@0: // Fullscreen is "sticky" for toplevel widgets on gonk: we michael@0: // must paint the entire screen, and should only have one michael@0: // toplevel widget, so it doesn't make sense to ever "exit" michael@0: // fullscreen. If we do, we can leave parts of the screen michael@0: // unpainted. michael@0: Resize(sVirtualBounds.x, sVirtualBounds.y, michael@0: sVirtualBounds.width, sVirtualBounds.height, michael@0: /*repaint*/true); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: float michael@0: nsWindow::GetDPI() michael@0: { michael@0: return GetGonkDisplay()->xdpi; michael@0: } michael@0: michael@0: double michael@0: nsWindow::GetDefaultScaleInternal() michael@0: { michael@0: float dpi = GetDPI(); michael@0: // The mean pixel density for mdpi devices is 160dpi, 240dpi for hdpi, michael@0: // and 320dpi for xhdpi, respectively. michael@0: // We'll take the mid-value between these three numbers as the boundary. michael@0: if (dpi < 200.0) { michael@0: return 1.0; // mdpi devices. michael@0: } michael@0: if (dpi < 300.0) { michael@0: return 1.5; // hdpi devices. michael@0: } michael@0: // xhdpi devices and beyond. michael@0: return floor(dpi / 150.0 + 0.5); michael@0: } michael@0: michael@0: LayerManager * michael@0: nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, michael@0: LayersBackend aBackendHint, michael@0: LayerManagerPersistence aPersistence, michael@0: bool* aAllowRetaining) michael@0: { michael@0: if (aAllowRetaining) michael@0: *aAllowRetaining = true; michael@0: if (mLayerManager) { michael@0: // This layer manager might be used for painting outside of DoDraw(), so we need michael@0: // to set the correct rotation on it. michael@0: if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) { michael@0: BasicLayerManager* manager = michael@0: static_cast(mLayerManager.get()); michael@0: manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, michael@0: ScreenRotation(EffectiveScreenRotation())); michael@0: } else if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) { michael@0: ClientLayerManager* manager = michael@0: static_cast(mLayerManager.get()); michael@0: manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, michael@0: ScreenRotation(EffectiveScreenRotation())); michael@0: } michael@0: return mLayerManager; michael@0: } michael@0: michael@0: // Set mUseLayersAcceleration here to make it consistent with michael@0: // nsBaseWidget::GetLayerManager michael@0: mUseLayersAcceleration = ComputeShouldAccelerate(mUseLayersAcceleration); michael@0: nsWindow *topWindow = sTopWindows[0]; michael@0: michael@0: if (!topWindow) { michael@0: LOGW(" -- no topwindow\n"); michael@0: return nullptr; michael@0: } michael@0: michael@0: if (sUsingOMTC) { michael@0: CreateCompositor(); michael@0: if (mCompositorParent) { michael@0: uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId(); michael@0: CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController()); michael@0: CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI()); michael@0: } michael@0: if (mLayerManager) michael@0: return mLayerManager; michael@0: } michael@0: michael@0: if (mUseLayersAcceleration) { michael@0: DebugOnly fbBounds = gScreenBounds; michael@0: if (!sGLContext) { michael@0: sGLContext = GLContextProvider::CreateForWindow(this); michael@0: } michael@0: michael@0: MOZ_ASSERT(fbBounds.value == gScreenBounds); michael@0: } michael@0: michael@0: // Fall back to software rendering. michael@0: sFramebufferOpen = Framebuffer::Open(); michael@0: if (sFramebufferOpen) { michael@0: LOG("Falling back to framebuffer software rendering"); michael@0: } else { michael@0: LOGE("Failed to mmap fb(?!?), aborting ..."); michael@0: NS_RUNTIMEABORT("Can't open GL context and can't fall back on /dev/graphics/fb0 ..."); michael@0: } michael@0: michael@0: mLayerManager = new ClientLayerManager(this); michael@0: mUseLayersAcceleration = false; michael@0: michael@0: return mLayerManager; michael@0: } michael@0: michael@0: gfxASurface * michael@0: nsWindow::GetThebesSurface() michael@0: { michael@0: /* This is really a dummy surface; this is only used when doing reflow, because michael@0: * we need a RenderingContext to measure text against. michael@0: */ michael@0: michael@0: // XXX this really wants to return already_AddRefed, but this only really gets used michael@0: // on direct assignment to a gfxASurface michael@0: return new gfxImageSurface(gfxIntSize(5,5), gfxImageFormat::RGB24); michael@0: } michael@0: michael@0: void michael@0: nsWindow::BringToTop() michael@0: { michael@0: if (!sTopWindows.IsEmpty()) { michael@0: if (nsIWidgetListener* listener = sTopWindows[0]->GetWidgetListener()) michael@0: listener->WindowDeactivated(); michael@0: } michael@0: michael@0: sTopWindows.RemoveElement(this); michael@0: sTopWindows.InsertElementAt(0, this); michael@0: michael@0: if (mWidgetListener) michael@0: mWidgetListener->WindowActivated(); michael@0: Invalidate(sVirtualBounds); michael@0: } michael@0: michael@0: void michael@0: nsWindow::UserActivity() michael@0: { michael@0: if (!mIdleService) { michael@0: mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); michael@0: } michael@0: michael@0: if (mIdleService) { michael@0: mIdleService->ResetIdleTimeOut(0); michael@0: } michael@0: } michael@0: michael@0: uint32_t michael@0: nsWindow::GetGLFrameBufferFormat() michael@0: { michael@0: if (mLayerManager && michael@0: mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) { michael@0: // We directly map the hardware fb on Gonk. The hardware fb michael@0: // has RGB format. michael@0: return LOCAL_GL_RGB; michael@0: } michael@0: return LOCAL_GL_NONE; michael@0: } michael@0: michael@0: nsIntRect michael@0: nsWindow::GetNaturalBounds() michael@0: { michael@0: return gScreenBounds; michael@0: } michael@0: michael@0: bool michael@0: nsWindow::NeedsPaint() michael@0: { michael@0: if (!mLayerManager) { michael@0: return false; michael@0: } michael@0: return nsIWidget::NeedsPaint(); michael@0: } michael@0: michael@0: Composer2D* michael@0: nsWindow::GetComposer2D() michael@0: { michael@0: if (!sUsingHwc) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (HwcComposer2D* hwc = HwcComposer2D::GetInstance()) { michael@0: return hwc->Initialized() ? hwc : nullptr; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: // nsScreenGonk.cpp michael@0: michael@0: nsScreenGonk::nsScreenGonk(void *nativeScreen) michael@0: { michael@0: } michael@0: michael@0: nsScreenGonk::~nsScreenGonk() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenGonk::GetRect(int32_t *outLeft, int32_t *outTop, michael@0: int32_t *outWidth, int32_t *outHeight) michael@0: { michael@0: *outLeft = sVirtualBounds.x; michael@0: *outTop = sVirtualBounds.y; michael@0: michael@0: *outWidth = sVirtualBounds.width; michael@0: *outHeight = sVirtualBounds.height; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenGonk::GetAvailRect(int32_t *outLeft, int32_t *outTop, michael@0: int32_t *outWidth, int32_t *outHeight) michael@0: { michael@0: return GetRect(outLeft, outTop, outWidth, outHeight); michael@0: } michael@0: michael@0: static uint32_t michael@0: ColorDepth() michael@0: { michael@0: switch (GetGonkDisplay()->surfaceformat) { michael@0: case GGL_PIXEL_FORMAT_RGB_565: michael@0: return 16; michael@0: case GGL_PIXEL_FORMAT_RGBA_8888: michael@0: return 32; michael@0: } michael@0: return 24; // GGL_PIXEL_FORMAT_RGBX_8888 michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenGonk::GetPixelDepth(int32_t *aPixelDepth) michael@0: { michael@0: // XXX: this should actually return 32 when we're using 24-bit michael@0: // color, because we use RGBX. michael@0: *aPixelDepth = ColorDepth(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenGonk::GetColorDepth(int32_t *aColorDepth) michael@0: { michael@0: return GetPixelDepth(aColorDepth); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenGonk::GetRotation(uint32_t* aRotation) michael@0: { michael@0: *aRotation = sScreenRotation; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenGonk::SetRotation(uint32_t aRotation) michael@0: { michael@0: if (!(aRotation <= ROTATION_270_DEG)) michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: michael@0: if (sScreenRotation == aRotation) michael@0: return NS_OK; michael@0: michael@0: sScreenRotation = aRotation; michael@0: uint32_t rotation = EffectiveScreenRotation(); michael@0: if (rotation == nsIScreen::ROTATION_90_DEG || michael@0: rotation == nsIScreen::ROTATION_270_DEG) { michael@0: sVirtualBounds = nsIntRect(0, 0, gScreenBounds.height, michael@0: gScreenBounds.width); michael@0: } else { michael@0: sVirtualBounds = gScreenBounds; michael@0: } michael@0: michael@0: nsAppShell::NotifyScreenRotation(); michael@0: michael@0: for (unsigned int i = 0; i < sTopWindows.Length(); i++) michael@0: sTopWindows[i]->Resize(sVirtualBounds.width, michael@0: sVirtualBounds.height, michael@0: true); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // NB: This isn't gonk-specific, but gonk is the only widget backend michael@0: // that does this calculation itself, currently. michael@0: static ScreenOrientation michael@0: ComputeOrientation(uint32_t aRotation, const nsIntSize& aScreenSize) michael@0: { michael@0: bool naturallyPortrait = (aScreenSize.height > aScreenSize.width); michael@0: switch (aRotation) { michael@0: case nsIScreen::ROTATION_0_DEG: michael@0: return (naturallyPortrait ? eScreenOrientation_PortraitPrimary : michael@0: eScreenOrientation_LandscapePrimary); michael@0: case nsIScreen::ROTATION_90_DEG: michael@0: // Arbitrarily choosing 90deg to be primary "unnatural" michael@0: // rotation. michael@0: return (naturallyPortrait ? eScreenOrientation_LandscapePrimary : michael@0: eScreenOrientation_PortraitPrimary); michael@0: case nsIScreen::ROTATION_180_DEG: michael@0: return (naturallyPortrait ? eScreenOrientation_PortraitSecondary : michael@0: eScreenOrientation_LandscapeSecondary); michael@0: case nsIScreen::ROTATION_270_DEG: michael@0: return (naturallyPortrait ? eScreenOrientation_LandscapeSecondary : michael@0: eScreenOrientation_PortraitSecondary); michael@0: default: michael@0: MOZ_CRASH("Gonk screen must always have a known rotation"); michael@0: } michael@0: } michael@0: michael@0: /*static*/ uint32_t michael@0: nsScreenGonk::GetRotation() michael@0: { michael@0: return sScreenRotation; michael@0: } michael@0: michael@0: /*static*/ ScreenConfiguration michael@0: nsScreenGonk::GetConfiguration() michael@0: { michael@0: ScreenOrientation orientation = ComputeOrientation(sScreenRotation, michael@0: gScreenBounds.Size()); michael@0: uint32_t colorDepth = ColorDepth(); michael@0: // NB: perpetuating colorDepth == pixelDepth illusion here, for michael@0: // consistency. michael@0: return ScreenConfiguration(sVirtualBounds, orientation, michael@0: colorDepth, colorDepth); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsScreenManagerGonk, nsIScreenManager) michael@0: michael@0: nsScreenManagerGonk::nsScreenManagerGonk() michael@0: { michael@0: mOneScreen = new nsScreenGonk(nullptr); michael@0: } michael@0: michael@0: nsScreenManagerGonk::~nsScreenManagerGonk() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenManagerGonk::GetPrimaryScreen(nsIScreen **outScreen) michael@0: { michael@0: NS_IF_ADDREF(*outScreen = mOneScreen.get()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenManagerGonk::ScreenForRect(int32_t inLeft, michael@0: int32_t inTop, michael@0: int32_t inWidth, michael@0: int32_t inHeight, michael@0: nsIScreen **outScreen) michael@0: { michael@0: return GetPrimaryScreen(outScreen); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenManagerGonk::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen) michael@0: { michael@0: return GetPrimaryScreen(outScreen); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenManagerGonk::GetNumberOfScreens(uint32_t *aNumberOfScreens) michael@0: { michael@0: *aNumberOfScreens = 1; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScreenManagerGonk::GetSystemDefaultScale(float *aDefaultScale) michael@0: { michael@0: *aDefaultScale = 1.0f; michael@0: return NS_OK; michael@0: }