Browse Source

Fixed TextBlock text wrapping.

And added render test (so far only to D2D backend)
pull/543/head
Steven Kirk 11 years ago
parent
commit
ec35cdde79
  1. 1
      src/Avalonia.Controls/Avalonia.Controls.csproj
  2. 4
      src/Avalonia.Controls/TextBlock.cs
  3. 3
      src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj
  4. 57
      src/Avalonia.SceneGraph/Media/FormattedText.cs
  5. 4
      src/Avalonia.SceneGraph/Media/TextWrapping.cs
  6. 4
      src/Avalonia.SceneGraph/Platform/IPlatformRenderInterface.cs
  7. 3
      src/Avalonia.SceneGraph/Rendering/RendererMixin.cs
  8. 3
      src/Gtk/Avalonia.Cairo/CairoPlatform.cs
  9. 2
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  10. 5
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  11. 6
      src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs
  12. 3
      tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.csproj
  13. 47
      tests/Avalonia.RenderTests/Controls/TextBlockTests.cs
  14. 5
      tests/Avalonia.RenderTests/TestBase.cs
  15. 3
      tests/Avalonia.UnitTests/TestServices.cs
  16. BIN
      tests/TestFiles/Direct2D1/Controls/TextBlock/Wrapping_NoWrap.expected.png

1
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -164,7 +164,6 @@
<Compile Include="ToolTip.cs" /> <Compile Include="ToolTip.cs" />
<Compile Include="UserControl.cs" /> <Compile Include="UserControl.cs" />
<Compile Include="Templates\TemplateExtensions.cs" /> <Compile Include="Templates\TemplateExtensions.cs" />
<Compile Include="TextWrapping.cs" />
<Compile Include="Utils\AncestorFinder.cs" /> <Compile Include="Utils\AncestorFinder.cs" />
<Compile Include="Utils\IEnumerableUtils.cs" /> <Compile Include="Utils\IEnumerableUtils.cs" />
<Compile Include="Utils\StringUtils.cs" /> <Compile Include="Utils\StringUtils.cs" />

4
src/Avalonia.Controls/TextBlock.cs

@ -99,6 +99,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
static TextBlock() static TextBlock()
{ {
ClipToBoundsProperty.OverrideDefaultValue<TextBlock>(true);
AffectsRender(ForegroundProperty); AffectsRender(ForegroundProperty);
AffectsRender(FontWeightProperty); AffectsRender(FontWeightProperty);
AffectsRender(FontSizeProperty); AffectsRender(FontSizeProperty);
@ -355,7 +356,8 @@ namespace Avalonia.Controls
FontSize, FontSize,
FontStyle, FontStyle,
TextAlignment, TextAlignment,
FontWeight); FontWeight,
TextWrapping);
result.Constraint = constraint; result.Constraint = constraint;
return result; return result;
} }

3
src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
@ -68,6 +68,7 @@
<Compile Include="Media\BrushMappingMode.cs" /> <Compile Include="Media\BrushMappingMode.cs" />
<Compile Include="Media\Color.cs" /> <Compile Include="Media\Color.cs" />
<Compile Include="Media\Colors.cs" /> <Compile Include="Media\Colors.cs" />
<Compile Include="Media\TextWrapping.cs" />
<Compile Include="Media\TransformGroup.cs" /> <Compile Include="Media\TransformGroup.cs" />
<Compile Include="Media\DashStyle.cs" /> <Compile Include="Media\DashStyle.cs" />
<Compile Include="Media\DrawingContext.cs" /> <Compile Include="Media\DrawingContext.cs" />

57
src/Avalonia.SceneGraph/Media/FormattedText.cs

