Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CoreText] Implement CTFontDescriptor.MatchFontDescriptors. Fixes #19397. #19399

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/CoreText/CTFont.Generator.cs
Expand Up @@ -32,4 +32,6 @@
namespace CoreText {
public partial class CTFont : NativeObject {
}
public partial class CTFontDescriptor : NativeObject {
}
}
68 changes: 51 additions & 17 deletions src/CoreText/CTFontDescriptor.cs
Expand Up @@ -32,6 +32,7 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;

using ObjCRuntime;
Expand Down Expand Up @@ -390,7 +391,7 @@ public CTFontDescriptorAttributes (NSDictionary dictionary)
[SupportedOSPlatform ("macos")]
[SupportedOSPlatform ("tvos")]
#endif
public class CTFontDescriptor : NativeObject {
public partial class CTFontDescriptor : NativeObject {
[Preserve (Conditional = true)]
internal CTFontDescriptor (NativeHandle handle, bool owns)
: base (handle, owns, true)
Expand Down Expand Up @@ -738,34 +739,67 @@ public CTFontDescriptor (CTFontDescriptorAttributes attributes)
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("tvos")]
#endif
#if NET
[DllImport (Constants.CoreTextLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
static unsafe extern bool CTFontDescriptorMatchFontDescriptorsWithProgressHandler (IntPtr descriptors, IntPtr mandatoryAttributes,
delegate* unmanaged<CTFontDescriptorMatchingState, IntPtr, bool> progressHandler);
static unsafe extern byte CTFontDescriptorMatchFontDescriptorsWithProgressHandler (IntPtr descriptors, IntPtr mandatoryAttributes, BlockLiteral* progressBlock);

public delegate bool CTFontDescriptorProgressHandler (CTFontDescriptorMatchingState state, CTFontDescriptorMatchingProgress progress);

#if !NET
delegate byte ct_font_desctiptor_progress_handler_t (IntPtr block, CTFontDescriptorMatchingState state, IntPtr progress);
static ct_font_desctiptor_progress_handler_t static_MatchFontDescriptorsHandler = MatchFontDescriptorsHandler;

[MonoPInvokeCallback (typeof (ct_font_desctiptor_progress_handler_t))]
#else
[DllImport (Constants.CoreTextLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
static extern bool CTFontDescriptorMatchFontDescriptorsWithProgressHandler (IntPtr descriptors, IntPtr mandatoryAttributes,
Func<CTFontDescriptorMatchingState, IntPtr, bool> progressHandler);
[UnmanagedCallersOnly]
#endif
static byte MatchFontDescriptorsHandler (IntPtr block, CTFontDescriptorMatchingState state, IntPtr progress)
{
var del = BlockLiteral.GetTarget<CTFontDescriptorProgressHandler> (block);
if (del is not null) {
var progressDictionary = Runtime.GetNSObject<NSDictionary> (progress)!;
var strongDictionary = new CTFontDescriptorMatchingProgress (progressDictionary);
var rv = del (state, strongDictionary);
return rv ? (byte) 1 : (byte) 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We like to cast too much hehe

Suggested change
return rv ? (byte) 1 : (byte) 0;
return (byte) (rv ? 1 : 0);

Of course this is meant as a joke, no need to change a thing ;)

}
return 0;
}

#if NET
[SupportedOSPlatform ("macos")]
[SupportedOSPlatform ("ios")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("tvos")]
#endif
public static bool MatchFontDescriptors (CTFontDescriptor [] descriptors, NSSet mandatoryAttributes, Func<CTFontDescriptorMatchingState, IntPtr, bool> progressHandler)
[BindingImpl (BindingImplOptions.Optimizable)]
public static bool MatchFontDescriptors (CTFontDescriptor [] descriptors, NSSet? mandatoryAttributes, CTFontDescriptorProgressHandler progressHandler)
{
if (descriptors is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (descriptors));

if (progressHandler is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (progressHandler));

unsafe {
#if NET
delegate* unmanaged<IntPtr, CTFontDescriptorMatchingState, IntPtr, byte> trampoline = &MatchFontDescriptorsHandler;
using var block = new BlockLiteral (trampoline, progressHandler, typeof (CTFontDescriptor), nameof (MatchFontDescriptorsHandler));
#else
using var block = new BlockLiteral ();
block.SetupBlockUnsafe (static_MatchFontDescriptorsHandler, progressHandler);
#endif
using var descriptorsArray = NSArray.FromNSObjects (descriptors);
var rv = CTFontDescriptorMatchFontDescriptorsWithProgressHandler (descriptorsArray.GetHandle (), mandatoryAttributes.GetHandle (), &block);
return rv != 0;
}
}

#if !XAMCORE_5_0
[EditorBrowsable (EditorBrowsableState.Never)]
[Obsolete ("Use 'MatchFontDescriptors (CTFontDescriptor[], NSSet, CTFontDescriptorProgressHandler)' instead.")]
public static bool MatchFontDescriptors (CTFontDescriptor [] descriptors, NSSet? mandatoryAttributes, Func<CTFontDescriptorMatchingState, IntPtr, bool> progressHandler)
{
// FIXME: the P/Invoke used below is wrong, it expects a block, not a function pointer.
// throwing a NIE instead of crashing until this is implemented properly.
throw new NotImplementedException ();
// var ma = mandatoryAttributes is null ? IntPtr.Zero : mandatoryAttributes.Handle;
// // FIXME: SIGSEGV probably due to mandatoryAttributes mismatch
// using (var ar = CFArray.FromNativeObjects (descriptors)) {
// return CTFontDescriptorMatchFontDescriptorsWithProgressHandler (ar.Handle, ma, progressHandler);
// }
}
#endif
}
}
6 changes: 6 additions & 0 deletions src/bgen/Generator.cs
Expand Up @@ -1951,6 +1951,9 @@ void GenerateStrongDictionaryTypes ()
} else if (elementType == TypeManager.System_String) {
getter = "GetArray<string> ({0}, (ptr) => CFString.FromHandle (ptr)!)";
setter = "SetArrayValue ({0}, value)";
} else if (elementType.Name == "CTFontDescriptor") {
getter = "GetArray<CTFontDescriptor> ({0}, (ptr) => new CTFontDescriptor (ptr, false))";
setter = "SetArrayValue ({0}, value)";
} else {
throw new BindingException (1033, true, pi.PropertyType, dictType, pi.Name);
}
Expand Down Expand Up @@ -1982,6 +1985,9 @@ void GenerateStrongDictionaryTypes ()
} else if (pi.PropertyType.Name == "CGImageSource") {
getter = "GetNativeValue<" + pi.PropertyType + "> ({0})";
setter = "SetNativeValue ({0}, value)";
} else if (pi.PropertyType.Name == "CTFontDescriptor") {
getter = "GetNativeValue<" + pi.PropertyType + "> ({0})";
setter = "SetNativeValue ({0}, value)";
} else {
throw new BindingException (1033, true, pi.PropertyType, dictType, pi.Name);
}
Expand Down
40 changes: 40 additions & 0 deletions src/coretext.cs
Expand Up @@ -325,6 +325,46 @@ interface CTFontCollectionOptionKey {
}
#endif

