Browse Source

Merge branch 'master' into issues/relsourcebindingproblem

pull/2114/head
Steven Kirk 8 years ago
committed by GitHub
parent
commit
e6536f7dcd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/Avalonia.Themes.Default/Accents/BaseDark.xaml
  2. 2
      src/Avalonia.Themes.Default/Accents/BaseLight.xaml
  3. 22
      src/Avalonia.Themes.Default/ScrollBar.xaml
  4. 41
      src/Avalonia.Themes.Default/TabControl.xaml
  5. 164
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  6. 8
      src/Shared/PlatformSupport/StandardRuntimePlatform.cs
  7. 7
      src/Windows/Avalonia.Win32/FramebufferManager.cs
  8. 3
      src/Windows/Avalonia.Win32/WindowImpl.cs
  9. 2
      tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs
  10. 4
      tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs

2
src/Avalonia.Themes.Default/Accents/BaseDark.xaml

@ -52,5 +52,7 @@
<sys:Double x:Key="FontSizeSmall">10</sys:Double>
<sys:Double x:Key="FontSizeNormal">12</sys:Double>
<sys:Double x:Key="FontSizeLarge">16</sys:Double>
<sys:Double x:Key="ScrollBarThickness">10</sys:Double>
</Style.Resources>
</Style>

2
src/Avalonia.Themes.Default/Accents/BaseLight.xaml

@ -52,5 +52,7 @@
<sys:Double x:Key="FontSizeSmall">10</sys:Double>
<sys:Double x:Key="FontSizeNormal">12</sys:Double>
<sys:Double x:Key="FontSizeLarge">16</sys:Double>
<sys:Double x:Key="ScrollBarThickness">10</sys:Double>
</Style.Resources>
</Style>

22
src/Avalonia.Themes.Default/ScrollBar.xaml

@ -3,7 +3,7 @@
<Setter Property="Template">
<ControlTemplate>
<Border Background="{DynamicResource ThemeControlMidBrush}">
<Grid RowDefinitions="10,*,10">
<Grid RowDefinitions="Auto,*,Auto">
<RepeatButton Name="PART_LineUpButton"
Classes="repeat"
Grid.Row="0"
@ -53,12 +53,11 @@
</Setter>
</Style>
<Style Selector="ScrollBar:horizontal">
<Setter Property="Height"
Value="10" />
<Setter Property="Height" Value="{DynamicResource ScrollBarThickness}" />
<Setter Property="Template">
<ControlTemplate>
<Border Background="{DynamicResource ThemeControlMidBrush}">
<Grid ColumnDefinitions="10,*,10">
<Grid ColumnDefinitions="Auto,*,Auto">
<RepeatButton Name="PART_LineUpButton"
Classes="repeat"
Grid.Row="0"
@ -108,22 +107,17 @@
</Setter>
</Style>
<Style Selector="ScrollBar:horizontal /template/ Thumb#thumb">
<Setter Property="MinWidth"
Value="10" />
<Setter Property="MinWidth" Value="{DynamicResource ScrollBarThickness}" />
</Style>
<Style Selector="ScrollBar:vertical">
<Setter Property="Width"
Value="10" />
<Setter Property="Width" Value="{DynamicResource ScrollBarThickness}" />
</Style>
<Style Selector="ScrollBar:vertical /template/ Thumb#thumb">
<Setter Property="MinHeight"
Value="10" />
<Setter Property="MinHeight" Value="{DynamicResource ScrollBarThickness}" />
</Style>
<Style Selector="ScrollBar /template/ RepeatButton.repeat">
<Setter Property="Padding"
Value="2" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="Padding" Value="2" />
<Setter Property="BorderThickness" Value="0" />
</Style>
<Style Selector="ScrollBar /template/ RepeatButton.repeattrack">
<Setter Property="Template">

41
src/Avalonia.Themes.Default/TabControl.xaml

@ -3,8 +3,6 @@
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
@ -16,28 +14,23 @@
Background="{TemplateBinding Background}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}">
<ScrollViewer
Name="PART_ScrollViewer"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<DockPanel>
<ItemsPresenter
Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
MemberSelector="{TemplateBinding MemberSelector}" >
</ItemsPresenter>
<ContentPresenter
Name="PART_Content"
Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding SelectedContent}"
ContentTemplate="{TemplateBinding SelectedContentTemplate}">
</ContentPresenter>
</DockPanel>
</ScrollViewer>
<DockPanel>
<ItemsPresenter
Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
MemberSelector="{TemplateBinding MemberSelector}" >
</ItemsPresenter>
<ContentPresenter
Name="PART_Content"
Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding SelectedContent}"
ContentTemplate="{TemplateBinding SelectedContentTemplate}">
</ContentPresenter>
</DockPanel>
</Border>
</ControlTemplate>
</Setter>

