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 void CreateFont(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical) {
54 // NOTE: If family name is null, empty or invalid,
55 // MS creates Microsoft Sans Serif font.
57 family = new FontFamily (familyName);
60 family = FontFamily.GenericSansSerif;
63 setProperties (family, emSize, style, unit, charSet, isVertical);
64 status = GDIPlus.GdipCreateFont (family.NativeObject, emSize, style, unit, out fontObject);
65 GDIPlus.CheckStatus (status);
68 private Font (SerializationInfo info, StreamingContext context)
75 name = (string)info.GetValue("Name", typeof(string));
76 size = (float)info.GetValue("Size", typeof(float));
77 style = (FontStyle)info.GetValue("Style", typeof(FontStyle));
78 unit = (GraphicsUnit)info.GetValue("Unit", typeof(GraphicsUnit));
80 CreateFont(name, size, style, unit, (byte)0, false);
83 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
85 info.AddValue("Name", Name);
86 info.AddValue("Size", Size);
87 info.AddValue("Style", Style);
88 info.AddValue("Unit", Unit);
96 public void Dispose ()
98 if (fontObject != IntPtr.Zero) {
99 GDIPlus.CheckStatus (GDIPlus.GdipDeleteFont (fontObject));
100 fontObject = IntPtr.Zero;
101 GC.SuppressFinalize (this);
105 internal void unitConversion (GraphicsUnit fromUnit, GraphicsUnit toUnit, float nSrc, out float nTrg)
111 case GraphicsUnit.Display:
114 case GraphicsUnit.Document:
117 case GraphicsUnit.Inch:
120 case GraphicsUnit.Millimeter:
121 inchs = nSrc / 25.4f;
123 case GraphicsUnit.Pixel:
124 case GraphicsUnit.World:
125 inchs = nSrc / Graphics.systemDpiX;
127 case GraphicsUnit.Point:
131 throw new ArgumentException("Invalid GraphicsUnit");
135 case GraphicsUnit.Display:
138 case GraphicsUnit.Document:
141 case GraphicsUnit.Inch:
144 case GraphicsUnit.Millimeter:
145 nTrg = inchs * 25.4f;
147 case GraphicsUnit.Pixel:
148 case GraphicsUnit.World:
149 nTrg = inchs * Graphics.systemDpiX;
151 case GraphicsUnit.Point:
155 throw new ArgumentException("Invalid GraphicsUnit");
159 internal void setProperties (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
162 _fontFamily = family;
165 // MS throws ArgumentException, if unit is set to GraphicsUnit.Display
168 _gdiCharSet = charSet;
169 _gdiVerticalFont = isVertical;
171 unitConversion (unit, GraphicsUnit.Point, emSize, out _sizeInPoints);
173 _bold = _italic = _strikeout = _underline = false;
175 if ((style & FontStyle.Bold) == FontStyle.Bold)
178 if ((style & FontStyle.Italic) == FontStyle.Italic)
181 if ((style & FontStyle.Strikeout) == FontStyle.Strikeout)
184 if ((style & FontStyle.Underline) == FontStyle.Underline)
188 public static Font FromHfont (IntPtr Hfont)
190 OperatingSystem osInfo = Environment.OSVersion;
193 FontStyle newStyle = FontStyle.Regular;
195 LOGFONTA lf = new LOGFONTA ();
197 // Sanity. Should we throw an exception?
198 if (Hfont == IntPtr.Zero) {
199 Font result = new Font ("Arial", (float)10.0, FontStyle.Regular);
203 if ((int) osInfo.Platform == 128 || (int) osInfo.Platform == 4) {
204 // If we're on Unix we use our private gdiplus API to avoid Wine
205 // dependencies in S.D
207 Status s = GDIPlus.GdipCreateFontFromHfont (Hfont, out newObject, ref lf);
208 GDIPlus.CheckStatus (s);
212 // This needs testing
213 // GetDC, SelectObject, ReleaseDC GetTextMetric and
214 // GetFontFace are not really GDIPlus, see gdipFunctions.cs
216 newStyle = FontStyle.Regular;
218 hdc = GDIPlus.GetDC (IntPtr.Zero);
219 Font f = FromLogFont (lf, hdc);
220 GDIPlus.ReleaseDC (hdc);
224 if (lf.lfItalic != 0) {
225 newStyle |= FontStyle.Italic;
228 if (lf.lfUnderline != 0) {
229 newStyle |= FontStyle.Underline;
232 if (lf.lfStrikeOut != 0) {
233 newStyle |= FontStyle.Strikeout;
236 if (lf.lfWeight > 400) {
237 newStyle |= FontStyle.Bold;
240 if (lf.lfHeight < 0) {
241 newSize = lf.lfHeight * -1;
243 newSize = lf.lfHeight;
246 return (new Font (newObject, lf.lfFaceName, newStyle, newSize));
249 public IntPtr ToHfont ()
252 OperatingSystem osInfo = Environment.OSVersion;
254 // Sanity. Should we throw an exception?
255 if (fontObject == IntPtr.Zero) {
259 if ((int) osInfo.Platform == 128 || (int) osInfo.Platform == 4) {
262 LOGFONTA lf = new LOGFONTA ();
264 Hfont = GDIPlus.CreateFontIndirectA (ref lf);
269 internal Font (IntPtr newFontObject, string familyName, FontStyle style, float size)
271 FontFamily fontFamily;
274 fontFamily = new FontFamily (familyName);
277 fontFamily = FontFamily.GenericSansSerif;
280 setProperties (fontFamily, size, style, GraphicsUnit.Pixel, 0, false);
281 fontObject = newFontObject;
284 public Font (Font original, FontStyle style)
287 setProperties (original.FontFamily, original.Size, style, original.Unit, original.GdiCharSet, original.GdiVerticalFont);
289 status = GDIPlus.GdipCreateFont (_fontFamily.NativeObject, Size, Style, Unit, out fontObject);
290 GDIPlus.CheckStatus (status);
293 public Font (FontFamily family, float emSize, GraphicsUnit unit)
294 : this (family, emSize, FontStyle.Regular, unit, (byte)0, false)
298 public Font (string familyName, float emSize, GraphicsUnit unit)
299 : this (new FontFamily (familyName), emSize, FontStyle.Regular, unit, (byte)0, false)
303 public Font (FontFamily family, float emSize)
304 : this (family, emSize, FontStyle.Regular, GraphicsUnit.Point, (byte)0, false)
308 public Font (FontFamily family, float emSize, FontStyle style)
309 : this (family, emSize, style, GraphicsUnit.Point, (byte)0, false)
313 public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit)
314 : this (family, emSize, style, unit, (byte)0, false)
318 public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet)
319 : this (family, emSize, style, unit, charSet, false)
323 public Font (FontFamily family, float emSize, FontStyle style,
324 GraphicsUnit unit, byte charSet, bool isVertical)
326 // MS does not accept null family
328 setProperties (family, emSize, style, unit, charSet, isVertical);
329 status = GDIPlus.GdipCreateFont (family.NativeObject, emSize, style, unit, out fontObject);
330 GDIPlus.CheckStatus (status);
333 public Font (string familyName, float emSize)
334 : this (familyName, emSize, FontStyle.Regular, GraphicsUnit.Point, (byte)0, false)
338 public Font (string familyName, float emSize, FontStyle style)
339 : this (familyName, emSize, style, GraphicsUnit.Point, (byte)0, false)
343 public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit)
344 : this (familyName, emSize, style, unit, (byte)0, false)
348 public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet)
349 : this (familyName, emSize, style, unit, charSet, false)
353 public Font (string familyName, float emSize, FontStyle style,
354 GraphicsUnit unit, byte charSet, bool isVertical)
356 CreateFont(familyName, emSize, style, unit, charSet, isVertical);
359 public object Clone ()
361 return new Font (this, Style);
364 internal IntPtr NativeObject {
375 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
382 private FontFamily _fontFamily;
385 public FontFamily FontFamily {
391 private byte _gdiCharSet;
393 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
394 public byte GdiCharSet {
400 private bool _gdiVerticalFont;
402 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
403 public bool GdiVerticalFont {
405 return _gdiVerticalFont;
412 return (int) Math.Ceiling (GetHeight ());
416 private bool _italic;
418 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
425 private string _name;
427 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
428 [Editor ("System.Drawing.Design.FontNameEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
429 [TypeConverter (typeof (FontConverter.FontNameConverter))]
443 private float _sizeInPoints;
446 public float SizeInPoints {
448 return _sizeInPoints;
452 private bool _strikeout;
454 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
455 public bool Strikeout {
461 private FontStyle _style;
464 public FontStyle Style {
470 private bool _underline;
472 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
473 public bool Underline {
479 private GraphicsUnit _unit;
481 [TypeConverter (typeof (FontConverter.FontUnitConverter))]
482 public GraphicsUnit Unit {
488 public override bool Equals (object obj)
493 Font fnt = (Font) obj;
495 if (fnt.FontFamily.Equals (FontFamily) && fnt.Size == Size &&
496 fnt.Style == Style && fnt.Unit == Unit &&
497 fnt.GdiCharSet == GdiCharSet &&
498 fnt.GdiVerticalFont == GdiVerticalFont)
504 public override int GetHashCode ()
506 return _name.GetHashCode ();
510 public static Font FromHdc (IntPtr hdc)
512 throw new NotImplementedException ();
515 [MonoTODO("This is temporary implementation")]
516 public static Font FromLogFont (object lf, IntPtr hdc)
519 LOGFONTA o = (LOGFONTA)lf;
520 GDIPlus.GdipCreateFontFromLogfontA (hdc, ref o, out newObject);
521 return new Font (newObject, "Microsoft Sans Serif", FontStyle.Regular, 10);
524 public float GetHeight ()
526 return GetHeight (Graphics.systemDpiY);
530 public static Font FromLogFont (object lf)
532 throw new NotImplementedException ();
535 public void ToLogFont (object logFont)
537 using (Graphics g = Graphics.FromHdc (GDIPlus.GetDC (IntPtr.Zero))) {
538 ToLogFont (logFont, g);
542 public void ToLogFont (object logFont, Graphics graphics)
544 if (graphics == null) {
545 throw new ArgumentNullException ("graphics");
548 // TODO: Does it make a sense to deal with LOGFONTW ?
549 LOGFONTA o = (LOGFONTA)logFont;
550 GDIPlus.CheckStatus (GDIPlus.GdipGetLogFontA(NativeObject, graphics.NativeObject, ref o));
553 public float GetHeight (Graphics graphics)
555 float height = GetHeight (graphics.DpiY);
557 switch (graphics.PageUnit) {
558 case GraphicsUnit.Document:
559 height *= (300f / graphics.DpiY);
561 case GraphicsUnit.Display:
562 height *= (75f / graphics.DpiY);
564 case GraphicsUnit.Inch:
565 height /= graphics.DpiY;
567 case GraphicsUnit.Millimeter:
568 height *= (25.4f / graphics.DpiY);
570 case GraphicsUnit.Point:
571 height *= (72f / graphics.DpiY);
574 case GraphicsUnit.Pixel:
575 case GraphicsUnit.World:
583 public float GetHeight (float dpi)
586 int emHeight = _fontFamily.GetEmHeight (_style);
587 int lineSpacing = _fontFamily.GetLineSpacing (_style);
589 height = lineSpacing * (_size / emHeight);
592 case GraphicsUnit.Document:
593 height *= (dpi / 300f);
595 case GraphicsUnit.Display:
596 height *= (dpi / 75f);
598 case GraphicsUnit.Inch:
601 case GraphicsUnit.Millimeter:
602 height *= (dpi / 25.4f);
604 case GraphicsUnit.Point:
605 height *= (dpi / 72f);
608 case GraphicsUnit.Pixel:
609 case GraphicsUnit.World:
617 public override String ToString ()
619 return String.Format ("[Font: Name={0}, Size={1}, Units={2}, GdiCharSet={3}, GdiVerticalFont={4}]", _name, _size, (int)_unit, _gdiCharSet, _gdiVerticalFont);