File: System\Windows\Media\Imaging\BitmapSourceSafeMILHandle.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
//
//
//
// Description:
//      A sub-class of SafeMILHandle that can estimate size for bitmap
//      source objects.
 
using MS.Internal;
 
using UnsafeNativeMethods = MS.Win32.PresentationCore.UnsafeNativeMethods;
 
namespace System.Windows.Media.Imaging
{
    /// <summary>
    /// Constructor which computes size of the handle and delegates
    /// to baseclass safe handle.
    /// </summary>
 
    internal class BitmapSourceSafeMILHandle : SafeMILHandle
    {
        static BitmapSourceSafeMILHandle() { }
 
        /// <summary>
        /// Use this constructor if the handle isn't ready yet and later
        /// set the handle with SetHandle.
        /// </summary>
        internal BitmapSourceSafeMILHandle() : base()
        {
        }
 
        /// <summary>
        /// Use this constructor if the handle exists at construction time.
        /// SafeMILHandle owns the release of the parameter.
        /// </summary>
        internal BitmapSourceSafeMILHandle(IntPtr handle) : base()
        {
            SetHandle(handle);
        }
 
        /// <summary>
        /// Use this constructor if the handle exists at construction time and memory pressure
        /// should be shared with another SafeMILHandle.
        /// SafeMILHandle owns the release of the parameter.
        /// </summary>
        internal BitmapSourceSafeMILHandle(IntPtr handle, SafeMILHandle copyMemoryPressureFrom)
            : this(handle)
        {
            CopyMemoryPressure(copyMemoryPressureFrom);
        }
 
        /// <summary>
        /// Calculate the rough size for this handle
        /// </summary>
        internal void CalculateSize()
        {
            UpdateEstimatedSize(ComputeEstimatedSize(handle));
        }
 
        /// <summary>
        /// Compute a rough estimate of the size in bytes for the image
        /// </summary>
        private static long ComputeEstimatedSize(IntPtr bitmapObject)
        {
            long estimatedSize = 0;
 
            if (bitmapObject != IntPtr.Zero)
            {
                IntPtr wicBitmap;
 
                //
                // QueryInterface for the bitmap source to ensure we are
                // calling through the right vtable on the pinvoke.
                //
 
                int hr = UnsafeNativeMethods.MILUnknown.QueryInterface(
                    bitmapObject,
                    ref _uuidBitmap,
                    out wicBitmap
                    );
 
                if (hr == HRESULT.S_OK)
                {
                    Debug.Assert(wicBitmap != IntPtr.Zero);
 
                    //
                    // The safe handle will release the ref added by the above QI
                    //
                    // There's no need to copy memory pressure. Partly because this SafeMILHandle
                    // is temporary and will be collected after this method returns, partly
                    // because there might no memory pressure calculated yet.
                    //
                    SafeMILHandle bitmapSourceSafeHandle = new SafeMILHandle(wicBitmap);
 
                    uint pixelWidth = 0;
                    uint pixelHeight = 0;
 
                    hr = UnsafeNativeMethods.WICBitmapSource.GetSize(
                        bitmapSourceSafeHandle,
                        out pixelWidth,
                        out pixelHeight);
 
                    if (hr == HRESULT.S_OK)
                    {
                        Guid guidFormat;
 
                        hr = UnsafeNativeMethods.WICBitmapSource.GetPixelFormat(bitmapSourceSafeHandle, out guidFormat);
                        if (hr == HRESULT.S_OK)
                        {
                            //
                            // Go to long space to avoid overflow and check for overflow
                            //
                            PixelFormat pixelFormat = new PixelFormat(guidFormat);
 
                            long scanlineSize = (long)pixelWidth * pixelFormat.InternalBitsPerPixel / 8;
 
                            //
                            // Check that scanlineSize is small enough that we can multiply by pixelHeight
                            // without an overflow.  Since pixelHeight is a 32-bit value and we multiply by pixelHeight,
                            // then we can only have a 32-bit scanlineSize.  Since we need a sign bit as well,
                            // we need to check that scanlineSize can fit in 30 bits.
                            //
 
                            if (scanlineSize < 0x40000000)
                            {
                                estimatedSize = pixelHeight * scanlineSize;
                            }
                        }
                    }
                }
            }
 
            return estimatedSize;
        }
 
        /// <summary>
        /// This is overridden to prevent JIT'ing due to new behavior in the CLR. (#708970)
        /// </summary>
        protected override bool ReleaseHandle()
        {
            return base.ReleaseHandle();
        }
 
        /// <summary>
        /// Guid for IWICBitmapSource
        /// </summary>
        private static Guid _uuidBitmap = MILGuidData.IID_IWICBitmapSource;
}
}