Exemple #1
0
        /// <summary>
        ///  Returns the Size of the given text using the specified font if not null, otherwise the font currently
        ///  set in the dc is used.
        ///  This method is used to get the size in points of a line of text; it uses GetTextExtentPoint32 function
        ///  which computes the width and height of the text ignoring TAB\CR\LF characters.
        ///  A text extent is the distance between the beginning of the space and a character that will fit in the space.
        /// </summary>
        public Size GetTextExtent(string text, WindowsFont font)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(Size.Empty);
            }

            Size size = new Size();

            if (font != null)
            {
                DeviceContext.SelectFont(font);
            }

            Gdi32.GetTextExtentPoint32W(DeviceContext.Hdc, text, text.Length, ref size);

            // Unselect, but not from Measurement DC as it keeps the same
            // font selected for perf reasons.
            if (font != null && !MeasurementDCInfo.IsMeasurementDC(DeviceContext))
            {
                DeviceContext.ResetFont();
            }

            return(new Size(size.Width, size.Height));
        }
Exemple #2
0
 public void RestoreHdc()
 {
     IntUnsafeNativeMethods.RestoreDC(new HandleRef(this, this.hDC), -1);
     if (this.contextStack != null)
     {
         GraphicsState state = (GraphicsState)this.contextStack.Pop();
         this.hCurrentBmp   = state.hBitmap;
         this.hCurrentBrush = state.hBrush;
         this.hCurrentPen   = state.hPen;
         this.hCurrentFont  = state.hFont;
         if ((state.font != null) && state.font.IsAlive)
         {
             this.selectedFont = state.font.Target as WindowsFont;
         }
         else
         {
             WindowsFont selectedFont = this.selectedFont;
             this.selectedFont = null;
             if ((selectedFont != null) && MeasurementDCInfo.IsMeasurementDC(this))
             {
                 selectedFont.Dispose();
             }
         }
     }
     MeasurementDCInfo.ResetIfIsMeasurementDC(this.hDC);
 }
        /// <summary>
        ///  Restores the device context to the specified state. The DC is restored by popping state information off a
        ///  stack created by earlier calls to the SaveHdc function.
        ///  The stack can contain the state information for several instances of the DC. If the state specified by the
        ///  specified parameter is not at the top of the stack, RestoreDC deletes all state information between the top
        ///  of the stack and the specified instance.
        ///  Specifies the saved state to be restored. If this parameter is positive, nSavedDC represents a specific
        ///  instance of the state to be restored. If this parameter is negative, nSavedDC represents an instance relative
        ///  to the current state. For example, -1 restores the most recently saved state.
        ///  See MSDN for more info.
        /// </summary>
        public void RestoreHdc()
        {
            // Note: Don't use the Hdc property here, it would force handle creation.
            Gdi32.RestoreDC(new HandleRef(this, _hDC), -1);
            Debug.Assert(_contextStack != null, "Someone is calling RestoreHdc() before SaveHdc()");

            if (_contextStack != null)
            {
                GraphicsState g = (GraphicsState)_contextStack.Pop();

                _hCurrentBmp   = g.hBitmap;
                _hCurrentBrush = g.hBrush;
                _hCurrentPen   = g.hPen;
                _hCurrentFont  = g.hFont;

                if (g.font != null && g.font.IsAlive)
                {
                    ActiveFont = g.font.Target as WindowsFont;
                }
                else
                {
                    WindowsFont?previousFont = ActiveFont;
                    ActiveFont = null;
                    if (previousFont != null && MeasurementDCInfo.IsMeasurementDC(this))
                    {
                        previousFont.Dispose();
                    }
                }
            }

            // in this case, GDI will copy back the previously saved font into the DC.
            // we dont actually know what the font is in our measurement DC so
            // we need to clear it off.
            MeasurementDCInfo.ResetIfIsMeasurementDC(_hDC);
        }