[Internal]
[Static]
interface CTFontDescriptorMatchingKeys {
[Field ("kCTFontDescriptorMatchingSourceDescriptor")]
NSString SourceDescriptorKey { get; }

[Field ("kCTFontDescriptorMatchingDescriptors")]
NSString DescriptorsKey { get; }

[Field ("kCTFontDescriptorMatchingResult")]
NSString ResultKey { get; }

[Field ("kCTFontDescriptorMatchingPercentage")]
NSString PercentageKey { get; }

[Field ("kCTFontDescriptorMatchingCurrentAssetSize")]
NSString CurrentAssetSizeKey { get; }

[Field ("kCTFontDescriptorMatchingTotalDownloadedSize")]
NSString TotalDownloadedSizeKey { get; }

[Field ("kCTFontDescriptorMatchingTotalAssetSize")]
NSString TotalAssetSizeKey { get; }

[Field ("kCTFontDescriptorMatchingError")]
NSString ErrorKey { get; }
}

[StrongDictionary ("CTFontDescriptorMatchingKeys")]
interface CTFontDescriptorMatchingProgress {
CTFontDescriptor SourceDescriptor { get; }
CTFontDescriptor [] Descriptors { get; }
CTFontDescriptor [] Result { get; }
double Percentage { get; }
long CurrentAssetSize { get; }
long TotalDownloadedSize { get; }
long TotalAssetSize { get; }
NSError Error { get; }
}

