diff --git a/src/CoreGraphics/CGBitmapContext.cs b/src/CoreGraphics/CGBitmapContext.cs index 33e22f98a2e7..f7f5d19274c6 100644 --- a/src/CoreGraphics/CGBitmapContext.cs +++ b/src/CoreGraphics/CGBitmapContext.cs @@ -29,6 +29,7 @@ #nullable enable using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; @@ -225,6 +226,175 @@ public CGBitmapFlags BitmapInfo { // do not return an invalid instance (null handle) if something went wrong return h == IntPtr.Zero ? null : new CGImage (h, true); } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern unsafe IntPtr /* CGContextRef */ CGBitmapContextCreateAdaptive ( + nuint /* size_t */ width, + nuint /* size_t */ height, + IntPtr /* CFDictionaryRef __nullable */ auxiliaryInfo, + BlockLiteral* /* (^__nullable onResolve)(const CGContentInfo* __nonnull, CGBitmapParameters* __nonnull) */ onResolve, + BlockLiteral* /* (^__nullable onAllocate)(const CGContentInfo* __nonnull, const CGBitmapParameters* __nonnull) */ onAllocate, + BlockLiteral* /* (^__nullable onFree)(CGRenderingBufferProviderRef __nonnull, const CGContentInfo* __nonnull, const CGBitmapParameters* __nonnull) */ onFree, + BlockLiteral* /* (^__nullable onError)(CFErrorRef __nonnull, const CGContentInfo* __nonnull, const CGBitmapParameters* __nonnull) */ onError + ); + + /// Create a bitmap context designed to choose the optimal bit depth, colorspace and EDR target headroom. + /// The width of the new . + /// The height of the new . + /// Any additional information for the creation of the new . + /// A callback to modify the used to create the new . + /// A callback to allocate memory for the new . + /// A callback to free any allocated memory for the new . + /// A callback that is called in case of any errors. + /// A new if successful, otherwise. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [BindingImpl (BindingImplOptions.Optimizable)] + public unsafe static CGBitmapContext? Create (nuint width, nuint height, NSDictionary? auxiliaryInfo, OnResolveCallback? onResolve, OnAllocateCallback? onAllocate, OnFreeCallback? onFree, OnErrorCallback? onError) + { + delegate* unmanaged onResolveTrampoline = &CGBitmapContextCreateAdaptive_OnResolve; + using var onResolveBlock = onResolve is null ? default (BlockLiteral) : new BlockLiteral (onResolveTrampoline, onResolve, typeof (CGBitmapContext), nameof (CGBitmapContextCreateAdaptive_OnResolve)); + + delegate* unmanaged onAllocateTrampoline = &CGBitmapContextCreateAdaptive_OnAllocate; + using var onAllocateBlock = onAllocate is null ? default (BlockLiteral) : new BlockLiteral (onAllocateTrampoline, onAllocate, typeof (CGBitmapContext), nameof (CGBitmapContextCreateAdaptive_OnAllocate)); + + delegate* unmanaged onFreeTrampoline = &CGBitmapContextCreateAdaptive_OnFree; + using var onFreeBlock = onFree is null ? default (BlockLiteral) : new BlockLiteral (onFreeTrampoline, onFree, typeof (CGBitmapContext), nameof (CGBitmapContextCreateAdaptive_OnFree)); + + delegate* unmanaged onErrorTrampoline = &CGBitmapContextCreateAdaptive_OnError; + using var onErrorBlock = onError is null ? default (BlockLiteral) : new BlockLiteral (onErrorTrampoline, onError, typeof (CGBitmapContext), nameof (CGBitmapContextCreateAdaptive_OnError)); + + var rv = CGBitmapContextCreateAdaptive ( + width, height, + auxiliaryInfo.GetHandle (), + onResolve is null ? null : &onResolveBlock, + onAllocate is null ? null : &onAllocateBlock, + onFree is null ? null : &onFreeBlock, + onError is null ? null : &onErrorBlock + ); + + GC.KeepAlive (auxiliaryInfo); + + if (rv == IntPtr.Zero) + return null; + + return new CGBitmapContext (rv, true); + } + + /// Create a bitmap context designed to choose the optimal bit depth, colorspace and EDR target headroom. + /// The width of the new . + /// The height of the new . + /// Any additional information for the creation of the new . + /// A callback to modify the used to create the new . + /// A callback to allocate memory for the new . + /// A callback to free any allocated memory for the new . + /// A callback that is called in case of any errors. + /// A new if successful, otherwise. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public unsafe static CGBitmapContext? Create (nuint width, nuint height, CGAdaptiveOptions? auxiliaryInfo, OnResolveCallback? onResolve, OnAllocateCallback? onAllocate, OnFreeCallback? onFree, OnErrorCallback? onError) + { + return Create (width, height, auxiliaryInfo?.Dictionary, onResolve, onAllocate, onFree, onError); + } + + public delegate bool OnResolveCallback (ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters); + + [UnmanagedCallersOnly] + unsafe static byte CGBitmapContextCreateAdaptive_OnResolve (IntPtr block, CGContentInfo* contentInfo, CGBitmapParameters* bitmapParameters) + { + var del = BlockLiteral.GetTarget (block); + if (del is not null) { + var rv = del (ref Unsafe.AsRef (contentInfo), ref Unsafe.AsRef (bitmapParameters)); + return rv.AsByte (); + } + return 0; + } + + public delegate CGRenderingBufferProvider /* CGRenderingBufferProviderRef */ OnAllocateCallback (ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters); + + [UnmanagedCallersOnly] + unsafe static IntPtr CGBitmapContextCreateAdaptive_OnAllocate (IntPtr block, CGContentInfo* contentInfo, CGBitmapParameters* bitmapParameters) + { + var del = BlockLiteral.GetTarget (block); + if (del is not null) { + var rv = del (ref Unsafe.AsRef (contentInfo), ref Unsafe.AsRef (bitmapParameters)); + return Runtime.RetainAndAutoreleaseHandle (rv); + } + return IntPtr.Zero; + } + + public delegate void OnFreeCallback (CGRenderingBufferProvider /* CGRenderingBufferProviderRef */ renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters); + + [UnmanagedCallersOnly] + unsafe static void CGBitmapContextCreateAdaptive_OnFree (IntPtr block, IntPtr /* CGRenderingBufferProviderRef */ bufferingProviderRef, CGContentInfo* contentInfo, CGBitmapParameters* bitmapParameters) + { + var del = BlockLiteral.GetTarget (block); + if (del is not null) { + using var renderingBufferProvider = new CGRenderingBufferProvider (bufferingProviderRef, false); + del (renderingBufferProvider, ref Unsafe.AsRef (contentInfo), ref Unsafe.AsRef (bitmapParameters)); + } + } + + public delegate void OnErrorCallback (NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters); + + [UnmanagedCallersOnly] + unsafe static void CGBitmapContextCreateAdaptive_OnError (IntPtr block, IntPtr errorHandle, CGContentInfo* contentInfo, CGBitmapParameters* bitmapParameters) + { + var del = BlockLiteral.GetTarget (block); + if (del is not null) { + var error = Runtime.GetNSObject (errorHandle, false)!; + del (error, ref Unsafe.AsRef (contentInfo), ref Unsafe.AsRef (bitmapParameters)); + } + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern CGContentToneMappingInfo CGContextGetContentToneMappingInfo (IntPtr /* CGContextRef __nonnull */ context); + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern void CGContextSetContentToneMappingInfo (IntPtr /* CGContextRef __nonnull */ context, CGContentToneMappingInfo info); + + /// Get or set the content tone mapping info. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public CGContentToneMappingInfo ContentToneMappingInfo { + get => CGContextGetContentToneMappingInfo (GetCheckedHandle ()); + set => CGContextSetContentToneMappingInfo (GetCheckedHandle (), value); + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern void CGContextSynchronizeAttributes (IntPtr /* CGContextRef */ context); + + /// Synchronize destination attributes. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public void SynchronizeAttributes () + { + CGContextSynchronizeAttributes (GetCheckedHandle ()); + } #endif // !COREBUILD } } diff --git a/src/CoreGraphics/CGBitmapInfo.cs b/src/CoreGraphics/CGBitmapInfo.cs new file mode 100644 index 000000000000..bca65d82abc6 --- /dev/null +++ b/src/CoreGraphics/CGBitmapInfo.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace CoreGraphics { + public static class CGBitmapInfoExtensions { + /// Get the alpha info flags for this value. + /// The value with the flags to get. + /// The alpha info flags for this value. + public static CGImageAlphaInfo GetAlphaInfo (this CGBitmapInfo value) + { + return (CGImageAlphaInfo) (value & CGBitmapInfo.AlphaInfoMask); + } + + /// Get the component info flags for this value. + /// The value with the flags to get. + /// The component info flags for this value. + public static CGImageComponentInfo GetComponentInfo (this CGBitmapInfo value) + { + return (CGImageComponentInfo) (value & CGBitmapInfo.ComponentInfoMask); + } + + /// Get the byte order info flags for this value. + /// The value with the flags to get. + /// The byte order info flags for this value. + public static CGImageByteOrderInfo GetByteOrderInfo (this CGBitmapInfo value) + { + return (CGImageByteOrderInfo) (value & CGBitmapInfo.ByteOrderInfoMask); + } + + /// Get the pixel format info flags for this value. + /// The value with the flags to get. + /// The pixel formatinfo flags for this value. + public static CGImagePixelFormatInfo GetPixelFormatInfo (this CGBitmapInfo value) + { + return (CGImagePixelFormatInfo) (value & CGBitmapInfo.PixelFormatInfoMask); + } + } +} diff --git a/src/CoreGraphics/CGBitmapParameters.cs b/src/CoreGraphics/CGBitmapParameters.cs new file mode 100644 index 000000000000..b849c636fdc6 --- /dev/null +++ b/src/CoreGraphics/CGBitmapParameters.cs @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#nullable enable + +using CoreFoundation; + +namespace CoreGraphics { + /// This struct contains values used when creating an adaptive bitmap context. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [SupportedOSPlatform ("tvos26.0")] + [StructLayout (LayoutKind.Sequential)] + public struct CGBitmapParameters { + nuint width; + nuint height; + nuint bytesPerPixel; + nuint alignedBytesPerRow; /* Rounded up to an appropriate value for bitmap data */ + CGComponent component; + CGBitmapLayout layout; + CGImagePixelFormatInfo format; + IntPtr /* CGColorSpaceRef */ colorSpace; + byte /* bool */ hasPremultipliedAlpha; + nint /* CFByteOrder */ byteOrder; + float edrTargetHeadroom; + + /// The width of the new . + public nuint Width { + get => width; + set => width = value; + } + + /// The height of the new . + public nuint Height { + get => height; + set => height = value; + } + + /// The number of bytes per pixel for the new . + public nuint BytesPerPixel { + get => bytesPerPixel; + set => bytesPerPixel = value; + } + + /// The number of aligned bytes per row for the new . + public nuint AlignedBytesPerRow { + get => alignedBytesPerRow; + set => alignedBytesPerRow = value; + } + + /// The value for the new . + public CGComponent Component { + get => component; + set => component = value; + } + + /// The value for the new . + public CGBitmapLayout Layout { + get => layout; + set => layout = value; + } + + /// The pixel format for the new . + public CGImagePixelFormatInfo Format { + get => format; + set => format = value; + } + + /// The handle for the colorspace of the new . + public IntPtr ColorSpaceHandle { + get => colorSpace; + set => colorSpace = value; + } + + /// The for the new . + /// When setting this value, the calling code must keep a reference to the instance, because this struct does not increment the retainCount of it to prevent the GC from collecting the instance. + public CGColorSpace? ColorSpace { + get => Runtime.GetINativeObject (colorSpace, false); + set { + // this is unsafe: the calling code must keep the managed CGColorSpace insatnce around somehow. +#pragma warning disable RBI0014 + colorSpace = value!.GetNonNullHandle (nameof (value)); +#pragma warning restore RBI0014 + } + } + + /// Whether the new has premultiplied alpha values. + public bool HasPremultipliedAlpha { + get => hasPremultipliedAlpha != 0; + set => hasPremultipliedAlpha = value.AsByte (); + } + + /// The byte order for the new . + public CFByteOrder ByteOrder { + get => (CFByteOrder) byteOrder; + set => byteOrder = (nint) (long) value; + } + + /// The EDR target headroom for the new . + public float EdrTargetHeadroom { + get => edrTargetHeadroom; + set => edrTargetHeadroom = value; + } + + /// Returns a string representation of this . + public override string ToString () + { + return $"CGBitmapParameters[Width={Width};Height={Height};BytesPerPixel={BytesPerPixel};AlignedBytesPerRow={AlignedBytesPerRow};Component={Component};Layout={Layout};Format={Format};ColorSpaceHandle={ColorSpaceHandle};ColorSpace={ColorSpace};HasPremultipliedAlpha={HasPremultipliedAlpha};ByteOrder={ByteOrder};EdrTargetHeadroom={EdrTargetHeadroom}]"; + } + } +} diff --git a/src/CoreGraphics/CGColor.cs b/src/CoreGraphics/CGColor.cs index fe41e8c784e4..fe859b83a3ce 100644 --- a/src/CoreGraphics/CGColor.cs +++ b/src/CoreGraphics/CGColor.cs @@ -412,6 +412,48 @@ public CGPattern? Pattern { [SupportedOSPlatform ("maccatalyst")] public string? AXName => CFString.FromHandle (AXNameFromColor (Handle)); + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern IntPtr /* CGColorRef gc_nullable */ CGColorCreateWithContentHeadroom (float headroom, IntPtr /* CGColorSpaceRef gc_nullable */ space, nfloat red, nfloat green, nfloat blue, nfloat alpha); + + /// Create a with the specified content headroom, colorspace and color and alpha values. + /// The content headroom for the new . + /// The colorspace for the new . + /// The red color value for the new . + /// The green color value for the new . + /// The blue color value for the new . + /// The alpha value for the new . + /// A new instance if successful, otherwise. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public static CGColor? CreateWithContentHeadroom (float headroom, CGColorSpace? colorSpace, nfloat red, nfloat green, nfloat blue, nfloat alpha) + { + var h = CGColorCreateWithContentHeadroom (headroom, colorSpace.GetHandle (), red, green, blue, alpha); + GC.KeepAlive (colorSpace); + return h == IntPtr.Zero ? null : new CGColor (h, owns: true); + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern float CGColorGetContentHeadroom (IntPtr /* CGColorRef cg_nullable */ color); + + /// Get the content headroom for the color. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public float ContentHeadroom { + get => CGColorGetContentHeadroom (GetCheckedHandle ()); + } + #endif // !COREBUILD } diff --git a/src/CoreGraphics/CGContentInfo.cs b/src/CoreGraphics/CGContentInfo.cs new file mode 100644 index 000000000000..9239ccda8875 --- /dev/null +++ b/src/CoreGraphics/CGContentInfo.cs @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#nullable enable + +using System; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +using ObjCRuntime; + +namespace CoreGraphics { + /// This struct contains values used when creating an adaptive bitmap context. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [SupportedOSPlatform ("tvos26.0")] + [StructLayout (LayoutKind.Sequential)] + public struct CGContentInfo { + CGComponent deepestImageComponent; /* deepest image component */ + CGColorModel contentColorModels; /* sum of all color models drawn */ + byte /* bool */ hasWideGamut; /* there is content in wide gamut color space */ + byte /* bool */ hasTransparency; /* there is transparent content */ + float largestContentHeadroom; + + /// The deepest image component. + public CGComponent DeepestImageComponent { + get => deepestImageComponent; + set => deepestImageComponent = value; + } + + /// The sum of all drawn color models. + public CGColorModel ContentColorModels { + get => contentColorModels; + set => contentColorModels = value; + } + + /// Whether there's content in the wide gamut colorspace or not. + public bool HasWideGamut { + get => hasWideGamut != 0; + set => hasWideGamut = value.AsByte (); + } + + /// Whether there's transparent content or not. + public bool HasTransparency { + get => hasTransparency != 0; + set => hasTransparency = value.AsByte (); + } + + /// The largest content headroom value. + public float LargestContentHeadroom { + get => largestContentHeadroom; + set => largestContentHeadroom = value; + } + + /// Returns a string representation of this . + public override string ToString () + { + return $"CGContentInfo [DeepestImageComponent={DeepestImageComponent};ContentColorModels={ContentColorModels};HasWideGamut={HasWideGamut};HasTransparency={HasTransparency};LargestContentHeadroom={LargestContentHeadroom}]"; + } + } +} diff --git a/src/CoreGraphics/CGContentToneMappingInfo.cs b/src/CoreGraphics/CGContentToneMappingInfo.cs new file mode 100644 index 000000000000..75f2e576ce26 --- /dev/null +++ b/src/CoreGraphics/CGContentToneMappingInfo.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using ObjCRuntime; + +namespace CoreGraphics { + /// A struct that defines tone mapping information. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [StructLayout (LayoutKind.Sequential)] + public struct CGContentToneMappingInfo { + CGToneMapping method; + IntPtr /* CFDictionaryRef __nullable */ options; + + /// The tone mapping method to use. + public CGToneMapping Method { + get => method; + set => method = value; + } + + /// Any tone-mapping options. + public NSDictionary? Options { + get => Runtime.GetNSObject (options); + set => options = Runtime.RetainAndAutoreleaseNSObject (value); + } + + /// Strongly typed tone-mapping options. + public CGToneMappingOptions? ToneMappingOptions { + get { + var dict = Options; + if (dict is null) + return null; + return new CGToneMappingOptions (dict); + } + set { + Options = value.GetDictionary (); + } + } + } +} diff --git a/src/CoreGraphics/CGGradient.cs b/src/CoreGraphics/CGGradient.cs index 1d27a6a35240..425020bd8507 100644 --- a/src/CoreGraphics/CGGradient.cs +++ b/src/CoreGraphics/CGGradient.cs @@ -200,6 +200,68 @@ public CGGradient (CGColorSpace? colorspace, CGColor [] colors) : base (Create (colorspace, colors), true) { } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + unsafe static extern IntPtr /* CGGradientRef __nullable */ CGGradientCreateWithContentHeadroom ( + float headroom, + IntPtr /* CGColorSpaceRef cg_nullable */ space, + nfloat* /* const CGFloat * cg_nullable */ components, + nfloat* /* const CGFloat * cg_nullable */ locations, + nint count); + + /// Create a with the specified content headroom. + /// The content headroom for the new . + /// The colorspace to use for the gradient. This colorspace must support HDR. + /// The color components to map into the new . + /// An array of values that determines where, in the range from 0.0 to 1.0, should each color be located in the new . + /// A new if successful, otherwise. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public static CGGradient? Create (float headroom, CGColorSpace? colorSpace, nfloat []? components, nfloat []? locations) + { + // "The number of locations is specified by `count'" + // "The number of color components is the product of `count' and the number of color components of `space'." + var locationLength = locations?.Length ?? 0; + var colorComponentsCount = colorSpace?.Components ?? 0; + var expectedColorComponents = (locations?.Length ?? 0) * (colorSpace?.Components ?? 0); + if (expectedColorComponents > 0 && (components is null || components.Length < expectedColorComponents)) + throw new ArgumentException (nameof (components), string.Format ("Must have at least {0} color components when the {1} array has {2} and the color space {3} has {4} color components.", expectedColorComponents, nameof (locations), locationLength, nameof (colorSpace), colorComponentsCount)); + + unsafe { + fixed (nfloat* componentsPtr = components) { + fixed (nfloat* locationsPtr = locations) { + var result = CGGradientCreateWithContentHeadroom (headroom, colorSpace.GetHandle (), componentsPtr, locationsPtr, locationLength); + GC.KeepAlive (colorSpace); + if (result == IntPtr.Zero) + return null; + return new CGGradient (result, true); + } + } + } + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern float CGGradientGetContentHeadroom (IntPtr /* CGGradientRef gc_nullable */ gradient); + + /// Get the content headroom for this gradient. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public float ContentHeadroom { + get => CGGradientGetContentHeadroom (GetCheckedHandle ()); + } + #endif // !COREBUILD } } diff --git a/src/CoreGraphics/CGImage.cs b/src/CoreGraphics/CGImage.cs index 618f54dfa6b4..c616cbb7a260 100644 --- a/src/CoreGraphics/CGImage.cs +++ b/src/CoreGraphics/CGImage.cs @@ -125,6 +125,14 @@ public enum CGImagePixelFormatInfo : uint { /// To be added. RgbCif10 = 4 << 16, /// To be added. + [SupportedOSPlatform ("ios")] + [SupportedOSPlatform ("tvos")] + [SupportedOSPlatform ("macos")] + [SupportedOSPlatform ("maccatalyst")] + [ObsoletedOSPlatform ("ios26.0", "Use 'CGBitmapInfo.ByteOrderInfoMask' instead.")] + [ObsoletedOSPlatform ("macos26.0", "Use 'CGBitmapInfo.ByteOrderInfoMask' instead.")] + [ObsoletedOSPlatform ("tvos26.0", "Use 'CGBitmapInfo.ByteOrderInfoMask' instead.")] + [ObsoletedOSPlatform ("maccatalyst26.0", "Use 'CGBitmapInfo.ByteOrderInfoMask' instead.")] Mask = 0xF0000, } @@ -877,6 +885,96 @@ public static float DefaultHdrImageContentHeadroom { [SupportedOSPlatform ("macos15.0")] [SupportedOSPlatform ("tvos18.0")] public bool ContainsImageSpecificToneMappingMetadata => CGImageContainsImageSpecificToneMappingMetadata (Handle) != 0; + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern float CGImageCalculateContentHeadroom (IntPtr /* CGImageRef cg_nullable */ image); + + /// Get the calculated the content headroom. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public float CalculatedContentHeadroom { + get => CGImageCalculateContentHeadroom (this.GetHandle ()); + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern float CGImageGetContentAverageLightLevel (IntPtr /* CGImageRef cg_nullable */ image); + + /// Get the content average light level. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public float ContentAverageLightLevel { + get => CGImageGetContentAverageLightLevel (this.GetHandle ()); + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern float CGImageCalculateContentAverageLightLevel (IntPtr /* CGImageRef cg_nullable */ image); + + /// Get the calculated content average light level. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public float CalculatedContentAverageLightLevel { + get => CGImageCalculateContentAverageLightLevel (this.GetHandle ()); + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern IntPtr /* CGImageRef cg_nullable */ CGImageCreateCopyWithContentAverageLightLevel (IntPtr /* CGImageRef cg_nullable */ image, float averageLightLevel); + + /// Create a copy of this image, adding or replacing the content average light level. + /// A new instance of successful, otherwise. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public CGImage? CopyWithContentAverageLightLevel (float contentAverageLightLevel) + { + var h = CGImageCreateCopyWithContentAverageLightLevel (this.GetHandle (), contentAverageLightLevel); + if (h == IntPtr.Zero) + return null; + return new CGImage (h, true); + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern IntPtr /* CGImageRef cg_nullable */ CGImageCreateCopyWithCalculatedHDRStats (IntPtr /* CGImageRef cg_nullable */ image); + + /// Create a copy of this image, adding or replacing the calculated HDR stats. + /// A new instance of successful, otherwise. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public CGImage? CopyWithCalculatedHdrStats () + { + var h = CGImageCreateCopyWithCalculatedHDRStats (this.GetHandle ()); + if (h == IntPtr.Zero) + return null; + return new CGImage (h, true); + } #endif // !COREBUILD } } diff --git a/src/CoreGraphics/CGRenderingBufferProvider.cs b/src/CoreGraphics/CGRenderingBufferProvider.cs new file mode 100644 index 000000000000..1c3c5e0f556d --- /dev/null +++ b/src/CoreGraphics/CGRenderingBufferProvider.cs @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using CoreFoundation; + +namespace CoreGraphics { + // typedef struct CF_BRIDGED_TYPE(id) CGRenderingBufferProvider* CGRenderingBufferProviderRef; + /// This struct is used when creating adaptive bitmap contexts. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public class CGRenderingBufferProvider : NativeObject { + [Preserve (Conditional = true)] + internal CGRenderingBufferProvider (NativeHandle handle, bool owns) + : base (handle, owns) + { + } +#if !COREBUILD + [DllImport (Constants.CoreGraphicsLibrary)] + unsafe static extern IntPtr /* CGRenderingBufferProviderRef __nullable */ CGRenderingBufferProviderCreate ( + IntPtr /* void *__nullable */ info, + nuint size, + /* void* __nullable(^__nonnull lockPointer)(void* __nullable info) */ BlockLiteral* lockPointer, + /* void (^__nullable unlockPointer)(void* __nullable info, void* __nonnull pointer) */ BlockLiteral* unlockPointer, + /* void (^__nullable releaseInfo)(void* __nullable info) */ BlockLiteral* releaseInfo); + + /// Create a new instance. + /// A user-defined value that is passed to the callbacks. + /// The size of the buffer to create. + /// A callback that is called to lock the pointer. + /// A callback that is called to unlock the pointer. + /// A callback that is called to release when the is destroyed. + /// A new instance if successful, otherwise. + [BindingImpl (BindingImplOptions.Optimizable)] + public unsafe static CGRenderingBufferProvider? Create (IntPtr info, nuint size, LockPointerCallback lockPointer, UnlockPointerCallback unlockPointer, ReleaseInfoCallback releaseInfo) + { + if (lockPointer is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (lockPointer)); + + delegate* unmanaged lockPointerTrampoline = &LockPointerBlock; + using var lockPointerBlock = new BlockLiteral (lockPointerTrampoline, lockPointer, typeof (CGRenderingBufferProvider), nameof (LockPointerBlock)); + + delegate* unmanaged unlockPointerTrampoline = &UnlockPointerBlock; + using var unlockPointerBlock = unlockPointer is null ? default (BlockLiteral) : new BlockLiteral (unlockPointerTrampoline, unlockPointer, typeof (CGRenderingBufferProvider), nameof (UnlockPointerBlock)); + + delegate* unmanaged releaseInfoTrampoline = &ReleaseInfoBlock; + using var releaseInfoBlock = releaseInfo is null ? default (BlockLiteral) : new BlockLiteral (releaseInfoTrampoline, releaseInfo, typeof (CGRenderingBufferProvider), nameof (ReleaseInfoBlock)); + + var h = CGRenderingBufferProviderCreate ( + info, + size, + &lockPointerBlock, + unlockPointer is null ? null : &unlockPointerBlock, + releaseInfo is null ? null : &releaseInfoBlock); + if (h == IntPtr.Zero) + return null; + return new CGRenderingBufferProvider (h, true); + } + + public delegate IntPtr LockPointerCallback (IntPtr info); + + [UnmanagedCallersOnly] + unsafe static IntPtr LockPointerBlock (BlockLiteral* block, IntPtr info) + { + var del = BlockLiteral.GetTarget ((IntPtr) block); + if (del is not null) + return del (info); + return IntPtr.Zero; + } + + public delegate void UnlockPointerCallback (IntPtr info, IntPtr pointer); + + [UnmanagedCallersOnly] + unsafe static void UnlockPointerBlock (BlockLiteral* block, IntPtr info, IntPtr pointer) + { + var del = BlockLiteral.GetTarget ((IntPtr) block); + if (del is not null) + del (info, pointer); + } + + public delegate void ReleaseInfoCallback (IntPtr info); + + [UnmanagedCallersOnly] + unsafe static void ReleaseInfoBlock (BlockLiteral* block, IntPtr info) + { + var del = BlockLiteral.GetTarget ((IntPtr) block); + if (del is not null) + del (info); + } + + [DllImport (Constants.CoreGraphicsLibrary)] + static extern IntPtr /* CGRenderingBufferProviderRef __nullable */ CGRenderingBufferProviderCreateWithCFData (IntPtr /* CFMutableDataRef */ data); + + /// Create a new instance for a given instance. + /// The data to use when creawting the new instance. + /// A new instance if successful, otherwise. + public static CGRenderingBufferProvider? Create (NSData data) + { + var h = CGRenderingBufferProviderCreateWithCFData (data.GetNonNullHandle (nameof (data))); + GC.KeepAlive (data); + if (h == IntPtr.Zero) + return null; + return new CGRenderingBufferProvider (h, true); + } + + [DllImport (Constants.CoreGraphicsLibrary)] + static extern nuint CGRenderingBufferProviderGetSize (IntPtr /* CGRenderingBufferProviderRef */ provider); + + /// Get the size of this . + public nuint Size { + get => CGRenderingBufferProviderGetSize (GetCheckedHandle ()); + } + + [DllImport (Constants.CoreGraphicsLibrary)] + static extern IntPtr CGRenderingBufferLockBytePtr (IntPtr /* CGRenderingBufferProviderRef */ provider); + + /// Lock the pointer, and return it. + public IntPtr LockBytePointer () + { + return CGRenderingBufferLockBytePtr (GetCheckedHandle ()); + } + + [DllImport (Constants.CoreGraphicsLibrary)] + static extern void CGRenderingBufferUnlockBytePtr (IntPtr /* CGRenderingBufferProviderRef */ provider); + + /// Unlock the pointer. + public void UnlockBytePointer () + { + CGRenderingBufferUnlockBytePtr (GetCheckedHandle ()); + } + + [DllImport (Constants.CoreGraphicsLibrary)] + static extern nuint CGRenderingBufferProviderGetTypeID (); + + /// Get this type's CFTypeID. + [DllImport (Constants.CoreGraphicsLibrary, EntryPoint = "CGRenderingBufferProviderGetTypeID")] + public extern static /* CFTypeID */ nint GetTypeId (); +#endif // !COREBUILD + } +} diff --git a/src/CoreGraphics/CGShading.cs b/src/CoreGraphics/CGShading.cs index a64b0352d118..cb088db995c0 100644 --- a/src/CoreGraphics/CGShading.cs +++ b/src/CoreGraphics/CGShading.cs @@ -66,26 +66,22 @@ protected internal override void Release () extern static /* CGShadingRef */ IntPtr CGShadingCreateAxial (/* CGColorSpaceRef */ IntPtr space, CGPoint start, CGPoint end, /* CGFunctionRef */ IntPtr functionHandle, byte extendStart, byte extendEnd); - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static CGShading CreateAxial (CGColorSpace colorspace, CGPoint start, CGPoint end, CGFunction function, bool extendStart, bool extendEnd) + /// Create a new axial shading. + /// The colorspace to use for the new . + /// The starting point for the axis. + /// The ending point for the axis + /// The shading function to use. + /// Whether the shading will extend beyond the starting point of the axis or not. + /// Whether the shading will extend beyond the ending point of the axis or not. + /// A new if successful, otherwise. + public static CGShading? CreateAxial (CGColorSpace? colorspace, CGPoint start, CGPoint end, CGFunction? function, bool extendStart, bool extendEnd) { - if (colorspace is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (colorspace)); - if (function is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (function)); - - CGShading result = new CGShading (CGShadingCreateAxial (colorspace.GetCheckedHandle (), start, end, function.GetCheckedHandle (), extendStart.AsByte (), extendEnd.AsByte ()), true); + var handle = CGShadingCreateAxial (colorspace.GetHandle (), start, end, function.GetHandle (), extendStart.AsByte (), extendEnd.AsByte ()); GC.KeepAlive (colorspace); GC.KeepAlive (function); - return result; + if (handle == IntPtr.Zero) + return null; + return new CGShading (handle, true); } [DllImport (Constants.CoreGraphicsLibrary)] @@ -93,19 +89,26 @@ public static CGShading CreateAxial (CGColorSpace colorspace, CGPoint start, CGP CGPoint start, /* CGFloat */ nfloat startRadius, CGPoint end, /* CGFloat */ nfloat endRadius, /* CGFunctionRef */ IntPtr function, byte extendStart, byte extendEnd); - public static CGShading CreateRadial (CGColorSpace colorspace, CGPoint start, nfloat startRadius, CGPoint end, nfloat endRadius, - CGFunction function, bool extendStart, bool extendEnd) + /// Create a new radial shading. + /// The colorspace to use for the new . + /// The center point for the starting circle. + /// The radius of the starting circle. + /// The center point for the ending circle + /// The radius of the ending circle. + /// The shading function to use. + /// Whether the shading will extend beyond the starting circle or not. + /// Whether the shading will extend beyond the ending circle or not. + /// A new if successful, otherwise. + public static CGShading? CreateRadial (CGColorSpace? colorspace, CGPoint start, nfloat startRadius, CGPoint end, nfloat endRadius, + CGFunction? function, bool extendStart, bool extendEnd) { - if (colorspace is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (colorspace)); - if (function is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (function)); - - CGShading result = new CGShading (CGShadingCreateRadial (colorspace.GetCheckedHandle (), start, startRadius, end, endRadius, - function.GetCheckedHandle (), extendStart.AsByte (), extendEnd.AsByte ()), true); + var handle = CGShadingCreateRadial (colorspace.GetHandle (), start, startRadius, end, endRadius, + function.GetHandle (), extendStart.AsByte (), extendEnd.AsByte ()); GC.KeepAlive (colorspace); GC.KeepAlive (function); - return result; + if (handle == IntPtr.Zero) + return null; + return new CGShading (handle, true); } [DllImport (Constants.CoreGraphicsLibrary)] @@ -113,6 +116,100 @@ public static CGShading CreateRadial (CGColorSpace colorspace, CGPoint start, nf [DllImport (Constants.CoreGraphicsLibrary)] extern static /* CGShadingRef */ IntPtr CGShadingRetain (/* CGShadingRef */ IntPtr shading); + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern IntPtr /* CGShadingRef __nullable */ CGShadingCreateAxialWithContentHeadroom ( + float headroom, + IntPtr /* CGColorSpaceRef cg_nullable */ space, + CGPoint start, + CGPoint end, + IntPtr /* CGFunctionRef cg_nullable */ function, + byte /* bool */ extendStart, + byte /* bool */ extendEnd); + + /// Create an axial shading with the specified content headroom. + /// The content headroom for the new . + /// The colorspace to use for the new . This colorspace must support HDR. + /// The starting point for the axis. + /// The ending point for the axis + /// The shading function to use. + /// Whether the shading will extend beyond the starting point of the axis or not. + /// Whether the shading will extend beyond the ending point of the axis or not. + /// A new if successful, otherwise. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public static CGShading? CreateAxial (float headroom, CGColorSpace? colorSpace, CGPoint start, CGPoint end, CGFunction? function, bool extendStart, bool extendEnd) + { + var handle = CGShadingCreateAxialWithContentHeadroom (headroom, colorSpace.GetHandle (), start, end, function.GetHandle (), extendStart.AsByte (), extendEnd.AsByte ()); + GC.KeepAlive (colorSpace); + GC.KeepAlive (function); + if (handle == IntPtr.Zero) + return null; + return new CGShading (handle, true); + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + extern static /* CGShadingRef */ IntPtr CGShadingCreateRadialWithContentHeadroom ( + float headroom, + /* CGColorSpaceRef cg_nullable */ IntPtr space, + CGPoint start, + /* CGFloat */ nfloat startRadius, + CGPoint end, + /* CGFloat */ nfloat endRadius, + /* CGFunctionRef cg_nullable */ IntPtr function, + byte extendStart, + byte extendEnd); + + /// Create a new radial shading with the specified content headroom. + /// The content headroom for the new . + /// The colorspace to use for the new . This colorspace must support HDR. + /// The center point for the starting circle. + /// The radius of the starting circle. + /// The center point for the ending circle + /// The radius of the ending circle. + /// The shading function to use. + /// Whether the shading will extend beyond the starting circle or not. + /// Whether the shading will extend beyond the ending circle or not. + /// A new if successful, otherwise. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public static CGShading? CreateRadial (float headroom, CGColorSpace? colorspace, CGPoint start, nfloat startRadius, CGPoint end, nfloat endRadius, CGFunction? function, bool extendStart, bool extendEnd) + { + var handle = CGShadingCreateRadialWithContentHeadroom (headroom, colorspace.GetHandle (), start, startRadius, end, endRadius, function.GetHandle (), extendStart.AsByte (), extendEnd.AsByte ()); + GC.KeepAlive (colorspace); + GC.KeepAlive (function); + if (handle == IntPtr.Zero) + return null; + return new CGShading (handle, true); + } + + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern float CGShadingGetContentHeadroom (IntPtr /* CGShadingRef gc_nullable */ shading); + + /// Get the content headroom for this shading. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public float ContentHeadroom { + get => CGShadingGetContentHeadroom (GetCheckedHandle ()); + } #endif // !COREBUILD } } diff --git a/src/CoreGraphics/CGToneMappingOptions.cs b/src/CoreGraphics/CGToneMappingOptions.cs new file mode 100644 index 000000000000..8af57bed240b --- /dev/null +++ b/src/CoreGraphics/CGToneMappingOptions.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Foundation; +using ObjCRuntime; + +namespace CoreGraphics { + /// A dictionary of tone mapping options. + partial class CGToneMappingOptions { + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + [DllImport (Constants.CoreGraphicsLibrary)] + static extern IntPtr /* CFDictionaryRef */ CGEXRToneMappingGammaGetDefaultOptions (); + + /// Get the default options for tone mapping using the EXR Gamma method. + [SupportedOSPlatform ("ios26.0")] + [SupportedOSPlatform ("tvos26.0")] + [SupportedOSPlatform ("maccatalyst26.0")] + [SupportedOSPlatform ("macos26.0")] + public static CGToneMappingOptions? GetDefaultExrToneMappingGammaOptions () + { + var handle = CGEXRToneMappingGammaGetDefaultOptions (); + var dict = Runtime.GetNSObject (handle); + if (dict is null) + return null; + return new CGToneMappingOptions (dict); + } + } +} diff --git a/src/DotNetGlobals.cs b/src/DotNetGlobals.cs index f35ba00b1d41..6d4f5bfc8cbc 100644 --- a/src/DotNetGlobals.cs +++ b/src/DotNetGlobals.cs @@ -1,4 +1,8 @@ global using System; global using System.Runtime.Versioning; // We need the SupportedOSPlatform/UnsupportedOSPlatform attributes pretty much everywhere +global using System.Runtime.InteropServices; + +global using Foundation; +global using ObjCRuntime; global using OSStatus = System.Int32; diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs index b570a9b6d639..1c0a02730fdb 100644 --- a/src/ObjCRuntime/Runtime.cs +++ b/src/ObjCRuntime/Runtime.cs @@ -2331,6 +2331,34 @@ public static NativeHandle RetainAndAutoreleaseNativeObject (INativeObject? obj) return obj.GetHandle (); } + /// Retain and autorelease the given object, then return the object's handle. + /// The object to retain and autorelease. + /// The object's handle (retained and autorelease). + /// The behavior is undefined if the handle's type doesn't support the 'retain' and 'autorelease' selectors. + [EditorBrowsable (EditorBrowsableState.Never)] + internal static NativeHandle RetainAndAutoreleaseHandle (INativeObject? obj) + { + if (obj is null) + return NativeHandle.Zero; +#pragma warning disable RBI0014 + return RetainAndAutoreleaseHandle (obj.GetHandle ()); +#pragma warning restore RBI0014 + } + + /// Retain and autorelease the given handle, then return the handle. + /// The handle to retain and autorelease. + /// The handle (retained and autorelease). + /// The behavior is undefined if the handle's type doesn't support the 'retain' and 'autorelease' selectors. + [EditorBrowsable (EditorBrowsableState.Never)] + internal static NativeHandle RetainAndAutoreleaseHandle (NativeHandle handle) + { + if (handle == NativeHandle.Zero) + return NativeHandle.Zero; + NSObject.DangerousRetain (handle); + NSObject.DangerousAutorelease (handle); + return handle; + } + static IntPtr CopyAndAutorelease (IntPtr ptr) { ptr = Messaging.IntPtr_objc_msgSend (ptr, Selector.GetHandle ("copy")); diff --git a/src/corefoundation.cs b/src/corefoundation.cs index 87afbd9bcb11..e902b599b143 100644 --- a/src/corefoundation.cs +++ b/src/corefoundation.cs @@ -168,4 +168,11 @@ public enum OSLogLevel : byte { Error = 0x10, Fault = 0x11, } + + [Native] + public enum CFByteOrder : long { + Unknown, + LittleEndian, + BigEndian, + } } diff --git a/src/coregraphics.cs b/src/coregraphics.cs index 50cede44cd00..0737f3b3e428 100644 --- a/src/coregraphics.cs +++ b/src/coregraphics.cs @@ -629,6 +629,21 @@ partial interface CGToneMappingOptionKeys { [Internal] [Field ("kCGEXRToneMappingGammaKneeHigh")] NSString ExrToneMappingGammaKneeHighKey { get; } + + [Internal] + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + [Field ("kCGPreferredDynamicRange")] + NSString PreferredDynamicRangeKey { get; } + + [Internal] + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + [Field ("kCGContentAverageLightLevel")] + NSString ContentAverageLightLevelKey { get; } + + [Internal] + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + [Field ("kCGContentAverageLightLevelNits")] + NSString ContentAverageLightLevelNitsKey { get; } } [TV (18, 0), Mac (15, 0), iOS (18, 0), MacCatalyst (18, 0)] @@ -641,6 +656,17 @@ interface CGToneMappingOptions { float ExrToneMappingGammaExposure { get; set; } float ExrToneMappingGammaKneeLow { get; set; } float ExrToneMappingGammaKneeHigh { get; set; } + + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + CGDynamicRange PreferredDynamicRange { get; set; } + + // property type deduced from similarly named properties on other classes + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + float ContentAverageLightLevel { get; set; } + + // property type: I've never seen floating-point nits, so use an integer type + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + nint ContentAverageLightLevelNits { get; } } [TV (18, 0), Mac (15, 0), iOS (18, 0), MacCatalyst (18, 0)] @@ -650,4 +676,79 @@ interface CoreGraphicsFields { [Field ("kCGDefaultHDRImageContentHeadroom")] float DefaultHdrImageContentHeadroom { get; } } + + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + [Flags] + public enum CGColorModel : uint { + NoColorant = 0u << 0, + Gray = 1u << 0, + Rgb = 1u << 1, + Cmyk = 1u << 2, + Lab = 1u << 3, + DeviceN = 1u << 4, + } + + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + public enum CGComponent : uint { + Unknown = 0, + Integer8Bit = 1, + Integer10Bit = 6, + Integer16Bit = 2, + Integer32Bit = 3, + Float16Bit = 5, + Float32Bit = 4, + } + + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + public enum CGBitmapLayout : uint { + AlphaOnly, + Gray, + GrayAlpha, + Rgba, + Argb, + Rgbx, + Xrgb, + Bgra, + Bgrx, + Abgr, + Xbgr, + Cmyk, + } + + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + [Partial] + interface CGAdaptiveKeys { + [Field ("kCGAdaptiveMaximumBitDepth")] + NSString MaximumBitDepthKey { get; } + } + + [StrongDictionary ("CGAdaptiveKeys")] + interface CGAdaptiveOptions { + CGComponent MaximumBitDepth { get; set; } + } + + public enum CGImageComponentInfo : uint { + Integer = (0u << 8), + Float = (1u << 8), + } + + [Flags] + public enum CGBitmapInfo : uint { + AlphaInfoMask = 0x1F, + ComponentInfoMask = 0xF00, + ByteOrderInfoMask = 0x7000, + PixelFormatInfoMask = 0xF0000, + } + + [TV (26, 0), Mac (26, 0), MacCatalyst (26, 0), iOS (26, 0)] + enum CGDynamicRange { + [Field ("kCGDynamicRangeHigh")] + High, + + [Field ("kCGDynamicRangeConstrained")] + Constrained, + + [Field ("kCGDynamicRangeStandard")] + Standard, + } } diff --git a/src/frameworks.sources b/src/frameworks.sources index 3ba666934b97..befc4810e5f6 100644 --- a/src/frameworks.sources +++ b/src/frameworks.sources @@ -503,8 +503,12 @@ COREGRAPHICS_CORE_SOURCES = \ COREGRAPHICS_SOURCES = \ CoreGraphics/CGBitmapContext.cs \ + CoreGraphics/CGBitmapInfo.cs \ + CoreGraphics/CGBitmapParameters.cs \ CoreGraphics/CGContextPDF.cs \ CoreGraphics/CGColorConversionInfo.cs \ + CoreGraphics/CGContentInfo.cs \ + CoreGraphics/CGContentToneMappingInfo.cs \ CoreGraphics/CGDataConsumer.cs \ CoreGraphics/CGDataProvider.cs \ CoreGraphics/CGEventSource.cs \ @@ -522,8 +526,10 @@ COREGRAPHICS_SOURCES = \ CoreGraphics/CGPDFStream.cs \ CoreGraphics/CGPDFString.cs \ CoreGraphics/CGPdfTagType.cs \ + CoreGraphics/CGRenderingBufferProvider.cs \ CoreGraphics/CGSession.cs \ CoreGraphics/CGShading.cs \ + CoreGraphics/CGToneMappingOptions.cs \ CoreGraphics/NativeDrawingMethods.cs \ CoreGraphics/NSValue.cs \ diff --git a/tests/cecil-tests/Documentation.KnownFailures.txt b/tests/cecil-tests/Documentation.KnownFailures.txt index 42186a2bd19a..4bdad31691ac 100644 --- a/tests/cecil-tests/Documentation.KnownFailures.txt +++ b/tests/cecil-tests/Documentation.KnownFailures.txt @@ -2006,6 +2006,9 @@ F:CoreData.NSPersistentCloudKitContainerSchemaInitializationOptions.DryRun F:CoreData.NSPersistentCloudKitContainerSchemaInitializationOptions.None F:CoreData.NSPersistentCloudKitContainerSchemaInitializationOptions.PrintSchema F:CoreData.NSPersistentStoreRequestType.BatchInsert +F:CoreFoundation.CFByteOrder.BigEndian +F:CoreFoundation.CFByteOrder.LittleEndian +F:CoreFoundation.CFByteOrder.Unknown F:CoreFoundation.CFComparisonResult.EqualTo F:CoreFoundation.CFComparisonResult.GreaterThan F:CoreFoundation.CFComparisonResult.LessThan @@ -2025,15 +2028,49 @@ F:CoreGraphics.CGAffineTransform.C F:CoreGraphics.CGAffineTransform.D F:CoreGraphics.CGAffineTransform.Tx F:CoreGraphics.CGAffineTransform.Ty +F:CoreGraphics.CGBitmapInfo.AlphaInfoMask +F:CoreGraphics.CGBitmapInfo.ByteOrderInfoMask +F:CoreGraphics.CGBitmapInfo.ComponentInfoMask +F:CoreGraphics.CGBitmapInfo.PixelFormatInfoMask +F:CoreGraphics.CGBitmapLayout.Abgr +F:CoreGraphics.CGBitmapLayout.AlphaOnly +F:CoreGraphics.CGBitmapLayout.Argb +F:CoreGraphics.CGBitmapLayout.Bgra +F:CoreGraphics.CGBitmapLayout.Bgrx +F:CoreGraphics.CGBitmapLayout.Cmyk +F:CoreGraphics.CGBitmapLayout.Gray +F:CoreGraphics.CGBitmapLayout.GrayAlpha +F:CoreGraphics.CGBitmapLayout.Rgba +F:CoreGraphics.CGBitmapLayout.Rgbx +F:CoreGraphics.CGBitmapLayout.Xbgr +F:CoreGraphics.CGBitmapLayout.Xrgb F:CoreGraphics.CGColorConversionInfoTriple.Intent F:CoreGraphics.CGColorConversionInfoTriple.Space F:CoreGraphics.CGColorConversionInfoTriple.Transform +F:CoreGraphics.CGColorModel.Cmyk +F:CoreGraphics.CGColorModel.DeviceN +F:CoreGraphics.CGColorModel.Gray +F:CoreGraphics.CGColorModel.Lab +F:CoreGraphics.CGColorModel.NoColorant +F:CoreGraphics.CGColorModel.Rgb +F:CoreGraphics.CGComponent.Float16Bit +F:CoreGraphics.CGComponent.Float32Bit +F:CoreGraphics.CGComponent.Integer10Bit +F:CoreGraphics.CGComponent.Integer16Bit +F:CoreGraphics.CGComponent.Integer32Bit +F:CoreGraphics.CGComponent.Integer8Bit +F:CoreGraphics.CGComponent.Unknown F:CoreGraphics.CGConstantColor.Black F:CoreGraphics.CGConstantColor.Clear F:CoreGraphics.CGConstantColor.White +F:CoreGraphics.CGDynamicRange.Constrained +F:CoreGraphics.CGDynamicRange.High +F:CoreGraphics.CGDynamicRange.Standard F:CoreGraphics.CGEventSuppressionState.NumberOfEventSuppressionStates F:CoreGraphics.CGEventType.TapDisabledByTimeout F:CoreGraphics.CGEventType.TapDisabledByUserInput +F:CoreGraphics.CGImageComponentInfo.Float +F:CoreGraphics.CGImageComponentInfo.Integer F:CoreGraphics.CGPdfTagType.Annotation F:CoreGraphics.CGPdfTagType.Art F:CoreGraphics.CGPdfTagType.Bibliography @@ -10138,6 +10175,7 @@ M:CoreFoundation.OSLog.Log(CoreFoundation.OSLogLevel,System.String) M:CoreFoundation.OSLog.Log(System.String) M:CoreFoundation.OSLog.Release M:CoreFoundation.OSLog.Retain +M:CoreGraphics.CGAdaptiveKeys.#ctor M:CoreGraphics.CGAffineTransform.#ctor(System.Runtime.InteropServices.NFloat,System.Runtime.InteropServices.NFloat,System.Runtime.InteropServices.NFloat,System.Runtime.InteropServices.NFloat,System.Runtime.InteropServices.NFloat,System.Runtime.InteropServices.NFloat) M:CoreGraphics.CGAffineTransform.Decompose M:CoreGraphics.CGAffineTransform.MakeRotation(System.Runtime.InteropServices.NFloat) @@ -10376,7 +10414,6 @@ M:CoreGraphics.CGRectExtensions.IsInfinite(CoreGraphics.CGRect) M:CoreGraphics.CGRectExtensions.IsNull(CoreGraphics.CGRect) M:CoreGraphics.CGRectExtensions.Standardize(CoreGraphics.CGRect) M:CoreGraphics.CGRectExtensions.UnionWith(CoreGraphics.CGRect,CoreGraphics.CGRect) -M:CoreGraphics.CGShading.CreateRadial(CoreGraphics.CGColorSpace,CoreGraphics.CGPoint,System.Runtime.InteropServices.NFloat,CoreGraphics.CGPoint,System.Runtime.InteropServices.NFloat,CoreGraphics.CGFunction,System.Boolean,System.Boolean) M:CoreGraphics.CGShading.Release M:CoreGraphics.CGShading.Retain M:CoreGraphics.CGSize.#ctor(System.Runtime.InteropServices.NFloat,System.Runtime.InteropServices.NFloat) @@ -19655,6 +19692,7 @@ P:CoreFoundation.CFSocket.Address P:CoreFoundation.CFSocket.RemoteAddress P:CoreFoundation.CFString.Item(System.IntPtr) P:CoreFoundation.OSLog.Default +P:CoreGraphics.CGAdaptiveOptions.MaximumBitDepth P:CoreGraphics.CGColor.AXName P:CoreGraphics.CGColorSpace.IsHdr P:CoreGraphics.CGColorSpace.IsHlgBased @@ -19674,10 +19712,13 @@ P:CoreGraphics.CGSessionProperties.LoginDone P:CoreGraphics.CGSessionProperties.OnConsole P:CoreGraphics.CGSessionProperties.UserId P:CoreGraphics.CGSessionProperties.UserName +P:CoreGraphics.CGToneMappingOptions.ContentAverageLightLevel +P:CoreGraphics.CGToneMappingOptions.ContentAverageLightLevelNits P:CoreGraphics.CGToneMappingOptions.ExrToneMappingGammaDefog P:CoreGraphics.CGToneMappingOptions.ExrToneMappingGammaExposure P:CoreGraphics.CGToneMappingOptions.ExrToneMappingGammaKneeHigh P:CoreGraphics.CGToneMappingOptions.ExrToneMappingGammaKneeLow +P:CoreGraphics.CGToneMappingOptions.PreferredDynamicRange P:CoreGraphics.CGToneMappingOptions.SkipBoostToHdr P:CoreGraphics.CGToneMappingOptions.Use100nitsHlgOotf P:CoreGraphics.CGToneMappingOptions.UseBT1886ForCoreVideoGamma @@ -26803,27 +26844,43 @@ T:CoreData.NSPersistentHistoryToken T:CoreData.NSPersistentHistoryTransaction T:CoreData.NSStagedMigrationManager T:CoreFoundation.CFArray +T:CoreFoundation.CFByteOrder T:CoreFoundation.CFComparisonResult T:CoreFoundation.CFStringTransform T:CoreFoundation.CGAffineTransformComponents T:CoreFoundation.OSLog T:CoreFoundation.OSLogLevel +T:CoreGraphics.CGAdaptiveKeys +T:CoreGraphics.CGAdaptiveOptions +T:CoreGraphics.CGBitmapContext.OnAllocateCallback +T:CoreGraphics.CGBitmapContext.OnErrorCallback +T:CoreGraphics.CGBitmapContext.OnFreeCallback +T:CoreGraphics.CGBitmapContext.OnResolveCallback +T:CoreGraphics.CGBitmapInfo +T:CoreGraphics.CGBitmapInfoExtensions +T:CoreGraphics.CGBitmapLayout T:CoreGraphics.CGColorConversionInfoTransformType T:CoreGraphics.CGColorConversionOptions +T:CoreGraphics.CGColorModel +T:CoreGraphics.CGComponent T:CoreGraphics.CGConstantColor T:CoreGraphics.CGDisplayStreamKeys T:CoreGraphics.CGDisplayStreamYCbCrMatrixOptionKeys +T:CoreGraphics.CGDynamicRange +T:CoreGraphics.CGImageComponentInfo T:CoreGraphics.CGPDFAccessPermissions T:CoreGraphics.CGPDFOutlineOptions T:CoreGraphics.CGPdfTagProperties T:CoreGraphics.CGPdfTagType T:CoreGraphics.CGPdfTagType_Extensions +T:CoreGraphics.CGRenderingBufferProvider.LockPointerCallback +T:CoreGraphics.CGRenderingBufferProvider.ReleaseInfoCallback +T:CoreGraphics.CGRenderingBufferProvider.UnlockPointerCallback T:CoreGraphics.CGSession T:CoreGraphics.CGSessionKeys T:CoreGraphics.CGSessionProperties T:CoreGraphics.CGToneMapping T:CoreGraphics.CGToneMappingOptionKeys -T:CoreGraphics.CGToneMappingOptions T:CoreGraphics.MatrixOrder T:CoreGraphics.NMatrix2 T:CoreGraphics.NMatrix3 diff --git a/tests/introspection/ApiCMAttachmentTest.cs b/tests/introspection/ApiCMAttachmentTest.cs index 0126d428cc0e..0b685316812f 100644 --- a/tests/introspection/ApiCMAttachmentTest.cs +++ b/tests/introspection/ApiCMAttachmentTest.cs @@ -248,6 +248,7 @@ protected virtual bool Skip (string nativeName) #endif return false; case "MTLIOCompressionContext": + case "CGRenderingBufferProvider": return true; default: return false; diff --git a/tests/monotouch-test/CoreGraphics/BitmapContextTest.cs b/tests/monotouch-test/CoreGraphics/BitmapContextTest.cs index f08bb0e1e197..6f237c5d8ccb 100644 --- a/tests/monotouch-test/CoreGraphics/BitmapContextTest.cs +++ b/tests/monotouch-test/CoreGraphics/BitmapContextTest.cs @@ -8,6 +8,8 @@ // using System; +using System.Runtime.InteropServices; + using Foundation; using CoreGraphics; using NUnit.Framework; @@ -110,5 +112,166 @@ public void ToImage () Assert.Null (c.ToImage (), "ToImage/Disposed"); } } + + [Test] + public void CreateAdaptive () + { + TestRuntime.AssertXcodeVersion (26, 0); + + nuint width = 256; + nuint height = 256; + + { + using var context = CGBitmapContext.Create (width, height, (NSDictionary?) null, null, null, null, null); + Assert.NotNull (context, "Context#1"); + } + + { + var calledOnResolve = false; + var calledOnAllocate = false; + var calledOnFree = false; + var calledOnError = false; + using var context = CGBitmapContext.Create (width, height, (CGAdaptiveOptions?) null, + (ref CGContentInfo info, ref CGBitmapParameters parameters) => { + Console.WriteLine ($"CreateAdaptive () OnResolve#2 info={info} parameters={parameters}"); + calledOnResolve = true; + return true; + }, + (ref CGContentInfo info, ref CGBitmapParameters parameters) => { + Console.WriteLine ($"CreateAdaptive () OnAllocate#2 info={info} parameters={parameters}"); + calledOnAllocate = true; + return null; + }, + (CGRenderingBufferProvider renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { + Console.WriteLine ($"CreateAdaptive () OnFree#2 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + calledOnFree = true; + }, + (NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { + Console.WriteLine ($"CreateAdaptive () OnError#2 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + calledOnError = true; + }); + + Assert.NotNull (context, "Context#2"); + + // This fails because onAllocate returns null + using var img = context.ToImage (); + Assert.Null (img, "ToImage"); + + Assert.That (calledOnResolve, Is.True, "calledOnResolve#2"); + Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#2"); + Assert.That (calledOnFree, Is.False, "calledOnFree#2"); + Assert.That (calledOnError, Is.True, "calledOnError#2"); + } + + { + var calledOnResolve = false; + var calledOnAllocate = false; + var calledOnFree = false; + var calledOnError = false; + var options = new CGAdaptiveOptions () { + MaximumBitDepth = CGComponent.Float16Bit, + }; + using var context = CGBitmapContext.Create (width, height, options, + (ref CGContentInfo info, ref CGBitmapParameters parameters) => { + Console.WriteLine ($"CreateAdaptive () OnResolve#3 info={info} parameters={parameters}"); + calledOnResolve = true; + return true; + }, + (ref CGContentInfo info, ref CGBitmapParameters parameters) => { + Console.WriteLine ($"CreateAdaptive () OnAllocate#3 info={info} parameters={parameters}"); + calledOnAllocate = true; + return null; + }, + (CGRenderingBufferProvider renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { + Console.WriteLine ($"CreateAdaptive () OnFree#3 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + calledOnFree = true; + }, + (NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { + Console.WriteLine ($"CreateAdaptive () OnError#3 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + calledOnError = true; + }); + + Assert.NotNull (context, "Context#3"); + + // This fails because onAllocate returns null + using var img = context.ToImage (); + Assert.Null (img, "ToImage"); + + Assert.That (calledOnResolve, Is.True, "calledOnResolve#3"); + Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#3"); + Assert.That (calledOnFree, Is.False, "calledOnFree#3"); + Assert.That (calledOnError, Is.True, "calledOnError#3"); + } + + + { + var calledOnLockPointer = false; + var calledOnUnlockPointer = false; + var calledOnReleaseInfo = false; + const int renderingBufferProviderSize = 512; + using (var renderingBufferProvider = CGRenderingBufferProvider.Create (IntPtr.Zero, renderingBufferProviderSize, + lockPointer: (info) => { + calledOnLockPointer = true; + var rv = Marshal.AllocHGlobal (renderingBufferProviderSize); + // Console.WriteLine ($"CreateAdaptive () OnLockPointer#4 ({info}) => {rv}"); + return rv; + }, + unlockPointer: (info, pointer) => { + // Console.WriteLine ($"CreateAdaptive () OnUnlockPointer#4 ({info}, {pointer})"); + calledOnUnlockPointer = true; + Marshal.FreeHGlobal (pointer); + }, + releaseInfo: (info) => { + // Console.WriteLine ($"CreateAdaptive () OnReleaseInfo#4 ({info})"); + calledOnReleaseInfo = true; + } + )) { + Assert.That (renderingBufferProvider, Is.Not.Null, "RenderingBufferProvider"); + + var calledOnResolve = false; + var calledOnAllocate = false; + var calledOnFree = false; + var calledOnError = false; + var options = new CGAdaptiveOptions () { + MaximumBitDepth = CGComponent.Float16Bit, + }; + + using (var context = CGBitmapContext.Create (width, height, options, + (ref CGContentInfo info, ref CGBitmapParameters parameters) => { + // Console.WriteLine ($"CreateAdaptive () OnResolve#4 info={info} parameters={parameters}"); + calledOnResolve = true; + return true; + }, + (ref CGContentInfo info, ref CGBitmapParameters parameters) => { + // Console.WriteLine ($"CreateAdaptive () OnAllocate#4 info={info} parameters={parameters}"); + calledOnAllocate = true; + return renderingBufferProvider; + }, + (CGRenderingBufferProvider renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { + // Console.WriteLine ($"CreateAdaptive () OnFree#4 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + calledOnFree = true; + }, + (NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { + // Console.WriteLine ($"CreateAdaptive () OnError#4 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + calledOnError = true; + })) { + + Assert.NotNull (context, "Context#4"); + + using var img = context.ToImage (); + Assert.NotNull (img, "ToImage"); + } + + Assert.That (calledOnResolve, Is.True, "calledOnResolve#4"); + Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#4"); + Assert.That (calledOnFree, Is.True, "calledOnFree#4"); + Assert.That (calledOnError, Is.False, "calledOnError#4"); + } + + Assert.That (calledOnLockPointer, Is.True, "calledOnLockPointer#4"); + Assert.That (calledOnUnlockPointer, Is.True, "calledOnUnlockPointer#4"); + Assert.That (calledOnReleaseInfo, Is.False, "calledOnReleaseInfo#4"); + } + } } } diff --git a/tests/monotouch-test/CoreGraphics/CGBitmapInfoTest.cs b/tests/monotouch-test/CoreGraphics/CGBitmapInfoTest.cs new file mode 100644 index 000000000000..beb200179142 --- /dev/null +++ b/tests/monotouch-test/CoreGraphics/CGBitmapInfoTest.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using CoreGraphics; + +namespace MonoTouchFixtures.CoreGraphics { + + [TestFixture] + [Preserve (AllMembers = true)] + public class CGBitmapInfoTest { + [Test] + public void Extensions () + { + Assert.AreEqual (CGImageAlphaInfo.PremultipliedLast, ((CGBitmapInfo) CGImageAlphaInfo.PremultipliedLast).GetAlphaInfo (), "GetAlphaInfo"); + Assert.AreEqual (CGImageComponentInfo.Float, ((CGBitmapInfo) CGImageComponentInfo.Float).GetComponentInfo (), "CGImageComponentInfo"); + Assert.AreEqual (CGImageByteOrderInfo.ByteOrder32Little, ((CGBitmapInfo) CGImageByteOrderInfo.ByteOrder32Little).GetByteOrderInfo (), "CGImageByteOrderInfo"); + Assert.AreEqual (CGImagePixelFormatInfo.Rgb101010, ((CGBitmapInfo) CGImagePixelFormatInfo.Rgb101010).GetPixelFormatInfo (), "CGImagePixelFormatInfo"); + } + } +} diff --git a/tests/monotouch-test/CoreGraphics/CGBitmapParametersTest.cs b/tests/monotouch-test/CoreGraphics/CGBitmapParametersTest.cs new file mode 100644 index 000000000000..8cb40d127e82 --- /dev/null +++ b/tests/monotouch-test/CoreGraphics/CGBitmapParametersTest.cs @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using CoreFoundation; + +using CoreGraphics; + +namespace MonoTouchFixtures.CoreGraphics { + + [TestFixture] + [Preserve (AllMembers = true)] + public class CGBitmapParametersTest { + [Test] + public void DefaultValuesTest () + { + Assert.Multiple (() => { + var p = new CGBitmapParameters (); + Assert.AreEqual ((nuint) 0u, p.Width, "Width"); + Assert.AreEqual ((nuint) 0u, p.Height, "Height"); + Assert.AreEqual ((nuint) 0u, p.BytesPerPixel, "BytesPerPixel"); + Assert.AreEqual ((nuint) 0u, p.AlignedBytesPerRow, "AlignedBytesPerRow"); + Assert.AreEqual (default (CGComponent), p.Component, "Component"); + Assert.AreEqual (default (CGBitmapLayout), p.Layout, "Layout"); + Assert.AreEqual (default (CGImagePixelFormatInfo), p.Format, "Format"); + Assert.AreEqual (IntPtr.Zero, p.ColorSpaceHandle, "ColorSpaceHandle"); + Assert.AreEqual (false, p.HasPremultipliedAlpha, "HasPremultipliedAlpha"); + Assert.AreEqual ((CFByteOrder) 0, p.ByteOrder, "ByteOrder"); + Assert.AreEqual (0f, p.EdrTargetHeadroom, "EdrTargetHeadroom"); + }); + } + + [Test] + public void PropertySetGetTest () + { + Assert.Multiple (() => { + var p = new CGBitmapParameters (); + p.Width = 123u; + p.Height = 456u; + p.BytesPerPixel = 4u; + p.AlignedBytesPerRow = 512u; + p.Component = (CGComponent) 1; + p.Layout = (CGBitmapLayout) 2; + p.Format = (CGImagePixelFormatInfo) 3; + p.ColorSpaceHandle = new IntPtr (0xDEADBEEF); + p.HasPremultipliedAlpha = true; + p.ByteOrder = CFByteOrder.LittleEndian; + p.EdrTargetHeadroom = 1.5f; + + Assert.AreEqual ((nuint) 123u, p.Width, "Width"); + Assert.AreEqual ((nuint) 456u, p.Height, "Height"); + Assert.AreEqual ((nuint) 4u, p.BytesPerPixel, "BytesPerPixel"); + Assert.AreEqual ((nuint) 512u, p.AlignedBytesPerRow, "AlignedBytesPerRow"); + Assert.AreEqual ((CGComponent) 1, p.Component, "Component"); + Assert.AreEqual ((CGBitmapLayout) 2, p.Layout, "Layout"); + Assert.AreEqual ((CGImagePixelFormatInfo) 3, p.Format, "Format"); + Assert.AreEqual (new IntPtr (0xDEADBEEF), p.ColorSpaceHandle, "ColorSpaceHandle"); + Assert.IsTrue (p.HasPremultipliedAlpha, "HasPremultipliedAlpha"); + Assert.AreEqual (CFByteOrder.LittleEndian, p.ByteOrder, "ByteOrder"); + Assert.AreEqual (1.5f, p.EdrTargetHeadroom, "EdrTargetHeadroom"); + }); + } + + [Test] + public void HasPremultipliedAlphaFalseTest () + { + var p = new CGBitmapParameters (); + p.HasPremultipliedAlpha = false; + Assert.IsFalse (p.HasPremultipliedAlpha, "HasPremultipliedAlpha"); + } + + [Test] + public void ByteOrderTest () + { + var p = new CGBitmapParameters (); + p.ByteOrder = CFByteOrder.BigEndian; + Assert.AreEqual (CFByteOrder.BigEndian, p.ByteOrder, "ByteOrder"); + p.ByteOrder = CFByteOrder.LittleEndian; + Assert.AreEqual (CFByteOrder.LittleEndian, p.ByteOrder, "ByteOrder"); + } + } +} diff --git a/tests/monotouch-test/CoreGraphics/CGContentInfoTest.cs b/tests/monotouch-test/CoreGraphics/CGContentInfoTest.cs new file mode 100644 index 000000000000..0e0416e93e00 --- /dev/null +++ b/tests/monotouch-test/CoreGraphics/CGContentInfoTest.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using Foundation; +using CoreGraphics; +using NUnit.Framework; +using ObjCRuntime; + +namespace MonoTouchFixtures.CoreGraphics { + [TestFixture] + [Preserve (AllMembers = true)] + public class CGContentInfoTest { + [Test] + public void DefaultValuesTest () + { + var c = new CGContentInfo (); + Assert.AreEqual (default (CGComponent), c.DeepestImageComponent, "DeepestImageComponent"); + Assert.AreEqual (default (CGColorModel), c.ContentColorModels, "ContentColorModels"); + Assert.IsFalse (c.HasWideGamut, "HasWideGamut"); + Assert.IsFalse (c.HasTransparency, "HasTransparency"); + Assert.AreEqual (0f, c.LargestContentHeadroom, "LargestContentHeadroom"); + } + + [Test] + public void PropertySetGetTest () + { + var c = new CGContentInfo (); + c.DeepestImageComponent = (CGComponent) 2; + c.ContentColorModels = (CGColorModel) 3; + c.HasWideGamut = true; + c.HasTransparency = true; + c.LargestContentHeadroom = 1.25f; + + Assert.AreEqual ((CGComponent) 2, c.DeepestImageComponent, "DeepestImageComponent"); + Assert.AreEqual ((CGColorModel) 3, c.ContentColorModels, "ContentColorModels"); + Assert.IsTrue (c.HasWideGamut, "HasWideGamut"); + Assert.IsTrue (c.HasTransparency, "HasTransparency"); + Assert.AreEqual (1.25f, c.LargestContentHeadroom, "LargestContentHeadroom"); + } + + [Test] + public void HasWideGamutFalseTest () + { + var c = new CGContentInfo (); + c.HasWideGamut = false; + Assert.IsFalse (c.HasWideGamut, "HasWideGamut"); + } + + [Test] + public void HasTransparencyFalseTest () + { + var c = new CGContentInfo (); + c.HasTransparency = false; + Assert.IsFalse (c.HasTransparency, "HasTransparency"); + } + } +} diff --git a/tests/monotouch-test/CoreGraphics/CGContentToneMappingInfoTest.cs b/tests/monotouch-test/CoreGraphics/CGContentToneMappingInfoTest.cs new file mode 100644 index 000000000000..c98155dea2b0 --- /dev/null +++ b/tests/monotouch-test/CoreGraphics/CGContentToneMappingInfoTest.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using Foundation; +using CoreGraphics; +using NUnit.Framework; +using ObjCRuntime; + +namespace MonoTouchFixtures.CoreGraphics { + [TestFixture] + [Preserve (AllMembers = true)] + public class CGContentToneMappingInfoTest { + [Test] + public void DefaultValuesTest () + { + TestRuntime.AssertXcodeVersion (16, 0); + + var t = new CGContentToneMappingInfo (); + Assert.AreEqual (CGToneMapping.Default, t.Method, "Method"); + Assert.IsNull (t.Options, "Options"); + Assert.IsNull (t.ToneMappingOptions, "ToneMappingOptions"); + } + + [Test] + public void PropertySetGetTest () + { + TestRuntime.AssertXcodeVersion (16, 0); + + var t = new CGContentToneMappingInfo (); + t.Method = CGToneMapping.ImageSpecificLumaScaling; + Assert.AreEqual (CGToneMapping.ImageSpecificLumaScaling, t.Method, "Method#1"); + t.Method = CGToneMapping.Default; + Assert.AreEqual (CGToneMapping.Default, t.Method, "Method#2"); + + using var dict = new NSDictionary (); + t.Options = dict; + Assert.AreSame (dict, t.Options, "Options#1"); + var toneMappingOptions = t.ToneMappingOptions!; + Assert.AreSame (dict, toneMappingOptions.Dictionary, "ToneMappingOptions#1"); + + Assert.IsFalse (toneMappingOptions.Use100nitsHlgOotf.HasValue, "ToneMappingOptions.Use100nitsHlgOotf #1"); + Assert.IsFalse (toneMappingOptions.UseBT1886ForCoreVideoGamma.HasValue, "ToneMappingOptions.UseBT1886ForCoreVideoGamma #1"); + Assert.IsFalse (toneMappingOptions.SkipBoostToHdr.HasValue, "ToneMappingOptions.SkipBoostToHdr #1"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaDefog.HasValue, "ToneMappingOptions.ExrToneMappingGammaDefog #1"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaExposure.HasValue, "ToneMappingOptions.ExrToneMappingGammaExposure #1"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaKneeLow.HasValue, "ToneMappingOptions.ExrToneMappingGammaKneeLow #1"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaKneeHigh.HasValue, "ToneMappingOptions.ExrToneMappingGammaKneeHigh #1"); + + using var mutableDict = new NSMutableDictionary (); + t.Options = mutableDict; + Assert.AreSame (mutableDict, t.Options, "Options#2"); + toneMappingOptions = t.ToneMappingOptions!; + Assert.AreSame (mutableDict, toneMappingOptions.Dictionary, "ToneMappingOptions#2"); + + Assert.IsFalse (toneMappingOptions.Use100nitsHlgOotf.HasValue, "ToneMappingOptions.Use100nitsHlgOotf #2"); + Assert.IsFalse (toneMappingOptions.UseBT1886ForCoreVideoGamma.HasValue, "ToneMappingOptions.UseBT1886ForCoreVideoGamma #2"); + Assert.IsFalse (toneMappingOptions.SkipBoostToHdr.HasValue, "ToneMappingOptions.SkipBoostToHdr #2"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaDefog.HasValue, "ToneMappingOptions.ExrToneMappingGammaDefog #2"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaExposure.HasValue, "ToneMappingOptions.ExrToneMappingGammaExposure #2"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaKneeLow.HasValue, "ToneMappingOptions.ExrToneMappingGammaKneeLow #2"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaKneeHigh.HasValue, "ToneMappingOptions.ExrToneMappingGammaKneeHigh #2"); + + toneMappingOptions.Use100nitsHlgOotf = false; + toneMappingOptions.UseBT1886ForCoreVideoGamma = true; + toneMappingOptions.SkipBoostToHdr = null; + toneMappingOptions.ExrToneMappingGammaDefog = 1.0f; + toneMappingOptions.ExrToneMappingGammaExposure = -1.0f; + toneMappingOptions.ExrToneMappingGammaKneeLow = 0.0f; + toneMappingOptions.ExrToneMappingGammaKneeHigh = null; + + Assert.IsFalse (toneMappingOptions.Use100nitsHlgOotf.Value, "ToneMappingOptions.Use100nitsHlgOotf #3"); + Assert.IsTrue (toneMappingOptions.UseBT1886ForCoreVideoGamma.Value, "ToneMappingOptions.UseBT1886ForCoreVideoGamma #3"); + Assert.IsFalse (toneMappingOptions.SkipBoostToHdr.HasValue, "ToneMappingOptions.SkipBoostToHdr #3"); + Assert.AreEqual (1.0f, toneMappingOptions.ExrToneMappingGammaDefog.Value, "ToneMappingOptions.ExrToneMappingGammaDefog #3"); + Assert.AreEqual (-1.0f, toneMappingOptions.ExrToneMappingGammaExposure.Value, "ToneMappingOptions.ExrToneMappingGammaExposure #3"); + Assert.AreEqual (0.0f, toneMappingOptions.ExrToneMappingGammaKneeLow.Value, "ToneMappingOptions.ExrToneMappingGammaKneeLow #3"); + Assert.IsFalse (toneMappingOptions.ExrToneMappingGammaKneeHigh.HasValue, "ToneMappingOptions.ExrToneMappingGammaKneeHigh #3"); + } + } +} diff --git a/tests/monotouch-test/CoreGraphics/CGImageTest.cs b/tests/monotouch-test/CoreGraphics/CGImageTest.cs index ba4b7d25dddb..9977228886f0 100644 --- a/tests/monotouch-test/CoreGraphics/CGImageTest.cs +++ b/tests/monotouch-test/CoreGraphics/CGImageTest.cs @@ -64,6 +64,22 @@ public void ContentHeadroom () Assert.IsFalse (copy.ContainsImageSpecificToneMappingMetadata, "ContainsImageSpecificToneMappingMetadata B"); Assert.AreEqual (4.92610836f, CGImage.DefaultHdrImageContentHeadroom, "DefaultHdrImageContentHeadroom"); + + if (TestRuntime.CheckXcodeVersion (26, 0)) { + Assert.That (copy.CalculatedContentHeadroom, Is.EqualTo (0.0f), "CalculatedContentHeadroom B"); + Assert.That (copy.ContentAverageLightLevel, Is.EqualTo (0.0f), "ContentAverageLightLevel B"); + Assert.That (copy.CalculatedContentAverageLightLevel, Is.Not.EqualTo (0.0f), "CalculatedContentAverageLightLevel B"); + + using var copy2 = img.CopyWithContentAverageLightLevel (0.75f); + Assert.That (copy2.CalculatedContentHeadroom, Is.EqualTo (0.0f), "CalculatedContentHeadroom C"); + Assert.That (copy2.ContentAverageLightLevel, Is.Not.EqualTo (0.0f), "ContentAverageLightLevel C"); + Assert.That (copy2.CalculatedContentAverageLightLevel, Is.Not.EqualTo (0.0f), "CalculatedContentAverageLightLevel C"); + + using var copy3 = img.CopyWithCalculatedHdrStats (); + Assert.That (copy3.CalculatedContentHeadroom, Is.EqualTo (0.0f), "CalculatedContentHeadroom D"); + Assert.That (copy3.ContentAverageLightLevel, Is.Not.EqualTo (0.0f), "ContentAverageLightLevel D"); + Assert.That (copy3.CalculatedContentAverageLightLevel, Is.Not.EqualTo (0.0f), "CalculatedContentAverageLightLevel D"); + } }); } } diff --git a/tests/monotouch-test/CoreGraphics/CGRenderingBufferProviderTest.cs b/tests/monotouch-test/CoreGraphics/CGRenderingBufferProviderTest.cs new file mode 100644 index 000000000000..f09328ab1ebd --- /dev/null +++ b/tests/monotouch-test/CoreGraphics/CGRenderingBufferProviderTest.cs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; + +using Foundation; +using CoreGraphics; +using NUnit.Framework; + +namespace MonoTouchFixtures.CoreGraphics { + + [TestFixture] + [Preserve (AllMembers = true)] + public class CGRenderingBufferProviderTest { + [Test] + public void CreateWithCFData_ReturnsNull () + { + TestRuntime.AssertXcodeVersion (26, 0); + + using var data = new NSMutableData (10); // Create a small CFMutableDataRef + var provider = CGRenderingBufferProvider.Create (data); + Assert.That (provider, Is.Null, "This shouldn't work"); // doesn't work because I have no idea what to put in the NSData to make it valid + } + + [Test] + public void SizeProperty_DoesNotThrow () + { + TestRuntime.AssertXcodeVersion (26, 0); + + var size = 512; + var calledOnLockPointer = false; + var calledOnUnlockPointer = false; + var calledOnReleaseInfo = false; + var provider = CGRenderingBufferProvider.Create ((nint) 0x0ee1f00d, (nuint) size, + lockPointer: (info) => { + calledOnLockPointer = true; + var rv = Marshal.AllocHGlobal (size); + // Console.WriteLine ($"CreateAdaptive () OnLockPointer#4 ({info}) => {rv}"); + return rv; + }, + unlockPointer: (info, pointer) => { + // Console.WriteLine ($"CreateAdaptive () OnUnlockPointer#4 ({info}, {pointer})"); + calledOnUnlockPointer = true; + Marshal.FreeHGlobal (pointer); + }, + releaseInfo: (info) => { + // Console.WriteLine ($"CreateAdaptive () OnReleaseInfo#4 ({info})"); + calledOnReleaseInfo = true; + }); + Assert.That (provider, Is.Not.Null, "provider"); + Assert.That (provider.Size, Is.EqualTo ((nuint) size), "size"); + Assert.That (calledOnLockPointer, Is.EqualTo (false), "calledOnLockPointer"); + Assert.That (calledOnUnlockPointer, Is.EqualTo (false), "calledOnUnlockPointer"); + Assert.That (calledOnReleaseInfo, Is.EqualTo (false), "calledOnReleaseInfo"); + } + + [Test] + public void GetTypeId () + { + TestRuntime.AssertXcodeVersion (26, 0); + + Assert.DoesNotThrow (() => { + var typeId = CGRenderingBufferProvider.GetTypeId (); + Assert.That (typeId, Is.GreaterThan ((nint) 0), "GetTypeId"); + }); + } + } +} diff --git a/tests/monotouch-test/CoreGraphics/CGToneMappingOptionsTest.cs b/tests/monotouch-test/CoreGraphics/CGToneMappingOptionsTest.cs new file mode 100644 index 000000000000..15a11ca20875 --- /dev/null +++ b/tests/monotouch-test/CoreGraphics/CGToneMappingOptionsTest.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; + +using Foundation; +using CoreGraphics; +using ObjCRuntime; + +using NUnit.Framework; + +namespace MonoTouchFixtures.CoreGraphics { + + [TestFixture] + [Preserve (AllMembers = true)] + public class CGToneMappingOptionsTest { + [Test] + public void DefaultOptions () + { + TestRuntime.AssertXcodeVersion (26, 0); + + var defaultOptions = CGToneMappingOptions.GetDefaultExrToneMappingGammaOptions (); + Assert.That (defaultOptions, Is.Not.Null, "Default"); + } + } +} diff --git a/tests/monotouch-test/CoreGraphics/ColorTest.cs b/tests/monotouch-test/CoreGraphics/ColorTest.cs index 247e0995341e..70f5fc5d7841 100644 --- a/tests/monotouch-test/CoreGraphics/ColorTest.cs +++ b/tests/monotouch-test/CoreGraphics/ColorTest.cs @@ -121,5 +121,24 @@ public void CreateByMatchingToColorSpace () Assert.IsNotNull (c2, "2"); } } + + [Test] + public void ContentHeadroom () + { + TestRuntime.AssertXcodeVersion (26, 0); + + using (var color = CGColor.CreateWithContentHeadroom (0.5f, null, 0.3f, 0.4f, 0.5f, 0.6f)) { + Assert.IsNull (color, "color #1"); + } + + using var headroomCapableColorspace = CGColorSpace.CreateWithName (CGColorSpaceNames.ExtendedSrgb); + using (var color = CGColor.CreateWithContentHeadroom (0.0f, headroomCapableColorspace, 0.3f, 0.4f, 0.5f, 0.6f)) { + Assert.IsNotNull (color, "color #2"); + Assert.That (color.ContentHeadroom, Is.EqualTo (0.0f), "ContentHeadroom #2"); + Assert.That (color.NumberOfComponents, Is.EqualTo ((nint) 4), "NumberOfComponents #2"); + Assert.That (color.Components, Is.EqualTo (new nfloat [] { 0.3f, 0.4f, 0.5f, 0.6f }), "Components #2"); + Assert.That (color.Alpha, Is.EqualTo ((nfloat) 0.6f), "Alpha #2"); + } + } } } diff --git a/tests/monotouch-test/CoreGraphics/FunctionTest.cs b/tests/monotouch-test/CoreGraphics/FunctionTest.cs index 7dfbe854e88a..acddc6a49922 100644 --- a/tests/monotouch-test/CoreGraphics/FunctionTest.cs +++ b/tests/monotouch-test/CoreGraphics/FunctionTest.cs @@ -9,6 +9,8 @@ #if !MONOMAC using System; +using System.Collections.Generic; + using Foundation; using CoreGraphics; using UIKit; @@ -43,31 +45,52 @@ public unsafe override void Draw (CGRect rect) var start = new CGPoint (rect.Left, rect.Bottom); var end = new CGPoint (rect.Left, rect.Top); - var domain = new nfloat [] { 0f, 1f }; - var range = new nfloat [] { 0f, 1f, 0f, 1f }; using (var context = UIGraphics.GetCurrentContext ()) using (var rgb = CGColorSpace.CreateDeviceGray ()) - using (var shadingFunction = new CGFunction (domain, range, Shading)) + using (var shadingFunction = CreateSlopedFunction (Shaded)) using (var shading = CGShading.CreateAxial (rgb, start, end, shadingFunction, true, false)) { context.DrawShading (shading); } base.Draw (rect); } + } - public unsafe void Shading (nfloat* data, nfloat* outData) - { - var p = data [0]; - outData [0] = 0.0f; - outData [1] = (1.0f - Slope (p, 2.0f)) * 0.5f; - Shaded (); + public unsafe static CGFunction CreateSlopedFunction (Action? shadedCallback, nint inputs = 1, nint outputs = 2) + { + if (inputs < 1 || outputs < 1) + throw new ArgumentOutOfRangeException (); + + var domain = new List (); + for (var i = 0; i < inputs; i++) { + domain.Add (0); + domain.Add (1); } + var range = new List (); + for (var i = 0; i < outputs; i++) { + range.Add (0); + range.Add (1); + } + return new CGFunction (domain.ToArray (), range.ToArray (), Shading); - public nfloat Slope (nfloat x, nfloat A) + nfloat Slope (nfloat x, nfloat A) { var p = Math.Pow (x, A); return (nfloat) (p / (p + Math.Pow (1.0f - x, A))); } + + void Shading (nfloat* data, nfloat* outData) + { + outData [0] = 0.0f; + for (var x = 0; x < inputs; x++) { + var p = data [x]; + for (var y = 1; y < outputs; y++) { + outData [y] = (1.0f - Slope (p, 2.0f)) * (1.0f / outputs) * y; + } + } + if (shadedCallback is not null) + shadedCallback (); + } } [Test] diff --git a/tests/monotouch-test/CoreGraphics/GradientTest.cs b/tests/monotouch-test/CoreGraphics/GradientTest.cs index 739beb03f9df..36a220fc181d 100644 --- a/tests/monotouch-test/CoreGraphics/GradientTest.cs +++ b/tests/monotouch-test/CoreGraphics/GradientTest.cs @@ -92,5 +92,33 @@ public void GradientDrawingOptions () // this would be "3" without a [Flags] attribute Assert.That (gdo.ToString (), Is.EqualTo ("DrawsBeforeStartLocation, DrawsAfterEndLocation"), "ToString/Flags"); } + + [Test] + public void CreateWithHeadroom () + { + TestRuntime.AssertXcodeVersion (26, 0); + + var colorComponents = new nfloat [] { + 0.1f, 0.2f, 0.3f, + 0.4f, 0.5f, 0.6f, + 0.7f, 0.8f, 0.9f, + }; + var locations = new nfloat [] { + 0, + 0.25f, + 1, + }; + + using var hdrCapableColorspace = CGColorSpace.CreateWithName (CGColorSpaceNames.DisplayP3_PQ); + Assert.IsTrue (hdrCapableColorspace.IsHdr, "IsHdr"); + using (var gradient = CGGradient.Create (0.5f, hdrCapableColorspace, colorComponents, locations)) { + Assert.IsNotNull (gradient, "Gradient #1"); + Assert.That (gradient.ContentHeadroom, Is.EqualTo (1.0f), "Gradient #1 - ContentHeadroom"); + } + + using (var gradient = CGGradient.Create (0.5f, null, colorComponents, locations)) { + Assert.IsNull (gradient, "Gradient #2"); + } + } } } diff --git a/tests/monotouch-test/CoreGraphics/ShadingTest.cs b/tests/monotouch-test/CoreGraphics/ShadingTest.cs new file mode 100644 index 000000000000..44220f4819c5 --- /dev/null +++ b/tests/monotouch-test/CoreGraphics/ShadingTest.cs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Runtime.InteropServices; +using Foundation; +using CoreGraphics; +using ObjCRuntime; +using NUnit.Framework; + +#if HAS_UIKIT +using UIKit; +#endif + +namespace MonoTouchFixtures.CoreGraphics { + + [TestFixture] + [Preserve (AllMembers = true)] + public class CGShadingTest { +#if HAS_UIKIT + [Test] + public void CreateAxialWithContentHeadroom () + { + CreateShadingWithContentHeadroomTest ((size, hdrCapableColorspace, function) => { + var start = new CGPoint (0, 0); + var end = new CGPoint (size.Height, size.Width); + + return CGShading.CreateAxial (0.5f, hdrCapableColorspace, start, end, function, true, false); + }); + } + + [Test] + public void CreateRadialWithContentHeadroom () + { + CreateShadingWithContentHeadroomTest ((size, hdrCapableColorspace, function) => { + var start = new CGPoint (0, 0); + var startRadius = 16.0f; + var end = new CGPoint (size.Height, size.Width); + var endRadius = 32.0f; + + return CGShading.CreateRadial (0.5f, hdrCapableColorspace, start, startRadius, end, endRadius, function, true, false); + }); + } + + void CreateShadingWithContentHeadroomTest (Func createShading) + { + TestRuntime.AssertXcodeVersion (26, 0); + + var size = new CGSize (128, 128); + var functionCalled = false; + Exception? ex = null; + + using var renderer = new UIGraphicsImageRenderer (size); + using var img = renderer.CreateImage ((context) => { + try { + using var hdrCapableColorspace = CGColorSpace.CreateWithName (CGColorSpaceNames.DisplayP3_PQ); + Assert.IsTrue (hdrCapableColorspace.IsHdr, "IsHdr"); + + using var slopedFunction = FunctionTest.CreateSlopedFunction (() => functionCalled = true, 1, hdrCapableColorspace.Components + 1); + + using var shading = createShading (size, hdrCapableColorspace, slopedFunction); + context.CGContext.DrawShading (shading); + } catch (Exception e) { + ex = e; + } + }); + + Assert.IsTrue (functionCalled, "Function called"); + Assert.IsNull (ex, "Exception"); + } +#endif + } +} diff --git a/tests/monotouch-test/GlobalUsings.cs b/tests/monotouch-test/GlobalUsings.cs new file mode 100644 index 000000000000..d833e9fc27ec --- /dev/null +++ b/tests/monotouch-test/GlobalUsings.cs @@ -0,0 +1,6 @@ +global using System; + +global using Foundation; +global using ObjCRuntime; + +global using NUnit.Framework; diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreGraphics.todo b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreGraphics.todo deleted file mode 100644 index 8e8e0f1ee6cd..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-CoreGraphics.todo +++ /dev/null @@ -1,34 +0,0 @@ -!missing-enum! CGBitmapLayout not bound -!missing-enum! CGColorModel not bound -!missing-enum! CGComponent not bound -!missing-enum! CGImageComponentInfo not bound -!missing-field! kCGAdaptiveMaximumBitDepth not bound -!missing-field! kCGContentAverageLightLevel not bound -!missing-field! kCGContentAverageLightLevelNits not bound -!missing-field! kCGDynamicRangeConstrained not bound -!missing-field! kCGDynamicRangeHigh not bound -!missing-field! kCGDynamicRangeStandard not bound -!missing-field! kCGPreferredDynamicRange not bound -!missing-pinvoke! CGBitmapContextCreateAdaptive is not bound -!missing-pinvoke! CGColorCreateWithContentHeadroom is not bound -!missing-pinvoke! CGColorGetContentHeadroom is not bound -!missing-pinvoke! CGContextGetContentToneMappingInfo is not bound -!missing-pinvoke! CGContextSetContentToneMappingInfo is not bound -!missing-pinvoke! CGContextSynchronizeAttributes is not bound -!missing-pinvoke! CGEXRToneMappingGammaGetDefaultOptions is not bound -!missing-pinvoke! CGImageCalculateContentAverageLightLevel is not bound -!missing-pinvoke! CGImageCalculateContentHeadroom is not bound -!missing-pinvoke! CGImageCreateCopyWithCalculatedHDRStats is not bound -!missing-pinvoke! CGImageCreateCopyWithContentAverageLightLevel is not bound -!missing-pinvoke! CGImageGetContentAverageLightLevel is not bound -!missing-pinvoke! CGRenderingBufferLockBytePtr is not bound -!missing-pinvoke! CGRenderingBufferProviderCreate is not bound -!missing-pinvoke! CGRenderingBufferProviderCreateWithCFData is not bound -!missing-pinvoke! CGRenderingBufferProviderGetSize is not bound -!missing-pinvoke! CGRenderingBufferProviderGetTypeID is not bound -!missing-pinvoke! CGRenderingBufferUnlockBytePtr is not bound -!missing-pinvoke! CGGradientCreateWithContentHeadroom is not bound -!missing-pinvoke! CGGradientGetContentHeadroom is not bound -!missing-pinvoke! CGShadingCreateAxialWithContentHeadroom is not bound -!missing-pinvoke! CGShadingCreateRadialWithContentHeadroom is not bound -!missing-pinvoke! CGShadingGetContentHeadroom is not bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-CoreFoundation.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-CoreFoundation.ignore index 63cf707b6bc0..f18340336cbb 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/common-CoreFoundation.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/common-CoreFoundation.ignore @@ -78,9 +78,12 @@ !missing-pinvoke! CFAllocatorReallocateTyped is not bound !missing-pinvoke! CFAllocatorSetDefault is not bound +## We've named the CFByteOrder enum slightly differently than it shows up in the headers +!missing-enum! __CFByteOrder not bound +!unknown-native-enum! CFByteOrder bound + ## unsorted -!missing-enum! __CFByteOrder not bound !missing-enum! CFCalendarUnit not bound !missing-enum! CFCharacterSetPredefinedSet not bound !missing-enum! CFDataSearchFlags not bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-CoreGraphics.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-CoreGraphics.ignore index a32969807625..08b2f0b58160 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/common-CoreGraphics.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/common-CoreGraphics.ignore @@ -12,7 +12,6 @@ ## unsorted -!missing-enum! CGBitmapInfo not bound !missing-enum! CGError not bound !missing-enum! CGFontPostScriptFormat not bound !missing-field! CGAffineTransformIdentity not bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreGraphics.todo b/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreGraphics.todo deleted file mode 100644 index 8e8e0f1ee6cd..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreGraphics.todo +++ /dev/null @@ -1,34 +0,0 @@ -!missing-enum! CGBitmapLayout not bound -!missing-enum! CGColorModel not bound -!missing-enum! CGComponent not bound -!missing-enum! CGImageComponentInfo not bound -!missing-field! kCGAdaptiveMaximumBitDepth not bound -!missing-field! kCGContentAverageLightLevel not bound -!missing-field! kCGContentAverageLightLevelNits not bound -!missing-field! kCGDynamicRangeConstrained not bound -!missing-field! kCGDynamicRangeHigh not bound -!missing-field! kCGDynamicRangeStandard not bound -!missing-field! kCGPreferredDynamicRange not bound -!missing-pinvoke! CGBitmapContextCreateAdaptive is not bound -!missing-pinvoke! CGColorCreateWithContentHeadroom is not bound -!missing-pinvoke! CGColorGetContentHeadroom is not bound -!missing-pinvoke! CGContextGetContentToneMappingInfo is not bound -!missing-pinvoke! CGContextSetContentToneMappingInfo is not bound -!missing-pinvoke! CGContextSynchronizeAttributes is not bound -!missing-pinvoke! CGEXRToneMappingGammaGetDefaultOptions is not bound -!missing-pinvoke! CGImageCalculateContentAverageLightLevel is not bound -!missing-pinvoke! CGImageCalculateContentHeadroom is not bound -!missing-pinvoke! CGImageCreateCopyWithCalculatedHDRStats is not bound -!missing-pinvoke! CGImageCreateCopyWithContentAverageLightLevel is not bound -!missing-pinvoke! CGImageGetContentAverageLightLevel is not bound -!missing-pinvoke! CGRenderingBufferLockBytePtr is not bound -!missing-pinvoke! CGRenderingBufferProviderCreate is not bound -!missing-pinvoke! CGRenderingBufferProviderCreateWithCFData is not bound -!missing-pinvoke! CGRenderingBufferProviderGetSize is not bound -!missing-pinvoke! CGRenderingBufferProviderGetTypeID is not bound -!missing-pinvoke! CGRenderingBufferUnlockBytePtr is not bound -!missing-pinvoke! CGGradientCreateWithContentHeadroom is not bound -!missing-pinvoke! CGGradientGetContentHeadroom is not bound -!missing-pinvoke! CGShadingCreateAxialWithContentHeadroom is not bound -!missing-pinvoke! CGShadingCreateRadialWithContentHeadroom is not bound -!missing-pinvoke! CGShadingGetContentHeadroom is not bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-CoreGraphics.todo b/tests/xtro-sharpie/api-annotations-dotnet/macOS-CoreGraphics.todo deleted file mode 100644 index 8e8e0f1ee6cd..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-CoreGraphics.todo +++ /dev/null @@ -1,34 +0,0 @@ -!missing-enum! CGBitmapLayout not bound -!missing-enum! CGColorModel not bound -!missing-enum! CGComponent not bound -!missing-enum! CGImageComponentInfo not bound -!missing-field! kCGAdaptiveMaximumBitDepth not bound -!missing-field! kCGContentAverageLightLevel not bound -!missing-field! kCGContentAverageLightLevelNits not bound -!missing-field! kCGDynamicRangeConstrained not bound -!missing-field! kCGDynamicRangeHigh not bound -!missing-field! kCGDynamicRangeStandard not bound -!missing-field! kCGPreferredDynamicRange not bound -!missing-pinvoke! CGBitmapContextCreateAdaptive is not bound -!missing-pinvoke! CGColorCreateWithContentHeadroom is not bound -!missing-pinvoke! CGColorGetContentHeadroom is not bound -!missing-pinvoke! CGContextGetContentToneMappingInfo is not bound -!missing-pinvoke! CGContextSetContentToneMappingInfo is not bound -!missing-pinvoke! CGContextSynchronizeAttributes is not bound -!missing-pinvoke! CGEXRToneMappingGammaGetDefaultOptions is not bound -!missing-pinvoke! CGImageCalculateContentAverageLightLevel is not bound -!missing-pinvoke! CGImageCalculateContentHeadroom is not bound -!missing-pinvoke! CGImageCreateCopyWithCalculatedHDRStats is not bound -!missing-pinvoke! CGImageCreateCopyWithContentAverageLightLevel is not bound -!missing-pinvoke! CGImageGetContentAverageLightLevel is not bound -!missing-pinvoke! CGRenderingBufferLockBytePtr is not bound -!missing-pinvoke! CGRenderingBufferProviderCreate is not bound -!missing-pinvoke! CGRenderingBufferProviderCreateWithCFData is not bound -!missing-pinvoke! CGRenderingBufferProviderGetSize is not bound -!missing-pinvoke! CGRenderingBufferProviderGetTypeID is not bound -!missing-pinvoke! CGRenderingBufferUnlockBytePtr is not bound -!missing-pinvoke! CGGradientCreateWithContentHeadroom is not bound -!missing-pinvoke! CGGradientGetContentHeadroom is not bound -!missing-pinvoke! CGShadingCreateAxialWithContentHeadroom is not bound -!missing-pinvoke! CGShadingCreateRadialWithContentHeadroom is not bound -!missing-pinvoke! CGShadingGetContentHeadroom is not bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/tvOS-CoreGraphics.todo b/tests/xtro-sharpie/api-annotations-dotnet/tvOS-CoreGraphics.todo deleted file mode 100644 index 8e8e0f1ee6cd..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/tvOS-CoreGraphics.todo +++ /dev/null @@ -1,34 +0,0 @@ -!missing-enum! CGBitmapLayout not bound -!missing-enum! CGColorModel not bound -!missing-enum! CGComponent not bound -!missing-enum! CGImageComponentInfo not bound -!missing-field! kCGAdaptiveMaximumBitDepth not bound -!missing-field! kCGContentAverageLightLevel not bound -!missing-field! kCGContentAverageLightLevelNits not bound -!missing-field! kCGDynamicRangeConstrained not bound -!missing-field! kCGDynamicRangeHigh not bound -!missing-field! kCGDynamicRangeStandard not bound -!missing-field! kCGPreferredDynamicRange not bound -!missing-pinvoke! CGBitmapContextCreateAdaptive is not bound -!missing-pinvoke! CGColorCreateWithContentHeadroom is not bound -!missing-pinvoke! CGColorGetContentHeadroom is not bound -!missing-pinvoke! CGContextGetContentToneMappingInfo is not bound -!missing-pinvoke! CGContextSetContentToneMappingInfo is not bound -!missing-pinvoke! CGContextSynchronizeAttributes is not bound -!missing-pinvoke! CGEXRToneMappingGammaGetDefaultOptions is not bound -!missing-pinvoke! CGImageCalculateContentAverageLightLevel is not bound -!missing-pinvoke! CGImageCalculateContentHeadroom is not bound -!missing-pinvoke! CGImageCreateCopyWithCalculatedHDRStats is not bound -!missing-pinvoke! CGImageCreateCopyWithContentAverageLightLevel is not bound -!missing-pinvoke! CGImageGetContentAverageLightLevel is not bound -!missing-pinvoke! CGRenderingBufferLockBytePtr is not bound -!missing-pinvoke! CGRenderingBufferProviderCreate is not bound -!missing-pinvoke! CGRenderingBufferProviderCreateWithCFData is not bound -!missing-pinvoke! CGRenderingBufferProviderGetSize is not bound -!missing-pinvoke! CGRenderingBufferProviderGetTypeID is not bound -!missing-pinvoke! CGRenderingBufferUnlockBytePtr is not bound -!missing-pinvoke! CGGradientCreateWithContentHeadroom is not bound -!missing-pinvoke! CGGradientGetContentHeadroom is not bound -!missing-pinvoke! CGShadingCreateAxialWithContentHeadroom is not bound -!missing-pinvoke! CGShadingCreateRadialWithContentHeadroom is not bound -!missing-pinvoke! CGShadingGetContentHeadroom is not bound