Files
basilisk55/widget/windows/WinCompositorWidget.cpp
T
roytam1 9c1bff8485 import changes from wg9s seamonkey-2.49 patches:
- Bug 1420865 - Don't check for CONTENT_MAY_CHANGE_TRANSFORM across layer trees. r=mstange, a=RyanVM
- Bug 1466991 - Part 1: Factor out ShouldUseXBLScope. r=smaug, a=RyanVM
- Bug 1376756 - gtk: while drawing nsTreeBodyFrame, fetch current row attributes for proper style rendering. r=karlt a=jorgk DONTBUILD
- Bug 1465458 - Fix launching downloads without a file extension on Windows. r=mak, a=RyanVM
- Bug 1470260 - Part 1: Ensure that 'this' stays alive for the duration of the TickRefreshDriver call. r=emilio, a=RyanVM
- Bug 1470260 - Part 2: Make RefreshDriverTimer ref-counted and hold a strong ref on it on the stack when nsRefreshDriver::Tick can be reached. r=emilio, a=RyanVM
- Bug 1469914 - Prevent the HAL from registering duplicate observers. r=froydnj, a=RyanVM
- Bug 1472925 - Keep a strong reference to MediaStreamGraph from GraphDriver. r=padenot, a=RyanVM
- Bug 468497: Inform the accessibility FocusManager when a XUL tree's view changes. r=MarcoZ a=jorgk DONTBUILD
- Bug 1362303: Avoid crashes when dragging on macOS due to failed allocations of large shmem segments. r=glandium
- Bug 1473161 - Add missing bound check in nsContentUtils::DataTransferItemToImage. r=nika, a=RyanVM
- Bug 1456294 - Hook ImmAssociateContextEx. r=masayuki, a=RyanVM
- Bug 1435319. r=valentin, a=RyanVM
- Bug 1478679 - Fix memory leak in LCovCompartment. r=nbp, a=RyanVM
- Bug 1468053 - Disable a workaround on macOS 10.14+ for an Apple bug described in bug 378645 involving popup windows that was fixed by Apple. r=mstange, a=RyanVM
- Bug 1403945 - Add utility functions to recognize OS X 10.13. r=mstange, a=sledru
- Bug 1468053 - Add nsCocoaFeatures::OnMojaveOrLater(). r=haik, a=RyanVM
- Bug 1467889 - Adjust some uses of XPCOM strings. r=mrbkap, r=mstange, a=RyanVM
- Bug 1474883 - Ensure D2D glyph cache is pruned after rendering 1000 transformed glyphs. r=bas, a=RyanVM
- Bug 1450989 - Capture the action and target as part of the form submission creation. r=bz, a=RyanVM
- Bug 1473113 - Defer initializing the MAR index until it's needed. r=rstrong, a=RyanVM
- Bug 1467363 - Protect access to mTransparentSurface with a lock. r=rhunt, a=RyanVM
- Bug 1404274 - Key Evaluation on the cloned JS objects. r=asuth, a=RyanVM
- Bug 1480640 - Fix hazard in CopyingStructuredCloneReadCallback. r=baku, a=RyanVM
- Bug 1480092 - Cherrypick rev 52add5896661d186dec284ed646a4b33b607d2c7. r=drno a=RyanVM
- Bug 1466577 - Race condition in WebSocketChannel::StopSession. r=hurley a=dveditz
- Bug 1461307 - Overwrite selection colors of widget which may be referred by IME via IM context with selection colors of GtkTextView. r=karlt, a=RyanVM
- Bug 1480521 - Backport fixes from Bug 1479900. r=sfink, a=RyanVM
- Bug 1469348 - Fix the problem of download file failed on Mac. r=paolo, a=RyanVM
- Bug 1478575 - Unify CamerasChild shutdown paths. r=gcp, a=RyanVM
- Bug 1461706 - Sync disabled state of number control regardless of appearance. r=jwatt, a=RyanVM
- Bug 1485224 - Make best efforts to write a stack frame atomically. r=froydnj
- Bug 1435212 - Add support for FFmpeg 4.0. r=bryce, a=jcristau
- Bug 1512882 - Use Windows 7 search icon on Windows 8.x. r=IanN a=IanN
- Bug 1496588: Avoid a UB in mozStorageService.cpp. r=froydnj
- Bug 1500759 - Root parameter dictionaries in AesTask::Init(). r=keeler, a=lizzard
2019-01-19 22:13:12 +08:00

