From 246cbfc566254f541b3cd04428679e07ab0f5859 Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Mon, 24 Nov 2025 12:50:03 +0100 Subject: [PATCH] Remove Direct2D1 (#20132) --- Avalonia.sln | 22 - CONTRIBUTING.md | 4 +- nukebuild/Build.cs | 2 - src/Avalonia.Base/Avalonia.Base.csproj | 3 - src/Avalonia.Base/Properties/AssemblyInfo.cs | 20 - .../Avalonia.Controls.csproj | 1 - src/Skia/Avalonia.Skia/Avalonia.Skia.csproj | 1 - .../Avalonia.Direct2D1.csproj | 22 - .../Avalonia.Direct2D1/Direct2D1Platform.cs | 306 -------- .../ExternalRenderTarget.cs | 49 -- .../FramebufferShimRenderTarget.cs | 75 -- .../Avalonia.Direct2D1/HwndRenderTarget.cs | 53 -- .../IExternalDirect2DRenderTargetSurface.cs | 10 - .../Avalonia.Direct2D1/ILayerFactory.cs | 9 - .../Media/AvaloniaTextRenderer.cs | 66 -- .../Avalonia.Direct2D1/Media/BrushImpl.cs | 17 - .../Avalonia.Direct2D1/Media/BrushWrapper.cs | 15 - .../Media/CombinedGeometryImpl.cs | 37 - .../Media/DWriteResourceFontFileEnumerator.cs | 67 -- .../Media/DWriteResourceFontFileStream.cs | 84 -- .../Media/DWriteResourceFontLoader.cs | 93 --- .../Media/Direct2D1FontCollectionCache.cs | 72 -- .../Media/DrawingContextImpl.cs | 736 ------------------ .../Media/EllipseGeometryImpl.cs | 24 - .../Media/FontManagerImpl.cs | 116 --- .../Media/GeometryGroupImpl.cs | 34 - .../Avalonia.Direct2D1/Media/GeometryImpl.cs | 130 ---- .../Avalonia.Direct2D1/Media/GlyphRunImpl.cs | 131 ---- .../Media/GlyphTypefaceImpl.cs | 216 ----- .../Media/ImageBrushImpl.cs | 124 --- .../Media/Imaging/BitmapImpl.cs | 36 - .../Media/Imaging/D2DBitmapImpl.cs | 59 -- .../Imaging/D2DRenderTargetBitmapImpl.cs | 77 -- .../Media/Imaging/WicBitmapImpl.cs | 278 ------- .../Imaging/WicRenderTargetBitmapImpl.cs | 55 -- .../Media/Imaging/WriteableWicBitmapImpl.cs | 34 - .../Media/LineGeometryImpl.cs | 24 - .../Media/LinearGradientBrushImpl.cs | 48 -- .../Media/RadialGradientBrushImpl.cs | 53 -- .../Media/RectangleGeometryImpl.cs | 23 - .../Media/SolidColorBrushImpl.cs | 37 - .../Media/StreamGeometryContextImpl.cs | 95 --- .../Media/StreamGeometryImpl.cs | 52 -- .../Media/TextShaperImpl.cs | 204 ----- .../Media/TransformedGeometryImpl.cs | 26 - .../Avalonia.Direct2D1/OptionalDispose.cs | 22 - .../Avalonia.Direct2D1/PrimitiveExtensions.cs | 226 ------ .../Avalonia.Direct2D1/RenderTarget.cs | 45 -- .../SwapChainRenderTarget.cs | 124 --- .../Avalonia.Direct2D1/Utils/DebugUtils.cs | 13 - .../Avalonia.Win32/Avalonia.Win32.csproj | 1 - .../Avalonia.Direct2D1.RenderTests.csproj | 28 - .../Avalonia.Direct2D1.UnitTests.csproj | 20 - .../Controls/Shapes/PathTests.cs | 69 -- .../Media/FontManagerImplTests.cs | 89 --- .../Media/GeometryTests.cs | 37 - .../Properties/AssemblyInfo.cs | 5 - .../RectComparer.cs | 21 - .../Controls/AdornerTests.cs | 6 +- .../Controls/BorderTests.cs | 4 - .../Controls/CustomRenderTests.cs | 4 - .../Controls/ImageBlendTests.cs | 4 - .../Controls/ImageCompositionTests.cs | 4 - .../Controls/ImageTests.cs | 4 - .../Controls/TextBlockTests.cs | 14 +- .../CrossTests/Brushes/CrossTileBrushTests.cs | 2 - .../Brushes/RadialGradientBrushTests.cs | 2 - .../CrossTests/CrossGeometryTests.cs | 2 - .../CrossTests/Media/DrawingContextTests.cs | 2 - .../CrossTests/Media/ImageScalingTests.cs | 2 - .../CrossUI/CrossUI.Avalonia.cs | 6 - .../GeometryClippingTests.cs | 4 - .../Avalonia.RenderTests/ManualRenderTimer.cs | 7 +- .../Avalonia.RenderTests/Media/BitmapTests.cs | 4 - .../Media/CombinedGeometryTests.cs | 4 - .../Media/ConicGradientBrushTests.cs | 4 - .../Media/GeometryDrawingTests.cs | 7 - .../Media/GeometryGroupTests.cs | 4 - .../Media/GlyphRunTests.cs | 4 - .../Media/ImageBrushTests.cs | 4 - .../Media/ImageDrawingTests.cs | 4 - .../Media/LinearGradientBrushTests.cs | 4 - .../Media/RadialGradientBrushTests.cs | 4 - .../RelativePointTestPrimitivesHelper.cs | 4 - .../Media/StreamGeometryTests.cs | 4 - .../Media/TextFormatting/TextLayoutTests.cs | 4 - .../Media/TileBrushTests.cs | 5 +- .../Media/VisualBrushTests.cs | 4 - .../Avalonia.RenderTests/OpacityMaskTests.cs | 4 - tests/Avalonia.RenderTests/SVGPathTests.cs | 6 - .../Shapes/EllipseTests.cs | 4 - .../Avalonia.RenderTests/Shapes/LineTests.cs | 4 - .../Avalonia.RenderTests/Shapes/PathTests.cs | 4 - .../Shapes/PolygonTests.cs | 4 - .../Shapes/PolylineTests.cs | 4 - .../Shapes/RectangleTests.cs | 4 - tests/Avalonia.RenderTests/TestBase.cs | 22 +- .../Avalonia.RenderTests/TestRenderHelper.cs | 12 - tests/Avalonia.RenderTests/TestRenderRoot.cs | 6 +- tests/Avalonia.RenderTests/TestSkip.cs | 4 - .../WpfCompareTestBase.cs | 9 - .../CrossTestBase.cs | 4 - .../Avalonia.UnitTests/InternalsVisibleTo.cs | 2 +- .../Transform_Should_Work_As_Expected.wpf.png | Bin 793 -> 790 bytes ...ld_Properly_CloseFigure_Flat_Bevel.wpf.png | Bin 6815 -> 7523 bytes ...ld_Properly_CloseFigure_Flat_Miter.wpf.png | Bin 7625 -> 8542 bytes ...ld_Properly_CloseFigure_Flat_Round.wpf.png | Bin 6910 -> 7630 bytes ...d_Properly_CloseFigure_Round_Bevel.wpf.png | Bin 6852 -> 7545 bytes ...d_Properly_CloseFigure_Round_Miter.wpf.png | Bin 7665 -> 8563 bytes ...d_Properly_CloseFigure_Round_Round.wpf.png | Bin 6947 -> 7651 bytes ...der_Geometry_With_Strokeless_Lines.wpf.png | Bin 3537 -> 3605 bytes ...ezierSegment_With_Strokeless_Lines.wpf.png | Bin 4265 -> 4049 bytes ...yLineSegment_With_Strokeless_Lines.wpf.png | Bin 362 -> 362 bytes .../Should_Render_Stream_Geometry.wpf.png | Bin 3500 -> 3564 bytes .../Transform_Should_Work_As_Expected.wpf.png | Bin 9566 -> 8639 bytes .../Should_Render_Aligned_TileBrush.wpf.png | Bin 393 -> 392 bytes .../Should_Render_Scaled_TileBrush.wpf.png | Bin 962 -> 722 bytes ...ender_TileBrush_With_TileMode_None.wpf.png | Bin 398 -> 396 bytes .../Should_Render_With_Transform.wpf.png | Bin 424 -> 426 bytes ...rd_Pattern_Is_Rendered_Identically.wpf.png | Bin 491 -> 430 bytes 120 files changed, 11 insertions(+), 4553 deletions(-) delete mode 100644 src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj delete mode 100644 src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/HwndRenderTarget.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/ILayerFactory.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/BrushWrapper.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/CombinedGeometryImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontLoader.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/Direct2D1FontCollectionCache.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/FontManagerImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/GeometryGroupImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/OptionalDispose.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/RenderTarget.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Utils/DebugUtils.cs delete mode 100644 tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj delete mode 100644 tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj delete mode 100644 tests/Avalonia.Direct2D1.UnitTests/Controls/Shapes/PathTests.cs delete mode 100644 tests/Avalonia.Direct2D1.UnitTests/Media/FontManagerImplTests.cs delete mode 100644 tests/Avalonia.Direct2D1.UnitTests/Media/GeometryTests.cs delete mode 100644 tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Avalonia.Direct2D1.UnitTests/RectComparer.cs delete mode 100644 tests/Avalonia.RenderTests/WpfCompareTestBase.cs diff --git a/Avalonia.sln b/Avalonia.sln index fff9f40ae..b7625ed1d 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32", "src\Windows\Avalonia.Win32\Avalonia.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1", "src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Simple", "src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}" @@ -23,10 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.UnitTests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base.UnitTests", "tests\Avalonia.Base.UnitTests\Avalonia.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.RenderTests", "tests\Avalonia.Direct2D1.RenderTests\Avalonia.Direct2D1.RenderTests.csproj", "{DABFD304-D6A4-4752-8123-C2CCF7AC7831}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.UnitTests", "tests\Avalonia.Direct2D1.UnitTests\Avalonia.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.UnitTests", "tests\Avalonia.Markup.Xaml.UnitTests\Avalonia.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}" @@ -108,7 +102,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\Rx.props = build\Rx.props build\SampleApp.props = build\SampleApp.props build\SharedVersion.props = build\SharedVersion.props - build\SharpDX.props = build\SharpDX.props build\SkiaSharp.props = build\SkiaSharp.props build\SourceGenerators.props = build\SourceGenerators.props build\SourceLink.props = build\SourceLink.props @@ -307,10 +300,6 @@ Global {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.Build.0 = Release|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.Build.0 = Debug|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -331,14 +320,6 @@ Global {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.Build.0 = Release|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.Build.0 = Debug|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -685,11 +666,8 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888} - {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888} {5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {2905FF23-53FB-45E6-AA49-6AF47A172056} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C} {6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d3ed95005..8351fc2ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ A bug fix will ideally be accompanied by tests. There are a few types of tests: - Unit tests are for issues that aren't related to platform features. These tests are located in the `tests` directly, categorised by the assembly which they're testing. - Integration tests are for issues that are related to platform features (for example fixing a bug with Window resizing). These tests are located in the `tests/Avalonia.IntegrationTests.Appium` directory. Integration tests should be run on Windows and macOS. See the readme in that directory for more information -- Render tests are for issues with rendering. These tests are located in `tests/Avalonia.RenderTests` with separate project files for Skia and Direct2D. The Direct2D backend is currently mostly unmaintained so render tests that just run on Skia are acceptable +- Render tests are for issues with rendering. These tests are located in `tests/Avalonia.RenderTests` and are imported in the `Avalonia.Skia.RenderTests` project. It's not always feasible to accompany a bug fix with a test, but doing so will speed up the review process. @@ -88,4 +88,4 @@ Render tests should describe what the produced image is: ## Code of Conduct This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. -For more information see the [Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct) \ No newline at end of file +For more information see the [Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct) diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index a272c05fc..d3c2cb1d0 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -308,8 +308,6 @@ partial class Build : NukeBuild .Executes(() => { RunCoreTest("Avalonia.Skia.RenderTests"); - if (Parameters.IsRunningOnWindows) - RunCoreTest("Avalonia.Direct2D1.RenderTests"); }); Target RunToolsTests => _ => _ diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 7efb8409a..ea1dfd766 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -29,7 +29,6 @@ - @@ -45,12 +44,10 @@ - - diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs index f094fed1d..5e1193f04 100644 --- a/src/Avalonia.Base/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs @@ -1,6 +1,3 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using Avalonia.Data; using Avalonia.Metadata; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")] @@ -18,20 +15,3 @@ using Avalonia.Metadata; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Imaging")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Transformation")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")] - -[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Controls, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Controls.ColorPicker, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Browser.Blazor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Browser, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] - diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index a650c8a0e..6e3f40892 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -14,7 +14,6 @@ - diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj index 3433706fd..9c4c4f62f 100644 --- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj +++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj @@ -22,7 +22,6 @@ - diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj deleted file mode 100644 index b09b73a73..000000000 --- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks) - true - true - - - - - - - - - - - - - - - - - diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs deleted file mode 100644 index e3aa990f1..000000000 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ /dev/null @@ -1,306 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using Avalonia.Controls.Platform.Surfaces; -using Avalonia.Direct2D1.Media; -using Avalonia.Direct2D1.Media.Imaging; -using Avalonia.Media; -using Avalonia.Media.Imaging; -using Avalonia.Media.TextFormatting; -using Avalonia.Platform; -using GlyphRun = Avalonia.Media.GlyphRun; -using SharpDX.Mathematics.Interop; - -namespace Avalonia -{ - public static class Direct2DApplicationExtensions - { - public static AppBuilder UseDirect2D1(this AppBuilder builder) - { - builder.UseRenderingSubsystem(Direct2D1.Direct2D1Platform.Initialize, "Direct2D1"); - return builder; - } - } -} - -namespace Avalonia.Direct2D1 -{ - internal class Direct2D1Platform : IPlatformRenderInterface - { - private static readonly Direct2D1Platform s_instance = new Direct2D1Platform(); - - public static SharpDX.Direct3D11.Device Direct3D11Device { get; private set; } - - public static SharpDX.Direct2D1.Factory1 Direct2D1Factory { get; private set; } - - public static SharpDX.Direct2D1.Device Direct2D1Device { get; private set; } - - public static SharpDX.DirectWrite.Factory1 DirectWriteFactory { get; private set; } - - public static SharpDX.WIC.ImagingFactory ImagingFactory { get; private set; } - - public static SharpDX.DXGI.Device1 DxgiDevice { get; private set; } - - private static readonly object s_initLock = new object(); - private static bool s_initialized = false; - - internal static void InitializeDirect2D() - { - lock (s_initLock) - { - if (s_initialized) - { - return; - } -#if DEBUG - if (Debugger.IsAttached) - { - try - { - Direct2D1Factory = new SharpDX.Direct2D1.Factory1( - SharpDX.Direct2D1.FactoryType.MultiThreaded, - SharpDX.Direct2D1.DebugLevel.Error); - } - catch - { - // ignore, retry below without the debug layer - } - } -#endif - if (Direct2D1Factory == null) - { - Direct2D1Factory = new SharpDX.Direct2D1.Factory1( - SharpDX.Direct2D1.FactoryType.MultiThreaded, - SharpDX.Direct2D1.DebugLevel.None); - } - - using (var factory = new SharpDX.DirectWrite.Factory()) - { - DirectWriteFactory = factory.QueryInterface(); - } - - ImagingFactory = new SharpDX.WIC.ImagingFactory(); - - var featureLevels = new[] - { - SharpDX.Direct3D.FeatureLevel.Level_11_1, - SharpDX.Direct3D.FeatureLevel.Level_11_0, - SharpDX.Direct3D.FeatureLevel.Level_10_1, - SharpDX.Direct3D.FeatureLevel.Level_10_0, - SharpDX.Direct3D.FeatureLevel.Level_9_3, - SharpDX.Direct3D.FeatureLevel.Level_9_2, - SharpDX.Direct3D.FeatureLevel.Level_9_1, - }; - - Direct3D11Device = new SharpDX.Direct3D11.Device( - SharpDX.Direct3D.DriverType.Hardware, - SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport | SharpDX.Direct3D11.DeviceCreationFlags.VideoSupport, - featureLevels); - - DxgiDevice = Direct3D11Device.QueryInterface(); - - Direct2D1Device = new SharpDX.Direct2D1.Device(Direct2D1Factory, DxgiDevice); - - s_initialized = true; - } - } - - public static void Initialize() - { - InitializeDirect2D(); - AvaloniaLocator.CurrentMutable - .Bind().ToConstant(s_instance) - .Bind().ToConstant(new FontManagerImpl()) - .Bind().ToConstant(new TextShaperImpl()); - SharpDX.Configuration.EnableReleaseOnFinalizer = true; - } - - private IRenderTarget CreateRenderTarget(IEnumerable surfaces) - { - foreach (var s in surfaces) - { - if (s is IPlatformHandle nativeWindow) - { - if (nativeWindow.HandleDescriptor != "HWND") - { - throw new NotSupportedException("Don't know how to create a Direct2D1 renderer from " + - nativeWindow.HandleDescriptor); - } - - return new HwndRenderTarget(nativeWindow); - } - if (s is IExternalDirect2DRenderTargetSurface external) - { - return new ExternalRenderTarget(external); - } - - if (s is IFramebufferPlatformSurface fb) - { - return new FramebufferShimRenderTarget(fb); - } - } - throw new NotSupportedException("Don't know how to create a Direct2D1 renderer from any of provided surfaces"); - } - - public IRenderTargetBitmapImpl CreateRenderTargetBitmap(PixelSize size, Vector dpi) - { - return new WicRenderTargetBitmapImpl(size, dpi); - } - - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat) - { - return new WriteableWicBitmapImpl(size, dpi, format, alphaFormat); - } - - public IGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect); - public IGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2); - public IGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect); - public IStreamGeometryImpl CreateStreamGeometry() => new StreamGeometryImpl(); - public IGeometryImpl CreateGeometryGroup(FillRule fillRule, IReadOnlyList children) => new GeometryGroupImpl(fillRule, children); - public IGeometryImpl CreateCombinedGeometry(GeometryCombineMode combineMode, IGeometryImpl g1, IGeometryImpl g2) => new CombinedGeometryImpl(combineMode, g1, g2); - public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, IReadOnlyList glyphInfos, Point baselineOrigin) - { - return new GlyphRunImpl(glyphTypeface, fontRenderingEmSize, glyphInfos, baselineOrigin); - } - - class D2DApi : IPlatformRenderInterfaceContext - { - private readonly Direct2D1Platform _platform; - - public D2DApi(Direct2D1Platform platform) - { - _platform = platform; - } - public object TryGetFeature(Type featureType) => null; - - public void Dispose() - { - } - - public IRenderTarget CreateRenderTarget(IEnumerable surfaces) => _platform.CreateRenderTarget(surfaces); - - public IDrawingContextLayerImpl CreateOffscreenRenderTarget(PixelSize pixelSize, double scaling) => - new WicRenderTargetBitmapImpl(pixelSize, new Vector(96 * scaling, 96 * scaling)); - - public bool IsLost => false; - public IReadOnlyDictionary PublicFeatures { get; } = new Dictionary(); - } - - public IPlatformRenderInterfaceContext CreateBackendContext(IPlatformGraphicsContext graphicsContext) => - new D2DApi(this); - - public IGeometryImpl BuildGlyphRunGeometry(GlyphRun glyphRun) - { - if (glyphRun.GlyphTypeface is not GlyphTypefaceImpl glyphTypeface) - { - throw new InvalidOperationException("PlatformImpl can't be null."); - } - - var pathGeometry = new SharpDX.Direct2D1.PathGeometry(Direct2D1Factory); - - using (var sink = pathGeometry.Open()) - { - var glyphInfos = glyphRun.GlyphInfos; - var glyphs = new short[glyphInfos.Count]; - - for (int i = 0; i < glyphInfos.Count; i++) - { - glyphs[i] = (short)glyphInfos[i].GlyphIndex; - } - - glyphTypeface.FontFace.GetGlyphRunOutline((float)glyphRun.FontRenderingEmSize, glyphs, null, null, false, !glyphRun.IsLeftToRight, sink); - - sink.Close(); - } - - var (baselineOriginX, baselineOriginY) = glyphRun.BaselineOrigin; - - var transformedGeometry = new SharpDX.Direct2D1.TransformedGeometry( - Direct2D1Factory, - pathGeometry, - new RawMatrix3x2(1.0f, 0.0f, 0.0f, 1.0f, (float)baselineOriginX, (float)baselineOriginY)); - - return new TransformedGeometryWrapper(transformedGeometry); - } - - private class TransformedGeometryWrapper : GeometryImpl - { - public TransformedGeometryWrapper(SharpDX.Direct2D1.TransformedGeometry geometry) : base(geometry) - { - - } - } - - /// - public IBitmapImpl LoadBitmap(string fileName) - { - return new WicBitmapImpl(fileName); - } - - /// - public IBitmapImpl LoadBitmap(Stream stream) - { - return new WicBitmapImpl(stream); - } - - public IWriteableBitmapImpl LoadWriteableBitmapToWidth(Stream stream, int width, - BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality) - { - return new WriteableWicBitmapImpl(stream, width, true, interpolationMode); - } - - public IWriteableBitmapImpl LoadWriteableBitmapToHeight(Stream stream, int height, - BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality) - { - return new WriteableWicBitmapImpl(stream, height, false, interpolationMode); - } - - public IWriteableBitmapImpl LoadWriteableBitmap(string fileName) - { - return new WriteableWicBitmapImpl(fileName); - } - - public IWriteableBitmapImpl LoadWriteableBitmap(Stream stream) - { - return new WriteableWicBitmapImpl(stream); - } - - /// - public IBitmapImpl LoadBitmapToWidth(Stream stream, int width, BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality) - { - return new WicBitmapImpl(stream, width, true, interpolationMode); - } - - /// - public IBitmapImpl LoadBitmapToHeight(Stream stream, int height, BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality) - { - return new WicBitmapImpl(stream, height, false, interpolationMode); - } - - /// - public IBitmapImpl ResizeBitmap(IBitmapImpl bitmapImpl, PixelSize destinationSize, BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality) - { - // https://github.com/sharpdx/SharpDX/issues/959 blocks implementation. - throw new NotImplementedException(); - } - - /// - public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) - { - return new WicBitmapImpl(format, alphaFormat, data, size, dpi, stride); - } - - public bool SupportsIndividualRoundRects => false; - - public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul; - - public PixelFormat DefaultPixelFormat => PixelFormat.Bgra8888; - public bool IsSupportedBitmapPixelFormat(PixelFormat format) => - format == PixelFormats.Bgra8888 - || format == PixelFormats.Rgba8888; - - public bool SupportsRegions => false; - public IPlatformRenderInterfaceRegion CreateRegion() => throw new NotSupportedException(); - } -} diff --git a/src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs deleted file mode 100644 index 8aa6e5c0e..000000000 --- a/src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Avalonia.Direct2D1.Media; -using Avalonia.Direct2D1.Media.Imaging; -using Avalonia.Platform; -using Avalonia.Rendering; -using SharpDX; - -namespace Avalonia.Direct2D1 -{ - class ExternalRenderTarget : IRenderTarget, ILayerFactory - { - private readonly IExternalDirect2DRenderTargetSurface _externalRenderTargetProvider; - - public ExternalRenderTarget( - IExternalDirect2DRenderTargetSurface externalRenderTargetProvider) - { - _externalRenderTargetProvider = externalRenderTargetProvider; - } - - public void Dispose() - { - _externalRenderTargetProvider.DestroyRenderTarget(); - } - - public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing) - { - var target = _externalRenderTargetProvider.GetOrCreateRenderTarget(); - _externalRenderTargetProvider.BeforeDrawing(); - return new DrawingContextImpl( null, target, useScaledDrawing, null, () => - { - try - { - _externalRenderTargetProvider.AfterDrawing(); - } - catch (SharpDXException ex) when ((uint) ex.HResult == 0x8899000C) // D2DERR_RECREATE_TARGET - { - _externalRenderTargetProvider.DestroyRenderTarget(); - } - }); - } - - public bool IsCorrupted => false; - - public IDrawingContextLayerImpl CreateLayer(Size size) - { - var renderTarget = _externalRenderTargetProvider.GetOrCreateRenderTarget(); - return D2DRenderTargetBitmapImpl.CreateCompatible(renderTarget, size); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs deleted file mode 100644 index 23faf79e9..000000000 --- a/src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs +++ /dev/null @@ -1,75 +0,0 @@ -#nullable enable - -using System; -using Avalonia.Controls.Platform.Surfaces; -using Avalonia.Direct2D1.Media; -using Avalonia.Platform; -using Avalonia.Win32.Interop; -using SharpDX.WIC; -using PixelFormat = Avalonia.Platform.PixelFormat; - -namespace Avalonia.Direct2D1 -{ - class FramebufferShimRenderTarget : IRenderTarget - { - private IFramebufferRenderTarget? _target; - - public FramebufferShimRenderTarget(IFramebufferPlatformSurface surface) - { - _target = surface.CreateFramebufferRenderTarget(); - } - - public void Dispose() - { - _target?.Dispose(); - _target = null; - } - - public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing) - { - if (_target == null) - throw new ObjectDisposedException(nameof(FramebufferShimRenderTarget)); - var locked = _target.Lock(); - if (locked.Format == PixelFormat.Rgb565) - { - locked.Dispose(); - throw new ArgumentException("Unsupported pixel format: " + locked.Format); - } - - return new FramebufferShim(locked) - .CreateDrawingContext(useScaledDrawing); - } - - public bool IsCorrupted => false; - - class FramebufferShim : WicRenderTargetBitmapImpl - { - private readonly ILockedFramebuffer _target; - - public FramebufferShim(ILockedFramebuffer target) : - base(target.Size, target.Dpi, target.Format) - { - _target = target; - } - - public override IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing) - { - return base.CreateDrawingContext(useScaledDrawing, () => - { - using (var l = WicImpl.Lock(BitmapLockFlags.Read)) - { - for (var y = 0; y < _target.Size.Height; y++) - { - UnmanagedMethods.CopyMemory( - (_target.Address + _target.RowBytes * y), - (l.Data.DataPointer + l.Stride * y), - (UIntPtr)Math.Min(l.Stride, _target.RowBytes)); - } - } - Dispose(); - _target.Dispose(); - }); - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/HwndRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/HwndRenderTarget.cs deleted file mode 100644 index 0597e88ed..000000000 --- a/src/Windows/Avalonia.Direct2D1/HwndRenderTarget.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Avalonia.Platform; -using Avalonia.Win32; -using Avalonia.Win32.Interop; -using SharpDX; -using SharpDX.DXGI; - -namespace Avalonia.Direct2D1 -{ - class HwndRenderTarget : SwapChainRenderTarget - { - private readonly IPlatformHandle _window; - - public HwndRenderTarget(IPlatformHandle window) - { - _window = window; - } - - protected override SwapChain1 CreateSwapChain(Factory2 dxgiFactory, SwapChainDescription1 swapChainDesc) - { - return new SwapChain1(dxgiFactory, Direct2D1Platform.DxgiDevice, _window.Handle, ref swapChainDesc); - } - - protected override Size2F GetWindowDpi() - { - if (UnmanagedMethods.ShCoreAvailable && Win32Platform.WindowsVersion > PlatformConstants.Windows8) - { - uint dpix, dpiy; - - var monitor = UnmanagedMethods.MonitorFromWindow( - _window.Handle, - UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST); - - if (UnmanagedMethods.GetDpiForMonitor( - monitor, - UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, - out dpix, - out dpiy) == 0) - { - return new Size2F(dpix, dpiy); - } - } - - return new Size2F(96, 96); - } - - protected override Size2 GetWindowSize() - { - UnmanagedMethods.RECT rc; - UnmanagedMethods.GetClientRect(_window.Handle, out rc); - return new Size2(rc.right - rc.left, rc.bottom - rc.top); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs b/src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs deleted file mode 100644 index 9c7d74ff6..000000000 --- a/src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Avalonia.Direct2D1 -{ - public interface IExternalDirect2DRenderTargetSurface - { - SharpDX.Direct2D1.RenderTarget GetOrCreateRenderTarget(); - void DestroyRenderTarget(); - void BeforeDrawing(); - void AfterDrawing(); - } -} diff --git a/src/Windows/Avalonia.Direct2D1/ILayerFactory.cs b/src/Windows/Avalonia.Direct2D1/ILayerFactory.cs deleted file mode 100644 index 504f4981f..000000000 --- a/src/Windows/Avalonia.Direct2D1/ILayerFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Avalonia.Platform; - -namespace Avalonia.Direct2D1 -{ - internal interface ILayerFactory - { - IDrawingContextLayerImpl CreateLayer(Size size); - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs b/src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs deleted file mode 100644 index cfd69571e..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs +++ /dev/null @@ -1,66 +0,0 @@ -using SharpDX; -using SharpDX.Direct2D1; -using SharpDX.DirectWrite; -using SharpDX.Mathematics.Interop; - -namespace Avalonia.Direct2D1.Media -{ - internal class AvaloniaTextRenderer : TextRendererBase - { - private readonly DrawingContextImpl _context; - - private readonly SharpDX.Direct2D1.RenderTarget _renderTarget; - - private readonly Brush _foreground; - - public AvaloniaTextRenderer( - DrawingContextImpl context, - SharpDX.Direct2D1.RenderTarget target, - Brush foreground) - { - _context = context; - _renderTarget = target; - _foreground = foreground; - } - - public override Result DrawGlyphRun( - object clientDrawingContext, - float baselineOriginX, - float baselineOriginY, - MeasuringMode measuringMode, - GlyphRun glyphRun, - GlyphRunDescription glyphRunDescription, - ComObject clientDrawingEffect) - { - var wrapper = clientDrawingEffect as BrushWrapper; - - // TODO: Work out how to get the size below rather than passing new Size(). - var brush = (wrapper == null) ? - _foreground : - _context.CreateBrush(wrapper.Brush, default).PlatformBrush; - - _renderTarget.DrawGlyphRun( - new RawVector2 { X = baselineOriginX, Y = baselineOriginY }, - glyphRun, - brush, - measuringMode); - - if (wrapper != null) - { - brush.Dispose(); - } - - return Result.Ok; - } - - public override RawMatrix3x2 GetCurrentTransform(object clientDrawingContext) - { - return _renderTarget.Transform; - } - - public override float GetPixelsPerDip(object clientDrawingContext) - { - return _renderTarget.DotsPerInch.Width / 96; - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs deleted file mode 100644 index 9fac86e0d..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Avalonia.Direct2D1.Media -{ - internal abstract class BrushImpl : IDisposable - { - public SharpDX.Direct2D1.Brush PlatformBrush { get; set; } - - public virtual void Dispose() - { - if (PlatformBrush != null) - { - PlatformBrush.Dispose(); - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/BrushWrapper.cs b/src/Windows/Avalonia.Direct2D1/Media/BrushWrapper.cs deleted file mode 100644 index e9acf996c..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/BrushWrapper.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Avalonia.Media; -using SharpDX; - -namespace Avalonia.Direct2D1.Media -{ - internal class BrushWrapper : ComObject - { - public BrushWrapper(IBrush brush) - { - Brush = brush; - } - - public IBrush Brush { get; private set; } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/CombinedGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/CombinedGeometryImpl.cs deleted file mode 100644 index b1ce16070..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/CombinedGeometryImpl.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Avalonia.Platform; -using SharpDX.Direct2D1; -using AM = Avalonia.Media; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// A Direct2D implementation of a . - /// - internal class CombinedGeometryImpl : GeometryImpl - { - /// - /// Initializes a new instance of the class. - /// - public CombinedGeometryImpl( - AM.GeometryCombineMode combineMode, - IGeometryImpl geometry1, - IGeometryImpl geometry2) - : base(CreateGeometry(combineMode, geometry1, geometry2)) - { - } - - private static Geometry CreateGeometry( - AM.GeometryCombineMode combineMode, - IGeometryImpl geometry1, - IGeometryImpl geometry2) - { - var g1 = ((GeometryImpl)geometry1).Geometry; - var g2 = ((GeometryImpl)geometry2).Geometry; - var dest = new PathGeometry(Direct2D1Platform.Direct2D1Factory); - using var sink = dest.Open(); - g1.Combine(g2, (CombineMode)combineMode, sink); - sink.Close(); - return dest; - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs deleted file mode 100644 index 42cc969b6..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs +++ /dev/null @@ -1,67 +0,0 @@ -using SharpDX; -using SharpDX.DirectWrite; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// Resource FontFileEnumerator. - /// - internal class DWriteResourceFontFileEnumerator : CallbackBase, FontFileEnumerator - { - private readonly Factory _factory; - private readonly FontFileLoader _loader; - private readonly DataStream _keyStream; - private FontFile _currentFontFile; - - /// - /// Initializes a new instance of the class. - /// - /// The factory. - /// The loader. - /// The key. - public DWriteResourceFontFileEnumerator(Factory factory, FontFileLoader loader, DataPointer key) - { - _factory = factory; - _loader = loader; - _keyStream = new DataStream(key.Pointer, key.Size, true, false); - } - - /// - /// Advances to the next font file in the collection. When it is first created, the enumerator is positioned before the first element of the collection and the first call to MoveNext advances to the first file. - /// - /// - /// the value TRUE if the enumerator advances to a file; otherwise, FALSE if the enumerator advances past the last file in the collection. - /// - /// HRESULT IDWriteFontFileEnumerator::MoveNext([Out] BOOL* hasCurrentFile) - bool FontFileEnumerator.MoveNext() - { - bool moveNext = _keyStream.RemainingLength != 0; - - if (!moveNext) return false; - - _currentFontFile?.Dispose(); - - _currentFontFile = new FontFile(_factory, _keyStream.PositionPointer, 4, _loader); - - _keyStream.Position += 4; - - return true; - } - - /// - /// Gets a reference to the current font file. - /// - /// - /// a reference to the newly created object. - /// HRESULT IDWriteFontFileEnumerator::GetCurrentFontFile([Out] IDWriteFontFile** fontFile) - FontFile FontFileEnumerator.CurrentFontFile - { - get - { - ((IUnknown)_currentFontFile).AddReference(); - - return _currentFontFile; - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs deleted file mode 100644 index bd2e9ab8c..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using SharpDX; -using SharpDX.DirectWrite; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// This FontFileStream implementation is reading data from a . - /// - internal class DWriteResourceFontFileStream : CallbackBase, FontFileStream - { - private readonly DataStream _stream; - - /// - /// Initializes a new instance of the class. - /// - /// The stream. - public DWriteResourceFontFileStream(DataStream stream) - { - _stream = stream; - } - - /// - /// Reads a fragment from a font file. - /// - /// When this method returns, contains an address of a reference to the start of the font file fragment. This parameter is passed uninitialized. - /// The offset of the fragment, in bytes, from the beginning of the font file. - /// The size of the file fragment, in bytes. - /// When this method returns, contains the address of - /// - /// Note that ReadFileFragment implementations must check whether the requested font file fragment is within the file bounds. Otherwise, an error should be returned from ReadFileFragment. {{DirectWrite}} may invoke methods on the same object from multiple threads simultaneously. Therefore, ReadFileFragment implementations that rely on internal mutable state must serialize access to such state across multiple threads. For example, an implementation that uses separate Seek and Read operations to read a file fragment must place the code block containing Seek and Read calls under a lock or a critical section. - /// - /// HRESULT IDWriteFontFileStream::ReadFileFragment([Out, Buffer] const void** fragmentStart,[None] __int64 fileOffset,[None] __int64 fragmentSize,[Out] void** fragmentContext) - void FontFileStream.ReadFileFragment(out IntPtr fragmentStart, long fileOffset, long fragmentSize, out IntPtr fragmentContext) - { - lock (this) - { - fragmentContext = IntPtr.Zero; - - _stream.Position = fileOffset; - - fragmentStart = _stream.PositionPointer; - } - } - - /// - /// Releases a fragment from a file. - /// - /// A reference to the client-defined context of a font fragment returned from {{ReadFileFragment}}. - /// void IDWriteFontFileStream::ReleaseFileFragment([None] void* fragmentContext) - void FontFileStream.ReleaseFileFragment(IntPtr fragmentContext) - { - // Nothing to release. No context are used - } - - /// - /// Obtains the total size of a file. - /// - /// the total size of the file. - /// - /// Implementing GetFileSize() for asynchronously loaded font files may require downloading the complete file contents. Therefore, this method should be used only for operations that either require a complete font file to be loaded (for example, copying a font file) or that need to make decisions based on the value of the file size (for example, validation against a persisted file size). - /// - /// HRESULT IDWriteFontFileStream::GetFileSize([Out] __int64* fileSize) - long FontFileStream.GetFileSize() - { - return _stream.Length; - } - - /// - /// Obtains the last modified time of the file. - /// - /// - /// the last modified time of the file in the format that represents the number of 100-nanosecond intervals since January 1, 1601 (UTC). - /// - /// - /// The "last modified time" is used by DirectWrite font selection algorithms to determine whether one font resource is more up to date than another one. - /// - /// HRESULT IDWriteFontFileStream::GetLastWriteTime([Out] __int64* lastWriteTime) - long FontFileStream.GetLastWriteTime() - { - return 0; - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontLoader.cs b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontLoader.cs deleted file mode 100644 index b60962a09..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontLoader.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections.Generic; -using SharpDX; -using SharpDX.DirectWrite; - -namespace Avalonia.Direct2D1.Media -{ - using System.IO; - - internal class DWriteResourceFontLoader : CallbackBase, FontCollectionLoader, FontFileLoader - { - private readonly List _fontStreams = new List(); - private readonly List _enumerators = new List(); - private readonly DataStream _keyStream; - - /// - /// Initializes a new instance of the class. - /// - /// The factory. - /// - public DWriteResourceFontLoader(Factory factory, Stream[] fontAssets) - { - var factory1 = factory; - - foreach (var asset in fontAssets) - { - var dataStream = new DataStream((int)asset.Length, true, true); - - asset.CopyTo(dataStream); - - dataStream.Position = 0; - - _fontStreams.Add(new DWriteResourceFontFileStream(dataStream)); - } - - // Build a Key storage that stores the index of the font - _keyStream = new DataStream(sizeof(int) * _fontStreams.Count, true, true); - - for (int i = 0; i < _fontStreams.Count; i++) - { - _keyStream.Write(i); - } - - _keyStream.Position = 0; - - // Register the - factory1.RegisterFontFileLoader(this); - factory1.RegisterFontCollectionLoader(this); - } - - - /// - /// Gets the key used to identify the FontCollection as well as storing index for fonts. - /// - /// The key. - public DataStream Key => _keyStream; - - /// - /// Creates a font file enumerator object that encapsulates a collection of font files. The font system calls back to this interface to create a font collection. - /// - /// Pointer to the object that was used to create the current font collection. - /// A font collection key that uniquely identifies the collection of font files within the scope of the font collection loader being used. The buffer allocated for this key must be at least the size, in bytes, specified by collectionKeySize. - /// - /// a reference to the newly created font file enumerator. - /// - /// HRESULT IDWriteFontCollectionLoader::CreateEnumeratorFromKey([None] IDWriteFactory* factory,[In, Buffer] const void* collectionKey,[None] int collectionKeySize,[Out] IDWriteFontFileEnumerator** fontFileEnumerator) - FontFileEnumerator FontCollectionLoader.CreateEnumeratorFromKey(Factory factory, DataPointer collectionKey) - { - var enumerator = new DWriteResourceFontFileEnumerator(factory, this, collectionKey); - - _enumerators.Add(enumerator); - - return enumerator; - } - - /// - /// Creates a font file stream object that encapsulates an open file resource. - /// - /// A reference to a font file reference key that uniquely identifies the font file resource within the scope of the font loader being used. The buffer allocated for this key must at least be the size, in bytes, specified by fontFileReferenceKeySize. - /// - /// a reference to the newly created object. - /// - /// - /// The resource is closed when the last reference to fontFileStream is released. - /// - /// HRESULT IDWriteFontFileLoader::CreateStreamFromKey([In, Buffer] const void* fontFileReferenceKey,[None] int fontFileReferenceKeySize,[Out] IDWriteFontFileStream** fontFileStream) - FontFileStream FontFileLoader.CreateStreamFromKey(DataPointer fontFileReferenceKey) - { - var index = SharpDX.Utilities.Read(fontFileReferenceKey.Pointer); - - return _fontStreams[index]; - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/Direct2D1FontCollectionCache.cs b/src/Windows/Avalonia.Direct2D1/Media/Direct2D1FontCollectionCache.cs deleted file mode 100644 index ad2ede3a9..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/Direct2D1FontCollectionCache.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Collections.Concurrent; -using Avalonia.Media; -using Avalonia.Media.Fonts; -using SharpDX.DirectWrite; -using FontFamily = Avalonia.Media.FontFamily; -using FontStyle = SharpDX.DirectWrite.FontStyle; -using FontWeight = SharpDX.DirectWrite.FontWeight; -using FontStretch = SharpDX.DirectWrite.FontStretch; -using Avalonia.Platform; -using System.Linq; -using System; - -namespace Avalonia.Direct2D1.Media -{ - internal static class Direct2D1FontCollectionCache - { - private static readonly ConcurrentDictionary s_cachedCollections; - internal static readonly FontCollection InstalledFontCollection; - - static Direct2D1FontCollectionCache() - { - s_cachedCollections = new ConcurrentDictionary(); - - InstalledFontCollection = Direct2D1Platform.DirectWriteFactory.GetSystemFontCollection(false); - } - - public static Font GetFont(Typeface typeface) - { - var fontFamily = typeface.FontFamily; - var fontCollection = GetOrAddFontCollection(fontFamily); - int index; - - foreach (var name in fontFamily.FamilyNames) - { - if (fontCollection.FindFamilyName(name, out index)) - { - return fontCollection.GetFontFamily(index).GetFirstMatchingFont( - (FontWeight)typeface.Weight, - (FontStretch)typeface.Stretch, - (FontStyle)typeface.Style); - } - } - - InstalledFontCollection.FindFamilyName("Segoe UI", out index); - - return InstalledFontCollection.GetFontFamily(index).GetFirstMatchingFont( - (FontWeight)typeface.Weight, - (FontStretch)typeface.Stretch, - (FontStyle)typeface.Style); - } - - private static FontCollection GetOrAddFontCollection(FontFamily fontFamily) - { - return fontFamily.Key == null ? InstalledFontCollection : s_cachedCollections.GetOrAdd(fontFamily.Key, CreateFontCollection); - } - - private static FontCollection CreateFontCollection(FontFamilyKey key) - { - var source = key.BaseUri != null ? new Uri(key.BaseUri, key.Source) : key.Source; - - var assets = FontFamilyLoader.LoadFontAssets(source); - - var assetLoader = AvaloniaLocator.Current.GetRequiredService(); - - var fontAssets = assets.Select(x => assetLoader.Open(x)).ToArray(); - - var fontLoader = new DWriteResourceFontLoader(Direct2D1Platform.DirectWriteFactory, fontAssets); - - return new FontCollection(Direct2D1Platform.DirectWriteFactory, fontLoader, fontLoader.Key); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs deleted file mode 100644 index c40c5e987..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ /dev/null @@ -1,736 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Numerics; -using Avalonia.Media; -using Avalonia.Platform; -using Avalonia.Utilities; -using Avalonia.Media.Imaging; -using SharpDX; -using SharpDX.Direct2D1; -using SharpDX.Mathematics.Interop; -using BitmapInterpolationMode = Avalonia.Media.Imaging.BitmapInterpolationMode; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// Draws using Direct2D1. - /// - internal class DrawingContextImpl : IDrawingContextImpl - { - private readonly ILayerFactory _layerFactory; - private readonly SharpDX.Direct2D1.RenderTarget _renderTarget; - private readonly DeviceContext _deviceContext; - private readonly bool _ownsDeviceContext; - private readonly SharpDX.DXGI.SwapChain1 _swapChain; - private readonly Action _finishedCallback; - - private readonly Stack _renderOptionsStack = new(); - - /// - /// Initializes a new instance of the class. - /// - /// The render target to draw to. - /// - /// An object to use to create layers. May be null, in which case a - /// will created when a new layer is requested. - /// - /// Whether to scale drawings according to the DPI of . - /// An optional swap chain associated with this drawing context. - /// An optional delegate to be called when context is disposed. - public DrawingContextImpl( - ILayerFactory layerFactory, - SharpDX.Direct2D1.RenderTarget renderTarget, - bool useScaledDrawing, - SharpDX.DXGI.SwapChain1 swapChain = null, - Action finishedCallback = null) - { - _layerFactory = layerFactory; - _renderTarget = renderTarget; - _swapChain = swapChain; - _finishedCallback = finishedCallback; - - if (_renderTarget is DeviceContext deviceContext) - { - _deviceContext = deviceContext; - _ownsDeviceContext = false; - } - else - { - _deviceContext = _renderTarget.QueryInterface(); - _ownsDeviceContext = true; - } - - if (!useScaledDrawing) - { - var scaling = _renderTarget.DotsPerInch.Width / 96; - if (!MathUtilities.AreClose(1, scaling)) - _postTransform = Matrix.CreateScale(1 / scaling, 1 / scaling); - } - - _deviceContext.BeginDraw(); - } - - /// - /// Gets the current transform of the drawing context. - /// - public Matrix Transform - { - get { return _transform; } - set - { - _transform = value; - _deviceContext.Transform = - (_postTransform.HasValue ? value * _postTransform.Value : value).ToDirect2D(); - } - } - - public Matrix4x4 Transform4x4 - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public RenderOptions RenderOptions - { - get => _renderOptions; - set - { - _renderOptions = value; - ApplyRenderOptions(value); - } - } - - /// - public void Clear(Color color) - { - _deviceContext.Clear(color.ToDirect2D()); - } - - /// - /// Ends a draw operation. - /// - public void Dispose() - { - foreach (var layer in _layerPool) - { - layer.Dispose(); - } - - try - { - _deviceContext.EndDraw(); - - _swapChain?.Present(1, SharpDX.DXGI.PresentFlags.None); - _finishedCallback?.Invoke(); - } - catch (SharpDXException ex) when ((uint)ex.HResult == 0x8899000C) // D2DERR_RECREATE_TARGET - { - throw new RenderTargetCorruptedException(ex); - } - finally - { - if (_ownsDeviceContext) - { - _deviceContext.Dispose(); - } - } - } - - /// - /// Draws a bitmap image. - /// - /// The bitmap image. - /// The opacity to draw with. - /// The rect in the image to draw. - /// The rect in the output to draw to. - public void DrawBitmap(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) - { - using (var d2d = ((BitmapImpl)source).GetDirect2DBitmap(_deviceContext)) - { - var interpolationMode = GetInterpolationMode(RenderOptions.BitmapInterpolationMode); - - // TODO: How to implement CompositeMode here? - - _deviceContext.DrawBitmap( - d2d.Value, - destRect.ToSharpDX(), - (float)opacity, - interpolationMode, - sourceRect.ToSharpDX(), - null); - } - } - - private static InterpolationMode GetInterpolationMode(BitmapInterpolationMode interpolationMode) - { - switch (interpolationMode) - { - case BitmapInterpolationMode.Unspecified: - case BitmapInterpolationMode.LowQuality: - return InterpolationMode.Linear; - case BitmapInterpolationMode.MediumQuality: - return InterpolationMode.MultiSampleLinear; - case BitmapInterpolationMode.HighQuality: - return InterpolationMode.HighQualityCubic; - case BitmapInterpolationMode.None: - return InterpolationMode.NearestNeighbor; - default: - throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null); - } - } - - public static CompositeMode GetCompositeMode(BitmapBlendingMode blendingMode) - { - switch (blendingMode) - { - case BitmapBlendingMode.SourceIn: - return CompositeMode.SourceIn; - case BitmapBlendingMode.SourceOut: - return CompositeMode.SourceOut; - case BitmapBlendingMode.Unspecified: - case BitmapBlendingMode.SourceOver: - return CompositeMode.SourceOver; - case BitmapBlendingMode.SourceAtop: - return CompositeMode.SourceAtop; - case BitmapBlendingMode.DestinationIn: - return CompositeMode.DestinationIn; - case BitmapBlendingMode.DestinationOut: - return CompositeMode.DestinationOut; - case BitmapBlendingMode.DestinationOver: - return CompositeMode.DestinationOver; - case BitmapBlendingMode.DestinationAtop: - return CompositeMode.DestinationAtop; - case BitmapBlendingMode.Xor: - return CompositeMode.Xor; - case BitmapBlendingMode.Plus: - return CompositeMode.Plus; - default: - throw new ArgumentOutOfRangeException(nameof(blendingMode), blendingMode, null); - } - } - - /// - /// Draws a bitmap image. - /// - /// The bitmap image. - /// The opacity mask to draw with. - /// The destination rect for the opacity mask. - /// The rect in the output to draw to. - public void DrawBitmap(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) - { - var interpolationMode = GetInterpolationMode(RenderOptions.BitmapInterpolationMode); - - using (var d2dSource = ((BitmapImpl)source).GetDirect2DBitmap(_deviceContext)) - using (var sourceBrush = new BitmapBrush1(_deviceContext, d2dSource.Value, new BitmapBrushProperties1 { InterpolationMode = interpolationMode })) - using (var d2dOpacityMask = CreateBrush(opacityMask, opacityMaskRect)) - using (var geometry = new SharpDX.Direct2D1.RectangleGeometry(Direct2D1Platform.Direct2D1Factory, destRect.ToDirect2D())) - { - if (d2dOpacityMask.PlatformBrush != null) - { - d2dOpacityMask.PlatformBrush.Transform = Matrix.CreateTranslation(opacityMaskRect.Position).ToDirect2D(); - } - - _deviceContext.FillGeometry( - geometry, - sourceBrush, - d2dOpacityMask.PlatformBrush); - } - } - - /// - /// Draws a line. - /// - /// The stroke pen. - /// The first point of the line. - /// The second point of the line. - public void DrawLine(IPen pen, Point p1, Point p2) - { - if (pen != null) - { - var bounds = new Rect(p1, p2); - - using (var d2dBrush = CreateBrush(pen.Brush, bounds)) - using (var d2dStroke = pen.ToDirect2DStrokeStyle(_deviceContext)) - { - if (d2dBrush.PlatformBrush != null) - { - _deviceContext.DrawLine( - p1.ToSharpDX(), - p2.ToSharpDX(), - d2dBrush.PlatformBrush, - (float)pen.Thickness, - d2dStroke); - } - } - } - } - - /// - /// Draws a geometry. - /// - /// The fill brush. - /// The stroke pen. - /// The geometry. - public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry) - { - if (brush != null) - { - using (var d2dBrush = CreateBrush(brush, geometry.Bounds)) - { - if (d2dBrush.PlatformBrush != null) - { - var impl = (GeometryImpl)geometry; - _deviceContext.FillGeometry(impl.Geometry, d2dBrush.PlatformBrush); - } - } - } - - if (pen != null) - { - using (var d2dBrush = CreateBrush(pen.Brush, geometry.GetRenderBounds(pen))) - using (var d2dStroke = pen.ToDirect2DStrokeStyle(_deviceContext)) - { - if (d2dBrush.PlatformBrush != null) - { - var impl = (GeometryImpl)geometry; - _deviceContext.DrawGeometry(impl.Geometry, d2dBrush.PlatformBrush, (float)pen.Thickness, d2dStroke); - } - } - } - } - - /// - public void DrawRectangle(IBrush brush, IPen pen, RoundedRect rrect, BoxShadows boxShadow = default) - { - var rc = rrect.Rect.ToDirect2D(); - var rect = rrect.Rect; - var radiusX = Math.Max(rrect.RadiiTopLeft.X, - Math.Max(rrect.RadiiTopRight.X, Math.Max(rrect.RadiiBottomRight.X, rrect.RadiiBottomLeft.X))); - var radiusY = Math.Max(rrect.RadiiTopLeft.Y, - Math.Max(rrect.RadiiTopRight.Y, Math.Max(rrect.RadiiBottomRight.Y, rrect.RadiiBottomLeft.Y))); - var isRounded = !MathUtilities.IsZero(radiusX) || !MathUtilities.IsZero(radiusY); - - if (brush != null) - { - using (var b = CreateBrush(brush, rect)) - { - if (b.PlatformBrush != null) - { - if (isRounded) - { - _deviceContext.FillRoundedRectangle( - new RoundedRectangle - { - Rect = new RawRectangleF( - (float)rect.X, - (float)rect.Y, - (float)rect.Right, - (float)rect.Bottom), - RadiusX = (float)radiusX, - RadiusY = (float)radiusY - }, - b.PlatformBrush); - } - else - { - _deviceContext.FillRectangle(rc, b.PlatformBrush); - } - } - } - } - - if (pen?.Brush != null) - { - using (var wrapper = CreateBrush(pen.Brush, rect)) - using (var d2dStroke = pen.ToDirect2DStrokeStyle(_deviceContext)) - { - if (wrapper.PlatformBrush != null) - { - if (isRounded) - { - _deviceContext.DrawRoundedRectangle( - new RoundedRectangle { Rect = rc, RadiusX = (float)radiusX, RadiusY = (float)radiusY }, - wrapper.PlatformBrush, - (float)pen.Thickness, - d2dStroke); - } - else - { - _deviceContext.DrawRectangle( - rc, - wrapper.PlatformBrush, - (float)pen.Thickness, - d2dStroke); - } - } - } - } - } - - public void DrawRegion(IBrush brush, IPen pen, IPlatformRenderInterfaceRegion region) - { - throw new NotSupportedException(); - } - - /// - public void DrawEllipse(IBrush brush, IPen pen, Rect rect) - { - var rc = rect.ToDirect2D(); - - if (brush != null) - { - using (var b = CreateBrush(brush, rect)) - { - if (b.PlatformBrush != null) - { - _deviceContext.FillEllipse(new Ellipse - { - Point = rect.Center.ToSharpDX(), - RadiusX = (float)(rect.Width / 2), - RadiusY = (float)(rect.Height / 2) - }, b.PlatformBrush); - } - } - } - - if (pen?.Brush != null) - { - using (var wrapper = CreateBrush(pen.Brush, rect)) - using (var d2dStroke = pen.ToDirect2DStrokeStyle(_deviceContext)) - { - if (wrapper.PlatformBrush != null) - { - _deviceContext.DrawEllipse(new Ellipse - { - Point = rect.Center.ToSharpDX(), - RadiusX = (float)(rect.Width / 2), - RadiusY = (float)(rect.Height / 2) - }, wrapper.PlatformBrush, (float)pen.Thickness, d2dStroke); - } - } - } - } - - /// - /// Draws a glyph run. - /// - /// The foreground. - /// The glyph run. - public void DrawGlyphRun(IBrush foreground, IGlyphRunImpl glyphRun) - { - using (var brush = CreateBrush(foreground, glyphRun.Bounds)) - { - var immutableGlyphRun = (GlyphRunImpl)glyphRun; - - var dxGlyphRun = immutableGlyphRun.GlyphRun; - - _renderTarget.DrawGlyphRun(glyphRun.BaselineOrigin.ToSharpDX(), dxGlyphRun, - brush.PlatformBrush, MeasuringMode.Natural); - } - } - - public IDrawingContextLayerImpl CreateLayer(PixelSize pixelSize) - { - var dpi = new Vector(_deviceContext.DotsPerInch.Width, _deviceContext.DotsPerInch.Height); - if (_layerFactory != null) - { - return _layerFactory.CreateLayer(pixelSize.ToSizeWithDpi(dpi)); - } - else - { - var platform = AvaloniaLocator.Current.GetRequiredService(); - - return (IDrawingContextLayerImpl)platform.CreateRenderTargetBitmap(pixelSize, dpi); - } - } - - /// - /// Pushes a clip rectange. - /// - /// The clip rectangle. - /// A disposable used to undo the clip rectangle. - public void PushClip(Rect clip) - { - _deviceContext.PushAxisAlignedClip(clip.ToSharpDX(), AntialiasMode.PerPrimitive); - } - - public void PushClip(RoundedRect clip) - { - //TODO: radius - _deviceContext.PushAxisAlignedClip(clip.Rect.ToDirect2D(), AntialiasMode.PerPrimitive); - } - - public void PushClip(IPlatformRenderInterfaceRegion region) - { - throw new NotSupportedException(); - } - - public void PopClip() - { - _deviceContext.PopAxisAlignedClip(); - } - - public void PushLayer(Rect bounds) - { - var parameters = new LayerParameters - { - ContentBounds = bounds.ToDirect2D(), - MaskTransform = PrimitiveExtensions.Matrix3x2Identity, - Opacity = 1 - }; - var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_deviceContext); - _deviceContext.PushLayer(ref parameters, layer); - - _layers.Push(layer); - } - - void IDrawingContextImpl.PopLayer() - { - PopLayer(); - } - - readonly Stack _layers = new Stack(); - private readonly Stack _layerPool = new Stack(); - private RenderOptions _renderOptions; - private readonly Matrix? _postTransform; - private Matrix _transform = Matrix.Identity; - - /// - /// Pushes an opacity value. - /// - /// The opacity. - /// The bounds. - /// A disposable used to undo the opacity. - public void PushOpacity(double opacity, Rect? bounds) - { - if (opacity < 1) - { - if(bounds == null || bounds == default(Rect)) - { - bounds = new Rect(0, 0, _renderTarget.PixelSize.Width, _renderTarget.PixelSize.Height); - } - - var parameters = new LayerParameters - { - MaskTransform = PrimitiveExtensions.Matrix3x2Identity, - Opacity = (float)opacity - }; - - if(bounds.HasValue) - { - parameters.ContentBounds = bounds.Value.ToDirect2D(); - } - - var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_deviceContext); - _deviceContext.PushLayer(ref parameters, layer); - - _layers.Push(layer); - } - else - _layers.Push(null); - } - - public void PopOpacity() - { - PopLayer(); - } - - public void PushRenderOptions(RenderOptions renderOptions) - { - _renderOptionsStack.Push(RenderOptions); - - RenderOptions = RenderOptions.MergeWith(renderOptions); - } - - public void PopRenderOptions() - { - RenderOptions = _renderOptionsStack.Pop(); - } - - private void PopLayer() - { - var layer = _layers.Pop(); - if (layer != null) - { - _deviceContext.PopLayer(); - _layerPool.Push(layer); - } - } - - /// - /// Creates a Direct2D brush wrapper for a Avalonia brush. - /// - /// The avalonia brush. - /// The size of the brush's target area. - /// The Direct2D brush wrapper. - public BrushImpl CreateBrush(IBrush brush, Rect destinationRect) - { - var solidColorBrush = brush as ISolidColorBrush; - var linearGradientBrush = brush as ILinearGradientBrush; - var radialGradientBrush = brush as IRadialGradientBrush; - var conicGradientBrush = brush as IConicGradientBrush; - var imageBrush = brush as IImageBrush; - var sceneBrush = brush as ISceneBrush; - var sceneBrushContent = brush as ISceneBrushContent; - - if (solidColorBrush != null) - { - return new SolidColorBrushImpl(solidColorBrush, _deviceContext); - } - else if (linearGradientBrush != null) - { - return new LinearGradientBrushImpl(linearGradientBrush, _deviceContext, destinationRect); - } - else if (radialGradientBrush != null) - { - return new RadialGradientBrushImpl(radialGradientBrush, _deviceContext, destinationRect); - } - else if (conicGradientBrush != null) - { - // there is no Direct2D implementation of Conic Gradients so use Radial as a stand-in - return new SolidColorBrushImpl(conicGradientBrush, _deviceContext); - } - else if (imageBrush?.Source?.Bitmap != null) - { - return new ImageBrushImpl( - imageBrush, - _deviceContext, - (BitmapImpl)imageBrush.Source.Bitmap.Item, - destinationRect); - } - else if (sceneBrush != null || sceneBrushContent != null) - { - sceneBrushContent ??= sceneBrush.CreateContent(); - if (sceneBrushContent != null) - { - var rect = sceneBrushContent.Rect; - var intermediateSize = rect.Size; - - if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1) - { - // We need to ensure the size we're requesting is an integer pixel size, otherwise - // D2D alters the DPI of the render target, which messes stuff up. PixelSize.FromSize - // will do the rounding for us. - var dpi = new Vector(_deviceContext.DotsPerInch.Width, _deviceContext.DotsPerInch.Height); - var pixelSize = PixelSize.FromSizeWithDpi(intermediateSize, dpi); - - var transform = rect.TopLeft == default ? - Matrix.Identity : - Matrix.CreateTranslation(-rect.X, -rect.Y); - - var brushTransform = Matrix.Identity; - - if (sceneBrushContent.Transform != null) - { - var transformOrigin = sceneBrushContent.TransformOrigin.ToPixels(rect); - var offset = Matrix.CreateTranslation(transformOrigin); - - brushTransform = -offset * sceneBrushContent.Transform.Value * offset; - } - - using (var intermediate = new BitmapRenderTarget( - _deviceContext, - CompatibleRenderTargetOptions.None, - pixelSize.ToSizeWithDpi(dpi).ToSharpDX())) - { - using (var ctx = new RenderTarget(intermediate).CreateDrawingContext(true)) - { - intermediate.Clear(null); - - if (sceneBrush?.TileMode == TileMode.None) - { - transform = brushTransform * transform; - } - - sceneBrushContent.Render(ctx, transform); - } - - return new ImageBrushImpl( - sceneBrushContent.Brush, - _deviceContext, - new D2DBitmapImpl(intermediate.Bitmap.QueryInterface()), - destinationRect); - } - - } - } - } - - return new SolidColorBrushImpl(null, _deviceContext); - } - - public void PushGeometryClip(IGeometryImpl clip) - { - var parameters = new LayerParameters - { - ContentBounds = PrimitiveExtensions.RectangleInfinite, - MaskTransform = PrimitiveExtensions.Matrix3x2Identity, - Opacity = 1, - GeometricMask = ((GeometryImpl)clip).Geometry, - MaskAntialiasMode = AntialiasMode.PerPrimitive - }; - var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_deviceContext); - _deviceContext.PushLayer(ref parameters, layer); - - _layers.Push(layer); - - } - - public void PopGeometryClip() - { - PopLayer(); - } - - public void PushBitmapBlendMode(BitmapBlendingMode blendingMode) - { - // TODO: Stubs for now - } - - public void PopBitmapBlendMode() - { - // TODO: Stubs for now - } - - public void PushOpacityMask(IBrush mask, Rect bounds) - { - var parameters = new LayerParameters - { - ContentBounds = PrimitiveExtensions.RectangleInfinite, - MaskTransform = PrimitiveExtensions.Matrix3x2Identity, - Opacity = 1, - OpacityBrush = CreateBrush(mask, bounds).PlatformBrush - }; - var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_deviceContext); - _deviceContext.PushLayer(ref parameters, layer); - - _layers.Push(layer); - } - - public void PopOpacityMask() - { - PopLayer(); - } - - public object GetFeature(Type t) => null; - - private void ApplyRenderOptions(RenderOptions renderOptions) - { - _deviceContext.AntialiasMode = renderOptions.EdgeMode != EdgeMode.Aliased ? AntialiasMode.PerPrimitive : AntialiasMode.Aliased; - switch (renderOptions.TextRenderingMode) - { - case TextRenderingMode.Unspecified: - _deviceContext.TextAntialiasMode = renderOptions.EdgeMode != EdgeMode.Aliased ? TextAntialiasMode.Default : TextAntialiasMode.Aliased; - break; - case TextRenderingMode.Alias: - _deviceContext.TextAntialiasMode = TextAntialiasMode.Aliased; - break; - case TextRenderingMode.Antialias: - _deviceContext.TextAntialiasMode = TextAntialiasMode.Grayscale; - break; - case TextRenderingMode.SubpixelAntialias: - _deviceContext.TextAntialiasMode = TextAntialiasMode.Cleartype; - break; - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs deleted file mode 100644 index 97fd6b63b..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs +++ /dev/null @@ -1,24 +0,0 @@ -using SharpDX.Direct2D1; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// A Direct2D implementation of a . - /// - internal class EllipseGeometryImpl : GeometryImpl - { - /// - /// Initializes a new instance of the class. - /// - public EllipseGeometryImpl(Rect rect) - : base(CreateGeometry(rect)) - { - } - - private static Geometry CreateGeometry(Rect rect) - { - var ellipse = new Ellipse(rect.Center.ToSharpDX(), (float)rect.Width / 2, (float)rect.Height / 2); - return new EllipseGeometry(Direct2D1Platform.Direct2D1Factory, ellipse); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/FontManagerImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/FontManagerImpl.cs deleted file mode 100644 index 4c3e798d4..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/FontManagerImpl.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using Avalonia.Media; -using Avalonia.Platform; -using FontFamily = Avalonia.Media.FontFamily; -using FontStretch = Avalonia.Media.FontStretch; -using FontStyle = Avalonia.Media.FontStyle; -using FontWeight = Avalonia.Media.FontWeight; - -namespace Avalonia.Direct2D1.Media -{ - internal class FontManagerImpl : IFontManagerImpl - { - public string GetDefaultFontFamilyName() - { - //ToDo: Implement a real lookup of the system's default font. - return "Segoe UI"; - } - - public string[] GetInstalledFontFamilyNames(bool checkForUpdates = false) - { - var familyCount = Direct2D1FontCollectionCache.InstalledFontCollection.FontFamilyCount; - - var fontFamilies = new string[familyCount]; - - for (var i = 0; i < familyCount; i++) - { - fontFamilies[i] = Direct2D1FontCollectionCache.InstalledFontCollection.GetFontFamily(i).FamilyNames.GetString(0); - } - - return fontFamilies; - } - - public bool TryMatchCharacter(int codepoint, FontStyle fontStyle, - FontWeight fontWeight, FontStretch fontStretch, CultureInfo culture, out Typeface typeface) - { - var familyCount = Direct2D1FontCollectionCache.InstalledFontCollection.FontFamilyCount; - - for (var i = 0; i < familyCount; i++) - { - var font = Direct2D1FontCollectionCache.InstalledFontCollection.GetFontFamily(i) - .GetMatchingFonts((SharpDX.DirectWrite.FontWeight)fontWeight, - (SharpDX.DirectWrite.FontStretch)fontStretch, - (SharpDX.DirectWrite.FontStyle)fontStyle).GetFont(0); - - if (!font.HasCharacter(codepoint)) - { - continue; - } - - var fontFamilyName = font.FontFamily.FamilyNames.GetString(0); - - typeface = new Typeface(fontFamilyName, fontStyle, fontWeight, fontStretch); - - return true; - } - - typeface = default; - - return false; - } - - public bool TryCreateGlyphTypeface(string familyName, FontStyle style, FontWeight weight, - FontStretch stretch, [NotNullWhen(true)] out IGlyphTypeface glyphTypeface) - { - var systemFonts = Direct2D1FontCollectionCache.InstalledFontCollection; - - if (familyName == FontFamily.DefaultFontFamilyName) - { - familyName = "Segoe UI"; - } - - if (systemFonts.FindFamilyName(familyName, out var index)) - { - var font = systemFonts.GetFontFamily(index).GetFirstMatchingFont( - (SharpDX.DirectWrite.FontWeight)weight, - (SharpDX.DirectWrite.FontStretch)stretch, - (SharpDX.DirectWrite.FontStyle)style); - - glyphTypeface = new GlyphTypefaceImpl(font); - - return true; - } - - glyphTypeface = null; - - return false; - } - - public bool TryCreateGlyphTypeface(Stream stream, FontSimulations fontSimulations, out IGlyphTypeface glyphTypeface) - { - var fontLoader = new DWriteResourceFontLoader(Direct2D1Platform.DirectWriteFactory, new[] { stream }); - - var fontCollection = new SharpDX.DirectWrite.FontCollection(Direct2D1Platform.DirectWriteFactory, fontLoader, fontLoader.Key); - - if (fontCollection.FontFamilyCount > 0) - { - var fontFamily = fontCollection.GetFontFamily(0); - - if (fontFamily.FontCount > 0) - { - var font = fontFamily.GetFont(0); - - glyphTypeface = new GlyphTypefaceImpl(font); - - return true; - } - } - - glyphTypeface = null; - - return false; - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/GeometryGroupImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GeometryGroupImpl.cs deleted file mode 100644 index 5e49ef6d4..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/GeometryGroupImpl.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using Avalonia.Platform; -using SharpDX.Direct2D1; -using AM = Avalonia.Media; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// A Direct2D implementation of a . - /// - internal class GeometryGroupImpl : GeometryImpl - { - /// - /// Initializes a new instance of the class. - /// - public GeometryGroupImpl(AM.FillRule fillRule, IReadOnlyList geometry) - : base(CreateGeometry(fillRule, geometry)) - { - } - - private static Geometry CreateGeometry(AM.FillRule fillRule, IReadOnlyList children) - { - var count = children.Count; - var c = new Geometry[count]; - - for (var i = 0; i < count; ++i) - { - c[i] = ((GeometryImpl)children[i]).Geometry; - } - - return new GeometryGroup(Direct2D1Platform.Direct2D1Factory, (FillMode)fillRule, c); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs deleted file mode 100644 index 2399dd69e..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System; -using Avalonia.Logging; -using Avalonia.Media; -using Avalonia.Platform; -using SharpDX.Direct2D1; -using Geometry = SharpDX.Direct2D1.Geometry; -using PathGeometry = SharpDX.Direct2D1.PathGeometry; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// The platform-specific interface for . - /// - internal abstract class GeometryImpl : IGeometryImpl - { - private const float ContourApproximation = 0.0001f; - - public GeometryImpl(Geometry geometry) - { - Geometry = geometry; - } - - /// - public Rect Bounds => Geometry.GetWidenedBounds(0).ToAvalonia(); - - /// - public double ContourLength => Geometry.ComputeLength(null, ContourApproximation); - - public Geometry Geometry { get; } - - /// - public Rect GetRenderBounds(Avalonia.Media.IPen pen) - { - if (pen == null || Math.Abs(pen.Thickness) < float.Epsilon) - return Geometry.GetBounds().ToAvalonia(); - var originalBounds = Geometry.GetWidenedBounds((float)pen.Thickness).ToAvalonia(); - switch (pen.LineCap) - { - case PenLineCap.Flat: - return originalBounds; - case PenLineCap.Round: - return originalBounds.Inflate(pen.Thickness / 2); - case PenLineCap.Square: - return originalBounds.Inflate(pen.Thickness); - default: - throw new ArgumentOutOfRangeException(); - } - } - - public IGeometryImpl GetWidenedGeometry(IPen pen) - { - var result = new PathGeometry(Direct2D1Platform.Direct2D1Factory); - - using (var sink = result.Open()) - { - Geometry.Widen( - (float)pen.Thickness, - pen.ToDirect2DStrokeStyle(Direct2D1Platform.Direct2D1Factory), - 0.25f, - sink); - sink.Close(); - } - - return new StreamGeometryImpl(result); - } - - /// - public bool FillContains(Point point) - { - return Geometry.FillContainsPoint(point.ToSharpDX()); - } - - /// - public IGeometryImpl Intersect(IGeometryImpl geometry) - { - var result = new PathGeometry(Direct2D1Platform.Direct2D1Factory); - using (var sink = result.Open()) - { - Geometry.Combine(((GeometryImpl)geometry).Geometry, CombineMode.Intersect, sink); - sink.Close(); - } - return new StreamGeometryImpl(result); - } - - /// - public bool StrokeContains(Avalonia.Media.IPen pen, Point point) - { - return Geometry.StrokeContainsPoint(point.ToSharpDX(), (float)(pen?.Thickness ?? 0)); - } - - public ITransformedGeometryImpl WithTransform(Matrix transform) - { - return new TransformedGeometryImpl( - new TransformedGeometry( - Direct2D1Platform.Direct2D1Factory, - GetSourceGeometry(), - transform.ToDirect2D()), - this); - } - - /// - public bool TryGetPointAtDistance(double distance, out Point point) - { - Geometry.ComputePointAtLength((float)distance, ContourApproximation, out var tangentVector); - point = new Point(tangentVector.X, tangentVector.Y); - return true; - } - - /// - public bool TryGetPointAndTangentAtDistance(double distance, out Point point, out Point tangent) - { - // Direct2D doesn't have this sadly. - Logger.TryGet(LogEventLevel.Warning, LogArea.Visual)?.Log(this, "TryGetPointAndTangentAtDistance is not available in Direct2D."); - point = new Point(); - tangent = new Point(); - return false; - } - - public bool TryGetSegment(double startDistance, double stopDistance, bool startOnBeginFigure, out IGeometryImpl segmentGeometry) - { - // Direct2D doesn't have this too sadly. - Logger.TryGet(LogEventLevel.Warning, LogArea.Visual)?.Log(this, "TryGetSegment is not available in Direct2D."); - - segmentGeometry = null; - return false; - } - - protected virtual Geometry GetSourceGeometry() => Geometry; - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs deleted file mode 100644 index 729797203..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections.Generic; -using Avalonia.Media; -using Avalonia.Media.TextFormatting; -using Avalonia.Platform; -using SharpDX.DirectWrite; - -#nullable enable - -namespace Avalonia.Direct2D1.Media -{ - internal class GlyphRunImpl : IGlyphRunImpl - { - private readonly GlyphTypefaceImpl _glyphTypefaceImpl; - - private readonly short[] _glyphIndices; - private readonly float[] _glyphAdvances; - private readonly GlyphOffset[] _glyphOffsets; - - private SharpDX.DirectWrite.GlyphRun? _glyphRun; - - public GlyphRunImpl(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, - IReadOnlyList glyphInfos, Point baselineOrigin) - { - _glyphTypefaceImpl = (GlyphTypefaceImpl)glyphTypeface; - - FontRenderingEmSize = fontRenderingEmSize; - BaselineOrigin = baselineOrigin; - - var glyphCount = glyphInfos.Count; - - _glyphIndices = new short[glyphCount]; - - for (var i = 0; i < glyphCount; i++) - { - _glyphIndices[i] = (short)glyphInfos[i].GlyphIndex; - } - - _glyphAdvances = new float[glyphCount]; - - var width = 0.0; - - for (var i = 0; i < glyphCount; i++) - { - var advance = glyphInfos[i].GlyphAdvance; - - width += advance; - - _glyphAdvances[i] = (float)advance; - } - - _glyphOffsets = new GlyphOffset[glyphCount]; - - var runBounds = new Rect(); - var currentX = 0.0; - var scale = fontRenderingEmSize / glyphTypeface.Metrics.DesignEmHeight; - for (var i = 0; i < glyphCount; i++) - { - var (x, y) = glyphInfos[i].GlyphOffset; - - _glyphOffsets[i] = new GlyphOffset - { - AdvanceOffset = (float)x, - AscenderOffset = (float)y - }; - - if (_glyphTypefaceImpl.TryGetGlyphMetrics(glyphInfos[i].GlyphIndex, out var metrics)) - { - // Found metrics with negative height, prefer to adjust it to positive. - var ybearing = metrics.YBearing; - var height = metrics.Height; - if (height < 0) - { - height = -height; - } - - // Not entirely sure about why we need to do this, but it seems to work - var xOffset = metrics.XBearing * scale; - var xWidth = xOffset > 0 ? xOffset : 0; - var xBearing = xOffset < 0 ? xOffset : 0; - - //yBearing is the vertical distance from the baseline to the top of the glyph's bbox. It is usually positive for horizontal layouts, and negative for vertical ones. - runBounds = runBounds.Union(new Rect(currentX + xBearing, baselineOrigin.Y - ybearing * scale, xWidth + metrics.Width * scale, height * scale)); - } - - currentX += glyphInfos[i].GlyphAdvance; - } - - Bounds = runBounds.Translate(new Vector(baselineOrigin.X, 0)); - } - - public SharpDX.DirectWrite.GlyphRun GlyphRun - { - get - { - if (_glyphRun != null) - { - return _glyphRun; - } - - _glyphRun = new SharpDX.DirectWrite.GlyphRun - { - FontFace = _glyphTypefaceImpl.FontFace, - FontSize = (float)FontRenderingEmSize, - Advances = _glyphAdvances, - Indices = _glyphIndices, - Offsets = _glyphOffsets - }; - - return _glyphRun; - } - } - - public IGlyphTypeface GlyphTypeface => _glyphTypefaceImpl; - - public double FontRenderingEmSize { get; } - - public Point BaselineOrigin { get; } - - public Rect Bounds { get; } - - public IReadOnlyList GetIntersections(float lowerBound, float upperBound) => Array.Empty(); - - public void Dispose() - { - //_glyphRun?.Dispose(); - - _glyphRun = null; - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs deleted file mode 100644 index 01add0f0c..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs +++ /dev/null @@ -1,216 +0,0 @@ -using System; -using Avalonia.Media; -using HarfBuzzSharp; -using SharpDX.DirectWrite; -using FontMetrics = Avalonia.Media.FontMetrics; -using FontSimulations = Avalonia.Media.FontSimulations; -using GlyphMetrics = Avalonia.Media.GlyphMetrics; - -namespace Avalonia.Direct2D1.Media -{ - internal class GlyphTypefaceImpl : IGlyphTypeface - { - private bool _isDisposed; - - public GlyphTypefaceImpl(SharpDX.DirectWrite.Font font) - { - DWFont = font; - - FontFace = new FontFace(DWFont).QueryInterface(); - - Face = new Face(GetTable); - - Font = new HarfBuzzSharp.Font(Face); - - Font.SetFunctionsOpenType(); - - Font.GetScale(out var xScale, out _); - - if (!Font.TryGetHorizontalFontExtents(out var fontExtents)) - { - Font.TryGetVerticalFontExtents(out fontExtents); - } - - Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.UnderlineOffset, out var underlinePosition); - Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.UnderlineSize, out var underlineThickness); - Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.StrikeoutOffset, out var strikethroughPosition); - Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.StrikeoutSize, out var strikethroughThickness); - - Metrics = new FontMetrics - { - DesignEmHeight = (short)xScale, - Ascent = -fontExtents.Ascender, - Descent = -fontExtents.Descender, - LineGap = fontExtents.LineGap, - UnderlinePosition = underlinePosition, - UnderlineThickness = underlineThickness, - StrikethroughPosition = strikethroughPosition, - StrikethroughThickness = strikethroughThickness, - IsFixedPitch = FontFace.IsMonospacedFont - }; - - FamilyName = DWFont.FontFamily.FamilyNames.GetString(0); - - Weight = (Avalonia.Media.FontWeight)DWFont.Weight; - - Style = (Avalonia.Media.FontStyle)DWFont.Style; - - Stretch = (Avalonia.Media.FontStretch)DWFont.Stretch; - } - - private Blob GetTable(Face face, Tag tag) - { - var dwTag = (int)SwapBytes(tag); - - if (FontFace.TryGetFontTable(dwTag, out var tableData, out _)) - { - return new Blob(tableData.Pointer, tableData.Size, MemoryMode.ReadOnly, () => { }); - } - - return null; - } - - private static uint SwapBytes(uint x) - { - x = (x >> 16) | (x << 16); - - return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); - } - - public SharpDX.DirectWrite.Font DWFont { get; } - - public FontFace1 FontFace { get; } - - public Face Face { get; } - - public HarfBuzzSharp.Font Font { get; } - - public FontMetrics Metrics { get; } - - public int GlyphCount { get; set; } - - public FontSimulations FontSimulations => FontSimulations.None; - - public string FamilyName { get; } - - public Avalonia.Media.FontWeight Weight { get; } - - public Avalonia.Media.FontStyle Style { get; } - - public Avalonia.Media.FontStretch Stretch { get; } - - /// - public ushort GetGlyph(uint codepoint) - { - if (Font.TryGetGlyph(codepoint, out var glyph)) - { - return (ushort)glyph; - } - - return 0; - } - - public bool TryGetGlyph(uint codepoint, out ushort glyph) - { - glyph = GetGlyph(codepoint); - - return glyph != 0; - } - - /// - public ushort[] GetGlyphs(ReadOnlySpan codepoints) - { - var glyphs = new ushort[codepoints.Length]; - - for (var i = 0; i < codepoints.Length; i++) - { - if (Font.TryGetGlyph(codepoints[i], out var glyph)) - { - glyphs[i] = (ushort)glyph; - } - } - - return glyphs; - } - - /// - public int GetGlyphAdvance(ushort glyph) - { - return Font.GetHorizontalGlyphAdvance(glyph); - } - - /// - public int[] GetGlyphAdvances(ReadOnlySpan glyphs) - { - var glyphIndices = new uint[glyphs.Length]; - - for (var i = 0; i < glyphs.Length; i++) - { - glyphIndices[i] = glyphs[i]; - } - - return Font.GetHorizontalGlyphAdvances(glyphIndices); - } - - public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics) - { - metrics = default; - - if (!Font.TryGetGlyphExtents(glyph, out var extents)) - { - return false; - } - - metrics = new GlyphMetrics - { - XBearing = extents.XBearing, - YBearing = extents.YBearing, - Width = extents.Width, - Height = extents.Height - }; - - return true; - } - - private void Dispose(bool disposing) - { - if (_isDisposed) - { - return; - } - - _isDisposed = true; - - if (!disposing) - { - return; - } - - Font?.Dispose(); - Face?.Dispose(); - FontFace?.Dispose(); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - public bool TryGetTable(uint tag, out byte[] table) - { - table = null; - var blob = Face.ReferenceTable(tag); - - if (blob.Length > 0) - { - table = blob.AsSpan().ToArray(); - - return true; - } - - return false; - } - } -} - diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs deleted file mode 100644 index 7f595f827..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs +++ /dev/null @@ -1,124 +0,0 @@ -using Avalonia.Media; -using Avalonia.Rendering.Utilities; -using Avalonia.Utilities; -using SharpDX.Direct2D1; - -namespace Avalonia.Direct2D1.Media -{ - internal sealed class ImageBrushImpl : BrushImpl - { - private readonly OptionalDispose _bitmap; - - public ImageBrushImpl( - ITileBrush brush, - SharpDX.Direct2D1.RenderTarget target, - BitmapImpl bitmap, - Rect destinationRect) - { - var dpi = new Vector(target.DotsPerInch.Width, target.DotsPerInch.Height); - var calc = new TileBrushCalculator(brush, bitmap.PixelSize.ToSizeWithDpi(dpi), destinationRect.Size); - - Vector brushOffset = default; - if (brush.DestinationRect.Unit == RelativeUnit.Relative) - brushOffset = new Vector(destinationRect.X, destinationRect.Y); - - if (!calc.NeedsIntermediate) - { - _bitmap = bitmap.GetDirect2DBitmap(target); - PlatformBrush = new BitmapBrush( - target, - _bitmap.Value, - GetBitmapBrushProperties(brush), - GetBrushProperties(brush, calc.DestinationRect, brushOffset)); - } - else - { - using (var intermediate = RenderIntermediate(target, bitmap, calc)) - { - PlatformBrush = new BitmapBrush( - target, - intermediate.Bitmap, - GetBitmapBrushProperties(brush), - GetBrushProperties(brush, calc.DestinationRect, brushOffset)); - } - } - } - - public override void Dispose() - { - _bitmap.Dispose(); - base.Dispose(); - } - - private static BitmapBrushProperties GetBitmapBrushProperties(ITileBrush brush) - { - var tileMode = brush.TileMode; - - return new BitmapBrushProperties - { - ExtendModeX = GetExtendModeX(tileMode), - ExtendModeY = GetExtendModeY(tileMode), - }; - } - - private static BrushProperties GetBrushProperties(ITileBrush brush, Rect destinationRect, Vector offset) - { - var tileTransform = - brush.TileMode != TileMode.None ? - Matrix.CreateTranslation(destinationRect.X, destinationRect.Y) : - Matrix.Identity; - - if (offset != default) - tileTransform = Matrix.CreateTranslation(offset); - - if (brush.Transform != null && brush.TileMode != TileMode.None) - { - var transformOrigin = brush.TransformOrigin.ToPixels(destinationRect); - var originOffset = Matrix.CreateTranslation(transformOrigin); - - tileTransform = -originOffset * brush.Transform.Value * originOffset * tileTransform; - } - - return new BrushProperties - { - Opacity = (float)brush.Opacity, - Transform = tileTransform.ToDirect2D(), - }; - } - - private static ExtendMode GetExtendModeX(TileMode tileMode) - { - return (tileMode & TileMode.FlipX) != 0 ? ExtendMode.Mirror : ExtendMode.Wrap; - } - - private static ExtendMode GetExtendModeY(TileMode tileMode) - { - return (tileMode & TileMode.FlipY) != 0 ? ExtendMode.Mirror : ExtendMode.Wrap; - } - - private BitmapRenderTarget RenderIntermediate( - SharpDX.Direct2D1.RenderTarget target, - BitmapImpl bitmap, - TileBrushCalculator calc) - { - var result = new BitmapRenderTarget( - target, - CompatibleRenderTargetOptions.None, - calc.IntermediateSize.ToSharpDX()); - - using (var context = new RenderTarget(result).CreateDrawingContext(true)) - { - var dpi = new Vector(target.DotsPerInch.Width, target.DotsPerInch.Height); - var rect = new Rect(bitmap.PixelSize.ToSizeWithDpi(dpi)); - - context.Clear(Colors.Transparent); - context.PushClip(calc.IntermediateClip); - context.Transform = calc.IntermediateTransform; - context.DrawBitmap(bitmap, 1, rect, rect); - context.PopClip(); - } - - return result; - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs deleted file mode 100644 index ac21d7cf6..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.IO; -using Avalonia.Platform; -using D2DBitmap = SharpDX.Direct2D1.Bitmap1; - -namespace Avalonia.Direct2D1.Media -{ - internal abstract class BitmapImpl : IBitmapImpl, IDisposable - { - public abstract Vector Dpi { get; } - public abstract PixelSize PixelSize { get; } - public int Version { get; protected set; } = 1; - - public abstract OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target); - - public void Save(string fileName, int? quality = null) - { - if (Path.GetExtension(fileName) != ".png") - { - // Yeah, we need to support other formats. - throw new NotSupportedException("Use PNG, stoopid."); - } - - using (FileStream s = new FileStream(fileName, FileMode.Create)) - { - Save(s, quality); - } - } - - public abstract void Save(Stream stream, int? quality = null); - - public virtual void Dispose() - { - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs deleted file mode 100644 index 2373a90eb..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.IO; -using Avalonia.Metadata; -using SharpDX.Direct2D1; -using SharpDX.WIC; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// A Direct2D Bitmap implementation that uses a GPU memory bitmap as its image. - /// - internal class D2DBitmapImpl : BitmapImpl - { - private readonly Bitmap1 _direct2DBitmap; - - /// - /// Initialize a new instance of the class - /// with a bitmap backed by GPU memory. - /// - /// The GPU bitmap. - /// - /// This bitmap must be either from the same render target, - /// or if the render target is a , - /// the device associated with this context, to be renderable. - /// - public D2DBitmapImpl(Bitmap1 d2DBitmap) - { - _direct2DBitmap = d2DBitmap ?? throw new ArgumentNullException(nameof(d2DBitmap)); - } - - public override Vector Dpi => new Vector(96, 96); - public override PixelSize PixelSize => _direct2DBitmap.PixelSize.ToAvalonia(); - - public override void Dispose() - { - base.Dispose(); - _direct2DBitmap.Dispose(); - } - - public override OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target) - { - return new OptionalDispose(_direct2DBitmap, false); - } - - public override void Save(Stream stream, int? quality = null) - { - using (var encoder = new PngBitmapEncoder(Direct2D1Platform.ImagingFactory, stream)) - using (var frame = new BitmapFrameEncode(encoder)) - using (var bitmapSource = _direct2DBitmap.QueryInterface()) - { - frame.Initialize(); - frame.WriteSource(bitmapSource); - frame.Commit(); - encoder.Commit(); - } - } - } -} -; diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs deleted file mode 100644 index 6d2d12504..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.IO; -using Avalonia.Platform; -using Avalonia.Rendering; -using Avalonia.Utilities; -using SharpDX; -using SharpDX.Direct2D1; -using D2DBitmap = SharpDX.Direct2D1.Bitmap1; - -namespace Avalonia.Direct2D1.Media.Imaging -{ - internal class D2DRenderTargetBitmapImpl : D2DBitmapImpl, IDrawingContextLayerImpl, ILayerFactory - { - private readonly BitmapRenderTarget _renderTarget; - - public D2DRenderTargetBitmapImpl(BitmapRenderTarget renderTarget) - : base(renderTarget.Bitmap.QueryInterface()) - { - _renderTarget = renderTarget; - } - - public static D2DRenderTargetBitmapImpl CreateCompatible( - SharpDX.Direct2D1.RenderTarget renderTarget, - Size size) - { - var bitmapRenderTarget = new BitmapRenderTarget( - renderTarget, - CompatibleRenderTargetOptions.None, - new Size2F((float)size.Width, (float)size.Height)); - return new D2DRenderTargetBitmapImpl(bitmapRenderTarget); - } - - public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing) - { - return new DrawingContextImpl( this, _renderTarget, useScaledDrawing, - null, () => Version++); - } - - public bool IsCorrupted => false; - - public void Blit(IDrawingContextImpl context) => throw new NotSupportedException(); - - public bool CanBlit => false; - - public IDrawingContextLayerImpl CreateLayer(Size size) - { - return CreateCompatible(_renderTarget, size); - } - - public override void Dispose() - { - _renderTarget.Dispose(); - } - - public override OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target) - { - return new OptionalDispose(_renderTarget.Bitmap.QueryInterface(), false); - } - - public override void Save(Stream stream, int? quality = null) - { - using (var wic = new WicRenderTargetBitmapImpl(PixelSize, Dpi)) - { - using (var dc = wic.CreateDrawingContext(true, null)) - { - dc.DrawBitmap( - this, - 1, - new Rect(PixelSize.ToSizeWithDpi(Dpi.X)), - new Rect(PixelSize.ToSizeWithDpi(Dpi.X))); - } - - wic.Save(stream); - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs deleted file mode 100644 index 894cd8c6d..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs +++ /dev/null @@ -1,278 +0,0 @@ -using System; -using System.IO; -using Avalonia.Win32.Interop; -using SharpDX.WIC; -using APixelFormat = Avalonia.Platform.PixelFormat; -using AlphaFormat = Avalonia.Platform.AlphaFormat; -using D2DBitmap = SharpDX.Direct2D1.Bitmap1; -using Avalonia.Platform; -using PixelFormat = SharpDX.WIC.PixelFormat; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// A WIC implementation of a . - /// - internal class WicBitmapImpl : BitmapImpl, IReadableBitmapWithAlphaImpl - { - private readonly BitmapDecoder _decoder; - - private static BitmapInterpolationMode ConvertInterpolationMode(Avalonia.Media.Imaging.BitmapInterpolationMode interpolationMode) - { - switch (interpolationMode) - { - case Avalonia.Media.Imaging.BitmapInterpolationMode.Unspecified: - return BitmapInterpolationMode.Fant; - - case Avalonia.Media.Imaging.BitmapInterpolationMode.LowQuality: - return BitmapInterpolationMode.NearestNeighbor; - - case Avalonia.Media.Imaging.BitmapInterpolationMode.MediumQuality: - return BitmapInterpolationMode.Fant; - - default: - case Avalonia.Media.Imaging.BitmapInterpolationMode.HighQuality: - return BitmapInterpolationMode.HighQualityCubic; - - } - } - - /// - /// Initializes a new instance of the class. - /// - /// The filename of the bitmap to load. - public WicBitmapImpl(string fileName) - { - using (var decoder = new BitmapDecoder(Direct2D1Platform.ImagingFactory, fileName, DecodeOptions.CacheOnDemand)) - using (var frame = decoder.GetFrame(0)) - { - WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, frame, BitmapCreateCacheOption.CacheOnDemand); - Dpi = new Vector(96, 96); - SetFormatFromWic(WicImpl.PixelFormat); - } - } - - private WicBitmapImpl(Bitmap bmp) - { - WicImpl = bmp; - Dpi = new Vector(96, 96); - SetFormatFromWic(WicImpl.PixelFormat); - } - - /// - /// Initializes a new instance of the class. - /// - /// The stream to read the bitmap from. - public WicBitmapImpl(Stream stream) - { - // https://stackoverflow.com/questions/48982749/decoding-image-from-stream-using-wic/48982889#48982889 - _decoder = new BitmapDecoder(Direct2D1Platform.ImagingFactory, stream, DecodeOptions.CacheOnLoad); - - using var frame = _decoder.GetFrame(0); - WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, frame, BitmapCreateCacheOption.CacheOnLoad); - Dpi = new Vector(96, 96); - SetFormatFromWic(WicImpl.PixelFormat); - } - - /// - /// Initializes a new instance of the class. - /// - /// The size of the bitmap in device pixels. - /// The DPI of the bitmap. - /// Pixel format - /// Alpha format. - public WicBitmapImpl(PixelSize size, Vector dpi, APixelFormat? pixelFormat = null, AlphaFormat? alphaFormat = null) - { - if (!pixelFormat.HasValue) - { - pixelFormat = APixelFormat.Bgra8888; - } - - if (!alphaFormat.HasValue) - { - alphaFormat = Platform.AlphaFormat.Premul; - } - - PixelFormat = pixelFormat; - AlphaFormat = alphaFormat; - WicImpl = new Bitmap( - Direct2D1Platform.ImagingFactory, - size.Width, - size.Height, - pixelFormat.Value.ToWic(alphaFormat.Value), - BitmapCreateCacheOption.CacheOnLoad); - - Dpi = dpi; - } - - public WicBitmapImpl(APixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) - { - WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, size.Width, size.Height, format.ToWic(alphaFormat), BitmapCreateCacheOption.CacheOnDemand); - WicImpl.SetResolution(dpi.X, dpi.Y); - PixelFormat = format; - AlphaFormat = alphaFormat; - Dpi = dpi; - - using (var l = WicImpl.Lock(BitmapLockFlags.Write)) - { - for (var row = 0; row < size.Height; row++) - { - UnmanagedMethods.CopyMemory( - (l.Data.DataPointer + row * l.Stride), - (data + row * stride), - (UIntPtr)l.Data.Pitch); - } - } - } - - public WicBitmapImpl(Stream stream, int decodeSize, bool horizontal, Avalonia.Media.Imaging.BitmapInterpolationMode interpolationMode) - { - _decoder = new BitmapDecoder(Direct2D1Platform.ImagingFactory, stream, DecodeOptions.CacheOnLoad); - - using var frame = _decoder.GetFrame(0); - - // now scale that to the size that we want - var realScale = horizontal ? ((double)frame.Size.Height / frame.Size.Width) : ((double)frame.Size.Width / frame.Size.Height); - - PixelSize desired; - - if (horizontal) - { - desired = new PixelSize(decodeSize, (int)(realScale * decodeSize)); - } - else - { - desired = new PixelSize((int)(realScale * decodeSize), decodeSize); - } - - if (frame.Size.Width != desired.Width || frame.Size.Height != desired.Height) - { - using (var scaler = new BitmapScaler(Direct2D1Platform.ImagingFactory)) - { - scaler.Initialize(frame, desired.Width, desired.Height, ConvertInterpolationMode(interpolationMode)); - - WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, scaler, BitmapCreateCacheOption.CacheOnLoad); - } - } - else - { - WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, frame, BitmapCreateCacheOption.CacheOnLoad); - } - - Dpi = new Vector(96, 96); - } - - private void SetFormatFromWic(Guid pixelFormat) - { - if (pixelFormat == SharpDX.WIC.PixelFormat.Format16bppBGR565) - { - PixelFormat = APixelFormat.Rgb565; - AlphaFormat = Platform.AlphaFormat.Premul; - } - else if (pixelFormat == SharpDX.WIC.PixelFormat.Format32bppRGB) - { - PixelFormat = APixelFormat.Rgb32; - AlphaFormat = Platform.AlphaFormat.Premul; - } - else if (pixelFormat == PixelFormats.Rgba8888.ToWic(Platform.AlphaFormat.Premul)) - { - PixelFormat = APixelFormat.Rgba8888; - AlphaFormat = Platform.AlphaFormat.Premul; - } - else if (pixelFormat == PixelFormats.Rgba8888.ToWic(Platform.AlphaFormat.Opaque)) - { - PixelFormat = APixelFormat.Rgba8888; - AlphaFormat = Platform.AlphaFormat.Opaque; - } - else if (pixelFormat == PixelFormats.Bgra8888.ToWic(Platform.AlphaFormat.Premul)) - { - PixelFormat = APixelFormat.Bgra8888; - AlphaFormat = Platform.AlphaFormat.Premul; - } - else if (pixelFormat == PixelFormats.Bgra8888.ToWic(Platform.AlphaFormat.Opaque)) - { - PixelFormat = APixelFormat.Bgra8888; - AlphaFormat = Platform.AlphaFormat.Opaque; - } - } - - public override Vector Dpi { get; } - - public override PixelSize PixelSize => WicImpl.Size.ToAvalonia(); - - public APixelFormat? PixelFormat { get; private set; } - - public AlphaFormat? AlphaFormat { get; private set; } - - public override void Dispose() - { - WicImpl.Dispose(); - _decoder?.Dispose(); - } - - /// - /// Gets the WIC implementation of the bitmap. - /// - public Bitmap WicImpl { get; } - - /// - /// Gets a Direct2D bitmap to use on the specified render target. - /// - /// The render target. - /// The Direct2D bitmap. - public override OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget renderTarget) - { - using var converter = new FormatConverter(Direct2D1Platform.ImagingFactory); - converter.Initialize(WicImpl, SharpDX.WIC.PixelFormat.Format32bppPBGRA); - - var d2dBitmap = D2DBitmap.FromWicBitmap(renderTarget, converter).QueryInterface(); - - return new OptionalDispose(d2dBitmap, true); - } - - public override void Save(Stream stream, int? quality = null) - { - using (var encoder = new PngBitmapEncoder(Direct2D1Platform.ImagingFactory, stream)) - using (var frame = new BitmapFrameEncode(encoder)) - { - frame.Initialize(); - frame.WriteSource(WicImpl); - frame.Commit(); - encoder.Commit(); - } - } - - class LockedBitmap : ILockedFramebuffer - { - private readonly WicBitmapImpl _parent; - private readonly BitmapLock _lock; - private readonly APixelFormat _format; - - public LockedBitmap(WicBitmapImpl parent, BitmapLock l, APixelFormat format) - { - _parent = parent; - _lock = l; - _format = format; - } - - - public void Dispose() - { - _lock.Dispose(); - _parent.Version++; - } - - public IntPtr Address => _lock.Data.DataPointer; - public PixelSize Size => _lock.Size.ToAvalonia(); - public int RowBytes => _lock.Stride; - public Vector Dpi => _parent.Dpi; - public APixelFormat Format => _format; - - } - - APixelFormat? IReadableBitmapImpl.Format => PixelFormat; - - public ILockedFramebuffer Lock() => - new LockedBitmap(this, WicImpl.Lock(BitmapLockFlags.Write), PixelFormat.Value); - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs deleted file mode 100644 index 1855063ab..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using Avalonia.Platform; -using Avalonia.Rendering; -using SharpDX.Direct2D1; -using RenderTargetProperties = SharpDX.Direct2D1.RenderTargetProperties; - -namespace Avalonia.Direct2D1.Media -{ - internal class WicRenderTargetBitmapImpl : WicBitmapImpl, IDrawingContextLayerImpl - { - private readonly WicRenderTarget _renderTarget; - - public WicRenderTargetBitmapImpl( - PixelSize size, - Vector dpi, - Platform.PixelFormat? pixelFormat = null) - : base(size, dpi, pixelFormat) - { - var props = new RenderTargetProperties - { - DpiX = (float)dpi.X, - DpiY = (float)dpi.Y, - }; - - _renderTarget = new WicRenderTarget( - Direct2D1Platform.Direct2D1Factory, - WicImpl, - props); - } - - public override void Dispose() - { - _renderTarget.Dispose(); - - base.Dispose(); - } - - public virtual IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing) - => CreateDrawingContext(useScaledDrawing, null); - - public bool IsCorrupted => false; - - public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing, Action finishedCallback) - { - return new DrawingContextImpl(null, _renderTarget, useScaledDrawing, finishedCallback: () => - { - Version++; - finishedCallback?.Invoke(); - }); - } - - public void Blit(IDrawingContextImpl context) => throw new NotSupportedException(); - public bool CanBlit => false; - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs deleted file mode 100644 index 0bdf90161..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.IO; -using Avalonia.Platform; -using SharpDX.WIC; -using PixelFormat = Avalonia.Platform.PixelFormat; - -namespace Avalonia.Direct2D1.Media.Imaging -{ - internal class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl - { - public WriteableWicBitmapImpl(Stream stream, int decodeSize, bool horizontal, - Avalonia.Media.Imaging.BitmapInterpolationMode interpolationMode) - : base(stream, decodeSize, horizontal, interpolationMode) - { - } - - public WriteableWicBitmapImpl(PixelSize size, Vector dpi, PixelFormat? pixelFormat, AlphaFormat? alphaFormat) - : base(size, dpi, pixelFormat, alphaFormat) - { - } - - public WriteableWicBitmapImpl(Stream stream) - : base(stream) - { - } - - public WriteableWicBitmapImpl(string fileName) - : base(fileName) - { - } - - public PixelFormat? Format => PixelFormat; - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs deleted file mode 100644 index 4e020d4ae..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs +++ /dev/null @@ -1,24 +0,0 @@ -using SharpDX.Direct2D1; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// A Direct2D implementation of a . - /// - internal class LineGeometryImpl : StreamGeometryImpl - { - /// - /// Initializes a new instance of the class. - /// - public LineGeometryImpl(Point p1, Point p2) - { - using (var sink = ((PathGeometry)Geometry).Open()) - { - sink.BeginFigure(p1.ToSharpDX(), FigureBegin.Hollow); - sink.AddLine(p2.ToSharpDX()); - sink.EndFigure(FigureEnd.Open); - sink.Close(); - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs deleted file mode 100644 index 08afcfa0f..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Linq; -using Avalonia.Media; - -namespace Avalonia.Direct2D1.Media -{ - internal class LinearGradientBrushImpl : BrushImpl - { - public LinearGradientBrushImpl( - ILinearGradientBrush brush, - SharpDX.Direct2D1.RenderTarget target, - Rect destinationRect) - { - if (brush.GradientStops.Count == 0) - { - return; - } - - var gradientStops = brush.GradientStops.Select(s => new SharpDX.Direct2D1.GradientStop - { - Color = s.Color.ToDirect2D(), - Position = (float)s.Offset - }).ToArray(); - - var startPoint = brush.StartPoint.ToPixels(destinationRect); - var endPoint = brush.EndPoint.ToPixels(destinationRect); - - using (var stops = new SharpDX.Direct2D1.GradientStopCollection( - target, - gradientStops, - brush.SpreadMethod.ToDirect2D())) - { - PlatformBrush = new SharpDX.Direct2D1.LinearGradientBrush( - target, - new SharpDX.Direct2D1.LinearGradientBrushProperties - { - StartPoint = startPoint.ToSharpDX(), - EndPoint = endPoint.ToSharpDX() - }, - new SharpDX.Direct2D1.BrushProperties - { - Opacity = (float)brush.Opacity, - Transform = PrimitiveExtensions.Matrix3x2Identity, - }, - stops); - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs deleted file mode 100644 index 0c42a0565..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Linq; -using Avalonia.Media; - -namespace Avalonia.Direct2D1.Media -{ - internal class RadialGradientBrushImpl : BrushImpl - { - public RadialGradientBrushImpl( - IRadialGradientBrush brush, - SharpDX.Direct2D1.RenderTarget target, - Rect destinationRect) - { - if (brush.GradientStops.Count == 0) - { - return; - } - - var gradientStops = brush.GradientStops.Select(s => new SharpDX.Direct2D1.GradientStop - { - Color = s.Color.ToDirect2D(), - Position = (float)s.Offset - }).ToArray(); - - var centerPoint = brush.Center.ToPixels(destinationRect); - var gradientOrigin = brush.GradientOrigin.ToPixels(destinationRect) - centerPoint; - - var radiusX = brush.RadiusX.ToValue(destinationRect.Width); - var radiusY = brush.RadiusY.ToValue(destinationRect.Height); - - using (var stops = new SharpDX.Direct2D1.GradientStopCollection( - target, - gradientStops, - brush.SpreadMethod.ToDirect2D())) - { - PlatformBrush = new SharpDX.Direct2D1.RadialGradientBrush( - target, - new SharpDX.Direct2D1.RadialGradientBrushProperties - { - Center = centerPoint.ToSharpDX(), - GradientOriginOffset = gradientOrigin.ToSharpDX(), - RadiusX = (float)radiusX, - RadiusY = (float)radiusY - }, - new SharpDX.Direct2D1.BrushProperties - { - Opacity = (float)brush.Opacity, - Transform = PrimitiveExtensions.Matrix3x2Identity, - }, - stops); - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs deleted file mode 100644 index 8e5dc7a67..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs +++ /dev/null @@ -1,23 +0,0 @@ -using SharpDX.Direct2D1; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// A Direct2D implementation of a . - /// - internal class RectangleGeometryImpl : GeometryImpl - { - /// - /// Initializes a new instance of the class. - /// - public RectangleGeometryImpl(Rect rect) - : base(CreateGeometry(rect)) - { - } - - private static Geometry CreateGeometry(Rect rect) - { - return new RectangleGeometry(Direct2D1Platform.Direct2D1Factory, rect.ToDirect2D()); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs deleted file mode 100644 index bf974798a..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Avalonia.Media; - -namespace Avalonia.Direct2D1.Media -{ - internal class SolidColorBrushImpl : BrushImpl - { - public SolidColorBrushImpl(ISolidColorBrush brush, SharpDX.Direct2D1.RenderTarget target) - { - PlatformBrush = new SharpDX.Direct2D1.SolidColorBrush( - target, - brush?.Color.ToDirect2D() ?? new SharpDX.Mathematics.Interop.RawColor4(), - new SharpDX.Direct2D1.BrushProperties - { - Opacity = brush != null ? (float)brush.Opacity : 1.0f, - Transform = target.Transform - } - ); - } - - /// - /// Direct2D has no ConicGradient implementation so fall back to a solid colour brush based on - /// the first gradient stop. - /// - public SolidColorBrushImpl(IConicGradientBrush brush, SharpDX.Direct2D1.DeviceContext target) - { - PlatformBrush = new SharpDX.Direct2D1.SolidColorBrush( - target, - brush?.GradientStops[0].Color.ToDirect2D() ?? new SharpDX.Mathematics.Interop.RawColor4(), - new SharpDX.Direct2D1.BrushProperties - { - Opacity = brush != null ? (float)brush.Opacity : 1.0f, - Transform = target.Transform - } - ); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs deleted file mode 100644 index 5ffe331ca..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using Avalonia.Logging; -using Avalonia.Media; -using Avalonia.Metadata; -using Avalonia.Platform; -using SharpDX.Direct2D1; -using D2D = SharpDX.Direct2D1; -using SweepDirection = SharpDX.Direct2D1.SweepDirection; - -namespace Avalonia.Direct2D1.Media -{ - internal class StreamGeometryContextImpl : IStreamGeometryContextImpl - { - private readonly GeometrySink _sink; - - public StreamGeometryContextImpl(GeometrySink sink) - { - _sink = sink; - } - - public void ArcTo( - Point point, - Size size, - double rotationAngle, - bool isLargeArc, - Avalonia.Media.SweepDirection sweepDirection) - { - _sink.AddArc(new D2D.ArcSegment - { - Point = point.ToSharpDX(), - Size = size.ToSharpDX(), - RotationAngle = (float)rotationAngle, - ArcSize = isLargeArc ? ArcSize.Large : ArcSize.Small, - SweepDirection = (SweepDirection)sweepDirection, - }); - } - - public void BeginFigure(Point startPoint, bool isFilled) - { - _sink.BeginFigure(startPoint.ToSharpDX(), isFilled ? FigureBegin.Filled : FigureBegin.Hollow); - } - - public void CubicBezierTo(Point point1, Point point2, Point point3) - { - _sink.AddBezier(new D2D.BezierSegment - { - Point1 = point1.ToSharpDX(), - Point2 = point2.ToSharpDX(), - Point3 = point3.ToSharpDX(), - }); - } - - public void QuadraticBezierTo(Point control, Point dest) - { - _sink.AddQuadraticBezier(new D2D.QuadraticBezierSegment - { - Point1 = control.ToSharpDX(), - Point2 = dest.ToSharpDX() - }); - } - - public void LineTo(Point point) - { - _sink.AddLine(point.ToSharpDX()); - } - - public void EndFigure(bool isClosed) - { - _sink.EndFigure(isClosed ? FigureEnd.Closed : FigureEnd.Open); - } - - public void SetFillRule(FillRule fillRule) - { - _sink.SetFillMode(fillRule == FillRule.EvenOdd ? FillMode.Alternate : FillMode.Winding); - } - - public void Dispose() - { - // Put a catch around sink.Close as it may throw if there were an error e.g. parsing a path. - try - { - _sink.Close(); - } - catch (Exception ex) - { - Logger.TryGet(LogEventLevel.Error, LogArea.Visual)?.Log( - this, - "GeometrySink.Close exception: {Exception}", - ex); - } - - _sink.Dispose(); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs deleted file mode 100644 index 684460916..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Avalonia.Platform; -using SharpDX.Direct2D1; - -namespace Avalonia.Direct2D1.Media -{ - /// - /// A Direct2D implementation of a . - /// - internal class StreamGeometryImpl : GeometryImpl, IStreamGeometryImpl - { - /// - /// Initializes a new instance of the class. - /// - public StreamGeometryImpl() - : base(CreateGeometry()) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// An existing Direct2D . - public StreamGeometryImpl(PathGeometry geometry) - : base(geometry) - { - } - - /// - public IStreamGeometryImpl Clone() - { - var result = new PathGeometry(Direct2D1Platform.Direct2D1Factory); - using (var sink = result.Open()) - { - ((PathGeometry)Geometry).Stream(sink); - sink.Close(); - } - - return new StreamGeometryImpl(result); - } - - /// - public IStreamGeometryContextImpl Open() - { - return new StreamGeometryContextImpl(((PathGeometry)Geometry).Open()); - } - - private static Geometry CreateGeometry() - { - return new PathGeometry(Direct2D1Platform.Direct2D1Factory); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs deleted file mode 100644 index 2d0edb8f3..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; -using System.Buffers; -using System.Collections.Concurrent; -using System.Globalization; -using System.Runtime.InteropServices; -using Avalonia.Media.TextFormatting; -using Avalonia.Media.TextFormatting.Unicode; -using Avalonia.Platform; -using HarfBuzzSharp; -using Buffer = HarfBuzzSharp.Buffer; -using GlyphInfo = HarfBuzzSharp.GlyphInfo; - -namespace Avalonia.Direct2D1.Media -{ - internal class TextShaperImpl : ITextShaperImpl - { - private static readonly ConcurrentDictionary s_cachedLanguage = new(); - - public ShapedBuffer ShapeText(ReadOnlyMemory text, TextShaperOptions options) - { - var textSpan = text.Span; - var typeface = options.Typeface; - var fontRenderingEmSize = options.FontRenderingEmSize; - var bidiLevel = options.BidiLevel; - var culture = options.Culture; - - using (var buffer = new Buffer()) - { - // HarfBuzz needs the surrounding characters to correctly shape the text - var containingText = GetContainingMemory(text, out var start, out var length).Span; - buffer.AddUtf16(containingText, start, length); - - MergeBreakPair(buffer); - - buffer.GuessSegmentProperties(); - - buffer.Direction = (bidiLevel & 1) == 0 ? Direction.LeftToRight : Direction.RightToLeft; - - var usedCulture = culture ?? CultureInfo.CurrentCulture; - - buffer.Language = s_cachedLanguage.GetOrAdd(usedCulture.LCID, _ => new Language(usedCulture)); - - var font = ((GlyphTypefaceImpl)typeface).Font; - - font.Shape(buffer, GetFeatures(options)); - - if (buffer.Direction == Direction.RightToLeft) - { - buffer.Reverse(); - } - - font.GetScale(out var scaleX, out _); - - var textScale = fontRenderingEmSize / scaleX; - - var bufferLength = buffer.Length; - - var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel); - - var glyphInfos = buffer.GetGlyphInfoSpan(); - - var glyphPositions = buffer.GetGlyphPositionSpan(); - - for (var i = 0; i < bufferLength; i++) - { - var sourceInfo = glyphInfos[i]; - - var glyphIndex = (ushort)sourceInfo.Codepoint; - - var glyphCluster = (int)(sourceInfo.Cluster); - - var glyphAdvance = GetGlyphAdvance(glyphPositions, i, textScale) + options.LetterSpacing; - - var glyphOffset = GetGlyphOffset(glyphPositions, i, textScale); - - if (glyphCluster < containingText.Length && containingText[glyphCluster] == '\t') - { - glyphIndex = typeface.GetGlyph(' '); - - glyphAdvance = options.IncrementalTabWidth > 0 ? - options.IncrementalTabWidth : - 4 * typeface.GetGlyphAdvance(glyphIndex) * textScale; - } - - shapedBuffer[i] = new Avalonia.Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset); - } - - return shapedBuffer; - } - } - - private static void MergeBreakPair(Buffer buffer) - { - var length = buffer.Length; - - var glyphInfos = buffer.GetGlyphInfoSpan(); - - var second = glyphInfos[length - 1]; - - if (!new Codepoint(second.Codepoint).IsBreakChar) - { - return; - } - - if (length > 1 && glyphInfos[length - 2].Codepoint == '\r' && second.Codepoint == '\n') - { - var first = glyphInfos[length - 2]; - - first.Codepoint = '\u200C'; - second.Codepoint = '\u200C'; - second.Cluster = first.Cluster; - - unsafe - { - fixed (GlyphInfo* p = &glyphInfos[length - 2]) - { - *p = first; - } - - fixed (GlyphInfo* p = &glyphInfos[length - 1]) - { - *p = second; - } - } - } - else - { - second.Codepoint = '\u200C'; - - unsafe - { - fixed (GlyphInfo* p = &glyphInfos[length - 1]) - { - *p = second; - } - } - } - } - - private static Vector GetGlyphOffset(ReadOnlySpan glyphPositions, int index, double textScale) - { - var position = glyphPositions[index]; - - var offsetX = position.XOffset * textScale; - - var offsetY = -position.YOffset * textScale; - - return new Vector(offsetX, offsetY); - } - - private static double GetGlyphAdvance(ReadOnlySpan glyphPositions, int index, double textScale) - { - // Depends on direction of layout - // glyphPositions[index].YAdvance * textScale; - return glyphPositions[index].XAdvance * textScale; - } - - private static ReadOnlyMemory GetContainingMemory(ReadOnlyMemory memory, out int start, out int length) - { - if (MemoryMarshal.TryGetString(memory, out var containingString, out start, out length)) - { - return containingString.AsMemory(); - } - - if (MemoryMarshal.TryGetArray(memory, out var segment)) - { - start = segment.Offset; - length = segment.Count; - return segment.Array.AsMemory(); - } - - if (MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager memoryManager, out start, out length)) - { - return memoryManager.Memory; - } - - // should never happen - throw new InvalidOperationException("Memory not backed by string, array or manager"); - } - - private static Feature[] GetFeatures(TextShaperOptions options) - { - if (options.FontFeatures is null || options.FontFeatures.Count == 0) - { - return Array.Empty(); - } - - var features = new Feature[options.FontFeatures.Count]; - - for (var i = 0; i < options.FontFeatures.Count; i++) - { - var fontFeature = options.FontFeatures[i]; - - features[i] = new Feature( - Tag.Parse(fontFeature.Tag), - (uint)fontFeature.Value, - (uint)fontFeature.Start, - (uint)fontFeature.End); - } - - return features; - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs deleted file mode 100644 index 64aaea6f0..000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Avalonia.Platform; -using SharpDX.Direct2D1; - -namespace Avalonia.Direct2D1.Media -{ - internal class TransformedGeometryImpl : GeometryImpl, ITransformedGeometryImpl - { - /// - /// Initializes a new instance of the class. - /// - /// The source geometry. - /// An existing Direct2D . - public TransformedGeometryImpl(TransformedGeometry geometry, GeometryImpl source) - : base(geometry) - { - SourceGeometry = source; - } - - public IGeometryImpl SourceGeometry { get; } - - /// - public Matrix Transform => ((TransformedGeometry)Geometry).Transform.ToAvalonia(); - - protected override Geometry GetSourceGeometry() => ((TransformedGeometry)Geometry).SourceGeometry; - } -} diff --git a/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs b/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs deleted file mode 100644 index d526da2b5..000000000 --- a/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Avalonia.Direct2D1 -{ - internal readonly record struct OptionalDispose : IDisposable where T : IDisposable - { - private readonly bool _dispose; - - public OptionalDispose(T value, bool dispose) - { - Value = value; - _dispose = dispose; - } - - public T Value { get; } - - public void Dispose() - { - if (_dispose) Value?.Dispose(); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs deleted file mode 100644 index d042d5616..000000000 --- a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs +++ /dev/null @@ -1,226 +0,0 @@ -using System; -using System.Linq; -using Avalonia.Platform; -using SharpDX; -using SharpDX.Direct2D1; -using SharpDX.Mathematics.Interop; -using DWrite = SharpDX.DirectWrite; - -namespace Avalonia.Direct2D1 -{ - internal static class PrimitiveExtensions - { - /// - /// The value for which all absolute numbers smaller than are considered equal to zero. - /// - public const float ZeroTolerance = 1e-6f; // Value a 8x higher than 1.19209290E-07F - - public static readonly RawRectangleF RectangleInfinite; - - /// - /// Gets the identity matrix. - /// - /// The identity matrix. - public readonly static RawMatrix3x2 Matrix3x2Identity = new RawMatrix3x2 { M11 = 1, M12 = 0, M21 = 0, M22 = 1, M31 = 0, M32 = 0 }; - - static PrimitiveExtensions() - { - RectangleInfinite = new RawRectangleF - { - Left = float.NegativeInfinity, - Top = float.NegativeInfinity, - Right = float.PositiveInfinity, - Bottom = float.PositiveInfinity - }; - } - - public static Rect ToAvalonia(this RawRectangleF r) - { - return new Rect(new Point(r.Left, r.Top), new Point(r.Right, r.Bottom)); - } - - public static PixelSize ToAvalonia(this Size2 p) => new PixelSize(p.Width, p.Height); - - public static Vector ToAvaloniaVector(this Size2F p) => new Vector(p.Width, p.Height); - - public static RawRectangleF ToSharpDX(this Rect r) - { - return new RawRectangleF((float)r.X, (float)r.Y, (float)r.Right, (float)r.Bottom); - } - - public static RawVector2 ToSharpDX(this Point p) - { - return new RawVector2 { X = (float)p.X, Y = (float)p.Y }; - } - - public static Size2F ToSharpDX(this Size p) - { - return new Size2F((float)p.Width, (float)p.Height); - } - - public static ExtendMode ToDirect2D(this Avalonia.Media.GradientSpreadMethod spreadMethod) - { - if (spreadMethod == Avalonia.Media.GradientSpreadMethod.Pad) - return ExtendMode.Clamp; - else if (spreadMethod == Avalonia.Media.GradientSpreadMethod.Reflect) - return ExtendMode.Mirror; - else - return ExtendMode.Wrap; - } - - public static SharpDX.Direct2D1.LineJoin ToDirect2D(this Avalonia.Media.PenLineJoin lineJoin) - { - if (lineJoin == Avalonia.Media.PenLineJoin.Round) - return LineJoin.Round; - else if (lineJoin == Avalonia.Media.PenLineJoin.Miter) - return LineJoin.Miter; - else - return LineJoin.Bevel; - } - - public static SharpDX.Direct2D1.CapStyle ToDirect2D(this Avalonia.Media.PenLineCap lineCap) - { - if (lineCap == Avalonia.Media.PenLineCap.Flat) - return CapStyle.Flat; - else if (lineCap == Avalonia.Media.PenLineCap.Round) - return CapStyle.Round; - else if (lineCap == Avalonia.Media.PenLineCap.Square) - return CapStyle.Square; - else - return CapStyle.Triangle; - } - - public static Guid ToWic(this Platform.PixelFormat format, Platform.AlphaFormat alphaFormat) - { - bool isPremul = alphaFormat == AlphaFormat.Premul; - - if (format == Platform.PixelFormat.Rgb565) - return SharpDX.WIC.PixelFormat.Format16bppBGR565; - if (format == Platform.PixelFormat.Bgra8888) - return isPremul ? SharpDX.WIC.PixelFormat.Format32bppPBGRA : SharpDX.WIC.PixelFormat.Format32bppBGRA; - if (format == Platform.PixelFormat.Rgba8888) - return isPremul ? SharpDX.WIC.PixelFormat.Format32bppPRGBA : SharpDX.WIC.PixelFormat.Format32bppRGBA; - throw new ArgumentException("Unknown pixel format"); - } - - /// - /// Converts a pen to a Direct2D stroke style. - /// - /// The pen to convert. - /// The render target. - /// The Direct2D brush. - public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.IPen pen, SharpDX.Direct2D1.RenderTarget renderTarget) - { - return pen.ToDirect2DStrokeStyle(Direct2D1Platform.Direct2D1Factory); - } - - /// - /// Converts a pen to a Direct2D stroke style. - /// - /// The pen to convert. - /// The factory associated with this resource. - /// The Direct2D brush. - public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.IPen pen, Factory factory) - { - var d2dLineCap = pen.LineCap.ToDirect2D(); - - var properties = new StrokeStyleProperties - { - DashStyle = DashStyle.Solid, - MiterLimit = (float)pen.MiterLimit, - LineJoin = pen.LineJoin.ToDirect2D(), - StartCap = d2dLineCap, - EndCap = d2dLineCap, - DashCap = d2dLineCap - }; - float[] dashes = null; - if (pen.DashStyle?.Dashes != null && pen.DashStyle.Dashes.Count > 0) - { - properties.DashStyle = DashStyle.Custom; - properties.DashOffset = (float)pen.DashStyle.Offset; - dashes = pen.DashStyle.Dashes.Select(x => (float)x).ToArray(); - } - - dashes = dashes ?? Array.Empty(); - - return new StrokeStyle(factory, properties, dashes); - } - - /// - /// Converts a Avalonia to Direct2D. - /// - /// The color to convert. - /// The Direct2D color. - public static RawColor4 ToDirect2D(this Avalonia.Media.Color color) - { - return new RawColor4( - (float)(color.R / 255.0), - (float)(color.G / 255.0), - (float)(color.B / 255.0), - (float)(color.A / 255.0)); - } - - /// - /// Converts a Avalonia to a Direct2D - /// - /// The . - /// The . - public static RawMatrix3x2 ToDirect2D(this Matrix matrix) - { - return new RawMatrix3x2 - { - M11 = (float)matrix.M11, - M12 = (float)matrix.M12, - M21 = (float)matrix.M21, - M22 = (float)matrix.M22, - M31 = (float)matrix.M31, - M32 = (float)matrix.M32 - }; - } - - /// - /// Converts a Direct2D to a Avalonia . - /// - /// The matrix - /// a . - public static Matrix ToAvalonia(this RawMatrix3x2 matrix) - { - return new Matrix( - matrix.M11, - matrix.M12, - matrix.M21, - matrix.M22, - matrix.M31, - matrix.M32); - } - - /// - /// Converts a Avalonia to a Direct2D - /// - /// The . - /// The . - public static RawRectangleF ToDirect2D(this Rect rect) - { - return new RawRectangleF( - (float)rect.X, - (float)rect.Y, - (float)rect.Right, - (float)rect.Bottom); - } - - public static DWrite.TextAlignment ToDirect2D(this Avalonia.Media.TextAlignment alignment) - { - switch (alignment) - { - case Avalonia.Media.TextAlignment.Left: - return DWrite.TextAlignment.Leading; - case Avalonia.Media.TextAlignment.Center: - return DWrite.TextAlignment.Center; - case Avalonia.Media.TextAlignment.Right: - return DWrite.TextAlignment.Trailing; - default: - throw new InvalidOperationException("Invalid TextAlignment"); - } - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/RenderTarget.cs b/src/Windows/Avalonia.Direct2D1/RenderTarget.cs deleted file mode 100644 index ecefcd9da..000000000 --- a/src/Windows/Avalonia.Direct2D1/RenderTarget.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Avalonia.Direct2D1.Media; -using Avalonia.Direct2D1.Media.Imaging; -using Avalonia.Platform; -using Avalonia.Rendering; - -namespace Avalonia.Direct2D1 -{ - internal class RenderTarget : IRenderTarget, ILayerFactory - { - /// - /// The render target. - /// - private readonly SharpDX.Direct2D1.RenderTarget _renderTarget; - - /// - /// Initializes a new instance of the class. - /// - /// The render target. - public RenderTarget(SharpDX.Direct2D1.RenderTarget renderTarget) - { - _renderTarget = renderTarget; - } - - /// - /// Creates a drawing context for a rendering session. - /// - /// An . - public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing) - { - return new DrawingContextImpl(this, _renderTarget, useScaledDrawing); - } - - public bool IsCorrupted => false; - - public IDrawingContextLayerImpl CreateLayer(Size size) - { - return D2DRenderTargetBitmapImpl.CreateCompatible(_renderTarget, size); - } - - public void Dispose() - { - _renderTarget.Dispose(); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs deleted file mode 100644 index 228ae6e46..000000000 --- a/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs +++ /dev/null @@ -1,124 +0,0 @@ -using Avalonia.Direct2D1.Media; -using Avalonia.Direct2D1.Media.Imaging; -using Avalonia.Platform; -using Avalonia.Rendering; -using SharpDX; -using SharpDX.Direct2D1; -using SharpDX.DXGI; - -namespace Avalonia.Direct2D1 -{ - internal abstract class SwapChainRenderTarget : IRenderTarget, ILayerFactory - { - private Size2 _savedSize; - private Size2F _savedDpi; - private DeviceContext _deviceContext; - private SwapChain1 _swapChain; - - /// - /// Creates a drawing context for a rendering session. - /// - /// An . - public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing) - { - var size = GetWindowSize(); - var dpi = GetWindowDpi(); - - if (size != _savedSize || dpi != _savedDpi) - { - _savedSize = size; - _savedDpi = dpi; - - Resize(); - } - - return new DrawingContextImpl(this, _deviceContext, useScaledDrawing, _swapChain); - } - - public bool IsCorrupted => false; - - public IDrawingContextLayerImpl CreateLayer(Size size) - { - if (_deviceContext == null) - { - CreateDeviceContext(); - } - - return D2DRenderTargetBitmapImpl.CreateCompatible(_deviceContext, size); - } - - public void Dispose() - { - _deviceContext?.Dispose(); - - _swapChain?.Dispose(); - } - - private void Resize() - { - _deviceContext?.Dispose(); - _deviceContext = null; - - _swapChain?.ResizeBuffers(0, 0, 0, Format.Unknown, SwapChainFlags.None); - - CreateDeviceContext(); - } - - private void CreateSwapChain() - { - var swapChainDescription = new SwapChainDescription1 - { - Width = _savedSize.Width, - Height = _savedSize.Height, - Format = Format.B8G8R8A8_UNorm, - SampleDescription = new SampleDescription - { - Count = 1, - Quality = 0, - }, - Usage = Usage.RenderTargetOutput, - BufferCount = 1, - SwapEffect = SwapEffect.Discard, - }; - - using (var dxgiAdapter = Direct2D1Platform.DxgiDevice.Adapter) - using (var dxgiFactory = dxgiAdapter.GetParent()) - { - _swapChain = CreateSwapChain(dxgiFactory, swapChainDescription); - } - } - - private void CreateDeviceContext() - { - _deviceContext = new DeviceContext(Direct2D1Platform.Direct2D1Device, DeviceContextOptions.None) { DotsPerInch = _savedDpi }; - - if (_swapChain == null) - { - CreateSwapChain(); - } - - using (var dxgiBackBuffer = _swapChain.GetBackBuffer(0)) - using (var d2dBackBuffer = new Bitmap1( - _deviceContext, - dxgiBackBuffer, - new BitmapProperties1( - new SharpDX.Direct2D1.PixelFormat - { - AlphaMode = SharpDX.Direct2D1.AlphaMode.Premultiplied, - Format = Format.B8G8R8A8_UNorm - }, - _savedSize.Width, - _savedSize.Height, - BitmapOptions.Target | BitmapOptions.CannotDraw))) - { - _deviceContext.Target = d2dBackBuffer; - } - } - - protected abstract SwapChain1 CreateSwapChain(SharpDX.DXGI.Factory2 dxgiFactory, SwapChainDescription1 swapChainDesc); - - protected abstract Size2F GetWindowDpi(); - - protected abstract Size2 GetWindowSize(); - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Utils/DebugUtils.cs b/src/Windows/Avalonia.Direct2D1/Utils/DebugUtils.cs deleted file mode 100644 index 9ce8f15cf..000000000 --- a/src/Windows/Avalonia.Direct2D1/Utils/DebugUtils.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Avalonia.Direct2D1.Media.Imaging; - -namespace Avalonia.Direct2D1.Utils -{ - internal static class DebugUtils - { - public static void Save(SharpDX.Direct2D1.BitmapRenderTarget bitmap, string filename) - { - var rtb = new D2DRenderTargetBitmapImpl(bitmap); - rtb.Save(filename); - } - } -} diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index 5659a5539..b9c3c3dbc 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -38,7 +38,6 @@ - diff --git a/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj b/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj deleted file mode 100644 index e6cf735b2..000000000 --- a/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - $(AvsCurrentTargetFramework) - $(DefineConstants);AVALONIA_D2D - true - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj b/tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj deleted file mode 100644 index b5335e7bf..000000000 --- a/tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - $(AvsCurrentTargetFramework) - - - - - - - - - - - - - - - - - diff --git a/tests/Avalonia.Direct2D1.UnitTests/Controls/Shapes/PathTests.cs b/tests/Avalonia.Direct2D1.UnitTests/Controls/Shapes/PathTests.cs deleted file mode 100644 index 72a3ba703..000000000 --- a/tests/Avalonia.Direct2D1.UnitTests/Controls/Shapes/PathTests.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Avalonia.Controls.Shapes; -using Avalonia.Layout; -using Avalonia.Media; -using Xunit; - -namespace Avalonia.Direct2D1.UnitTests.Controls.Shapes -{ - public class PathTests - { - private static readonly RectComparer Compare = new RectComparer(); - - [Fact] - public void Should_Measure_Expander_Triangle_Correctly() - { - using (AvaloniaLocator.EnterScope()) - { - Direct2D1Platform.Initialize(); - - var target = new Path - { - Data = StreamGeometry.Parse("M 0 2 L 4 6 L 0 10 Z"), - StrokeThickness = 0, - HorizontalAlignment = HorizontalAlignment.Left, - VerticalAlignment = VerticalAlignment.Top, - UseLayoutRounding = false, - }; - - target.Measure(new Size(100, 100)); - target.Arrange(new Rect(0, 0, 100, 100)); - - Assert.Equal(new Rect(0, 0, 4, 10), target.Bounds, Compare); - } - } - - [Fact] - public void Should_Measure_Expander_Triangle_With_Stroke_Correctly() - { - using (AvaloniaLocator.EnterScope()) - { - Direct2D1Platform.Initialize(); - - var target = new Path - { - Data = StreamGeometry.Parse("M 0 2 L 4 6 L 0 10 Z"), - Stroke = Brushes.Black, - StrokeThickness = 2, - HorizontalAlignment = HorizontalAlignment.Left, - VerticalAlignment = VerticalAlignment.Top, - UseLayoutRounding = false, - }; - - target.Measure(new Size(100, 100)); - target.Arrange(new Rect(0, 0, 100, 100)); - - // Measured geometry with stroke of 2px is: - // - // {-1, -0.414, 6.414, 12.828} (see GeometryTests) - // - // With origin at 0,0 the bounds should equal: - // - // Assert.Equal(new Rect(0, 0, 5.414, 12.414), target.Bounds, compare); - // - // However Path.Measure doesn't correctly handle strokes currently, so testing for - // the (incorrect) current output for now... - Assert.Equal(new Rect(0, 0, 4, 10), target.Bounds, Compare); - } - } - } -} diff --git a/tests/Avalonia.Direct2D1.UnitTests/Media/FontManagerImplTests.cs b/tests/Avalonia.Direct2D1.UnitTests/Media/FontManagerImplTests.cs deleted file mode 100644 index 15e85750e..000000000 --- a/tests/Avalonia.Direct2D1.UnitTests/Media/FontManagerImplTests.cs +++ /dev/null @@ -1,89 +0,0 @@ -using Avalonia.Direct2D1.Media; -using Avalonia.Media; -using Avalonia.UnitTests; -using Xunit; - -namespace Avalonia.Direct2D1.UnitTests.Media -{ - public class FontManagerImplTests - { - private static string s_fontUri = "resm:Avalonia.Direct2D1.UnitTests.Assets?assembly=Avalonia.Direct2D1.UnitTests#Noto Mono"; - - [Fact] - public void Should_Create_Typeface_From_Fallback() - { - using (AvaloniaLocator.EnterScope()) - { - Direct2D1Platform.Initialize(); - - var typeface = new Typeface(new FontFamily("A, B, Arial")); - - var glyphTypeface = typeface.GlyphTypeface; - - Assert.Equal("Arial", glyphTypeface.FamilyName); - } - } - - [Fact] - public void Should_Create_Typeface_From_Fallback_Bold() - { - using (AvaloniaLocator.EnterScope()) - { - Direct2D1Platform.Initialize(); - - var typeface = new Typeface(new FontFamily("A, B, Arial"), weight: FontWeight.Bold); - - var glyphTypeface = typeface.GlyphTypeface; - - Assert.Equal("Arial", glyphTypeface.FamilyName); - - Assert.Equal(FontWeight.Bold, glyphTypeface.Weight); - - Assert.Equal(FontStyle.Normal, glyphTypeface.Style); - } - } - - [Fact] - public void Should_Create_Typeface_For_Unknown_Font() - { - using (AvaloniaLocator.EnterScope()) - { - Direct2D1Platform.Initialize(); - - var glyphTypeface = new Typeface(new FontFamily("Unknown")).GlyphTypeface; - - var defaultName = FontManager.Current.DefaultFontFamily.Name; - - Assert.Equal(defaultName, glyphTypeface.FamilyName); - } - } - - [Fact] - public void Should_Load_Typeface_From_Resource() - { - using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) - { - Direct2D1Platform.Initialize(); - - var fontManager = new FontManagerImpl(); - - var glyphTypeface = new Typeface(s_fontUri).GlyphTypeface; - - Assert.Equal("Noto Mono", glyphTypeface.FamilyName); - } - } - - [Fact] - public void Should_Load_Nearest_Matching_Font() - { - using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) - { - Direct2D1Platform.Initialize(); - - var glyphTypeface = new Typeface(s_fontUri, FontStyle.Italic, FontWeight.Black).GlyphTypeface; - - Assert.Equal("Noto Mono", glyphTypeface.FamilyName); - } - } - } -} diff --git a/tests/Avalonia.Direct2D1.UnitTests/Media/GeometryTests.cs b/tests/Avalonia.Direct2D1.UnitTests/Media/GeometryTests.cs deleted file mode 100644 index d8b6b13b2..000000000 --- a/tests/Avalonia.Direct2D1.UnitTests/Media/GeometryTests.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Avalonia.Media; -using Xunit; - -namespace Avalonia.Direct2D1.UnitTests.Media -{ - public class GeometryTests - { - private static readonly RectComparer Compare = new RectComparer(); - - [Fact] - public void Should_Measure_Expander_Triangle_Correctly() - { - using (AvaloniaLocator.EnterScope()) - { - Direct2D1Platform.Initialize(); - - var target = StreamGeometry.Parse("M 0 2 L 4 6 L 0 10 Z"); - - Assert.Equal(new Rect(0, 2, 4, 8), target.Bounds, Compare); - } - } - - [Fact] - public void Should_Measure_Expander_Triangle_With_Stroke_Correctly() - { - using (AvaloniaLocator.EnterScope()) - { - Direct2D1Platform.Initialize(); - - var target = StreamGeometry.Parse("M 0 2 L 4 6 L 0 10 Z"); - var pen = new Pen(Brushes.Black, 2); - - Assert.Equal(new Rect(-1, -0.414, 6.414, 12.828), target.GetRenderBounds(pen), Compare); - } - } - } -} diff --git a/tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs b/tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs deleted file mode 100644 index a0b39114d..000000000 --- a/tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Reflection; -using Xunit; - -// Don't run tests in parallel. -[assembly: CollectionBehavior(DisableTestParallelization = true)] \ No newline at end of file diff --git a/tests/Avalonia.Direct2D1.UnitTests/RectComparer.cs b/tests/Avalonia.Direct2D1.UnitTests/RectComparer.cs deleted file mode 100644 index 9c289cf58..000000000 --- a/tests/Avalonia.Direct2D1.UnitTests/RectComparer.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Avalonia.Direct2D1.UnitTests -{ - public class RectComparer : IEqualityComparer - { - public bool Equals(Rect a, Rect b) - { - return Math.Round(a.X, 3) == Math.Round(b.X, 3) && - Math.Round(a.Y, 3) == Math.Round(b.Y, 3) && - Math.Round(a.Width, 3) == Math.Round(b.Width, 3) && - Math.Round(a.Height, 3) == Math.Round(b.Height, 3); - } - - public int GetHashCode(Rect obj) - { - throw new NotImplementedException(); - } - } -} diff --git a/tests/Avalonia.RenderTests/Controls/AdornerTests.cs b/tests/Avalonia.RenderTests/Controls/AdornerTests.cs index b158bf798..fa60c1285 100644 --- a/tests/Avalonia.RenderTests/Controls/AdornerTests.cs +++ b/tests/Avalonia.RenderTests/Controls/AdornerTests.cs @@ -6,11 +6,7 @@ using Avalonia.Layout; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests; -#else -namespace Avalonia.Direct2D1.RenderTests.Controls; -#endif public class AdornerTests : TestBase { @@ -85,4 +81,4 @@ public class AdornerTests : TestBase testName: "Focus_Adorner_Is_Properly_Clipped_Clip_" + clip); } -} \ No newline at end of file +} diff --git a/tests/Avalonia.RenderTests/Controls/BorderTests.cs b/tests/Avalonia.RenderTests/Controls/BorderTests.cs index cde39e8bf..9e2f06ea6 100644 --- a/tests/Avalonia.RenderTests/Controls/BorderTests.cs +++ b/tests/Avalonia.RenderTests/Controls/BorderTests.cs @@ -4,11 +4,7 @@ using Avalonia.Layout; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Controls -#endif { public class BorderTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs b/tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs index ff36877d9..5ea894ba5 100644 --- a/tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs +++ b/tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs @@ -5,11 +5,7 @@ using Avalonia.Layout; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Controls -#endif { public class CustomRenderTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Controls/ImageBlendTests.cs b/tests/Avalonia.RenderTests/Controls/ImageBlendTests.cs index 1f8f5d224..77d23eee7 100644 --- a/tests/Avalonia.RenderTests/Controls/ImageBlendTests.cs +++ b/tests/Avalonia.RenderTests/Controls/ImageBlendTests.cs @@ -6,11 +6,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Controls -#endif { public class ImageBlendTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Controls/ImageCompositionTests.cs b/tests/Avalonia.RenderTests/Controls/ImageCompositionTests.cs index 8236468ae..e16f780c2 100644 --- a/tests/Avalonia.RenderTests/Controls/ImageCompositionTests.cs +++ b/tests/Avalonia.RenderTests/Controls/ImageCompositionTests.cs @@ -6,11 +6,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Controls -#endif { public class ImageCompositionTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Controls/ImageTests.cs b/tests/Avalonia.RenderTests/Controls/ImageTests.cs index 3bf935d19..1e3f35ec2 100644 --- a/tests/Avalonia.RenderTests/Controls/ImageTests.cs +++ b/tests/Avalonia.RenderTests/Controls/ImageTests.cs @@ -5,11 +5,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Controls -#endif { public class ImageTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs index ad543ae4e..45b8c5d2c 100644 --- a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs +++ b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs @@ -8,11 +8,7 @@ using Avalonia.Layout; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Controls -#endif { public class TextBlockTests : TestBase { @@ -299,7 +295,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls }; target.Children.Add(CreateText("aaaa")); target.Children.Add(CreateText("a a ")); - target.Children.Add(CreateText(" ")); // This one does not render correctly on Direct2D1 + target.Children.Add(CreateText(" ")); target.Children.Add(CreateText("LLLL")); var testName = $"Should_Keep_TrailingWhiteSpace"; @@ -343,11 +339,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls await RenderToFile(target, testName); CompareImages(testName); -#if AVALONIA_SKIA const string symbolsFont = "resm:Avalonia.Skia.RenderTests.Assets?assembly=Avalonia.Skia.RenderTests#Source Serif 4 36pt"; -#else - const string symbolsFont = "resm:Avalonia.Direct2D1.RenderTests.Assets?assembly=Avalonia.Direct2D1.RenderTests#Source Serif 4 36pt"; -#endif static TextBlock CreateText(string text) => new TextBlock { ClipToBounds = false, @@ -380,11 +372,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls await RenderToFile(target, testName); CompareImages(testName); -#if AVALONIA_SKIA const string symbolsFont = "resm:Avalonia.Skia.RenderTests.Assets?assembly=Avalonia.Skia.RenderTests#Source Serif 4 36pt"; -#else - const string symbolsFont = "resm:Avalonia.Direct2D1.RenderTests.Assets?assembly=Avalonia.Direct2D1.RenderTests#Source Serif 4 36pt"; -#endif static TextBlock CreateText(string text) => new TextBlock { HorizontalAlignment = HorizontalAlignment.Center, diff --git a/tests/Avalonia.RenderTests/CrossTests/Brushes/CrossTileBrushTests.cs b/tests/Avalonia.RenderTests/CrossTests/Brushes/CrossTileBrushTests.cs index db5a75e02..599ef948e 100644 --- a/tests/Avalonia.RenderTests/CrossTests/Brushes/CrossTileBrushTests.cs +++ b/tests/Avalonia.RenderTests/CrossTests/Brushes/CrossTileBrushTests.cs @@ -5,8 +5,6 @@ using Xunit; #if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests; -#elif AVALONIA_D2D -namespace Avalonia.Direct2D1.RenderTests; #else namespace Avalonia.RenderTests.WpfCompare; #endif diff --git a/tests/Avalonia.RenderTests/CrossTests/Brushes/RadialGradientBrushTests.cs b/tests/Avalonia.RenderTests/CrossTests/Brushes/RadialGradientBrushTests.cs index 98529dcbe..54b356a68 100644 --- a/tests/Avalonia.RenderTests/CrossTests/Brushes/RadialGradientBrushTests.cs +++ b/tests/Avalonia.RenderTests/CrossTests/Brushes/RadialGradientBrushTests.cs @@ -4,8 +4,6 @@ using Xunit; #if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests; -#elif AVALONIA_D2D -namespace Avalonia.Direct2D1.RenderTests; #else namespace Avalonia.RenderTests.WpfCompare; #endif diff --git a/tests/Avalonia.RenderTests/CrossTests/CrossGeometryTests.cs b/tests/Avalonia.RenderTests/CrossTests/CrossGeometryTests.cs index ac4a701f9..667126310 100644 --- a/tests/Avalonia.RenderTests/CrossTests/CrossGeometryTests.cs +++ b/tests/Avalonia.RenderTests/CrossTests/CrossGeometryTests.cs @@ -8,8 +8,6 @@ using Xunit; #if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests; -#elif AVALONIA_D2D -namespace Avalonia.Direct2D1.RenderTests; #else namespace Avalonia.RenderTests.WpfCompare; #endif diff --git a/tests/Avalonia.RenderTests/CrossTests/Media/DrawingContextTests.cs b/tests/Avalonia.RenderTests/CrossTests/Media/DrawingContextTests.cs index 5ce8f258d..19a49cea9 100644 --- a/tests/Avalonia.RenderTests/CrossTests/Media/DrawingContextTests.cs +++ b/tests/Avalonia.RenderTests/CrossTests/Media/DrawingContextTests.cs @@ -3,8 +3,6 @@ using CrossUI; #if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests.CrossTests; -#elif AVALONIA_D2D -namespace Avalonia.Direct2D1.RenderTests.CrossTests; #else namespace Avalonia.RenderTests.WpfCompare.CrossTests; #endif diff --git a/tests/Avalonia.RenderTests/CrossTests/Media/ImageScalingTests.cs b/tests/Avalonia.RenderTests/CrossTests/Media/ImageScalingTests.cs index 478fddf1e..a635227f4 100644 --- a/tests/Avalonia.RenderTests/CrossTests/Media/ImageScalingTests.cs +++ b/tests/Avalonia.RenderTests/CrossTests/Media/ImageScalingTests.cs @@ -5,8 +5,6 @@ using CrossUI; #if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests.CrossTests; -#elif AVALONIA_D2D -namespace Avalonia.Direct2D1.RenderTests.CrossTests; #else namespace Avalonia.RenderTests.WpfCompare.CrossTests; #endif diff --git a/tests/Avalonia.RenderTests/CrossUI/CrossUI.Avalonia.cs b/tests/Avalonia.RenderTests/CrossUI/CrossUI.Avalonia.cs index 15c6bbac3..2bc308a27 100644 --- a/tests/Avalonia.RenderTests/CrossUI/CrossUI.Avalonia.cs +++ b/tests/Avalonia.RenderTests/CrossUI/CrossUI.Avalonia.cs @@ -84,14 +84,8 @@ namespace CrossUI } } -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests.CrossUI { -#else -namespace Avalonia.Direct2D1.RenderTests.CrossUI -{ -#endif - class AvaloniaCrossControl : Control { private readonly CrossControl _src; diff --git a/tests/Avalonia.RenderTests/GeometryClippingTests.cs b/tests/Avalonia.RenderTests/GeometryClippingTests.cs index 7a01c308a..469cef98f 100644 --- a/tests/Avalonia.RenderTests/GeometryClippingTests.cs +++ b/tests/Avalonia.RenderTests/GeometryClippingTests.cs @@ -7,11 +7,7 @@ using System.Text; using Xunit; using System.Threading.Tasks; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests -#endif { public class GeometryClippingTests : TestBase { diff --git a/tests/Avalonia.RenderTests/ManualRenderTimer.cs b/tests/Avalonia.RenderTests/ManualRenderTimer.cs index 0dc994aaa..3dab7f08b 100644 --- a/tests/Avalonia.RenderTests/ManualRenderTimer.cs +++ b/tests/Avalonia.RenderTests/ManualRenderTimer.cs @@ -2,12 +2,7 @@ using Avalonia.Rendering; using System.Threading.Tasks; using System; - -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests -#endif { public class ManualRenderTimer : IRenderTimer { @@ -16,4 +11,4 @@ namespace Avalonia.Direct2D1.RenderTests public void TriggerTick() => Tick?.Invoke(TimeSpan.Zero); public Task TriggerBackgroundTick() => Task.Run(TriggerTick); } -} \ No newline at end of file +} diff --git a/tests/Avalonia.RenderTests/Media/BitmapTests.cs b/tests/Avalonia.RenderTests/Media/BitmapTests.cs index 38b23e1bf..0f849a040 100644 --- a/tests/Avalonia.RenderTests/Media/BitmapTests.cs +++ b/tests/Avalonia.RenderTests/Media/BitmapTests.cs @@ -13,11 +13,7 @@ using Path = System.IO.Path; #pragma warning disable CS0649 -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class BitmapTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/CombinedGeometryTests.cs b/tests/Avalonia.RenderTests/Media/CombinedGeometryTests.cs index 9c5c0248c..386188464 100644 --- a/tests/Avalonia.RenderTests/Media/CombinedGeometryTests.cs +++ b/tests/Avalonia.RenderTests/Media/CombinedGeometryTests.cs @@ -4,11 +4,7 @@ using Avalonia.Controls.Shapes; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class CombinedGeometryTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/ConicGradientBrushTests.cs b/tests/Avalonia.RenderTests/Media/ConicGradientBrushTests.cs index eea1ea8cf..a649f9cc8 100644 --- a/tests/Avalonia.RenderTests/Media/ConicGradientBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/ConicGradientBrushTests.cs @@ -4,11 +4,7 @@ using System; using System.Threading.Tasks; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class ConicGradientBrushTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs b/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs index f6e7ba0c4..2f99eea7f 100644 --- a/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs +++ b/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs @@ -1,14 +1,7 @@ using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else - -using Avalonia.Direct2D1.RenderTests; - -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class GeometryDrawingTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/GeometryGroupTests.cs b/tests/Avalonia.RenderTests/Media/GeometryGroupTests.cs index 9ebbd30e0..7fc69602e 100644 --- a/tests/Avalonia.RenderTests/Media/GeometryGroupTests.cs +++ b/tests/Avalonia.RenderTests/Media/GeometryGroupTests.cs @@ -6,11 +6,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class GeometryGroupTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/GlyphRunTests.cs b/tests/Avalonia.RenderTests/Media/GlyphRunTests.cs index 1b5083924..b8398ea09 100644 --- a/tests/Avalonia.RenderTests/Media/GlyphRunTests.cs +++ b/tests/Avalonia.RenderTests/Media/GlyphRunTests.cs @@ -8,11 +8,7 @@ using Avalonia.Media.Imaging; using Avalonia.Media.TextFormatting; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class GlyphRunTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/ImageBrushTests.cs b/tests/Avalonia.RenderTests/Media/ImageBrushTests.cs index aef33bc13..77dd4d29a 100644 --- a/tests/Avalonia.RenderTests/Media/ImageBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/ImageBrushTests.cs @@ -6,11 +6,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class ImageBrushTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/ImageDrawingTests.cs b/tests/Avalonia.RenderTests/Media/ImageDrawingTests.cs index 8a571c4d1..4294e3874 100644 --- a/tests/Avalonia.RenderTests/Media/ImageDrawingTests.cs +++ b/tests/Avalonia.RenderTests/Media/ImageDrawingTests.cs @@ -4,11 +4,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class ImageDrawingTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs b/tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs index 15081c529..411dfc583 100644 --- a/tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs @@ -7,11 +7,7 @@ using System.Text; using System.Threading.Tasks; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class LinearGradientBrushTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs index bffacf454..aee0bb5ae 100644 --- a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs @@ -7,11 +7,7 @@ using System.Text; using System.Threading.Tasks; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class RadialGradientBrushTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/RelativePointTestPrimitivesHelper.cs b/tests/Avalonia.RenderTests/Media/RelativePointTestPrimitivesHelper.cs index e84c5fcd7..26036398d 100644 --- a/tests/Avalonia.RenderTests/Media/RelativePointTestPrimitivesHelper.cs +++ b/tests/Avalonia.RenderTests/Media/RelativePointTestPrimitivesHelper.cs @@ -7,11 +7,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class RelativePointTestPrimitivesHelper : Control { diff --git a/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs b/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs index fc9cbf6a7..5a36e9865 100644 --- a/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs +++ b/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs @@ -6,11 +6,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class StreamGeometryTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs index ea47cf0c6..d5406c559 100644 --- a/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs +++ b/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs @@ -9,11 +9,7 @@ using Avalonia.Media.TextFormatting; using Avalonia.Utilities; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class TextLayoutTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Media/TileBrushTests.cs b/tests/Avalonia.RenderTests/Media/TileBrushTests.cs index c3249422e..33003d7a8 100644 --- a/tests/Avalonia.RenderTests/Media/TileBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/TileBrushTests.cs @@ -5,11 +5,8 @@ using Avalonia.Media; using Avalonia.Media.Immutable; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests; -#else -namespace Avalonia.Direct2D1.RenderTests.Media; -#endif + public class DrawingBrushTests: TestBase { public DrawingBrushTests() diff --git a/tests/Avalonia.RenderTests/Media/VisualBrushTests.cs b/tests/Avalonia.RenderTests/Media/VisualBrushTests.cs index bf4fc5708..2f86634c6 100644 --- a/tests/Avalonia.RenderTests/Media/VisualBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/VisualBrushTests.cs @@ -6,11 +6,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Media -#endif { public class VisualBrushTests : TestBase { diff --git a/tests/Avalonia.RenderTests/OpacityMaskTests.cs b/tests/Avalonia.RenderTests/OpacityMaskTests.cs index 6ce7e72df..a9348e351 100644 --- a/tests/Avalonia.RenderTests/OpacityMaskTests.cs +++ b/tests/Avalonia.RenderTests/OpacityMaskTests.cs @@ -7,11 +7,7 @@ using System.Text; using Xunit; using System.Threading.Tasks; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests -#endif { public class OpacityMaskTests : TestBase { diff --git a/tests/Avalonia.RenderTests/SVGPathTests.cs b/tests/Avalonia.RenderTests/SVGPathTests.cs index 3d0275c07..7db544626 100644 --- a/tests/Avalonia.RenderTests/SVGPathTests.cs +++ b/tests/Avalonia.RenderTests/SVGPathTests.cs @@ -7,13 +7,7 @@ using System.Text; using Xunit; using System.Threading.Tasks; -#if AVALONIA_CAIRO -namespace Avalonia.Cairo.RenderTests -#elif AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests -#endif { public class SVGPathTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Shapes/EllipseTests.cs b/tests/Avalonia.RenderTests/Shapes/EllipseTests.cs index 085176098..4c7e02ecf 100644 --- a/tests/Avalonia.RenderTests/Shapes/EllipseTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/EllipseTests.cs @@ -4,11 +4,7 @@ using Avalonia.Controls.Shapes; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Shapes -#endif { public class EllipseTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Shapes/LineTests.cs b/tests/Avalonia.RenderTests/Shapes/LineTests.cs index 70e030182..b8fa23d32 100644 --- a/tests/Avalonia.RenderTests/Shapes/LineTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/LineTests.cs @@ -4,11 +4,7 @@ using Avalonia.Controls.Shapes; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Shapes -#endif { public class LineTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Shapes/PathTests.cs b/tests/Avalonia.RenderTests/Shapes/PathTests.cs index 4f1412990..0f95f61a4 100644 --- a/tests/Avalonia.RenderTests/Shapes/PathTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/PathTests.cs @@ -4,11 +4,7 @@ using Avalonia.Layout; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Shapes -#endif { using System.Threading.Tasks; using Avalonia.Collections; diff --git a/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs b/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs index b918f7180..301ee46cf 100644 --- a/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs @@ -4,11 +4,7 @@ using Avalonia.Controls.Shapes; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Shapes -#endif { public class PolygonTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs b/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs index 12420b524..e110b4e30 100644 --- a/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs @@ -4,11 +4,7 @@ using Avalonia.Controls.Shapes; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Shapes -#endif { public class PolylineTests : TestBase { diff --git a/tests/Avalonia.RenderTests/Shapes/RectangleTests.cs b/tests/Avalonia.RenderTests/Shapes/RectangleTests.cs index 026fd0d89..add63013d 100644 --- a/tests/Avalonia.RenderTests/Shapes/RectangleTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/RectangleTests.cs @@ -4,11 +4,7 @@ using Avalonia.Controls.Shapes; using Avalonia.Media; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests.Shapes -#endif { public class RectangleTests : TestBase { diff --git a/tests/Avalonia.RenderTests/TestBase.cs b/tests/Avalonia.RenderTests/TestBase.cs index 2e753ec8b..fe8074fe5 100644 --- a/tests/Avalonia.RenderTests/TestBase.cs +++ b/tests/Avalonia.RenderTests/TestBase.cs @@ -16,30 +16,19 @@ using System.Threading; using Avalonia.Controls.Platform.Surfaces; using Avalonia.Media; using Avalonia.Rendering.Composition; +using Avalonia.Skia; using Avalonia.Threading; using Avalonia.UnitTests; using Avalonia.Utilities; using SixLabors.ImageSharp.PixelFormats; using Image = SixLabors.ImageSharp.Image; -#if AVALONIA_SKIA -using Avalonia.Skia; -#else -using Avalonia.Direct2D1; -#endif -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests -#endif { public class TestBase : IDisposable { -#if AVALONIA_SKIA private static string s_fontUri = "resm:Avalonia.Skia.RenderTests.Assets?assembly=Avalonia.Skia.RenderTests#Noto Mono"; -#else - private static string s_fontUri = "resm:Avalonia.Direct2D1.RenderTests.Assets?assembly=Avalonia.Direct2D1.RenderTests#Noto Mono"; -#endif + public static FontFamily TestFontFamily = new FontFamily(s_fontUri); private const double AllowedError = 0.022; @@ -49,12 +38,7 @@ namespace Avalonia.Direct2D1.RenderTests outputPath = outputPath.Replace('\\', Path.DirectorySeparatorChar); var testPath = GetTestsDirectory(); var testFiles = Path.Combine(testPath, "TestFiles"); -#if AVALONIA_SKIA - var platform = "Skia"; -#else - var platform = "Direct2D1"; -#endif - OutputPath = Path.Combine(testFiles, platform, outputPath); + OutputPath = Path.Combine(testFiles, "Skia", outputPath); TestRenderHelper.BeginTest(); } diff --git a/tests/Avalonia.RenderTests/TestRenderHelper.cs b/tests/Avalonia.RenderTests/TestRenderHelper.cs index 53ef16a6e..7e9d27f35 100644 --- a/tests/Avalonia.RenderTests/TestRenderHelper.cs +++ b/tests/Avalonia.RenderTests/TestRenderHelper.cs @@ -21,17 +21,9 @@ using Avalonia.UnitTests; using Avalonia.Utilities; using SixLabors.ImageSharp.PixelFormats; using Image = SixLabors.ImageSharp.Image; -#if AVALONIA_SKIA using Avalonia.Skia; -#else -using Avalonia.Direct2D1; -#endif -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests; -#else -namespace Avalonia.Direct2D1.RenderTests; -#endif static class TestRenderHelper { @@ -40,11 +32,7 @@ static class TestRenderHelper static TestRenderHelper() { -#if AVALONIA_SKIA SkiaPlatform.Initialize(); -#else - Direct2D1Platform.Initialize(); -#endif AvaloniaLocator.CurrentMutable .Bind() .ToConstant(s_dispatcherImpl); diff --git a/tests/Avalonia.RenderTests/TestRenderRoot.cs b/tests/Avalonia.RenderTests/TestRenderRoot.cs index 64fda9ae8..3e3a5e91d 100644 --- a/tests/Avalonia.RenderTests/TestRenderRoot.cs +++ b/tests/Avalonia.RenderTests/TestRenderRoot.cs @@ -6,11 +6,7 @@ using Avalonia.Controls; using Avalonia.Platform; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests -#endif { public class TestRenderRoot : Decorator, IRenderRoot { @@ -55,4 +51,4 @@ namespace Avalonia.Direct2D1.RenderTests public PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, RenderScaling); } -} \ No newline at end of file +} diff --git a/tests/Avalonia.RenderTests/TestSkip.cs b/tests/Avalonia.RenderTests/TestSkip.cs index c09a25b4c..88bb965f6 100644 --- a/tests/Avalonia.RenderTests/TestSkip.cs +++ b/tests/Avalonia.RenderTests/TestSkip.cs @@ -3,11 +3,7 @@ using System.IO; using System.Runtime.InteropServices; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests -#else -namespace Avalonia.Direct2D1.RenderTests -#endif { public class Win32Fact : FactAttribute { diff --git a/tests/Avalonia.RenderTests/WpfCompareTestBase.cs b/tests/Avalonia.RenderTests/WpfCompareTestBase.cs deleted file mode 100644 index 36db8b3da..000000000 --- a/tests/Avalonia.RenderTests/WpfCompareTestBase.cs +++ /dev/null @@ -1,9 +0,0 @@ -#if AVALONIA_SKIA -namespace Avalonia.Skia.RenderTests; -#else -namespace Avalonia.Direct2D1.RenderTests; -#endif -class WpfCompareTestBase -{ - -} diff --git a/tests/Avalonia.Skia.RenderTests/CrossTestBase.cs b/tests/Avalonia.Skia.RenderTests/CrossTestBase.cs index 776fe36b5..bbb5f4aa2 100644 --- a/tests/Avalonia.Skia.RenderTests/CrossTestBase.cs +++ b/tests/Avalonia.Skia.RenderTests/CrossTestBase.cs @@ -10,11 +10,7 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using Xunit; -#if AVALONIA_SKIA namespace Avalonia.Skia.RenderTests; -#else -namespace Avalonia.Direct2D1.RenderTests; -#endif class CrossFactAttribute : FactAttribute { diff --git a/tests/Avalonia.UnitTests/InternalsVisibleTo.cs b/tests/Avalonia.UnitTests/InternalsVisibleTo.cs index c989c2531..3e6534e77 100644 --- a/tests/Avalonia.UnitTests/InternalsVisibleTo.cs +++ b/tests/Avalonia.UnitTests/InternalsVisibleTo.cs @@ -5,7 +5,7 @@ [assembly:System.Runtime.CompilerServices.InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly:System.Runtime.CompilerServices.InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly:System.Runtime.CompilerServices.InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly:System.Runtime.CompilerServices.InternalsVisibleTo("Avalonia.Direct2D.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] + diff --git a/tests/TestFiles/CrossTests/Media/DrawingContext/Transform_Should_Work_As_Expected.wpf.png b/tests/TestFiles/CrossTests/Media/DrawingContext/Transform_Should_Work_As_Expected.wpf.png index 0c3b8c2b14a0ebc2a2b5416dcf7798e4e150a9f6..dd9ef0b02de0ff46f939017c20c569e0ff4d46e2 100644 GIT binary patch delta 193 zcmV;y06zbj29^epRxqncL_t(|UhUSgQN%zL1;H=UAqgdMIOISIr)16{igO5rNQAG# zMjEQyd~0s))XtNU0&kI^1Ty?v%W>db`^GGbj0&b$Z#pkWXu2?ugX z&G|#`N!A~`wfrdqlaT^#k)Q=K;Q!j@WD(~W$NXdgw+G@r7Ve6 diff --git a/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Flat_Bevel.wpf.png b/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Flat_Bevel.wpf.png index e174ccad15f168cc9f2cb3f64706d0f09fb945e5..556820e979b07e1aff9de58b33a667a38f103d5e 100644 GIT binary patch literal 7523 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 B4=exx literal 6815 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 diff --git a/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Flat_Miter.wpf.png b/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Flat_Miter.wpf.png index 8cf98ba633671510748dff8e53eaacc6cbc6b73c..f7ae2a893c261edb84e7f422c99103bc05c1a829 100644 GIT binary patch literal 8542 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 E0@&110RR91 literal 7625 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 diff --git a/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Flat_Round.wpf.png b/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Flat_Round.wpf.png index f44dd37b36a3d41f6650a3b81c812d77262bebeb..89a0a327e42dcb92262c32d5abc5397fe3e550a6 100644 GIT binary patch literal 7630 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 literal 6910 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 diff --git a/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Round_Bevel.wpf.png b/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Round_Bevel.wpf.png index 57565c7fe9d2087d2af0ca05f09aa0590b19ca17..900afa45cd72bda6caa7c1556feece33cf7c8ccd 100644 GIT binary patch literal 7545 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 diff --git a/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Round_Miter.wpf.png b/tests/TestFiles/CrossTests/Media/Geometry/Should_Properly_CloseFigure_Round_Miter.wpf.png index 7814ba07c0fa9ad61b0a4b4e53e9c2b8cb7fb922..30578a506caf52bbf8c5f5a3c9ab16fc685780ad 100644 GIT binary patch literal 8563 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 v(S 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 CSaLG} literal 3537 zcmeHKXH-+!76y$G0*ruwq0Cr8kx;^*B2`31sR|k{HK9nP6PXYc5;Pfl5ET`qi-Ob; zq(*82fdM2~C<+9IC|wN!>Fr%y^M1eg^Zj^tt+V!b_TBrObSEGSa-;5*(m3xJHk8VoW&o<5J2;qz z9bck+;dK#7Dq(Alp9opECX(h7b{x2CQHsJm%4-K`9viEcnx zXBs$!FMh&i03{CPc`2Eh8eUjzJbtE6wx8yrRu#Z?eDmgwOn0VX(WbrD3*Bb2oAc{G z3Wh4Y?b4qSHg5-?yk-gByqp7#vUbIdQfCGhpJp0h|Y+pIoRkYj+KzRDnNtXkhV1eo1ZQq3|VIuhCM+5Cm(J;slG z`)S|ST?K-VWgey*t`&(Gfl0C^TH{pUa9t3pB5djV+~&qw@4HdM+duM$8Y8w?e0?PH zN~Uo{gC1-{RF254C6o?T`u3l_T;=!4*0qsTucxP19l$;QGA~bVGomVR#C5ptR=FOG zFO3)$d}&Xbn;mTyo4G2`p8fi%Ty2vx%#Pouk9FV%eH*MU4PTyh!^;dyBlHekd})(K z!e$(2$qFkbPjqJ`wkeH8mB9F9hobuTkp#-XcFVR+ zilVg0X_oa`oVw~C_Oxeh?$qM6533Wsc^Hs*TPyjiP0vZqb4yYBGm7HtSs3L$ehEo4 za=62Q#at6bofUZMSTb}rqCC?U$4%2jP}(>~2d{eGh4xAZ-zXlND^+~twx-CvyO;Js z_Rt7-LMk;_ed=7FO0rjLscoW0Vbqgm-cBB+?RGK1 zPTYR`PO|vmLhbvJBRcgwbEtj*^&Upz7}--(87gQn>~dDq(`720;rFhG6nRS4*S5Ak zO?L6veHgI77zbTY?RzE1CwQSZbN3eSiK%`O#;6})hpk*{KLTG<*3;BhqWVGW!AFI*;>{(bslfc zy0tP6*L5hc(g?tr|K{}PAN>XHGm-?T*9rE+bIxH3{n;VSvbCnb!y7nyxZP#K1}UYL zK~}S#tiP1S0jrVKd@1JZpi#2b`|S6D!R>j@6JEd^i5dAz<|FGgJ0Hbodn|-JtBy`47)l5p*ScnzJft?OQc(ZmhExJFRX-7cwd_ z+R>AV5%w05yC3y`^S`|XFGTy=laBt>1olnGh8V#wQ=UF8AYF@4CChGIu}Rmx5XxToX2pSIdd+NF{XD(Oe-QPC!;u3W>NIDD ztsnPwX4!yeG$(qN4`e1BhZK>$_=@&3me^=V6POy3-w`K!LdXEVF;gWkh z;tfHWF;tH2X3bxpAMYCLEwV3q&Uhh?3SF4KcI*2P<0dFOGIo!475Lv;o*kV7SKe!X zrq(cGv(6yoE5Hc(Hoyt?_C@{8{k1&8{&dn&dw9`N!0UjNJRnu8Fx1K!)YmUfO#?8*phoaO0H< zRaLz39dlY6YLcYmZRvKoL64bHU}UJOh(wIUUvNmXR-Tpu`2@s667d)r`A)j{x)zif4Yz|EG8KeD zreyQ>^*i*Pb*oIPDIFDqj0pjgUCEU!s)6up6;GnBW>Kgui=^^jb^SUwwu z6nRliihuEdofbh!$W!3^Jzxxw;pHiSL#xc3R565VLVbdatb?e58J$?mgT_qrR(MMg zRaJ+AQNAwj?hT@Nj51a{2b`np2q1wG=NY%kq*~DxUVQVA1d$D0A>V%+4Vcmu3MGCb zGr9t;;3v97cg#`!iLB_3Dl_muk-NyCI?F?fc)$=UfI4bv8~u<*_?&{eS>9ceLg-Cv zZKFgf#BiD8b|wI0=9JRQ&_QBk?W z__2=1yte%j2-k*ihwvpXfz71sE;>vP2Olf~?**ysMTpo%Q~Dj9|7?!L@z9j9B1_{g SZVC7d6S{QX`W)>nhWsy6AB_+I diff --git a/tests/TestFiles/CrossTests/Media/Geometry/Should_Render_PolyBezierSegment_With_Strokeless_Lines.wpf.png b/tests/TestFiles/CrossTests/Media/Geometry/Should_Render_PolyBezierSegment_With_Strokeless_Lines.wpf.png index 097ae18331378b057ad5fde3593f5fce39777a43..81413bcfddb813bbab9e9348ea4522fc6f4c7c5f 100644 GIT binary patch delta 3129 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 T%lO3@00000NkvXXu0mjfqzGo$ delta 3351 zcmV+y4e0XGAE_abReumZNklH#6sa=V$MI_Vd6xYwxWy^ZlIju6M7!ekK3_000000F#&uJb%FEG;K{M%E5Ta za#kFl8o!RyqCO+eKOE&ylypjzo#P#Op4U(0t+u?|n^E4G9Zvok|K9(iek1l=GrwoXVSXPN=krZ!Ld}pILh>5r%Cb;XST$ zD9ZV9u#?;vnNx)J@J6VB_jdd&H-mc$LQo z{t`9NQzK7!r#X%-lH1+JLl17R)X6B>3;aTqKg{X_d4CQgQJ*wj7zdw>5_R7vyN+3| za#LefCc?jq-<79U&?6&Ec&GXJ@A4>@#I2!h zz`)d}O@CKJ5u>(RF6TITW)`n%+%ka|He`zv-nzczP6Lu--WY|t^icNv{xW{=dQ|AK zI$R-R)MfEL%?YxMPMr{!@hW?OpNf+43s{3KOn7rbNBLYF9F1?!l3}A)*9p#sBzsgI zkJ^|zI#ibpi`X>zOq85AU_}MqrR4bEyitE5>VM~=He3rx&g!`QQsEdlGPPB zjyef0hdlfu%A;mgvpKmfZ@D@Su89~mqRk%IzdBzbZqg@_{5E;BuJ;#~Fz|%8_Lf{3 z2RFvIl4Iat0rhd>&*Ht4!ylfTU4vDso7H?FO2jEooY=2=vz{?3Z`LFEb+ZnO8fd~> z4u3{D76)I7Z$WPfD^Q0%WN%6|C{0c(@hFicOmn%zNOYU5VZ}-=&-iGRCrs3Z`3x-K ztrO91jDu_AOSj-UYf>L2M$$X^X}r&(QIY&Iuj$ScC(DVkA$8@4oTu=UC^-QR*u#Jl z-rA6SJ-%cMud_il`OT#Ffv9sbiS0z$Lw}ttduO~q%pssdHTiuw-iMj|<^(vPHGqV- zF2a6ye5sc0p<{K}Lo_CnXiN^|mZFSajZb+aZs-C%Q|Bl|tjd^W%rEpf;jQCzqam3b zi!amCJ@ib81|)k?%8xZBV^lY@xjjlwMiZatxsns!eje}Dh*y?oWSn}M@J@62o`38$ zF;15OC^=~)$NOqbwqBh_a7!FqAHQp>E-)~4wTB$%`#`*ZbA=l76Bv!2CA@X5$_L}i z@_3K|s@ojr%;~$#oZd!tobLS*pU!G8z<||VDdQ%6@`H$1x#|OKwH_tB<-#bL>{@1w zEl`&Y`d+-Bv)4B#zA;#Jz33mp9_&rZ~v$%H4=FLglG=$#|7({92BY!Rs*LtveBAvU}R>9LAz9Z-17(zR{Q* z$aOR6m1%BMp0Vl3>>S1{*Y<6G7zf{vI%5|MQb!5z^k}?16#u-Q6Gp7gn9ec2cSW&C zd@q#qqdXG74>#iQ9(7V~PICK(r5G8a4iet!wegZW5=nMpS9v@>6W@+vYtYWr-5hfj z2C)fFsN`xinfO|bhQZiy!hbu>wJRgp1@@L}`Zm#!Mw4sD| znnM^O;RO~`C%ENMhg>Qs7m8

aJ;z#n06$F|ZOj!L7!toZ#k0oqt~0K*BrCErN4- zA7I~dSESm5@|~z9zDp~IqC6Wv%fsyjU}eNB`e)4vZ%zVf9&As5rR_E(--_A}Zu?Su zcAt))pJm5jt?EV=cf@B+k1w5DW5PQiC`~0!Da<^m`y42(@h8eG3iE`=e8f?Zo z65d?m$JjX7sNII-MGeVb>g3t0+Y_Kub+YIq@wt2{%Ehy5uzy}F9?~$42Bo>DJpnpX z*TuXp%5&|75fhi7-|7YyH`}?5by{J#m z?#yaF0;{#69)I5Hk@%~gZ%=?;s@oM`7x%eO&Ca)-O>bbh%B%7D{bH17+6%Ch6(qd1 z7bTM2CfD5sdapblFVT=3$OL#xjSBGWgFo#>?vu$`1`?h2cZ+|%$CEke5Y3&7IP)hciWbaA# zqHKxjJrR>EK?Yl=4$I1?Q~8t%7P4dyZ@ERX3q#hN5#^ys5}%IG^I7f10V@|sc41rP zdgIMw5wEgD?1K3%(ZidM7Ruk^uaNM^At`Rxg?waQ!Zl251Z zo1MdnEq~F&TaHS0VVg9kM!7qZ#%H7C&TRveJIqOTVH|Q9)aKq@!ELmIAW zYhbH17sN|WYP%sCk^xQpDz~)7i?*xvouf4tHs(877b_|e)@^p$#*+&m=xl*zVW7Nmq-uya@ z-38un2v4Wjr2PzOxTvjx(P>VJ^37;Ko{Vy+z1XE(ch?MUU=O{ES9EAU32)Be21c#9 zFn=15m!d@7rE+m!hC>=a9to!O;Iy(k9 zk*?zvU0XEa)w>J4OOp-9ZEZuc=|_ea$G>m$8(>bI#w$9u=#Yj_v^BuHbn(crT-F`{ zEWi+lF7{V>a6Ie zCzI*1_QEP1X={KLSZlnZ2Np?qb@u}c%14IHz0ru=8I4IkK3suvTKt`7v?l;7vVV?v zMPDqE@M>UyeQK_c2IR3QD;RfM^zH&{w90rzU+CclHl(>Y8ju$!lj+&*h5b6WtpV0# zW$}uhSR~=Kz&o&{=5V|`9}USelS4k%)&Og?l6XZ=ERgW#fNp?g3Bs?%$e|(v)TiI71;0O5EIsbO@A|)Z5zy+@EXnltihs_Lrho$x?(chkjTyrM_uOn4g!FR)>Cb(lw@5ji?L z2k0yDs_zVG0D3GJe4jiNjmWjLb3MF3Uwt56(IXOGpy%o?M|Vdfa(#ONpr^zuvylua h1Cj6s8Tw{2`9Izydl0?`F|Yst002ovPDHLkV1gO>j~4&{ diff --git a/tests/TestFiles/CrossTests/Media/Geometry/Should_Render_PolyLineSegment_With_Strokeless_Lines.wpf.png b/tests/TestFiles/CrossTests/Media/Geometry/Should_Render_PolyLineSegment_With_Strokeless_Lines.wpf.png index 3efd30c5bd133a76a86a9f49cf44f90ebf7887ce..2bd3338187ade854c04c72148f1cbe308d11088c 100644 GIT binary patch delta 61 zcmaFG^onUhyyQYg1_ho28xH=rZ+_0GB@}tvwD{bFjrR}4Pi(w2@dKAwG2<&grei-s Rr~YFA0#8>zmvv4FO#n(P8hHQ! delta 62 zcmaFG^onUhyrd!H0Rx7^8`k`>EcbW(F+q;`!}hz@M(4BzCpKQ5xPU`^(x$(!{Fsh0 S8rm*o00K`}KbLh*2~7Y~K^b}g diff --git a/tests/TestFiles/CrossTests/Media/Geometry/Should_Render_Stream_Geometry.wpf.png b/tests/TestFiles/CrossTests/Media/Geometry/Should_Render_Stream_Geometry.wpf.png index 2fb85630ab250a949ee82e951a35e13782d68cf2..d24a21d577e944564ada3f3f0a1b79f4cd71bf16 100644 GIT binary patch literal 3564 zcmeHK`#;ldAD_&uIgLh>V-7{c=FXuLDRNp8V#&QtL!y#H;Xz}H%F3ZM)vZ;GG-XI+ zIgAXgkuq6#jOO?-COM9JzV7?^2ku{=*Ykb7KCka}_+0Pn`?|iL&*%NVu6ud9D8aVC zKp>Eko2!#I2qa?;7!nErMn>;)JAs!>jJL}{(2Gv(37`W$?Rdly1ggkVSPhZ``Wr8} zo`?Z~lv~zKrY-VmFo2Zm=H%!bj}!Mhggsf*Ynq)=m(NgCUVluD2D8}*ValdO*=)4D zrj;GGJ)7Q>hKLSk8Xtn`SYesjvhwm(^lbJ4h`hXtws-qr_CbiO=Dv2q;O?c>bep4- zi>If1md2L%bxE!NB`l5`8_`)?NoeRYQ&p7(!IFX;Kp>nm6ZF*a9~tV{jIhyGm^62D zd1bPk*V=k@joXy@=3Bfbrn$erV0pGpkH?CeS<&qZwi^A6Cs}7^W+rFJiU!p+aKp2+ z-K#%79UbLbHtw1ksQ>M;SNrf>f{zK}eRDH;S(N4Q{`>dJgt^h1%aWnAHJWUpDgl${ z?yPqG3X=F1X?PEF_>1_Jbh5zHrBYBPo$L=9DsixZ9qBONZ`Y zw$c3<0&XBLv?_A#-MbrsINTR*N|yl^8Bp>mC(vU1W3R9>|8?kZv$a|;csyQ%e{jHg@uCaM@zrVAVmR59f@;OT_fmry2%R_a?xl}UzbKk^nrO%3zo!3f==4?Y+Hz!k>Px17A_Mra=8te#hgv98S7cdTXmQ z;9f=L9jV7reRquf{ORZKPwx%`Hq{54rPTGmn3|qm5c}xp=p0F=g$L5TOM%@I6HlIx zj1-4JL1cCPTcY;a*(jm?aSQ5g&k~~L{2%9Q%n}n5lcgu+<>fz4&QH-LXtFwdY;3IZ z<;&p)_Y)^i-u7dJSkAq<#M=4b!Gmd

CE3-MfOyE`i?ds{Zp_N3d10)R!O5#}#*u zjL^%<%4$h3V)yLig?_?8Xj`%NeDNh?S{F;|tDv9|9Uni=sPVcba;?DL3ETDWbh8J% zXYrYtvv70T#&5Q>kL)(XFtonVHlyaLv<5 zEp_19tCr{UvXE5=GQICn)=Gle4_lt0cDydzyFE%f-85rYm}_sOo;`RY+q)Q7zL@++ z*T{~R*_9Aiq%zyPxk2AfH!H?bf}E21l7Jt-*$p?(N}O(2ANWY=QgE3d>;rRKJUu<_ zdd}Z~==hC~WHvc6_my^s{m@}FSFk@>GenPOqru!mkpBFk;o-NqbkhnIt3P^_Y*D+x zT-k@Ld36`rt^uRSGwB_M*cd+x>g(4}I|sCk9prs$5*85v{Ar_6f9WXjQdL^QrHS)z}49>G9}YTk=j-v@?b^^|3xZ;nhY3o>jkw ze1O!OSq{;QUV-)^`e>-xO?|>0c`(|KPAL1nerP;-^7V;552YOj*iGKg{qE&*ni%Tt z^xS$yq5;2>S@y;->!l)oa!fq zhFC*p`RLe7cS^IpwT(t*RQS|2XfNDOMf@$k;Y@&!V?Q7sd*^ zRm)^*OLRg*KGYklC@b4l{n7+;PYI7-WkHA?f)(d+?Xy>vHtQcry8q}4qP5Xsd6 z)l?auiwOyWIAO8olqkfDj6{;vk6)YYQjmR^}t-0MQ`u08s{~r#q7t`{PC#4OCn^J!G zf_J2vGeA%w5fL5~G{Eig`z-R@TX7IV%G_MciGYCUMv{$<&G5>~7u@KXXXN=JTsap| z4${pu&k{O6T)+igb7l44#cUH@ZZx;Bcqb6ttH;RYvDH+gv|Rud;#7DH&2cqB9b1A(7|0b!@CoZunSuC^1Ual0h+I6Slr6sI( zTLrM{m<82XBlC6nvsX1W^iLCg+@524W!wGz{VN+9rtKX&g1y75@7F6zsza+x*R{i< zm?SmUnu9{^mk#u zAY^5<1PO#f|Fr=flx?Rt zHXU8vRg8Le0PKNGOHo;h!UXxIZtUH}(SMYKZ$lhbuO;jcQrxg*DS3TDX?UhK6Fah%lhC)7VIGaVq-i zEWB(h8j|Wpzzl^zd#@qWn(UB1`HEy~2uB}f&OvO;B-8^4O9-HuML4qFwB#U)GYChZ zL^uHx1dz}bG(;6cF?|nV-&f=4lL1hH0oI3uyyAc^M(KegAjmX{3I{QoN#MbW@H$|S z1ddQfrhT}ImYdPX#xx_ZETW4C_k$xk0ncq5#GC7c1TYak(3DTEQ8mvBQaojk^!boV zNC1{swd9j60BT33fR<60yFTl13P++O~V$6-Oong<0yP5il~A z&P-J0v9@)nBDgsvBp(gsAW&z@otzX=#VUIC`8AQk`@+joUefAPH^6g%&Ic$C9Xap@ z9Tyh|q&yJeyzcIt>#e62sG#)2Oq43==W@yNPw5PBuW%NMN`2n}`u72!&u?f;je?tF zdVrK)ULK?IM54mwp$t8Y1+|I_A{t^rJxk4(L7+D`2r^!2|G-3~j*UB4j84ew0yi{} No3p3Wi-QF6e*on+B%lBQ literal 3500 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 diff --git a/tests/TestFiles/CrossTests/Media/RadialGradientBrush/Transform_Should_Work_As_Expected.wpf.png b/tests/TestFiles/CrossTests/Media/RadialGradientBrush/Transform_Should_Work_As_Expected.wpf.png index 0c2d53389656c3443c9bfa851cd82bc0c8c6d986..f1ad3b04393426b9f8bb0242472df6fe3dd353aa 100644 GIT binary patch literal 8639 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 literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^DIm?d;{J#EL_OI|BUk%gR=X;nl zE@occebeT!4$wFH`eMx_`wncS*oB?@SIztUfNAdSsjn>g{Vwc`UJK;%TA7!xx^Dip zA2mpyNv2(_I#*q}Q34~Z;2t11K=OF;d)q;TIn>R|W#{R2*Q__5DlFhy`KpPi$ovXyL2 zQ;=JU)en}XJugZ=aC%8zeEC3liqWFW2eD~*x%kTUeQj}I$-Lzb3)PbWRNcA+hZT^4X%->HW1m9c(<~s&YS3j3^P6VM%xNb!1@J z*w6hZkrl}2EbxddW?b|)-^qBKizQ``Po@CK Na!*%3mvv4FO#mF;Ny`8L literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW??`q<)A;WS3ujRsS8y$?AMCt&*Ppyb3SVv2TPNK0{sb~7w8Te;w2xm9p_?6sg|Df PA7s0ytDnm{r-UW|qI^jn diff --git a/tests/TestFiles/CrossTests/Media/TileBrushes/Should_Render_With_Transform.wpf.png b/tests/TestFiles/CrossTests/Media/TileBrushes/Should_Render_With_Transform.wpf.png index 4276ba62c808a57d6452b456b179bf68c0a30fcd..01610b2cf5c35956a70b3cf7958bfa89f028fe5f 100644 GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?%|OS&4Wf;s&0F5 zzEsp}b<~TLFf2It>8*afp}}Pqpds`I2Y$vJW89ZG^Zo4|b1#<4G?+I!2yn2V5&AD> zlHPm&%B}6Y?631Vd5&F?qXGv@lLO_%kGpf7-~7G%_x?@=0Tw1l3?hzqG3R5sb8mA& O;o|A)=d#Wzp$PyorCZJb literal 424 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?94KVRBx>N$;D<636{>Ag)5go%YjI62t5w!KRfs=Q+NEFvvAjiFi;pXc)I$ztaD0e F0ss@jo$&ww literal 491 zcmeAS@N?(olHy`uVBq!ia0vp^DImiu-RbSIjg0b^6Z#^R@r}bqc7sO^|R*npYXI?R3%UMw`NO zZAUnSls$SB3}3Ixx&CY#bLFEsyq$s&WqYnHzl7jj3%$AStS!;b*IX5 z^DHN*pSuZiCJWFZ$GmH`&cbKa!KWDQdSU=F|(|?7`g7ePo(z?BM=TnDy z7U|Al{XqZfe_d$;=glY$-IiU9>h-u+!I{JdM9{GxOpc#(7M^CiwH+8i44$rjF6*2U FngEv+!7Km(