Skip to content

Commit 53b30ed

Browse files
authored
Fix transparent rendering with parents that have a background image (#13797)
If a Graphics backing HDC has an offset origin (SetViewportOrgEx), drawing with a texture brush will reset it. Getting the HDC and releasing it will restore the offset. Add a few helper methods to HDC to make debugging this sort of thing easier. Fixes #13784
1 parent 0597206 commit 53b30ed

File tree

6 files changed

+32
-5
lines changed

6 files changed

+32
-5
lines changed

src/System.Private.Windows.Core/src/NativeMethods.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,12 @@ GetSystemMetrics
118118
GetThreadLocale
119119
GetViewportExtEx
120120
GetViewportOrgEx
121+
GetWindowOrgEx
121122
GetWindowRect
122123
GetWindowText
123124
GetWindowTextLength
124125
GetWindowThreadProcessId
126+
GetWorldTransform
125127
GlobalAlloc
126128
GlobalFree
127129
GlobalLock
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,31 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Drawing;
5+
using System.Numerics;
6+
using System.Runtime.CompilerServices;
7+
48
namespace Windows.Win32.Graphics.Gdi;
59

610
internal readonly partial struct HDC : IHandle<HDC>
711
{
812
HDC IHandle<HDC>.Handle => this;
913
object? IHandle<HDC>.Wrapper => null;
14+
15+
internal Point GetViewPointOrigin() =>
16+
PInvokeCore.GetViewportOrgEx(this, out Point point) ? point : Point.Empty;
17+
18+
internal Point GetWindowOrigin() =>
19+
PInvokeCore.GetWindowOrgEx(this, out Point point) ? point : Point.Empty;
20+
21+
internal Matrix3x2 GetWorldTransform()
22+
{
23+
if (PInvokeCore.GetWorldTransform(this, out XFORM matrix))
24+
{
25+
return Unsafe.As<XFORM, Matrix3x2>(ref matrix);
26+
}
27+
28+
// If we can't get the transform, return the identity matrix.
29+
return Matrix3x2.Identity;
30+
}
1031
}

src/System.Windows.Forms.Primitives/src/NativeMethods.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ GetWindow
224224
GetWindowDisplayAffinity
225225
GetWindowDpiAwarenessContext
226226
GetWindowPlacement
227-
GetWorldTransform
228227
GMR_*
229228
HC_*
230229
HDHITTESTINFO

src/System.Windows.Forms.Primitives/tests/TestUtilities/DeviceContextState.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ public DeviceContextState(HDC hdc)
3232
TextAlign = PInvoke.GetTextAlign(hdc);
3333
BackgroundMode = PInvoke.GetBkMode(hdc);
3434

35-
Matrix3x2 transform = default;
36-
PInvoke.GetWorldTransform(hdc, (XFORM*)(void*)&transform);
37-
Transform = transform;
35+
Transform = hdc.GetWorldTransform();
3836

3937
Point point = default;
4038
PInvoke.GetBrushOrgEx(hdc, &point);

src/System.Windows.Forms/System/Windows/Forms/Rendering/ControlPaint.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,13 @@ internal static void DrawBackgroundImage(
462462
}
463463

464464
g.FillRectangle(textureBrush, clipRect);
465+
466+
// If the Graphics backing HDC has an offset origin (SetViewportOrgEx), drawing with a texture brush will
467+
// reset it. Getting the HDC and releasing it will restore the offset.
468+
//
469+
// See https://github.com/dotnet/winforms/issues/13784 for a repro.
470+
g.GetHdc();
471+
g.ReleaseHdc();
465472
}
466473
else
467474
{

src/System.Windows.Forms/System/Windows/Forms/Rendering/ScreenDcCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private static unsafe void ValidateHdc(HDC hdc)
111111
Debug.Assert(PInvoke.GetBkMode(hdc) == BACKGROUND_MODE.OPAQUE);
112112

113113
Matrix3x2 matrix = default;
114-
Debug.Assert(PInvoke.GetWorldTransform(hdc, (XFORM*)(void*)&matrix));
114+
Debug.Assert(PInvokeCore.GetWorldTransform(hdc, (XFORM*)(void*)&matrix));
115115
Debug.Assert(matrix.IsIdentity);
116116
}
117117
}

0 commit comments

Comments
 (0)