diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt')
10 files changed, 2168 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp new file mode 100755 index 000000000..0211e6887 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp @@ -0,0 +1,229 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" + +#include <windows.graphics.display.h> + +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +CoreWindowNativeWindow::~CoreWindowNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) +{ + ComPtr<IPropertySet> props = propertySet; + ComPtr<IInspectable> win = window; + SIZE swapChainSize = {}; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (FAILED(result)) + { + return false; + } + + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &mSwapChainSizeSpecified); + if (FAILED(result)) + { + return false; + } + + // The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty, &mSwapChainScale, &mSwapChainScaleSpecified); + if (FAILED(result)) + { + return false; + } + + if (!mSwapChainScaleSpecified) + { + // Default value for the scale is 1.0f + mSwapChainScale = 1.0f; + } + + // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified + if (mSwapChainScaleSpecified && mSwapChainSizeSpecified) + { + ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty."); + return false; + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mCoreWindow); + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output occurs automatically because if + // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain. + if (mSwapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + } + else + { + Size coreWindowSize; + result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize); + + if (SUCCEEDED(result)) + { + mClientRect = clientRect(coreWindowSize); + } + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool CoreWindowNativeWindow::registerForSizeChangeEvents() +{ + ComPtr<IWindowSizeChangedEventHandler> sizeChangedHandler; + HRESULT result = Microsoft::WRL::MakeAndInitialize<CoreWindowSizeChangedHandler>(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); + if (SUCCEEDED(result)) + { + result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void CoreWindowNativeWindow::unregisterForSizeChangeEvents() +{ + if (mCoreWindow) + { + (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken); + } + mSizeChangedEventToken.value = 0; +} + +HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, + IDXGIFactory2 *factory, + DXGI_FORMAT format, + unsigned int width, + unsigned int height, + bool containsAlpha, + IDXGISwapChain1 **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = + DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + + *swapChain = nullptr; + + ComPtr<IDXGISwapChain1> newSwapChain; + HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + if (SUCCEEDED(result)) + { + result = newSwapChain.CopyTo(swapChain); + } + + if (SUCCEEDED(result)) + { + // If automatic swapchain resize behaviors have been disabled, then + // unregister for the resize change events. + if (mSupportsSwapChainResize == false) + { + unregisterForSizeChangeEvents(); + } + } + + return result; +} + +inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const Size &windowSize, + const RECT &clientRect) +{ + // We don't need to do any additional work to scale CoreWindow swapchains. + // Using DXGI_SCALING_STRETCH to create the swapchain above does all the necessary work. + return S_OK; +} + +HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow> &coreWindow, + Size *windowSize) +{ + ABI::Windows::Foundation::Rect bounds; + HRESULT result = coreWindow->get_Bounds(&bounds); + if (SUCCEEDED(result)) + { + *windowSize = { ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) }; + } + + return result; +} + +static float GetLogicalDpi() +{ + ComPtr<ABI::Windows::Graphics::Display::IDisplayPropertiesStatics> displayProperties; + + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) + { + float dpi = 96.0f; + if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) + { + return dpi; + } + } + + // Return 96 dpi as a default if display properties cannot be obtained. + return 96.0f; +} + +float ConvertDipsToPixels(float dips) +{ + static const float dipsPerInch = 96.0f; + return dips * GetLogicalDpi() / dipsPerInch; +} +} diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h new file mode 100755 index 000000000..d43bf0ba5 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h @@ -0,0 +1,92 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CoreWindowNativeWindow.h: NativeWindow for managing ICoreWindow native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ + +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" + +#include <memory> + +#include <EGL/eglplatform.h> + +typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t IWindowSizeChangedEventHandler; + +namespace rx +{ +float ConvertDipsToPixels(float dips); + +class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this<CoreWindowNativeWindow> +{ + public: + ~CoreWindowNativeWindow(); + + bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override; + HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory2 *factory, + DXGI_FORMAT format, + unsigned int width, + unsigned int height, + bool containsAlpha, + IDXGISwapChain1 **swapChain) override; + + protected: + HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) override; + + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + + private: + ComPtr<ABI::Windows::UI::Core::ICoreWindow> mCoreWindow; + ComPtr<IMap<HSTRING, IInspectable*>> mPropertyMap; +}; + +[uuid(7F924F66-EBAE-40E5-A10B-B8F35E245190)] +class CoreWindowSizeChangedHandler : + public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, IWindowSizeChangedEventHandler> +{ + public: + CoreWindowSizeChangedHandler() { } + HRESULT RuntimeClassInitialize(std::shared_ptr<InspectableNativeWindow> host) + { + if (!host) + { + return E_INVALIDARG; + } + + mHost = host; + return S_OK; + } + + // IWindowSizeChangedEventHandler + IFACEMETHOD(Invoke)(ABI::Windows::UI::Core::ICoreWindow *sender, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *sizeChangedEventArgs) + { + std::shared_ptr<InspectableNativeWindow> host = mHost.lock(); + if (host) + { + ABI::Windows::Foundation::Size windowSize; + if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) + { + Size windowSizeInPixels = {ConvertDipsToPixels(windowSize.Width), + ConvertDipsToPixels(windowSize.Height)}; + host->setNewClientSize(windowSizeInPixels); + } + } + + return S_OK; + } + + private: + std::weak_ptr<InspectableNativeWindow> mHost; +}; + +HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow> &coreWindow, + Size *windowSize); +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow_unittest.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow_unittest.cpp new file mode 100755 index 000000000..6b5ae14c5 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow_unittest.cpp @@ -0,0 +1,356 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +// WINAPI_FAMILY is required to be defined as WINAPI_FAMILY_PC_APP +// to ensure that the proper defines are set when including additional +// headers which rely on Windows Store specific configuration. +// This would normally be defined already but this unittest exe is compiled +// as a desktop application which results in WINAPI_FAMILY being +// set to WINAPI_FAMILY_DESKTOP_APP +#undef WINAPI_FAMILY +#define WINAPI_FAMILY WINAPI_FAMILY_PC_APP +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include <angle_windowsstore.h> + +using namespace rx; +using namespace ABI::Windows::ApplicationModel::Core; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::System; + +namespace +{ + +// Mock Generic interfaces which are NOT ICoreWindow or +// IPropertySet +MIDL_INTERFACE("A4D67D0A-0E7F-4DF7-918B-7A1395413AF2") +IAmInspectable : public IInspectable +{ +}; + +class GenericIInspectable : public RuntimeClass < + RuntimeClassFlags<WinRtClassicComMix>, + IAmInspectable > +{ +}; + +MIDL_INTERFACE("3CBCFE7A-E000-4094-B2D2-B7C9A4D67A2C") +IAmUnknown : public IUnknown +{ +}; + +class GenericIUnknown : public RuntimeClass < + RuntimeClassFlags<ClassicCom>, + IAmUnknown > +{ +}; + +// Mock ICoreWindow +class MockCoreWindow : public ABI::Windows::UI::Core::ICoreWindow +{ + public: + // IUnknown + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) + { + *ppvObject = NULL; + + if (IsEqualIID(IID_IUnknown, riid)) + { + *ppvObject = static_cast<IUnknown*>(this); + return S_OK; + } + + if (IsEqualIID(IID_IInspectable, riid)) + { + *ppvObject = static_cast<IInspectable*>(this); + return S_OK; + } + + if (IsEqualIID(IID_ICoreWindow, riid)) + { + *ppvObject = static_cast<ABI::Windows::UI::Core::ICoreWindow*>(this); + return S_OK; + } + + return E_NOINTERFACE; + } + + STDMETHOD_(ULONG, AddRef)(){ return 1; } + STDMETHOD_(ULONG, Release)(){ return 1; } + + // IInspectable + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, GetIids, HRESULT(ULONG *, IID**)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, GetRuntimeClassName, HRESULT(HSTRING *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, GetTrustLevel, HRESULT(TrustLevel *)); + + // ICoreWindow + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_AutomationHostProvider, HRESULT(IInspectable **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Bounds, HRESULT(Rect *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_CustomProperties, HRESULT(IPropertySet **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Dispatcher, HRESULT(ICoreDispatcher **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_FlowDirection, HRESULT(CoreWindowFlowDirection *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_FlowDirection, HRESULT(CoreWindowFlowDirection)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_IsInputEnabled, HRESULT(boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_IsInputEnabled, HRESULT(boolean)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_PointerCursor, HRESULT(ICoreCursor**)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_PointerCursor, HRESULT(ICoreCursor*)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_PointerPosition, HRESULT(Point*)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Visible, HRESULT(boolean *)); + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, Activate, HRESULT()); + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, Close , HRESULT()); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, GetAsyncKeyState, HRESULT(ABI::Windows::System::VirtualKey, ABI::Windows::UI::Core::CoreVirtualKeyStates*)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, GetKeyState, HRESULT(ABI::Windows::System::VirtualKey, ABI::Windows::UI::Core::CoreVirtualKeyStates*)); + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, ReleasePointerCapture, HRESULT()); + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, SetPointerCapture, HRESULT()); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Activated, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowActivatedEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Activated, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_AutomationProviderRequested, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CAutomationProviderRequestedEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_AutomationProviderRequested, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_CharacterReceived, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CCharacterReceivedEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_CharacterReceived, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Closed, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CCoreWindowEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Closed, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_InputEnabled, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CInputEnabledEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_InputEnabled, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_KeyDown, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CKeyEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_KeyDown, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_KeyUp, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CKeyEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_KeyUp, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerCaptureLost, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerCaptureLost, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerEntered, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerEntered, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerExited, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerExited, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerMoved, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerMoved, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerPressed, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerPressed, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerReleased, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerReleased, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_TouchHitTesting, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CTouchHitTestingEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_TouchHitTesting, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerWheelChanged, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerWheelChanged, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_SizeChanged, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_SizeChanged, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_VisibilityChanged, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CVisibilityChangedEventArgs*, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_VisibilityChanged, HRESULT(EventRegistrationToken)); +}; + +HRESULT CreatePropertyMap(IMap<HSTRING, IInspectable*>** propertyMap) +{ + HRESULT result = S_OK; + ComPtr<IPropertySet> propertySet; + ComPtr<IActivationFactory> propertySetFactory; + result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Collections_PropertySet).Get(), &propertySetFactory); + EXPECT_HRESULT_SUCCEEDED(result); + + result = propertySetFactory->ActivateInstance(&propertySet); + EXPECT_HRESULT_SUCCEEDED(result); + + result = propertySet.CopyTo(propertyMap); + EXPECT_HRESULT_SUCCEEDED(result); + + return result; +} + +HRESULT CreatePropertyValueStatics(IPropertyValueStatics** propertyStatics) +{ + ComPtr<IPropertyValueStatics> propertyValueStatics; + HRESULT result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &propertyValueStatics); + EXPECT_HRESULT_SUCCEEDED(result); + + result = propertyValueStatics.CopyTo(propertyStatics); + EXPECT_HRESULT_SUCCEEDED(result); + + return result; +} + +HRESULT SetInspectablePropertyValue(const ComPtr<IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t* propertyName, IInspectable* inspectable) +{ + boolean propertyReplaced = false; + return propertyMap->Insert(HStringReference(propertyName).Get(), inspectable, &propertyReplaced); +} + +void expectNativeWindowInitCalls(MockCoreWindow &coreWindow, bool expectBounds) +{ + if (expectBounds) + { + EXPECT_CALL(coreWindow, get_Bounds(testing::_)).Times(1); + } + + EXPECT_CALL(coreWindow, add_SizeChanged(testing::_, testing::_)).Times(1); + EXPECT_CALL(coreWindow, remove_SizeChanged(testing::_)).Times(1); +} + +TEST(NativeWindowTest, NativeWindowNull) +{ + NativeWindow nativeWindow(nullptr); + EXPECT_FALSE(nativeWindow.initialize()); +} + +TEST(NativeWindowTest, NativeWindowBadInspectable) +{ + ComPtr<IAmInspectable> notCoreWindow = Make<GenericIInspectable>(); + NativeWindow nativeWindow(notCoreWindow.Get()); + EXPECT_FALSE(nativeWindow.initialize()); +} + +TEST(NativeWindowTest, NativeWindowNotInspectable) +{ + ComPtr<IAmUnknown> notIInspectable = Make<GenericIUnknown>(); + NativeWindow nativeWindow((IInspectable*)notIInspectable.Get()); + EXPECT_FALSE(nativeWindow.initialize()); +} + +TEST(NativeWindowTest, NativeWindowValidCoreWindow) +{ + MockCoreWindow mockCoreWindow; + expectNativeWindowInitCalls(mockCoreWindow, true); + NativeWindow nativeWindow(&mockCoreWindow); + EXPECT_TRUE(nativeWindow.initialize()); +} + +TEST(NativeWindowTest, NativeWindowValidCoreWindowInPropertySet) +{ + // COM is required to be initialized for creation of the property set + EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); + { + MockCoreWindow mockCoreWindow; + ComPtr<IMap<HSTRING, IInspectable*>> propertySet; + + // Add the CoreWindow to the property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, &mockCoreWindow)); + + expectNativeWindowInitCalls(mockCoreWindow, true); + NativeWindow nativeWindow(propertySet.Get()); + EXPECT_TRUE(nativeWindow.initialize()); + } + CoUninitialize(); +} + +TEST(NativeWindowTest, NativeWindowMissingCoreWindowInPropertySet) +{ + // COM is required to be initialized for creation of the property set + EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); + { + MockCoreWindow mockCoreWindow; + ComPtr<IMap<HSTRING, IInspectable*>> propertySet; + + EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); + + NativeWindow nativeWindow(propertySet.Get()); + EXPECT_FALSE(nativeWindow.initialize()); + } + CoUninitialize(); +} + +// Tests that the scale property works as expected in a property set with a SwapChainPanel +class CoreWindowScaleTest : public testing::TestWithParam<std::pair<float, bool>> +{ +}; + +TEST_P(CoreWindowScaleTest, ValidateScale) +{ + float scale = GetParam().first; + bool expectedResult = GetParam().second; + + // COM is required to be initialized for creation of the property set + EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); + { + MockCoreWindow mockCoreWindow; + ComPtr<IMap<HSTRING, IInspectable*>> propertySet; + ComPtr<IPropertyValueStatics> propertyValueStatics; + ComPtr<IPropertyValue> singleValue; + + // Create a simple property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockCoreWindow))); + + // Add a valid scale factor to the property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); + propertyValueStatics->CreateSingle(scale, reinterpret_cast<IInspectable**>(singleValue.GetAddressOf())); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderResolutionScaleProperty, reinterpret_cast<IInspectable*>(singleValue.Get()))); + + // Check native window init status and calls to the mock swapchainpanel + NativeWindow nativeWindow(propertySet.Get()); + if (expectedResult) + { + expectNativeWindowInitCalls(mockCoreWindow, true); + } + + EXPECT_EQ(nativeWindow.initialize(), expectedResult); + } + CoUninitialize(); +} + +typedef std::pair<float, bool> scaleValidPair; +static const scaleValidPair scales[] = { scaleValidPair(1.0f, true), + scaleValidPair(0.5f, true), + scaleValidPair(0.0f, false), + scaleValidPair(0.01f, true), + scaleValidPair(2.00f, true) }; + +INSTANTIATE_TEST_CASE_P(NativeWindowTest, + CoreWindowScaleTest, + testing::ValuesIn(scales)); + +// Tests that the size property works as expected in a property set with a SwapChainPanel +class CoreWindowSizeTest : public testing::TestWithParam<std::tuple<float, float, bool>> +{ +}; + +TEST_P(CoreWindowSizeTest, ValidateSize) +{ + Size renderSize = { std::get<0>(GetParam()), std::get<1>(GetParam()) }; + bool expectedResult = std::get<2>(GetParam()); + + // COM is required to be initialized for creation of the property set + EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); + { + MockCoreWindow mockCoreWindow; + ComPtr<IMap<HSTRING, IInspectable*>> propertySet; + ComPtr<IPropertyValueStatics> propertyValueStatics; + ComPtr<IPropertyValue> sizeValue; + + // Create a simple property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockCoreWindow))); + + // Add a valid size to the property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); + propertyValueStatics->CreateSize(renderSize, reinterpret_cast<IInspectable**>(sizeValue.GetAddressOf())); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderSurfaceSizeProperty, reinterpret_cast<IInspectable*>(sizeValue.Get()))); + + // Check native window init status and calls to the mock swapchainpanel + NativeWindow nativeWindow(propertySet.Get()); + if (expectedResult) + { + expectNativeWindowInitCalls(mockCoreWindow, false); + } + + EXPECT_EQ(nativeWindow.initialize(), expectedResult); + } + CoUninitialize(); +} + +typedef std::tuple<float, float, bool> sizeValidPair; +static const sizeValidPair sizes[] = { sizeValidPair( 800, 480, true), + sizeValidPair( 0, 480, false), + sizeValidPair( 800, 0, false), + sizeValidPair( 0, 0, false) }; + +INSTANTIATE_TEST_CASE_P(NativeWindowTest, + CoreWindowSizeTest, + testing::ValuesIn(sizes)); + +} // namespace diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp new file mode 100755 index 000000000..c7fcf8634 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp @@ -0,0 +1,276 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InspectableNativeWindow.cpp: NativeWindow base class for managing IInspectable native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +namespace rx +{ + +bool IsCoreWindow(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Core::ICoreWindow> *coreWindow) +{ + if (!window) + { + return false; + } + + ComPtr<IInspectable> win = window; + ComPtr<ABI::Windows::UI::Core::ICoreWindow> coreWin; + if (SUCCEEDED(win.As(&coreWin))) + { + if (coreWindow != nullptr) + { + *coreWindow = coreWin.Detach(); + } + return true; + } + + return false; +} + +bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> *swapChainPanel) +{ + if (!window) + { + return false; + } + + ComPtr<IInspectable> win = window; + ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> panel; + if (SUCCEEDED(win.As(&panel))) + { + if (swapChainPanel != nullptr) + { + *swapChainPanel = panel.Detach(); + } + return true; + } + + return false; +} + +bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet, IInspectable **eglNativeWindow) +{ + if (!window) + { + return false; + } + + ComPtr<IInspectable> props = window; + ComPtr<IPropertySet> propSet; + ComPtr<IInspectable> nativeWindow; + ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> propMap; + boolean hasEglNativeWindowPropertyKey = false; + + HRESULT result = props.As(&propSet); + if (SUCCEEDED(result)) + { + result = propSet.As(&propMap); + } + + // Look for the presence of the EGLNativeWindowType in the property set + if (SUCCEEDED(result)) + { + result = propMap->HasKey(HStringReference(EGLNativeWindowTypeProperty).Get(), &hasEglNativeWindowPropertyKey); + } + + // If the IPropertySet does not contain the required EglNativeWindowType key, the property set is + // considered invalid. + if (SUCCEEDED(result) && !hasEglNativeWindowPropertyKey) + { + ERR("Could not find EGLNativeWindowTypeProperty in IPropertySet. Valid EGLNativeWindowTypeProperty values include ICoreWindow"); + return false; + } + + // The EglNativeWindowType property exists, so retreive the IInspectable that represents the EGLNativeWindowType + if (SUCCEEDED(result) && hasEglNativeWindowPropertyKey) + { + result = propMap->Lookup(HStringReference(EGLNativeWindowTypeProperty).Get(), &nativeWindow); + } + + if (SUCCEEDED(result)) + { + if (propertySet != nullptr) + { + result = propSet.CopyTo(propertySet); + } + } + + if (SUCCEEDED(result)) + { + if (eglNativeWindow != nullptr) + { + result = nativeWindow.CopyTo(eglNativeWindow); + } + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +// Retrieve an optional property from a property set +HRESULT GetOptionalPropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap, + const wchar_t *propertyName, + boolean *hasKey, + ComPtr<ABI::Windows::Foundation::IPropertyValue> &propertyValue) +{ + if (!propertyMap || !hasKey) + { + return E_INVALIDARG; + } + + // Assume that the value does not exist + *hasKey = false; + + HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), hasKey); + if (SUCCEEDED(result) && !(*hasKey)) + { + // Value does not exist, so return S_OK and set the exists parameter to false to indicate + // that a the optional property does not exist. + return S_OK; + } + + if (SUCCEEDED(result)) + { + result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue); + } + + return result; +} + +// Attempts to read an optional SIZE property value that is assumed to be in the form of +// an ABI::Windows::Foundation::Size. This function validates the Size value before returning +// it to the caller. +// +// Possible return values are: +// S_OK, valueExists == true - optional SIZE value was successfully retrieved and validated +// S_OK, valueExists == false - optional SIZE value was not found +// E_INVALIDARG, valueExists = false - optional SIZE value was malformed in the property set. +// * Incorrect property type ( must be PropertyType_Size) +// * Invalid property value (width/height must be > 0) +// Additional errors may be returned from IMap or IPropertyValue +// +HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap, + const wchar_t *propertyName, SIZE *value, bool *valueExists) +{ + ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue; + ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty; + Size sizeValue = { 0, 0 }; + boolean hasKey = false; + + if (!propertyMap || !value || !valueExists) + { + return E_INVALIDARG; + } + + // Assume that the value does not exist + *valueExists = false; + *value = { 0, 0 }; + + HRESULT result = GetOptionalPropertyValue(propertyMap, propertyName, &hasKey, propertyValue); + if (SUCCEEDED(result) && hasKey) + { + result = propertyValue->get_Type(&propertyType); + + // Check if the expected Size property is of PropertyType_Size type. + if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size) + { + if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0)) + { + // A valid property value exists + *value = { static_cast<long>(sizeValue.Width), static_cast<long>(sizeValue.Height) }; + *valueExists = true; + result = S_OK; + } + else + { + // An invalid Size property was detected. Width/Height values must > 0 + result = E_INVALIDARG; + } + } + else + { + // An invalid property type was detected. Size property must be of PropertyType_Size + result = E_INVALIDARG; + } + } + + return result; +} + +// Attempts to read an optional float property value that is assumed to be in the form of +// an ABI::Windows::Foundation::Single. This function validates the Single value before returning +// it to the caller. +// +// Possible return values are: +// S_OK, valueExists == true - optional Single value was successfully retrieved and validated +// S_OK, valueExists == false - optional Single value was not found +// E_INVALIDARG, valueExists = false - optional Single value was malformed in the property set. +// * Incorrect property type ( must be PropertyType_Single) +// * Invalid property value (must be > 0) +// Additional errors may be returned from IMap or IPropertyValue +// +HRESULT GetOptionalSinglePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap, + const wchar_t *propertyName, float *value, bool *valueExists) +{ + ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue; + ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty; + float scaleValue = 0.0f; + boolean hasKey = false; + + if (!propertyMap || !value || !valueExists) + { + return E_INVALIDARG; + } + + // Assume that the value does not exist + *valueExists = false; + *value = 0.0f; + + HRESULT result = GetOptionalPropertyValue(propertyMap, propertyName, &hasKey, propertyValue); + if (SUCCEEDED(result) && hasKey) + { + result = propertyValue->get_Type(&propertyType); + + // Check if the expected Scale property is of PropertyType_Single type. + if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Single) + { + if (SUCCEEDED(propertyValue->GetSingle(&scaleValue)) && (scaleValue > 0.0f)) + { + // A valid property value exists + *value = scaleValue; + *valueExists = true; + result = S_OK; + } + else + { + // An invalid scale was set + result = E_INVALIDARG; + } + } + else + { + // An invalid property type was detected. Size property must be of PropertyType_Single + result = E_INVALIDARG; + } + } + + return result; +} + +RECT InspectableNativeWindow::clientRect(const Size &size) +{ + // We don't have to check if a swapchain scale was specified here; the default value is 1.0f + // which will have no effect. + return {0, 0, lround(size.Width * mSwapChainScale), lround(size.Height * mSwapChainScale)}; +} +} diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h new file mode 100755 index 000000000..3e67269f3 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h @@ -0,0 +1,131 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InspectableNativeWindow.h: Host specific implementation interface for +// managing IInspectable native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include "angle_windowsstore.h" + +#include <EGL/eglplatform.h> + +#include <windows.applicationmodel.core.h> +#include <windows.ui.xaml.h> +#include <windows.ui.xaml.media.dxinterop.h> +#include <wrl.h> +#include <wrl/wrappers/corewrappers.h> + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +class InspectableNativeWindow +{ + public: + InspectableNativeWindow() : + mSupportsSwapChainResize(true), + mSwapChainSizeSpecified(false), + mSwapChainScaleSpecified(false), + mSwapChainScale(1.0f), + mClientRectChanged(false), + mClientRect({0,0,0,0}), + mNewClientRect({0,0,0,0}) + { + mSizeChangedEventToken.value = 0; + } + virtual ~InspectableNativeWindow(){} + + virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0; + virtual HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory2 *factory, + DXGI_FORMAT format, + unsigned int width, + unsigned int height, + bool containsAlpha, + IDXGISwapChain1 **swapChain) = 0; + + bool getClientRect(RECT *rect) + { + if (mClientRectChanged) + { + mClientRect = mNewClientRect; + } + + *rect = mClientRect; + + return true; + } + + // setNewClientSize is used by the WinRT size change handler. It isn't used by the rest of ANGLE. + void setNewClientSize(const Size &newWindowSize) + { + // If the client doesn't support swapchain resizing then we should have already unregistered from size change handler + ASSERT(mSupportsSwapChainResize); + + if (mSupportsSwapChainResize) + { + // If the swapchain size was specified then we should ignore this call too + if (!mSwapChainSizeSpecified) + { + mNewClientRect = clientRect(newWindowSize); + mClientRectChanged = true; + + // If a scale was specified, then now is the time to apply the scale matrix for the new swapchain size and window size + if (mSwapChainScaleSpecified) + { + scaleSwapChain(newWindowSize, mNewClientRect); + } + } + + // Even if the swapchain size was fixed, the window might have changed size. + // In this case, we should recalculate the scale matrix to account for the new window size + if (mSwapChainSizeSpecified) + { + scaleSwapChain(newWindowSize, mClientRect); + } + } + } + + protected: + virtual HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) = 0; + RECT clientRect(const Size &size); + + bool mSupportsSwapChainResize; // Support for IDXGISwapChain::ResizeBuffers method + bool mSwapChainSizeSpecified; // If an EGLRenderSurfaceSizeProperty was specified + bool mSwapChainScaleSpecified; // If an EGLRenderResolutionScaleProperty was specified + float mSwapChainScale; // The scale value specified by the EGLRenderResolutionScaleProperty property + RECT mClientRect; + RECT mNewClientRect; + bool mClientRectChanged; + + EventRegistrationToken mSizeChangedEventToken; +}; + +bool IsCoreWindow(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Core::ICoreWindow> *coreWindow = nullptr); +bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> *swapChainPanel = nullptr); +bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr); + +HRESULT GetOptionalPropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap, + const wchar_t *propertyName, + boolean *hasKey, + ComPtr<ABI::Windows::Foundation::IPropertyValue> &propertyValue); + +HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap, + const wchar_t *propertyName, SIZE *value, bool *valueExists); + +HRESULT GetOptionalSinglePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap, + const wchar_t *propertyName, float *value, bool *valueExists); +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp new file mode 100755 index 000000000..a5ce4ca68 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp @@ -0,0 +1,126 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow11WinRT.cpp: NativeWindow base class for managing IInspectable native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h" + +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +namespace rx +{ +NativeWindow11WinRT::NativeWindow11WinRT(EGLNativeWindowType window, bool hasAlpha) + : NativeWindow11(window), mHasAlpha(hasAlpha) +{ +} + +bool NativeWindow11WinRT::initialize() +{ + EGLNativeWindowType window = getNativeWindow(); + + // If the native window type is a IPropertySet, extract the + // EGLNativeWindowType (IInspectable) and initialize the + // proper host with this IPropertySet. + ComPtr<ABI::Windows::Foundation::Collections::IPropertySet> propertySet; + ComPtr<IInspectable> eglNativeWindow; + if (IsEGLConfiguredPropertySet(window, &propertySet, &eglNativeWindow)) + { + // A property set was found and the EGLNativeWindowType was + // retrieved. The mWindow member of the host to must be updated + // to use the EGLNativeWindowType specified in the property set. + // mWindow is treated as a raw pointer not an AddRef'd interface, so + // the old mWindow does not need a Release() before this assignment. + window = eglNativeWindow.Get(); + } + + ComPtr<ABI::Windows::UI::Core::ICoreWindow> coreWindow; + ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> swapChainPanel; + if (IsCoreWindow(window, &coreWindow)) + { + mImpl = std::make_shared<CoreWindowNativeWindow>(); + if (mImpl) + { + return mImpl->initialize(window, propertySet.Get()); + } + } + else if (IsSwapChainPanel(window, &swapChainPanel)) + { + mImpl = std::make_shared<SwapChainPanelNativeWindow>(); + if (mImpl) + { + return mImpl->initialize(window, propertySet.Get()); + } + } + else + { + ERR( + "Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include " + "ICoreWindow, ISwapChainPanel and IPropertySet"); + } + + return false; +} + +bool NativeWindow11WinRT::getClientRect(LPRECT rect) const +{ + if (mImpl) + { + return mImpl->getClientRect(rect); + } + + return false; +} + +bool NativeWindow11WinRT::isIconic() const +{ + return false; +} + +HRESULT NativeWindow11WinRT::createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + IDXGISwapChain **swapChain) +{ + if (mImpl) + { + IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject<IDXGIFactory2>(factory); + IDXGISwapChain1 *swapChain1 = nullptr; + HRESULT result = + mImpl->createSwapChain(device, factory2, format, width, height, mHasAlpha, &swapChain1); + SafeRelease(factory2); + *swapChain = static_cast<IDXGISwapChain *>(swapChain1); + return result; + } + + return E_UNEXPECTED; +} + +void NativeWindow11WinRT::commitChange() +{ +} + +// static +bool NativeWindow11WinRT::IsValidNativeWindow(EGLNativeWindowType window) +{ + // A Valid EGLNativeWindowType IInspectable can only be: + // + // ICoreWindow + // ISwapChainPanel + // IPropertySet + // + // Anything else will be rejected as an invalid IInspectable. + return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window); +} + +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h new file mode 100755 index 000000000..996fd3a10 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow11WinRT.h: NativeWindow base class for managing IInspectable native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_H_ + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h" + +#include <memory> +#include <windows.applicationmodel.core.h> +#include <wrl.h> +#include <wrl/wrappers/corewrappers.h> + +namespace rx +{ +class InspectableNativeWindow; + +class NativeWindow11WinRT : public NativeWindow11 +{ + public: + NativeWindow11WinRT(EGLNativeWindowType window, bool hasAlpha); + + bool initialize() override; + bool getClientRect(LPRECT rect) const override; + bool isIconic() const override; + + HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + IDXGISwapChain **swapChain) override; + + void commitChange() override; + + static bool IsValidNativeWindow(EGLNativeWindowType window); + + private: + bool mHasAlpha; + std::shared_ptr<InspectableNativeWindow> mImpl; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_H_ diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp new file mode 100755 index 000000000..1dae1ad7d --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp @@ -0,0 +1,355 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainPanelNativeWindow.cpp: NativeWindow for managing ISwapChainPanel native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +#include <algorithm> +#include <math.h> + +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::UI::Xaml; +using namespace Microsoft::WRL; + +namespace rx +{ +SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +template <typename T> +struct AddFtmBase +{ + typedef Implements<RuntimeClassFlags<ClassicCom>, T, FtmBase> Type; +}; + +template <typename CODE> +HRESULT RunOnUIThread(CODE &&code, const ComPtr<ICoreDispatcher> &dispatcher) +{ + ComPtr<IAsyncAction> asyncAction; + HRESULT result = S_OK; + + boolean hasThreadAccess; + result = dispatcher->get_HasThreadAccess(&hasThreadAccess); + if (FAILED(result)) + { + return result; + } + + if (hasThreadAccess) + { + return code(); + } + else + { + Event waitEvent(CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS)); + if (!waitEvent.IsValid()) + { + return E_FAIL; + } + + HRESULT codeResult = E_FAIL; + auto handler = + Callback<AddFtmBase<IDispatchedHandler>::Type>([&codeResult, &code, &waitEvent] + { + codeResult = code(); + SetEvent(waitEvent.Get()); + return S_OK; + }); + + result = dispatcher->RunAsync(CoreDispatcherPriority_Normal, handler.Get(), + asyncAction.GetAddressOf()); + if (FAILED(result)) + { + return result; + } + + auto waitResult = WaitForSingleObjectEx(waitEvent.Get(), 10 * 1000, true); + if (waitResult != WAIT_OBJECT_0) + { + // Wait 10 seconds before giving up. At this point, the application is in an + // unrecoverable state (probably deadlocked). We therefore terminate the application + // entirely. This also prevents stack corruption if the async operation is eventually + // run. + ERR("Timeout waiting for async action on UI thread. The UI thread might be blocked."); + std::terminate(); + return E_FAIL; + } + + return codeResult; + } +} + +bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) +{ + ComPtr<IPropertySet> props = propertySet; + ComPtr<IInspectable> win = window; + SIZE swapChainSize = {}; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (FAILED(result)) + { + return false; + } + + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &mSwapChainSizeSpecified); + if (FAILED(result)) + { + return false; + } + + // The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty, &mSwapChainScale, &mSwapChainScaleSpecified); + if (FAILED(result)) + { + return false; + } + + if (!mSwapChainScaleSpecified) + { + // Default value for the scale is 1.0f + mSwapChainScale = 1.0f; + } + + // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified + if (mSwapChainScaleSpecified && mSwapChainSizeSpecified) + { + ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty."); + return false; + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mSwapChainPanel); + } + + ComPtr<IDependencyObject> swapChainPanelDependencyObject; + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&swapChainPanelDependencyObject); + } + + if (SUCCEEDED(result)) + { + result = swapChainPanelDependencyObject->get_Dispatcher( + mSwapChainPanelDispatcher.GetAddressOf()); + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output needs to be handled by the + // host for swapchain panels even though the scaling mode setting + // DXGI_SCALING_STRETCH is configured on the swapchain. + if (mSwapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + } + else + { + Size swapChainPanelSize; + result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, + &swapChainPanelSize); + + if (SUCCEEDED(result)) + { + // Update the client rect to account for any swapchain scale factor + mClientRect = clientRect(swapChainPanelSize); + } + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() +{ + ComPtr<ISizeChangedEventHandler> sizeChangedHandler; + ComPtr<IFrameworkElement> frameworkElement; + HRESULT result = Microsoft::WRL::MakeAndInitialize<SwapChainPanelSizeChangedHandler>(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&frameworkElement); + } + + if (SUCCEEDED(result)) + { + result = RunOnUIThread( + [this, frameworkElement, sizeChangedHandler] + { + return frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), + &mSizeChangedEventToken); + }, + mSwapChainPanelDispatcher); + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() +{ + ComPtr<IFrameworkElement> frameworkElement; + if (mSwapChainPanel && SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) + { + RunOnUIThread( + [this, frameworkElement] + { + return frameworkElement->remove_SizeChanged(mSizeChangedEventToken); + }, + mSwapChainPanelDispatcher); + } + + mSizeChangedEventToken.value = 0; +} + +HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, + IDXGIFactory2 *factory, + DXGI_FORMAT format, + unsigned int width, + unsigned int height, + bool containsAlpha, + IDXGISwapChain1 **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = + DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.AlphaMode = + containsAlpha ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE; + + *swapChain = nullptr; + + ComPtr<IDXGISwapChain1> newSwapChain; + ComPtr<ISwapChainPanelNative> swapChainPanelNative; + Size currentPanelSize = {}; + + HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&swapChainPanelNative); + } + + if (SUCCEEDED(result)) + { + result = RunOnUIThread( + [swapChainPanelNative, newSwapChain] + { + return swapChainPanelNative->SetSwapChain(newSwapChain.Get()); + }, + mSwapChainPanelDispatcher); + } + + if (SUCCEEDED(result)) + { + // The swapchain panel host requires an instance of the swapchain set on the SwapChainPanel + // to perform the runtime-scale behavior. This swapchain is cached here because there are + // no methods for retreiving the currently configured on from ISwapChainPanelNative. + mSwapChain = newSwapChain; + result = newSwapChain.CopyTo(swapChain); + } + + // If the host is responsible for scaling the output of the swapchain, then + // scale it now before returning an instance to the caller. This is done by + // first reading the current size of the swapchain panel, then scaling + if (SUCCEEDED(result)) + { + if (mSwapChainSizeSpecified || mSwapChainScaleSpecified) + { + result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, + ¤tPanelSize); + + // Scale the swapchain to fit inside the contents of the panel. + if (SUCCEEDED(result)) + { + result = scaleSwapChain(currentPanelSize, mClientRect); + } + } + } + + return result; +} + +HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &windowSize, const RECT &clientRect) +{ + Size renderScale = {windowSize.Width / (float)clientRect.right, + windowSize.Height / (float)clientRect.bottom}; + // Setup a scale matrix for the swap chain + DXGI_MATRIX_3X2_F scaleMatrix = {}; + scaleMatrix._11 = renderScale.Width; + scaleMatrix._22 = renderScale.Height; + + ComPtr<IDXGISwapChain2> swapChain2; + HRESULT result = mSwapChain.As(&swapChain2); + if (SUCCEEDED(result)) + { + result = swapChain2->SetMatrixTransform(&scaleMatrix); + } + + return result; +} + +HRESULT GetSwapChainPanelSize( + const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, + const ComPtr<ICoreDispatcher> &dispatcher, + Size *windowSize) +{ + ComPtr<IUIElement> uiElement; + HRESULT result = swapChainPanel.As(&uiElement); + if (SUCCEEDED(result)) + { + result = RunOnUIThread( + [uiElement, windowSize] { return uiElement->get_RenderSize(windowSize); }, dispatcher); + } + + return result; +} +}
\ No newline at end of file diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h new file mode 100755 index 000000000..f9a2fc0e4 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h @@ -0,0 +1,93 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainPanelNativeWindow.h: NativeWindow for managing ISwapChainPanel native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ + +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" + +#include <memory> + +namespace rx +{ +class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this<SwapChainPanelNativeWindow> +{ + public: + ~SwapChainPanelNativeWindow(); + + bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override; + HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory2 *factory, + DXGI_FORMAT format, + unsigned int width, + unsigned int height, + bool containsAlpha, + IDXGISwapChain1 **swapChain) override; + + protected: + HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) override; + + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + + private: + ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> mSwapChainPanel; + ComPtr<ABI::Windows::UI::Core::ICoreDispatcher> mSwapChainPanelDispatcher; + ComPtr<IMap<HSTRING, IInspectable*>> mPropertyMap; + ComPtr<IDXGISwapChain1> mSwapChain; +}; + +[uuid(8ACBD974-8187-4508-AD80-AEC77F93CF36)] +class SwapChainPanelSizeChangedHandler : + public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, ABI::Windows::UI::Xaml::ISizeChangedEventHandler> +{ + public: + SwapChainPanelSizeChangedHandler() { } + HRESULT RuntimeClassInitialize(std::shared_ptr<InspectableNativeWindow> host) + { + if (!host) + { + return E_INVALIDARG; + } + + mHost = host; + return S_OK; + } + + // ISizeChangedEventHandler + IFACEMETHOD(Invoke)(IInspectable *sender, ABI::Windows::UI::Xaml::ISizeChangedEventArgs *sizeChangedEventArgs) + { + std::shared_ptr<InspectableNativeWindow> host = mHost.lock(); + if (host) + { + // The size of the ISwapChainPanel control is returned in DIPs. + // We are keeping these in dips because the swapchain created for composition + // also uses dip units. This keeps dimensions, viewports, etc in the same unit. + // XAML Clients of the ISwapChainPanel are required to use dips to define their + // layout sizes as well. + ABI::Windows::Foundation::Size newSize; + HRESULT result = sizeChangedEventArgs->get_NewSize(&newSize); + if (SUCCEEDED(result)) + { + host->setNewClientSize(newSize); + } + } + + return S_OK; + } + + private: + std::weak_ptr<InspectableNativeWindow> mHost; +}; + +HRESULT GetSwapChainPanelSize( + const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, + const ComPtr<ABI::Windows::UI::Core::ICoreDispatcher> &dispatcher, + Size *windowSize); +} +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow_unittest.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow_unittest.cpp new file mode 100755 index 000000000..026c42449 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow_unittest.cpp @@ -0,0 +1,460 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +// WINAPI_FAMILY is required to be defined as WINAPI_FAMILY_PC_APP +// to ensure that the proper defines are set when including additional +// headers which rely on Windows Store specific configuration. +// This would normally be defined already but this unittest exe is compiled +// as a desktop application which results in WINAPI_FAMILY being +// set to WINAPI_FAMILY_DESKTOP_APP +#undef WINAPI_FAMILY +#define WINAPI_FAMILY WINAPI_FAMILY_PC_APP +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include <angle_windowsstore.h> +#include <windows.ui.xaml.h> +#include <windows.ui.xaml.media.dxinterop.h> + +using namespace rx; +using namespace ABI::Windows::ApplicationModel::Core; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::System; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Data; +using namespace ABI::Windows::UI::Xaml::Media; +using namespace ABI::Windows::UI::Xaml::Input; +using namespace ABI::Windows::UI::Xaml; + +namespace +{ + +// Mock ISwapChainPanel +class MockSwapChainPanel : public ISwapChainPanel, + IFrameworkElement, + IUIElement, + ISwapChainPanelNative +{ + public: + // IUnknown + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) + { + *ppvObject = NULL; + + if (IsEqualIID(IID_IUnknown, riid)) + { + *ppvObject = reinterpret_cast<IUnknown*>(this); + return S_OK; + } + + if (IsEqualIID(IID_IInspectable, riid)) + { + *ppvObject = reinterpret_cast<IInspectable*>(this); + return S_OK; + } + + if (IsEqualIID(IID_ISwapChainPanel, riid)) + { + *ppvObject = static_cast<ISwapChainPanel*>(this); + return S_OK; + } + + if (IsEqualIID(IID_IFrameworkElement, riid)) + { + *ppvObject = static_cast<IFrameworkElement*>(this); + return S_OK; + } + + if (IsEqualIID(IID_IUIElement, riid)) + { + *ppvObject = static_cast<IUIElement*>(this); + return S_OK; + } + + if (IsEqualIID(__uuidof(ISwapChainPanelNative), riid)) + { + *ppvObject = static_cast<ISwapChainPanelNative*>(this); + return S_OK; + } + + return E_NOINTERFACE; + } + + STDMETHOD_(ULONG, AddRef)(){ return 1; } + STDMETHOD_(ULONG, Release)(){ return 1; } + + // IInspectable + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, GetIids, HRESULT(ULONG *, IID**)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, GetRuntimeClassName, HRESULT(HSTRING *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, GetTrustLevel, HRESULT(TrustLevel *)); + + // ISwapChainPanelNative + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, SetSwapChain, HRESULT(IDXGISwapChain *)); + + // ISwapChainPanel + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_CompositionScaleX, HRESULT(FLOAT *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_CompositionScaleY, HRESULT(FLOAT *)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_CompositionScaleChanged, HRESULT(__FITypedEventHandler_2_Windows__CUI__CXaml__CControls__CSwapChainPanel_IInspectable*, EventRegistrationToken*)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_CompositionScaleChanged, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, CreateCoreIndependentInputSource, HRESULT(CoreInputDeviceTypes, ICoreInputSourceBase**)); + + // IFrameworkElement + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Triggers, HRESULT(__FIVector_1_Windows__CUI__CXaml__CTriggerBase **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Resources, HRESULT(IResourceDictionary **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Resources, HRESULT(IResourceDictionary *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Tag, HRESULT(IInspectable **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Tag, HRESULT(IInspectable *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Language, HRESULT(HSTRING *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Language, HRESULT(HSTRING)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_ActualWidth, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_ActualHeight, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Width, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Width, HRESULT(DOUBLE)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Height, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Height, HRESULT(DOUBLE)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_MinWidth, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_MinWidth, HRESULT(DOUBLE)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_MaxWidth, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_MaxWidth, HRESULT(DOUBLE)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_MinHeight, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_MinHeight, HRESULT(DOUBLE)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_MaxHeight, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_MaxHeight, HRESULT(DOUBLE)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_HorizontalAlignment, HRESULT(HorizontalAlignment *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_HorizontalAlignment, HRESULT(HorizontalAlignment)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_VerticalAlignment, HRESULT(VerticalAlignment *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_VerticalAlignment, HRESULT(VerticalAlignment)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Margin, HRESULT(Thickness *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Margin, HRESULT(Thickness)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Name, HRESULT(HSTRING*)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Name, HRESULT(HSTRING)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_BaseUri, HRESULT(IUriRuntimeClass **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_DataContext, HRESULT(IInspectable **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_DataContext, HRESULT(IInspectable *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Style, HRESULT(IStyle **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Style, HRESULT(IStyle *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Parent, HRESULT(IDependencyObject **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_FlowDirection, HRESULT(FlowDirection *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_FlowDirection, HRESULT(FlowDirection)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Loaded, HRESULT(IRoutedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Loaded, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Unloaded, HRESULT(IRoutedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Unloaded, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_SizeChanged, HRESULT(ISizeChangedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_SizeChanged, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_LayoutUpdated, HRESULT(__FIEventHandler_1_IInspectable *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_LayoutUpdated, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, FindName, HRESULT(HSTRING, IInspectable **)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, SetBinding, HRESULT(IDependencyProperty *, IBindingBase *)); + + // IUIElement + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_DesiredSize, HRESULT(ABI::Windows::Foundation::Size *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_AllowDrop, HRESULT(boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_AllowDrop, HRESULT(boolean)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Opacity, HRESULT(DOUBLE *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Opacity, HRESULT(DOUBLE)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Clip, HRESULT(IRectangleGeometry **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Clip, HRESULT(IRectangleGeometry *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_RenderTransform, HRESULT(ITransform **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_RenderTransform, HRESULT(ITransform *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Projection, HRESULT(IProjection **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Projection, HRESULT(IProjection *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_RenderTransformOrigin, HRESULT(Point *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_RenderTransformOrigin, HRESULT(Point)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_IsHitTestVisible, HRESULT(boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_IsHitTestVisible, HRESULT(boolean)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Visibility, HRESULT(Visibility *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Visibility, HRESULT(Visibility)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_RenderSize, HRESULT(Size *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_UseLayoutRounding, HRESULT(boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_UseLayoutRounding, HRESULT(boolean)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Transitions, HRESULT(__FIVector_1_Windows__CUI__CXaml__CMedia__CAnimation__CTransition **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_Transitions, HRESULT(__FIVector_1_Windows__CUI__CXaml__CMedia__CAnimation__CTransition *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_CacheMode, HRESULT(ICacheMode **)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_CacheMode, HRESULT(ICacheMode *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_IsTapEnabled, HRESULT(boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_IsTapEnabled, HRESULT(boolean)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_IsDoubleTapEnabled, HRESULT(boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_IsDoubleTapEnabled, HRESULT(boolean)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_IsRightTapEnabled, HRESULT(boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_IsRightTapEnabled, HRESULT(boolean)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_IsHoldingEnabled, HRESULT(boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_IsHoldingEnabled, HRESULT(boolean)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_ManipulationMode, HRESULT(ManipulationModes *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_ManipulationMode, HRESULT(ManipulationModes)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_PointerCaptures, HRESULT(__FIVectorView_1_Windows__CUI__CXaml__CInput__CPointer **)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_KeyUp, HRESULT(IKeyEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_KeyUp, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_KeyDown, HRESULT(IKeyEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_KeyDown, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_GotFocus, HRESULT(IRoutedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_GotFocus, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_LostFocus, HRESULT(IRoutedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_LostFocus, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_DragEnter, HRESULT(IDragEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_DragEnter, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_DragLeave, HRESULT(IDragEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_DragLeave, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_DragOver, HRESULT(IDragEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_DragOver, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Drop, HRESULT(IDragEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Drop, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerPressed, HRESULT(IPointerEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerPressed, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerMoved, HRESULT(IPointerEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerMoved, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerReleased, HRESULT(IPointerEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerReleased, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerExited, HRESULT(IPointerEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerExited, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerCaptureLost, HRESULT(IPointerEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerCaptureLost, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerCanceled, HRESULT(IPointerEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerCanceled, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerWheelChanged, HRESULT(IPointerEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerWheelChanged, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerEntered, HRESULT(IPointerEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerEntered, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Tapped, HRESULT(ITappedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Tapped, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_DoubleTapped, HRESULT(IDoubleTappedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_DoubleTapped, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Holding, HRESULT(IHoldingEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Holding, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_RightTapped, HRESULT(IRightTappedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_RightTapped, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_ManipulationStarting, HRESULT(IManipulationStartingEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_ManipulationStarting, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_ManipulationInertiaStarting, HRESULT(IManipulationInertiaStartingEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_ManipulationInertiaStarting, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_ManipulationStarted, HRESULT(IManipulationStartedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_ManipulationStarted, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_ManipulationDelta, HRESULT(IManipulationDeltaEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_ManipulationDelta, HRESULT(EventRegistrationToken)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_ManipulationCompleted, HRESULT(IManipulationCompletedEventHandler *, EventRegistrationToken *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_ManipulationCompleted, HRESULT(EventRegistrationToken)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, Measure, HRESULT(Size)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, Arrange, HRESULT(Rect)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, CapturePointer, HRESULT(IPointer *, boolean *)); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, ReleasePointerCapture, HRESULT(IPointer *)); + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, ReleasePointerCaptures, HRESULT()); + MOCK_METHOD3_WITH_CALLTYPE(STDMETHODCALLTYPE, AddHandler, HRESULT(IRoutedEvent *, IInspectable *, boolean)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, RemoveHandler, HRESULT(IRoutedEvent *, IInspectable *)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, TransformToVisual, HRESULT(IUIElement *, IGeneralTransform **)); + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, InvalidateMeasure, HRESULT()); + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, InvalidateArrange, HRESULT()); + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, UpdateLayout, HRESULT()); +}; + +HRESULT CreatePropertyMap(IMap<HSTRING, IInspectable*>** propertyMap) +{ + HRESULT result = S_OK; + ComPtr<IPropertySet> propertySet; + ComPtr<IActivationFactory> propertySetFactory; + result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Collections_PropertySet).Get(), &propertySetFactory); + EXPECT_HRESULT_SUCCEEDED(result); + + result = propertySetFactory->ActivateInstance(&propertySet); + EXPECT_HRESULT_SUCCEEDED(result); + + result = propertySet.CopyTo(propertyMap); + EXPECT_HRESULT_SUCCEEDED(result); + + return result; +} + +HRESULT CreatePropertyValueStatics(IPropertyValueStatics** propertyStatics) +{ + ComPtr<IPropertyValueStatics> propertyValueStatics; + HRESULT result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &propertyValueStatics); + EXPECT_HRESULT_SUCCEEDED(result); + + result = propertyValueStatics.CopyTo(propertyStatics); + EXPECT_HRESULT_SUCCEEDED(result); + + return result; +} + +HRESULT SetInspectablePropertyValue(const ComPtr<IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t* propertyName, IInspectable* inspectable) +{ + boolean propertyReplaced = false; + return propertyMap->Insert(HStringReference(propertyName).Get(), inspectable, &propertyReplaced); +} + +void expectNativeWindowInitCalls(MockSwapChainPanel &panel, bool expectRenderSize) +{ + if (expectRenderSize) + { + EXPECT_CALL(panel, get_RenderSize(testing::_)).Times(1); + } + + EXPECT_CALL(panel, add_SizeChanged(testing::_, testing::_)).Times(1); + EXPECT_CALL(panel, remove_SizeChanged(testing::_)).Times(1); +} + +TEST(NativeWindowTest, SwapChainPanelByItself) +{ + MockSwapChainPanel mockSwapChainPanel; + NativeWindow nativeWindow(reinterpret_cast<IInspectable*>(&mockSwapChainPanel)); + expectNativeWindowInitCalls(mockSwapChainPanel, true); + EXPECT_TRUE(nativeWindow.initialize()); +} + +TEST(NativeWindowTest, SwapChainPanelInPropertySet) +{ + // COM is required to be initialized for creation of the property set + EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); + { + MockSwapChainPanel mockSwapChainPanel; + ComPtr<IMap<HSTRING, IInspectable*>> propertySet; + + // Create a simple property set with the swapchainpanel + EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel))); + + // Check native window init calls + NativeWindow nativeWindow(propertySet.Get()); + expectNativeWindowInitCalls(mockSwapChainPanel, true); + EXPECT_TRUE(nativeWindow.initialize()); + } + CoUninitialize(); +} + +TEST(NativeWindowTest, SwapChainPanelInPropertySetWithSizeAndScale) +{ + // COM is required to be initialized for creation of the property set + EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); + { + MockSwapChainPanel mockSwapChainPanel; + ComPtr<IMap<HSTRING, IInspectable*>> propertySet; + ComPtr<IPropertyValueStatics> propertyValueStatics; + ComPtr<IPropertyValue> singleValue; + ComPtr<IPropertyValue> sizeValue; + + // Create a simple property set with the swapchainpanel + EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel))); + + // Add a valid scale factor to the property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); + propertyValueStatics->CreateSingle(0.5f, reinterpret_cast<IInspectable**>(singleValue.GetAddressOf())); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderResolutionScaleProperty, reinterpret_cast<IInspectable*>(singleValue.Get()))); + + // Add a valid size to the property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); + propertyValueStatics->CreateSize({ 480, 800 }, reinterpret_cast<IInspectable**>(sizeValue.GetAddressOf())); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderSurfaceSizeProperty, reinterpret_cast<IInspectable*>(sizeValue.Get()))); + + // Check native window init fails, since we shouldn't be able to set a size and a scale together + NativeWindow nativeWindow(propertySet.Get()); + EXPECT_FALSE(nativeWindow.initialize()); + } + CoUninitialize(); +} + +// Tests that the scale property works as expected in a property set with a SwapChainPanel +class SwapChainPanelScaleTest : public testing::TestWithParam<std::pair<float, bool>> +{ +}; + +TEST_P(SwapChainPanelScaleTest, ValidateScale) +{ + float scale = GetParam().first; + bool expectedResult = GetParam().second; + + // COM is required to be initialized for creation of the property set + EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); + { + MockSwapChainPanel mockSwapChainPanel; + ComPtr<IMap<HSTRING, IInspectable*>> propertySet; + ComPtr<IPropertyValueStatics> propertyValueStatics; + ComPtr<IPropertyValue> singleValue; + + // Create a simple property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel))); + + // Add a valid scale factor to the property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); + propertyValueStatics->CreateSingle(scale, reinterpret_cast<IInspectable**>(singleValue.GetAddressOf())); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderResolutionScaleProperty, reinterpret_cast<IInspectable*>(singleValue.Get()))); + + // Check native window init status and calls to the mock swapchainpanel + NativeWindow nativeWindow(propertySet.Get()); + if (expectedResult) + { + expectNativeWindowInitCalls(mockSwapChainPanel, true); + } + + EXPECT_EQ(nativeWindow.initialize(), expectedResult); + } + CoUninitialize(); +} + +typedef std::pair<float, bool> scaleValidPair; +static const scaleValidPair scales[] = { scaleValidPair(1.0f, true), + scaleValidPair(0.5f, true), + scaleValidPair(0.0f, false), + scaleValidPair(0.01f, true), + scaleValidPair(2.00f, true) }; + +INSTANTIATE_TEST_CASE_P(NativeWindowTest, + SwapChainPanelScaleTest, + testing::ValuesIn(scales)); + +// Tests that the size property works as expected in a property set with a SwapChainPanel +class SwapChainPanelSizeTest : public testing::TestWithParam<std::tuple<float, float, bool>> +{ +}; + +TEST_P(SwapChainPanelSizeTest, ValidateSize) +{ + Size renderSize = { std::get<0>(GetParam()), std::get<1>(GetParam()) }; + bool expectedResult = std::get<2>(GetParam()); + + // COM is required to be initialized for creation of the property set + EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); + { + MockSwapChainPanel mockSwapChainPanel; + ComPtr<IMap<HSTRING, IInspectable*>> propertySet; + ComPtr<IPropertyValueStatics> propertyValueStatics; + ComPtr<IPropertyValue> sizeValue; + + // Create a simple property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel))); + + // Add a valid size to the property set + EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); + propertyValueStatics->CreateSize(renderSize, reinterpret_cast<IInspectable**>(sizeValue.GetAddressOf())); + EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderSurfaceSizeProperty, reinterpret_cast<IInspectable*>(sizeValue.Get()))); + + // Check native window init status and calls to the mock swapchainpanel + NativeWindow nativeWindow(propertySet.Get()); + if (expectedResult) + { + expectNativeWindowInitCalls(mockSwapChainPanel, false); + } + + EXPECT_EQ(nativeWindow.initialize(), expectedResult); + } + CoUninitialize(); +} + +typedef std::tuple<float, float, bool> sizeValidPair; +static const sizeValidPair sizes[] = { sizeValidPair( 800, 480, true), + sizeValidPair( 0, 480, false), + sizeValidPair( 800, 0, false), + sizeValidPair( 0, 0, false) }; + +INSTANTIATE_TEST_CASE_P(NativeWindowTest, + SwapChainPanelSizeTest, + testing::ValuesIn(sizes)); + +} // namespace |