@ -21,13 +21,15 @@ namespace Avalonia.Media
/// <param name="fontStyle">The font style.</param> /// <param name="fontStyle">The font style.</param>
/// <param name="textAlignment">The text alignment.</param> /// <param name="textAlignment">The text alignment.</param>
/// <param name="fontWeight">The font weight.</param> /// <param name="fontWeight">The font weight.</param>
/// <param name="wrapping">The text wrapping mode.</param>
public FormattedText( public FormattedText(
string text, string text,
string fontFamilyName, string fontFamilyName,
double fontSize, double fontSize,
FontStyle fontStyle, FontStyle fontStyle = FontStyle.Normal,
TextAlignment textAlignment, TextAlignment textAlignment = TextAlignment.Left,
FontWeight fontWeight) FontWeight fontWeight = FontWeight.Normal,
TextWrapping wrapping = TextWrapping.Wrap)
{ {
Contract.Requires<ArgumentNullException>(text != null); Contract.Requires<ArgumentNullException>(text != null);
Contract.Requires<ArgumentNullException>(fontFamilyName != null); Contract.Requires<ArgumentNullException>(fontFamilyName != null);
@ -39,6 +41,7 @@ namespace Avalonia.Media
FontStyle = fontStyle; FontStyle = fontStyle;
FontWeight = fontWeight; FontWeight = fontWeight;
TextAlignment = textAlignment; TextAlignment = textAlignment;
Wrapping = wrapping;
var platform = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>(); var platform = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
@ -53,7 +56,8 @@ namespace Avalonia.Media
fontSize, fontSize,
fontStyle, fontStyle,
textAlignment, textAlignment,
fontWeight); fontWeight,
wrapping);
} }
/// <summary> /// <summary>
@ -76,63 +80,42 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Gets the font family. /// Gets the font family.
/// </summary> /// </summary>
public string FontFamilyName public string FontFamilyName { get; }
{
get;
private set;
}
/// <summary> /// <summary>
/// Gets the font size. /// Gets the font size.
/// </summary> /// </summary>
public double FontSize public double FontSize { get; }
{
get;
private set;
}
/// <summary> /// <summary>
/// Gets the font style. /// Gets the font style.
/// </summary> /// </summary>
public FontStyle FontStyle public FontStyle FontStyle { get; }
{
get;
private set;
}
/// <summary> /// <summary>
/// Gets the font weight. /// Gets the font weight.
/// </summary> /// </summary>
public FontWeight FontWeight public FontWeight FontWeight { get; }
{
get;
private set;
}
/// <summary> /// <summary>
/// Gets the text. /// Gets the text.
/// </summary> /// </summary>
public string Text public string Text { get; }
{
get;
private set;
}
/// <summary> /// <summary>
/// Gets platform-specific platform implementation. /// Gets platform-specific platform implementation.
/// </summary> /// </summary>
public IFormattedTextImpl PlatformImpl public IFormattedTextImpl PlatformImpl { get; }
{
get; }
/// <summary> /// <summary>
/// Gets the text alignment. /// Gets the text alignment.
/// </summary> /// </summary>
public TextAlignment TextAlignment public TextAlignment TextAlignment { get; }
{
get; /// <summary>
private set; /// Gets the text wrapping.
} /// </summary>
public TextWrapping Wrapping { get; }
/// <summary> /// <summary>
/// Disposes of unmanaged resources associated with the formatted text. /// Disposes of unmanaged resources associated with the formatted text.

4
src/Avalonia.Controls/TextWrapping.cs → src/Avalonia.SceneGraph/Media/TextWrapping.cs