[Static]
[Partial]
interface CTStringAttributeKey {
Expand Down
1 change: 0 additions & 1 deletion tests/cecil-tests/BlittablePInvokes.KnownFailures.cs
Expand Up @@ -207,7 +207,6 @@ public partial class BlittablePInvokes {
"System.Boolean CoreServices.FSEvent::FSEventsPurgeEventsForDeviceUpToEventId(System.UInt64,System.UInt64)",
"System.Boolean CoreServices.FSEventStream::FSEventStreamStart(System.IntPtr)",
"System.Boolean CoreText.CTFont::CTFontGetGlyphsForCharacters(System.IntPtr,System.Char[],System.UInt16[],System.IntPtr)",
"System.Boolean CoreText.CTFontDescriptor::CTFontDescriptorMatchFontDescriptorsWithProgressHandler(System.IntPtr,System.IntPtr,method System.Boolean *(CoreText.CTFontDescriptorMatchingState,System.IntPtr))",
"System.Boolean CoreText.CTFontManager::CTFontManagerIsSupportedFont(System.IntPtr)",
"System.Boolean CoreText.CTFontManager::CTFontManagerRegisterFontsForURL(System.IntPtr,CoreText.CTFontManagerScope,System.IntPtr&)",
"System.Boolean CoreText.CTFontManager::CTFontManagerRegisterFontsForURLs(System.IntPtr,CoreText.CTFontManagerScope,System.IntPtr&)",
Expand Down
27 changes: 27 additions & 0 deletions tests/monotouch-test/CoreText/FontDescriptorTest.cs
Expand Up @@ -8,6 +8,9 @@
//

using System;
using System.Threading;
using System.Threading.Tasks;

using Foundation;
using CoreText;
#if MONOMAC
Expand Down Expand Up @@ -71,5 +74,29 @@ public void WithFeature ()
Assert.That (set_feature.FeatureWeak, Is.EqualTo ((int) CTFontFeatureLigatures.Selector.RareLigaturesOn), "#2");
}
}

[Test]
public void MatchFontDescriptors ()
{
var fda1 = new CTFontDescriptorAttributes () {
Name = "Helvetica",
};
using var desc1 = new CTFontDescriptor (fda1);
var tcs = new TaskCompletionSource<bool> ();
var rv = CTFontDescriptor.MatchFontDescriptors (new CTFontDescriptor [] { desc1 }, null, (CTFontDescriptorMatchingState state, CTFontDescriptorMatchingProgress progress) => {
try {
if (state == CTFontDescriptorMatchingState.Finished) {
Assert.AreEqual (1, progress.Result.Length, "Result.Length");
Assert.AreEqual (fda1.Name, progress.Result [0].GetAttributes ().Name, "Result[0].Name");
tcs.TrySetResult (true);
}
} catch (Exception e) {
tcs.TrySetException (e);
}
return true;
});
Assert.IsTrue (rv, "Return value");
TestRuntime.RunAsync (TimeSpan.FromSeconds (30), tcs.Task);
}
}
}
Expand Up @@ -4,14 +4,6 @@
!missing-enum! CTRubyAlignment not bound
!missing-enum! CTRubyOverhang not bound
!missing-enum! CTRubyPosition not bound
!missing-field! kCTFontDescriptorMatchingCurrentAssetSize not bound
!missing-field! kCTFontDescriptorMatchingDescriptors not bound
!missing-field! kCTFontDescriptorMatchingError not bound
!missing-field! kCTFontDescriptorMatchingPercentage not bound
!missing-field! kCTFontDescriptorMatchingResult not bound
!missing-field! kCTFontDescriptorMatchingSourceDescriptor not bound
!missing-field! kCTFontDescriptorMatchingTotalAssetSize not bound
!missing-field! kCTFontDescriptorMatchingTotalDownloadedSize not bound
!missing-field! kCTFontDownloadableAttribute not bound
!missing-field! kCTFontDownloadedAttribute not bound
!missing-field! kCTFontManagerRegisteredFontsChangedNotification not bound
Expand Down
8 changes: 0 additions & 8 deletions tests/xtro-sharpie/common-CoreText.ignore
Expand Up @@ -24,14 +24,6 @@
!missing-field! kCTFontCollectionRemoveDuplicatesOption not bound
!missing-field! kCTFontCopyrightNameKey not bound
!missing-field! kCTFontDescriptionNameKey not bound
!missing-field! kCTFontDescriptorMatchingCurrentAssetSize not bound
!missing-field! kCTFontDescriptorMatchingDescriptors not bound
!missing-field! kCTFontDescriptorMatchingError not bound
!missing-field! kCTFontDescriptorMatchingPercentage not bound
!missing-field! kCTFontDescriptorMatchingResult not bound
!missing-field! kCTFontDescriptorMatchingSourceDescriptor not bound
!missing-field! kCTFontDescriptorMatchingTotalAssetSize not bound
!missing-field! kCTFontDescriptorMatchingTotalDownloadedSize not bound
!missing-field! kCTFontDesignerNameKey not bound
!missing-field! kCTFontDesignerURLNameKey not bound
!missing-field! kCTFontDisplayNameAttribute not bound
Expand Down