Add CanvasComposition, for interop with Windows.UI.Composition

This commit is contained in:
Damyan Pepper 2015-10-13 15:15:48 -07:00
Родитель f9e4af8b74
Коммит f1f6c40b40
40 изменённых файлов: 1913 добавлений и 11 удалений

Просмотреть файл

@ -152,6 +152,7 @@
</UAPProject>
<UAPProject Include="samples\SimpleSample\UAP\SimpleSample.uap.csproj" />
<UAPProject Include="samples\CoreWindowExample\UAP\CoreWindowExample.uap.csproj" />
<UAPProject Include="samples\CompositionExample\CompositionExample.csproj" />
<UAPProject Include="samples\ExampleGallery\Direct3DInterop\UAP\ExampleGallery.Direct3DInterop.uap.vcxproj">
<BuildInParallel>false</BuildInParallel>
</UAPProject>

Просмотреть файл

@ -105,6 +105,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExampleGallery.Direct3DInte
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExampleGallery.Direct3DInterop.Shared", "samples\ExampleGallery\Direct3DInterop\Shared\ExampleGallery.Direct3DInterop.Shared.vcxitems", "{8E486BCA-FE9B-4F99-9D2E-A277905E84EB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompositionExample", "Samples\CompositionExample\CompositionExample.csproj", "{60836F00-A727-402B-AFD7-2779675B29A2}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
winrt\test.managed\Shared\winrt.test.managed.Shared.projitems*{70fb7b71-d56c-4bf1-9282-27aa58043cc0}*SharedItemsImports = 4
@ -321,6 +323,24 @@ Global
{A81F96D0-4924-40E3-A463-3CB9EE55AA93}.Release|Win32.Build.0 = Release|Win32
{A81F96D0-4924-40E3-A463-3CB9EE55AA93}.Release|x64.ActiveCfg = Release|x64
{A81F96D0-4924-40E3-A463-3CB9EE55AA93}.Release|x64.Build.0 = Release|x64
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|ARM.ActiveCfg = Debug|ARM
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|ARM.Build.0 = Debug|ARM
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|ARM.Deploy.0 = Debug|ARM
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|Win32.ActiveCfg = Debug|Win32
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|Win32.Build.0 = Debug|Win32
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|Win32.Deploy.0 = Debug|Win32
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|x64.ActiveCfg = Debug|x64
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|x64.Build.0 = Debug|x64
{60836F00-A727-402B-AFD7-2779675B29A2}.Debug|x64.Deploy.0 = Debug|x64
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|ARM.ActiveCfg = Release|ARM
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|ARM.Build.0 = Release|ARM
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|ARM.Deploy.0 = Release|ARM
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|Win32.ActiveCfg = Release|Win32
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|Win32.Build.0 = Release|Win32
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|Win32.Deploy.0 = Release|Win32
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|x64.ActiveCfg = Release|x64
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|x64.Build.0 = Release|x64
{60836F00-A727-402B-AFD7-2779675B29A2}.Release|x64.Deploy.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -361,5 +381,6 @@ Global
{81A681BB-9434-420E-8A27-1656AEFDCA4B} = {671EACB0-6255-4050-B092-1A874625AD5C}
{A81F96D0-4924-40E3-A463-3CB9EE55AA93} = {81A681BB-9434-420E-8A27-1656AEFDCA4B}
{8E486BCA-FE9B-4F99-9D2E-A277905E84EB} = {81A681BB-9434-420E-8A27-1656AEFDCA4B}
{60836F00-A727-402B-AFD7-2779675B29A2} = {EC7BD4FF-9DAE-4698-9FDA-244478B0203B}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,189 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.UI.Composition;
using System;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.UI.Composition;
using Windows.UI.Core;
namespace CompositionExample
{
class App : IFrameworkView
{
CoreWindow window;
Compositor compositor;
CanvasDevice device;
CompositionGraphicsDevice compositionGraphicsDevice;
DrawingSurfaceRenderer drawingSurfaceRenderer;
SwapChainRenderer swapChainRenderer;
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Random rnd = new Random();
public void Initialize(CoreApplicationView applicationView)
{
applicationView.Activated += applicationView_Activated;
}
public void Uninitialize()
{
swapChainRenderer?.Dispose();
cancellationTokenSource.Cancel();
}
void applicationView_Activated(CoreApplicationView sender, IActivatedEventArgs args)
{
CoreWindow.GetForCurrentThread().Activate();
}
public void Load(string entryPoint)
{
}
public void Run()
{
CoreWindow.GetForCurrentThread().Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);
}
public void SetWindow(CoreWindow window)
{
this.window = window;
CoreApplication.Suspending += CoreApplication_Suspending;
compositor = new Compositor();
CreateDevice();
drawingSurfaceRenderer = new DrawingSurfaceRenderer(compositor, compositionGraphicsDevice);
swapChainRenderer = new SwapChainRenderer(compositor);
swapChainRenderer.SetDevice(device, new Size(window.Bounds.Width, window.Bounds.Height));
drawingSurfaceRenderer.Visual.Offset = new Vector3(-drawingSurfaceRenderer.Size.ToVector2(), 0);
swapChainRenderer.Visual.Offset = new Vector3((float)window.Bounds.Width, (float)window.Bounds.Height, 0);
var rootVisual = compositor.CreateContainerVisual();
rootVisual.Children.InsertAtTop(swapChainRenderer.Visual);
rootVisual.Children.InsertAtTop(drawingSurfaceRenderer.Visual);
compositor.CreateTargetForCurrentView().Root = rootVisual;
var ignoredTask = UpdateVisualsLoop();
}
async Task UpdateVisualsLoop()
{
var token = cancellationTokenSource.Token;
while (!token.IsCancellationRequested)
{
UpdateVisual(swapChainRenderer.Visual, swapChainRenderer.Size);
UpdateVisual(drawingSurfaceRenderer.Visual, drawingSurfaceRenderer.Size);
await Task.Delay(TimeSpan.FromSeconds(2));
}
}
void UpdateVisual(Visual visual, Size size)
{
UpdateVisualPosition(visual, size);
UpdateVisualOpacity(visual);
}
void UpdateVisualPosition(Visual visual, Size size)
{
var oldOffset = visual.Offset;
var newOffset = new Vector3(
(float)(rnd.NextDouble() * (window.Bounds.Width - size.Width)),
(float)(rnd.NextDouble() * (window.Bounds.Height - size.Height)),
0);
visual.Offset = newOffset;
visual.Size = size.ToVector2();
AnimateOffset(visual, oldOffset, newOffset);
}
void UpdateVisualOpacity(Visual visual)
{
var oldOpacity = visual.Opacity;
var newOpacity = (float)rnd.NextDouble();
var animation = compositor.CreateScalarKeyFrameAnimation();
animation.InsertKeyFrame(0, oldOpacity);
animation.InsertKeyFrame(1, newOpacity);
visual.Opacity = newOpacity;
visual.StartAnimation("Opacity", animation);
}
void AnimateOffset(Visual visual, Vector3 oldOffset, Vector3 newOffset)
{
var animation = compositor.CreateVector3KeyFrameAnimation();
animation.InsertKeyFrame(0, oldOffset);
animation.InsertKeyFrame(1, newOffset);
animation.Duration = TimeSpan.FromSeconds(1);
visual.StartAnimation("Offset", animation);
}
void CoreApplication_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs args)
{
try
{
device.Trim();
}
catch (Exception e) when (device.IsDeviceLost(e.HResult))
{
device.RaiseDeviceLost();
}
}
void CreateDevice()
{
device = CanvasDevice.GetSharedDevice();
device.DeviceLost += Device_DeviceLost;
if (compositionGraphicsDevice == null)
{
compositionGraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, device);
}
else
{
CanvasComposition.SetCanvasDevice(compositionGraphicsDevice, device);
}
if (swapChainRenderer != null)
swapChainRenderer.SetDevice(device, new Size(window.Bounds.Width, window.Bounds.Height));
}
void Device_DeviceLost(CanvasDevice sender, object args)
{
device.DeviceLost -= Device_DeviceLost;
var unwaitedTask = window.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => CreateDevice());
}
}
class ViewSource : IFrameworkViewSource
{
public IFrameworkView CreateView()
{
return new App();
}
static void Main(string[] args)
{
CoreApplication.Run(new ViewSource());
}
}
}

Двоичные данные
samples/CompositionExample/Assets/Logo.scale-100.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.1 KiB

Двоичные данные
samples/CompositionExample/Assets/SmallLogo.scale-100.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Двоичные данные
samples/CompositionExample/Assets/SplashScreen.scale-100.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичные данные
samples/CompositionExample/Assets/Square71x71Logo.scale-100.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичные данные
samples/CompositionExample/Assets/StoreLogo.scale-100.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Двоичные данные
samples/CompositionExample/Assets/WideLogo.scale-100.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.6 KiB

