1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsWindowGfx.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,829 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * nsWindowGfx - Painting and aceleration. 1.11 + */ 1.12 + 1.13 +// XXX Future: this should really be a stand alone class stored as 1.14 +// a member of nsWindow with getters and setters for things like render 1.15 +// mode and methods for handling paint. 1.16 + 1.17 +/************************************************************** 1.18 + ************************************************************** 1.19 + ** 1.20 + ** BLOCK: Includes 1.21 + ** 1.22 + ** Include headers. 1.23 + ** 1.24 + ************************************************************** 1.25 + **************************************************************/ 1.26 + 1.27 +#include "mozilla/plugins/PluginInstanceParent.h" 1.28 +using mozilla::plugins::PluginInstanceParent; 1.29 + 1.30 +#include "nsWindowGfx.h" 1.31 +#include <windows.h> 1.32 +#include "gfxImageSurface.h" 1.33 +#include "gfxUtils.h" 1.34 +#include "gfxWindowsSurface.h" 1.35 +#include "gfxWindowsPlatform.h" 1.36 +#include "mozilla/gfx/2D.h" 1.37 +#include "mozilla/gfx/DataSurfaceHelpers.h" 1.38 +#include "mozilla/gfx/Tools.h" 1.39 +#include "mozilla/RefPtr.h" 1.40 +#include "nsGfxCIID.h" 1.41 +#include "gfxContext.h" 1.42 +#include "nsRenderingContext.h" 1.43 +#include "prmem.h" 1.44 +#include "WinUtils.h" 1.45 +#include "nsIWidgetListener.h" 1.46 +#include "mozilla/unused.h" 1.47 + 1.48 +#ifdef MOZ_ENABLE_D3D9_LAYER 1.49 +#include "LayerManagerD3D9.h" 1.50 +#endif 1.51 +#ifdef MOZ_ENABLE_D3D10_LAYER 1.52 +#include "LayerManagerD3D10.h" 1.53 +#endif 1.54 +#include "mozilla/layers/CompositorParent.h" 1.55 +#include "ClientLayerManager.h" 1.56 + 1.57 +#include "nsUXThemeData.h" 1.58 +#include "nsUXThemeConstants.h" 1.59 + 1.60 +extern "C" { 1.61 +#define PIXMAN_DONT_DEFINE_STDINT 1.62 +#include "pixman.h" 1.63 +} 1.64 + 1.65 +using namespace mozilla; 1.66 +using namespace mozilla::gfx; 1.67 +using namespace mozilla::layers; 1.68 +using namespace mozilla::widget; 1.69 + 1.70 +/************************************************************** 1.71 + ************************************************************** 1.72 + ** 1.73 + ** BLOCK: Variables 1.74 + ** 1.75 + ** nsWindow Class static initializations and global variables. 1.76 + ** 1.77 + ************************************************************** 1.78 + **************************************************************/ 1.79 + 1.80 +/************************************************************** 1.81 + * 1.82 + * SECTION: nsWindow statics 1.83 + * 1.84 + **************************************************************/ 1.85 + 1.86 +static nsAutoPtr<uint8_t> sSharedSurfaceData; 1.87 +static gfxIntSize sSharedSurfaceSize; 1.88 + 1.89 +struct IconMetrics { 1.90 + int32_t xMetric; 1.91 + int32_t yMetric; 1.92 + int32_t defaultSize; 1.93 +}; 1.94 + 1.95 +// Corresponds 1:1 to the IconSizeType enum 1.96 +static IconMetrics sIconMetrics[] = { 1.97 + {SM_CXSMICON, SM_CYSMICON, 16}, // small icon 1.98 + {SM_CXICON, SM_CYICON, 32} // regular icon 1.99 +}; 1.100 + 1.101 +/************************************************************** 1.102 + ************************************************************** 1.103 + ** 1.104 + ** BLOCK: nsWindowGfx impl. 1.105 + ** 1.106 + ** Misc. graphics related utilities. 1.107 + ** 1.108 + ************************************************************** 1.109 + **************************************************************/ 1.110 + 1.111 +/* static */ bool 1.112 +nsWindow::IsRenderMode(gfxWindowsPlatform::RenderMode rmode) 1.113 +{ 1.114 + return gfxWindowsPlatform::GetPlatform()->GetRenderMode() == rmode; 1.115 +} 1.116 + 1.117 +/************************************************************** 1.118 + ************************************************************** 1.119 + ** 1.120 + ** BLOCK: nsWindow impl. 1.121 + ** 1.122 + ** Paint related nsWindow methods. 1.123 + ** 1.124 + ************************************************************** 1.125 + **************************************************************/ 1.126 + 1.127 +// GetRegionToPaint returns the invalidated region that needs to be painted 1.128 +nsIntRegion nsWindow::GetRegionToPaint(bool aForceFullRepaint, 1.129 + PAINTSTRUCT ps, HDC aDC) 1.130 +{ 1.131 + if (aForceFullRepaint) { 1.132 + RECT paintRect; 1.133 + ::GetClientRect(mWnd, &paintRect); 1.134 + return nsIntRegion(WinUtils::ToIntRect(paintRect)); 1.135 + } 1.136 + 1.137 + HRGN paintRgn = ::CreateRectRgn(0, 0, 0, 0); 1.138 + if (paintRgn != nullptr) { 1.139 + int result = GetRandomRgn(aDC, paintRgn, SYSRGN); 1.140 + if (result == 1) { 1.141 + POINT pt = {0,0}; 1.142 + ::MapWindowPoints(nullptr, mWnd, &pt, 1); 1.143 + ::OffsetRgn(paintRgn, pt.x, pt.y); 1.144 + } 1.145 + nsIntRegion rgn(WinUtils::ConvertHRGNToRegion(paintRgn)); 1.146 + ::DeleteObject(paintRgn); 1.147 + return rgn; 1.148 + } 1.149 + return nsIntRegion(WinUtils::ToIntRect(ps.rcPaint)); 1.150 +} 1.151 + 1.152 +#define WORDSSIZE(x) ((x).width * (x).height) 1.153 +static bool 1.154 +EnsureSharedSurfaceSize(gfxIntSize size) 1.155 +{ 1.156 + gfxIntSize screenSize; 1.157 + screenSize.height = GetSystemMetrics(SM_CYSCREEN); 1.158 + screenSize.width = GetSystemMetrics(SM_CXSCREEN); 1.159 + 1.160 + if (WORDSSIZE(screenSize) > WORDSSIZE(size)) 1.161 + size = screenSize; 1.162 + 1.163 + if (WORDSSIZE(screenSize) < WORDSSIZE(size)) 1.164 + NS_WARNING("Trying to create a shared surface larger than the screen"); 1.165 + 1.166 + if (!sSharedSurfaceData || (WORDSSIZE(size) > WORDSSIZE(sSharedSurfaceSize))) { 1.167 + sSharedSurfaceSize = size; 1.168 + sSharedSurfaceData = nullptr; 1.169 + sSharedSurfaceData = (uint8_t *)malloc(WORDSSIZE(sSharedSurfaceSize) * 4); 1.170 + } 1.171 + 1.172 + return (sSharedSurfaceData != nullptr); 1.173 +} 1.174 + 1.175 +nsIWidgetListener* nsWindow::GetPaintListener() 1.176 +{ 1.177 + if (mDestroyCalled) 1.178 + return nullptr; 1.179 + return mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener; 1.180 +} 1.181 + 1.182 +bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) 1.183 +{ 1.184 + // We never have reentrant paint events, except when we're running our RPC 1.185 + // windows event spin loop. If we don't trap for this, we'll try to paint, 1.186 + // but view manager will refuse to paint the surface, resulting is black 1.187 + // flashes on the plugin rendering surface. 1.188 + if (mozilla::ipc::MessageChannel::IsSpinLoopActive() && mPainting) 1.189 + return false; 1.190 + 1.191 + if (mWindowType == eWindowType_plugin) { 1.192 + 1.193 + /** 1.194 + * After we CallUpdateWindow to the child, occasionally a WM_PAINT message 1.195 + * is posted to the parent event loop with an empty update rect. Do a 1.196 + * dummy paint so that Windows stops dispatching WM_PAINT in an inifinite 1.197 + * loop. See bug 543788. 1.198 + */ 1.199 + RECT updateRect; 1.200 + if (!GetUpdateRect(mWnd, &updateRect, FALSE) || 1.201 + (updateRect.left == updateRect.right && 1.202 + updateRect.top == updateRect.bottom)) { 1.203 + PAINTSTRUCT ps; 1.204 + BeginPaint(mWnd, &ps); 1.205 + EndPaint(mWnd, &ps); 1.206 + return true; 1.207 + } 1.208 + 1.209 + PluginInstanceParent* instance = reinterpret_cast<PluginInstanceParent*>( 1.210 + ::GetPropW(mWnd, L"PluginInstanceParentProperty")); 1.211 + if (instance) { 1.212 + unused << instance->CallUpdateWindow(); 1.213 + } else { 1.214 + // We should never get here since in-process plugins should have 1.215 + // subclassed our HWND and handled WM_PAINT, but in some cases that 1.216 + // could fail. Return without asserting since it's not our fault. 1.217 + NS_WARNING("Plugin failed to subclass our window"); 1.218 + } 1.219 + 1.220 + ValidateRect(mWnd, nullptr); 1.221 + return true; 1.222 + } 1.223 + 1.224 + ClientLayerManager *clientLayerManager = 1.225 + (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) 1.226 + ? static_cast<ClientLayerManager*>(GetLayerManager()) 1.227 + : nullptr; 1.228 + 1.229 + if (clientLayerManager && mCompositorParent && 1.230 + !mBounds.IsEqualEdges(mLastPaintBounds)) 1.231 + { 1.232 + // Do an early async composite so that we at least have something on the 1.233 + // screen in the right place, even if the content is out of date. 1.234 + mCompositorParent->ScheduleRenderOnCompositorThread(); 1.235 + } 1.236 + mLastPaintBounds = mBounds; 1.237 + 1.238 + PAINTSTRUCT ps; 1.239 + 1.240 +#ifdef MOZ_XUL 1.241 + if (!aDC && (eTransparencyTransparent == mTransparencyMode)) 1.242 + { 1.243 + // For layered translucent windows all drawing should go to memory DC and no 1.244 + // WM_PAINT messages are normally generated. To support asynchronous painting 1.245 + // we force generation of WM_PAINT messages by invalidating window areas with 1.246 + // RedrawWindow, InvalidateRect or InvalidateRgn function calls. 1.247 + // BeginPaint/EndPaint must be called to make Windows think that invalid area 1.248 + // is painted. Otherwise it will continue sending the same message endlessly. 1.249 + ::BeginPaint(mWnd, &ps); 1.250 + ::EndPaint(mWnd, &ps); 1.251 + 1.252 + aDC = mMemoryDC; 1.253 + } 1.254 +#endif 1.255 + 1.256 + mPainting = true; 1.257 + 1.258 +#ifdef WIDGET_DEBUG_OUTPUT 1.259 + HRGN debugPaintFlashRegion = nullptr; 1.260 + HDC debugPaintFlashDC = nullptr; 1.261 + 1.262 + if (debug_WantPaintFlashing()) 1.263 + { 1.264 + debugPaintFlashRegion = ::CreateRectRgn(0, 0, 0, 0); 1.265 + ::GetUpdateRgn(mWnd, debugPaintFlashRegion, TRUE); 1.266 + debugPaintFlashDC = ::GetDC(mWnd); 1.267 + } 1.268 +#endif // WIDGET_DEBUG_OUTPUT 1.269 + 1.270 + HDC hDC = aDC ? aDC : (::BeginPaint(mWnd, &ps)); 1.271 + mPaintDC = hDC; 1.272 + 1.273 +#ifdef MOZ_XUL 1.274 + bool forceRepaint = aDC || (eTransparencyTransparent == mTransparencyMode); 1.275 +#else 1.276 + bool forceRepaint = nullptr != aDC; 1.277 +#endif 1.278 + nsIntRegion region = GetRegionToPaint(forceRepaint, ps, hDC); 1.279 + 1.280 + if (clientLayerManager && mCompositorParent) { 1.281 + // We need to paint to the screen even if nothing changed, since if we 1.282 + // don't have a compositing window manager, our pixels could be stale. 1.283 + clientLayerManager->SetNeedsComposite(true); 1.284 + clientLayerManager->SendInvalidRegion(region); 1.285 + } 1.286 + 1.287 + nsIWidgetListener* listener = GetPaintListener(); 1.288 + if (listener) { 1.289 + listener->WillPaintWindow(this); 1.290 + } 1.291 + // Re-get the listener since the will paint notification may have killed it. 1.292 + listener = GetPaintListener(); 1.293 + if (!listener) { 1.294 + return false; 1.295 + } 1.296 + 1.297 + if (clientLayerManager && mCompositorParent && clientLayerManager->NeedsComposite()) { 1.298 + mCompositorParent->ScheduleRenderOnCompositorThread(); 1.299 + clientLayerManager->SetNeedsComposite(false); 1.300 + } 1.301 + 1.302 + bool result = true; 1.303 + if (!region.IsEmpty() && listener) 1.304 + { 1.305 + // Should probably pass in a real region here, using GetRandomRgn 1.306 + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/clipping_4q0e.asp 1.307 + 1.308 +#ifdef WIDGET_DEBUG_OUTPUT 1.309 + debug_DumpPaintEvent(stdout, 1.310 + this, 1.311 + region, 1.312 + nsAutoCString("noname"), 1.313 + (int32_t) mWnd); 1.314 +#endif // WIDGET_DEBUG_OUTPUT 1.315 + 1.316 + switch (GetLayerManager()->GetBackendType()) { 1.317 + case LayersBackend::LAYERS_BASIC: 1.318 + { 1.319 + nsRefPtr<gfxASurface> targetSurface; 1.320 + 1.321 +#if defined(MOZ_XUL) 1.322 + // don't support transparency for non-GDI rendering, for now 1.323 + if ((IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || 1.324 + IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) && 1.325 + eTransparencyTransparent == mTransparencyMode) { 1.326 + if (mTransparentSurface == nullptr) 1.327 + SetupTranslucentWindowMemoryBitmap(mTransparencyMode); 1.328 + targetSurface = mTransparentSurface; 1.329 + } 1.330 +#endif 1.331 + 1.332 + nsRefPtr<gfxWindowsSurface> targetSurfaceWin; 1.333 + if (!targetSurface && 1.334 + (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || 1.335 + IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D))) 1.336 + { 1.337 + uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 : 1.338 + gfxWindowsSurface::FLAG_IS_TRANSPARENT; 1.339 + targetSurfaceWin = new gfxWindowsSurface(hDC, flags); 1.340 + targetSurface = targetSurfaceWin; 1.341 + } 1.342 + 1.343 + nsRefPtr<gfxImageSurface> targetSurfaceImage; 1.344 + if (!targetSurface && 1.345 + (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH32) || 1.346 + IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24))) 1.347 + { 1.348 + gfxIntSize surfaceSize(ps.rcPaint.right - ps.rcPaint.left, 1.349 + ps.rcPaint.bottom - ps.rcPaint.top); 1.350 + 1.351 + if (!EnsureSharedSurfaceSize(surfaceSize)) { 1.352 + NS_ERROR("Couldn't allocate a shared image surface!"); 1.353 + return false; 1.354 + } 1.355 + 1.356 + // don't use the shared surface directly; instead, create a new one 1.357 + // that just reuses its buffer. 1.358 + targetSurfaceImage = new gfxImageSurface(sSharedSurfaceData.get(), 1.359 + surfaceSize, 1.360 + surfaceSize.width * 4, 1.361 + gfxImageFormat::RGB24); 1.362 + 1.363 + if (targetSurfaceImage && !targetSurfaceImage->CairoStatus()) { 1.364 + targetSurfaceImage->SetDeviceOffset(gfxPoint(-ps.rcPaint.left, -ps.rcPaint.top)); 1.365 + targetSurface = targetSurfaceImage; 1.366 + } 1.367 + } 1.368 + 1.369 + if (!targetSurface) { 1.370 + NS_ERROR("Invalid RenderMode!"); 1.371 + return false; 1.372 + } 1.373 + 1.374 + nsRefPtr<gfxContext> thebesContext; 1.375 + if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(mozilla::gfx::BackendType::CAIRO)) { 1.376 + RECT paintRect; 1.377 + ::GetClientRect(mWnd, &paintRect); 1.378 + RefPtr<mozilla::gfx::DrawTarget> dt = 1.379 + gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(targetSurface, 1.380 + mozilla::gfx::IntSize(paintRect.right - paintRect.left, 1.381 + paintRect.bottom - paintRect.top)); 1.382 + thebesContext = new gfxContext(dt); 1.383 + } else { 1.384 + thebesContext = new gfxContext(targetSurface); 1.385 + } 1.386 + 1.387 + // don't need to double buffer with anything but GDI 1.388 + BufferMode doubleBuffering = mozilla::layers::BufferMode::BUFFER_NONE; 1.389 + if (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || 1.390 + IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) { 1.391 +#ifdef MOZ_XUL 1.392 + switch (mTransparencyMode) { 1.393 + case eTransparencyGlass: 1.394 + case eTransparencyBorderlessGlass: 1.395 + default: 1.396 + // If we're not doing translucency, then double buffer 1.397 + doubleBuffering = mozilla::layers::BufferMode::BUFFERED; 1.398 + break; 1.399 + case eTransparencyTransparent: 1.400 + // If we're rendering with translucency, we're going to be 1.401 + // rendering the whole window; make sure we clear it first 1.402 + thebesContext->SetOperator(gfxContext::OPERATOR_CLEAR); 1.403 + thebesContext->Paint(); 1.404 + thebesContext->SetOperator(gfxContext::OPERATOR_OVER); 1.405 + break; 1.406 + } 1.407 +#else 1.408 + doubleBuffering = mozilla::layers::BufferMode::BUFFERED; 1.409 +#endif 1.410 + } 1.411 + 1.412 + { 1.413 + AutoLayerManagerSetup 1.414 + setupLayerManager(this, thebesContext, doubleBuffering); 1.415 + result = listener->PaintWindow(this, region); 1.416 + } 1.417 + 1.418 +#ifdef MOZ_XUL 1.419 + if ((IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || 1.420 + IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D))&& 1.421 + eTransparencyTransparent == mTransparencyMode) { 1.422 + // Data from offscreen drawing surface was copied to memory bitmap of transparent 1.423 + // bitmap. Now it can be read from memory bitmap to apply alpha channel and after 1.424 + // that displayed on the screen. 1.425 + UpdateTranslucentWindow(); 1.426 + } else 1.427 +#endif 1.428 + 1.429 + if (result) { 1.430 + if (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24) || 1.431 + IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH32)) 1.432 + { 1.433 + gfxIntSize surfaceSize = targetSurfaceImage->GetSize(); 1.434 + 1.435 + // Just blit this directly 1.436 + BITMAPINFOHEADER bi; 1.437 + memset(&bi, 0, sizeof(BITMAPINFOHEADER)); 1.438 + bi.biSize = sizeof(BITMAPINFOHEADER); 1.439 + bi.biWidth = surfaceSize.width; 1.440 + bi.biHeight = - surfaceSize.height; 1.441 + bi.biPlanes = 1; 1.442 + bi.biBitCount = 32; 1.443 + bi.biCompression = BI_RGB; 1.444 + 1.445 + if (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24)) { 1.446 + // On Windows CE/Windows Mobile, 24bpp packed-pixel sources 1.447 + // seem to be far faster to blit than 32bpp (see bug 484864). 1.448 + // So, convert the bits to 24bpp by stripping out the unused 1.449 + // alpha byte. 24bpp DIBs also have scanlines that are 4-byte 1.450 + // aligned though, so that must be taken into account. 1.451 + int srcstride = surfaceSize.width*4; 1.452 + int dststride = surfaceSize.width*3; 1.453 + dststride = (dststride + 3) & ~3; 1.454 + 1.455 + // Convert in place 1.456 + for (int j = 0; j < surfaceSize.height; ++j) { 1.457 + unsigned int *src = (unsigned int*) (targetSurfaceImage->Data() + j*srcstride); 1.458 + unsigned int *dst = (unsigned int*) (targetSurfaceImage->Data() + j*dststride); 1.459 + 1.460 + // go 4 pixels at a time, since each 4 pixels 1.461 + // turns into 3 DWORDs when converted into BGR: 1.462 + // BGRx BGRx BGRx BGRx -> BGRB GRBG RBGR 1.463 + // 1.464 + // However, since we're dealing with little-endian ints, this is actually: 1.465 + // xRGB xrgb xRGB xrgb -> bRGB GBrg rgbR 1.466 + int width_left = surfaceSize.width; 1.467 + while (width_left >= 4) { 1.468 + unsigned int a = *src++; 1.469 + unsigned int b = *src++; 1.470 + unsigned int c = *src++; 1.471 + unsigned int d = *src++; 1.472 + 1.473 + *dst++ = (a & 0x00ffffff) | (b << 24); 1.474 + *dst++ = ((b & 0x00ffff00) >> 8) | (c << 16); 1.475 + *dst++ = ((c & 0x00ff0000) >> 16) | (d << 8); 1.476 + 1.477 + width_left -= 4; 1.478 + } 1.479 + 1.480 + // then finish up whatever number of pixels are left, 1.481 + // using bytes. 1.482 + unsigned char *bsrc = (unsigned char*) src; 1.483 + unsigned char *bdst = (unsigned char*) dst; 1.484 + switch (width_left) { 1.485 + case 3: 1.486 + *bdst++ = *bsrc++; 1.487 + *bdst++ = *bsrc++; 1.488 + *bdst++ = *bsrc++; 1.489 + bsrc++; 1.490 + case 2: 1.491 + *bdst++ = *bsrc++; 1.492 + *bdst++ = *bsrc++; 1.493 + *bdst++ = *bsrc++; 1.494 + bsrc++; 1.495 + case 1: 1.496 + *bdst++ = *bsrc++; 1.497 + *bdst++ = *bsrc++; 1.498 + *bdst++ = *bsrc++; 1.499 + bsrc++; 1.500 + case 0: 1.501 + break; 1.502 + } 1.503 + } 1.504 + 1.505 + bi.biBitCount = 24; 1.506 + } 1.507 + 1.508 + StretchDIBits(hDC, 1.509 + ps.rcPaint.left, ps.rcPaint.top, 1.510 + surfaceSize.width, surfaceSize.height, 1.511 + 0, 0, 1.512 + surfaceSize.width, surfaceSize.height, 1.513 + targetSurfaceImage->Data(), 1.514 + (BITMAPINFO*) &bi, 1.515 + DIB_RGB_COLORS, 1.516 + SRCCOPY); 1.517 + } 1.518 + } 1.519 + } 1.520 + break; 1.521 +#ifdef MOZ_ENABLE_D3D9_LAYER 1.522 + case LayersBackend::LAYERS_D3D9: 1.523 + { 1.524 + nsRefPtr<LayerManagerD3D9> layerManagerD3D9 = 1.525 + static_cast<mozilla::layers::LayerManagerD3D9*>(GetLayerManager()); 1.526 + layerManagerD3D9->SetClippingRegion(region); 1.527 + result = listener->PaintWindow(this, region); 1.528 + if (layerManagerD3D9->DeviceWasRemoved()) { 1.529 + mLayerManager->Destroy(); 1.530 + mLayerManager = nullptr; 1.531 + // When our device was removed, we should have gfxWindowsPlatform 1.532 + // check if its render mode is up to date! 1.533 + gfxWindowsPlatform::GetPlatform()->UpdateRenderMode(); 1.534 + Invalidate(); 1.535 + } 1.536 + } 1.537 + break; 1.538 +#endif 1.539 +#ifdef MOZ_ENABLE_D3D10_LAYER 1.540 + case LayersBackend::LAYERS_D3D10: 1.541 + { 1.542 + gfxWindowsPlatform::GetPlatform()->UpdateRenderMode(); 1.543 + LayerManagerD3D10 *layerManagerD3D10 = static_cast<mozilla::layers::LayerManagerD3D10*>(GetLayerManager()); 1.544 + if (layerManagerD3D10->device() != gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) { 1.545 + Invalidate(); 1.546 + } else { 1.547 + result = listener->PaintWindow(this, region); 1.548 + } 1.549 + } 1.550 + break; 1.551 +#endif 1.552 + case LayersBackend::LAYERS_CLIENT: 1.553 + result = listener->PaintWindow(this, region); 1.554 + break; 1.555 + default: 1.556 + NS_ERROR("Unknown layers backend used!"); 1.557 + break; 1.558 + } 1.559 + } 1.560 + 1.561 + if (!aDC) { 1.562 + ::EndPaint(mWnd, &ps); 1.563 + } 1.564 + 1.565 + mPaintDC = nullptr; 1.566 + mLastPaintEndTime = TimeStamp::Now(); 1.567 + 1.568 +#if defined(WIDGET_DEBUG_OUTPUT) 1.569 + if (debug_WantPaintFlashing()) 1.570 + { 1.571 + // Only flash paint events which have not ignored the paint message. 1.572 + // Those that ignore the paint message aren't painting anything so there 1.573 + // is only the overhead of the dispatching the paint event. 1.574 + if (result) { 1.575 + ::InvertRgn(debugPaintFlashDC, debugPaintFlashRegion); 1.576 + PR_Sleep(PR_MillisecondsToInterval(30)); 1.577 + ::InvertRgn(debugPaintFlashDC, debugPaintFlashRegion); 1.578 + PR_Sleep(PR_MillisecondsToInterval(30)); 1.579 + } 1.580 + ::ReleaseDC(mWnd, debugPaintFlashDC); 1.581 + ::DeleteObject(debugPaintFlashRegion); 1.582 + } 1.583 +#endif // WIDGET_DEBUG_OUTPUT 1.584 + 1.585 + mPainting = false; 1.586 + 1.587 + // Re-get the listener since painting may have killed it. 1.588 + listener = GetPaintListener(); 1.589 + if (listener) 1.590 + listener->DidPaintWindow(); 1.591 + 1.592 + if (aNestingLevel == 0 && ::GetUpdateRect(mWnd, nullptr, false)) { 1.593 + OnPaint(aDC, 1); 1.594 + } 1.595 + 1.596 + return result; 1.597 +} 1.598 + 1.599 +gfxIntSize nsWindowGfx::GetIconMetrics(IconSizeType aSizeType) { 1.600 + int32_t width = ::GetSystemMetrics(sIconMetrics[aSizeType].xMetric); 1.601 + int32_t height = ::GetSystemMetrics(sIconMetrics[aSizeType].yMetric); 1.602 + 1.603 + if (width == 0 || height == 0) { 1.604 + width = height = sIconMetrics[aSizeType].defaultSize; 1.605 + } 1.606 + 1.607 + return gfxIntSize(width, height); 1.608 +} 1.609 + 1.610 +nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer, 1.611 + bool aIsCursor, 1.612 + uint32_t aHotspotX, 1.613 + uint32_t aHotspotY, 1.614 + gfxIntSize aScaledSize, 1.615 + HICON *aIcon) { 1.616 + 1.617 + MOZ_ASSERT((aScaledSize.width > 0 && aScaledSize.height > 0) || 1.618 + (aScaledSize.width == 0 && aScaledSize.height == 0)); 1.619 + 1.620 + // Get the image data 1.621 + RefPtr<SourceSurface> surface = 1.622 + aContainer->GetFrame(imgIContainer::FRAME_CURRENT, 1.623 + imgIContainer::FLAG_SYNC_DECODE); 1.624 + NS_ENSURE_TRUE(surface, NS_ERROR_NOT_AVAILABLE); 1.625 + 1.626 + IntSize frameSize = surface->GetSize(); 1.627 + if (frameSize.IsEmpty()) { 1.628 + return NS_ERROR_FAILURE; 1.629 + } 1.630 + 1.631 + IntSize iconSize(aScaledSize.width, aScaledSize.height); 1.632 + if (iconSize == IntSize(0, 0)) { // use frame's intrinsic size 1.633 + iconSize = frameSize; 1.634 + } 1.635 + 1.636 + RefPtr<DataSourceSurface> dataSurface; 1.637 + bool mappedOK; 1.638 + DataSourceSurface::MappedSurface map; 1.639 + 1.640 + if (iconSize != frameSize) { 1.641 + // Scale the surface 1.642 + dataSurface = Factory::CreateDataSourceSurface(iconSize, 1.643 + SurfaceFormat::B8G8R8A8); 1.644 + NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); 1.645 + mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map); 1.646 + NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE); 1.647 + 1.648 + RefPtr<DrawTarget> dt = 1.649 + Factory::CreateDrawTargetForData(BackendType::CAIRO, 1.650 + map.mData, 1.651 + dataSurface->GetSize(), 1.652 + map.mStride, 1.653 + SurfaceFormat::B8G8R8A8); 1.654 + dt->DrawSurface(surface, 1.655 + Rect(0, 0, iconSize.width, iconSize.height), 1.656 + Rect(0, 0, frameSize.width, frameSize.height), 1.657 + DrawSurfaceOptions(), 1.658 + DrawOptions(1.0f, CompositionOp::OP_SOURCE)); 1.659 + } else if (surface->GetFormat() != SurfaceFormat::B8G8R8A8) { 1.660 + // Convert format to SurfaceFormat::B8G8R8A8 1.661 + dataSurface = gfxUtils:: 1.662 + CopySurfaceToDataSourceSurfaceWithFormat(surface, 1.663 + SurfaceFormat::B8G8R8A8); 1.664 + NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); 1.665 + mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map); 1.666 + } else { 1.667 + dataSurface = surface->GetDataSurface(); 1.668 + NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); 1.669 + mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map); 1.670 + } 1.671 + NS_ENSURE_TRUE(dataSurface && mappedOK, NS_ERROR_FAILURE); 1.672 + MOZ_ASSERT(dataSurface->GetFormat() == SurfaceFormat::B8G8R8A8); 1.673 + 1.674 + uint8_t* data = nullptr; 1.675 + nsAutoArrayPtr<uint8_t> autoDeleteArray; 1.676 + if (map.mStride == BytesPerPixel(dataSurface->GetFormat()) * iconSize.width) { 1.677 + // Mapped data is already packed 1.678 + data = map.mData; 1.679 + } else { 1.680 + // We can't use map.mData since the pixels are not packed (as required by 1.681 + // CreateDIBitmap, which is called under the DataToBitmap call below). 1.682 + // 1.683 + // We must unmap before calling SurfaceToPackedBGRA because it needs access 1.684 + // to the pixel data. 1.685 + dataSurface->Unmap(); 1.686 + map.mData = nullptr; 1.687 + 1.688 + data = autoDeleteArray = SurfaceToPackedBGRA(dataSurface); 1.689 + NS_ENSURE_TRUE(data, NS_ERROR_FAILURE); 1.690 + } 1.691 + 1.692 + HBITMAP bmp = DataToBitmap(data, iconSize.width, -iconSize.height, 32); 1.693 + uint8_t* a1data = Data32BitTo1Bit(data, iconSize.width, iconSize.height); 1.694 + if (map.mData) { 1.695 + dataSurface->Unmap(); 1.696 + } 1.697 + if (!a1data) { 1.698 + return NS_ERROR_FAILURE; 1.699 + } 1.700 + 1.701 + HBITMAP mbmp = DataToBitmap(a1data, iconSize.width, -iconSize.height, 1); 1.702 + PR_Free(a1data); 1.703 + 1.704 + ICONINFO info = {0}; 1.705 + info.fIcon = !aIsCursor; 1.706 + info.xHotspot = aHotspotX; 1.707 + info.yHotspot = aHotspotY; 1.708 + info.hbmMask = mbmp; 1.709 + info.hbmColor = bmp; 1.710 + 1.711 + HCURSOR icon = ::CreateIconIndirect(&info); 1.712 + ::DeleteObject(mbmp); 1.713 + ::DeleteObject(bmp); 1.714 + if (!icon) 1.715 + return NS_ERROR_FAILURE; 1.716 + *aIcon = icon; 1.717 + return NS_OK; 1.718 +} 1.719 + 1.720 +// Adjust cursor image data 1.721 +uint8_t* nsWindowGfx::Data32BitTo1Bit(uint8_t* aImageData, 1.722 + uint32_t aWidth, uint32_t aHeight) 1.723 +{ 1.724 + // We need (aWidth + 7) / 8 bytes plus zero-padding up to a multiple of 1.725 + // 4 bytes for each row (HBITMAP requirement). Bug 353553. 1.726 + uint32_t outBpr = ((aWidth + 31) / 8) & ~3; 1.727 + 1.728 + // Allocate and clear mask buffer 1.729 + uint8_t* outData = (uint8_t*)PR_Calloc(outBpr, aHeight); 1.730 + if (!outData) 1.731 + return nullptr; 1.732 + 1.733 + int32_t *imageRow = (int32_t*)aImageData; 1.734 + for (uint32_t curRow = 0; curRow < aHeight; curRow++) { 1.735 + uint8_t *outRow = outData + curRow * outBpr; 1.736 + uint8_t mask = 0x80; 1.737 + for (uint32_t curCol = 0; curCol < aWidth; curCol++) { 1.738 + // Use sign bit to test for transparency, as alpha byte is highest byte 1.739 + if (*imageRow++ < 0) 1.740 + *outRow |= mask; 1.741 + 1.742 + mask >>= 1; 1.743 + if (!mask) { 1.744 + outRow ++; 1.745 + mask = 0x80; 1.746 + } 1.747 + } 1.748 + } 1.749 + 1.750 + return outData; 1.751 +} 1.752 + 1.753 +/** 1.754 + * Convert the given image data to a HBITMAP. If the requested depth is 1.755 + * 32 bit, a bitmap with an alpha channel will be returned. 1.756 + * 1.757 + * @param aImageData The image data to convert. Must use the format accepted 1.758 + * by CreateDIBitmap. 1.759 + * @param aWidth With of the bitmap, in pixels. 1.760 + * @param aHeight Height of the image, in pixels. 1.761 + * @param aDepth Image depth, in bits. Should be one of 1, 24 and 32. 1.762 + * 1.763 + * @return The HBITMAP representing the image. Caller should call 1.764 + * DeleteObject when done with the bitmap. 1.765 + * On failure, nullptr will be returned. 1.766 + */ 1.767 +HBITMAP nsWindowGfx::DataToBitmap(uint8_t* aImageData, 1.768 + uint32_t aWidth, 1.769 + uint32_t aHeight, 1.770 + uint32_t aDepth) 1.771 +{ 1.772 + HDC dc = ::GetDC(nullptr); 1.773 + 1.774 + if (aDepth == 32) { 1.775 + // Alpha channel. We need the new header. 1.776 + BITMAPV4HEADER head = { 0 }; 1.777 + head.bV4Size = sizeof(head); 1.778 + head.bV4Width = aWidth; 1.779 + head.bV4Height = aHeight; 1.780 + head.bV4Planes = 1; 1.781 + head.bV4BitCount = aDepth; 1.782 + head.bV4V4Compression = BI_BITFIELDS; 1.783 + head.bV4SizeImage = 0; // Uncompressed 1.784 + head.bV4XPelsPerMeter = 0; 1.785 + head.bV4YPelsPerMeter = 0; 1.786 + head.bV4ClrUsed = 0; 1.787 + head.bV4ClrImportant = 0; 1.788 + 1.789 + head.bV4RedMask = 0x00FF0000; 1.790 + head.bV4GreenMask = 0x0000FF00; 1.791 + head.bV4BlueMask = 0x000000FF; 1.792 + head.bV4AlphaMask = 0xFF000000; 1.793 + 1.794 + HBITMAP bmp = ::CreateDIBitmap(dc, 1.795 + reinterpret_cast<CONST BITMAPINFOHEADER*>(&head), 1.796 + CBM_INIT, 1.797 + aImageData, 1.798 + reinterpret_cast<CONST BITMAPINFO*>(&head), 1.799 + DIB_RGB_COLORS); 1.800 + ::ReleaseDC(nullptr, dc); 1.801 + return bmp; 1.802 + } 1.803 + 1.804 + char reserved_space[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2]; 1.805 + BITMAPINFOHEADER& head = *(BITMAPINFOHEADER*)reserved_space; 1.806 + 1.807 + head.biSize = sizeof(BITMAPINFOHEADER); 1.808 + head.biWidth = aWidth; 1.809 + head.biHeight = aHeight; 1.810 + head.biPlanes = 1; 1.811 + head.biBitCount = (WORD)aDepth; 1.812 + head.biCompression = BI_RGB; 1.813 + head.biSizeImage = 0; // Uncompressed 1.814 + head.biXPelsPerMeter = 0; 1.815 + head.biYPelsPerMeter = 0; 1.816 + head.biClrUsed = 0; 1.817 + head.biClrImportant = 0; 1.818 + 1.819 + BITMAPINFO& bi = *(BITMAPINFO*)reserved_space; 1.820 + 1.821 + if (aDepth == 1) { 1.822 + RGBQUAD black = { 0, 0, 0, 0 }; 1.823 + RGBQUAD white = { 255, 255, 255, 0 }; 1.824 + 1.825 + bi.bmiColors[0] = white; 1.826 + bi.bmiColors[1] = black; 1.827 + } 1.828 + 1.829 + HBITMAP bmp = ::CreateDIBitmap(dc, &head, CBM_INIT, aImageData, &bi, DIB_RGB_COLORS); 1.830 + ::ReleaseDC(nullptr, dc); 1.831 + return bmp; 1.832 +}