Exemple #4
0
        public IntPtr SelectFont(WindowsFont font)
        {
            if (font.Equals(this.Font))
            {
                return(IntPtr.Zero);
            }
            IntPtr      ptr          = this.SelectObject(font.Hfont, GdiObjectType.Font);
            WindowsFont selectedFont = this.selectedFont;

            this.selectedFont = font;
            this.hCurrentFont = font.Hfont;
            if ((selectedFont != null) && MeasurementDCInfo.IsMeasurementDC(this))
            {
                selectedFont.Dispose();
            }
            if (MeasurementDCInfo.IsMeasurementDC(this))
            {
                if (ptr != IntPtr.Zero)
                {
                    MeasurementDCInfo.LastUsedFont = font;
                    return(ptr);
                }
                MeasurementDCInfo.Reset();
            }
            return(ptr);
        }
        /// <summary>
        ///  Returns the Size of the given text using the specified font if not null, otherwise the font currently
        ///  set in the dc is used.
        ///  This method is used to get the size in points of a line of text; it uses GetTextExtentPoint32 function
        ///  which computes the width and height of the text ignoring TAB\CR\LF characters.
        ///  A text extent is the distance between the beginning of the space and a character that will fit in the space.
        /// </summary>
        public Size GetTextExtent(string text, WindowsFont font)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(Size.Empty);
            }

            Size      size = new Size();
            HandleRef hdc  = new HandleRef(null, dc.Hdc);

            if (font != null)
            {
                dc.SelectFont(font);
            }

            IntUnsafeNativeMethods.GetTextExtentPoint32W(hdc, text, text.Length, ref size);

            // Unselect, but not from Measurement DC as it keeps the same
            // font selected for perf reasons.
            if (font != null && !MeasurementDCInfo.IsMeasurementDC(dc))
            {
                dc.ResetFont();
            }

            return(new Size(size.Width, size.Height));
        }
Exemple #6
0
        /// <summary>
        ///  Selects the specified object into the dc.  If the specified object is the same as the one currently selected
        ///  in the dc, the object is not set and a null value is returned.
        /// </summary>
        public IntPtr SelectFont(WindowsFont font)
        {
            // Fonts are one of the most expensive objects to select in an hdc and in many cases we are passed a Font that is the
            // same as the one already selected in the dc so to avoid a perf hit we get the hdc font's log font and compare it
            // with the one passed in before selecting it in the hdc.
            // Also, we avoid performing GDI operations that if done on an enhanced metafile DC would add an entry to it, hence
            // reducing the size of the metafile.
            if (font.Equals(Font))
            {
                return(IntPtr.Zero);
            }
            IntPtr result = SelectObject(font.Hfont, GdiObjectType.Font);

            WindowsFont previousFont = selectedFont;

            selectedFont = font;
            hCurrentFont = font.Hfont;

            // the measurement DC always leaves fonts selected for pref reasons.
            // in this case, we need to diposse the font since the original
            // creator didn't fully dispose.
            if (previousFont != null)
            {
                if (MeasurementDCInfo.IsMeasurementDC(this))
                {
                    previousFont.Dispose();
                }
            }

#if OPTIMIZED_MEASUREMENTDC
            // once we've changed the font, update the last used font.
            if (MeasurementDCInfo.IsMeasurementDC(this))
            {
                if (result != IntPtr.Zero)
                {
                    MeasurementDCInfo.LastUsedFont = font;
                }
                else
                {
                    // there was an error selecting the Font into the DC, we dont know anything about it.
                    MeasurementDCInfo.Reset();
                }
            }
#endif
            return(result);
        }