Просмотреть файл

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">Win32</Platform>
<ProjectGuid>{60836F00-A727-402B-AFD7-2779675B29A2}</ProjectGuid>
<OutputType>AppContainerExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CompositionExample</RootNamespace>
<AssemblyName>CompositionExample</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<Import Project="..\..\build\Win2D.cs.props" />
<PropertyGroup>
<PackageCertificateKeyFile>$(AssetDir)TemporaryKey.pfx</PackageCertificateKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\winrt\dll\winrt.dll.uap.vcxproj">
<Project>{8cf21e5d-e0a2-4fe7-8e2b-a025cf52dcfb}</Project>
<Name>winrt.dll.uap</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="App.cs" />
<Compile Include="DrawingSurfaceRenderer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SwapChainRenderer.cs" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="$(AssetDir)TemporaryKey.pfx" />
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Content Include="$(AssetDir)RuntimeDirectives.rd.xml" />
<Content Include="Assets\Logo.scale-100.png" />
<Content Include="Assets\SmallLogo.scale-100.png" />
<Content Include="Assets\SplashScreen.scale-100.png" />
<Content Include="Assets\Square71x71Logo.scale-100.png" />
<Content Include="Assets\StoreLogo.scale-100.png" />
<Content Include="Assets\WideLogo.scale-100.png" />
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using Microsoft.Graphics.Canvas.Text;
using Microsoft.Graphics.Canvas.UI.Composition;
using System.Numerics;
using Windows.Foundation;
using Windows.Graphics.DirectX;
using Windows.UI;
using Windows.UI.Composition;
namespace CompositionExample
{
class DrawingSurfaceRenderer
{
SpriteVisual drawingSurfaceVisual;
CompositionDrawingSurface drawingSurface;
public Visual Visual { get { return drawingSurfaceVisual; } }
public Size Size { get { return drawingSurface.Size; } }
public DrawingSurfaceRenderer(Compositor compositor, CompositionGraphicsDevice compositionGraphicsDevice)
{
drawingSurfaceVisual = compositor.CreateSpriteVisual();
drawingSurface = compositionGraphicsDevice.CreateDrawingSurface(new Size(256, 256), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
drawingSurfaceVisual.Brush = compositor.CreateSurfaceBrush(drawingSurface);
DrawDrawingSurface();
compositionGraphicsDevice.RenderingDeviceReplaced += CompositionGraphicsDevice_RenderingDeviceReplaced;
}
void CompositionGraphicsDevice_RenderingDeviceReplaced(CompositionGraphicsDevice sender, RenderingDeviceReplacedEventArgs args)
{
DrawDrawingSurface();
}
void DrawDrawingSurface()
{
using (var ds = CanvasComposition.CreateDrawingSession(drawingSurface))
{
ds.Clear(Colors.Transparent);
var rect = new Rect(new Point(2, 2), (drawingSurface.Size.ToVector2() - new Vector2(4, 4)).ToSize());
ds.FillRoundedRectangle(rect, 15, 15, Colors.LightBlue);
ds.DrawRoundedRectangle(rect, 15, 15, Colors.Gray, 2);
ds.DrawText("This is a composition drawing surface", rect, Colors.Black, new CanvasTextFormat()
{
FontFamily = "Comic Sans MS",
FontSize = 32,
WordWrapping = CanvasWordWrapping.WholeWord,
VerticalAlignment = CanvasVerticalAlignment.Center,
HorizontalAlignment = CanvasHorizontalAlignment.Center
});
}
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
<Identity Name="Win2DCompositionExample" Publisher="CN=Microsoft Corportation" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="b6cfff57-2afa-4919-b308-d3c49d4f7a76" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>Win2D Composition Example</DisplayName>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="CompositionExample.App">
<uap:VisualElements DisplayName="Win2D Composition Example" Square150x150Logo="Assets\Logo.png" Square44x44Logo="Assets\SmallLogo.png" Description="CompositionExample" BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\WideLogo.png" Square71x71Logo="Assets\Square71x71Logo.png">
<uap:ShowNameOnTiles>
<uap:ShowOn Tile="square150x150Logo" />
<uap:ShowOn Tile="wide310x150Logo" />
</uap:ShowNameOnTiles>
</uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
</Capabilities>
</Package>

Просмотреть файл

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("CompositionExample")]
[assembly: AssemblyProduct("Win2D")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyCopyright("Copyright (c) Microsoft Corporation")]
[assembly: ComVisible(false)]

Просмотреть файл

@ -0,0 +1,131 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Text;
using Microsoft.Graphics.Canvas.UI.Composition;
using System;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Composition;
namespace CompositionExample
{
class SwapChainRenderer : IDisposable
{
Compositor compositor;
CanvasSwapChain swapChain;
SpriteVisual swapChainVisual;
CancellationTokenSource swapChainDrawLoopCancellationTokenSource;
int drawCount;
public Visual Visual { get { return swapChainVisual; } }
public Size Size
{
get
{
if (swapChain == null)
return new Size(0, 0);
return swapChain.Size;
}
}
public SwapChainRenderer(Compositor compositor)
{
this.compositor = compositor;
swapChainVisual = compositor.CreateSpriteVisual();
}
public void Dispose()
{
swapChainDrawLoopCancellationTokenSource?.Cancel();
swapChain?.Dispose();
}
public void SetDevice(CanvasDevice device, Size windowSize)
{
swapChainDrawLoopCancellationTokenSource?.Cancel();
swapChain = new CanvasSwapChain(device, 256, 256, 96);
swapChainVisual.Brush = compositor.CreateSurfaceBrush(CanvasComposition.CreateCompositionSurfaceForSwapChain(compositor, swapChain));
swapChainDrawLoopCancellationTokenSource = new CancellationTokenSource();
Task.Factory.StartNew(
DrawLoop,
swapChainDrawLoopCancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
void DrawLoop()
{
var canceled = swapChainDrawLoopCancellationTokenSource.Token;
try
{
while (!canceled.IsCancellationRequested)
{
DrawSwapChain(swapChain);
}
swapChain.Dispose();
}
catch (Exception e) when (swapChain.Device.IsDeviceLost(e.HResult))
{
swapChain.Device.RaiseDeviceLost();
}
}
void DrawSwapChain(CanvasSwapChain swapChain)
{
++drawCount;
using (var ds = swapChain.CreateDrawingSession(Colors.Transparent))
{
var size = swapChain.Size.ToVector2();
var radius = (Math.Min(size.X, size.Y) / 2.0f) - 4.0f;
var center = size / 2;
ds.FillCircle(center, radius, Colors.LightGoldenrodYellow);
ds.DrawCircle(center, radius, Colors.LightGray);
double mu = (-drawCount / 50.0f);
for (int i =0; i < 16; ++i)
{
double a = mu + (i / 16.0) * Math.PI * 2;
var x = (float)Math.Sin(a);
var y = (float)Math.Cos(a);
ds.DrawLine(center, center + new Vector2(x, y) * radius, Colors.Black, 5);
}
var rectLength = Math.Sqrt(radius * radius * 2);
ds.FillCircle(center, (float)rectLength / 2, Colors.LightGoldenrodYellow);
var rect = new Rect(center.X - rectLength / 2, center.Y - rectLength / 2, rectLength, rectLength);
ds.DrawText("This is a swap chain",
rect,
Colors.Black,
new CanvasTextFormat()
{
FontFamily = "Comic Sans MS",
FontSize = 24,
VerticalAlignment = CanvasVerticalAlignment.Center,
HorizontalAlignment = CanvasHorizontalAlignment.Center,
WordWrapping = CanvasWordWrapping.WholeWord,
});
}
swapChain.Present();
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
},
"frameworks": {
"uap10.0": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

Просмотреть файл

@ -39,9 +39,10 @@ namespace ExampleGallery
static AppInfo[] apps =
{
new AppInfo("ExampleGallery", DrawExampleGalleryIcon, Color.FromArgb(255, 0xE7, 0x59, 0x34)) { AddShadow = true },
new AppInfo("CoreWindowExample", DrawCoreWindowIcon, Colors.CornflowerBlue) { ImageScale = 0.6f },
new AppInfo("SimpleSample", DrawSimpleSampleIcon, Colors.CornflowerBlue) { ImageScale = 0.6f },
new AppInfo("ExampleGallery", DrawExampleGalleryIcon, Color.FromArgb(255, 0xE7, 0x59, 0x34)) { AddShadow = true },
new AppInfo("CoreWindowExample", DrawCoreWindowIcon, Colors.CornflowerBlue) { ImageScale = 0.6f },
new AppInfo("SimpleSample", DrawSimpleSampleIcon, Colors.CornflowerBlue) { ImageScale = 0.6f },
new AppInfo("CompositionExample", DrawCompositionExampleIcon, Colors.Goldenrod) { AddShadow = true, ImageScale = 0.6f },
};
@ -255,11 +256,18 @@ namespace ExampleGallery
}
// For CoreWindowExample, we draw the same simple graphics as the sample itself.
// For SimpleSample, we draw the same simple graphics as the sample itself.
static void DrawSimpleSampleIcon(CanvasDrawingSession ds, IconInfo iconInfo)
{
ds.DrawEllipse(155, 115, 80, 30, Colors.Black, 3);
ds.DrawText("Hello, world!", 100, 100, Colors.Yellow);
}
// Generate an icon for CompositionExample
private static void DrawCompositionExampleIcon(CanvasDrawingSession ds, IconInfo iconInfo)
{
ds.DrawText("C", 0, 0, Colors.White);
}
}
}

Просмотреть файл

@ -10,6 +10,7 @@ namespace DocPreprocess
{
new Tag("Experimental", "This API is marked as [Experimental], meaning it may be subject to change in future Win2D releases.") { PropagateTypeTagsToMembers = true },
new Tag("Win10", "This API is available on Windows 10 (Universal Windows Platform) only. It is not supported on Windows 8.1 or Phone 8.1."),
new Tag("TH2", "This API is available on TH2 only.") { PropagateTypeTagsToMembers = true }, // TODO 5874: update with appropriate text
new Tag("NoComposition", "Supported by Win2D but not Windows.UI.Composition."),
};

Просмотреть файл

@ -39,5 +39,27 @@ Licensed under the MIT License. See LICENSE.txt in the project root for license
</summary>
</member>
<member name="N:Windows.UI.Composition">
<summary>
<a href="http://msdn.microsoft.com/library/windows/apps/Windows.UI.Composition">This namespace is documented on MSDN.</a>
</summary>
</member>
<member name="T:Windows.UI.Composition.Compositor">
<tocexclude />
</member>
<member name="T:Windows.UI.Composition.CompositionDrawingSurface">
<tocexclude />
</member>
<member name="T:Windows.UI.Composition.CompositionGraphicsDevice">
<tocexclude />
</member>
<member name="T:Windows.UI.Composition.ICompositionSurface">
<tocexclude />
</member>
</members>
</doc>

Просмотреть файл

@ -9,9 +9,10 @@ Licensed under the MIT License. See LICENSE.txt in the project root for license
<File Source="LICENSE.txt" />
<Sample Source="samples\CoreWindowExample" Destination="CoreWindowExample" />
<Sample Source="samples\ExampleGallery" Destination="ExampleGallery" />
<Sample Source="samples\SimpleSample" Destination="SimpleSample" />
<Sample Source="samples\CoreWindowExample" Destination="CoreWindowExample" />
<Sample Source="samples\ExampleGallery" Destination="ExampleGallery" />
<Sample Source="samples\SimpleSample" Destination="SimpleSample" />
<Sample Source="samples\CompositionExample" Destination="CompositionExample\UAP" />
<Property Name="AssetDir" Value="build\assets\" />

Просмотреть файл

@ -41,6 +41,9 @@ namespace exportsample
{
// Delete all the directories under the sample (leaving any files in the root). This is to allow
// us to catch (re)moved files.
if (!Directory.Exists(sample.Destination))
return;
foreach (var dir in Directory.EnumerateDirectories(sample.Destination))
{
Directory.Delete(dir, true);

Просмотреть файл

@ -0,0 +1,88 @@
<?xml version="1.0"?>
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See LICENSE.txt in the project root for license information.
-->
<doc>
<assembly>
<name>Microsoft.Graphics.Canvas</name>
</assembly>
<members>
<member name="T:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition" Experimental="true" TH2="true">
<summary>
Methods for using Win2D with Windows.UI.Composition.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.CreateCompositionGraphicsDevice(Windows.UI.Composition.Compositor,Microsoft.Graphics.Canvas.CanvasDevice)">
<summary>
Creates a CompositionGraphicsDevice associated with a CanvasDevice.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.CreateCompositionSurfaceForSwapChain(Windows.UI.Composition.Compositor,Microsoft.Graphics.Canvas.CanvasSwapChain)">
<summary>
Creates an ICompositionSurface associated with a CanvasSwapChain.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.CreateDrawingSession(Windows.UI.Composition.CompositionDrawingSurface)">
<summary>
Creates a CanvasDrawingSession for drawing to the given CompositionDrawingSurface.
</summary>
<remarks>
<p>
The initial content of the drawing surface is undefined, so apps
should ensure that they either call Clear or draw over the entire
surface.
</p>
</remarks>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.CreateDrawingSession(Windows.UI.Composition.CompositionDrawingSurface,Windows.Foundation.Rect)">
<summary>
Creates a CanvasDrawingSession for updating a region of the given CompositionDrawingSurface.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.GetCanvasDevice(Windows.UI.Composition.CompositionGraphicsDevice)">
<summary>
Gets the CanvasDevice associated with the given CompositionGraphicsDevice.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.Resize(Windows.UI.Composition.CompositionDrawingSurface,Windows.Foundation.Size)">
<summary>
Resizes the given CompositionDrawingSurface.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.ResumeDrawing(Windows.UI.Composition.CompositionDrawingSurface)">
<summary>
Resumes drawing on the given CompositionDrawingSurface.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.Scroll(Windows.UI.Composition.CompositionDrawingSurface,System.Nullable{Windows.Foundation.Rect},System.Nullable{Windows.Foundation.Rect},Microsoft.Graphics.Canvas.UI.Composition.Point)">
<summary>
Scrolls the given CompositionDrawingSurface.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.SetCanvasDevice(Windows.UI.Composition.CompositionGraphicsDevice,Microsoft.Graphics.Canvas.CanvasDevice)">
<summary>
Sets the CanvasDevice associated with the given CompositionGraphicsDevice.
</summary>
</member>
<member name="M:Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition.SuspendDrawing(Windows.UI.Composition.CompositionDrawingSurface)">
<summary>
Suspends drawing on the given CompositionDrawingSurface.
</summary>
</member>
</members>
</doc>

Просмотреть файл

@ -31,6 +31,10 @@ Licensed under the MIT License. See LICENSE.txt in the project root for license
<summary>This namespace defines common types for using Win2D with UI frameworks.</summary>
</member>
<member name="N:Microsoft.Graphics.Canvas.UI.Composition">
<summary>This namespace provides Win2D interoperability with Windows.UI.Composition.</summary>
</member>
<member name="N:Microsoft.Graphics.Canvas.UI.Xaml">
<summary>This namespace provides Win2D-enabled XAML controls.</summary>
</member>

Просмотреть файл

@ -13,6 +13,14 @@ namespace Windows.Graphics.Imaging
public class SoftwareBitmap { internal SoftwareBitmap() { } }
}
namespace Windows.UI.Composition
{
public class Compositor { internal Compositor() { } }
public class CompositionDrawingSurface { internal CompositionDrawingSurface() { } }
public class CompositionGraphicsDevice { internal CompositionGraphicsDevice() { } }
public interface ICompositionSurface { }
}
namespace Windows.UI.Input.Inking
{
public class InkStroke { internal InkStroke() { } }
@ -200,4 +208,38 @@ namespace Microsoft.Graphics.Canvas.Text
set { throw new System.NotImplementedException(); }
}
}
}
namespace Microsoft.Graphics.Canvas.UI.Composition
{
/// <summary></summary>
public static class CanvasComposition
{
/// <summary></summary>
public static Windows.UI.Composition.CompositionGraphicsDevice CreateCompositionGraphicsDevice(Windows.UI.Composition.Compositor compositor, Microsoft.Graphics.Canvas.CanvasDevice canvasDevice) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static Windows.UI.Composition.ICompositionSurface CreateCompositionSurfaceForSwapChain(Windows.UI.Composition.Compositor compositor, Microsoft.Graphics.Canvas.CanvasSwapChain swapChain) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static Microsoft.Graphics.Canvas.CanvasDrawingSession CreateDrawingSession(Windows.UI.Composition.CompositionDrawingSurface drawingSurface) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static Microsoft.Graphics.Canvas.CanvasDrawingSession CreateDrawingSession(Windows.UI.Composition.CompositionDrawingSurface drawingSurface, global::Windows.Foundation.Rect updateRect) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static Microsoft.Graphics.Canvas.CanvasDevice GetCanvasDevice(Windows.UI.Composition.CompositionGraphicsDevice graphicsDevice) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static void Resize(Windows.UI.Composition.CompositionDrawingSurface drawingSurface, global::Windows.Foundation.Size sizeInPixels) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static void ResumeDrawing(Windows.UI.Composition.CompositionDrawingSurface drawingSurface) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static void Scroll(Windows.UI.Composition.CompositionDrawingSurface drawingSurface, global::Windows.Foundation.Rect? scrollRect, global::Windows.Foundation.Rect? clipRect, Point offset) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static void SetCanvasDevice(Windows.UI.Composition.CompositionGraphicsDevice graphicsDevice, Microsoft.Graphics.Canvas.CanvasDevice canvasDevice) { throw new System.NotImplementedException(); }
/// <summary></summary>
public static void SuspendDrawing(Windows.UI.Composition.CompositionDrawingSurface drawingSurface) { throw new System.NotImplementedException(); }
}
// This shouldn't be necessary, and it is in the wrong namespace, but it
// conflicts with the W.F.Point generated for the numerics docs if it is put
// in the right namespace, and it complains that it can't be found if it
// isn't present at all.
public struct Point { }
}

Просмотреть файл

@ -15,6 +15,7 @@ import "Windows.Graphics.Printing.idl";
#if WINVER > _WIN32_WINNT_WINBLUE
import "Windows.UI.Input.Inking.idl";
import "Windows.UI.Composition.idl";
#endif
#if WINVER <= _WIN32_WINNT_WINBLUE
@ -54,6 +55,7 @@ import "Windows.UI.Input.Inking.idl";
#include "xaml\CanvasSwapChainPanel.abi.idl"
#include "xaml\CanvasVirtualImageSource.abi.idl"
#include "xaml\CanvasVirtualControl.abi.idl"
#include "composition\CanvasComposition.abi.idl"
#include "effects\generated\ArithmeticCompositeEffect.abi.idl"
#include "effects\generated\AtlasEffect.abi.idl"

Просмотреть файл

@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#if WINVER > _WIN32_WINNT_WINBLUE
namespace Microsoft.Graphics.Canvas.UI.Composition
{
runtimeclass CanvasComposition;
[version(VERSION), uuid(162DEB43-1CF5-46F8-A0AF-356B23158F92), exclusiveto(CanvasComposition)]
interface ICanvasCompositionStatics : IInspectable
{
//
// Compositor interop
//
HRESULT CreateCompositionGraphicsDevice(
[in] Windows.UI.Composition.Compositor* compositor,
[in] Microsoft.Graphics.Canvas.CanvasDevice* canvasDevice,
[out, retval] Windows.UI.Composition.CompositionGraphicsDevice** graphicsDevice);
HRESULT CreateCompositionSurfaceForSwapChain(
[in] Windows.UI.Composition.Compositor* compositor,
[in] Microsoft.Graphics.Canvas.CanvasSwapChain* swapChain,
[out, retval] Windows.UI.Composition.ICompositionSurface** compositionSurface);
//
// CompositionGraphicsDevice interop
//
HRESULT GetCanvasDevice(
[in] Windows.UI.Composition.CompositionGraphicsDevice* graphicsDevice,
[out, retval] Microsoft.Graphics.Canvas.CanvasDevice** canvasDevice);
HRESULT SetCanvasDevice(
[in] Windows.UI.Composition.CompositionGraphicsDevice* graphicsDevice,
[in] Microsoft.Graphics.Canvas.CanvasDevice* canvasDevice);
//
// CompositionDrawingSurface interop
//
// NOTE: no ClearColor here. It's up to apps to decide if they want to
// clear or if they want to just draw over the entire region. (Differs
// from CanvasImageSource where we apply this policy).
[overload("CreateDrawingSession")]
HRESULT CreateDrawingSession(
[in] Windows.UI.Composition.CompositionDrawingSurface* drawingSurface,
[out, retval] Microsoft.Graphics.Canvas.CanvasDrawingSession** drawingSession);
[overload("CreateDrawingSession")]
HRESULT CreateDrawingSessionWithUpdateRect(
[in] Windows.UI.Composition.CompositionDrawingSurface* drawingSurface,
[in] Windows.Foundation.Rect updateRect,
[out, retval] Microsoft.Graphics.Canvas.CanvasDrawingSession** drawingSession);
HRESULT SuspendDrawing(
[in] Windows.UI.Composition.CompositionDrawingSurface* drawingSurface);
HRESULT ResumeDrawing(
[in] Windows.UI.Composition.CompositionDrawingSurface* drawingSurface);
// QUESTION: Why isn't this on CompositionDrawingSurface's interface?
//
// NOTE: sizeInPixels is converted to integer by rounding (rather than
// truncating). This is to match the behavior of CreateDrawingSurface.
HRESULT Resize(
[in] Windows.UI.Composition.CompositionDrawingSurface* drawingSurface,
[in] Windows.Foundation.Size sizeInPixels);
// QUESTION: Why isn't this on CompositionDrawingSurface's interface?
//
// NOTE: Rects are converted to RECTs by converting first to l,r,t,b and
// then rounding. Points are converted by rounding. This is to try and
// match CreateDrawingSurface's behavior.
HRESULT Scroll(
[in] Windows.UI.Composition.CompositionDrawingSurface* drawingSurface,
[in] Windows.Foundation.IReference<Windows.Foundation.Rect>* scrollRect,
[in] Windows.Foundation.IReference<Windows.Foundation.Rect>* clipRect,
[in] Windows.Foundation.Point offset);
}
[version(VERSION), static(ICanvasCompositionStatics, VERSION)]
runtimeclass CanvasComposition
{
}
}
#endif

Просмотреть файл

@ -0,0 +1,287 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#include "pch.h"
#if WINVER > _WIN32_WINNT_WINBLUE
#include "CanvasComposition.h"
#include "../utils/ApiInformationAdapter.h"
using namespace ABI::Microsoft::Graphics::Canvas::UI::Composition;
using namespace ABI::Windows::UI::Composition;
ActivatableStaticOnlyFactory(CanvasCompositionStatics);
HRESULT CanvasCompositionStatics::RuntimeClassInitialize()
{
return ExceptionBoundary(
[&]
{
//
// The composition APIs are only available when the Universal API
// Contract v2 is present. To nip any problems in the bud we
// prevent any of the CanvasComposition APIs from being called if
// this contract isn't present.
//
bool compositionApiPresent = ApiInformationAdapter::GetInstance()->IsApiContractPresent(UNIVERSAL_API_CONTRACT, 2);
if (!compositionApiPresent)
ThrowHR(E_NOTIMPL);
});
}
IFACEMETHODIMP CanvasCompositionStatics::CreateCompositionGraphicsDevice(
ICompositor* compositor,
ICanvasDevice* canvasDevice,
ICompositionGraphicsDevice** graphicsDevice)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(compositor);
CheckInPointer(canvasDevice);
CheckAndClearOutPointer(graphicsDevice);
auto d2dDevice = GetWrappedResource<ID2D1Device1>(canvasDevice);
auto compositorInterop = As<ICompositorInterop>(compositor);
ThrowIfFailed(compositorInterop->CreateGraphicsDevice(d2dDevice.Get(), graphicsDevice));
});
}
IFACEMETHODIMP CanvasCompositionStatics::CreateCompositionSurfaceForSwapChain(
ICompositor* compositor,
ICanvasSwapChain* swapChain,
ICompositionSurface** compositionSurface)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(compositor);
CheckInPointer(swapChain);
CheckAndClearOutPointer(compositionSurface);
auto compositorInterop = As<ICompositorInterop>(compositor);
auto dxgiSwapChain = GetWrappedResource<IDXGISwapChain>(swapChain);
ThrowIfFailed(compositorInterop->CreateCompositionSurfaceForSwapChain(dxgiSwapChain.Get(), compositionSurface));
});
}
IFACEMETHODIMP CanvasCompositionStatics::GetCanvasDevice(
ICompositionGraphicsDevice* graphicsDevice,
ICanvasDevice** canvasDevice)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(graphicsDevice);
CheckAndClearOutPointer(canvasDevice);
auto interop = As<ICompositionGraphicsDeviceInterop>(graphicsDevice);
ComPtr<IUnknown> renderingDevice;
ThrowIfFailed(interop->GetRenderingDevice(&renderingDevice));
auto device = ResourceManager::GetOrCreate<ICanvasDevice>(renderingDevice.Get());
ThrowIfFailed(device.CopyTo(canvasDevice));
});
}
IFACEMETHODIMP CanvasCompositionStatics::SetCanvasDevice(
ICompositionGraphicsDevice* graphicsDevice,
ICanvasDevice* canvasDevice)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(graphicsDevice);
CheckInPointer(canvasDevice);
auto interop = As<ICompositionGraphicsDeviceInterop>(graphicsDevice);
auto d2dDevice = GetWrappedResource<ID2D1Device>(canvasDevice);
ThrowIfFailed(interop->SetRenderingDevice(d2dDevice.Get()));
});
}
IFACEMETHODIMP CanvasCompositionStatics::CreateDrawingSession(
ICompositionDrawingSurface* drawingSurface,
ICanvasDrawingSession** drawingSession)
{
return CreateDrawingSessionImpl(drawingSurface, nullptr, drawingSession);
}
static RECT ToRECTForCompositor(Rect const& rect)
{
RECT r{};
r.left = static_cast<LONG>(std::round(rect.X));
r.right = static_cast<LONG>(std::round(rect.X + rect.Width));
r.top = static_cast<LONG>(std::round(rect.Y));
r.bottom = static_cast<LONG>(std::round(rect.Y + rect.Height));
return r;
}
IFACEMETHODIMP CanvasCompositionStatics::CreateDrawingSessionWithUpdateRect(
ICompositionDrawingSurface* drawingSurface,
Rect updateRect,
ICanvasDrawingSession** drawingSession)
{
RECT rect = ToRECTForCompositor(updateRect);
return CreateDrawingSessionImpl(drawingSurface, &rect, drawingSession);
}
class CompositionDrawingSurfaceDrawingSessionAdapter
: public DrawingSessionBaseAdapter
, private LifespanTracker<CompositionDrawingSurfaceDrawingSessionAdapter>
{
ComPtr<ICompositionDrawingSurfaceInterop> m_drawingSurface;
public:
CompositionDrawingSurfaceDrawingSessionAdapter(ComPtr<ICompositionDrawingSurfaceInterop>&& drawingSurface)
: m_drawingSurface(std::move(drawingSurface))
{
}
virtual void EndDraw(ID2D1DeviceContext1*) override
{
ThrowIfFailed(m_drawingSurface->EndDraw());
}
};
HRESULT CanvasCompositionStatics::CreateDrawingSessionImpl(ICompositionDrawingSurface* drawingSurface, RECT const* updateRect, ICanvasDrawingSession** drawingSession)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(drawingSurface);
CheckAndClearOutPointer(drawingSession);
auto drawingSurfaceInterop = As<ICompositionDrawingSurfaceInterop>(drawingSurface);
ComPtr<ID2D1DeviceContext> deviceContext;
POINT offset;
ThrowIfFailed(drawingSurfaceInterop->BeginDraw(updateRect, IID_PPV_ARGS(&deviceContext), &offset));
deviceContext->SetTransform(D2D1::Matrix3x2F::Translation((float)offset.x, (float)offset.y));
// Although we could look up the owner using interop, via the
// deviceContext, drawing session will do this lazily for us if
// anyone actually requests it.
ICanvasDevice* owner = nullptr;
auto newDs = CanvasDrawingSession::CreateNew(
As<ID2D1DeviceContext1>(deviceContext).Get(),
std::make_shared<CompositionDrawingSurfaceDrawingSessionAdapter>(std::move(drawingSurfaceInterop)),
owner,
D2D1_POINT_2F{ (float)offset.x, (float)offset.y });
ThrowIfFailed(newDs.CopyTo(drawingSession));
});
}
IFACEMETHODIMP CanvasCompositionStatics::SuspendDrawing(
ICompositionDrawingSurface* drawingSurface)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(drawingSurface);
auto drawingSurfaceInterop = As<ICompositionDrawingSurfaceInterop>(drawingSurface);
ThrowIfFailed(drawingSurfaceInterop->SuspendDraw());
});
}
IFACEMETHODIMP CanvasCompositionStatics::ResumeDrawing(
ICompositionDrawingSurface* drawingSurface)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(drawingSurface);
auto drawingSurfaceInterop = As<ICompositionDrawingSurfaceInterop>(drawingSurface);
ThrowIfFailed(drawingSurfaceInterop->ResumeDraw());
});
}
IFACEMETHODIMP CanvasCompositionStatics::Resize(
ICompositionDrawingSurface* drawingSurface,
Size size)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(drawingSurface);
SIZE newSize{};
newSize.cx = static_cast<LONG>(std::round(size.Width));
newSize.cy = static_cast<LONG>(std::round(size.Height));
auto drawingSurfaceInterop = As<ICompositionDrawingSurfaceInterop>(drawingSurface);
ThrowIfFailed(drawingSurfaceInterop->Resize(newSize));
});
}
static RECT MaybeGetRECT(IReference<Rect>* maybeRect)
{
RECT r{};
if (!maybeRect)
return r;
Rect rect;
ThrowIfFailed(maybeRect->get_Value(&rect));
return ToRECTForCompositor(rect);
}
IFACEMETHODIMP CanvasCompositionStatics::Scroll(
ICompositionDrawingSurface* drawingSurface,
IReference<Rect>* scrollRect,
IReference<Rect>* clipRect,
Point offset)
{
return ExceptionBoundary(
[&]
{
CheckInPointer(drawingSurface);
RECT scroll = MaybeGetRECT(scrollRect);
RECT clip = MaybeGetRECT(clipRect);
int offsetX = static_cast<int>(std::round(offset.X));
int offsetY = static_cast<int>(std::round(offset.Y));
auto drawingSurfaceInterop = As<ICompositionDrawingSurfaceInterop>(drawingSurface);
ThrowIfFailed(drawingSurfaceInterop->Scroll(
scrollRect ? &scroll : nullptr,
clipRect ? &clip : nullptr,
offsetX,
offsetY));
});
}
#endif

