summaryrefslogtreecommitdiffstats
path: root/widget/tests/gtest/TestWinWindowOcclusionTracker.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/tests/gtest/TestWinWindowOcclusionTracker.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/widget/tests/gtest/TestWinWindowOcclusionTracker.cpp b/widget/tests/gtest/TestWinWindowOcclusionTracker.cpp
new file mode 100644
index 0000000000..b1f1114a3a
--- /dev/null
+++ b/widget/tests/gtest/TestWinWindowOcclusionTracker.cpp
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include <dwmapi.h>
+#include <windows.h>
+
+#include "MockWinWidget.h"
+#include "mozilla/widget/WinWindowOcclusionTracker.h"
+#include "mozilla/WindowsVersion.h"
+
+using namespace mozilla;
+using namespace mozilla::widget;
+
+class WinWindowOcclusionTrackerTest : public ::testing::Test {
+ protected:
+ HWND CreateNativeWindow(DWORD aStyle, DWORD aExStyle) {
+ mMockWinWidget =
+ MockWinWidget::Create(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | aStyle,
+ aExStyle, LayoutDeviceIntRect(0, 0, 100, 100));
+ EXPECT_NE(nullptr, mMockWinWidget.get());
+ HWND hwnd = mMockWinWidget->GetWnd();
+ HRGN region = ::CreateRectRgn(0, 0, 0, 0);
+ EXPECT_NE(nullptr, region);
+ if (::GetWindowRgn(hwnd, region) == COMPLEXREGION) {
+ // On Windows 7, the newly created window has a complex region, which
+ // means it will be ignored during the occlusion calculation. So, force
+ // it to have a simple region so that we get test coverage on win 7.
+ RECT boundingRect;
+ EXPECT_TRUE(::GetWindowRect(hwnd, &boundingRect));
+ HRGN rectangularRegion = ::CreateRectRgnIndirect(&boundingRect);
+ EXPECT_NE(nullptr, rectangularRegion);
+ ::SetWindowRgn(hwnd, rectangularRegion, /* bRedraw = */ TRUE);
+ ::DeleteObject(rectangularRegion);
+ }
+ ::DeleteObject(region);
+
+ ::ShowWindow(hwnd, SW_SHOWNORMAL);
+ EXPECT_TRUE(UpdateWindow(hwnd));
+ return hwnd;
+ }
+
+ // Wrapper around IsWindowVisibleAndFullyOpaque so only the test class
+ // needs to be a friend of NativeWindowOcclusionTrackerWin.
+ bool CheckWindowVisibleAndFullyOpaque(HWND aHWnd,
+ LayoutDeviceIntRect* aWinRect) {
+ bool ret = WinWindowOcclusionTracker::IsWindowVisibleAndFullyOpaque(
+ aHWnd, aWinRect);
+ // In general, if IsWindowVisibleAndFullyOpaque returns false, the
+ // returned rect should not be altered.
+ if (!ret) {
+ EXPECT_EQ(*aWinRect, LayoutDeviceIntRect(0, 0, 0, 0));
+ }
+ return ret;
+ }
+
+ RefPtr<MockWinWidget> mMockWinWidget;
+};
+
+TEST_F(WinWindowOcclusionTrackerTest, VisibleOpaqueWindow) {
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, /* aExStyle = */ 0);
+ LayoutDeviceIntRect returnedRect;
+ // Normal windows should be visible.
+ EXPECT_TRUE(CheckWindowVisibleAndFullyOpaque(hwnd, &returnedRect));
+
+ // Check that the returned rect == the actual window rect of the hwnd.
+ RECT winRect;
+ ASSERT_TRUE(::GetWindowRect(hwnd, &winRect));
+ EXPECT_EQ(returnedRect, LayoutDeviceIntRect(winRect.left, winRect.top,
+ winRect.right - winRect.left,
+ winRect.bottom - winRect.top));
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, MinimizedWindow) {
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, /* aExStyle = */ 0);
+ LayoutDeviceIntRect winRect;
+ ::ShowWindow(hwnd, SW_MINIMIZE);
+ // Minimized windows are not considered visible.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, TransparentWindow) {
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, WS_EX_TRANSPARENT);
+ LayoutDeviceIntRect winRect;
+ // Transparent windows are not considered visible and opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, ToolWindow) {
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, WS_EX_TOOLWINDOW);
+ LayoutDeviceIntRect winRect;
+ // Tool windows are not considered visible and opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, LayeredAlphaWindow) {
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, WS_EX_LAYERED);
+ LayoutDeviceIntRect winRect;
+ BYTE alpha = 1;
+ DWORD flags = LWA_ALPHA;
+ COLORREF colorRef = RGB(1, 1, 1);
+ SetLayeredWindowAttributes(hwnd, colorRef, alpha, flags);
+ // Layered windows with alpha < 255 are not considered visible and opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, UpdatedLayeredAlphaWindow) {
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, WS_EX_LAYERED);
+ LayoutDeviceIntRect winRect;
+ HDC hdc = ::CreateCompatibleDC(nullptr);
+ EXPECT_NE(nullptr, hdc);
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA};
+
+ ::UpdateLayeredWindow(hwnd, hdc, nullptr, nullptr, nullptr, nullptr,
+ RGB(0xFF, 0xFF, 0xFF), &blend, ULW_OPAQUE);
+ // Layered windows set up with UpdateLayeredWindow instead of
+ // SetLayeredWindowAttributes should not be considered visible and opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+ ::DeleteDC(hdc);
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, LayeredNonAlphaWindow) {
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, WS_EX_LAYERED);
+ LayoutDeviceIntRect winRect;
+ BYTE alpha = 1;
+ DWORD flags = 0;
+ COLORREF colorRef = RGB(1, 1, 1);
+ ::SetLayeredWindowAttributes(hwnd, colorRef, alpha, flags);
+ // Layered non alpha windows are considered visible and opaque.
+ EXPECT_TRUE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, ComplexRegionWindow) {
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, /* aExStyle = */ 0);
+ LayoutDeviceIntRect winRect;
+ // Create a region with rounded corners, which should be a complex region.
+ HRGN region = CreateRoundRectRgn(1, 1, 100, 100, 5, 5);
+ EXPECT_NE(nullptr, region);
+ ::SetWindowRgn(hwnd, region, /* bRedraw = */ TRUE);
+ // Windows with complex regions are not considered visible and fully opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+ DeleteObject(region);
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, PopupWindow) {
+ HWND hwnd = CreateNativeWindow(WS_POPUP, /* aExStyle = */ 0);
+ LayoutDeviceIntRect winRect;
+ // Normal Popup Windows are not considered visible.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+}
+
+TEST_F(WinWindowOcclusionTrackerTest, CloakedWindow) {
+ // Cloaking is only supported in Windows 8 and above.
+ if (!IsWin8OrLater()) {
+ return;
+ }
+ HWND hwnd = CreateNativeWindow(/* aStyle = */ 0, /* aExStyle = */ 0);
+ LayoutDeviceIntRect winRect;
+ BOOL cloak = TRUE;
+ ::DwmSetWindowAttribute(hwnd, DWMWA_CLOAK, &cloak, sizeof(cloak));
+ // Cloaked Windows are not considered visible.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &winRect));
+}