/* -*- 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/. */
/* * nsWindowGfx - Painting and aceleration.
*/
/************************************************************** ************************************************************** ** ** BLOCK: Includes ** ** Include headers. ** **************************************************************
**************************************************************/
// Avoid starting the GPU process for the initial navigator:blank window. if (mIsEarlyBlankWindow) { // Call BeginPaint/EndPaint or Windows will keep sending us messages.
::BeginPaint(mWnd, &ps);
::EndPaint(mWnd, &ps); returntrue;
}
if (didResize && knowsCompositor && layerManager) { // Do an early async composite so that we at least have something on the // screen in the right place, even if the content is out of date.
layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
}
mLastPaintBounds = mBounds;
RefPtr<nsWindow> strongThis(this); if (nsIWidgetListener* listener = GetPaintListener()) { // WillPaintWindow will update our transparent area if needed, which we use // below. Note that this might kill the listener.
listener->WillPaintWindow(this);
}
// For layered translucent popups all drawing should go to memory DC and no // WM_PAINT messages are normally generated. To support asynchronous painting // we force generation of WM_PAINT messages by invalidating window areas with // RedrawWindow, InvalidateRect or InvalidateRgn function calls. constbool usingMemoryDC =
IsPopup() && renderer->GetBackendType() == LayersBackend::LAYERS_NONE &&
mTransparencyMode == TransparencyMode::Transparent; const LayoutDeviceIntRect winRect = [&] {
RECT r;
::GetWindowRect(mWnd, &r);
::MapWindowPoints(nullptr, mWnd, (LPPOINT)&r, 2); return WinUtils::ToIntRect(r);
}();
LayoutDeviceIntRegion region;
LayoutDeviceIntRegion translucentRegion; // BeginPaint/EndPaint must be called to make Windows think that invalid // area is painted. Otherwise it will continue sending the same message // endlessly. Note that we need to call it after WillPaintWindow, which // informs us of our transparent region, but also before clearing the // nc-area, since ::BeginPaint might send WM_NCPAINT messages[1]. // [1]: // https://learn.microsoft.com/en-us/windows/win32/gdi/the-wm-paint-message
HDC hDC = ::BeginPaint(mWnd, &ps); if (usingMemoryDC) {
::EndPaint(mWnd, &ps); // We're guaranteed to have a widget proxy since we called // GetLayerManager().
hDC = mBasicLayersSurface->GetTransparentDC();
region = translucentRegion = LayoutDeviceIntRegion{winRect};
} else {
region = GetRegionToPaint(ps, hDC); if (mTransparencyMode == TransparencyMode::Transparent) {
translucentRegion = LayoutDeviceIntRegion{winRect};
translucentRegion.SubOut(mOpaqueRegion);
region.OrWith(translucentRegion);
}
if (mNeedsNCAreaClear ||
(didResize && mTransparencyMode == TransparencyMode::Transparent)) { // We need to clear the non-client-area region, and the transparent parts // of the window to black (once). auto black = reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH));
nsAutoRegion regionToClear(ComputeNonClientHRGN()); if (!translucentRegion.IsEmpty()) {
nsAutoRegion translucent(WinUtils::RegionToHRGN(translucentRegion));
::CombineRgn(regionToClear, regionToClear, translucent, RGN_OR);
}
::FillRgn(hDC, regionToClear, black);
}
}
mNeedsNCAreaClear = false;
bool didPaint = false; auto endPaint = MakeScopeExit([&] { if (!usingMemoryDC) {
::EndPaint(mWnd, &ps);
} if (didPaint) {
mLastPaintEndTime = TimeStamp::Now(); if (nsIWidgetListener* listener = GetPaintListener()) {
listener->DidPaintWindow();
} if (aNestingLevel == 0 && ::GetUpdateRect(mWnd, nullptr, false)) {
OnPaint(1);
}
}
});
if (region.IsEmpty() || !GetPaintListener()) { returnfalse;
}
if (knowsCompositor && layerManager) {
layerManager->SendInvalidRegion(region.ToUnknownRegion());
layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
}
bool result = true; switch (renderer->GetBackendType()) { case LayersBackend::LAYERS_NONE: {
RefPtr<gfxASurface> targetSurface;
// don't support transparency for non-GDI rendering, for now if (usingMemoryDC) { // This mutex needs to be held when EnsureTransparentSurface is // called.
MutexAutoLock lock(mBasicLayersSurface->GetTransparentSurfaceLock());
targetSurface = mBasicLayersSurface->EnsureTransparentSurface();
}
RECT paintRect;
::GetClientRect(mWnd, &paintRect);
RefPtr<DrawTarget> dt = gfxPlatform::CreateDrawTargetForSurface(
targetSurface, IntSize(paintRect.right - paintRect.left,
paintRect.bottom - paintRect.top)); if (!dt || !dt->IsValid()) {
gfxWarning()
<< "nsWindow::OnPaint failed in CreateDrawTargetForSurface"; returnfalse;
}
// don't need to double buffer with anything but GDI
BufferMode doubleBuffering = mozilla::layers::BufferMode::BUFFER_NONE; switch (mTransparencyMode) { case TransparencyMode::Transparent: // If we're rendering with translucency, we're going to be // rendering the whole window; make sure we clear it first
dt->ClearRect(Rect(dt->GetRect())); break; default: // If we're not doing translucency, then double buffer
doubleBuffering = mozilla::layers::BufferMode::BUFFERED; break;
}
gfxContext thebesContext(dt);
{
AutoLayerManagerSetup setupLayerManager(this, &thebesContext,
doubleBuffering); if (nsIWidgetListener* listener = GetPaintListener()) {
result = listener->PaintWindow(this, region);
}
}
if (usingMemoryDC) { // 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.
mBasicLayersSurface->RedrawTransparentWindow();
}
} break; case LayersBackend::LAYERS_WR: { if (nsIWidgetListener* listener = GetPaintListener()) {
result = listener->PaintWindow(this, region);
} if (!gfxEnv::MOZ_DISABLE_FORCE_PRESENT()) {
nsCOMPtr<nsIRunnable> event = NewRunnableMethod( "nsWindow::ForcePresent", this, &nsWindow::ForcePresent);
NS_DispatchToMainThread(event);
}
} break; default:
NS_ERROR("Unknown layers backend used!"); break;
}
didPaint = true; return result;
}
bool nsWindow::NeedsToTrackWindowOcclusionState() { if (!WinWindowOcclusionTracker::Get()) { returnfalse;
}
if (mCompositorSession && mWindowType == WindowType::TopLevel) { returntrue;
}
bool isFullyOccluded = aState == mozilla::widget::OcclusionState::OCCLUDED; // When window is minimized, it is not set as fully occluded. if (mFrameState->GetSizeMode() == nsSizeMode_Minimized) {
isFullyOccluded = false;
}
// Don't dispatch if the new occlustion state is the same as the current // state. if (mIsFullyOccluded == isFullyOccluded) { return;
}
if (mWidgetListener) {
mWidgetListener->OcclusionStateChanged(mIsFullyOccluded);
}
}
void nsWindow::MaybeEnableWindowOcclusion(bool aEnable) { // WindowOcclusion is enabled/disabled only when compositor session exists. // See nsWindow::NeedsToTrackWindowOcclusionState(). if (!mCompositorSession) { return;
}
// This override of CreateCompositor is to add support for sending the IPC // call for RequesetFxrOutput as soon as the compositor for this widget is // available. void nsWindow::CreateCompositor() {
nsBaseWidget::CreateCompositor();
MaybeEnableWindowOcclusion(/* aEnable */ true);
if (mRequestFxrOutputPending) {
GetRemoteRenderer()->SendRequestFxrOutput();
}
}
void nsWindow::RequestFxrOutput() { if (GetRemoteRenderer() != nullptr) {
MOZ_CRASH("RequestFxrOutput should happen before Compositor is created.");
} else { // The compositor isn't ready, so indicate to make the IPC call when // it is available.
mRequestFxrOutputPending = true;
}
}
uint8_t* data = nullptr;
UniquePtr<uint8_t[]> autoDeleteArray; if (map.mStride == BytesPerPixel(dataSurface->GetFormat()) * iconSize.width) { // Mapped data is already packed
data = map.mData;
} else { // We can't use map.mData since the pixels are not packed (as required by // CreateDIBitmap, which is called under the DataToBitmap call below). // // We must unmap before calling SurfaceToPackedBGRA because it needs access // to the pixel data.
dataSurface->Unmap();
map.mData = nullptr;
autoDeleteArray = SurfaceToPackedBGRA(dataSurface);
data = autoDeleteArray.get();
NS_ENSURE_TRUE(data, NS_ERROR_FAILURE);
}
// Adjust cursor image data
uint8_t* nsWindowGfx::Data32BitTo1Bit(uint8_t* aImageData, uint32_t aWidth,
uint32_t aHeight) { // We need (aWidth + 7) / 8 bytes plus zero-padding up to a multiple of // 4 bytes for each row (HBITMAP requirement). Bug 353553.
uint32_t outBpr = ((aWidth + 31) / 8) & ~3;
// Allocate and clear mask buffer
uint8_t* outData = (uint8_t*)calloc(outBpr, aHeight); if (!outData) return nullptr;
int32_t* imageRow = (int32_t*)aImageData; for (uint32_t curRow = 0; curRow < aHeight; curRow++) {
uint8_t* outRow = outData + curRow * outBpr;
uint8_t mask = 0x80; for (uint32_t curCol = 0; curCol < aWidth; curCol++) { // Use sign bit to test for transparency, as alpha byte is highest byte if (*imageRow++ < 0) *outRow |= mask;
/** * Convert the given image data to a HBITMAP. If the requested depth is * 32 bit, a bitmap with an alpha channel will be returned. * * @param aImageData The image data to convert. Must use the format accepted * by CreateDIBitmap. * @param aWidth With of the bitmap, in pixels. * @param aHeight Height of the image, in pixels. * @param aDepth Image depth, in bits. Should be one of 1, 24 and 32. * * @return The HBITMAP representing the image. Caller should call * DeleteObject when done with the bitmap. * On failure, nullptr will be returned.
*/
HBITMAP nsWindowGfx::DataToBitmap(uint8_t* aImageData, uint32_t aWidth,
uint32_t aHeight, uint32_t aDepth) {
HDC dc = ::GetDC(nullptr);
if (aDepth == 32) { // Alpha channel. We need the new header.
BITMAPV4HEADER head = {0};
head.bV4Size = sizeof(head);
head.bV4Width = aWidth;
head.bV4Height = aHeight;
head.bV4Planes = 1;
head.bV4BitCount = aDepth;
head.bV4V4Compression = BI_BITFIELDS;
head.bV4SizeImage = 0; // Uncompressed
head.bV4XPelsPerMeter = 0;
head.bV4YPelsPerMeter = 0;
head.bV4ClrUsed = 0;
head.bV4ClrImportant = 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.