Просмотреть файл

@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#pragma once
#if WINVER > _WIN32_WINNT_WINBLUE
namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas { namespace UI { namespace Composition
{
using namespace ABI::Windows::UI::Composition;
class CanvasCompositionStatics : public ActivationFactory<ICanvasCompositionStatics>
{
InspectableClassStatic(RuntimeClass_Microsoft_Graphics_Canvas_UI_Composition_CanvasComposition, BaseTrust);
public:
HRESULT RuntimeClassInitialize();
IFACEMETHODIMP CreateCompositionGraphicsDevice(
ICompositor* compositor,
ICanvasDevice* canvasDevice,
ICompositionGraphicsDevice** graphicsDevice) override;
IFACEMETHODIMP CreateCompositionSurfaceForSwapChain(
ICompositor* compositor,
ICanvasSwapChain* swapChain,
ICompositionSurface** compositionSurface) override;
IFACEMETHODIMP GetCanvasDevice(
ICompositionGraphicsDevice* graphicsDevice,
ICanvasDevice** canvasDevice) override;
IFACEMETHODIMP SetCanvasDevice(
ICompositionGraphicsDevice* graphicsDevice,
ICanvasDevice* canvasDevice) override;
IFACEMETHODIMP CreateDrawingSession(
ICompositionDrawingSurface* drawingSurface,
ICanvasDrawingSession** drawingSession) override;
IFACEMETHODIMP CreateDrawingSessionWithUpdateRect(
ICompositionDrawingSurface* drawingSurface,
Rect updateRect,
ICanvasDrawingSession** drawingSession) override;
IFACEMETHODIMP SuspendDrawing(
ICompositionDrawingSurface* drawingSurface) override;
IFACEMETHODIMP ResumeDrawing(
ICompositionDrawingSurface* drawingSurface) override;
IFACEMETHODIMP Resize(
ICompositionDrawingSurface* drawingSurface,
Size size) override;
IFACEMETHODIMP Scroll(
ICompositionDrawingSurface* drawingSurface,
IReference<Rect>* scrollRect,
IReference<Rect>* clipRect,
Point offset) override;
private:
HRESULT CreateDrawingSessionImpl(ICompositionDrawingSurface* drawingSurface, RECT const* rect, ICanvasDrawingSession** drawingSession);
};
} } } } } }
#endif

