Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | /* |
michael@0 | 7 | * nsWindowGfx - Painting and aceleration. |
michael@0 | 8 | */ |
michael@0 | 9 | |
michael@0 | 10 | // XXX Future: this should really be a stand alone class stored as |
michael@0 | 11 | // a member of nsWindow with getters and setters for things like render |
michael@0 | 12 | // mode and methods for handling paint. |
michael@0 | 13 | |
michael@0 | 14 | /************************************************************** |
michael@0 | 15 | ************************************************************** |
michael@0 | 16 | ** |
michael@0 | 17 | ** BLOCK: Includes |
michael@0 | 18 | ** |
michael@0 | 19 | ** Include headers. |
michael@0 | 20 | ** |
michael@0 | 21 | ************************************************************** |
michael@0 | 22 | **************************************************************/ |
michael@0 | 23 | |
michael@0 | 24 | #include "mozilla/plugins/PluginInstanceParent.h" |
michael@0 | 25 | using mozilla::plugins::PluginInstanceParent; |
michael@0 | 26 | |
michael@0 | 27 | #include "nsWindowGfx.h" |
michael@0 | 28 | #include <windows.h> |
michael@0 | 29 | #include "gfxImageSurface.h" |
michael@0 | 30 | #include "gfxUtils.h" |
michael@0 | 31 | #include "gfxWindowsSurface.h" |
michael@0 | 32 | #include "gfxWindowsPlatform.h" |
michael@0 | 33 | #include "mozilla/gfx/2D.h" |
michael@0 | 34 | #include "mozilla/gfx/DataSurfaceHelpers.h" |
michael@0 | 35 | #include "mozilla/gfx/Tools.h" |
michael@0 | 36 | #include "mozilla/RefPtr.h" |
michael@0 | 37 | #include "nsGfxCIID.h" |
michael@0 | 38 | #include "gfxContext.h" |
michael@0 | 39 | #include "nsRenderingContext.h" |
michael@0 | 40 | #include "prmem.h" |
michael@0 | 41 | #include "WinUtils.h" |
michael@0 | 42 | #include "nsIWidgetListener.h" |
michael@0 | 43 | #include "mozilla/unused.h" |
michael@0 | 44 | |
michael@0 | 45 | #ifdef MOZ_ENABLE_D3D9_LAYER |
michael@0 | 46 | #include "LayerManagerD3D9.h" |
michael@0 | 47 | #endif |
michael@0 | 48 | #ifdef MOZ_ENABLE_D3D10_LAYER |
michael@0 | 49 | #include "LayerManagerD3D10.h" |
michael@0 | 50 | #endif |
michael@0 | 51 | #include "mozilla/layers/CompositorParent.h" |
michael@0 | 52 | #include "ClientLayerManager.h" |
michael@0 | 53 | |
michael@0 | 54 | #include "nsUXThemeData.h" |
michael@0 | 55 | #include "nsUXThemeConstants.h" |
michael@0 | 56 | |
michael@0 | 57 | extern "C" { |
michael@0 | 58 | #define PIXMAN_DONT_DEFINE_STDINT |
michael@0 | 59 | #include "pixman.h" |
michael@0 | 60 | } |
michael@0 | 61 | |
michael@0 | 62 | using namespace mozilla; |
michael@0 | 63 | using namespace mozilla::gfx; |
michael@0 | 64 | using namespace mozilla::layers; |
michael@0 | 65 | using namespace mozilla::widget; |
michael@0 | 66 | |
michael@0 | 67 | /************************************************************** |
michael@0 | 68 | ************************************************************** |
michael@0 | 69 | ** |
michael@0 | 70 | ** BLOCK: Variables |
michael@0 | 71 | ** |
michael@0 | 72 | ** nsWindow Class static initializations and global variables. |
michael@0 | 73 | ** |
michael@0 | 74 | ************************************************************** |
michael@0 | 75 | **************************************************************/ |
michael@0 | 76 | |
michael@0 | 77 | /************************************************************** |
michael@0 | 78 | * |
michael@0 | 79 | * SECTION: nsWindow statics |
michael@0 | 80 | * |
michael@0 | 81 | **************************************************************/ |
michael@0 | 82 | |
michael@0 | 83 | static nsAutoPtr<uint8_t> sSharedSurfaceData; |
michael@0 | 84 | static gfxIntSize sSharedSurfaceSize; |
michael@0 | 85 | |
michael@0 | 86 | struct IconMetrics { |
michael@0 | 87 | int32_t xMetric; |
michael@0 | 88 | int32_t yMetric; |
michael@0 | 89 | int32_t defaultSize; |
michael@0 | 90 | }; |
michael@0 | 91 | |
michael@0 | 92 | // Corresponds 1:1 to the IconSizeType enum |
michael@0 | 93 | static IconMetrics sIconMetrics[] = { |
michael@0 | 94 | {SM_CXSMICON, SM_CYSMICON, 16}, // small icon |
michael@0 | 95 | {SM_CXICON, SM_CYICON, 32} // regular icon |
michael@0 | 96 | }; |
michael@0 | 97 | |
michael@0 | 98 | /************************************************************** |
michael@0 | 99 | ************************************************************** |
michael@0 | 100 | ** |
michael@0 | 101 | ** BLOCK: nsWindowGfx impl. |
michael@0 | 102 | ** |
michael@0 | 103 | ** Misc. graphics related utilities. |
michael@0 | 104 | ** |
michael@0 | 105 | ************************************************************** |
michael@0 | 106 | **************************************************************/ |
michael@0 | 107 | |
michael@0 | 108 | /* static */ bool |
michael@0 | 109 | nsWindow::IsRenderMode(gfxWindowsPlatform::RenderMode rmode) |
michael@0 | 110 | { |
michael@0 | 111 | return gfxWindowsPlatform::GetPlatform()->GetRenderMode() == rmode; |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | /************************************************************** |
michael@0 | 115 | ************************************************************** |
michael@0 | 116 | ** |
michael@0 | 117 | ** BLOCK: nsWindow impl. |
michael@0 | 118 | ** |
michael@0 | 119 | ** Paint related nsWindow methods. |
michael@0 | 120 | ** |
michael@0 | 121 | ************************************************************** |
michael@0 | 122 | **************************************************************/ |
michael@0 | 123 | |
michael@0 | 124 | // GetRegionToPaint returns the invalidated region that needs to be painted |
michael@0 | 125 | nsIntRegion nsWindow::GetRegionToPaint(bool aForceFullRepaint, |
michael@0 | 126 | PAINTSTRUCT ps, HDC aDC) |
michael@0 | 127 | { |
michael@0 | 128 | if (aForceFullRepaint) { |
michael@0 | 129 | RECT paintRect; |
michael@0 | 130 | ::GetClientRect(mWnd, &paintRect); |
michael@0 | 131 | return nsIntRegion(WinUtils::ToIntRect(paintRect)); |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | HRGN paintRgn = ::CreateRectRgn(0, 0, 0, 0); |
michael@0 | 135 | if (paintRgn != nullptr) { |
michael@0 | 136 | int result = GetRandomRgn(aDC, paintRgn, SYSRGN); |
michael@0 | 137 | if (result == 1) { |
michael@0 | 138 | POINT pt = {0,0}; |
michael@0 | 139 | ::MapWindowPoints(nullptr, mWnd, &pt, 1); |
michael@0 | 140 | ::OffsetRgn(paintRgn, pt.x, pt.y); |
michael@0 | 141 | } |
michael@0 | 142 | nsIntRegion rgn(WinUtils::ConvertHRGNToRegion(paintRgn)); |
michael@0 | 143 | ::DeleteObject(paintRgn); |
michael@0 | 144 | return rgn; |
michael@0 | 145 | } |
michael@0 | 146 | return nsIntRegion(WinUtils::ToIntRect(ps.rcPaint)); |
michael@0 | 147 | } |
michael@0 | 148 | |
michael@0 | 149 | #define WORDSSIZE(x) ((x).width * (x).height) |
michael@0 | 150 | static bool |
michael@0 | 151 | EnsureSharedSurfaceSize(gfxIntSize size) |
michael@0 | 152 | { |
michael@0 | 153 | gfxIntSize screenSize; |
michael@0 | 154 | screenSize.height = GetSystemMetrics(SM_CYSCREEN); |
michael@0 | 155 | screenSize.width = GetSystemMetrics(SM_CXSCREEN); |
michael@0 | 156 | |
michael@0 | 157 | if (WORDSSIZE(screenSize) > WORDSSIZE(size)) |
michael@0 | 158 | size = screenSize; |
michael@0 | 159 | |
michael@0 | 160 | if (WORDSSIZE(screenSize) < WORDSSIZE(size)) |
michael@0 | 161 | NS_WARNING("Trying to create a shared surface larger than the screen"); |
michael@0 | 162 | |
michael@0 | 163 | if (!sSharedSurfaceData || (WORDSSIZE(size) > WORDSSIZE(sSharedSurfaceSize))) { |
michael@0 | 164 | sSharedSurfaceSize = size; |
michael@0 | 165 | sSharedSurfaceData = nullptr; |
michael@0 | 166 | sSharedSurfaceData = (uint8_t *)malloc(WORDSSIZE(sSharedSurfaceSize) * 4); |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | return (sSharedSurfaceData != nullptr); |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | nsIWidgetListener* nsWindow::GetPaintListener() |
michael@0 | 173 | { |
michael@0 | 174 | if (mDestroyCalled) |
michael@0 | 175 | return nullptr; |
michael@0 | 176 | return mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) |
michael@0 | 180 | { |
michael@0 | 181 | // We never have reentrant paint events, except when we're running our RPC |
michael@0 | 182 | // windows event spin loop. If we don't trap for this, we'll try to paint, |
michael@0 | 183 | // but view manager will refuse to paint the surface, resulting is black |
michael@0 | 184 | // flashes on the plugin rendering surface. |
michael@0 | 185 | if (mozilla::ipc::MessageChannel::IsSpinLoopActive() && mPainting) |
michael@0 | 186 | return false; |
michael@0 | 187 | |
michael@0 | 188 | if (mWindowType == eWindowType_plugin) { |
michael@0 | 189 | |
michael@0 | 190 | /** |
michael@0 | 191 | * After we CallUpdateWindow to the child, occasionally a WM_PAINT message |
michael@0 | 192 | * is posted to the parent event loop with an empty update rect. Do a |
michael@0 | 193 | * dummy paint so that Windows stops dispatching WM_PAINT in an inifinite |
michael@0 | 194 | * loop. See bug 543788. |
michael@0 | 195 | */ |
michael@0 | 196 | RECT updateRect; |
michael@0 | 197 | if (!GetUpdateRect(mWnd, &updateRect, FALSE) || |
michael@0 | 198 | (updateRect.left == updateRect.right && |
michael@0 | 199 | updateRect.top == updateRect.bottom)) { |
michael@0 | 200 | PAINTSTRUCT ps; |
michael@0 | 201 | BeginPaint(mWnd, &ps); |
michael@0 | 202 | EndPaint(mWnd, &ps); |
michael@0 | 203 | return true; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | PluginInstanceParent* instance = reinterpret_cast<PluginInstanceParent*>( |
michael@0 | 207 | ::GetPropW(mWnd, L"PluginInstanceParentProperty")); |
michael@0 | 208 | if (instance) { |
michael@0 | 209 | unused << instance->CallUpdateWindow(); |
michael@0 | 210 | } else { |
michael@0 | 211 | // We should never get here since in-process plugins should have |
michael@0 | 212 | // subclassed our HWND and handled WM_PAINT, but in some cases that |
michael@0 | 213 | // could fail. Return without asserting since it's not our fault. |
michael@0 | 214 | NS_WARNING("Plugin failed to subclass our window"); |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | ValidateRect(mWnd, nullptr); |
michael@0 | 218 | return true; |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | ClientLayerManager *clientLayerManager = |
michael@0 | 222 | (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) |
michael@0 | 223 | ? static_cast<ClientLayerManager*>(GetLayerManager()) |
michael@0 | 224 | : nullptr; |
michael@0 | 225 | |
michael@0 | 226 | if (clientLayerManager && mCompositorParent && |
michael@0 | 227 | !mBounds.IsEqualEdges(mLastPaintBounds)) |
michael@0 | 228 | { |
michael@0 | 229 | // Do an early async composite so that we at least have something on the |
michael@0 | 230 | // screen in the right place, even if the content is out of date. |
michael@0 | 231 | mCompositorParent->ScheduleRenderOnCompositorThread(); |
michael@0 | 232 | } |
michael@0 | 233 | mLastPaintBounds = mBounds; |
michael@0 | 234 | |
michael@0 | 235 | PAINTSTRUCT ps; |
michael@0 | 236 | |
michael@0 | 237 | #ifdef MOZ_XUL |
michael@0 | 238 | if (!aDC && (eTransparencyTransparent == mTransparencyMode)) |
michael@0 | 239 | { |
michael@0 | 240 | // For layered translucent windows all drawing should go to memory DC and no |
michael@0 | 241 | // WM_PAINT messages are normally generated. To support asynchronous painting |
michael@0 | 242 | // we force generation of WM_PAINT messages by invalidating window areas with |
michael@0 | 243 | // RedrawWindow, InvalidateRect or InvalidateRgn function calls. |
michael@0 | 244 | // BeginPaint/EndPaint must be called to make Windows think that invalid area |
michael@0 | 245 | // is painted. Otherwise it will continue sending the same message endlessly. |
michael@0 | 246 | ::BeginPaint(mWnd, &ps); |
michael@0 | 247 | ::EndPaint(mWnd, &ps); |
michael@0 | 248 | |
michael@0 | 249 | aDC = mMemoryDC; |
michael@0 | 250 | } |
michael@0 | 251 | #endif |
michael@0 | 252 | |
michael@0 | 253 | mPainting = true; |
michael@0 | 254 | |
michael@0 | 255 | #ifdef WIDGET_DEBUG_OUTPUT |
michael@0 | 256 | HRGN debugPaintFlashRegion = nullptr; |
michael@0 | 257 | HDC debugPaintFlashDC = nullptr; |
michael@0 | 258 | |
michael@0 | 259 | if (debug_WantPaintFlashing()) |
michael@0 | 260 | { |
michael@0 | 261 | debugPaintFlashRegion = ::CreateRectRgn(0, 0, 0, 0); |
michael@0 | 262 | ::GetUpdateRgn(mWnd, debugPaintFlashRegion, TRUE); |
michael@0 | 263 | debugPaintFlashDC = ::GetDC(mWnd); |
michael@0 | 264 | } |
michael@0 | 265 | #endif // WIDGET_DEBUG_OUTPUT |
michael@0 | 266 | |
michael@0 | 267 | HDC hDC = aDC ? aDC : (::BeginPaint(mWnd, &ps)); |
michael@0 | 268 | mPaintDC = hDC; |
michael@0 | 269 | |
michael@0 | 270 | #ifdef MOZ_XUL |
michael@0 | 271 | bool forceRepaint = aDC || (eTransparencyTransparent == mTransparencyMode); |
michael@0 | 272 | #else |
michael@0 | 273 | bool forceRepaint = nullptr != aDC; |
michael@0 | 274 | #endif |
michael@0 | 275 | nsIntRegion region = GetRegionToPaint(forceRepaint, ps, hDC); |
michael@0 | 276 | |
michael@0 | 277 | if (clientLayerManager && mCompositorParent) { |
michael@0 | 278 | // We need to paint to the screen even if nothing changed, since if we |
michael@0 | 279 | // don't have a compositing window manager, our pixels could be stale. |
michael@0 | 280 | clientLayerManager->SetNeedsComposite(true); |
michael@0 | 281 | clientLayerManager->SendInvalidRegion(region); |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | nsIWidgetListener* listener = GetPaintListener(); |
michael@0 | 285 | if (listener) { |
michael@0 | 286 | listener->WillPaintWindow(this); |
michael@0 | 287 | } |
michael@0 | 288 | // Re-get the listener since the will paint notification may have killed it. |
michael@0 | 289 | listener = GetPaintListener(); |
michael@0 | 290 | if (!listener) { |
michael@0 | 291 | return false; |
michael@0 | 292 | } |
michael@0 | 293 | |
michael@0 | 294 | if (clientLayerManager && mCompositorParent && clientLayerManager->NeedsComposite()) { |
michael@0 | 295 | mCompositorParent->ScheduleRenderOnCompositorThread(); |
michael@0 | 296 | clientLayerManager->SetNeedsComposite(false); |
michael@0 | 297 | } |
michael@0 | 298 | |
michael@0 | 299 | bool result = true; |
michael@0 | 300 | if (!region.IsEmpty() && listener) |
michael@0 | 301 | { |
michael@0 | 302 | // Should probably pass in a real region here, using GetRandomRgn |
michael@0 | 303 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/clipping_4q0e.asp |
michael@0 | 304 | |
michael@0 | 305 | #ifdef WIDGET_DEBUG_OUTPUT |
michael@0 | 306 | debug_DumpPaintEvent(stdout, |
michael@0 | 307 | this, |
michael@0 | 308 | region, |
michael@0 | 309 | nsAutoCString("noname"), |
michael@0 | 310 | (int32_t) mWnd); |
michael@0 | 311 | #endif // WIDGET_DEBUG_OUTPUT |
michael@0 | 312 | |
michael@0 | 313 | switch (GetLayerManager()->GetBackendType()) { |
michael@0 | 314 | case LayersBackend::LAYERS_BASIC: |
michael@0 | 315 | { |
michael@0 | 316 | nsRefPtr<gfxASurface> targetSurface; |
michael@0 | 317 | |
michael@0 | 318 | #if defined(MOZ_XUL) |
michael@0 | 319 | // don't support transparency for non-GDI rendering, for now |
michael@0 | 320 | if ((IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || |
michael@0 | 321 | IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) && |
michael@0 | 322 | eTransparencyTransparent == mTransparencyMode) { |
michael@0 | 323 | if (mTransparentSurface == nullptr) |
michael@0 | 324 | SetupTranslucentWindowMemoryBitmap(mTransparencyMode); |
michael@0 | 325 | targetSurface = mTransparentSurface; |
michael@0 | 326 | } |
michael@0 | 327 | #endif |
michael@0 | 328 | |
michael@0 | 329 | nsRefPtr<gfxWindowsSurface> targetSurfaceWin; |
michael@0 | 330 | if (!targetSurface && |
michael@0 | 331 | (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || |
michael@0 | 332 | IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D))) |
michael@0 | 333 | { |
michael@0 | 334 | uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 : |
michael@0 | 335 | gfxWindowsSurface::FLAG_IS_TRANSPARENT; |
michael@0 | 336 | targetSurfaceWin = new gfxWindowsSurface(hDC, flags); |
michael@0 | 337 | targetSurface = targetSurfaceWin; |
michael@0 | 338 | } |
michael@0 | 339 | |
michael@0 | 340 | nsRefPtr<gfxImageSurface> targetSurfaceImage; |
michael@0 | 341 | if (!targetSurface && |
michael@0 | 342 | (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH32) || |
michael@0 | 343 | IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24))) |
michael@0 | 344 | { |
michael@0 | 345 | gfxIntSize surfaceSize(ps.rcPaint.right - ps.rcPaint.left, |
michael@0 | 346 | ps.rcPaint.bottom - ps.rcPaint.top); |
michael@0 | 347 | |
michael@0 | 348 | if (!EnsureSharedSurfaceSize(surfaceSize)) { |
michael@0 | 349 | NS_ERROR("Couldn't allocate a shared image surface!"); |
michael@0 | 350 | return false; |
michael@0 | 351 | } |
michael@0 | 352 | |
michael@0 | 353 | // don't use the shared surface directly; instead, create a new one |
michael@0 | 354 | // that just reuses its buffer. |
michael@0 | 355 | targetSurfaceImage = new gfxImageSurface(sSharedSurfaceData.get(), |
michael@0 | 356 | surfaceSize, |
michael@0 | 357 | surfaceSize.width * 4, |
michael@0 | 358 | gfxImageFormat::RGB24); |
michael@0 | 359 | |
michael@0 | 360 | if (targetSurfaceImage && !targetSurfaceImage->CairoStatus()) { |
michael@0 | 361 | targetSurfaceImage->SetDeviceOffset(gfxPoint(-ps.rcPaint.left, -ps.rcPaint.top)); |
michael@0 | 362 | targetSurface = targetSurfaceImage; |
michael@0 | 363 | } |
michael@0 | 364 | } |
michael@0 | 365 | |
michael@0 | 366 | if (!targetSurface) { |
michael@0 | 367 | NS_ERROR("Invalid RenderMode!"); |
michael@0 | 368 | return false; |
michael@0 | 369 | } |
michael@0 | 370 | |
michael@0 | 371 | nsRefPtr<gfxContext> thebesContext; |
michael@0 | 372 | if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(mozilla::gfx::BackendType::CAIRO)) { |
michael@0 | 373 | RECT paintRect; |
michael@0 | 374 | ::GetClientRect(mWnd, &paintRect); |
michael@0 | 375 | RefPtr<mozilla::gfx::DrawTarget> dt = |
michael@0 | 376 | gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(targetSurface, |
michael@0 | 377 | mozilla::gfx::IntSize(paintRect.right - paintRect.left, |
michael@0 | 378 | paintRect.bottom - paintRect.top)); |
michael@0 | 379 | thebesContext = new gfxContext(dt); |
michael@0 | 380 | } else { |
michael@0 | 381 | thebesContext = new gfxContext(targetSurface); |
michael@0 | 382 | } |
michael@0 | 383 | |
michael@0 | 384 | // don't need to double buffer with anything but GDI |
michael@0 | 385 | BufferMode doubleBuffering = mozilla::layers::BufferMode::BUFFER_NONE; |
michael@0 | 386 | if (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || |
michael@0 | 387 | IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) { |
michael@0 | 388 | #ifdef MOZ_XUL |
michael@0 | 389 | switch (mTransparencyMode) { |
michael@0 | 390 | case eTransparencyGlass: |
michael@0 | 391 | case eTransparencyBorderlessGlass: |
michael@0 | 392 | default: |
michael@0 | 393 | // If we're not doing translucency, then double buffer |
michael@0 | 394 | doubleBuffering = mozilla::layers::BufferMode::BUFFERED; |
michael@0 | 395 | break; |
michael@0 | 396 | case eTransparencyTransparent: |
michael@0 | 397 | // If we're rendering with translucency, we're going to be |
michael@0 | 398 | // rendering the whole window; make sure we clear it first |
michael@0 | 399 | thebesContext->SetOperator(gfxContext::OPERATOR_CLEAR); |
michael@0 | 400 | thebesContext->Paint(); |
michael@0 | 401 | thebesContext->SetOperator(gfxContext::OPERATOR_OVER); |
michael@0 | 402 | break; |
michael@0 | 403 | } |
michael@0 | 404 | #else |
michael@0 | 405 | doubleBuffering = mozilla::layers::BufferMode::BUFFERED; |
michael@0 | 406 | #endif |
michael@0 | 407 | } |
michael@0 | 408 | |
michael@0 | 409 | { |
michael@0 | 410 | AutoLayerManagerSetup |
michael@0 | 411 | setupLayerManager(this, thebesContext, doubleBuffering); |
michael@0 | 412 | result = listener->PaintWindow(this, region); |
michael@0 | 413 | } |
michael@0 | 414 | |
michael@0 | 415 | #ifdef MOZ_XUL |
michael@0 | 416 | if ((IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || |
michael@0 | 417 | IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D))&& |
michael@0 | 418 | eTransparencyTransparent == mTransparencyMode) { |
michael@0 | 419 | // Data from offscreen drawing surface was copied to memory bitmap of transparent |
michael@0 | 420 | // bitmap. Now it can be read from memory bitmap to apply alpha channel and after |
michael@0 | 421 | // that displayed on the screen. |
michael@0 | 422 | UpdateTranslucentWindow(); |
michael@0 | 423 | } else |
michael@0 | 424 | #endif |
michael@0 | 425 | |
michael@0 | 426 | if (result) { |
michael@0 | 427 | if (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24) || |
michael@0 | 428 | IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH32)) |
michael@0 | 429 | { |
michael@0 | 430 | gfxIntSize surfaceSize = targetSurfaceImage->GetSize(); |
michael@0 | 431 | |
michael@0 | 432 | // Just blit this directly |
michael@0 | 433 | BITMAPINFOHEADER bi; |
michael@0 | 434 | memset(&bi, 0, sizeof(BITMAPINFOHEADER)); |
michael@0 | 435 | bi.biSize = sizeof(BITMAPINFOHEADER); |
michael@0 | 436 | bi.biWidth = surfaceSize.width; |
michael@0 | 437 | bi.biHeight = - surfaceSize.height; |
michael@0 | 438 | bi.biPlanes = 1; |
michael@0 | 439 | bi.biBitCount = 32; |
michael@0 | 440 | bi.biCompression = BI_RGB; |
michael@0 | 441 | |
michael@0 | 442 | if (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24)) { |
michael@0 | 443 | // On Windows CE/Windows Mobile, 24bpp packed-pixel sources |
michael@0 | 444 | // seem to be far faster to blit than 32bpp (see bug 484864). |
michael@0 | 445 | // So, convert the bits to 24bpp by stripping out the unused |
michael@0 | 446 | // alpha byte. 24bpp DIBs also have scanlines that are 4-byte |
michael@0 | 447 | // aligned though, so that must be taken into account. |
michael@0 | 448 | int srcstride = surfaceSize.width*4; |
michael@0 | 449 | int dststride = surfaceSize.width*3; |
michael@0 | 450 | dststride = (dststride + 3) & ~3; |
michael@0 | 451 | |
michael@0 | 452 | // Convert in place |
michael@0 | 453 | for (int j = 0; j < surfaceSize.height; ++j) { |
michael@0 | 454 | unsigned int *src = (unsigned int*) (targetSurfaceImage->Data() + j*srcstride); |
michael@0 | 455 | unsigned int *dst = (unsigned int*) (targetSurfaceImage->Data() + j*dststride); |
michael@0 | 456 | |
michael@0 | 457 | // go 4 pixels at a time, since each 4 pixels |
michael@0 | 458 | // turns into 3 DWORDs when converted into BGR: |
michael@0 | 459 | // BGRx BGRx BGRx BGRx -> BGRB GRBG RBGR |
michael@0 | 460 | // |
michael@0 | 461 | // However, since we're dealing with little-endian ints, this is actually: |
michael@0 | 462 | // xRGB xrgb xRGB xrgb -> bRGB GBrg rgbR |
michael@0 | 463 | int width_left = surfaceSize.width; |
michael@0 | 464 | while (width_left >= 4) { |
michael@0 | 465 | unsigned int a = *src++; |
michael@0 | 466 | unsigned int b = *src++; |
michael@0 | 467 | unsigned int c = *src++; |
michael@0 | 468 | unsigned int d = *src++; |
michael@0 | 469 | |
michael@0 | 470 | *dst++ = (a & 0x00ffffff) | (b << 24); |
michael@0 | 471 | *dst++ = ((b & 0x00ffff00) >> 8) | (c << 16); |
michael@0 | 472 | *dst++ = ((c & 0x00ff0000) >> 16) | (d << 8); |
michael@0 | 473 | |
michael@0 | 474 | width_left -= 4; |
michael@0 | 475 | } |
michael@0 | 476 | |
michael@0 | 477 | // then finish up whatever number of pixels are left, |
michael@0 | 478 | // using bytes. |
michael@0 | 479 | unsigned char *bsrc = (unsigned char*) src; |
michael@0 | 480 | unsigned char *bdst = (unsigned char*) dst; |
michael@0 | 481 | switch (width_left) { |
michael@0 | 482 | case 3: |
michael@0 | 483 | *bdst++ = *bsrc++; |
michael@0 | 484 | *bdst++ = *bsrc++; |
michael@0 | 485 | *bdst++ = *bsrc++; |
michael@0 | 486 | bsrc++; |
michael@0 | 487 | case 2: |
michael@0 | 488 | *bdst++ = *bsrc++; |
michael@0 | 489 | *bdst++ = *bsrc++; |
michael@0 | 490 | *bdst++ = *bsrc++; |
michael@0 | 491 | bsrc++; |
michael@0 | 492 | case 1: |
michael@0 | 493 | *bdst++ = *bsrc++; |
michael@0 | 494 | *bdst++ = *bsrc++; |
michael@0 | 495 | *bdst++ = *bsrc++; |
michael@0 | 496 | bsrc++; |
michael@0 | 497 | case 0: |
michael@0 | 498 | break; |
michael@0 | 499 | } |
michael@0 | 500 | } |
michael@0 | 501 | |
michael@0 | 502 | bi.biBitCount = 24; |
michael@0 | 503 | } |
michael@0 | 504 | |
michael@0 | 505 | StretchDIBits(hDC, |
michael@0 | 506 | ps.rcPaint.left, ps.rcPaint.top, |
michael@0 | 507 | surfaceSize.width, surfaceSize.height, |
michael@0 | 508 | 0, 0, |
michael@0 | 509 | surfaceSize.width, surfaceSize.height, |
michael@0 | 510 | targetSurfaceImage->Data(), |
michael@0 | 511 | (BITMAPINFO*) &bi, |
michael@0 | 512 | DIB_RGB_COLORS, |
michael@0 | 513 | SRCCOPY); |
michael@0 | 514 | } |
michael@0 | 515 | } |
michael@0 | 516 | } |
michael@0 | 517 | break; |
michael@0 | 518 | #ifdef MOZ_ENABLE_D3D9_LAYER |
michael@0 | 519 | case LayersBackend::LAYERS_D3D9: |
michael@0 | 520 | { |
michael@0 | 521 | nsRefPtr<LayerManagerD3D9> layerManagerD3D9 = |
michael@0 | 522 | static_cast<mozilla::layers::LayerManagerD3D9*>(GetLayerManager()); |
michael@0 | 523 | layerManagerD3D9->SetClippingRegion(region); |
michael@0 | 524 | result = listener->PaintWindow(this, region); |
michael@0 | 525 | if (layerManagerD3D9->DeviceWasRemoved()) { |
michael@0 | 526 | mLayerManager->Destroy(); |
michael@0 | 527 | mLayerManager = nullptr; |
michael@0 | 528 | // When our device was removed, we should have gfxWindowsPlatform |
michael@0 | 529 | // check if its render mode is up to date! |
michael@0 | 530 | gfxWindowsPlatform::GetPlatform()->UpdateRenderMode(); |
michael@0 | 531 | Invalidate(); |
michael@0 | 532 | } |
michael@0 | 533 | } |
michael@0 | 534 | break; |
michael@0 | 535 | #endif |
michael@0 | 536 | #ifdef MOZ_ENABLE_D3D10_LAYER |
michael@0 | 537 | case LayersBackend::LAYERS_D3D10: |
michael@0 | 538 | { |
michael@0 | 539 | gfxWindowsPlatform::GetPlatform()->UpdateRenderMode(); |
michael@0 | 540 | LayerManagerD3D10 *layerManagerD3D10 = static_cast<mozilla::layers::LayerManagerD3D10*>(GetLayerManager()); |
michael@0 | 541 | if (layerManagerD3D10->device() != gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) { |
michael@0 | 542 | Invalidate(); |
michael@0 | 543 | } else { |
michael@0 | 544 | result = listener->PaintWindow(this, region); |
michael@0 | 545 | } |
michael@0 | 546 | } |
michael@0 | 547 | break; |
michael@0 | 548 | #endif |
michael@0 | 549 | case LayersBackend::LAYERS_CLIENT: |
michael@0 | 550 | result = listener->PaintWindow(this, region); |
michael@0 | 551 | break; |
michael@0 | 552 | default: |
michael@0 | 553 | NS_ERROR("Unknown layers backend used!"); |
michael@0 | 554 | break; |
michael@0 | 555 | } |
michael@0 | 556 | } |
michael@0 | 557 | |
michael@0 | 558 | if (!aDC) { |
michael@0 | 559 | ::EndPaint(mWnd, &ps); |
michael@0 | 560 | } |
michael@0 | 561 | |
michael@0 | 562 | mPaintDC = nullptr; |
michael@0 | 563 | mLastPaintEndTime = TimeStamp::Now(); |
michael@0 | 564 | |
michael@0 | 565 | #if defined(WIDGET_DEBUG_OUTPUT) |
michael@0 | 566 | if (debug_WantPaintFlashing()) |
michael@0 | 567 | { |
michael@0 | 568 | // Only flash paint events which have not ignored the paint message. |
michael@0 | 569 | // Those that ignore the paint message aren't painting anything so there |
michael@0 | 570 | // is only the overhead of the dispatching the paint event. |
michael@0 | 571 | if (result) { |
michael@0 | 572 | ::InvertRgn(debugPaintFlashDC, debugPaintFlashRegion); |
michael@0 | 573 | PR_Sleep(PR_MillisecondsToInterval(30)); |
michael@0 | 574 | ::InvertRgn(debugPaintFlashDC, debugPaintFlashRegion); |
michael@0 | 575 | PR_Sleep(PR_MillisecondsToInterval(30)); |
michael@0 | 576 | } |
michael@0 | 577 | ::ReleaseDC(mWnd, debugPaintFlashDC); |
michael@0 | 578 | ::DeleteObject(debugPaintFlashRegion); |
michael@0 | 579 | } |
michael@0 | 580 | #endif // WIDGET_DEBUG_OUTPUT |
michael@0 | 581 | |
michael@0 | 582 | mPainting = false; |
michael@0 | 583 | |
michael@0 | 584 | // Re-get the listener since painting may have killed it. |
michael@0 | 585 | listener = GetPaintListener(); |
michael@0 | 586 | if (listener) |
michael@0 | 587 | listener->DidPaintWindow(); |
michael@0 | 588 | |
michael@0 | 589 | if (aNestingLevel == 0 && ::GetUpdateRect(mWnd, nullptr, false)) { |
michael@0 | 590 | OnPaint(aDC, 1); |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | return result; |
michael@0 | 594 | } |
michael@0 | 595 | |
michael@0 | 596 | gfxIntSize nsWindowGfx::GetIconMetrics(IconSizeType aSizeType) { |
michael@0 | 597 | int32_t width = ::GetSystemMetrics(sIconMetrics[aSizeType].xMetric); |
michael@0 | 598 | int32_t height = ::GetSystemMetrics(sIconMetrics[aSizeType].yMetric); |
michael@0 | 599 | |
michael@0 | 600 | if (width == 0 || height == 0) { |
michael@0 | 601 | width = height = sIconMetrics[aSizeType].defaultSize; |
michael@0 | 602 | } |
michael@0 | 603 | |
michael@0 | 604 | return gfxIntSize(width, height); |
michael@0 | 605 | } |
michael@0 | 606 | |
michael@0 | 607 | nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer, |
michael@0 | 608 | bool aIsCursor, |
michael@0 | 609 | uint32_t aHotspotX, |
michael@0 | 610 | uint32_t aHotspotY, |
michael@0 | 611 | gfxIntSize aScaledSize, |
michael@0 | 612 | HICON *aIcon) { |
michael@0 | 613 | |
michael@0 | 614 | MOZ_ASSERT((aScaledSize.width > 0 && aScaledSize.height > 0) || |
michael@0 | 615 | (aScaledSize.width == 0 && aScaledSize.height == 0)); |
michael@0 | 616 | |
michael@0 | 617 | // Get the image data |
michael@0 | 618 | RefPtr<SourceSurface> surface = |
michael@0 | 619 | aContainer->GetFrame(imgIContainer::FRAME_CURRENT, |
michael@0 | 620 | imgIContainer::FLAG_SYNC_DECODE); |
michael@0 | 621 | NS_ENSURE_TRUE(surface, NS_ERROR_NOT_AVAILABLE); |
michael@0 | 622 | |
michael@0 | 623 | IntSize frameSize = surface->GetSize(); |
michael@0 | 624 | if (frameSize.IsEmpty()) { |
michael@0 | 625 | return NS_ERROR_FAILURE; |
michael@0 | 626 | } |
michael@0 | 627 | |
michael@0 | 628 | IntSize iconSize(aScaledSize.width, aScaledSize.height); |
michael@0 | 629 | if (iconSize == IntSize(0, 0)) { // use frame's intrinsic size |
michael@0 | 630 | iconSize = frameSize; |
michael@0 | 631 | } |
michael@0 | 632 | |
michael@0 | 633 | RefPtr<DataSourceSurface> dataSurface; |
michael@0 | 634 | bool mappedOK; |
michael@0 | 635 | DataSourceSurface::MappedSurface map; |
michael@0 | 636 | |
michael@0 | 637 | if (iconSize != frameSize) { |
michael@0 | 638 | // Scale the surface |
michael@0 | 639 | dataSurface = Factory::CreateDataSourceSurface(iconSize, |
michael@0 | 640 | SurfaceFormat::B8G8R8A8); |
michael@0 | 641 | NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); |
michael@0 | 642 | mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map); |
michael@0 | 643 | NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE); |
michael@0 | 644 | |
michael@0 | 645 | RefPtr<DrawTarget> dt = |
michael@0 | 646 | Factory::CreateDrawTargetForData(BackendType::CAIRO, |
michael@0 | 647 | map.mData, |
michael@0 | 648 | dataSurface->GetSize(), |
michael@0 | 649 | map.mStride, |
michael@0 | 650 | SurfaceFormat::B8G8R8A8); |
michael@0 | 651 | dt->DrawSurface(surface, |
michael@0 | 652 | Rect(0, 0, iconSize.width, iconSize.height), |
michael@0 | 653 | Rect(0, 0, frameSize.width, frameSize.height), |
michael@0 | 654 | DrawSurfaceOptions(), |
michael@0 | 655 | DrawOptions(1.0f, CompositionOp::OP_SOURCE)); |
michael@0 | 656 | } else if (surface->GetFormat() != SurfaceFormat::B8G8R8A8) { |
michael@0 | 657 | // Convert format to SurfaceFormat::B8G8R8A8 |
michael@0 | 658 | dataSurface = gfxUtils:: |
michael@0 | 659 | CopySurfaceToDataSourceSurfaceWithFormat(surface, |
michael@0 | 660 | SurfaceFormat::B8G8R8A8); |
michael@0 | 661 | NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); |
michael@0 | 662 | mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map); |
michael@0 | 663 | } else { |
michael@0 | 664 | dataSurface = surface->GetDataSurface(); |
michael@0 | 665 | NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); |
michael@0 | 666 | mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map); |
michael@0 | 667 | } |
michael@0 | 668 | NS_ENSURE_TRUE(dataSurface && mappedOK, NS_ERROR_FAILURE); |
michael@0 | 669 | MOZ_ASSERT(dataSurface->GetFormat() == SurfaceFormat::B8G8R8A8); |
michael@0 | 670 | |
michael@0 | 671 | uint8_t* data = nullptr; |
michael@0 | 672 | nsAutoArrayPtr<uint8_t> autoDeleteArray; |
michael@0 | 673 | if (map.mStride == BytesPerPixel(dataSurface->GetFormat()) * iconSize.width) { |
michael@0 | 674 | // Mapped data is already packed |
michael@0 | 675 | data = map.mData; |
michael@0 | 676 | } else { |
michael@0 | 677 | // We can't use map.mData since the pixels are not packed (as required by |
michael@0 | 678 | // CreateDIBitmap, which is called under the DataToBitmap call below). |
michael@0 | 679 | // |
michael@0 | 680 | // We must unmap before calling SurfaceToPackedBGRA because it needs access |
michael@0 | 681 | // to the pixel data. |
michael@0 | 682 | dataSurface->Unmap(); |
michael@0 | 683 | map.mData = nullptr; |
michael@0 | 684 | |
michael@0 | 685 | data = autoDeleteArray = SurfaceToPackedBGRA(dataSurface); |
michael@0 | 686 | NS_ENSURE_TRUE(data, NS_ERROR_FAILURE); |
michael@0 | 687 | } |
michael@0 | 688 | |
michael@0 | 689 | HBITMAP bmp = DataToBitmap(data, iconSize.width, -iconSize.height, 32); |
michael@0 | 690 | uint8_t* a1data = Data32BitTo1Bit(data, iconSize.width, iconSize.height); |
michael@0 | 691 | if (map.mData) { |
michael@0 | 692 | dataSurface->Unmap(); |
michael@0 | 693 | } |
michael@0 | 694 | if (!a1data) { |
michael@0 | 695 | return NS_ERROR_FAILURE; |
michael@0 | 696 | } |
michael@0 | 697 | |
michael@0 | 698 | HBITMAP mbmp = DataToBitmap(a1data, iconSize.width, -iconSize.height, 1); |
michael@0 | 699 | PR_Free(a1data); |
michael@0 | 700 | |
michael@0 | 701 | ICONINFO info = {0}; |
michael@0 | 702 | info.fIcon = !aIsCursor; |
michael@0 | 703 | info.xHotspot = aHotspotX; |
michael@0 | 704 | info.yHotspot = aHotspotY; |
michael@0 | 705 | info.hbmMask = mbmp; |
michael@0 | 706 | info.hbmColor = bmp; |
michael@0 | 707 | |
michael@0 | 708 | HCURSOR icon = ::CreateIconIndirect(&info); |
michael@0 | 709 | ::DeleteObject(mbmp); |
michael@0 | 710 | ::DeleteObject(bmp); |
michael@0 | 711 | if (!icon) |
michael@0 | 712 | return NS_ERROR_FAILURE; |
michael@0 | 713 | *aIcon = icon; |
michael@0 | 714 | return NS_OK; |
michael@0 | 715 | } |
michael@0 | 716 | |
michael@0 | 717 | // Adjust cursor image data |
michael@0 | 718 | uint8_t* nsWindowGfx::Data32BitTo1Bit(uint8_t* aImageData, |
michael@0 | 719 | uint32_t aWidth, uint32_t aHeight) |
michael@0 | 720 | { |
michael@0 | 721 | // We need (aWidth + 7) / 8 bytes plus zero-padding up to a multiple of |
michael@0 | 722 | // 4 bytes for each row (HBITMAP requirement). Bug 353553. |
michael@0 | 723 | uint32_t outBpr = ((aWidth + 31) / 8) & ~3; |
michael@0 | 724 | |
michael@0 | 725 | // Allocate and clear mask buffer |
michael@0 | 726 | uint8_t* outData = (uint8_t*)PR_Calloc(outBpr, aHeight); |
michael@0 | 727 | if (!outData) |
michael@0 | 728 | return nullptr; |
michael@0 | 729 | |
michael@0 | 730 | int32_t *imageRow = (int32_t*)aImageData; |
michael@0 | 731 | for (uint32_t curRow = 0; curRow < aHeight; curRow++) { |
michael@0 | 732 | uint8_t *outRow = outData + curRow * outBpr; |
michael@0 | 733 | uint8_t mask = 0x80; |
michael@0 | 734 | for (uint32_t curCol = 0; curCol < aWidth; curCol++) { |
michael@0 | 735 | // Use sign bit to test for transparency, as alpha byte is highest byte |
michael@0 | 736 | if (*imageRow++ < 0) |
michael@0 | 737 | *outRow |= mask; |
michael@0 | 738 | |
michael@0 | 739 | mask >>= 1; |
michael@0 | 740 | if (!mask) { |
michael@0 | 741 | outRow ++; |
michael@0 | 742 | mask = 0x80; |
michael@0 | 743 | } |
michael@0 | 744 | } |
michael@0 | 745 | } |
michael@0 | 746 | |
michael@0 | 747 | return outData; |
michael@0 | 748 | } |
michael@0 | 749 | |
michael@0 | 750 | /** |
michael@0 | 751 | * Convert the given image data to a HBITMAP. If the requested depth is |
michael@0 | 752 | * 32 bit, a bitmap with an alpha channel will be returned. |
michael@0 | 753 | * |
michael@0 | 754 | * @param aImageData The image data to convert. Must use the format accepted |
michael@0 | 755 | * by CreateDIBitmap. |
michael@0 | 756 | * @param aWidth With of the bitmap, in pixels. |
michael@0 | 757 | * @param aHeight Height of the image, in pixels. |
michael@0 | 758 | * @param aDepth Image depth, in bits. Should be one of 1, 24 and 32. |
michael@0 | 759 | * |
michael@0 | 760 | * @return The HBITMAP representing the image. Caller should call |
michael@0 | 761 | * DeleteObject when done with the bitmap. |
michael@0 | 762 | * On failure, nullptr will be returned. |
michael@0 | 763 | */ |
michael@0 | 764 | HBITMAP nsWindowGfx::DataToBitmap(uint8_t* aImageData, |
michael@0 | 765 | uint32_t aWidth, |
michael@0 | 766 | uint32_t aHeight, |
michael@0 | 767 | uint32_t aDepth) |
michael@0 | 768 | { |
michael@0 | 769 | HDC dc = ::GetDC(nullptr); |
michael@0 | 770 | |
michael@0 | 771 | if (aDepth == 32) { |
michael@0 | 772 | // Alpha channel. We need the new header. |
michael@0 | 773 | BITMAPV4HEADER head = { 0 }; |
michael@0 | 774 | head.bV4Size = sizeof(head); |
michael@0 | 775 | head.bV4Width = aWidth; |
michael@0 | 776 | head.bV4Height = aHeight; |
michael@0 | 777 | head.bV4Planes = 1; |
michael@0 | 778 | head.bV4BitCount = aDepth; |
michael@0 | 779 | head.bV4V4Compression = BI_BITFIELDS; |
michael@0 | 780 | head.bV4SizeImage = 0; // Uncompressed |
michael@0 | 781 | head.bV4XPelsPerMeter = 0; |
michael@0 | 782 | head.bV4YPelsPerMeter = 0; |
michael@0 | 783 | head.bV4ClrUsed = 0; |
michael@0 | 784 | head.bV4ClrImportant = 0; |
michael@0 | 785 | |
michael@0 | 786 | head.bV4RedMask = 0x00FF0000; |
michael@0 | 787 | head.bV4GreenMask = 0x0000FF00; |
michael@0 | 788 | head.bV4BlueMask = 0x000000FF; |
michael@0 | 789 | head.bV4AlphaMask = 0xFF000000; |
michael@0 | 790 | |
michael@0 | 791 | HBITMAP bmp = ::CreateDIBitmap(dc, |
michael@0 | 792 | reinterpret_cast<CONST BITMAPINFOHEADER*>(&head), |
michael@0 | 793 | CBM_INIT, |
michael@0 | 794 | aImageData, |
michael@0 | 795 | reinterpret_cast<CONST BITMAPINFO*>(&head), |
michael@0 | 796 | DIB_RGB_COLORS); |
michael@0 | 797 | ::ReleaseDC(nullptr, dc); |
michael@0 | 798 | return bmp; |
michael@0 | 799 | } |
michael@0 | 800 | |
michael@0 | 801 | char reserved_space[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2]; |
michael@0 | 802 | BITMAPINFOHEADER& head = *(BITMAPINFOHEADER*)reserved_space; |
michael@0 | 803 | |
michael@0 | 804 | head.biSize = sizeof(BITMAPINFOHEADER); |
michael@0 | 805 | head.biWidth = aWidth; |
michael@0 | 806 | head.biHeight = aHeight; |
michael@0 | 807 | head.biPlanes = 1; |
michael@0 | 808 | head.biBitCount = (WORD)aDepth; |
michael@0 | 809 | head.biCompression = BI_RGB; |
michael@0 | 810 | head.biSizeImage = 0; // Uncompressed |
michael@0 | 811 | head.biXPelsPerMeter = 0; |
michael@0 | 812 | head.biYPelsPerMeter = 0; |
michael@0 | 813 | head.biClrUsed = 0; |
michael@0 | 814 | head.biClrImportant = 0; |
michael@0 | 815 | |
michael@0 | 816 | BITMAPINFO& bi = *(BITMAPINFO*)reserved_space; |
michael@0 | 817 | |
michael@0 | 818 | if (aDepth == 1) { |
michael@0 | 819 | RGBQUAD black = { 0, 0, 0, 0 }; |
michael@0 | 820 | RGBQUAD white = { 255, 255, 255, 0 }; |
michael@0 | 821 | |
michael@0 | 822 | bi.bmiColors[0] = white; |
michael@0 | 823 | bi.bmiColors[1] = black; |
michael@0 | 824 | } |
michael@0 | 825 | |
michael@0 | 826 | HBITMAP bmp = ::CreateDIBitmap(dc, &head, CBM_INIT, aImageData, &bi, DIB_RGB_COLORS); |
michael@0 | 827 | ::ReleaseDC(nullptr, dc); |
michael@0 | 828 | return bmp; |
michael@0 | 829 | } |