Move transparency handling to WinCompositorWigetProxy. (bug 1265975 part 4, r=jimm)

This commit is contained in:
David Anderson 2016-05-04 22:00:14 -07:00
Родитель 309e579428
Коммит d4a4548584
5 изменённых файлов: 224 добавлений и 181 удалений

Просмотреть файл

@ -6,19 +6,32 @@
#include "WinCompositorWidgetProxy.h"
#include "nsWindow.h"
#include "VsyncDispatcher.h"
#include "mozilla/gfx/Point.h"
namespace mozilla {
namespace widget {
using namespace mozilla::gfx;
WinCompositorWidgetProxy::WinCompositorWidgetProxy(nsWindow* aWindow)
: mWindow(aWindow),
mWnd(reinterpret_cast<HWND>(aWindow->GetNativeData(NS_NATIVE_WINDOW)))
mWnd(reinterpret_cast<HWND>(aWindow->GetNativeData(NS_NATIVE_WINDOW))),
mTransparencyMode(aWindow->GetTransparencyMode()),
mMemoryDC(nullptr),
mCompositeDC(nullptr)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(!aWindow->Destroyed());
MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
}
void
WinCompositorWidgetProxy::OnDestroyWindow()
{
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
}
bool
WinCompositorWidgetProxy::PreRender(layers::LayerManagerComposite* aManager)
{
@ -36,12 +49,6 @@ WinCompositorWidgetProxy::PostRender(layers::LayerManagerComposite* aManager)
mPresentLock.Leave();
}
void
WinCompositorWidgetProxy::EndRemoteDrawing()
{
mWindow->EndRemoteDrawing();
}
nsIWidget*
WinCompositorWidgetProxy::RealWidget()
{
@ -63,7 +70,50 @@ WinCompositorWidgetProxy::GetClientSize()
already_AddRefed<gfx::DrawTarget>
WinCompositorWidgetProxy::StartRemoteDrawing()
{
return mWindow->StartRemoteDrawing();
MOZ_ASSERT(!mCompositeDC);
RefPtr<gfxASurface> surf;
if (mTransparencyMode == eTransparencyTransparent) {
surf = EnsureTransparentSurface();
}
// Must call this after EnsureTransparentSurface(), since it could update
// the DC.
HDC dc = GetWindowSurface();
if (!surf) {
if (!dc) {
return nullptr;
}
uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 :
gfxWindowsSurface::FLAG_IS_TRANSPARENT;
surf = new gfxWindowsSurface(dc, flags);
}
IntSize size = surf->GetSize();
if (size.width <= 0 || size.height <= 0) {
if (dc) {
FreeWindowSurface(dc);
}
return nullptr;
}
MOZ_ASSERT(!mCompositeDC);
mCompositeDC = dc;
return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size);
}
void
WinCompositorWidgetProxy::EndRemoteDrawing()
{
if (mTransparencyMode == eTransparencyTransparent) {
MOZ_ASSERT(mTransparentSurface);
RedrawTransparentWindow();
}
if (mCompositeDC) {
FreeWindowSurface(mCompositeDC);
}
mCompositeDC = nullptr;
}
already_AddRefed<CompositorVsyncDispatcher>
@ -85,5 +135,114 @@ WinCompositorWidgetProxy::LeavePresentLock()
mPresentLock.Leave();
}
RefPtr<gfxASurface>
WinCompositorWidgetProxy::EnsureTransparentSurface()
{
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
if (!mTransparentSurface) {
LayoutDeviceIntSize size = GetClientSize();
CreateTransparentSurface(size.width, size.height);
}
RefPtr<gfxASurface> surface = mTransparentSurface;
return surface.forget();
}
void
WinCompositorWidgetProxy::CreateTransparentSurface(int32_t aWidth, int32_t aHeight)
{
MOZ_ASSERT(!mTransparentSurface && !mMemoryDC);
RefPtr<gfxWindowsSurface> surface =
new gfxWindowsSurface(IntSize(aWidth, aHeight), SurfaceFormat::A8R8G8B8_UINT32);
mTransparentSurface = surface;
mMemoryDC = surface->GetDC();
}
void
WinCompositorWidgetProxy::UpdateTransparency(nsTransparencyMode aMode)
{
if (mTransparencyMode == aMode) {
return;
}
mTransparencyMode = aMode;
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
if (mTransparencyMode == eTransparencyTransparent) {
EnsureTransparentSurface();
}
}
void
WinCompositorWidgetProxy::ClearTransparentWindow()
{
if (!mTransparentSurface) {
return;
}
IntSize size = mTransparentSurface->GetSize();
RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->
CreateDrawTargetForSurface(mTransparentSurface, size);
drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
RedrawTransparentWindow();
}
void
WinCompositorWidgetProxy::ResizeTransparentWindow(int32_t aNewWidth, int32_t aNewHeight)
{
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
if (mTransparentSurface &&
mTransparentSurface->GetSize() == IntSize(aNewWidth, aNewHeight))
{
return;
}
// Destroy the old surface.
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
CreateTransparentSurface(aNewWidth, aNewHeight);
}
bool
WinCompositorWidgetProxy::RedrawTransparentWindow()
{
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
LayoutDeviceIntSize size = GetClientSize();
::GdiFlush();
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
SIZE winSize = { size.width, size.height };
POINT srcPos = { 0, 0 };
HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true);
RECT winRect;
::GetWindowRect(hWnd, &winRect);
// perform the alpha blend
return !!::UpdateLayeredWindow(
hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC,
&srcPos, 0, &bf, ULW_ALPHA);
}
HDC
WinCompositorWidgetProxy::GetWindowSurface()
{
return eTransparencyTransparent == mTransparencyMode
? mMemoryDC
: ::GetDC(mWnd);
}
void
WinCompositorWidgetProxy::FreeWindowSurface(HDC dc)
{
if (eTransparencyTransparent != mTransparencyMode)
::ReleaseDC(mWnd, dc);
}
} // namespace widget
} // namespace mozilla