164
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -37,6 +37,7 @@ namespace Avalonia.Rendering
private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
private IRef<IDrawOperation> _currentDraw;
private readonly IDeferredRendererLock _lock;
private readonly object _sceneLock = new object();
/// <summary>
/// Initializes a new instance of the <see cref="DeferredRenderer"/> class.
@ -84,6 +85,7 @@ namespace Avalonia.Rendering
RenderTarget = renderTarget;
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
Layers = new RenderLayers();
_lock = new ManagedDeferredRendererLock();
}
/// <inheritdoc/>
@ -118,8 +120,13 @@ namespace Avalonia.Rendering
/// </summary>
public void Dispose()
{
var scene = Interlocked.Exchange(ref _scene, null);
scene?.Dispose();
lock (_sceneLock)
{
var scene = _scene;
_scene = null;
scene?.Dispose();
}
Stop();
Layers.Clear();
@ -134,7 +141,8 @@ namespace Avalonia.Rendering
// When unit testing the renderLoop may be null, so update the scene manually.
UpdateScene();
}
//It's safe to access _scene here without a lock since
//it's only changed from UI thread which we are currently on
return _scene?.Item.HitTest(p, root, filter) ?? Enumerable.Empty<IVisual>();
}
@ -172,7 +180,8 @@ namespace Avalonia.Rendering
}
}
bool IRenderLoopTask.NeedsUpdate => _dirty == null || _dirty.Count > 0;
bool NeedsUpdate => _dirty == null || _dirty.Count > 0;
bool IRenderLoopTask.NeedsUpdate => NeedsUpdate;
void IRenderLoopTask.Update(TimeSpan time) => UpdateScene();
@ -197,79 +206,105 @@ namespace Avalonia.Rendering
internal void UnitTestUpdateScene() => UpdateScene();
internal void UnitTestRender() => Render(_scene.Item, false);
internal void UnitTestRender() => Render(false);
private void Render(bool forceComposite)
{
using (var l = _lock.TryLock())
if (l != null)
using (var scene = _scene?.Clone())
{
Render(scene?.Item, forceComposite);
}
}
private void Render(Scene scene, bool forceComposite)
{
bool renderOverlay = DrawDirtyRects || DrawFps;
bool composite = false;
if (RenderTarget == null)
{
RenderTarget = ((IRenderRoot)_root).CreateRenderTarget();
}
if (l == null)
return;
if (renderOverlay)
{
_dirtyRectsDisplay.Tick();
}
try
{
if (scene != null && scene.Size != Size.Empty)
IDrawingContextImpl context = null;
try
{
IDrawingContextImpl context = null;
if (scene.Generation != _lastSceneId)
try
{
context = RenderTarget.CreateDrawingContext(this);
Layers.Update(scene, context);
IDrawingContextImpl GetContext()
{
if (context != null)
return context;
if (RenderTarget == null)
RenderTarget = ((IRenderRoot)_root).CreateRenderTarget();
return context = RenderTarget.CreateDrawingContext(this);
RenderToLayers(scene);
}
if (DebugFramesPath != null)
var (scene, updated) = UpdateRenderLayersAndConsumeSceneIfNeeded(GetContext);
using (scene)
{
SaveDebugFrames(scene.Generation);
var overlay = DrawDirtyRects || DrawFps;
if (DrawDirtyRects)
_dirtyRectsDisplay.Tick();
if (overlay)
RenderOverlay(scene.Item, GetContext());
if (updated || forceComposite || overlay)
RenderComposite(scene.Item, GetContext());
}
}
finally
{
context?.Dispose();
}
}
catch (RenderTargetCorruptedException ex)
{
Logging.Logger.Information("Renderer", this, "Render target was corrupted. Exception: {0}", ex);
RenderTarget?.Dispose();
RenderTarget = null;
}
}
}
_lastSceneId = scene.Generation;
private (IRef<Scene> scene, bool updated) UpdateRenderLayersAndConsumeSceneIfNeeded(Func<IDrawingContextImpl> contextFactory,
bool recursiveCall = false)
{
IRef<Scene> sceneRef;
lock (_sceneLock)
sceneRef = _scene?.Clone();
if (sceneRef == null)
return (null, false);
using (sceneRef)
{
var scene = sceneRef.Item;
if (scene.Generation != _lastSceneId)
{
var context = contextFactory();
Layers.Update(scene, context);
composite = true;
}
RenderToLayers(scene);
if (renderOverlay)
if (DebugFramesPath != null)
{
context = context ?? RenderTarget.CreateDrawingContext(this);
RenderOverlay(scene, context);
RenderComposite(scene, context);
SaveDebugFrames(scene.Generation);
}
else if (composite || forceComposite)
lock (_sceneLock)
_lastSceneId = scene.Generation;
// We have consumed the previously available scene, but there might be some dirty
// rects since the last update. *If* we are on UI thread, we can force immediate scene
// rebuild before rendering anything on-screen
// We are calling the same method recursively here
if (!recursiveCall && Dispatcher.UIThread.CheckAccess() && NeedsUpdate)
{
context = context ?? RenderTarget.CreateDrawingContext(this);
RenderComposite(scene, context);
UpdateScene();
var (rs, _) = UpdateRenderLayersAndConsumeSceneIfNeeded(contextFactory, true);
return (rs, true);
}
context?.Dispose();
// Indicate that we have updated the layers
return (sceneRef.Clone(), true);
}
// Just return scene, layers weren't updated
return (sceneRef.Clone(), false);
}
catch (RenderTargetCorruptedException ex)
{
Logging.Logger.Information("Renderer", this, "Render target was corrupted. Exception: {0}", ex);
RenderTarget?.Dispose();
RenderTarget = null;
}
}
private void Render(IDrawingContextImpl context, VisualNode node, IVisual layer, Rect clipBounds)
{
if (layer == null || node.LayerRoot == layer)
@ -405,6 +440,11 @@ namespace Avalonia.Rendering
private void UpdateScene()
{
Dispatcher.UIThread.VerifyAccess();
lock (_sceneLock)
{
if (_scene?.Item.Generation > _lastSceneId)
return;
}
if (_root.IsVisible)
{
var sceneRef = RefCountable.Create(_scene?.Item.CloneScene() ?? new Scene(_root));
@ -423,15 +463,23 @@ namespace Avalonia.Rendering
}
}
var oldScene = Interlocked.Exchange(ref _scene, sceneRef);
oldScene?.Dispose();
lock (_sceneLock)
{
var oldScene = _scene;
_scene = sceneRef;
oldScene?.Dispose();
}
_dirty.Clear();
}
else
{
var oldScene = Interlocked.Exchange(ref _scene, null);
oldScene?.Dispose();
lock (_sceneLock)
{
var oldScene = _scene;
_scene = null;
oldScene?.Dispose();
}
}
}

