1
0
Fork 0
firefox/widget/windows/InProcessWinCompositorWidget.cpp
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

219 lines
6.6 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 "InProcessWinCompositorWidget.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/layers/Compositor.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "gfxPlatform.h"
#include "HeadlessCompositorWidget.h"
#include "HeadlessWidget.h"
#include "nsIWidget.h"
#include "nsWindow.h"
#include "VsyncDispatcher.h"
#include "WinCompositorWindowThread.h"
#include <ddraw.h>
namespace mozilla::widget {
using namespace mozilla::gfx;
using namespace mozilla;
/* static */
RefPtr<CompositorWidget> CompositorWidget::CreateLocal(
const CompositorWidgetInitData& aInitData,
const layers::CompositorOptions& aOptions, nsIWidget* aWidget) {
if (aInitData.type() ==
CompositorWidgetInitData::THeadlessCompositorWidgetInitData) {
return new HeadlessCompositorWidget(
aInitData.get_HeadlessCompositorWidgetInitData(), aOptions,
static_cast<HeadlessWidget*>(aWidget));
}
return new InProcessWinCompositorWidget(
aInitData.get_WinCompositorWidgetInitData(), aOptions,
static_cast<nsWindow*>(aWidget));
}
InProcessWinCompositorWidget::InProcessWinCompositorWidget(
const WinCompositorWidgetInitData& aInitData,
const layers::CompositorOptions& aOptions, nsWindow* aWindow)
: WinCompositorWidget(aInitData, aOptions),
mWindow(aWindow),
mWnd(reinterpret_cast<HWND>(aInitData.hWnd())),
mCompositeDC(nullptr),
mLockedBackBufferData(nullptr) {
MOZ_ASSERT(mWindow);
MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
}
void InProcessWinCompositorWidget::OnDestroyWindow() {
gfx::CriticalSectionAutoEnter presentLock(&mPresentLock);
}
bool InProcessWinCompositorWidget::OnWindowResize(
const LayoutDeviceIntSize& aSize) {
return true;
}
bool InProcessWinCompositorWidget::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 InProcessWinCompositorWidget::PostRender(
WidgetRenderingContext* aContext) {
mPresentLock.Leave();
}
LayoutDeviceIntSize InProcessWinCompositorWidget::GetClientSize() {
RECT r;
if (!::GetClientRect(mWnd, &r)) {
return LayoutDeviceIntSize();
}
return LayoutDeviceIntSize(r.right - r.left, r.bottom - r.top);
}
already_AddRefed<gfx::DrawTarget>
InProcessWinCompositorWidget::StartRemoteDrawing() {
MOZ_ASSERT(!mCompositeDC);
// Must call this after EnsureTransparentSurface(), since it could update
// the DC.
HDC dc = GetWindowSurface();
if (!dc) {
return nullptr;
}
uint32_t flags = TransparencyModeIs(TransparencyMode::Opaque)
? 0
: gfxWindowsSurface::FLAG_IS_TRANSPARENT;
RefPtr<gfxASurface> surf = new gfxWindowsSurface(dc, flags);
IntSize size = surf->GetSize();
if (size.width <= 0 || size.height <= 0) {
if (dc) {
FreeWindowSurface(dc);
}
return nullptr;
}
RefPtr<DrawTarget> dt =
mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(
surf->CairoSurface(), size);
if (dt) {
mCompositeDC = dc;
} else {
FreeWindowSurface(dc);
}
return dt.forget();
}
void InProcessWinCompositorWidget::EndRemoteDrawing() {
MOZ_ASSERT(!mLockedBackBufferData);
if (mCompositeDC) {
FreeWindowSurface(mCompositeDC);
}
mCompositeDC = nullptr;
}
already_AddRefed<gfx::DrawTarget>
InProcessWinCompositorWidget::GetBackBufferDrawTarget(
gfx::DrawTarget* aScreenTarget, const gfx::IntRect& aRect,
bool* aOutIsCleared) {
MOZ_ASSERT(!mLockedBackBufferData);
RefPtr<gfx::DrawTarget> target = CompositorWidget::GetBackBufferDrawTarget(
aScreenTarget, aRect, aOutIsCleared);
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>
InProcessWinCompositorWidget::EndBackBufferDrawing() {
if (mLockedBackBufferData) {
MOZ_ASSERT(mLastBackBuffer);
mLastBackBuffer->ReleaseBits(mLockedBackBufferData);
mLockedBackBufferData = nullptr;
}
return CompositorWidget::EndBackBufferDrawing();
}
bool InProcessWinCompositorWidget::InitCompositor(
layers::Compositor* aCompositor) {
return true;
}
void InProcessWinCompositorWidget::EnterPresentLock() { mPresentLock.Enter(); }
void InProcessWinCompositorWidget::LeavePresentLock() { mPresentLock.Leave(); }
void InProcessWinCompositorWidget::UpdateTransparency(TransparencyMode aMode) {
gfx::CriticalSectionAutoEnter presentLock(&mPresentLock);
SetTransparencyMode(aMode);
}
void InProcessWinCompositorWidget::NotifyVisibilityUpdated(
bool aIsFullyOccluded) {
mIsFullyOccluded = aIsFullyOccluded;
}
bool InProcessWinCompositorWidget::GetWindowIsFullyOccluded() const {
bool isFullyOccluded = mIsFullyOccluded;
return isFullyOccluded;
}
HDC InProcessWinCompositorWidget::GetWindowSurface() { return ::GetDC(mWnd); }
void InProcessWinCompositorWidget::FreeWindowSurface(HDC dc) {
::ReleaseDC(mWnd, dc);
}
bool InProcessWinCompositorWidget::IsHidden() const { return ::IsIconic(mWnd); }
nsIWidget* InProcessWinCompositorWidget::RealWidget() { return mWindow; }
void InProcessWinCompositorWidget::ObserveVsync(VsyncObserver* aObserver) {
if (RefPtr<CompositorVsyncDispatcher> cvd =
mWindow->GetCompositorVsyncDispatcher()) {
cvd->SetCompositorVsyncObserver(aObserver);
}
}
void InProcessWinCompositorWidget::UpdateCompositorWnd(
const HWND aCompositorWnd, const HWND aParentWnd) {
MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
MOZ_ASSERT(aCompositorWnd && aParentWnd);
MOZ_ASSERT(aParentWnd == mWnd);
// Since we're in the parent process anyway, we can just call SetParent
// directly.
::SetParent(aCompositorWnd, aParentWnd);
mSetParentCompleted = true;
}
} // namespace mozilla::widget