Bug 1799258 - Fix constexpr issue on base toolchain builds. r=gfx-reviewers,lsalzman
[gecko.git] / widget / windows / RemoteBackbuffer.cpp
blob5bd5e18ff320dc976ca679816c3f6e1f3493d064
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "RemoteBackbuffer.h"
7 #include "GeckoProfiler.h"
8 #include "nsThreadUtils.h"
9 #include "mozilla/Span.h"
10 #include <algorithm>
11 #include <type_traits>
13 namespace mozilla {
14 namespace widget {
15 namespace remote_backbuffer {
17 // This number can be adjusted as a time-memory tradeoff
18 constexpr uint8_t kMaxDirtyRects = 8;
20 struct IpcSafeRect {
21 explicit IpcSafeRect(const gfx::IntRect& aRect)
22 : x(aRect.x), y(aRect.y), width(aRect.width), height(aRect.height) {}
23 int32_t x;
24 int32_t y;
25 int32_t width;
26 int32_t height;
29 enum class ResponseResult {
30 Unknown,
31 Error,
32 BorrowSuccess,
33 BorrowSameBuffer,
34 PresentSuccess
37 enum class SharedDataType {
38 BorrowRequest,
39 BorrowRequestAllowSameBuffer,
40 BorrowResponse,
41 PresentRequest,
42 PresentResponse
45 struct BorrowResponseData {
46 ResponseResult result;
47 int32_t width;
48 int32_t height;
49 HANDLE fileMapping;
52 struct PresentRequestData {
53 uint8_t lenDirtyRects;
54 IpcSafeRect dirtyRects[kMaxDirtyRects];
57 struct PresentResponseData {
58 ResponseResult result;
61 struct SharedData {
62 SharedDataType dataType;
63 union {
64 BorrowResponseData borrowResponse;
65 PresentRequestData presentRequest;
66 PresentResponseData presentResponse;
67 } data;
70 static_assert(std::is_trivially_copyable<SharedData>::value &&
71 std::is_standard_layout<SharedData>::value,
72 "SharedData must be safe to pass over IPC boundaries");
74 class SharedImage {
75 public:
76 SharedImage()
77 : mWidth(0), mHeight(0), mFileMapping(nullptr), mPixelData(nullptr) {}
79 ~SharedImage() {
80 if (mPixelData) {
81 MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mPixelData));
84 if (mFileMapping) {
85 MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
89 bool Initialize(int32_t aWidth, int32_t aHeight) {
90 MOZ_ASSERT(aWidth > 0);
91 MOZ_ASSERT(aHeight > 0);
93 mWidth = aWidth;
94 mHeight = aHeight;
96 DWORD bufferSize = static_cast<DWORD>(mHeight * GetStride());
98 mFileMapping = ::CreateFileMappingW(
99 INVALID_HANDLE_VALUE, nullptr /*secattr*/, PAGE_READWRITE,
100 0 /*sizeHigh*/, bufferSize, nullptr /*name*/);
101 if (!mFileMapping) {
102 return false;
105 void* mappedFilePtr =
106 ::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
107 0 /*offsetLow*/, 0 /*bytesToMap*/);
108 if (!mappedFilePtr) {
109 return false;
112 mPixelData = reinterpret_cast<unsigned char*>(mappedFilePtr);
114 return true;
117 bool InitializeRemote(int32_t aWidth, int32_t aHeight, HANDLE aFileMapping) {
118 MOZ_ASSERT(aWidth > 0);
119 MOZ_ASSERT(aHeight > 0);
120 MOZ_ASSERT(aFileMapping);
122 mWidth = aWidth;
123 mHeight = aHeight;
124 mFileMapping = aFileMapping;
126 void* mappedFilePtr =
127 ::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
128 0 /*offsetLow*/, 0 /*bytesToMap*/);
129 if (!mappedFilePtr) {
130 return false;
133 mPixelData = reinterpret_cast<unsigned char*>(mappedFilePtr);
135 return true;
138 HBITMAP CreateDIBSection() {
139 BITMAPINFO bitmapInfo = {};
140 bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader);
141 bitmapInfo.bmiHeader.biWidth = mWidth;
142 bitmapInfo.bmiHeader.biHeight = -mHeight;
143 bitmapInfo.bmiHeader.biPlanes = 1;
144 bitmapInfo.bmiHeader.biBitCount = 32;
145 bitmapInfo.bmiHeader.biCompression = BI_RGB;
146 void* dummy = nullptr;
147 return ::CreateDIBSection(nullptr /*paletteDC*/, &bitmapInfo,
148 DIB_RGB_COLORS, &dummy, mFileMapping,
149 0 /*offset*/);
152 HANDLE CreateRemoteFileMapping(HANDLE aTargetProcess) {
153 MOZ_ASSERT(aTargetProcess);
155 HANDLE fileMapping = nullptr;
156 if (!::DuplicateHandle(GetCurrentProcess(), mFileMapping, aTargetProcess,
157 &fileMapping, 0 /*desiredAccess*/,
158 FALSE /*inheritHandle*/, DUPLICATE_SAME_ACCESS)) {
159 return nullptr;
161 return fileMapping;
164 already_AddRefed<gfx::DrawTarget> CreateDrawTarget() {
165 return gfx::Factory::CreateDrawTargetForData(
166 gfx::BackendType::CAIRO, mPixelData, IntSize(mWidth, mHeight),
167 GetStride(), gfx::SurfaceFormat::B8G8R8A8);
170 void CopyPixelsFrom(const SharedImage& other) {
171 const unsigned char* src = other.mPixelData;
172 unsigned char* dst = mPixelData;
174 int32_t width = std::min(mWidth, other.mWidth);
175 int32_t height = std::min(mHeight, other.mHeight);
177 for (int32_t row = 0; row < height; ++row) {
178 memcpy(dst, src, static_cast<uint32_t>(width * kBytesPerPixel));
179 src += other.GetStride();
180 dst += GetStride();
184 int32_t GetWidth() { return mWidth; }
186 int32_t GetHeight() { return mHeight; }
188 SharedImage(const SharedImage&) = delete;
189 SharedImage(SharedImage&&) = delete;
190 SharedImage& operator=(const SharedImage&) = delete;
191 SharedImage& operator=(SharedImage&&) = delete;
193 private:
194 static constexpr int32_t kBytesPerPixel = 4;
196 int32_t GetStride() const {
197 // DIB requires 32-bit row alignment
198 return (((mWidth * kBytesPerPixel) + 3) / 4) * 4;
201 int32_t mWidth;
202 int32_t mHeight;
203 HANDLE mFileMapping;
204 unsigned char* mPixelData;
207 class PresentableSharedImage {
208 public:
209 PresentableSharedImage()
210 : mSharedImage(),
211 mDeviceContext(nullptr),
212 mDIBSection(nullptr),
213 mSavedObject(nullptr) {}
215 ~PresentableSharedImage() {
216 if (mSavedObject) {
217 MOZ_ALWAYS_TRUE(::SelectObject(mDeviceContext, mSavedObject));
220 if (mDIBSection) {
221 MOZ_ALWAYS_TRUE(::DeleteObject(mDIBSection));
224 if (mDeviceContext) {
225 MOZ_ALWAYS_TRUE(::DeleteDC(mDeviceContext));
229 bool Initialize(int32_t aWidth, int32_t aHeight) {
230 if (!mSharedImage.Initialize(aWidth, aHeight)) {
231 return false;
234 mDeviceContext = ::CreateCompatibleDC(nullptr);
235 if (!mDeviceContext) {
236 return false;
239 mDIBSection = mSharedImage.CreateDIBSection();
240 if (!mDIBSection) {
241 return false;
244 mSavedObject = ::SelectObject(mDeviceContext, mDIBSection);
245 if (!mSavedObject) {
246 return false;
249 return true;
252 bool PresentToWindow(HWND aWindowHandle, TransparencyMode aTransparencyMode,
253 Span<const IpcSafeRect> aDirtyRects) {
254 if (aTransparencyMode == TransparencyMode::Transparent) {
255 // If our window is a child window or a child-of-a-child, the window
256 // that needs to be updated is the top level ancestor of the tree
257 HWND topLevelWindow = WinUtils::GetTopLevelHWND(aWindowHandle, true);
258 MOZ_ASSERT(::GetWindowLongPtr(topLevelWindow, GWL_EXSTYLE) &
259 WS_EX_LAYERED);
261 BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
262 POINT srcPos = {0, 0};
263 RECT clientRect = {};
264 if (!::GetClientRect(aWindowHandle, &clientRect)) {
265 return false;
267 MOZ_ASSERT(clientRect.left == 0);
268 MOZ_ASSERT(clientRect.top == 0);
269 int32_t width = clientRect.right;
270 int32_t height = clientRect.bottom;
271 SIZE winSize = {width, height};
272 // Window resize could cause the client area to be different than
273 // mSharedImage's size. If the client area doesn't match,
274 // PresentToWindow() returns false without calling UpdateLayeredWindow().
275 // Another call to UpdateLayeredWindow() will follow shortly, since the
276 // resize will eventually force the backbuffer to repaint itself again.
277 // When client area is larger than mSharedImage's size,
278 // UpdateLayeredWindow() draws the window completely invisible. But it
279 // does not return false.
280 if (width != mSharedImage.GetWidth() ||
281 height != mSharedImage.GetHeight()) {
282 return false;
285 return !!::UpdateLayeredWindow(
286 topLevelWindow, nullptr /*paletteDC*/, nullptr /*newPos*/, &winSize,
287 mDeviceContext, &srcPos, 0 /*colorKey*/, &bf, ULW_ALPHA);
290 IntRect sharedImageRect{0, 0, mSharedImage.GetWidth(),
291 mSharedImage.GetHeight()};
293 bool result = true;
295 HDC windowDC = ::GetDC(aWindowHandle);
296 if (!windowDC) {
297 return false;
300 for (auto& ipcDirtyRect : aDirtyRects) {
301 IntRect dirtyRect{ipcDirtyRect.x, ipcDirtyRect.y, ipcDirtyRect.width,
302 ipcDirtyRect.height};
303 IntRect bltRect = dirtyRect.Intersect(sharedImageRect);
305 if (!::BitBlt(windowDC, bltRect.x /*dstX*/, bltRect.y /*dstY*/,
306 bltRect.width, bltRect.height, mDeviceContext,
307 bltRect.x /*srcX*/, bltRect.y /*srcY*/, SRCCOPY)) {
308 result = false;
309 break;
313 MOZ_ALWAYS_TRUE(::ReleaseDC(aWindowHandle, windowDC));
315 return result;
318 HANDLE CreateRemoteFileMapping(HANDLE aTargetProcess) {
319 return mSharedImage.CreateRemoteFileMapping(aTargetProcess);
322 already_AddRefed<gfx::DrawTarget> CreateDrawTarget() {
323 return mSharedImage.CreateDrawTarget();
326 void CopyPixelsFrom(const PresentableSharedImage& other) {
327 mSharedImage.CopyPixelsFrom(other.mSharedImage);
330 int32_t GetWidth() { return mSharedImage.GetWidth(); }
332 int32_t GetHeight() { return mSharedImage.GetHeight(); }
334 PresentableSharedImage(const PresentableSharedImage&) = delete;
335 PresentableSharedImage(PresentableSharedImage&&) = delete;
336 PresentableSharedImage& operator=(const PresentableSharedImage&) = delete;
337 PresentableSharedImage& operator=(PresentableSharedImage&&) = delete;
339 private:
340 SharedImage mSharedImage;
341 HDC mDeviceContext;
342 HBITMAP mDIBSection;
343 HGDIOBJ mSavedObject;
346 Provider::Provider()
347 : mWindowHandle(nullptr),
348 mTargetProcess(nullptr),
349 mFileMapping(nullptr),
350 mRequestReadyEvent(nullptr),
351 mResponseReadyEvent(nullptr),
352 mSharedDataPtr(nullptr),
353 mStopServiceThread(false),
354 mServiceThread(nullptr),
355 mBackbuffer() {}
357 Provider::~Provider() {
358 mBackbuffer.reset();
360 if (mServiceThread) {
361 mStopServiceThread = true;
362 MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
363 MOZ_ALWAYS_TRUE(PR_JoinThread(mServiceThread) == PR_SUCCESS);
366 if (mSharedDataPtr) {
367 MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mSharedDataPtr));
370 if (mResponseReadyEvent) {
371 MOZ_ALWAYS_TRUE(::CloseHandle(mResponseReadyEvent));
374 if (mRequestReadyEvent) {
375 MOZ_ALWAYS_TRUE(::CloseHandle(mRequestReadyEvent));
378 if (mFileMapping) {
379 MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
382 if (mTargetProcess) {
383 MOZ_ALWAYS_TRUE(::CloseHandle(mTargetProcess));
387 bool Provider::Initialize(HWND aWindowHandle, DWORD aTargetProcessId,
388 TransparencyMode aTransparencyMode) {
389 MOZ_ASSERT(aWindowHandle);
390 MOZ_ASSERT(aTargetProcessId);
392 mWindowHandle = aWindowHandle;
394 mTargetProcess = ::OpenProcess(PROCESS_DUP_HANDLE, FALSE /*inheritHandle*/,
395 aTargetProcessId);
396 if (!mTargetProcess) {
397 return false;
400 mFileMapping = ::CreateFileMappingW(
401 INVALID_HANDLE_VALUE, nullptr /*secattr*/, PAGE_READWRITE, 0 /*sizeHigh*/,
402 static_cast<DWORD>(sizeof(SharedData)), nullptr /*name*/);
403 if (!mFileMapping) {
404 return false;
407 mRequestReadyEvent =
408 ::CreateEventW(nullptr /*secattr*/, FALSE /*manualReset*/,
409 FALSE /*initialState*/, nullptr /*name*/);
410 if (!mRequestReadyEvent) {
411 return false;
414 mResponseReadyEvent =
415 ::CreateEventW(nullptr /*secattr*/, FALSE /*manualReset*/,
416 FALSE /*initialState*/, nullptr /*name*/);
417 if (!mResponseReadyEvent) {
418 return false;
421 void* mappedFilePtr =
422 ::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
423 0 /*offsetLow*/, 0 /*bytesToMap*/);
424 if (!mappedFilePtr) {
425 return false;
428 mSharedDataPtr = reinterpret_cast<SharedData*>(mappedFilePtr);
430 mStopServiceThread = false;
432 // Use a raw NSPR OS-level thread here instead of nsThread because we are
433 // performing low-level synchronization across processes using Win32 Events,
434 // and nsThread is designed around an incompatible "in-process task queue"
435 // model
436 mServiceThread = PR_CreateThread(
437 PR_USER_THREAD, [](void* p) { static_cast<Provider*>(p)->ThreadMain(); },
438 this, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,
439 0 /*default stack size*/);
440 if (!mServiceThread) {
441 return false;
444 mTransparencyMode = uint32_t(aTransparencyMode);
446 return true;
449 Maybe<RemoteBackbufferHandles> Provider::CreateRemoteHandles() {
450 return Some(
451 RemoteBackbufferHandles(ipc::FileDescriptor(mFileMapping),
452 ipc::FileDescriptor(mRequestReadyEvent),
453 ipc::FileDescriptor(mResponseReadyEvent)));
456 void Provider::UpdateTransparencyMode(TransparencyMode aTransparencyMode) {
457 mTransparencyMode = uint32_t(aTransparencyMode);
460 void Provider::ThreadMain() {
461 AUTO_PROFILER_REGISTER_THREAD("RemoteBackbuffer");
462 NS_SetCurrentThreadName("RemoteBackbuffer");
464 while (true) {
466 AUTO_PROFILER_THREAD_SLEEP;
467 MOZ_ALWAYS_TRUE(::WaitForSingleObject(mRequestReadyEvent, INFINITE) ==
468 WAIT_OBJECT_0);
471 if (mStopServiceThread) {
472 break;
475 switch (mSharedDataPtr->dataType) {
476 case SharedDataType::BorrowRequest:
477 case SharedDataType::BorrowRequestAllowSameBuffer: {
478 BorrowResponseData responseData = {};
480 HandleBorrowRequest(&responseData,
481 mSharedDataPtr->dataType ==
482 SharedDataType::BorrowRequestAllowSameBuffer);
484 mSharedDataPtr->dataType = SharedDataType::BorrowResponse;
485 mSharedDataPtr->data.borrowResponse = responseData;
487 MOZ_ALWAYS_TRUE(::SetEvent(mResponseReadyEvent));
489 break;
491 case SharedDataType::PresentRequest: {
492 PresentRequestData requestData = mSharedDataPtr->data.presentRequest;
493 PresentResponseData responseData = {};
495 HandlePresentRequest(requestData, &responseData);
497 mSharedDataPtr->dataType = SharedDataType::PresentResponse;
498 mSharedDataPtr->data.presentResponse = responseData;
500 MOZ_ALWAYS_TRUE(::SetEvent(mResponseReadyEvent));
502 break;
504 default:
505 break;
510 void Provider::HandleBorrowRequest(BorrowResponseData* aResponseData,
511 bool aAllowSameBuffer) {
512 MOZ_ASSERT(aResponseData);
514 aResponseData->result = ResponseResult::Error;
516 RECT clientRect = {};
517 if (!::GetClientRect(mWindowHandle, &clientRect)) {
518 return;
521 MOZ_ASSERT(clientRect.left == 0);
522 MOZ_ASSERT(clientRect.top == 0);
524 int32_t width = clientRect.right ? clientRect.right : 1;
525 int32_t height = clientRect.bottom ? clientRect.bottom : 1;
527 bool needNewBackbuffer = !aAllowSameBuffer || !mBackbuffer ||
528 (mBackbuffer->GetWidth() != width) ||
529 (mBackbuffer->GetHeight() != height);
531 if (!needNewBackbuffer) {
532 aResponseData->result = ResponseResult::BorrowSameBuffer;
533 return;
536 auto newBackbuffer = std::make_unique<PresentableSharedImage>();
537 if (!newBackbuffer->Initialize(width, height)) {
538 return;
541 // Preserve the contents of the old backbuffer (if it exists)
542 if (mBackbuffer) {
543 newBackbuffer->CopyPixelsFrom(*mBackbuffer);
544 mBackbuffer.reset();
547 HANDLE remoteFileMapping =
548 newBackbuffer->CreateRemoteFileMapping(mTargetProcess);
549 if (!remoteFileMapping) {
550 return;
553 aResponseData->result = ResponseResult::BorrowSuccess;
554 aResponseData->width = width;
555 aResponseData->height = height;
556 aResponseData->fileMapping = remoteFileMapping;
558 mBackbuffer = std::move(newBackbuffer);
561 void Provider::HandlePresentRequest(const PresentRequestData& aRequestData,
562 PresentResponseData* aResponseData) {
563 MOZ_ASSERT(aResponseData);
565 Span rectSpan(aRequestData.dirtyRects, kMaxDirtyRects);
567 aResponseData->result = ResponseResult::Error;
569 if (!mBackbuffer) {
570 return;
573 if (!mBackbuffer->PresentToWindow(
574 mWindowHandle, GetTransparencyMode(),
575 rectSpan.First(aRequestData.lenDirtyRects))) {
576 return;
579 aResponseData->result = ResponseResult::PresentSuccess;
582 Client::Client()
583 : mFileMapping(nullptr),
584 mRequestReadyEvent(nullptr),
585 mResponseReadyEvent(nullptr),
586 mSharedDataPtr(nullptr),
587 mBackbuffer() {}
589 Client::~Client() {
590 mBackbuffer.reset();
592 if (mSharedDataPtr) {
593 MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mSharedDataPtr));
596 if (mResponseReadyEvent) {
597 MOZ_ALWAYS_TRUE(::CloseHandle(mResponseReadyEvent));
600 if (mRequestReadyEvent) {
601 MOZ_ALWAYS_TRUE(::CloseHandle(mRequestReadyEvent));
604 if (mFileMapping) {
605 MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
609 bool Client::Initialize(const RemoteBackbufferHandles& aRemoteHandles) {
610 MOZ_ASSERT(aRemoteHandles.fileMapping().IsValid());
611 MOZ_ASSERT(aRemoteHandles.requestReadyEvent().IsValid());
612 MOZ_ASSERT(aRemoteHandles.responseReadyEvent().IsValid());
614 // FIXME: Due to PCompositorWidget using virtual Recv methods,
615 // RemoteBackbufferHandles is passed by const reference, and cannot have its
616 // signature customized, meaning that we need to clone the handles here.
618 // Once PCompositorWidget is migrated to use direct call semantics, the
619 // signature can be changed to accept RemoteBackbufferHandles by rvalue
620 // reference or value, and the DuplicateHandle calls here can be avoided.
621 mFileMapping = aRemoteHandles.fileMapping().ClonePlatformHandle().release();
622 mRequestReadyEvent =
623 aRemoteHandles.requestReadyEvent().ClonePlatformHandle().release();
624 mResponseReadyEvent =
625 aRemoteHandles.responseReadyEvent().ClonePlatformHandle().release();
627 void* mappedFilePtr =
628 ::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
629 0 /*offsetLow*/, 0 /*bytesToMap*/);
630 if (!mappedFilePtr) {
631 return false;
634 mSharedDataPtr = reinterpret_cast<SharedData*>(mappedFilePtr);
636 return true;
639 already_AddRefed<gfx::DrawTarget> Client::BorrowDrawTarget() {
640 mSharedDataPtr->dataType = mBackbuffer
641 ? SharedDataType::BorrowRequestAllowSameBuffer
642 : SharedDataType::BorrowRequest;
644 MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
645 MOZ_ALWAYS_TRUE(::WaitForSingleObject(mResponseReadyEvent, INFINITE) ==
646 WAIT_OBJECT_0);
648 if (mSharedDataPtr->dataType != SharedDataType::BorrowResponse) {
649 return nullptr;
652 BorrowResponseData responseData = mSharedDataPtr->data.borrowResponse;
654 if ((responseData.result != ResponseResult::BorrowSameBuffer) &&
655 (responseData.result != ResponseResult::BorrowSuccess)) {
656 return nullptr;
659 if (responseData.result == ResponseResult::BorrowSuccess) {
660 mBackbuffer.reset();
662 auto newBackbuffer = std::make_unique<SharedImage>();
663 if (!newBackbuffer->InitializeRemote(responseData.width,
664 responseData.height,
665 responseData.fileMapping)) {
666 return nullptr;
669 mBackbuffer = std::move(newBackbuffer);
672 MOZ_ASSERT(mBackbuffer);
674 return mBackbuffer->CreateDrawTarget();
677 bool Client::PresentDrawTarget(gfx::IntRegion aDirtyRegion) {
678 mSharedDataPtr->dataType = SharedDataType::PresentRequest;
680 // Simplify the region until it has <= kMaxDirtyRects
681 aDirtyRegion.SimplifyOutward(kMaxDirtyRects);
683 Span rectSpan(mSharedDataPtr->data.presentRequest.dirtyRects, kMaxDirtyRects);
685 uint8_t rectIndex = 0;
686 for (auto iter = aDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
687 rectSpan[rectIndex] = IpcSafeRect(iter.Get());
688 ++rectIndex;
691 mSharedDataPtr->data.presentRequest.lenDirtyRects = rectIndex;
693 MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
694 MOZ_ALWAYS_TRUE(::WaitForSingleObject(mResponseReadyEvent, INFINITE) ==
695 WAIT_OBJECT_0);
697 if (mSharedDataPtr->dataType != SharedDataType::PresentResponse) {
698 return false;
701 if (mSharedDataPtr->data.presentResponse.result !=
702 ResponseResult::PresentSuccess) {
703 return false;
706 return true;
709 } // namespace remote_backbuffer
710 } // namespace widget
711 } // namespace mozilla