ソースを参照

Merge branch 'master' into scenegraph

 Conflicts:
	src/Skia/Avalonia.Skia/DrawingContextImpl.cs
Steven Kirk 8 年 前
コミット
bf6b9c1e7f

+ 4 - 1
src/Avalonia.Controls/Platform/ExportWindowingSubsystemAttribute.cs

@@ -9,16 +9,19 @@ namespace Avalonia.Platform
     [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
     public class ExportWindowingSubsystemAttribute : Attribute
     {
-        public ExportWindowingSubsystemAttribute(OperatingSystemType requiredRuntimePlatform, int priority, string name, Type initializationType, string initializationMethod)
+        public ExportWindowingSubsystemAttribute(OperatingSystemType requiredRuntimePlatform, int priority, string name, Type initializationType,
+            string initializationMethod, Type environmentChecker = null)
         {
             Name = name;
             InitializationType = initializationType;
             InitializationMethod = initializationMethod;
+            EnvironmentChecker = environmentChecker;
             RequiredOS = requiredRuntimePlatform;
             Priority = priority;
         }
 
         public string InitializationMethod { get; private set; }
+        public Type EnvironmentChecker { get; }
         public Type InitializationType { get; private set; }
         public string Name { get; private set; }
         public int Priority { get; private set; }

+ 16 - 2
src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs

@@ -31,6 +31,20 @@ namespace Avalonia
             Instance = app;
         }
 
+        bool CheckEnvironment(Type checkerType)
+        {
+            if (checkerType == null)
+                return true;
+            try
+            {
+                return ((IModuleEnvironmentChecker) Activator.CreateInstance(checkerType)).IsCompatible;
+            }
+            catch
+            {
+                return false;
+            }
+        }
+
         /// <summary>
         /// Instructs the <see cref="AppBuilder"/> to use the best settings for the platform.
         /// </summary>
@@ -43,13 +57,13 @@ namespace Avalonia
 
             var windowingSubsystemAttribute = (from assembly in RuntimePlatform.GetLoadedAssemblies()
                                                from attribute in assembly.GetCustomAttributes<ExportWindowingSubsystemAttribute>()
-                                               where attribute.RequiredOS == os
+                                               where attribute.RequiredOS == os && CheckEnvironment(attribute.EnvironmentChecker)
                                                orderby attribute.Priority ascending
                                                select attribute).First();
 
             var renderingSubsystemAttribute = (from assembly in RuntimePlatform.GetLoadedAssemblies()
                                                from attribute in assembly.GetCustomAttributes<ExportRenderingSubsystemAttribute>()
-                                               where attribute.RequiredOS == os
+                                               where attribute.RequiredOS == os && CheckEnvironment(attribute.EnvironmentChecker)
                                                where attribute.RequiresWindowingSubsystem == null
                                                 || attribute.RequiresWindowingSubsystem == windowingSubsystemAttribute.Name
                                                orderby attribute.Priority ascending

+ 1 - 0
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@@ -122,6 +122,7 @@
     <Compile Include="Rendering\DirtyVisuals.cs" />
     <Compile Include="Rendering\DisplayDirtyRect.cs" />
     <Compile Include="Rendering\DisplayDirtyRects.cs" />
+    <Compile Include="Platform\IModuleEnvironmentChecker.cs" />
     <Compile Include="Rendering\IRenderer.cs" />
     <Compile Include="Rendering\IRendererFactory.cs" />
     <Compile Include="Rendering\IRenderLoop.cs" />

+ 4 - 1
src/Avalonia.Visuals/Platform/ExportRenderingSubsystemAttribute.cs

@@ -9,16 +9,19 @@ namespace Avalonia.Platform
     [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
     public class ExportRenderingSubsystemAttribute : Attribute
     {
-        public ExportRenderingSubsystemAttribute(OperatingSystemType requiredOS, int priority, string name, Type initializationType, string initializationMethod)
+        public ExportRenderingSubsystemAttribute(OperatingSystemType requiredOS, int priority, string name, Type initializationType, string initializationMethod,
+            Type environmentChecker = null)
         {
             Name = name;
             InitializationType = initializationType;
             InitializationMethod = initializationMethod;
+            EnvironmentChecker = environmentChecker;
             RequiredOS = requiredOS;
             Priority = priority;
         }
 
         public string InitializationMethod { get; private set; }
+        public Type EnvironmentChecker { get; }
         public Type InitializationType { get; private set; }
         public string Name { get; private set; }
         public int Priority { get; private set; }

+ 7 - 0
src/Avalonia.Visuals/Platform/IModuleEnvironmentChecker.cs

@@ -0,0 +1,7 @@
+namespace Avalonia.Platform
+{
+    public interface IModuleEnvironmentChecker
+    {
+        bool IsCompatible { get; }
+    }
+}

+ 4 - 2
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@@ -19,10 +19,12 @@ namespace Avalonia.Skia
 
         public DrawingContextImpl(SKCanvas canvas, Matrix? postTransform = null, params IDisposable[] disposables)
         {
-            if (_postTransform.HasValue && !_postTransform.Value.IsIdentity)
+            if (postTransform.HasValue && !postTransform.Value.IsIdentity)
                 _postTransform = postTransform;
             _disposables = disposables;
             Canvas = canvas;
+            Canvas.Clear();
+            Transform = Matrix.Identity;
         }
 
         public void Clear(Color color)
@@ -362,7 +364,7 @@ namespace Avalonia.Skia
             Canvas.Restore();
         }
 
-        private Matrix _currentTransform = Matrix.Identity;
+        private Matrix _currentTransform;
 
         public Matrix Transform
         {

+ 1 - 0
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@@ -97,6 +97,7 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RenderTarget.cs" />
     <Compile Include="SwapChainRenderTarget.cs" />
+    <Compile Include="WindowsVersionChecker.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="app.config" />

+ 2 - 1
src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs

@@ -6,5 +6,6 @@ using Avalonia.Platform;
 using Avalonia.Direct2D1;
 
 [assembly: AssemblyTitle("Avalonia.Direct2D1")]
-[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 1, "Direct2D1", typeof(Direct2D1Platform), nameof(Direct2D1Platform.Initialize))]
+[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 1, "Direct2D1", typeof(Direct2D1Platform), nameof(Direct2D1Platform.Initialize),
+    typeof(WindowsVersionChecker))]
 

+ 15 - 0
src/Windows/Avalonia.Direct2D1/WindowsVersionChecker.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Platform;
+
+namespace Avalonia.Direct2D1
+{
+    class WindowsVersionChecker : IModuleEnvironmentChecker
+    {
+        //Direct2D backend doesn't work with Win7 anymore
+        public bool IsCompatible => Environment.OSVersion.Version >= new Version(6, 2);
+    }
+}

+ 2 - 0
src/Windows/Avalonia.Win32.NetStandard/Avalonia.Win32.NetStandard.csproj

@@ -75,6 +75,8 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="ComStreamWrapper.cs" />
+    <Compile Include="Gdip.cs" />
     <Compile Include="IconImpl.cs" />
     <Compile Include="NativeWin32Platform.cs" />
     <Compile Include="Win32Exception.cs" />

+ 197 - 0
src/Windows/Avalonia.Win32.NetStandard/ComStreamWrapper.cs

@@ -0,0 +1,197 @@
+//
+// System.Drawing.ComIStreamWrapper.cs
+//
+// Author:
+//   Kornél Pál <http://www.kornelpal.hu/>
+//
+// Copyright (C) 2005-2008 Kornél Pál
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
+
+namespace Avalonia.Win32
+{
+    // Stream to IStream wrapper for COM interop
+    internal sealed class ComIStreamWrapper : IStream
+    {
+        private const int STG_E_INVALIDFUNCTION = unchecked((int)0x80030001);
+
+        private readonly Stream baseStream;
+        private long position = -1;
+
+        internal ComIStreamWrapper(Stream stream)
+        {
+            baseStream = stream;
+        }
+
+        private void SetSizeToPosition()
+        {
+            if (position != -1)
+            {
+                if (position > baseStream.Length)
+                    baseStream.SetLength(position);
+                baseStream.Position = position;
+                position = -1;
+            }
+        }
+
+        public void Read(byte[] pv, int cb, IntPtr pcbRead)
+        {
+            int read = 0;
+
+            if (cb != 0)
+            {
+                SetSizeToPosition();
+                read = baseStream.Read(pv, 0, cb);
+            }
+
+            if (pcbRead != IntPtr.Zero)
+                Marshal.WriteInt32(pcbRead, read);
+        }
+
+        public void Write(byte[] pv, int cb, IntPtr pcbWritten)
+        {
+            if (cb != 0)
+            {
+                SetSizeToPosition();
+                baseStream.Write(pv, 0, cb);
+            }
+
+            if (pcbWritten != IntPtr.Zero)
+                Marshal.WriteInt32(pcbWritten, cb);
+        }
+
+        public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
+        {
+            long length = baseStream.Length;
+            long newPosition;
+
+            switch ((SeekOrigin)dwOrigin)
+            {
+                case SeekOrigin.Begin:
+                    newPosition = dlibMove;
+                    break;
+                case SeekOrigin.Current:
+                    if (position == -1)
+                        newPosition = baseStream.Position + dlibMove;
+                    else
+                        newPosition = position + dlibMove;
+                    break;
+                case SeekOrigin.End:
+                    newPosition = length + dlibMove;
+                    break;
+                default:
+                    throw new COMException(null, STG_E_INVALIDFUNCTION);
+            }
+
+            if (newPosition > length)
+                position = newPosition;
+            else
+            {
+                baseStream.Position = newPosition;
+                position = -1;
+            }
+
+            if (plibNewPosition != IntPtr.Zero)
+                Marshal.WriteInt64(plibNewPosition, newPosition);
+        }
+
+        public void SetSize(long libNewSize)
+        {
+            baseStream.SetLength(libNewSize);
+        }
+
+        public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
+        {
+            byte[] buffer;
+            long written = 0;
+            int read;
+            int count;
+
+            if (cb != 0)
+            {
+                if (cb < 4096)
+                    count = (int)cb;
+                else
+                    count = 4096;
+                buffer = new byte[count];
+                SetSizeToPosition();
+                while (true)
+                {
+                    if ((read = baseStream.Read(buffer, 0, count)) == 0)
+                        break;
+                    pstm.Write(buffer, read, IntPtr.Zero);
+                    written += read;
+                    if (written >= cb)
+                        break;
+                    if (cb - written < 4096)
+                        count = (int)(cb - written);
+                }
+            }
+
+            if (pcbRead != IntPtr.Zero)
+                Marshal.WriteInt64(pcbRead, written);
+            if (pcbWritten != IntPtr.Zero)
+                Marshal.WriteInt64(pcbWritten, written);
+        }
+
+        public void Commit(int grfCommitFlags)
+        {
+            baseStream.Flush();
+            SetSizeToPosition();
+        }
+
+        public void Revert()
+        {
+            throw new COMException(null, STG_E_INVALIDFUNCTION);
+        }
+
+        public void LockRegion(long libOffset, long cb, int dwLockType)
+        {
+            throw new COMException(null, STG_E_INVALIDFUNCTION);
+        }
+
+        public void UnlockRegion(long libOffset, long cb, int dwLockType)
+        {
+            throw new COMException(null, STG_E_INVALIDFUNCTION);
+        }
+
+        public void Stat(out STATSTG pstatstg, int grfStatFlag)
+        {
+            pstatstg = new STATSTG();
+            pstatstg.cbSize = baseStream.Length;
+        }
+
+        public void Clone(out IStream ppstm)
+        {
+            ppstm = null;
+            throw new COMException(null, STG_E_INVALIDFUNCTION);
+        }
+    }
+}

+ 128 - 0
src/Windows/Avalonia.Win32.NetStandard/Gdip.cs

@@ -0,0 +1,128 @@
+//
+// Code copy-pasted from from Mono / System.Drawing.*.cs
+// Original license below:
+//
+// Authors: 
+//  Alexandre Pigolkine ([email protected])
+//  Jordi Mas ([email protected])
+//	Sanjay Gupta ([email protected])
+//	Ravindra ([email protected])
+//	Peter Dennis Bartok ([email protected])
+//	Sebastien Pouliot  <[email protected]>
+//
+//
+// Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Win32
+{
+    static class Gdip
+    {
+        public enum Status
+        {
+            Ok = 0,
+            GenericError = 1,
+            InvalidParameter = 2,
+            OutOfMemory = 3,
+            ObjectBusy = 4,
+            InsufficientBuffer = 5,
+            NotImplemented = 6,
+            Win32Error = 7,
+            WrongState = 8,
+            Aborted = 9,
+            FileNotFound = 10,
+            ValueOverflow = 11,
+            AccessDenied = 12,
+            UnknownImageFormat = 13,
+            FontFamilyNotFound = 14,
+            FontStyleNotFound = 15,
+            NotTrueTypeFont = 16,
+            UnsupportedGdiplusVersion = 17,
+            GdiplusNotInitialized = 18,
+            PropertyNotFound = 19,
+            PropertyNotSupported = 20,
+            ProfileNotFound = 21
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        internal struct GdiplusStartupInput
+        {
+            // internalted to silent compiler
+            internal uint GdiplusVersion;
+            internal IntPtr DebugEventCallback;
+            internal int SuppressBackgroundThread;
+            internal int SuppressExternalCodecs;
+
+            internal static GdiplusStartupInput MakeGdiplusStartupInput()
+            {
+                GdiplusStartupInput result = new GdiplusStartupInput();
+                result.GdiplusVersion = 1;
+                result.DebugEventCallback = IntPtr.Zero;
+                result.SuppressBackgroundThread = 0;
+                result.SuppressExternalCodecs = 0;
+                return result;
+            }
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        internal struct GdiplusStartupOutput
+        {
+            internal IntPtr NotificationHook;
+            internal IntPtr NotificationUnhook;
+
+            internal static GdiplusStartupOutput MakeGdiplusStartupOutput()
+            {
+                GdiplusStartupOutput result = new GdiplusStartupOutput();
+                result.NotificationHook = result.NotificationUnhook = IntPtr.Zero;
+                return result;
+            }
+        }
+
+
+        [DllImport("gdiplus.dll")]
+        public static extern Status GdiplusStartup(ref ulong token, ref GdiplusStartupInput input, ref GdiplusStartupOutput output);
+
+        [DllImport("gdiplus.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
+        public static extern Status GdipLoadImageFromStream([MarshalAs(UnmanagedType.Interface, MarshalTypeRef = typeof(IStream))] IStream stream, out IntPtr image);
+        [DllImport("gdiplus.dll")]
+        public static extern Status GdipCreateHICONFromBitmap(IntPtr bmp, out IntPtr HandleIcon);
+
+        [DllImport("gdiplus.dll")]
+        internal static extern Status GdipDisposeImage(IntPtr image);
+
+        static Gdip()
+        {
+            ulong token = 0;
+            var input = GdiplusStartupInput.MakeGdiplusStartupInput();
+            var output = GdiplusStartupOutput.MakeGdiplusStartupOutput();
+            GdiplusStartup(ref token, ref input, ref output);
+        }
+    }
+}

+ 28 - 2
src/Windows/Avalonia.Win32.NetStandard/IconImpl.cs

@@ -2,6 +2,8 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
 using System.Text;
 using System.Threading.Tasks;
 using Avalonia.Platform;
@@ -10,10 +12,34 @@ namespace Avalonia.Win32
 {
     public class IconImpl : IWindowIconImpl
     {
-        public  IntPtr HIcon { get; set; }
+        private readonly MemoryStream _ms;
+
+        public IconImpl(Stream data)
+        {
+            _ms =  new MemoryStream();
+            data.CopyTo(_ms);
+            _ms.Seek(0, SeekOrigin.Begin);
+            IntPtr bitmap;
+            var status = Gdip.GdipLoadImageFromStream(new ComIStreamWrapper(_ms), out bitmap);
+            if (status != Gdip.Status.Ok)
+                throw new Exception("Unable to load icon, gdip status: " + (int) status);
+            IntPtr icon;
+            status = Gdip.GdipCreateHICONFromBitmap(bitmap, out icon);
+            if (status != Gdip.Status.Ok)
+                throw new Exception("Unable to create HICON, gdip status: " + (int)status);
+            Gdip.GdipDisposeImage(bitmap);
+            HIcon = icon;
+        }
+
+        public  IntPtr HIcon { get;}
         public void Save(Stream outputStream)
         {
-            throw new NotImplementedException();
+            lock (_ms)
+            {
+                _ms.Seek(0, SeekOrigin.Begin);
+                _ms.CopyTo(outputStream);
+            }
         }
+        
     }
 }

+ 13 - 3
src/Windows/Avalonia.Win32.NetStandard/NativeWin32Platform.cs

@@ -11,10 +11,20 @@ namespace Avalonia.Win32
     partial class Win32Platform
     {
         //TODO: An actual implementation
-        public IWindowIconImpl LoadIcon(string fileName) => new IconImpl();
+        public IWindowIconImpl LoadIcon(string fileName)
+        {
+            //No file IO for netstandard, still waiting for proper net core tooling
+            throw new NotSupportedException();
+        }
 
-        public IWindowIconImpl LoadIcon(Stream stream) => new IconImpl();
+        public IWindowIconImpl LoadIcon(Stream stream) => new IconImpl(stream);
 
-        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) => new IconImpl();
+        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
+        {
+            var ms = new MemoryStream();
+            bitmap.Save(ms);
+            ms.Seek(0, SeekOrigin.Begin);
+            return new IconImpl(ms);
+        }
     }
 }