From e9e8d8f1db4261523068c7aa0a0f8fb77c1750de Mon Sep 17 00:00:00 2001 From: Igor Velikorossov Date: Fri, 14 May 2021 09:31:57 +1000 Subject: [PATCH] Allow to skip TextRenderer asserts (#4901) While painting LinkedLabel we modify device context before drawing the label's text. Because of that we hit the asserts in TextRenderer.GetApplyStateFlags. Since the DC state is expected, skip the assertions. Closes #4857 --- .../src/System/Windows/Forms/LinkLabel.cs | 7 +- .../System/Windows/Forms/TextFormatFlags.cs | 65 +++++++++---------- .../src/System/Windows/Forms/TextRenderer.cs | 30 ++++++--- 3 files changed, 59 insertions(+), 43 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/LinkLabel.cs b/src/System.Windows.Forms/src/System/Windows/Forms/LinkLabel.cs index 123873bc7fe..c83cced2d6a 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/LinkLabel.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/LinkLabel.cs @@ -1506,7 +1506,12 @@ protected override void OnTextAlignChanged(EventArgs e) font, clientRectWithPadding, brushColor, - CreateTextFormatFlags(clientRectWithPadding.Size)); + CreateTextFormatFlags(clientRectWithPadding.Size) +#if DEBUG + // Skip the asserts in TextRenderer because the DC has been modified + | TextRenderer.SkipAssertFlag +#endif + ); } if (Focused && ShowFocusCues && FocusLink == link) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/TextFormatFlags.cs b/src/System.Windows.Forms/src/System/Windows/Forms/TextFormatFlags.cs index eca377acecf..2bbed8686ec 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/TextFormatFlags.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/TextFormatFlags.cs @@ -15,59 +15,58 @@ namespace System.Windows.Forms [Flags] public enum TextFormatFlags { - Bottom = (int)User32.DT.BOTTOM, - EndEllipsis = (int)User32.DT.END_ELLIPSIS, - ExpandTabs = (int)User32.DT.EXPANDTABS, - ExternalLeading = (int)User32.DT.EXTERNALLEADING, - Default = (int)User32.DT.DEFAULT, - HidePrefix = (int)User32.DT.HIDEPREFIX, - HorizontalCenter = (int)User32.DT.CENTER, - Internal = (int)User32.DT.INTERNAL, + Bottom = (int)User32.DT.BOTTOM, + EndEllipsis = (int)User32.DT.END_ELLIPSIS, + ExpandTabs = (int)User32.DT.EXPANDTABS, + ExternalLeading = (int)User32.DT.EXTERNALLEADING, + Default = (int)User32.DT.DEFAULT, + HidePrefix = (int)User32.DT.HIDEPREFIX, + HorizontalCenter = (int)User32.DT.CENTER, + Internal = (int)User32.DT.INTERNAL, /// /// This is the default. /// - Left = (int)User32.DT.LEFT, + Left = (int)User32.DT.LEFT, [Obsolete("ModifyString mutates strings and should be avoided. It will be blocked in a future release.")] - ModifyString = (int)User32.DT.MODIFYSTRING, - NoClipping = (int)User32.DT.NOCLIP, - NoPrefix = (int)User32.DT.NOPREFIX, - NoFullWidthCharacterBreak = (int)User32.DT.NOFULLWIDTHCHARBREAK, - PathEllipsis = (int)User32.DT.PATH_ELLIPSIS, - PrefixOnly = (int)User32.DT.PREFIXONLY, - Right = (int)User32.DT.RIGHT, - RightToLeft = (int)User32.DT.RTLREADING, - SingleLine = (int)User32.DT.SINGLELINE, - TextBoxControl = (int)User32.DT.EDITCONTROL, + ModifyString = (int)User32.DT.MODIFYSTRING, + NoClipping = (int)User32.DT.NOCLIP, + NoPrefix = (int)User32.DT.NOPREFIX, + NoFullWidthCharacterBreak = (int)User32.DT.NOFULLWIDTHCHARBREAK, + PathEllipsis = (int)User32.DT.PATH_ELLIPSIS, + PrefixOnly = (int)User32.DT.PREFIXONLY, + Right = (int)User32.DT.RIGHT, + RightToLeft = (int)User32.DT.RTLREADING, + SingleLine = (int)User32.DT.SINGLELINE, + TextBoxControl = (int)User32.DT.EDITCONTROL, /// /// This is the default. /// - Top = (int)User32.DT.TOP, + Top = (int)User32.DT.TOP, - VerticalCenter = (int)User32.DT.VCENTER, - WordBreak = (int)User32.DT.WORDBREAK, - WordEllipsis = (int)User32.DT.WORD_ELLIPSIS, + VerticalCenter = (int)User32.DT.VCENTER, + WordBreak = (int)User32.DT.WORDBREAK, + WordEllipsis = (int)User32.DT.WORD_ELLIPSIS, - /// /// The following flags are exclusive of TextRenderer (no Windows native flags) /// and apply to methods receiving a Graphics as the IDeviceContext object, and /// specify whether to reapply clipping and coordintate transformations to the hdc /// obtained from the Graphics object, which returns a clean hdc. - /// - PreserveGraphicsClipping = 0x01000000, - PreserveGraphicsTranslateTransform = 0x02000000, + /// + /// These get stripped off by TextExtensions before we call DrawText or MeasureText + /// (see: GdiUnsupportedFlagMask). + + PreserveGraphicsClipping = 0x0100_0000, + PreserveGraphicsTranslateTransform = 0x0200_0000, /// /// Adds padding related to the drawing binding box, computed according to the font size. /// Match the System.Internal.GDI.TextPaddingOptions. /// - /// - /// This is the default. - /// - GlyphOverhangPadding = 0x00000000, - NoPadding = 0x10000000, - LeftAndRightPadding = 0x20000000 + GlyphOverhangPadding = 0x0000_0000, + NoPadding = 0x1000_0000, + LeftAndRightPadding = 0x2000_0000 } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/TextRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/TextRenderer.cs index 05272586f8a..377f4e8206c 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/TextRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/TextRenderer.cs @@ -14,6 +14,13 @@ namespace System.Windows.Forms /// public static class TextRenderer { +#if DEBUG + // In various cases the DC may have already been modified, and we don't pass TextFormatFlags.PreserveGraphicsClipping + // or TextFormatFlags.PreserveGraphicsTranslateTransform flags, that set off the asserts in GetApplyStateFlags + // method. This flags allows us to skip those assert for the cases we know we don't need these flags. + internal static TextFormatFlags SkipAssertFlag = (TextFormatFlags)0x4000_0000; +#endif + internal static Gdi32.QUALITY DefaultQuality { get; } = GetDefaultFontQuality(); internal static Size MaxSize { get; } = new Size(int.MaxValue, int.MaxValue); @@ -620,15 +627,20 @@ private static ApplyGraphicsProperties GetApplyStateFlags(IDeviceContext deviceC apply |= ApplyGraphicsProperties.TranslateTransform; } - Debug.Assert(apply.HasFlag(ApplyGraphicsProperties.Clipping) - || graphics.Clip is null - || graphics.Clip.GetHrgn(graphics) == IntPtr.Zero, - "Must preserve Graphics clipping region!"); - - Debug.Assert(apply.HasFlag(ApplyGraphicsProperties.TranslateTransform) - || graphics.Transform is null - || graphics.Transform.IsIdentity, - "Must preserve Graphics transformation!"); +#if DEBUG + if ((textFormatFlags & SkipAssertFlag) == 0) + { + Debug.Assert(apply.HasFlag(ApplyGraphicsProperties.Clipping) + || graphics.Clip is null + || graphics.Clip.GetHrgn(graphics) == IntPtr.Zero, + "Must preserve Graphics clipping region!"); + + Debug.Assert(apply.HasFlag(ApplyGraphicsProperties.TranslateTransform) + || graphics.Transform is null + || graphics.Transform.IsIdentity, + "Must preserve Graphics transformation!"); + } +#endif return apply; }