@ -2,8 +2,8 @@
// 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.
using System ;
using System ;
using System.Collections.Concurrent ;
using System.Collections.Generic ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Linq ;
using Avalonia.Media ;
using Avalonia.Media ;
using Avalonia.Platform ;
using Avalonia.Platform ;
@ -26,59 +26,46 @@ namespace Avalonia.Direct2D1.Media
var factory = AvaloniaLocator . Current . GetService < DWrite . Factory > ( ) ;
var factory = AvaloniaLocator . Current . GetService < DWrite . Factory > ( ) ;
DWrite . TextFormat textFormat ;
if ( typeface . FontFamily . BaseUri ! = null )
if ( typeface . FontFamily . BaseUri ! = null )
{
{
var fontFamily = AvaloniaLocator . Current . GetService < IFontFamilyCache > ( ) . GetOrAddFontFamily ( typeface . FontFamily ) ;
var fontCollection = Direct2D1CustomFontResourceCache . GetOrAddCustomFontResource ( typeface . FontFamily , factory ) ;
fontFamily . TryGetFamilyTypeface ( out var familyTypeface ) ;
var fontLoader = new ResourceFontLoader ( factory , familyTypeface . ResourceUri ) ;
var fontCollection = new DWrite . FontCollection ( factory , fontLoader , fontLoader . Key ) ;
textFormat = new DWrite . TextFormat (
factory ,
using ( var textFormat =
typeface . FontFamily . Name ,
new DWrite . TextFormat ( factory , typeface . FontFamily . Name , fontCollection , DWrite . FontWeight . Normal ,
fontCollection ,
DWrite . FontStyle . Normal , DWrite . FontStretch . Normal , ( float ) typeface . FontSize ) )
( DWrite . FontWeight ) typeface . Weight ,
{
( DWrite . FontStyle ) typeface . Style ,
textFormat . TextAlignment = DWrite . TextAlignment . Center ;
DWrite . FontStretch . Normal ,
textFormat . ParagraphAlignment = DWrite . ParagraphAlignment . Center ;
( float ) typeface . FontSize ) ;
textFormat . WordWrapping = wrapping = = TextWrapping . Wrap ?
DWrite . WordWrapping . Wrap :
DWrite . WordWrapping . NoWrap ;
TextLayout = new DWrite . TextLayout ( factory , Text ? ? string . Empty , textFormat , ( float ) constraint . Width ,
( float ) constraint . Height )
{
TextAlignment = textAlignment . ToDirect2D ( )
} ;
}
}
}
else
else
{
{
using ( var f ormat = new DWrite . TextFormat (
textFormat = new DWrite . TextFormat (
factory ,
factory ,
typeface ? . FontFamily . Name ? ? "Courier New" ,
typeface . FontFamily . Name ,
( DWrite . FontWeight ) ( typeface . Weight ) ,
( DWrite . FontWeight ) typeface . Weight ,
( DWrite . FontStyle ) ( typeface . Style ) ,
( DWrite . FontStyle ) typeface . Style ,
( float ) typeface . FontSize ) )
( float ) typeface . FontSize ) ;
{
format . WordWrapping = wrapping = = TextWrapping . Wrap ?
DWrite . WordWrapping . Wrap :
DWrite . WordWrapping . NoWrap ;
TextLayout = new DWrite . TextLayout (
factory ,
text ? ? string . Empty ,
format ,
( float ) constraint . Width ,
( float ) constraint . Height )
{
TextAlignment = textAlignment . ToDirect2D ( )
} ;
}
}
}
textFormat . TextAlignment = DWrite . TextAlignment . Center ;
textFormat . ParagraphAlignment = DWrite . ParagraphAlignment . Center ;
textFormat . WordWrapping = wrapping = = TextWrapping . Wrap ?
DWrite . WordWrapping . Wrap :
DWrite . WordWrapping . NoWrap ;
TextLayout = new DWrite . TextLayout ( factory , Text ? ? string . Empty , textFormat , ( float ) constraint . Width ,
( float ) constraint . Height )
{
TextAlignment = textAlignment . ToDirect2D ( )
} ;
textFormat . Dispose ( ) ;
if ( spans ! = null )
if ( spans ! = null )
{
{
foreach ( var span in spans )
foreach ( var span in spans )
@ -98,10 +85,10 @@ namespace Avalonia.Direct2D1.Media
public DWrite . TextLayout TextLayout { get ; }
public DWrite . TextLayout TextLayout { get ; }
public void Dispose ( )
//public void Dispose()
{
//{
TextLayout . Dispose ( ) ;
// TextLayout.Dispose();
}
//}
public IEnumerable < FormattedTextLine > GetLines ( )
public IEnumerable < FormattedTextLine > GetLines ( )
{
{
@ -111,14 +98,11 @@ namespace Avalonia.Direct2D1.Media
public TextHitTestResult HitTestPoint ( Point point )
public TextHitTestResult HitTestPoint ( Point point )
{
{
SharpDX . Mathematics . Interop . RawBool isTrailingHit ;
SharpDX . Mathematics . Interop . RawBool isInside ;
var result = TextLayout . HitTestPoint (
var result = TextLayout . HitTestPoint (
( float ) point . X ,
( float ) point . X ,
( float ) point . Y ,
( float ) point . Y ,
out isTrailingHit ,
out var isTrailingHit ,
out isInside ) ;
out var isInside ) ;
return new TextHitTestResult
return new TextHitTestResult
{
{
@ -130,14 +114,7 @@ namespace Avalonia.Direct2D1.Media
public Rect HitTestTextPosition ( int index )
public Rect HitTestTextPosition ( int index )
{
{
float x ;
var result = TextLayout . HitTestTextPosition ( index , false , out _ , out _ ) ;
float y ;
var result = TextLayout . HitTestTextPosition (
index ,
false ,
out x ,
out y ) ;
return new Rect ( result . Left , result . Top , result . Width , result . Height ) ;
return new Rect ( result . Left , result . Top , result . Width , result . Height ) ;
}
}
@ -175,12 +152,29 @@ namespace Avalonia.Direct2D1.Media
}
}
}
}
internal static class Direct2D1CustomFontResourceCache
{
private static readonly ConcurrentDictionary < FontFamilyKey , DWrite . FontCollection > s_cachedFonts =
new ConcurrentDictionary < FontFamilyKey , DWrite . FontCollection > ( ) ;
public static DWrite . FontCollection GetOrAddCustomFontResource ( FontFamily fontFamily , DWrite . Factory factory )
{
return s_cachedFonts . GetOrAdd ( fontFamily . Key , x = > CreateCustomFontResource ( x , factory ) ) ;
}
private static DWrite . FontCollection CreateCustomFontResource ( FontFamilyKey fontFamilyKey , DWrite . Factory factory )
{
var fontLoader = new ResourceFontLoader ( factory , fontFamilyKey . BaseUri ) ;
return new DWrite . FontCollection ( factory , fontLoader , fontLoader . Key ) ;
}
}
public class ResourceFontLoader : CallbackBase , DWrite . FontCollectionLoader , DWrite . FontFileLoader
public class ResourceFontLoader : CallbackBase , DWrite . FontCollectionLoader , DWrite . FontFileLoader
{
{
private readonly List < ResourceFontFileStream > _f ontStreams = new List < ResourceFontFileStream > ( ) ;
private readonly List < ResourceFontFileStream > _f ontStreams = new List < ResourceFontFileStream > ( ) ;
private readonly List < ResourceFontFileEnumerator > _ enumerators = new List < ResourceFontFileEnumerator > ( ) ;
private readonly List < ResourceFontFileEnumerator > _ enumerators = new List < ResourceFontFileEnumerator > ( ) ;
private readonly DataStream _ keyStream ;
private readonly DataStream _ keyStream ;
private readonly DWrite . Factory _f actory ;
/// <summary>
/// <summary>
@ -190,7 +184,7 @@ namespace Avalonia.Direct2D1.Media
/// <param name="fontResource"></param>
/// <param name="fontResource"></param>
public ResourceFontLoader ( DWrite . Factory factory , Uri fontResource )
public ResourceFontLoader ( DWrite . Factory factory , Uri fontResource )
{
{
_f actory = factory ;
var factory1 = factory ;
var assets = AvaloniaLocator . Current . GetService < IAssetLoader > ( ) ;
var assets = AvaloniaLocator . Current . GetService < IAssetLoader > ( ) ;
@ -215,8 +209,8 @@ namespace Avalonia.Direct2D1.Media
_ keyStream . Position = 0 ;
_ keyStream . Position = 0 ;
// Register the
// Register the
_f actory . RegisterFontFileLoader ( this ) ;
factory1 . RegisterFontFileLoader ( this ) ;
_f actory . RegisterFontCollectionLoader ( this ) ;
factory1 . RegisterFontCollectionLoader ( this ) ;
}
}
@ -224,13 +218,7 @@ namespace Avalonia.Direct2D1.Media
/// Gets the key used to identify the FontCollection as well as storing index for fonts.
/// Gets the key used to identify the FontCollection as well as storing index for fonts.
/// </summary>
/// </summary>
/// <value>The key.</value>
/// <value>The key.</value>
public DataStream Key
public DataStream Key = > _ keyStream ;
{
get
{
return _ keyStream ;
}
}
/// <summary>
/// <summary>
/// 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.
/// 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.
@ -282,7 +270,7 @@ namespace Avalonia.Direct2D1.Media
/// <param name="stream">The stream.</param>
/// <param name="stream">The stream.</param>
public ResourceFontFileStream ( DataStream stream )
public ResourceFontFileStream ( DataStream stream )
{
{
this . _ stream = stream ;
_ stream = stream ;
}
}
/// <summary>
/// <summary>
@ -384,19 +372,15 @@ namespace Avalonia.Direct2D1.Media
{
{
bool moveNext = keyStream . RemainingLength ! = 0 ;
bool moveNext = keyStream . RemainingLength ! = 0 ;
if ( moveNext )
if ( ! moveNext ) return false ;
{
if ( _ currentFontFile ! = null )
{
_ currentFontFile . Dispose ( ) ;
}
_ currentFontFile = new DWrite . FontFile ( _f actory , keyStream . PositionPointer , 4 , _l oader ) ;
_ currentFontFile ? . Dispose ( ) ;
keyStream . Position + = 4 ;
_ currentFontFile = new DWrite . FontFile ( _f actory , keyStream . PositionPointer , 4 , _l oader ) ;
}
keyStream . Position + = 4 ;
return moveNext ;
return true ;
}
}
/// <summary>
/// <summary>