Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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"
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) {
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));
}