@ -1,10 +1,10 @@
// Copyright (c) The Avalonia Project. All rights reserved. // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Controls namespace Avalonia.Media
{ {
/// <summary> /// <summary>
/// Controls the wrapping mode in a <see cref="TextBlock"/>. /// Controls the wrapping mode of text.
/// </summary> /// </summary>
public enum TextWrapping public enum TextWrapping
{ {

4
src/Avalonia.SceneGraph/Platform/IPlatformRenderInterface.cs

@ -20,6 +20,7 @@ namespace Avalonia.Platform
/// <param name="fontStyle">The font style.</param> /// <param name="fontStyle">The font style.</param>
/// <param name="textAlignment">The text alignment.</param> /// <param name="textAlignment">The text alignment.</param>
/// <param name="fontWeight">The font weight.</param> /// <param name="fontWeight">The font weight.</param>
/// <param name="wrapping">The text wrapping mode.</param>
/// <returns>An <see cref="IFormattedTextImpl"/>.</returns> /// <returns>An <see cref="IFormattedTextImpl"/>.</returns>
IFormattedTextImpl CreateFormattedText( IFormattedTextImpl CreateFormattedText(
string text, string text,
@ -27,7 +28,8 @@ namespace Avalonia.Platform
double fontSize, double fontSize,
FontStyle fontStyle, FontStyle fontStyle,
TextAlignment textAlignment, TextAlignment textAlignment,
FontWeight fontWeight); FontWeight fontWeight,
TextWrapping wrapping);
/// <summary> /// <summary>
/// Creates a stream geometry implementation. /// Creates a stream geometry implementation.

3
src/Avalonia.SceneGraph/Rendering/RendererMixin.cs

@ -62,7 +62,8 @@ namespace Avalonia.Rendering
var txt = new FormattedText("Frame #" + s_frameNum + " FPS: " + s_fps, "Arial", 18, var txt = new FormattedText("Frame #" + s_frameNum + " FPS: " + s_fps, "Arial", 18,
FontStyle.Normal, FontStyle.Normal,
TextAlignment.Left, TextAlignment.Left,
FontWeight.Normal)) FontWeight.Normal,
TextWrapping.NoWrap))
{ {
ctx.FillRectangle(Brushes.White, new Rect(pt, txt.Measure())); ctx.FillRectangle(Brushes.White, new Rect(pt, txt.Measure()));
ctx.DrawText(Brushes.Black, pt, txt); ctx.DrawText(Brushes.Black, pt, txt);

3
src/Gtk/Avalonia.Cairo/CairoPlatform.cs

@ -44,7 +44,8 @@ namespace Avalonia.Cairo
double fontSize, double fontSize,
FontStyle fontStyle, FontStyle fontStyle,
TextAlignment textAlignment, TextAlignment textAlignment,
Avalonia.Media.FontWeight fontWeight) Avalonia.Media.FontWeight fontWeight,
TextWrapping wrapping)
{ {
return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight); return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight);
} }

2
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -18,7 +18,7 @@ namespace Avalonia.Skia
} }
public IFormattedTextImpl CreateFormattedText(string text, string fontFamilyName, double fontSize, FontStyle fontStyle, public IFormattedTextImpl CreateFormattedText(string text, string fontFamilyName, double fontSize, FontStyle fontStyle,
TextAlignment textAlignment, FontWeight fontWeight) TextAlignment textAlignment, FontWeight fontWeight, TextWrapping wrapping)
{ {
return FormattedTextImpl.Create(text, fontFamilyName, fontSize, fontStyle, textAlignment, fontWeight); return FormattedTextImpl.Create(text, fontFamilyName, fontSize, fontStyle, textAlignment, fontWeight);
} }

5
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@ -49,9 +49,10 @@ namespace Avalonia.Direct2D1
double fontSize, double fontSize,
FontStyle fontStyle, FontStyle fontStyle,
TextAlignment textAlignment, TextAlignment textAlignment,
FontWeight fontWeight) FontWeight fontWeight,
TextWrapping wrapping)
{ {
return new FormattedTextImpl(text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight); return new FormattedTextImpl(text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight, wrapping);
} }
public IRenderTarget CreateRenderer(IPlatformHandle handle) public IRenderTarget CreateRenderer(IPlatformHandle handle)

6
src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs

