2 // System.Drawing.Fonts.cs
5 // Alexandre Pigolkine (pigolkine@gmx.de)
6 // Miguel de Icaza (miguel@ximian.com)
7 // Todd Berman (tberman@sevenl.com)
8 // Jordi Mas i Hernandez (jordi@ximian.com)
9 // Ravindra (rkumar@novell.com)
11 // Copyright (C) 2004 Ximian, Inc. (http://www.ximian.com)
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Runtime.Serialization;
37 using System.Runtime.InteropServices;
38 using System.ComponentModel;
40 namespace System.Drawing
44 [Editor ("System.Drawing.Design.FontEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
45 [TypeConverter (typeof (FontConverter))]
46 public sealed class Font : MarshalByRefObject, ISerializable, ICloneable, IDisposable
48 private IntPtr fontObject = IntPtr.Zero;
50 private Font (SerializationInfo info, StreamingContext context)
54 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
63 public void Dispose ()
65 if (fontObject != IntPtr.Zero) {
66 GDIPlus.CheckStatus (GDIPlus.GdipDeleteFont (fontObject));
67 fontObject = IntPtr.Zero;
68 GC.SuppressFinalize (this);
72 internal void unitConversion (GraphicsUnit fromUnit, GraphicsUnit toUnit, float nSrc, out float nTrg)
78 case GraphicsUnit.Display:
81 case GraphicsUnit.Document:
84 case GraphicsUnit.Inch:
87 case GraphicsUnit.Millimeter:
90 case GraphicsUnit.Pixel:
91 case GraphicsUnit.World:
92 inchs = nSrc / Graphics.systemDpiX;
94 case GraphicsUnit.Point:
98 throw new ArgumentException("Invalid GraphicsUnit");
102 case GraphicsUnit.Display:
105 case GraphicsUnit.Document:
108 case GraphicsUnit.Inch:
111 case GraphicsUnit.Millimeter:
112 nTrg = inchs * 25.4f;
114 case GraphicsUnit.Pixel:
115 case GraphicsUnit.World:
116 nTrg = inchs * Graphics.systemDpiX;
118 case GraphicsUnit.Point:
122 throw new ArgumentException("Invalid GraphicsUnit");
126 internal void setProperties (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
129 _fontFamily = family;
132 // MS throws ArgumentException, if unit is set to GraphicsUnit.Display
135 _gdiCharSet = charSet;
136 _gdiVerticalFont = isVertical;
138 unitConversion (unit, GraphicsUnit.Point, emSize, out _sizeInPoints);
140 _bold = _italic = _strikeout = _underline = false;
142 if ((style & FontStyle.Bold) == FontStyle.Bold)
145 if ((style & FontStyle.Italic) == FontStyle.Italic)
148 if ((style & FontStyle.Strikeout) == FontStyle.Strikeout)
151 if ((style & FontStyle.Underline) == FontStyle.Underline)
155 public static Font FromHfont (IntPtr Hfont)
157 OperatingSystem osInfo = Environment.OSVersion;
160 FontStyle newStyle = FontStyle.Regular;
162 LOGFONTA lf = new LOGFONTA ();
164 // Sanity. Should we throw an exception?
165 if (Hfont == IntPtr.Zero) {
166 Font result = new Font ("Arial", (float)10.0, FontStyle.Regular);
170 if ((int) osInfo.Platform == 128 || (int) osInfo.Platform == 4) {
171 // If we're on Unix we use our private gdiplus API to avoid Wine
172 // dependencies in S.D
174 Status s = GDIPlus.GdipCreateFontFromHfont (Hfont, out newObject, ref lf);
175 GDIPlus.CheckStatus (s);
179 // This needs testing
180 // GetDC, SelectObject, ReleaseDC GetTextMetric and
181 // GetFontFace are not really GDIPlus, see gdipFunctions.cs
183 newStyle = FontStyle.Regular;
185 hdc = GDIPlus.GetDC (IntPtr.Zero);
186 Font f = FromLogFont (lf, hdc);
187 GDIPlus.ReleaseDC (hdc);
191 if (lf.lfItalic != 0) {
192 newStyle |= FontStyle.Italic;
195 if (lf.lfUnderline != 0) {
196 newStyle |= FontStyle.Underline;
199 if (lf.lfStrikeOut != 0) {
200 newStyle |= FontStyle.Strikeout;
203 if (lf.lfWeight > 400) {
204 newStyle |= FontStyle.Bold;
207 if (lf.lfHeight < 0) {
208 newSize = lf.lfHeight * -1;
210 newSize = lf.lfHeight;
213 return (new Font (newObject, lf.lfFaceName, newStyle, newSize));
216 public IntPtr ToHfont ()
219 OperatingSystem osInfo = Environment.OSVersion;
221 // Sanity. Should we throw an exception?
222 if (fontObject == IntPtr.Zero) {
226 if ((int) osInfo.Platform == 128 || (int) osInfo.Platform == 4) {
229 LOGFONTA lf = new LOGFONTA ();
231 Hfont = GDIPlus.CreateFontIndirectA (ref lf);
236 internal Font (IntPtr newFontObject, string familyName, FontStyle style, float size)
238 FontFamily fontFamily;
241 fontFamily = new FontFamily (familyName);
244 fontFamily = FontFamily.GenericSansSerif;
247 setProperties (fontFamily, size, style, GraphicsUnit.Pixel, 0, false);
248 fontObject = newFontObject;
251 public Font (Font original, FontStyle style)
254 setProperties (original.FontFamily, original.Size, style, original.Unit, original.GdiCharSet, original.GdiVerticalFont);
256 status = GDIPlus.GdipCreateFont (_fontFamily.NativeObject, Size, Style, Unit, out fontObject);
257 GDIPlus.CheckStatus (status);
260 public Font (FontFamily family, float emSize, GraphicsUnit unit)
261 : this (family, emSize, FontStyle.Regular, unit, (byte)0, false)
265 public Font (string familyName, float emSize, GraphicsUnit unit)
266 : this (new FontFamily (familyName), emSize, FontStyle.Regular, unit, (byte)0, false)
270 public Font (FontFamily family, float emSize)
271 : this (family, emSize, FontStyle.Regular, GraphicsUnit.Point, (byte)0, false)
275 public Font (FontFamily family, float emSize, FontStyle style)
276 : this (family, emSize, style, GraphicsUnit.Point, (byte)0, false)
280 public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit)
281 : this (family, emSize, style, unit, (byte)0, false)
285 public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet)
286 : this (family, emSize, style, unit, charSet, false)
290 public Font (FontFamily family, float emSize, FontStyle style,
291 GraphicsUnit unit, byte charSet, bool isVertical)
293 // MS does not accept null family
295 setProperties (family, emSize, style, unit, charSet, isVertical);
296 status = GDIPlus.GdipCreateFont (family.NativeObject, emSize, style, unit, out fontObject);
297 GDIPlus.CheckStatus (status);
300 public Font (string familyName, float emSize)
301 : this (familyName, emSize, FontStyle.Regular, GraphicsUnit.Point, (byte)0, false)
305 public Font (string familyName, float emSize, FontStyle style)
306 : this (familyName, emSize, style, GraphicsUnit.Point, (byte)0, false)
310 public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit)
311 : this (familyName, emSize, style, unit, (byte)0, false)
315 public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet)
316 : this (familyName, emSize, style, unit, charSet, false)
320 public Font (string familyName, float emSize, FontStyle style,
321 GraphicsUnit unit, byte charSet, bool isVertical)
323 // NOTE: If family name is null, empty or invalid,
324 // MS creates Microsoft Sans Serif font.
328 family = new FontFamily (familyName);
331 family = FontFamily.GenericSansSerif;
334 setProperties (family, emSize, style, unit, charSet, isVertical);
336 status = GDIPlus.GdipCreateFont (family.NativeObject, emSize, style, unit, out fontObject);
337 GDIPlus.CheckStatus (status);
340 public object Clone ()
342 return new Font (this, Style);
345 internal IntPtr NativeObject {
356 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
363 private FontFamily _fontFamily;
366 public FontFamily FontFamily {
372 private byte _gdiCharSet;
374 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
375 public byte GdiCharSet {
381 private bool _gdiVerticalFont;
383 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
384 public bool GdiVerticalFont {
386 return _gdiVerticalFont;
393 return (int) Math.Ceiling (GetHeight ());
397 private bool _italic;
399 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
406 private string _name;
408 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
409 [Editor ("System.Drawing.Design.FontNameEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
410 [TypeConverter (typeof (FontConverter.FontNameConverter))]
424 private float _sizeInPoints;
427 public float SizeInPoints {
429 return _sizeInPoints;
433 private bool _strikeout;
435 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
436 public bool Strikeout {
442 private FontStyle _style;
445 public FontStyle Style {
451 private bool _underline;
453 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
454 public bool Underline {
460 private GraphicsUnit _unit;
462 [TypeConverter (typeof (FontConverter.FontUnitConverter))]
463 public GraphicsUnit Unit {
469 public override bool Equals (object obj)
474 Font fnt = (Font) obj;
476 if (fnt.FontFamily.Equals (FontFamily) && fnt.Size == Size &&
477 fnt.Style == Style && fnt.Unit == Unit &&
478 fnt.GdiCharSet == GdiCharSet &&
479 fnt.GdiVerticalFont == GdiVerticalFont)
485 public override int GetHashCode ()
487 return _name.GetHashCode ();
491 public static Font FromHdc (IntPtr hdc)
493 throw new NotImplementedException ();
496 [MonoTODO("This is temporary implementation")]
497 public static Font FromLogFont (object lf, IntPtr hdc)
500 LOGFONTA o = (LOGFONTA)lf;
501 GDIPlus.GdipCreateFontFromLogfontA (hdc, ref o, out newObject);
502 return new Font (newObject, "Microsoft Sans Serif", FontStyle.Regular, 10);
505 public float GetHeight ()
507 return GetHeight (Graphics.systemDpiY);
511 public static Font FromLogFont (object lf)
513 throw new NotImplementedException ();
516 public void ToLogFont (object logFont)
518 using (Graphics g = Graphics.FromHdc (GDIPlus.GetDC (IntPtr.Zero))) {
519 ToLogFont (logFont, g);
523 public void ToLogFont (object logFont, Graphics graphics)
525 if (graphics == null) {
526 throw new ArgumentNullException ("graphics");
529 // TODO: Does it make a sense to deal with LOGFONTW ?
530 LOGFONTA o = (LOGFONTA)logFont;
531 GDIPlus.CheckStatus (GDIPlus.GdipGetLogFontA(NativeObject, graphics.NativeObject, ref o));
534 public float GetHeight (Graphics graphics)
536 float height = GetHeight (graphics.DpiY);
538 switch (graphics.PageUnit) {
539 case GraphicsUnit.Document:
540 height *= (300f / graphics.DpiY);
542 case GraphicsUnit.Display:
543 height *= (75f / graphics.DpiY);
545 case GraphicsUnit.Inch:
546 height /= graphics.DpiY;
548 case GraphicsUnit.Millimeter:
549 height *= (25.4f / graphics.DpiY);
551 case GraphicsUnit.Point:
552 height *= (72f / graphics.DpiY);
555 case GraphicsUnit.Pixel:
556 case GraphicsUnit.World:
564 public float GetHeight (float dpi)
567 int emHeight = _fontFamily.GetEmHeight (_style);
568 int lineSpacing = _fontFamily.GetLineSpacing (_style);
570 height = lineSpacing * (_size / emHeight);
573 case GraphicsUnit.Document:
574 height *= (dpi / 300f);
576 case GraphicsUnit.Display:
577 height *= (dpi / 75f);
579 case GraphicsUnit.Inch:
582 case GraphicsUnit.Millimeter:
583 height *= (dpi / 25.4f);
585 case GraphicsUnit.Point:
586 height *= (dpi / 72f);
589 case GraphicsUnit.Pixel:
590 case GraphicsUnit.World:
598 public override String ToString ()
600 return String.Format ("[Font: Name={0}, Size={1}, Units={2}, GdiCharSet={3}, GdiVerticalFont={4}]", _name, _size, (int)_unit, _gdiCharSet, _gdiVerticalFont);