Exemple #7
0
        /// <summary>
        ///  Restores the device context to the specified state. The DC is restored by popping state information off a
        ///  stack created by earlier calls to the SaveHdc function.
        ///  The stack can contain the state information for several instances of the DC. If the state specified by the
        ///  specified parameter is not at the top of the stack, RestoreDC deletes all state information between the top
        ///  of the stack and the specified instance.
        ///  Specifies the saved state to be restored. If this parameter is positive, nSavedDC represents a specific
        ///  instance of the state to be restored. If this parameter is negative, nSavedDC represents an instance relative
        ///  to the current state. For example, -1 restores the most recently saved state.
        ///  See MSDN for more info.
        /// </summary>
        public void RestoreHdc()
        {
#if TRACK_HDC
            bool result =
#endif
            // Note: Don't use the Hdc property here, it would force handle creation.
            Gdi32.RestoreDC(new HandleRef(this, _hDC), -1);
#if TRACK_HDC
            // Note: Winforms may call this method during app exit at which point the DC may have been finalized already causing this assert to popup.
            Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("ret[0]=DC.RestoreHdc(hDc=0x{1:x8})", result, unchecked ((int)this.hDC))));
#endif
            Debug.Assert(_contextStack != null, "Someone is calling RestoreHdc() before SaveHdc()");

            if (_contextStack != null)
            {
                GraphicsState g = (GraphicsState)_contextStack.Pop();

                _hCurrentBmp   = g.hBitmap;
                _hCurrentBrush = g.hBrush;
                _hCurrentPen   = g.hPen;
                _hCurrentFont  = g.hFont;

                if (g.font != null && g.font.IsAlive)
                {
                    ActiveFont = g.font.Target as WindowsFont;
                }
                else
                {
                    WindowsFont?previousFont = ActiveFont;
                    ActiveFont = null;
                    if (previousFont != null && MeasurementDCInfo.IsMeasurementDC(this))
                    {
                        previousFont.Dispose();
                    }
                }
            }

#if OPTIMIZED_MEASUREMENTDC
            // in this case, GDI will copy back the previously saved font into the DC.
            // we dont actually know what the font is in our measurement DC so
            // we need to clear it off.
            MeasurementDCInfo.ResetIfIsMeasurementDC(_hDC);
#endif
        }
        public Size MeasureText(string text, WindowsFont font, Size proposedSize, IntTextFormatFlags flags)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(Size.Empty);
            }
            IntNativeMethods.DRAWTEXTPARAMS lpDTParams = null;
            if (MeasurementDCInfo.IsMeasurementDC(this.DeviceContext))
            {
                lpDTParams = MeasurementDCInfo.GetTextMargins(this, font);
            }
            if (lpDTParams == null)
            {
                lpDTParams = this.GetTextMargins(font);
            }
            int num = (1 + lpDTParams.iLeftMargin) + lpDTParams.iRightMargin;

            if (proposedSize.Width <= num)
            {
                proposedSize.Width = num;
            }
            if (proposedSize.Height <= 0)
            {
                proposedSize.Height = 1;
            }
            IntNativeMethods.RECT lpRect = IntNativeMethods.RECT.FromXYWH(0, 0, proposedSize.Width, proposedSize.Height);
            HandleRef             hDC    = new HandleRef(null, this.dc.Hdc);

            if (font != null)
            {
                this.dc.SelectFont(font);
            }
            if ((proposedSize.Height >= MaxSize.Height) && ((flags & IntTextFormatFlags.SingleLine) != IntTextFormatFlags.Default))
            {
                flags &= ~(IntTextFormatFlags.Bottom | IntTextFormatFlags.VerticalCenter);
            }
            if (proposedSize.Width == MaxSize.Width)
            {
                flags &= ~IntTextFormatFlags.WordBreak;
            }
            flags |= IntTextFormatFlags.CalculateRectangle;
            IntUnsafeNativeMethods.DrawTextEx(hDC, text, ref lpRect, (int)flags, lpDTParams);
            return(lpRect.Size);
        }
        public Size GetTextExtent(string text, WindowsFont font)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(Size.Empty);
            }
            IntNativeMethods.SIZE size = new IntNativeMethods.SIZE();
            HandleRef             hDC  = new HandleRef(null, this.dc.Hdc);

            if (font != null)
            {
                this.dc.SelectFont(font);
            }
            IntUnsafeNativeMethods.GetTextExtentPoint32(hDC, text, size);
            if ((font != null) && !MeasurementDCInfo.IsMeasurementDC(this.dc))
            {
                this.dc.ResetFont();
            }
            return(new Size(size.cx, size.cy));
        }