Просмотреть файл

@ -69,6 +69,12 @@
#include <windows.ui.xaml.media.dxinterop.h>
#include <windows.graphics.display.h>
#if WINVER > _WIN32_WINNT_WINBLUE
#include <windows.foundation.metadata.h>
#include <windows.ui.composition.h>
#include <windows.ui.composition.interop.h>
#endif
#pragma warning(default: 4265) // "class has virtual functions, but destructor is not virtual"
// Public

Просмотреть файл

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#include "pch.h"
#if WINVER > _WIN32_WINNT_WINBLUE
#include "ApiInformationAdapter.h"
using namespace ABI::Windows::Foundation::Metadata;
bool DefaultApiInformationAdapter::IsApiContractPresent(wchar_t const* contractName, int majorVersion)
{
assert(majorVersion >= 0 && majorVersion <= 0xFF);
ComPtr<IApiInformationStatics> apiInformation;
ThrowIfFailed(GetActivationFactory(
HStringReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(),
&apiInformation));
boolean isPresent;
ThrowIfFailed(apiInformation->IsApiContractPresentByMajor(
HStringReference(contractName).Get(),
static_cast<uint16_t>(majorVersion),
&isPresent));
return !!isPresent;
}
#endif

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#pragma once
class DefaultApiInformationAdapter;
static wchar_t const* UNIVERSAL_API_CONTRACT = L"Windows.Foundation.UniversalApiContract";
//
// Adapter for accessing information about which APIs are present on the system
// via Windows.Foundation.Metadata.ApiInformation.
//
class ApiInformationAdapter : public Singleton<ApiInformationAdapter, DefaultApiInformationAdapter>
{
public:
virtual ~ApiInformationAdapter() = default;
virtual bool IsApiContractPresent(wchar_t const* contractName, int majorVersion) = 0;
};
//
// Default implementation of ApiInformationAdapter calls through to
// Windows.Foundation.Metadata.ApiInformation.
//
class DefaultApiInformationAdapter : public ApiInformationAdapter
{
public:
virtual bool IsApiContractPresent(wchar_t const* contractName, int majorVersion) override;
};

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
@ -45,6 +45,7 @@
<Exec Command="$(MdMergeExe) -v @(MetaDataDir -> '-metadata_dir &quot;%(Identity)&quot;', ' ') -o &quot;$(MergedWinmdDirectory)&quot; -i &quot;$(UnmergedWinmdDirectory)&quot; -partial -n:Microsoft.Graphics.Canvas:3" />
</Target>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)composition\CanvasComposition.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)drawing\CanvasActiveLayer.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)drawing\DeviceContextPool.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)effects\generated\ChromaKeyEffect.h" />
@ -78,6 +79,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)printing\CanvasPrintTaskOptionsChangedEventArgs.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)printing\DeferrableTask.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)printing\DeferrableTaskScheduler.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)utils\ApiInformationAdapter.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)utils\CachedResourceReference.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)utils\LockUtilities.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)utils\TemporaryTransform.h" />
@ -166,6 +168,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)utils\Strings.inl" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)composition\CanvasComposition.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)effects\generated\ChromaKeyEffect.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)effects\generated\ContrastEffect.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)effects\generated\EdgeDetectionEffect.cpp" />
@ -197,6 +200,7 @@
<ClCompile Include="$(MSBuildThisFileDirectory)printing\CanvasPrintDocumentAdapter.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)printing\CanvasPrintEventArgs.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)printing\DeferrableTask.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)utils\ApiInformationAdapter.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)utils\ResourceManager.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)xaml\CanvasAnimatedControl.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)xaml\CanvasAnimatedControlAdapter.cpp" />
@ -278,6 +282,7 @@
</MidlRT>
<None Include="$(MSBuildThisFileDirectory)Canvas.codegen.idl" />
<None Include="$(MSBuildThisFileDirectory)brushes\CanvasBrush.abi.idl" />
<None Include="$(MSBuildThisFileDirectory)composition\CanvasComposition.abi.idl" />
<None Include="$(MSBuildThisFileDirectory)xaml\CanvasAnimatedControl.abi.idl" />
<None Include="$(MSBuildThisFileDirectory)xaml\CanvasControl.abi.idl" />
<None Include="$(MSBuildThisFileDirectory)xaml\CanvasImageSource.abi.idl" />

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="effects">
@ -34,6 +34,9 @@
<Filter Include="printing">
<UniqueIdentifier>{007da80b-0c24-4f3a-a5be-1ec320c18646}</UniqueIdentifier>
</Filter>
<Filter Include="composition">
<UniqueIdentifier>{6833e68e-c2a4-4af0-a737-aa8e537554c8}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<MidlRT Include="$(MSBuildThisFileDirectory)Canvas.abi.idl" />
@ -346,6 +349,12 @@
<ClCompile Include="$(MSBuildThisFileDirectory)printing\DeferrableTask.cpp">
<Filter>printing</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)composition\CanvasComposition.cpp">
<Filter>composition</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)utils\ApiInformationAdapter.cpp">
<Filter>utils</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)pch.h" />
@ -703,6 +712,12 @@
<ClInclude Include="$(MSBuildThisFileDirectory)printing\DeferrableTaskScheduler.h">
<Filter>printing</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)composition\CanvasComposition.h">
<Filter>composition</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)utils\ApiInformationAdapter.h">
<Filter>utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Canvas.codegen.idl" />
@ -949,5 +964,8 @@
<None Include="$(MSBuildThisFileDirectory)printing\CanvasPrintDocument.abi.idl">
<Filter>printing</Filter>
</None>
<None Include="$(MSBuildThisFileDirectory)composition\CanvasComposition.abi.idl">
<Filter>composition</Filter>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,432 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#include "pch.h"
#if WINVER > _WIN32_WINNT_WINBLUE
#include <lib/composition/CanvasComposition.h>
using namespace ABI::Microsoft::Graphics::Canvas::UI::Composition;
static int const AnyOffsetX = 123;
static int const AnyOffsetY = -456;
static HRESULT const AnyErrorResult = 0x81234567;
static ComPtr<ICanvasCompositionStatics> GetCompositionStatics()
{
ComPtr<ICanvasCompositionStatics> composition;
ThrowIfFailed(MakeAndInitialize<CanvasCompositionStatics>(&composition));
return composition;
}
TEST_CLASS(CanvasCompositionUnitTests)
{
public:
struct Fixture
{
std::shared_ptr<ApiInformationTestAdapter> ApiInformation = ApiInformationTestAdapter::Create();
ComPtr<ICanvasCompositionStatics> Composition;
Fixture()
{
ApiInformation->AddContract(UNIVERSAL_API_CONTRACT, 2);
Composition = GetCompositionStatics();
}
Fixture(Fixture const&) = delete;
Fixture& operator=(Fixture const&) = delete;
};
TEST_METHOD_EX(CanvasComposition_CreateCompositionGraphicsDevice_FailsWhenPassedNullParameters)
{
Fixture f;
auto compositor = Make<MockCompositor>();
auto canvasDevice = Make<MockCanvasDevice>();
ComPtr<ICompositionGraphicsDevice> graphicsDevice;
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateCompositionGraphicsDevice(nullptr, canvasDevice.Get(), &graphicsDevice));
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateCompositionGraphicsDevice(compositor.Get(), nullptr, &graphicsDevice));
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateCompositionGraphicsDevice(compositor.Get(), canvasDevice.Get(), nullptr));
}
TEST_METHOD_EX(CanvasComposition_CreateCompositionGraphicsDevice)
{
Fixture f;
auto compositor = Make<MockCompositor>();
auto d2dDevice = Make<StubD2DDevice>();
auto canvasDevice = Make<CanvasDevice>(d2dDevice.Get());
auto graphicsDevice = Make<MockCompositionGraphicsDevice>();
compositor->CreateGraphicsDeviceMethod.SetExpectedCalls(1,
[&] (IUnknown* renderingDevice, ICompositionGraphicsDevice** value)
{
Assert::IsTrue(IsSameInstance(d2dDevice.Get(), renderingDevice));
return graphicsDevice.CopyTo(value);
});
ComPtr<ICompositionGraphicsDevice> actualGraphicsDevice;
ThrowIfFailed(f.Composition->CreateCompositionGraphicsDevice(compositor.Get(), canvasDevice.Get(), &actualGraphicsDevice));
Assert::IsTrue(IsSameInstance(graphicsDevice.Get(), actualGraphicsDevice.Get()));
}
TEST_METHOD_EX(CanvasComposition_CreateCompositionSurfaceForSwapChain_FailsWhenPassedNullParameters)
{
Fixture f;
auto compositor = Make<MockCompositor>();
auto swapChain = Make<MockCanvasSwapChain>();
ComPtr<ICompositionSurface> compositionSurface;
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateCompositionSurfaceForSwapChain(nullptr, swapChain.Get(), &compositionSurface));
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateCompositionSurfaceForSwapChain(compositor.Get(), nullptr, &compositionSurface));
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateCompositionSurfaceForSwapChain(compositor.Get(), swapChain.Get(), nullptr));
}
TEST_METHOD_EX(CanvasComposition_CreateCompositionSurfaceForSwapChain)
{
Fixture f;
auto compositor = Make<MockCompositor>();
auto dxgiSwapChain = Make<MockDxgiSwapChain>();
auto canvasDevice = Make<MockCanvasDevice>();
auto canvasSwapChain = Make<CanvasSwapChain>(canvasDevice.Get(), dxgiSwapChain.Get(), DEFAULT_DPI, false);
auto compositionSurface = Make<RuntimeClass<ICompositionSurface>>();
compositor->CreateCompositionSurfaceForSwapChainMethod.SetExpectedCalls(1,
[&] (IUnknown* swapChain, ICompositionSurface** value)
{
Assert::IsTrue(IsSameInstance(dxgiSwapChain.Get(), swapChain));
return compositionSurface.CopyTo(value);
});
ComPtr<ICompositionSurface> actualCompositionSurface;
ThrowIfFailed(f.Composition->CreateCompositionSurfaceForSwapChain(compositor.Get(), canvasSwapChain.Get(), &actualCompositionSurface));
Assert::IsTrue(IsSameInstance(compositionSurface.Get(), actualCompositionSurface.Get()));
}
TEST_METHOD_EX(CanvasComposition_GetCanvasDevice_FailsWhenPassedNullParameters)
{
Fixture f;
auto graphicsDevice = Make<MockCompositionGraphicsDevice>();
ComPtr<ICanvasDevice> canvasDevice;
Assert::AreEqual(E_INVALIDARG, f.Composition->GetCanvasDevice(nullptr, &canvasDevice));
Assert::AreEqual(E_INVALIDARG, f.Composition->GetCanvasDevice(graphicsDevice.Get(), nullptr));
}
TEST_METHOD_EX(CanvasComposition_GetCanvasDevice)
{
Fixture f;
auto graphicsDevice = Make<MockCompositionGraphicsDevice>();
auto d2dDevice = Make<StubD2DDevice>();
auto canvasDevice = Make<CanvasDevice>(d2dDevice.Get());
graphicsDevice->GetRenderingDeviceMethod.SetExpectedCalls(1,
[&] (IUnknown** value)
{
return d2dDevice.CopyTo(value);
});
ComPtr<ICanvasDevice> actualCanvasDevice;
ThrowIfFailed(f.Composition->GetCanvasDevice(graphicsDevice.Get(), &actualCanvasDevice));
Assert::IsTrue(IsSameInstance(canvasDevice.Get(), actualCanvasDevice.Get()));
}
TEST_METHOD_EX(CanvasComposition_SetCanvasDevice_FailsWhenPassedNullParameters)
{
Fixture f;
auto graphicsDevice = Make<MockCompositionGraphicsDevice>();
auto canvasDevice = Make<MockCanvasDevice>();
Assert::AreEqual(E_INVALIDARG, f.Composition->SetCanvasDevice(nullptr, canvasDevice.Get()));
Assert::AreEqual(E_INVALIDARG, f.Composition->SetCanvasDevice(graphicsDevice.Get(), nullptr));
}
TEST_METHOD_EX(CanvasComposition_SetCanvasDevice)
{
Fixture f;
auto graphicsDevice = Make<MockCompositionGraphicsDevice>();
auto d2dDevice = Make<StubD2DDevice>();
auto canvasDevice = Make<CanvasDevice>(d2dDevice.Get());
graphicsDevice->SetRenderingDeviceMethod.SetExpectedCalls(1,
[&] (IUnknown* value)
{
Assert::IsTrue(IsSameInstance(d2dDevice.Get(), value));
return S_OK;
});
ThrowIfFailed(f.Composition->SetCanvasDevice(graphicsDevice.Get(), canvasDevice.Get()));
}
TEST_METHOD_EX(CanvasComposition_CreateDrawingSession_FailsWhenPassedNullParameters)
{
Fixture f;
auto drawingSurface = Make<MockCompositionDrawingSurface>();
ComPtr<ICanvasDrawingSession> drawingSession;
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateDrawingSession(nullptr, &drawingSession));
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateDrawingSession(drawingSurface.Get(), nullptr));
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateDrawingSessionWithUpdateRect(nullptr, Rect{}, &drawingSession));
Assert::AreEqual(E_INVALIDARG, f.Composition->CreateDrawingSessionWithUpdateRect(drawingSurface.Get(), Rect{}, nullptr));
}
struct DrawingSurfaceFixture : public Fixture
{
ComPtr<MockCompositionDrawingSurface> DrawingSurface = Make<MockCompositionDrawingSurface>();
};
struct DrawingSessionFixture : public DrawingSurfaceFixture
{
ComPtr<StubD2DDeviceContext> D2DDeviceContext = Make<StubD2DDeviceContext>();
DrawingSessionFixture()
{
D2DDeviceContext->SetTransformMethod.SetExpectedCalls(1,
[&] (D2D1_MATRIX_3X2_F const* m)
{
Assert::AreEqual(1.0f, m->_11);
Assert::AreEqual(0.0f, m->_12);
Assert::AreEqual(0.0f, m->_21);
Assert::AreEqual(1.0f, m->_22);
Assert::AreEqual((float)AnyOffsetX, m->_31);
Assert::AreEqual((float)AnyOffsetY, m->_32);
});
}
HRESULT DoBeginDraw(REFIID iid, void** updateObject, POINT* updateOffset)
{
Assert::AreEqual(__uuidof(ID2D1DeviceContext), iid);
ThrowIfFailed(D2DDeviceContext.CopyTo(iid, updateObject));
*updateOffset = POINT{ AnyOffsetX, AnyOffsetY };
return S_OK;
}
void Check(ComPtr<ICanvasDrawingSession> drawingSession)
{
auto actualDeviceContext = GetWrappedResource<ID2D1DeviceContext1>(drawingSession);
Assert::IsTrue(IsSameInstance(D2DDeviceContext.Get(), actualDeviceContext.Get()));
// the return value from EndDraw should be passed back through Close()
DrawingSurface->EndDrawMethod.SetExpectedCalls(1,
[&]
{
return AnyErrorResult;
});
Assert::AreEqual(AnyErrorResult, As<IClosable>(drawingSession)->Close());
}
};
TEST_METHOD_EX(CanvasComposition_CreateDrawingSession)
{
DrawingSessionFixture f;
f.DrawingSurface->BeginDrawMethod.SetExpectedCalls(1,
[&] (const RECT* updateRect, REFIID iid, void** updateObject, POINT* updateOffset)
{
Assert::IsNull(updateRect);
return f.DoBeginDraw(iid, updateObject, updateOffset);
});
ComPtr<ICanvasDrawingSession> drawingSession;
ThrowIfFailed(f.Composition->CreateDrawingSession(f.DrawingSurface.Get(), &drawingSession));
f.Check(drawingSession);
}
TEST_METHOD_EX(CanvasComposition_CreateDrawingSessionWithUpdateRect)
{
DrawingSessionFixture f;
Rect anyRect{};
anyRect.X = 1.1f;
anyRect.Y = 2.1f;
anyRect.Width = 3.1f;
anyRect.Height = 4.4f;
RECT anyRECT;
anyRECT.left = 1;
anyRECT.right = 4; // (1.1 + 3.1) = (4.2) - Composition rounds, so this becomes 4
anyRECT.top = 2;
anyRECT.bottom = 7; // (2.1 + 4.4) = (6.5) - Composition rounds, so this becomes 7.
f.DrawingSurface->BeginDrawMethod.SetExpectedCalls(1,
[&] (const RECT* updateRect, REFIID iid, void** updateObject, POINT* updateOffset)
{
Assert::IsNotNull(updateRect);
Assert::AreEqual(anyRECT, *updateRect);
return f.DoBeginDraw(iid, updateObject, updateOffset);
});
ComPtr<ICanvasDrawingSession> drawingSession;
ThrowIfFailed(f.Composition->CreateDrawingSessionWithUpdateRect(f.DrawingSurface.Get(), anyRect, &drawingSession));
f.Check(drawingSession);
}
TEST_METHOD_EX(CanvasComposition_SuspendDrawing_FailsWhenPassedNullParameters)
{
Fixture f;
Assert::AreEqual(E_INVALIDARG, f.Composition->SuspendDrawing(nullptr));
}
TEST_METHOD_EX(CanvasComposition_SuspendDrawing)
{
DrawingSurfaceFixture f;
f.DrawingSurface->SuspendDrawMethod.SetExpectedCalls(1,
[]
{
return AnyErrorResult;
});
Assert::AreEqual(AnyErrorResult, f.Composition->SuspendDrawing(f.DrawingSurface.Get()));
}
TEST_METHOD_EX(CanvasComposition_ResumeDrawing_FailsWhenPassedNullParameters)
{
Fixture f;
Assert::AreEqual(E_INVALIDARG, f.Composition->ResumeDrawing(nullptr));
}
TEST_METHOD_EX(CanvasComposition_ResumeDrawing)
{
DrawingSurfaceFixture f;
f.DrawingSurface->ResumeDrawMethod.SetExpectedCalls(1,
[]
{
return AnyErrorResult;
});
Assert::AreEqual(AnyErrorResult, f.Composition->ResumeDrawing(f.DrawingSurface.Get()));
}
TEST_METHOD_EX(CanvasComposition_Resize_FailsWhenPassedNullParameters)
{
DrawingSurfaceFixture f;
Assert::AreEqual(E_INVALIDARG, f.Composition->Resize(nullptr, Size{}));
}
TEST_METHOD_EX(CanvasComposition_Resize)
{
DrawingSurfaceFixture f;
Size anySize{ 12.49f, 12.50f };
SIZE expectedSIZE{ 12, 13 }; // Compositor rounds rather than truncates
f.DrawingSurface->ResizeMethod.SetExpectedCalls(1,
[&] (SIZE size)
{
Assert::AreEqual(expectedSIZE.cx, size.cx);
Assert::AreEqual(expectedSIZE.cy, size.cy);
return AnyErrorResult;
});
Assert::AreEqual(AnyErrorResult, f.Composition->Resize(f.DrawingSurface.Get(), anySize));
}
TEST_METHOD_EX(CanvasComposition_Scroll_FailsWhenPassedNullParameters)
{
DrawingSurfaceFixture f;
IReference<Rect>* nullScrollRectIsValid = nullptr;
IReference<Rect>* nullClipRectIsValid = nullptr;
Assert::AreEqual(E_INVALIDARG, f.Composition->Scroll(nullptr, nullScrollRectIsValid, nullClipRectIsValid, Point{}));
}
struct ScrollFixture : public DrawingSurfaceFixture
{
Rect ScrollRectValue{ 1.1f, 1.4f, 2.3f, 2.1f };
Rect ClipRectValue{ 3.4f, 3.4f, 4.1f, 4.0f };
RECT ExpectedScrollRect{ 1, 1, 3, 4 };
RECT ExpectedClipRect{ 3, 3, 8, 7 };
ComPtr<IReference<Rect>> ScrollRect = Make<Nullable<Rect>>(ScrollRectValue);
ComPtr<IReference<Rect>> ClipRect = Make<Nullable<Rect>>(ClipRectValue);
void Test(bool scroll, bool clip)
{
Point offset{ -1.5f, 1.5f };
int expectedOffsetX = -2;
int expectedOffsetY = 2;
DrawingSurface->ScrollMethod.SetExpectedCalls(1,
[=] (RECT const* scrollRect, RECT const* clipRect, int offsetX, int offsetY)
{
if (scroll)
Assert::AreEqual(ExpectedScrollRect, *scrollRect);
else
Assert::IsNull(scrollRect);
if (clip)
Assert::AreEqual(ExpectedClipRect, *clipRect);
else
Assert::IsNull(clipRect);
Assert::AreEqual(expectedOffsetX, offsetX);
Assert::AreEqual(expectedOffsetY, offsetY);
return AnyErrorResult;
});
Assert::AreEqual(AnyErrorResult, Composition->Scroll(
DrawingSurface.Get(),
scroll ? ScrollRect.Get() : nullptr,
clip ? ClipRect.Get() : nullptr,
offset));
}
};
TEST_METHOD_EX(CanvasComposition_Scroll_NoRects)
{
ScrollFixture f;
f.Test(false, false);
}
TEST_METHOD_EX(CanvasComposition_Scroll_ScrollRect)
{
ScrollFixture f;
f.Test(true, false);
}
TEST_METHOD_EX(CanvasComposition_Scroll_ClipRect)
{
ScrollFixture f;
f.Test(false, true);
}
TEST_METHOD_EX(CanvasComposition_Scroll_ScrollRectAndClipRect)
{
ScrollFixture f;
f.Test(true, true);
}
TEST_METHOD_EX(CanvasComposition_When_CompositionApiNotPresent_CannotActivate)
{
auto apiInformation = ApiInformationTestAdapter::Create();
ExpectHResultException(E_NOTIMPL, [] { GetCompositionStatics(); });
}
};
#endif