341 lines
8.5 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WinCompositorWidget.h"
#include "gfxPrefs.h"
#include "mozilla/gfx/DeviceManagerDx.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/layers/Compositor.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsWindow.h"
#include "VsyncDispatcher.h"
#include <ddraw.h>
namespace mozilla {
namespace widget {
using namespace mozilla;
using namespace mozilla::gfx;
WinCompositorWidget::WinCompositorWidget(const CompositorWidgetInitData& aInitData,
const layers::CompositorOptions& aOptions)
: CompositorWidget(aOptions)
, mWidgetKey(aInitData.widgetKey()),
mWnd(reinterpret_cast<HWND>(aInitData.hWnd())),
mTransparentSurfaceLock("mTransparentSurfaceLock"),
mTransparencyMode(static_cast<nsTransparencyMode>(aInitData.transparencyMode())),
mMemoryDC(nullptr),
mCompositeDC(nullptr),
mLockedBackBufferData(nullptr)
{
MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
// mNotDeferEndRemoteDrawing is set on the main thread during init,
// but is only accessed after on the compositor thread.
mNotDeferEndRemoteDrawing = gfxPrefs::LayersCompositionFrameRate() == 0 ||
gfxPlatform::IsInLayoutAsapMode() ||
gfxPlatform::ForceSoftwareVsync();
}
void
WinCompositorWidget::OnDestroyWindow()
{
MutexAutoLock lock(mTransparentSurfaceLock);
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
}
bool
WinCompositorWidget::PreRender(WidgetRenderingContext* aContext)
{
// This can block waiting for WM_SETTEXT to finish
// Using PreRender is unnecessarily pessimistic because
// we technically only need to block during the present call
// not all of compositor rendering
mPresentLock.Enter();
return true;
}
void
WinCompositorWidget::PostRender(WidgetRenderingContext* aContext)
{
mPresentLock.Leave();
}
LayoutDeviceIntSize
WinCompositorWidget::GetClientSize()
{
RECT r;
if (!::GetClientRect(mWnd, &r)) {
return LayoutDeviceIntSize();
}
return LayoutDeviceIntSize(
r.right - r.left,
r.bottom - r.top);
}
already_AddRefed<gfx::DrawTarget>
WinCompositorWidget::StartRemoteDrawing()
{
MutexAutoLock lock(mTransparentSurfaceLock);
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
WinCompositorWidget::EndRemoteDrawing()
{
MOZ_ASSERT(!mLockedBackBufferData);
if (mTransparencyMode == eTransparencyTransparent) {
MOZ_ASSERT(mTransparentSurface);
RedrawTransparentWindow();
}
if (mCompositeDC) {
FreeWindowSurface(mCompositeDC);
}
mCompositeDC = nullptr;
}
bool
WinCompositorWidget::NeedsToDeferEndRemoteDrawing()
{
if(mNotDeferEndRemoteDrawing) {
return false;
}
IDirectDraw7* ddraw = DeviceManagerDx::Get()->GetDirectDraw();
if (!ddraw) {
return false;
}
DWORD scanLine = 0;
int height = ::GetSystemMetrics(SM_CYSCREEN);
HRESULT ret = ddraw->GetScanLine(&scanLine);
if (ret == DDERR_VERTICALBLANKINPROGRESS) {
scanLine = 0;
} else if (ret != DD_OK) {
return false;
}
// Check if there is a risk of tearing with GDI.
if (static_cast<int>(scanLine) > height / 2) {
// No need to defer.
return false;
}
return true;
}
already_AddRefed<gfx::DrawTarget>
WinCompositorWidget::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
const LayoutDeviceIntRect& aRect,
const LayoutDeviceIntRect& aClearRect)
{
MOZ_ASSERT(!mLockedBackBufferData);
RefPtr<gfx::DrawTarget> target =
CompositorWidget::GetBackBufferDrawTarget(aScreenTarget, aRect, aClearRect);
if (!target) {
return nullptr;
}
MOZ_ASSERT(target->GetBackendType() == BackendType::CAIRO);
uint8_t* destData;
IntSize destSize;
int32_t destStride;
SurfaceFormat destFormat;
if (!target->LockBits(&destData, &destSize, &destStride, &destFormat)) {
// LockBits is not supported. Use original DrawTarget.
return target.forget();
}
RefPtr<gfx::DrawTarget> dataTarget =
Factory::CreateDrawTargetForData(BackendType::CAIRO,
destData,
destSize,
destStride,
destFormat);
mLockedBackBufferData = destData;
return dataTarget.forget();
}
already_AddRefed<gfx::SourceSurface>
WinCompositorWidget::EndBackBufferDrawing()
{
if (mLockedBackBufferData) {
MOZ_ASSERT(mLastBackBuffer);
mLastBackBuffer->ReleaseBits(mLockedBackBufferData);
mLockedBackBufferData = nullptr;
}
return CompositorWidget::EndBackBufferDrawing();
}
bool
WinCompositorWidget::InitCompositor(layers::Compositor* aCompositor)
{
if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_BASIC) {
DeviceManagerDx::Get()->InitializeDirectDraw();
}
return true;
}
uintptr_t
WinCompositorWidget::GetWidgetKey()
{
return mWidgetKey;
}
void
WinCompositorWidget::EnterPresentLock()
{
mPresentLock.Enter();
}
void
WinCompositorWidget::LeavePresentLock()
{
mPresentLock.Leave();
}
RefPtr<gfxASurface>
WinCompositorWidget::EnsureTransparentSurface()
{
mTransparentSurfaceLock.AssertCurrentThreadOwns();
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
IntSize size = GetClientSize().ToUnknownSize();
if (!mTransparentSurface || mTransparentSurface->GetSize() != size) {
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
CreateTransparentSurface(size);
}
RefPtr<gfxASurface> surface = mTransparentSurface;
return surface.forget();
}
void
WinCompositorWidget::CreateTransparentSurface(const gfx::IntSize& aSize)
{
mTransparentSurfaceLock.AssertCurrentThreadOwns();
MOZ_ASSERT(!mTransparentSurface && !mMemoryDC);
RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(aSize, SurfaceFormat::A8R8G8B8_UINT32);
mTransparentSurface = surface;
mMemoryDC = surface->GetDC();
}
void
WinCompositorWidget::UpdateTransparency(nsTransparencyMode aMode)
{
MutexAutoLock lock(mTransparentSurfaceLock);
if (mTransparencyMode == aMode) {
return;
}
mTransparencyMode = aMode;
mTransparentSurface = nullptr;
mMemoryDC = nullptr;
if (mTransparencyMode == eTransparencyTransparent) {
EnsureTransparentSurface();
}
}
void
WinCompositorWidget::ClearTransparentWindow()
{
MutexAutoLock lock(mTransparentSurfaceLock);
if (!mTransparentSurface) {
return;
}
EnsureTransparentSurface();
IntSize size = mTransparentSurface->GetSize();
if (!size.IsEmpty()) {
RefPtr<DrawTarget> drawTarget =
gfxPlatform::CreateDrawTargetForSurface(mTransparentSurface, size);
if (!drawTarget) {
return;
}
drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
RedrawTransparentWindow();
}
}
bool
WinCompositorWidget::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
WinCompositorWidget::GetWindowSurface()
{
return eTransparencyTransparent == mTransparencyMode
? mMemoryDC
: ::GetDC(mWnd);
}
void
WinCompositorWidget::FreeWindowSurface(HDC dc)
{
if (eTransparencyTransparent != mTransparencyMode)
::ReleaseDC(mWnd, dc);
}
} // namespace widget
} // namespace mozilla