| File: System\Windows\Forms\ErrorProvider\ErrorProvider.IconRegion.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; namespace System.Windows.Forms; public partial class ErrorProvider { /// <summary> /// This represents the HRGN of icon. The region is calculate from the icon's mask. /// </summary> internal class IconRegion : IHandle<HICON> { private Region? _region; private readonly Icon _icon; public IconRegion(Icon icon, int currentDpi) { _icon = ScaleHelper.ScaleSmallIconToDpi(icon, currentDpi); } /// <summary> /// Returns the handle of the icon. /// </summary> public HICON Handle => (HICON)_icon.Handle; /// <summary> /// Returns the handle of the region. /// </summary> public unsafe Region Region { get { if (_region is not null) { return _region; } _region = new Region(new Rectangle(0, 0, 0, 0)); Size size = _icon.Size; Bitmap bitmap = _icon.ToBitmap(); using HBITMAP mask = (HBITMAP)ControlPaint.CreateHBitmapTransparencyMask(bitmap); bitmap.Dispose(); // It is been observed that users can use non standard size icons // (not a 16 bit multiples for width and height) and GetBitmapBits method allocate bytes in multiple // of 16 bits for each row. Following calculation is to get right width in bytes. int bitmapBitsAllocationSize = 16; // If width is not multiple of 16, we need to allocate BitmapBitsAllocationSize for remaining bits. int widthInBytes = 2 * ((size.Width + 15) / bitmapBitsAllocationSize); // its in bytes. using BufferScope<byte> bits = new(widthInBytes * size.Height); fixed (void* pbits = bits) { PInvoke.GetBitmapBits(mask, bits.Length, pbits); for (int y = 0; y < size.Height; y++) { for (int x = 0; x < size.Width; x++) { // see if bit is set in mask. bits in byte are reversed. 0 is black (set). if ((bits[y * widthInBytes + x / 8] & (1 << (7 - (x % 8)))) == 0) { _region.Union(new Rectangle(x, y, 1, 1)); } } } } _region.Intersect(new Rectangle(0, 0, size.Width, size.Height)); return _region; } } /// <summary> /// Return the size of the icon. /// </summary> public Size Size => _icon.Size; /// <summary> /// Release any resources held by this Object. /// </summary> public void Dispose() { _region?.Dispose(); _region = null; } } }