Просмотреть файл

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#pragma once
#if WINVER > _WIN32_WINNT_WINBLUE
class MockCompositionDrawingSurface : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>,
ICompositionDrawingSurface,
ICompositionDrawingSurfaceInterop>
{
public:
// ICompositionDrawingSurface
MOCK_METHOD1(get_AlphaMode , HRESULT(DirectXAlphaMode* value));
MOCK_METHOD1(get_PixelFormat , HRESULT(DirectXPixelFormat* value));
MOCK_METHOD1(get_Size , HRESULT(Size *value));
// ICompositionDrawingSurfaceInterop
MOCK_METHOD4(BeginDraw, HRESULT(const RECT* updateRect, REFIID iid, void** updateObject, POINT* updateOffset));
MOCK_METHOD0(EndDraw, HRESULT());
MOCK_METHOD1(Resize, HRESULT(SIZE pixelSize));
MOCK_METHOD4(Scroll, HRESULT(const RECT* scrollRect, const RECT* clipRect, int offsetX, int offsetY));
MOCK_METHOD0(ResumeDraw, HRESULT());
MOCK_METHOD0(SuspendDraw, HRESULT());
};
#endif

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#pragma once
#if WINVER > _WIN32_WINNT_WINBLUE
class MockCompositionGraphicsDevice : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>,
ICompositionGraphicsDevice,
ICompositionGraphicsDeviceInterop>
{
public:
// ICompositionGraphicsDevice
MOCK_METHOD4(CreateDrawingSurface, HRESULT(Size sizePixels, DirectXPixelFormat pixelFormat, DirectXAlphaMode alphaMode, ICompositionDrawingSurface** result));
MOCK_METHOD2(add_RenderingDeviceReplaced, HRESULT(ITypedEventHandler<CompositionGraphicsDevice*, RenderingDeviceReplacedEventArgs*>* handler, EventRegistrationToken *token));
MOCK_METHOD1(remove_RenderingDeviceReplaced, HRESULT(EventRegistrationToken token));
// ICompositionGraphicsDeviceInterop
MOCK_METHOD1(GetRenderingDevice, HRESULT(IUnknown** ppBackingDevice));
MOCK_METHOD1(SetRenderingDevice, HRESULT(IUnknown* pBackingDevice));
};
#endif