8
src/Shared/PlatformSupport/StandardRuntimePlatform.cs

@ -89,9 +89,11 @@ namespace Avalonia.Shared.PlatformSupport
#if DEBUG
if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId)
{
Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
+ Environment.StackTrace
+ "\n\nBlob created by " + _backtrace);
lock(_lock)
if (!IsDisposed)
Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
+ Environment.StackTrace
+ "\n\nBlob created by " + _backtrace);
}
#endif
DoDispose();

7
src/Windows/Avalonia.Win32/FramebufferManager.cs

@ -5,7 +5,7 @@ using Avalonia.Win32.Interop;
namespace Avalonia.Win32
{
class FramebufferManager : IFramebufferPlatformSurface, IDisposable
class FramebufferManager : IFramebufferPlatformSurface
{
private readonly IntPtr _hwnd;
private WindowFramebuffer _fb;
@ -29,10 +29,5 @@ namespace Avalonia.Win32
}
return _fb;
}
public void Dispose()
{
_fb?.Deallocate();
}
}
}

3
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -13,6 +13,7 @@ using Avalonia.Input.Raw;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
@ -234,8 +235,6 @@ namespace Avalonia.Win32
public void Dispose()
{
_framebuffer?.Dispose();
_framebuffer = null;
if (_hwnd != IntPtr.Zero)
{
UnmanagedMethods.DestroyWindow(_hwnd);

2
tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

@ -99,6 +99,8 @@ namespace Avalonia.Layout.UnitTests
}
};
window.Resources["ScrollBarThickness"] = 10.0;
window.Show();
window.LayoutManager.ExecuteInitialLayoutPass(window);

4
tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs

@ -405,7 +405,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Renderer = new DeferredRenderer(root, null);
root.Measure(Size.Infinity);
root.Arrange(new Rect(container.DesiredSize));
root.Renderer.Paint(Rect.Empty);
var result = root.Renderer.HitTest(new Point(50, 150), root, null).First();
Assert.Equal(item1, result);
@ -421,6 +422,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
container.InvalidateArrange();
container.Arrange(new Rect(container.DesiredSize));
root.Renderer.Paint(Rect.Empty);
result = root.Renderer.HitTest(new Point(50, 150), root, null).First();
Assert.Equal(item2, result);

Loading…
Cancel
Save