Просмотреть файл

@ -34,13 +34,42 @@ public:
return this;
}
// Callbacks for nsWindow.
void EnterPresentLock();
void LeavePresentLock();
void OnDestroyWindow();
// Transparency handling.
void UpdateTransparency(nsTransparencyMode aMode);
void ClearTransparentWindow();
bool RedrawTransparentWindow();
// Update the bounds of the transparent surface.
void ResizeTransparentWindow(int32_t aNewWidth, int32_t aNewHeight);
// Ensure that a transparent surface exists, then return it.
RefPtr<gfxASurface> EnsureTransparentSurface();
HDC GetTransparentDC() const {
return mMemoryDC;
}
private:
HDC GetWindowSurface();
void FreeWindowSurface(HDC dc);
void CreateTransparentSurface(int32_t aWidth, int32_t aHeight);
private:
nsWindow* mWindow;
HWND mWnd;
gfx::CriticalSection mPresentLock;
// Transparency handling.
nsTransparencyMode mTransparencyMode;
RefPtr<gfxASurface> mTransparentSurface;
HDC mMemoryDC;
HDC mCompositeDC;
};
} // namespace widget

Просмотреть файл

@ -396,7 +396,6 @@ nsWindow::nsWindow()
mWnd = nullptr;
mTransitionWnd = nullptr;
mPaintDC = nullptr;
mCompositeDC = nullptr;
mPrevWndProc = nullptr;
mNativeDragTarget = nullptr;
mInDtor = false;
@ -431,8 +430,6 @@ nsWindow::nsWindow()
mCachedHitTestTime = TimeStamp::Now();
mCachedHitTestResult = 0;
#ifdef MOZ_XUL
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
mTransparencyMode = eTransparencyOpaque;
memset(&mGlassMargins, 0, sizeof mGlassMargins);
#endif
@ -1302,7 +1299,9 @@ NS_METHOD nsWindow::Show(bool bState)
// Clear contents to avoid ghosting of old content if we display
// this window again.
if (wasVisible && mTransparencyMode == eTransparencyTransparent) {
ClearTranslucentWindow();
if (RefPtr<WinCompositorWidgetProxy> proxy = GetCompositorWidgetProxy()) {
proxy->ClearTransparentWindow();
}
}
if (mWindowType != eWindowType_dialog) {
::ShowWindow(mWnd, SW_HIDE);
@ -1558,10 +1557,11 @@ NS_METHOD nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
return NS_OK;
}
#ifdef MOZ_XUL
if (eTransparencyTransparent == mTransparencyMode)
ResizeTranslucentWindow(width, height);
#endif
if (mTransparencyMode == eTransparencyTransparent) {
if (RefPtr<WinCompositorWidgetProxy> proxy = GetCompositorWidgetProxy()) {
proxy->ResizeTransparentWindow(width, height);
}
}
// Set cached value for lightweight and printing
mBounds.width = width;
@ -1616,10 +1616,11 @@ NS_METHOD nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
return NS_OK;
}
#ifdef MOZ_XUL
if (eTransparencyTransparent == mTransparencyMode)
ResizeTranslucentWindow(width, height);
#endif
if (eTransparencyTransparent == mTransparencyMode) {
if (RefPtr<WinCompositorWidgetProxy> proxy = GetCompositorWidgetProxy()) {
proxy->ResizeTransparentWindow(width, height);
}
}
// Set cached value for lightweight and printing
mBounds.x = x;
@ -3208,27 +3209,6 @@ nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen)
return rv;
}
HDC nsWindow::GetWindowSurface()
{
#ifdef MOZ_XUL
return eTransparencyTransparent == mTransparencyMode
? mMemoryDC
: ::GetDC(mWnd);
#else
return ::GetDC(mWnd);
#endif
}
void nsWindow::FreeWindowSurface(HDC dc)
{
#ifdef MOZ_XUL
if (eTransparencyTransparent != mTransparencyMode)
::ReleaseDC(mWnd, dc);
#else
::ReleaseDC(mWnd, dc);
#endif
}
/**************************************************************
*
* SECTION: Native data storage
@ -3729,59 +3709,6 @@ nsWindow::GetCompositorWidgetProxy()
return mCompositorWidgetProxy ? mCompositorWidgetProxy->AsWindowsProxy() : nullptr;
}
already_AddRefed<mozilla::gfx::DrawTarget>
nsWindow::StartRemoteDrawing()
{
MOZ_ASSERT(!mCompositeDC);
HDC dc = GetWindowSurface();
RefPtr<gfxASurface> surf;
if (mTransparencyMode == eTransparencyTransparent) {
if (!mTransparentSurface) {
SetupTranslucentWindowMemoryBitmap(mTransparencyMode);
}
if (mTransparentSurface) {
surf = mTransparentSurface;
}
}
if (!surf) {
if (!dc) {
return nullptr;
}
uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 :
gfxWindowsSurface::FLAG_IS_TRANSPARENT;
surf = new gfxWindowsSurface(dc, flags);
}
mozilla::gfx::IntSize size(surf->GetSize().width, surf->GetSize().height);
if (size.width <= 0 || size.height <= 0) {
if (dc) {
FreeWindowSurface(dc);
}
return nullptr;
}
MOZ_ASSERT(!mCompositeDC);
mCompositeDC = dc;
return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size);
}
void
nsWindow::EndRemoteDrawing()
{
if (mTransparencyMode == eTransparencyTransparent) {
MOZ_ASSERT(gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend()
|| mTransparentSurface);
UpdateTranslucentWindow();
}
if (mCompositeDC) {
FreeWindowSurface(mCompositeDC);
}
mCompositeDC = nullptr;
}
void
nsWindow::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries)
{
@ -6284,10 +6211,11 @@ void nsWindow::OnWindowPosChanged(WINDOWPOS* wp)
newHeight = r.bottom - r.top;
nsIntRect rect(wp->x, wp->y, newWidth, newHeight);
#ifdef MOZ_XUL
if (eTransparencyTransparent == mTransparencyMode)
ResizeTranslucentWindow(newWidth, newHeight);
#endif
if (eTransparencyTransparent == mTransparencyMode) {
if (RefPtr<WinCompositorWidgetProxy> proxy = GetCompositorWidgetProxy()) {
proxy->ResizeTransparentWindow(newWidth, newHeight);
}
}
if (newWidth > mLastSize.width)
{
@ -6805,11 +6733,9 @@ void nsWindow::OnDestroy()
if (mCursor == -1)
SetCursor(eCursor_standard);
#ifdef MOZ_XUL
// Reset transparency
if (eTransparencyTransparent == mTransparencyMode)
SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
#endif
if (RefPtr<WinCompositorWidgetProxy> proxy = GetCompositorWidgetProxy()) {
proxy->OnDestroyWindow();
}
// Finalize panning feedback to possibly restore window displacement
mGesture.PanFeedbackFinalize(mWnd, true);
@ -7073,17 +6999,6 @@ nsWindow::GetAccessible()
#ifdef MOZ_XUL
void nsWindow::ResizeTranslucentWindow(int32_t aNewWidth, int32_t aNewHeight, bool force)
{
if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
return;
RefPtr<gfxWindowsSurface> newSurface =
new gfxWindowsSurface(IntSize(aNewWidth, aNewHeight), SurfaceFormat::A8R8G8B8_UINT32);
mTransparentSurface = newSurface;
mMemoryDC = newSurface->GetDC();
}
void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
{
if (aMode == mTransparencyMode)
@ -7135,57 +7050,12 @@ void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode)
memset(&mGlassMargins, 0, sizeof mGlassMargins);
mTransparencyMode = aMode;
SetupTranslucentWindowMemoryBitmap(aMode);
if (RefPtr<WinCompositorWidgetProxy> proxy = GetCompositorWidgetProxy()) {
proxy->UpdateTransparency(aMode);
}
UpdateGlass();
}
void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode)
{
if (eTransparencyTransparent == aMode) {
ResizeTranslucentWindow(mBounds.width, mBounds.height, true);
} else {
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
}
}
void nsWindow::ClearTranslucentWindow()
{
if (mTransparentSurface) {
IntSize size = mTransparentSurface->GetSize();
RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->
CreateDrawTargetForSurface(mTransparentSurface, size);
drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
UpdateTranslucentWindow();
}
}
nsresult nsWindow::UpdateTranslucentWindow()
{
if (mBounds.IsEmpty())
return NS_OK;
::GdiFlush();
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
SIZE winSize = { mBounds.width, mBounds.height };
POINT srcPos = { 0, 0 };
HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true);
RECT winRect;
::GetWindowRect(hWnd, &winRect);
// perform the alpha blend
bool updateSuccesful =
::UpdateLayeredWindow(hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC,
&srcPos, 0, &bf, ULW_ALPHA);
if (!updateSuccesful) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
#endif //MOZ_XUL
/**************************************************************

Просмотреть файл

@ -314,8 +314,6 @@ public:
nsIKeyEventInPluginCallback* aCallback) override;
mozilla::widget::CompositorWidgetProxy* NewCompositorWidgetProxy() override;
already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing();
void EndRemoteDrawing();
protected:
virtual ~nsWindow();
@ -470,17 +468,10 @@ protected:
private:
void SetWindowTranslucencyInner(nsTransparencyMode aMode);
nsTransparencyMode GetWindowTranslucencyInner() const { return mTransparencyMode; }
void ResizeTranslucentWindow(int32_t aNewWidth, int32_t aNewHeight, bool force = false);
nsresult UpdateTranslucentWindow();
void ClearTranslucentWindow();
void SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode);
void UpdateGlass();
protected:
#endif // MOZ_XUL
HDC GetWindowSurface();
void FreeWindowSurface(HDC dc);
static bool IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult);
void IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam);
@ -594,7 +585,6 @@ protected:
// Graphics
HDC mPaintDC; // only set during painting
HDC mCompositeDC; // only set during StartRemoteDrawing
LayoutDeviceIntRect mLastPaintBounds;
@ -602,9 +592,6 @@ protected:
// Transparency
#ifdef MOZ_XUL
// Use layered windows to support full 256 level alpha translucency
RefPtr<gfxASurface> mTransparentSurface;
HDC mMemoryDC;
nsTransparencyMode mTransparencyMode;
nsIntRegion mPossiblyTransparentRegion;
MARGINS mGlassMargins;

Просмотреть файл

@ -240,7 +240,8 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel)
::BeginPaint(mWnd, &ps);
::EndPaint(mWnd, &ps);
aDC = mMemoryDC;
// We're guaranteed to have a widget proxy since we called GetLayerManager().
aDC = GetCompositorWidgetProxy()->GetTransparentDC();
}
#endif
@ -312,10 +313,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel)
#if defined(MOZ_XUL)
// don't support transparency for non-GDI rendering, for now
if (eTransparencyTransparent == mTransparencyMode) {
if (mTransparentSurface == nullptr) {
SetupTranslucentWindowMemoryBitmap(mTransparencyMode);
}
targetSurface = mTransparentSurface;
targetSurface = GetCompositorWidgetProxy()->EnsureTransparentSurface();
}
#endif
@ -380,7 +378,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel)
// Data from offscreen drawing surface was copied to memory bitmap of transparent
// bitmap. Now it can be read from memory bitmap to apply alpha channel and after
// that displayed on the screen.
UpdateTranslucentWindow();
GetCompositorWidgetProxy()->RedrawTransparentWindow();
}
#endif
}