internal static bool IsFontInUse(WindowsFont wf) { if (wf == null) { return false; } for (int i = 0; i < activeDeviceContexts.Count; i++) { DeviceContext dc = activeDeviceContexts[i] as DeviceContext; if (dc != null && (dc.ActiveFont == wf || dc.IsFontOnContextStack(wf))) { return true; } } return false; }
/// GetTextMargins - checks to see if we have cached information about the current font, /// returns info about it. /// An MRU of Font margins was considered, but seems like overhead. internal static IntNativeMethods.DRAWTEXTPARAMS GetTextMargins(WindowsGraphics wg, WindowsFont font) { // PERF: operate on a local reference rather than party directly on the thread static one. CachedInfo currentCachedInfo = cachedMeasurementDCInfo; if (currentCachedInfo != null && currentCachedInfo.LeftTextMargin >0 && currentCachedInfo.RightTextMargin >0 && font == currentCachedInfo.LastUsedFont) { // we have to return clones as DrawTextEx will modify this struct return new IntNativeMethods.DRAWTEXTPARAMS(currentCachedInfo.LeftTextMargin,currentCachedInfo.RightTextMargin); } else if (currentCachedInfo == null) { currentCachedInfo = new CachedInfo(); cachedMeasurementDCInfo = currentCachedInfo; } IntNativeMethods.DRAWTEXTPARAMS drawTextParams = wg.GetTextMargins(font); currentCachedInfo.LeftTextMargin = drawTextParams.iLeftMargin; currentCachedInfo.RightTextMargin = drawTextParams.iRightMargin; // returning a copy here to be consistent with the return value from the cache. return new IntNativeMethods.DRAWTEXTPARAMS(currentCachedInfo.LeftTextMargin,currentCachedInfo.RightTextMargin); }
/// <devdoc> /// Draws the text in the given bounds, using the given Font, foreColor and backColor, and according to the specified /// TextFormatFlags flags. /// If font is null, the font currently selected in the hdc is used. /// If foreColor and/or backColor are Color.Empty, the hdc current text and/or background color are used. /// </devdoc> public void DrawText(string text, WindowsFont font, Rectangle bounds, Color foreColor, Color backColor, IntTextFormatFlags flags) { if (string.IsNullOrEmpty(text) || foreColor == Color.Transparent) { return; } Debug.Assert(((uint)flags & GdiUnsupportedFlagMask) == 0, "Some custom flags were left over and are not GDI compliant!"); Debug.Assert((flags & IntTextFormatFlags.CalculateRectangle) == 0, "CalculateRectangle flag is set, text won't be drawn"); HandleRef hdc = new HandleRef(this.dc, this.dc.Hdc); // DrawText requires default text alignment. if (this.dc.TextAlignment != DeviceContextTextAlignment.Default) { this.dc.SetTextAlignment(DeviceContextTextAlignment.Default); } // color empty means use the one currently selected in the dc. if (!foreColor.IsEmpty && foreColor != this.dc.TextColor) { this.dc.SetTextColor(foreColor); } if (font != null) { this.dc.SelectFont(font); } DeviceContextBackgroundMode newBackGndMode = (backColor.IsEmpty || backColor == Color.Transparent) ? DeviceContextBackgroundMode.Transparent : DeviceContextBackgroundMode.Opaque; if (this.dc.BackgroundMode != newBackGndMode) { this.dc.SetBackgroundMode(newBackGndMode); } if (newBackGndMode != DeviceContextBackgroundMode.Transparent && backColor != this.dc.BackgroundColor) { this.dc.SetBackgroundColor(backColor); } IntNativeMethods.DRAWTEXTPARAMS dtparams = GetTextMargins(font); bounds = AdjustForVerticalAlignment(hdc, text, bounds, flags, dtparams); // Adjust unbounded rect to avoid overflow since Rectangle ctr does not do param validation. if (bounds.Width == MaxSize.Width) { bounds.Width = bounds.Width - bounds.X; } if (bounds.Height == MaxSize.Height) { bounds.Height = bounds.Height - bounds.Y; } IntNativeMethods.RECT rect = new IntNativeMethods.RECT(bounds); 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) * { * IntUnsafeNativeMethods.SelectObject(hdc, new HandleRef( null, hOldFont)); * } * * if( foreColor != textColor ) * { * this.dc.SetTextColor(textColor); * } * * if( backColor != bkColor ) * { * this.dc.SetBackgroundColor(bkColor); * } * * if( bckMode != newMode ) * { * this.dc.SetBackgroundMode(bckMode); * } * * if( align != DeviceContextTextAlignment.Default ) * { * // Default text alignment required by DrewText. * this.dc.SetTextAlignment(align); * } */ }
/// <devdoc> /// Draws the text centered in the given rectangle and using the given Font, foreColor and backColor. /// </devdoc> public void DrawText(string text, WindowsFont font, Rectangle bounds, Color foreColor, Color backColor) { DrawText(text, font, bounds, foreColor, backColor, IntTextFormatFlags.HorizontalCenter | IntTextFormatFlags.VerticalCenter); }
/// <devdoc> /// Draws the text at the specified point, using the given Font, foreColor and backColor, and according /// to the specified flags. /// </devdoc> public void DrawText(string text, WindowsFont font, Point pt, Color foreColor, Color backColor, IntTextFormatFlags flags) { Rectangle bounds = new Rectangle(pt.X, pt.Y, int.MaxValue, int.MaxValue); DrawText(text, font, bounds, foreColor, backColor, flags); }
/// <devdoc> /// Draws the text at the specified point, using the given Font, foreColor and backColor. /// CR/LF are honored. /// </devdoc> public void DrawText(string text, WindowsFont font, Point pt, Color foreColor, Color backColor) { DrawText(text, font, pt, foreColor, backColor, IntTextFormatFlags.Default); }
public static WindowsFont GetWindowsFont(Font font, WindowsFontQuality fontQuality) { if (font == null) { return(null); } // First check if font is in the cache. int count = 0; int index = currentIndex; // Search by index of most recently added object. while (count < WindowsFontCache.Count) { if (WindowsFontCache[index].Key.Equals(font)) // don't do shallow comparison, we could miss cloned fonts. { // We got a Font in the cache, let's see if we have a WindowsFont with the same quality as required by the caller. // WARNING: It is not expected that the WindowsFont is disposed externally since it is created by this class. Debug.Assert(WindowsFontCache[index].Value.Hfont != IntPtr.Zero, "Cached WindowsFont was disposed, enable GDI_FINALIZATION_WATCH to track who did it!"); WindowsFont wf = WindowsFontCache[index].Value; if (wf.Quality == fontQuality) { return(wf); } } index--; count++; if (index < 0) { index = CacheSize - 1; } } // Font is not in the cache, let's add it. WindowsFont winFont = WindowsFont.FromFont(font, fontQuality); KeyValuePair <Font, WindowsFont> newEntry = new KeyValuePair <Font, WindowsFont>(font, winFont); currentIndex++; if (currentIndex == CacheSize) { currentIndex = 0; } if (WindowsFontCache.Count == CacheSize) // No more room, update current index. { WindowsFont wfont = null; // Go through the existing fonts in the cache, and see if any // are not in use by a DC. If one isn't, replace that. If // all are in use, new up a new font and do not cache it. bool finished = false; int startIndex = currentIndex; int loopIndex = startIndex + 1; while (!finished) { if (loopIndex >= CacheSize) { loopIndex = 0; } if (loopIndex == startIndex) { finished = true; } wfont = WindowsFontCache[loopIndex].Value; if (!DeviceContexts.IsFontInUse(wfont)) { currentIndex = loopIndex; finished = true; break; } else { loopIndex++; wfont = null; } } if (wfont != null) { WindowsFontCache[currentIndex] = newEntry; winFont.OwnedByCacheManager = true; #if GDI_FONT_CACHE_TRACK Debug.WriteLine("Removing from cache: " + wfont); Debug.WriteLine("Adding to cache: " + winFont); #endif wfont.OwnedByCacheManager = false; wfont.Dispose(); } else { // do not cache font - caller is ALWAYS responsible for // disposing now. If it is owned by the CM, it will not // disposed. winFont.OwnedByCacheManager = false; #if GDI_FONT_CACHE_TRACK Debug.WriteLine("Creating uncached font: " + winFont); #endif } } else { winFont.OwnedByCacheManager = true; WindowsFontCache.Add(newEntry); #if GDI_FONT_CACHE_TRACK Debug.WriteLine("Adding to cache: " + winFont); #endif } return(winFont); }
/// <devdoc> /// 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. /// </devdoc> 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(this.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, this.dc.Hdc); if (font != null) { this.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; }
internal void DisposeFont(bool disposing) { if (disposing) { DeviceContexts.RemoveDeviceContext(this); } if (selectedFont != null && selectedFont.Hfont != IntPtr.Zero) { IntPtr hCurrentFont = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_FONT); if (hCurrentFont == selectedFont.Hfont) { // select initial font back in IntUnsafeNativeMethods.SelectObject(new HandleRef(this, this.Hdc), new HandleRef( null, hInitialFont)); hCurrentFont = hInitialFont; } selectedFont.Dispose(disposing); selectedFont = null; } }
internal void UpdateFont(WindowsFont font) { if (LastUsedFont != font) { LastUsedFont = font; LeftTextMargin = -1; RightTextMargin = -1; } }
public static WindowsFont FromHfont( IntPtr hFont, bool takeOwnership ) { IntNativeMethods.LOGFONT lf = new IntNativeMethods.LOGFONT(); IntUnsafeNativeMethods.GetObject(new HandleRef(null, hFont), lf); WindowsFont wf = new WindowsFont( lf, /*createHandle*/ false ); wf.hFont = hFont; wf.ownHandle = takeOwnership; // if true, hFont will be deleted on dispose. return wf; }
public bool IsFontOnContextStack(WindowsFont wf) { if (contextStack == null) { return false; } foreach (GraphicsState g in contextStack) { if (g.hFont == wf.Hfont) { return true; } } return false; }
public void ResetFont() { #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(this.Hdc); #endif IntUnsafeNativeMethods.SelectObject(new HandleRef(this, this.Hdc), new HandleRef( null, hInitialFont )); selectedFont = null; hCurrentFont = hInitialFont; }
/// <devdoc> /// 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. /// </devdoc> 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( this.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 DEBUG //Disabling this assert until DevDiv Bugs 95968 gets fixed //Debug.Assert(previousFont.Hfont != IntPtr.Zero, "A font has been disposed before it was unselected from the DC. This will leak a GDI handle on Win9x! Call ResetFont()"); #endif 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; }
/// <devdoc> /// Returns the Size in logical units of the given text using the given Font and using the specified rectangle /// as the text bounding box (see overload below for more info). /// TAB/CR/LF are taken into account. /// </devdoc> public Size MeasureText(string text, WindowsFont font, Size proposedSize) { return(MeasureText(text, font, proposedSize, IntTextFormatFlags.Default)); }
/// GetTextMargins - checks to see if we have cached information about the current font, /// returns info about it. /// An MRU of Font margins was considered, but seems like overhead. internal static Interop.User32.DRAWTEXTPARAMS GetTextMargins(WindowsGraphics wg, WindowsFont font) { // PERF: operate on a local reference rather than party directly on the thread static one. CachedInfo currentCachedInfo = cachedMeasurementDCInfo; if (currentCachedInfo != null && currentCachedInfo.LeftTextMargin > 0 && currentCachedInfo.RightTextMargin > 0 && font == currentCachedInfo.LastUsedFont) { // we have to return clones as DrawTextEx will modify this struct return(new Interop.User32.DRAWTEXTPARAMS { iLeftMargin = currentCachedInfo.LeftTextMargin, iRightMargin = currentCachedInfo.RightTextMargin }); } else if (currentCachedInfo == null) { currentCachedInfo = new CachedInfo(); cachedMeasurementDCInfo = currentCachedInfo; } Interop.User32.DRAWTEXTPARAMS drawTextParams = wg.GetTextMargins(font); currentCachedInfo.LeftTextMargin = drawTextParams.iLeftMargin; currentCachedInfo.RightTextMargin = drawTextParams.iRightMargin; // returning a copy here to be consistent with the return value from the cache. return(new Interop.User32.DRAWTEXTPARAMS { iLeftMargin = currentCachedInfo.LeftTextMargin, iRightMargin = currentCachedInfo.RightTextMargin }); }
/// <devdoc> /// Draws the text at the specified point, using the given Font and foreColor, and according to the /// specified flags. /// </devdoc> public void DrawText(string text, WindowsFont font, Point pt, Color foreColor, IntTextFormatFlags flags) { DrawText(text, font, pt, foreColor, Color.Empty, flags); }
/// <devdoc> /// Returns the Size in logical units of the given text using the given Font and using the specified rectangle /// as the text bounding box (see overload below for more info). /// TAB/CR/LF are taken into account. /// </devdoc> public Size MeasureText(string text, WindowsFont font, Size proposedSize) { return MeasureText( text, font, proposedSize, IntTextFormatFlags.Default ); }
/// <devdoc> /// Draws the text at the specified point, using the given Font, foreColor and backColor, and according /// to the specified flags. /// </devdoc> public void DrawText(string text, WindowsFont font, Point pt, Color foreColor, Color backColor, IntTextFormatFlags flags) { Rectangle bounds = new Rectangle( pt.X, pt.Y, Int32.MaxValue, Int32.MaxValue ); DrawText( text, font, bounds, foreColor, backColor, flags ); }
/// <summary> /// 1. generate imgages for windows fonts then google ones /// </summary> /// <param name="args"></param> static void Main(string[] args) { //init google fonts from ttf file var googleFontDirs = Directory.GetDirectories(ConfigurationManager.AppSettings["GoogleFontDir"]) .SelectMany(x => Directory.GetFiles(x) .Where(m => m.Contains(".ttf"))) .ToList(); var googleFonts = googleFontDirs.Select(x => { var tmp = x.Split('\\'); var fontName = tmp[tmp.Length - 1].Replace(".ttf", "").Trim(); return(new { fontName = fontName, path = x }); }).ToList(); //---------- FontImageExporter exporter = new FontImageExporter(); Console.WriteLine("export one test image (mostly for testing purpose), or export char level images in various fonts? (1 / 2) "); if (Console.ReadLine().Equals("1")) { //font name Console.WriteLine("Font Name?"); var fontName = Console.ReadLine(); //17 size is good size to produce height of 28 Console.WriteLine("Font Size"); var fontSize = Convert.ToInt32(Console.ReadLine()); //create fontdata, check against windows/google fonts //lets assume that if it is not windows font then it is google font var fontData = default(FontData); if (FontResource.Fonts_Small.Any(x => x.Equals(fontName))) { fontData = new WindowsFont(fontName, fontSize); } else { var tmp = googleFonts.FirstOrDefault(x => x.fontName.Equals(fontName)); fontData = new GoogleFont(fontName, fontSize, tmp.path); } //content Console.WriteLine("what is the word you want to generate? ('.' is treated as linebreak, so it supports multi lines)"); var word = Console.ReadLine(); var strbuilder = new StringBuilder(); //where the word consists of multi chars, append some space around it if (word.Length > 1) { strbuilder.AppendLine(); var words = word.Split('.').ToList(); words.ForEach(x => { strbuilder.Append(' ', 1).Append(x).Append(' ', 2); strbuilder.AppendLine(); }); strbuilder.AppendLine(); strbuilder.Append(' ', 6).Append("."); } else { strbuilder.Append(word); } var path = ConfigurationManager.AppSettings["ExportWordDir"]; Directory.CreateDirectory(path); var name = Guid.NewGuid().ToString(); //resize and save new images Console.WriteLine("resize to 28*28?"); var resize = Convert.ToBoolean(Console.ReadLine()); if (resize) { exporter.SaveOneImage(strbuilder.ToString(), name, fontData, path, new List <ImageDecorator> { new ResizeDecorator(28, 28) }); } else { exporter.SaveOneImage(strbuilder.ToString(), name, fontData, path); } } else { Console.WriteLine("export windows font images or google font images. (1 / 2)"); var command = Console.ReadLine(); int fontSize = Convert.ToInt32(ConfigurationManager.AppSettings["DefaultExportFontSize"]); var fontDatas = new List <FontData>(); if (command.Equals("2")) { var googleFontDatas = googleFonts.Select(x => { var e = new GoogleFont(fontName: x.fontName, fontSize: fontSize, fontPath: x.path); return((FontData)e); }).ToList(); //google fonts are many, some are too unnormal, manually create a list with all normal font names string[] googleFontNameList = File.ReadAllLines(@"..\..\fonts_small.txt"); fontDatas = googleFontDatas.Where(x => googleFontNameList.Contains(x.FontName)).ToList(); } else if (command.Equals("1")) { fontDatas = FontResource.Fonts_Small.Select(x => { var font = new WindowsFont(x, fontSize); return((FontData)font); }).ToList(); } //---------------auto adjust offset //X,Y - 3,6 for font 40 is good, remove some offset manually Console.WriteLine("remove white pixel as offsets? (true/false)"); var removeOffset = Convert.ToBoolean(Console.ReadLine()); var offsetRemoveOption = -1; var offsetX = 0; var offsetY = 0; if (removeOffset) { Console.WriteLine("specify offset removal option - remove offsets (0) / even and remove offsets (1) / even and keep offset remains (2)? (0,1,2)"); offsetRemoveOption = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("specify offsets - 'X,Y' - (x-3, y-6, fontsize 40), (x-2, y-4, fontsize 27)"); var offsets = Console.ReadLine(); offsetX = Convert.ToInt32(offsets.Split(',')[0]); offsetY = Convert.ToInt32(offsets.Split(',')[1]); } var decorators = new List <ImageDecorator>(); if (removeOffset) { if (offsetRemoveOption == 0) { decorators.Add(new PeelDecorator(offsetX, offsetX, offsetY, offsetY)); } else if (offsetRemoveOption == 1) { //X,Y - 3,6 is tested decorators.Add(new EvenAndPeelDecorator(offsetX, offsetX, offsetY, offsetY)); } else if (offsetRemoveOption == 2) { decorators.Add(new AutoPeelDecorator(offsetX, offsetX, offsetY, offsetY)); } } exporter.ExportFontData(fontDatas, decorators); } Console.WriteLine("END"); //following code not used in the main program, some of the google fonts are bad, manually remove them, keep a list of google fonts that are good //System.IO.StreamWriter file = new System.IO.StreamWriter(@"..\..\googlefonts.txt"); //var allfonts = Directory.GetDirectories(@"D:\Test\FontData_After_Filter_stag"); //allfonts.ToList().ForEach(x => { // var dir = new DirectoryInfo(x); // var dirName = dir.Name; // file.WriteLine(dirName); //}); //file.Close(); }
/// <devdoc> /// Draws the text centered in the given rectangle and using the given Font and foreColor. /// </devdoc> public void DrawText(string text, WindowsFont font, Rectangle bounds, Color foreColor) { DrawText(text, font, bounds, foreColor, Color.Empty); }
private static IEnumerable <TestCaseData> GetRelativeFontCases() { string input; RelativeFont expected; input = "{7, 3, 0, 1, 100}"; expected = new AutoFont { Scale = 100, }; yield return (new TestCaseData(input, expected) .SetArgDisplayNames("Без изменений")); input = "{7, 3, 4, 400, 1, 110}"; expected = new AutoFont { Bold = false, Scale = 110, }; yield return (new TestCaseData(input, expected) .SetArgDisplayNames("Полужирный")); input = "{7, 3, 8, 1, 1, 120}"; expected = new AutoFont { Italic = true, Scale = 120, }; yield return (new TestCaseData(input, expected) .SetArgDisplayNames("Курсив")); input = "{7, 3, 12, 700, 0, 1, 130}"; expected = new AutoFont { Bold = true, Italic = false, Scale = 130, }; yield return (new TestCaseData(input, expected) .SetArgDisplayNames("Полужирный и курсив")); input = "{7, 3, 1, \"Times New Roman\", 1, 140}"; expected = new AutoFont { FaceName = "Times New Roman", Scale = 140, }; yield return (new TestCaseData(input, expected) .SetArgDisplayNames("Имя шрифта")); input = "{7, 3, 61, 700, 1, 1, 1, \"Arial\", 1, 150}"; expected = new AutoFont { Bold = true, Italic = true, Underline = true, Strikeout = true, FaceName = "Arial", Scale = 150, }; yield return (new TestCaseData(input, expected) .SetArgDisplayNames("Полностью заполнен")); input = "{7, 1, 61, { 0 }, 700, 1, 1, 1, \"Lucida Console\", 1, 160}"; expected = new WindowsFont { Bold = true, Italic = true, Underline = true, Strikeout = true, FaceName = "Lucida Console", Scale = 160, }; yield return (new TestCaseData(input, expected) .SetArgDisplayNames("Полностью заполненный StyleBasedFont")); }
/// <devdoc> /// Draws the text in the given bounds, using the given Font and foreColor, and according to the specified flags. /// </devdoc> public void DrawText(string text, WindowsFont font, Rectangle bounds, Color color, IntTextFormatFlags flags) { DrawText( text, font, bounds, color, Color.Empty, flags ); }
/// <devdoc> /// Draws the text in the given bounds, using the given Font, foreColor and backColor, and according to the specified /// TextFormatFlags flags. /// If font is null, the font currently selected in the hdc is used. /// If foreColor and/or backColor are Color.Empty, the hdc current text and/or background color are used. /// </devdoc> public void DrawText(string text, WindowsFont font, Rectangle bounds, Color foreColor, Color backColor, IntTextFormatFlags flags) { if (string.IsNullOrEmpty(text) || foreColor == Color.Transparent) { return; } Debug.Assert( ((uint)flags & GdiUnsupportedFlagMask) == 0, "Some custom flags were left over and are not GDI compliant!" ); Debug.Assert( (flags & IntTextFormatFlags.CalculateRectangle) == 0, "CalculateRectangle flag is set, text won't be drawn" ); HandleRef hdc = new HandleRef( this.dc, this.dc.Hdc); // DrawText requires default text alignment. if( this.dc.TextAlignment != DeviceContextTextAlignment.Default ) { this.dc.SetTextAlignment(DeviceContextTextAlignment.Default ); } // color empty means use the one currently selected in the dc. if( !foreColor.IsEmpty && foreColor != this.dc.TextColor) { this.dc.SetTextColor(foreColor); } if (font != null) { this.dc.SelectFont(font); } DeviceContextBackgroundMode newBackGndMode = (backColor.IsEmpty || backColor == Color.Transparent) ? DeviceContextBackgroundMode.Transparent : DeviceContextBackgroundMode.Opaque; if( this.dc.BackgroundMode != newBackGndMode ) { this.dc.SetBackgroundMode( newBackGndMode ); } if( newBackGndMode != DeviceContextBackgroundMode.Transparent && backColor != this.dc.BackgroundColor ) { this.dc.SetBackgroundColor( backColor ); } IntNativeMethods.DRAWTEXTPARAMS dtparams = GetTextMargins(font); bounds = AdjustForVerticalAlignment(hdc, text, bounds, flags, dtparams); // Adjust unbounded rect to avoid overflow since Rectangle ctr does not do param validation. if( bounds.Width == MaxSize.Width ) { bounds.Width = bounds.Width - bounds.X; } if( bounds.Height == MaxSize.Height ) { bounds.Height = bounds.Height - bounds.Y; } IntNativeMethods.RECT rect = new IntNativeMethods.RECT(bounds); 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) { IntUnsafeNativeMethods.SelectObject(hdc, new HandleRef( null, hOldFont)); } if( foreColor != textColor ) { this.dc.SetTextColor(textColor); } if( backColor != bkColor ) { this.dc.SetBackgroundColor(bkColor); } if( bckMode != newMode ) { this.dc.SetBackgroundMode(bckMode); } if( align != DeviceContextTextAlignment.Default ) { // Default text alignment required by DrewText. this.dc.SetTextAlignment(align); } */ }
/// <devdoc> /// Draws the text in the given bounds, using the given Font and foreColor, and according to the specified flags. /// </devdoc> public void DrawText(string text, WindowsFont font, Rectangle bounds, Color color, IntTextFormatFlags flags) { DrawText(text, font, bounds, color, Color.Empty, flags); }
/// <devdoc> /// <para> /// Calculates the spacing required for drawing text w/o clipping hanging parts of a glyph. /// </para> /// </devdoc> public float GetOverhangPadding( WindowsFont font ) { // Some parts of a glyphs may be clipped depending on the font & font style, GDI+ adds 1/6 of tmHeight // to each size of the text bounding box when drawing text to account for that; we do it here as well. WindowsFont tmpfont = font; if( tmpfont == null) { tmpfont = this.dc.Font; } float overhangPadding = tmpfont.Height / 6f; if( tmpfont != font ) { tmpfont.Dispose(); } return overhangPadding; }
/// <devdoc> /// Returns the Size in logical units of the given text using the given Font. /// CR/LF/TAB are taken into account. /// </devdoc> public Size MeasureText(string text, WindowsFont font) { return(MeasureText(text, font, MaxSize, IntTextFormatFlags.Default)); }
/// <devdoc> /// Get the bounding box internal text padding to be used when drawing text. /// </devdoc> public IntNativeMethods.DRAWTEXTPARAMS GetTextMargins(WindowsFont font) { // DrawText(Ex) adds a small space at the beginning of the text bounding box but not at the end, // this is more noticeable when the font has the italic style. We compensate with this factor. int leftMargin = 0; int rightMargin = 0; float overhangPadding = 0; switch( this.TextPadding ) { case TextPaddingOptions.GlyphOverhangPadding: // [overhang padding][Text][overhang padding][italic padding] overhangPadding = GetOverhangPadding(font); leftMargin = (int) Math.Ceiling(overhangPadding); rightMargin = (int) Math.Ceiling(overhangPadding * (1 + ItalicPaddingFactor)); break; case TextPaddingOptions.LeftAndRightPadding: // [2 * overhang padding][Text][2 * overhang padding][italic padding] overhangPadding = GetOverhangPadding(font); leftMargin = (int) Math.Ceiling(2 * overhangPadding); rightMargin = (int) Math.Ceiling(overhangPadding * (2 + ItalicPaddingFactor)); break; case TextPaddingOptions.NoPadding: default: break; } return new IntNativeMethods.DRAWTEXTPARAMS(leftMargin, rightMargin); }
/// <devdoc> /// 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. /// </devdoc> 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(this.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, this.dc.Hdc); if (font != null) { this.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); }
/// <devdoc> /// <para> /// 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. /// </para> /// </devdoc> 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); // Unselect, but not from Measurement DC as it keeps the same // font selected for perf reasons. if (font != null && !MeasurementDCInfo.IsMeasurementDC(this.dc)) { this.dc.ResetFont(); } return new Size(size.cx, size.cy); }
private void DrawGroupBox(PaintEventArgs e) { Graphics graphics = e.Graphics; Rectangle textRectangle = ClientRectangle; // Max text bounding box passed to drawing methods to support RTL. int textOffset = 8; // Offset from the left bound. Color backColor = DisabledColor; Pen light = new Pen(ControlPaint.Light(backColor, 1.0f)); Pen dark = new Pen(ControlPaint.Dark(backColor, 0f)); Size textSize; textRectangle.X += textOffset; textRectangle.Width -= 2 * textOffset; try { if (UseCompatibleTextRendering) { using (Brush textBrush = new SolidBrush(ForeColor)){ using (StringFormat format = new StringFormat()){ format.HotkeyPrefix = ShowKeyboardCues ? System.Drawing.Text.HotkeyPrefix.Show : System.Drawing.Text.HotkeyPrefix.Hide; // Adjust string format for Rtl controls if (RightToLeft == RightToLeft.Yes) { format.FormatFlags |= StringFormatFlags.DirectionRightToLeft; } textSize = Size.Ceiling(graphics.MeasureString(Text, Font, textRectangle.Width, format)); if (Enabled) { graphics.DrawString(Text, Font, textBrush, textRectangle, format); } else { ControlPaint.DrawStringDisabled(graphics, Text, Font, backColor, textRectangle, format); } } } } else { using (WindowsGraphics wg = WindowsGraphics.FromGraphics(graphics)){ IntTextFormatFlags flags = IntTextFormatFlags.WordBreak | IntTextFormatFlags.TextBoxControl; if (!ShowKeyboardCues) { flags |= IntTextFormatFlags.HidePrefix; } if (RightToLeft == RightToLeft.Yes) { flags |= IntTextFormatFlags.RightToLeft; flags |= IntTextFormatFlags.Right; } using (WindowsFont wfont = WindowsGraphicsCacheManager.GetWindowsFont(this.Font)) { textSize = wg.MeasureText(Text, wfont, new Size(textRectangle.Width, int.MaxValue), flags); if (Enabled) { wg.DrawText(Text, wfont, textRectangle, ForeColor, flags); } else { ControlPaint.DrawStringDisabled(wg, Text, Font, backColor, textRectangle, ((TextFormatFlags)flags)); } } } } int textLeft = textOffset; // Left side of binding box (independent on RTL). if (RightToLeft == RightToLeft.Yes) { textLeft += textRectangle.Width - textSize.Width; } // Math.Min to assure we paint at least a small line. int textRight = Math.Min(textLeft + textSize.Width, Width - 6); int boxTop = FontHeight / 2; if (SystemInformation.HighContrast && AccessibilityImprovements.Level1) { Color boxColor; if (Enabled) { boxColor = ForeColor; } else { boxColor = SystemColors.GrayText; } bool needToDispose = !boxColor.IsSystemColor; Pen boxPen = null; try { if (needToDispose) { boxPen = new Pen(boxColor); } else { boxPen = SystemPens.FromSystemColor(boxColor); } // left graphics.DrawLine(boxPen, 0, boxTop, 0, Height); //bottom graphics.DrawLine(boxPen, 0, Height - 1, Width, Height - 1); //top-left graphics.DrawLine(boxPen, 0, boxTop, textLeft, boxTop); //top-right graphics.DrawLine(boxPen, textRight, boxTop, Width - 1, boxTop); //right graphics.DrawLine(boxPen, Width - 1, boxTop, Width - 1, Height - 1); } finally { if (needToDispose && boxPen != null) { boxPen.Dispose(); } } } else { // left graphics.DrawLine(light, 1, boxTop, 1, Height - 1); graphics.DrawLine(dark, 0, boxTop, 0, Height - 2); // bottom graphics.DrawLine(light, 0, Height - 1, Width, Height - 1); graphics.DrawLine(dark, 0, Height - 2, Width - 1, Height - 2); // top-left graphics.DrawLine(dark, 0, boxTop - 1, textLeft, boxTop - 1); graphics.DrawLine(light, 1, boxTop, textLeft, boxTop); // top-right graphics.DrawLine(dark, textRight, boxTop - 1, Width - 2, boxTop - 1); graphics.DrawLine(light, textRight, boxTop, Width - 1, boxTop); // right graphics.DrawLine(light, Width - 1, boxTop - 1, Width - 1, Height - 1); graphics.DrawLine(dark, Width - 2, boxTop, Width - 2, Height - 2); } } finally { light.Dispose(); dark.Dispose(); } }
/// <devdoc> /// Returns the Size in logical units of the given text using the given Font. /// CR/LF/TAB are taken into account. /// </devdoc> public Size MeasureText(string text, WindowsFont font) { return MeasureText(text, font, MaxSize, IntTextFormatFlags.Default); }