Exemple #10
0
        /// <summary>
        ///  Returns the Size in logical units of the given text using the given Font, and according to the formatting flags.
        ///  The proposed size is used to create a bounding rectangle as follows:
        ///  - If there are multiple lines of text, DrawText uses the width of the rectangle pointed to by
        ///  the lpRect parameter and extends the base of the rectangle to bound the last line of text.
        ///  - If the largest word is wider than the rectangle, the width is expanded.
        ///  - If the text is less than the width of the rectangle, the width is reduced.
        ///  - If there is only one line of text, DrawText modifies the right side of the rectangle so that
        ///  it bounds the last character in the line.
        ///  If the font is null, the hdc's current font will be used.
        ///
        ///  Note for vertical fonts (if ever supported): DrawTextEx uses GetTextExtentPoint32 for measuring the text and this
        ///  function has the following limitation (from MSDN):
        ///  - This function assumes that the text is horizontal, that is, that the escapement is always 0. This is true for both
        ///  the horizontal and vertical measurements of the text.  The application must convert it explicitly.
        /// </summary>
        public Size MeasureText(string text, WindowsFont font, Size proposedSize, User32.DT flags)
        {
            Debug.Assert(((uint)flags & GdiUnsupportedFlagMask) == 0, "Some custom flags were left over and are not GDI compliant!");

            if (string.IsNullOrEmpty(text))
            {
                return(Size.Empty);
            }

            // DrawText returns a rectangle useful for aligning, but not guaranteed to encompass all
            // pixels (its not a FitBlackBox, if the text is italicized, it will overhang on the right.)
            // So we need to account for this.

#if OPTIMIZED_MEASUREMENTDC
            User32.DRAWTEXTPARAMS dtparams;
            // use the cache if we've got it
            if (MeasurementDCInfo.IsMeasurementDC(DeviceContext))
            {
                dtparams = MeasurementDCInfo.GetTextMargins(this, font);
            }
            else
            {
                dtparams = GetTextMargins(font);
            }
#else
            User32.DRAWTEXTPARAMS dtparams = GetTextMargins(font);
#endif

            // If Width / Height are < 0, we need to make them larger or DrawText will return
            // an unbounded measurement when we actually trying to make it very narrow.
            int minWidth = 1 + dtparams.iLeftMargin + dtparams.iRightMargin;

            if (proposedSize.Width <= minWidth)
            {
                proposedSize.Width = minWidth;
            }
            if (proposedSize.Height <= 0)
            {
                proposedSize.Height = 1;
            }

            var rect = new RECT(0, 0, proposedSize.Width, proposedSize.Height);
            if (font != null)
            {
                DeviceContext.SelectFont(font);
            }

            // If proposedSize.Height >= MaxSize.Height it is assumed bounds needed.  If flags contain SINGLELINE and
            // VCENTER or BOTTOM options, DrawTextEx does not bind the rectangle to the actual text height since
            // it assumes the text is to be vertically aligned; we need to clear the VCENTER and BOTTOM flags to
            // get the actual text bounds.
            if (proposedSize.Height >= MaxSize.Height && (flags & User32.DT.SINGLELINE) != 0)
            {
                // Clear vertical-alignment flags.
                flags &= ~(User32.DT.BOTTOM | User32.DT.VCENTER);
            }

            if (proposedSize.Width == MaxSize.Width)
            {
                // PERF: No constraining width means no word break.
                // in this case, we dont care about word wrapping - there should be enough room to fit it all
                flags &= ~(User32.DT.WORDBREAK);
            }

            flags |= User32.DT.CALCRECT;
            User32.DrawTextExW(DeviceContext.Hdc, text, text.Length, ref rect, flags, ref dtparams);

            return(rect.Size);
        }
        /// <summary>
        ///  Returns the Size in logical units of the given text using the given Font, and according to the formatting flags.
        ///  The proposed size is used to create a bounding rectangle as follows:
        ///  - If there are multiple lines of text, DrawText uses the width of the rectangle pointed to by
        ///  the lpRect parameter and extends the base of the rectangle to bound the last line of text.
        ///  - If the largest word is wider than the rectangle, the width is expanded.
        ///  - If the text is less than the width of the rectangle, the width is reduced.
        ///  - If there is only one line of text, DrawText modifies the right side of the rectangle so that
        ///  it bounds the last character in the line.
        ///  If the font is null, the hdc's current font will be used.
        ///
        ///  Note for vertical fonts (if ever supported): DrawTextEx uses GetTextExtentPoint32 for measuring the text and this
        ///  function has the following limitation (from MSDN):
        ///  - This function assumes that the text is horizontal, that is, that the escapement is always 0. This is true for both
        ///  the horizontal and vertical measurements of the text.  The application must convert it explicitly.
        /// </summary>
        public Size MeasureText(string text, WindowsFont font, Size proposedSize, IntTextFormatFlags flags)
        {
            Debug.Assert(((uint)flags & GdiUnsupportedFlagMask) == 0, "Some custom flags were left over and are not GDI compliant!");

            if (string.IsNullOrEmpty(text))
            {
                return(Size.Empty);
            }

            //
            // DrawText returns a rectangle useful for aligning, but not guaranteed to encompass all
            // pixels (its not a FitBlackBox, if the text is italicized, it will overhang on the right.)
            // So we need to account for this.
            //
            IntNativeMethods.DRAWTEXTPARAMS dtparams = null;

#if OPTIMIZED_MEASUREMENTDC
            // use the cache if we've got it
            if (MeasurementDCInfo.IsMeasurementDC(DeviceContext))
            {
                dtparams = MeasurementDCInfo.GetTextMargins(this, font);
            }
#endif

            if (dtparams == null)
            {
                dtparams = GetTextMargins(font);
            }

            //
            // If Width / Height are < 0, we need to make them larger or DrawText will return
            // an unbounded measurement when we actually trying to make it very narrow.
            //

            int minWidth = 1 + dtparams.iLeftMargin + dtparams.iRightMargin;

            if (proposedSize.Width <= minWidth)
            {
                proposedSize.Width = minWidth;
            }
            if (proposedSize.Height <= 0)
            {
                proposedSize.Height = 1;
            }

            IntNativeMethods.RECT rect = IntNativeMethods.RECT.FromXYWH(0, 0, proposedSize.Width, proposedSize.Height);

            HandleRef hdc = new HandleRef(null, dc.Hdc);

            if (font != null)
            {
                dc.SelectFont(font);
            }

            // If proposedSize.Height >= MaxSize.Height it is assumed bounds needed.  If flags contain SingleLine and
            // VerticalCenter or Bottom options, DrawTextEx does not bind the rectangle to the actual text height since
            // it assumes the text is to be vertically aligned; we need to clear the VerticalCenter and Bottom flags to
            // get the actual text bounds.
            if (proposedSize.Height >= MaxSize.Height && (flags & IntTextFormatFlags.SingleLine) != 0)
            {
                // Clear vertical-alignment flags.
                flags &= ~(IntTextFormatFlags.Bottom | IntTextFormatFlags.VerticalCenter);
            }

            if (proposedSize.Width == MaxSize.Width)
            {
                // PERF: No constraining width means no word break.
                // in this case, we dont care about word wrapping - there should be enough room to fit it all
                flags &= ~(IntTextFormatFlags.WordBreak);
            }

            flags |= IntTextFormatFlags.CalculateRectangle;
            IntUnsafeNativeMethods.DrawTextEx(hdc, text, ref rect, (int)flags, dtparams);

            /* No need to restore previous objects into the dc (see comments on top of the class).
             *
             * if( hOldFont != IntPtr.Zero )
             * {
             *  this.dc.SelectObject(hOldFont);
             * }
             */

            return(rect.Size);
        }