Просмотреть файл

@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#pragma once
#if WINVER > _WIN32_WINNT_WINBLUE
using namespace ABI::Windows::UI::Composition;
class MockCompositor : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>,
ICompositor,
ICompositorInterop>
{
public:
// ICompositor
MOCK_METHOD1(CreateColorKeyFrameAnimation , HRESULT(IColorKeyFrameAnimation** result));
MOCK_METHOD1(CreateColorBrush , HRESULT(ICompositionColorBrush** result));
MOCK_METHOD2(CreateColorBrushWithColor , HRESULT(Color color, ICompositionColorBrush** result));
MOCK_METHOD1(CreateContainerVisual , HRESULT(IContainerVisual** result));
MOCK_METHOD3(CreateCubicBezierEasingFunction , HRESULT(Vector2 controlPoint1, Vector2 controlPoint2, ICubicBezierEasingFunction** result));
MOCK_METHOD2(CreateEffectFactory , HRESULT(IGraphicsEffect* graphicsEffect, ICompositionEffectFactory** result));
MOCK_METHOD3(CreateEffectFactoryWithProperties , HRESULT(IGraphicsEffect* graphicsEffect, IIterable<HSTRING>* animatableProperties, ICompositionEffectFactory* *result));
MOCK_METHOD1(CreateExpressionAnimation , HRESULT(IExpressionAnimation** result));
MOCK_METHOD2(CreateExpressionAnimationWithExpression , HRESULT(HSTRING expression, IExpressionAnimation** result));
MOCK_METHOD1(CreateInsetClip , HRESULT(IInsetClip** result));
MOCK_METHOD5(CreateInsetClipWithInsets , HRESULT(FLOAT leftInset, FLOAT topInset, FLOAT rightInset, FLOAT bottomInset, IInsetClip** result));
MOCK_METHOD1(CreateLinearEasingFunction , HRESULT(ILinearEasingFunction** result));
MOCK_METHOD1(CreatePropertySet , HRESULT(ICompositionPropertySet** result));
MOCK_METHOD1(CreateQuaternionKeyFrameAnimation , HRESULT(IQuaternionKeyFrameAnimation** result));
MOCK_METHOD1(CreateScalarKeyFrameAnimation , HRESULT(IScalarKeyFrameAnimation** result));
MOCK_METHOD2(CreateScopedBatch , HRESULT(CompositionBatchTypes batchType, ICompositionScopedBatch** result));
MOCK_METHOD1(CreateSpriteVisual , HRESULT(ISpriteVisual** result));
MOCK_METHOD1(CreateSurfaceBrush , HRESULT(ICompositionSurfaceBrush** result));
MOCK_METHOD2(CreateSurfaceBrushWithSurface , HRESULT(ICompositionSurface* surface, ICompositionSurfaceBrush** result));
MOCK_METHOD1(CreateTargetForCurrentView , HRESULT(ABI::Windows::UI::Composition::ICompositionTarget** result));
MOCK_METHOD1(CreateVector2KeyFrameAnimation , HRESULT(IVector2KeyFrameAnimation** result));
MOCK_METHOD1(CreateVector3KeyFrameAnimation , HRESULT(IVector3KeyFrameAnimation** result));
MOCK_METHOD1(CreateVector4KeyFrameAnimation , HRESULT(IVector4KeyFrameAnimation** result));
MOCK_METHOD2(GetCommitBatch , HRESULT(CompositionBatchTypes batchType, ICompositionCommitBatch** result));
// ICompositorInterop
MOCK_METHOD2(CreateCompositionSurfaceForHandle , HRESULT(HANDLE hDxgiSwapChain, ICompositionSurface** value));
MOCK_METHOD2(CreateCompositionSurfaceForSwapChain , HRESULT(IUnknown* pDxgiSwapChain, ICompositionSurface** value));
MOCK_METHOD2(CreateGraphicsDevice , HRESULT(IUnknown* pRenderingDevice, ICompositionGraphicsDevice** value));
};
#endif

