diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index 59f0d551b0..43088eb0ea 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -212,7 +212,10 @@ namespace Avalonia.Controls.Presenters
if (length > 0)
{
- result.SetForegroundBrush(Brushes.White, start, length);
+ result.Spans = new[]
+ {
+ new FormattedTextStyleSpan(start, length, foregroundBrush: Brushes.White),
+ };
}
return result;
@@ -228,15 +231,13 @@ namespace Avalonia.Controls.Presenters
}
else
{
- // TODO: Pretty sure that measuring "X" isn't the right way to do this...
- return new FormattedText(
- "X",
- FontFamily,
- FontSize,
- availableSize,
- FontStyle,
- TextAlignment,
- FontWeight).Measure();
+ return new FormattedText
+ {
+ Text = "X",
+ Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
+ TextAlignment = TextAlignment,
+ Constraint = availableSize,
+ }.Measure();
}
}
diff --git a/src/Avalonia.Controls/Primitives/AccessText.cs b/src/Avalonia.Controls/Primitives/AccessText.cs
index 29032ae430..4bb80e6d3f 100644
--- a/src/Avalonia.Controls/Primitives/AccessText.cs
+++ b/src/Avalonia.Controls/Primitives/AccessText.cs
@@ -85,16 +85,14 @@ namespace Avalonia.Controls.Primitives
/// A object.
protected override FormattedText CreateFormattedText(Size constraint)
{
- var result = new FormattedText(
- StripAccessKey(Text),
- FontFamily,
- FontSize,
- constraint,
- FontStyle,
- TextAlignment,
- FontWeight);
- result.Constraint = constraint;
- return result;
+ return new FormattedText
+ {
+ Constraint = constraint,
+ Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
+ Text = StripAccessKey(Text),
+ TextAlignment = TextAlignment,
+ Wrapping = TextWrapping,
+ };
}
///
diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs
index 1c8ed01e47..9d71dcfe73 100644
--- a/src/Avalonia.Controls/TextBlock.cs
+++ b/src/Avalonia.Controls/TextBlock.cs
@@ -350,17 +350,14 @@ namespace Avalonia.Controls
/// A object.
protected virtual FormattedText CreateFormattedText(Size constraint)
{
- var result = new FormattedText(
- Text ?? string.Empty,
- FontFamily,
- FontSize,
- constraint,
- FontStyle,
- TextAlignment,
- FontWeight,
- TextWrapping);
- result.Constraint = constraint;
- return result;
+ return new FormattedText
+ {
+ Constraint = constraint,
+ Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
+ Text = Text ?? string.Empty,
+ TextAlignment = TextAlignment,
+ Wrapping = TextWrapping,
+ };
}
///
diff --git a/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs
index 72dd1d603c..93f8790741 100644
--- a/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs
+++ b/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs
@@ -117,7 +117,11 @@ namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters
FormattedText GetText(string str, RFont font)
{
var f = ((FontAdapter)font);
- return new FormattedText(str, f.Name, font.Size, Size.Infinity, f.FontStyle, TextAlignment.Left, f.Weight);
+ return new FormattedText
+ {
+ Text = str,
+ Typeface = new Typeface(f.Name, font.Size, f.FontStyle, f.Weight),
+ };
}
public override void MeasureString(string str, RFont font, double maxWidth, out int charFit, out double charFitWidth)
diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj
index c820a83c2a..dd9a795937 100644
--- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj
+++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj
@@ -2,6 +2,7 @@
netstandard1.1
false
+ Avalonia
true
diff --git a/src/Avalonia.Visuals/Media/FormattedText.cs b/src/Avalonia.Visuals/Media/FormattedText.cs
index 1308091b2f..9a052f4eb9 100644
--- a/src/Avalonia.Visuals/Media/FormattedText.cs
+++ b/src/Avalonia.Visuals/Media/FormattedText.cs
@@ -12,64 +12,30 @@ namespace Avalonia.Media
///
public class FormattedText
{
+ private readonly IPlatformRenderInterface _platform;
+ private Size _constraint = Size.Infinity;
+ private IFormattedTextImpl _platformImpl;
+ private IReadOnlyList _spans;
+ private Typeface _typeface;
+ private string _text;
+ private TextAlignment _textAlignment;
+ private TextWrapping _wrapping;
+
///
/// Initializes a new instance of the class.
///
- /// The text.
- /// The font family.
- /// The font size.
- /// The text layout constraints.
- /// The font style.
- /// The text alignment.
- /// The font weight.
- /// The text wrapping mode.
- public FormattedText(
- string text,
- string fontFamilyName,
- double fontSize,
- Size constraint,
- FontStyle fontStyle = FontStyle.Normal,
- TextAlignment textAlignment = TextAlignment.Left,
- FontWeight fontWeight = FontWeight.Normal,
- TextWrapping wrapping = TextWrapping.Wrap)
+ public FormattedText()
{
- Contract.Requires(text != null);
- Contract.Requires(fontFamilyName != null);
-
- if (fontSize <= 0)
- {
- throw new ArgumentException("FontSize must be greater than 0");
- }
-
- if (fontWeight <= 0)
- {
- throw new ArgumentException("FontWeight must be greater than 0");
- }
-
- Text = text;
- FontFamilyName = fontFamilyName;
- FontSize = fontSize;
- FontStyle = fontStyle;
- FontWeight = fontWeight;
- TextAlignment = textAlignment;
- Wrapping = wrapping;
-
- var platform = AvaloniaLocator.Current.GetService();
-
- if (platform == null)
- {
- throw new Exception("Could not create FormattedText: IPlatformRenderInterface not registered.");
- }
+ _platform = AvaloniaLocator.Current.GetService();
+ }
- PlatformImpl = platform.CreateFormattedText(
- text,
- fontFamilyName,
- fontSize,
- fontStyle,
- textAlignment,
- fontWeight,
- wrapping,
- constraint);
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The platform render interface.
+ public FormattedText(IPlatformRenderInterface platform)
+ {
+ _platform = platform;
}
///
@@ -77,49 +43,77 @@ namespace Avalonia.Media
///
public Size Constraint
{
- get { return PlatformImpl.Constraint; }
- set { PlatformImpl = PlatformImpl.WithConstraint(value); }
+ get => _constraint;
+ set => Set(ref _constraint, value);
}
///
- /// Gets the font family.
+ /// Gets or sets the base typeface.
///
- public string FontFamilyName { get; }
+ public Typeface Typeface
+ {
+ get => _typeface;
+ set => Set(ref _typeface, value);
+ }
///
- /// Gets the font size.
+ /// Gets or sets a collection of spans that describe the formatting of subsections of the
+ /// text.
///
- public double FontSize { get; }
+ public IReadOnlyList Spans
+ {
+ get => _spans;
+ set => Set(ref _spans, value);
+ }
///
- /// Gets the font style.
+ /// Gets or sets the text.
///
- public FontStyle FontStyle { get; }
+ public string Text
+ {
+ get => _text;
+ set => Set(ref _text, value);
+ }
///
- /// Gets the font weight.
+ /// Gets or sets the aligment of the text.
///
- public FontWeight FontWeight { get; }
+ public TextAlignment TextAlignment
+ {
+ get => _textAlignment;
+ set => Set(ref _textAlignment, value);
+ }
///
- /// Gets the text.
+ /// Gets or sets the text wrapping.
///
- public string Text { get; }
+ public TextWrapping Wrapping
+ {
+ get => _wrapping;
+ set => Set(ref _wrapping, value);
+ }
///
/// Gets platform-specific platform implementation.
///
- public IFormattedTextImpl PlatformImpl { get; private set; }
-
- ///
- /// Gets the text alignment.
- ///
- public TextAlignment TextAlignment { get; }
-
- ///
- /// Gets the text wrapping.
- ///
- public TextWrapping Wrapping { get; }
+ public IFormattedTextImpl PlatformImpl
+ {
+ get
+ {
+ if (_platformImpl == null)
+ {
+ _platformImpl = _platform.CreateFormattedText(
+ _text,
+ _typeface,
+ _textAlignment,
+ _wrapping,
+ _constraint,
+ _spans);
+ }
+
+ return _platformImpl;
+ }
+ }
///
/// Gets the lines in the text.
@@ -174,15 +168,10 @@ namespace Avalonia.Media
return PlatformImpl.Size;
}
- ///
- /// Sets the foreground brush for the specified text range.
- ///
- /// The brush.
- /// The start of the text range.
- /// The length of the text range.
- public void SetForegroundBrush(IBrush brush, int startIndex, int length)
+ private void Set(ref T field, T value)
{
- PlatformImpl.SetForegroundBrush(brush, startIndex, length);
+ field = value;
+ _platformImpl = null;
}
}
}
diff --git a/src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs b/src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs
new file mode 100644
index 0000000000..75bf76c996
--- /dev/null
+++ b/src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Avalonia.Media
+{
+ public class FormattedTextStyleSpan
+ {
+ public FormattedTextStyleSpan(
+ int startIndex,
+ int length,
+ IBrush foregroundBrush = null)
+ {
+ StartIndex = startIndex;
+ Length = length;
+ ForegroundBrush = foregroundBrush;
+ }
+
+ public int StartIndex { get; }
+ public int Length { get; }
+ public IBrush ForegroundBrush { get; }
+ }
+}
diff --git a/src/Avalonia.Visuals/Media/Typeface.cs b/src/Avalonia.Visuals/Media/Typeface.cs
new file mode 100644
index 0000000000..b05d5d02e5
--- /dev/null
+++ b/src/Avalonia.Visuals/Media/Typeface.cs
@@ -0,0 +1,35 @@
+using System;
+using Avalonia.Media;
+
+namespace Avalonia.Media
+{
+ public class Typeface
+ {
+ public Typeface(
+ string fontFamilyName,
+ double fontSize,
+ FontStyle style = FontStyle.Normal,
+ FontWeight weight = FontWeight.Normal)
+ {
+ if (fontSize <= 0)
+ {
+ throw new ArgumentException("Font size must be > 0.");
+ }
+
+ if (weight <= 0)
+ {
+ throw new ArgumentException("Font weight must be > 0.");
+ }
+
+ FontFamilyName = fontFamilyName;
+ FontSize = fontSize;
+ Style = style;
+ Weight = weight;
+ }
+
+ public string FontFamilyName { get; }
+ public double FontSize { get; }
+ public FontStyle Style { get; }
+ public FontWeight Weight { get; }
+ }
+}
diff --git a/src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs b/src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs
index 9ffa3d6228..606da02c49 100644
--- a/src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs
+++ b/src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs
@@ -58,20 +58,5 @@ namespace Avalonia.Platform
/// The number of characters in the text range.
/// The character bounds.
IEnumerable HitTestTextRange(int index, int length);
-
- ///
- /// Sets the foreground brush for the specified text range.
- ///
- /// The brush.
- /// The start of the text range.
- /// The length of the text range.
- void SetForegroundBrush(IBrush brush, int startIndex, int length);
-
- ///
- /// Makes a clone of the formatted text with the specified constraint.
- ///
- /// The constraint.
- /// The cloned formatted text.
- IFormattedTextImpl WithConstraint(Size constraint);
}
}
diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
index 075d795a4c..aab8521f6d 100644
--- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
+++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
@@ -17,23 +17,19 @@ namespace Avalonia.Platform
/// Creates a formatted text implementation.
///
/// The text.
- /// The font family.
- /// The font size.
- /// The font style.
+ /// The base typeface.
/// The text alignment.
- /// The font weight.
/// The text wrapping mode.
/// The text layout constraints.
+ /// The style spans.
/// An .
IFormattedTextImpl CreateFormattedText(
string text,
- string fontFamilyName,
- double fontSize,
- FontStyle fontStyle,
+ Typeface typeface,
TextAlignment textAlignment,
- FontWeight fontWeight,
TextWrapping wrapping,
- Size constraint);
+ Size constraint,
+ IReadOnlyList spans);
///
/// Creates a stream geometry implementation.
diff --git a/src/Avalonia.Visuals/Rendering/RendererBase.cs b/src/Avalonia.Visuals/Rendering/RendererBase.cs
index ae15eff7fc..707b31998a 100644
--- a/src/Avalonia.Visuals/Rendering/RendererBase.cs
+++ b/src/Avalonia.Visuals/Rendering/RendererBase.cs
@@ -7,11 +7,21 @@ namespace Avalonia.Rendering
{
public class RendererBase
{
+ private static readonly Typeface s_fpsTypeface = new Typeface("Arial", 18);
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
private int _framesThisSecond;
private int _fps;
+ private FormattedText _fpsText;
private TimeSpan _lastFpsUpdate;
+ public RendererBase()
+ {
+ _fpsText = new FormattedText
+ {
+ Typeface = new Typeface(null, 18),
+ };
+ }
+
protected void RenderFps(IDrawingContextImpl context, Rect clientRect, bool incrementFrameCount)
{
var now = _stopwatch.Elapsed;
@@ -29,20 +39,13 @@ namespace Avalonia.Rendering
_lastFpsUpdate = now;
}
- var txt = new FormattedText(
- string.Format("FPS: {0:000}", _fps),
- "Arial", 18,
- Size.Infinity,
- FontStyle.Normal,
- TextAlignment.Left,
- FontWeight.Normal,
- TextWrapping.NoWrap);
- var size = txt.Measure();
+ _fpsText.Text = string.Format("FPS: {0:000}", _fps);
+ var size = _fpsText.Measure();
var rect = new Rect(clientRect.Right - size.Width, 0, size.Width, size.Height);
context.Transform = Matrix.Identity;
context.FillRectangle(Brushes.Black, rect);
- context.DrawText(Brushes.White, rect.TopLeft, txt.PlatformImpl);
+ context.DrawText(Brushes.White, rect.TopLeft, _fpsText.PlatformImpl);
}
}
}
diff --git a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs
index b28535f02c..934cf593b1 100644
--- a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs
+++ b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs
@@ -47,15 +47,20 @@ namespace Avalonia.Cairo
public IFormattedTextImpl CreateFormattedText(
string text,
- string fontFamily,
- double fontSize,
- FontStyle fontStyle,
+ Typeface typeface,
TextAlignment textAlignment,
- Avalonia.Media.FontWeight fontWeight,
TextWrapping wrapping,
- Size constraint)
+ Size constraint,
+ IReadOnlyList spans)
{
- return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight, constraint);
+ return new FormattedTextImpl(
+ s_pangoContext,
+ text,
+ typeface,
+ textAlignment,
+ wrapping,
+ constraint,
+ spans);
}
public IRenderTarget CreateRenderTarget(IEnumerable