@ -18,7 +18,8 @@ namespace Avalonia.Direct2D1.Media
double fontSize, double fontSize,
FontStyle fontStyle, FontStyle fontStyle,
TextAlignment textAlignment, TextAlignment textAlignment,
FontWeight fontWeight) FontWeight fontWeight,
TextWrapping wrapping)
{ {
var factory = AvaloniaLocator.Current.GetService<DWrite.Factory>(); var factory = AvaloniaLocator.Current.GetService<DWrite.Factory>();
@ -29,6 +30,9 @@ namespace Avalonia.Direct2D1.Media
(DWrite.FontStyle)fontStyle, (DWrite.FontStyle)fontStyle,
(float)fontSize)) (float)fontSize))
{ {
format.WordWrapping = wrapping == TextWrapping.Wrap ?
DWrite.WordWrapping.Wrap : DWrite.WordWrapping.NoWrap;
TextLayout = new DWrite.TextLayout( TextLayout = new DWrite.TextLayout(
factory, factory,
text ?? string.Empty, text ?? string.Empty,

3
tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.csproj

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -73,6 +73,7 @@
<Otherwise /> <Otherwise />
</Choose> </Choose>
<ItemGroup> <ItemGroup>
<Compile Include="Controls\TextBlockTests.cs" />
<Compile Include="Media\ImageBrushTests.cs" /> <Compile Include="Media\ImageBrushTests.cs" />
<Compile Include="Media\VisualBrushTests.cs" /> <Compile Include="Media\VisualBrushTests.cs" />
<Compile Include="Controls\ImageTests.cs" /> <Compile Include="Controls\ImageTests.cs" />

47
tests/Avalonia.RenderTests/Controls/TextBlockTests.cs

@ -0,0 +1,47 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Media;
using Xunit;
#if AVALONIA_CAIRO
namespace Avalonia.Cairo.RenderTests.Controls
#elif AVALONIA_SKIA
namespace Avalonia.Skia.RenderTests
#else
namespace Avalonia.Direct2D1.RenderTests.Controls
#endif
{
public class TextBlockTests : TestBase
{
public TextBlockTests()
: base(@"Controls\TextBlock")
{
}
[Fact]
public void Wrapping_NoWrap()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Child = new TextBlock
{
Background = Brushes.Red,
FontSize = 12,
Foreground = Brushes.Black,
Text = "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit",
VerticalAlignment = VerticalAlignment.Top,
TextWrapping = TextWrapping.NoWrap,
}
};
RenderToFile(target);
CompareImages();
}
}
}

5
tests/Avalonia.RenderTests/TestBase.cs

@ -58,6 +58,11 @@ namespace Avalonia.Direct2D1.RenderTests
protected void RenderToFile(Control target, [CallerMemberName] string testName = "") protected void RenderToFile(Control target, [CallerMemberName] string testName = "")
{ {
if (!Directory.Exists(OutputPath))
{
Directory.CreateDirectory(OutputPath);
}
string path = Path.Combine(OutputPath, testName + ".out.png"); string path = Path.Combine(OutputPath, testName + ".out.png");
using (RenderTargetBitmap bitmap = new RenderTargetBitmap( using (RenderTargetBitmap bitmap = new RenderTargetBitmap(

3
tests/Avalonia.UnitTests/TestServices.cs

@ -143,7 +143,8 @@ namespace Avalonia.UnitTests
It.IsAny<double>(), It.IsAny<double>(),
It.IsAny<FontStyle>(), It.IsAny<FontStyle>(),
It.IsAny<TextAlignment>(), It.IsAny<TextAlignment>(),
It.IsAny<FontWeight>()) == Mock.Of<IFormattedTextImpl>() && It.IsAny<FontWeight>(),
It.IsAny<TextWrapping>()) == Mock.Of<IFormattedTextImpl>() &&
x.CreateStreamGeometry() == Mock.Of<IStreamGeometryImpl>( x.CreateStreamGeometry() == Mock.Of<IStreamGeometryImpl>(
y => y.Open() == Mock.Of<IStreamGeometryContextImpl>())); y => y.Open() == Mock.Of<IStreamGeometryContextImpl>()));
} }

BIN
tests/TestFiles/Direct2D1/Controls/TextBlock/Wrapping_NoWrap.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Loading…
Cancel
Save