Skip to content

Optimize icon rendering: simplify logic and eliminate redundant calculations #13449

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

DJm00n
Copy link
Contributor

@DJm00n DJm00n commented May 13, 2025

  • Replaced HDC with Graphics in DrawIcon() for smoother GDI+ integration
  • Optimized Rectangle management – removed unnecessary variables, directly adjusting sizes
  • Simplified stretch logic (Inflate) – replaced complex calculations with a concise method call
  • Unified Draw() and DrawUnstretched() – now both directly call DrawIcon() without intermediate processing
  • Eliminated duplicate Matrix.Offset calculations, ensuring targetRect is adjusted directly
  • No functional changes, just cleaner, more maintainable code 🚀

Regression?

  • No
Microsoft Reviewers: Open in CodeFlow

…lations

- Replaced HDC with Graphics in DrawIcon() for smoother GDI+ integration
- Optimized Rectangle management – removed unnecessary variables, directly adjusting sizes
- Simplified stretch logic (Inflate) – replaced complex calculations with a concise method call
- Unified Draw() and DrawUnstretched() – now both directly call DrawIcon() without intermediate processing
- Eliminated duplicate Matrix.Offset calculations, ensuring targetRect is adjusted directly
- No functional changes, just cleaner, more maintainable code 🚀
Copy link

codecov bot commented May 13, 2025

Codecov Report

Attention: Patch coverage is 73.33333% with 4 lines in your changes missing coverage. Please review.

Project coverage is 76.60189%. Comparing base (5821493) to head (28c65ed).
Report is 29 commits behind head on main.

Additional details and impacted files
@@                 Coverage Diff                  @@
##                main      #13449          +/-   ##
====================================================
+ Coverage   62.21083%   76.60189%   +14.39105%     
====================================================
  Files           3213        3230          +17     
  Lines         638302      639043         +741     
  Branches       47201       47287          +86     
====================================================
+ Hits          397093      489519       +92426     
+ Misses        234153      145951       -88202     
+ Partials        7056        3573        -3483     
Flag Coverage Δ
Debug 76.60189% <73.33333%> (+14.39105%) ⬆️
integration 18.79058% <0.00000%> (+0.00179%) ⬆️
production 51.00214% <73.33333%> (+32.21335%) ⬆️
test 97.40411% <ø> (ø)
unit 48.40830% <73.33333%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@DJm00n
Copy link
Contributor Author

DJm00n commented Jun 5, 2025

@JeremyKuhne can you please take a look at this PR?

@JeremyKuhne
Copy link
Member

Looking, also letting CoPilot have a look.

@JeremyKuhne JeremyKuhne requested a review from Copilot June 5, 2025 17:20
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors Icon.DrawIcon to use Graphics instead of raw HDC, simplifies rectangle handling, and unifies the two Draw methods.

  • Replaced HDC-based drawing with Graphics and DeviceContextHdcScope
  • Collapsed manual width/height calculations into Rectangle operations (Inflate, Offset, Intersect)
  • Streamlined Draw and DrawUnstretched to forward directly to DrawIcon

Reviewed Changes

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

File Description
src/System.Drawing.Common/src/System/Drawing/Icon.cs Refactored DrawIcon signature/logic, simplified rectangle math
src/System.Drawing.Common/src/System/Drawing/Icon.cs (Draw overloads) Removed manual transform offset and copy, now calls DrawIcon directly

Comment on lines +278 to +280
imageRect.Inflate(stretch
? new Size(targetRect.Width / imageRect.Width, targetRect.Height / imageRect.Height)
: new Size(0, 0));
Copy link
Preview

Copilot AI Jun 5, 2025

Choose a reason for hiding this comment

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

Using Rectangle.Inflate with a scale factor (targetRect.Width / imageRect.Width) inflates the rectangle by pixel amounts rather than resizing it to the desired dimensions. This misuses Inflate for stretching logic and leads to incorrect sizing. Consider directly assigning imageRect.Size = targetRect.Size when stretch is true, or apply a proper scaling transformation.

Suggested change
imageRect.Inflate(stretch
? new Size(targetRect.Width / imageRect.Width, targetRect.Height / imageRect.Height)
: new Size(0, 0));
if (stretch)
{
imageRect.Size = targetRect.Size;
}

Copilot uses AI. Check for mistakes.


int drawWidth, drawHeight;
int clipWidth, clipHeight;
targetRect.Offset(Point.Round(graphics.Transform.Offset));
Copy link
Preview

Copilot AI Jun 5, 2025

Choose a reason for hiding this comment

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

[nitpick] Switching from truncating the graphics transform offset (previously via integer cast) to rounding may shift drawing by one pixel. If precise alignment is critical, use consistent rounding or truncation to match existing behavior or clearly document this change.

Suggested change
targetRect.Offset(Point.Round(graphics.Transform.Offset));
targetRect.Offset(Point.Truncate(graphics.Transform.Offset));

Copilot uses AI. Check for mistakes.

Copy link
Member

@JeremyKuhne JeremyKuhne left a comment

Choose a reason for hiding this comment

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

Love the cleanup here! If you can do this in steps where you move the calculations into a private helper first and create some good unit tests, I'd be happy to work with you to take this. (We're extremely resource bound for a while.)

Once the helper methods are collapsed to a single line there is no need to keep them.

Ultimately this helper code should really live in the Graphics class. It could also be further optimized by avoiding creating the Matrix object by using TransformElements.

@dotnet-policy-service dotnet-policy-service bot added the waiting-author-feedback The team requires more information from the author label Jun 5, 2025
@DJm00n
Copy link
Contributor Author

DJm00n commented Jun 5, 2025

@JeremyKuhne I also wanted to do the same changes in the System.Windows.Forms.Cursor class. How can I properly share code between them?

@dotnet-policy-service dotnet-policy-service bot added untriaged The team needs to look at this issue in the next triage and removed waiting-author-feedback The team requires more information from the author labels Jun 5, 2025
@JeremyKuhne
Copy link
Member

@DJm00n Presumably by putting the code in Graphics as they share the need for it to render?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Infrastructure untriaged The team needs to look at this issue in the next triage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants