Skip to content

Commit ff0d8d0

Browse files
authored
Optimize OnDrawItem to prevent GDI resource exhaustion by caching scaled icon size (#14123)
* Optimize OnDrawItem to prevent GDI resource exhaustion by caching scaled icon size
1 parent af998d1 commit ff0d8d0

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

src/System.Windows.Forms.Design/src/System/Drawing/Design/CursorEditor.CursorUI.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ private class CursorUI : ListBox
1616
{
1717
private IWindowsFormsEditorService? _editorService;
1818
private readonly TypeConverter _cursorConverter;
19+
private readonly Dictionary<(Cursor cursor, int dpi), int> _cursorWidthCache = new();
1920

2021
public CursorUI()
2122
{
@@ -46,6 +47,7 @@ public void End()
4647
{
4748
_editorService = null;
4849
Value = null;
50+
_cursorWidthCache.Clear();
4951
}
5052

5153
protected override void OnClick(EventArgs e)
@@ -65,7 +67,7 @@ protected override void OnDrawItem(DrawItemEventArgs e)
6567
string? text = _cursorConverter.ConvertToString(cursor);
6668
Font font = e.Font!;
6769
using var brushText = e.ForeColor.GetCachedSolidBrushScope();
68-
var cursorWidth = ScaleHelper.ScaleSmallIconToDpi(Icon.FromHandle(cursor.Handle), DeviceDpi).Size.Width;
70+
int cursorWidth = GetCursorWidthForDpi(cursor, DeviceDpi);
6971

7072
e.DrawBackground();
7173
e.Graphics.FillRectangle(SystemBrushes.Control, new Rectangle(e.Bounds.X + 2, e.Bounds.Y + 2, cursorWidth, e.Bounds.Height - 4));
@@ -76,6 +78,23 @@ protected override void OnDrawItem(DrawItemEventArgs e)
7678
}
7779
}
7880

81+
private int GetCursorWidthForDpi(Cursor cursor, int dpi)
82+
{
83+
(Cursor cursor, int dpi) key = (cursor, dpi);
84+
if (_cursorWidthCache.TryGetValue(key, out int cursorWidth))
85+
{
86+
return cursorWidth;
87+
}
88+
89+
using Icon wrapper = Icon.FromHandle(cursor.Handle);
90+
using Icon clone = (Icon)wrapper.Clone();
91+
using Icon scaled = ScaleHelper.ScaleSmallIconToDpi(clone, dpi, alwaysCreateNew: true);
92+
93+
cursorWidth = scaled.Size.Width;
94+
_cursorWidthCache[key] = cursorWidth;
95+
return cursorWidth;
96+
}
97+
7998
protected override bool ProcessDialogKey(Keys keyData)
8099
{
81100
if ((keyData & Keys.KeyCode) == Keys.Return && (keyData & (Keys.Alt | Keys.Control)) == 0)

0 commit comments

Comments
 (0)