Просмотреть файл

@ -25,9 +25,13 @@ using namespace ABI::Microsoft::Graphics::Canvas::Effects;
#include "../test.external/MockDxgiSurface.h"
#include "utils/Helpers.h"
#include "utils/ApiInformationTestAdapter.h"
#include "mocks/MockHelpers.h"
#include "mocks/MockAsyncAction.h"
#include "mocks/MockDxgiSwapChain.h"
#include "mocks/MockCompositor.h"
#include "mocks/MockCompositionGraphicsDevice.h"
#include "mocks/MockCompositionDrawingSurface.h"
#include "mocks/MockCanvasDevice.h"
#include "mocks/MockCanvasDrawingSession.h"
#include "mocks/MockCanvasImageSourceDrawingSessionFactory.h"

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
#pragma once
#if WINVER > _WIN32_WINNT_WINBLUE
#include <lib/utils/ApiInformationAdapter.h>
class ApiInformationTestAdapter : public ApiInformationAdapter
{
std::vector<std::pair<std::wstring, int>> m_contracts;
public:
static std::shared_ptr<ApiInformationTestAdapter> Create()
{
auto adapter = std::make_shared<ApiInformationTestAdapter>();
ApiInformationAdapter::SetInstance(adapter);
return adapter;
}
ApiInformationTestAdapter()
{
AddContract(UNIVERSAL_API_CONTRACT, 1);
}
void AddContract(wchar_t const* contractName, int majorVersion)
{
m_contracts.push_back({contractName, majorVersion});
}
virtual bool IsApiContractPresent(wchar_t const* contractName, int majorVersion)
{
std::pair<std::wstring, int> toFind(contractName, majorVersion);
return (std::find(m_contracts.begin(), m_contracts.end(), toFind) != m_contracts.end());
}
};
#endif

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
@ -23,6 +23,9 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockCanvasVirtualImageSource.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockCompositionDrawingSurface.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockCompositionGraphicsDevice.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockCompositor.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockCoreWindow.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockD2DEllipseGeometry.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockD2DRectangleGeometry.h" />
@ -41,6 +44,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)stubs\StubResourceCreatorWithDpi.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)stubs\StubStorageFile.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)stubs\StubStorageFileStatics.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)utils\ApiInformationTestAdapter.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)xaml\BaseControlTestAdapter.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)xaml\BasicControlFixture.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)xaml\CanvasAnimatedControlTestAdapter.h" />
@ -124,6 +128,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)xaml\StubDispatcher.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)composition\CanvasCompositionUnitTests.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)graphics\CanvasPrintDocumentUnitTests.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="xaml">
@ -16,6 +16,9 @@
<Filter Include="stubs">
<UniqueIdentifier>{c531b9c2-9295-431a-a302-c74e2f1730b4}</UniqueIdentifier>
</Filter>
<Filter Include="composition">
<UniqueIdentifier>{7b54d51e-b689-4225-87a4-c1f1995ccd9b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)pch.cpp" />
@ -151,6 +154,9 @@
<ClCompile Include="$(MSBuildThisFileDirectory)graphics\CanvasTextRenderingParametersUnitTests.cpp">
<Filter>graphics</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)composition\CanvasCompositionUnitTests.cpp">
<Filter>composition</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)pch.h" />
@ -457,6 +463,18 @@
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockPrintTaskOptions.h">
<Filter>mocks</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockCompositor.h">
<Filter>mocks</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockCompositionDrawingSurface.h">
<Filter>mocks</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)mocks\MockCompositionGraphicsDevice.h">
<Filter>mocks</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)utils\ApiInformationTestAdapter.h">
<Filter>utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="$(MSBuildThisFileDirectory)readme.txt" />