summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-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')
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp229
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h92
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow_unittest.cpp356
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp276
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h131
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp126
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h50
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp355
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h93
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow_unittest.cpp460
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,
+ &currentPanelSize);
+
+ // 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