fix typo
[mcs.git] / class / System.Drawing / System.Drawing / Font.cs
blob6b16e44addcfdc1d512862f86a1435c698e18c24
1 //
2 // System.Drawing.Fonts.cs
3 //
4 // Authors:
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)
12 // Copyright (C) 2004, 2006 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Runtime.Serialization;
35 using System.Runtime.InteropServices;
36 using System.Security.Permissions;
37 using System.ComponentModel;
39 namespace System.Drawing
41 [Serializable]
42 [ComVisible (true)]
43 [Editor ("System.Drawing.Design.FontEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
44 [TypeConverter (typeof (FontConverter))]
45 public sealed class Font : MarshalByRefObject, ISerializable, ICloneable, IDisposable
47 private IntPtr fontObject = IntPtr.Zero;
48 #if NET_2_0
49 private string systemFontName;
50 private string originalFontName;
51 #endif
52 private float _size;
53 private object olf;
55 private const byte DefaultCharSet = 1;
56 private static int CharSetOffset = -1;
58 private void CreateFont (string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
60 #if ONLY_1_1
61 if (familyName == null)
62 throw new ArgumentNullException ("familyName");
63 #endif
64 #if NET_2_0
65 originalFontName = familyName;
66 #endif
67 FontFamily family;
68 // NOTE: If family name is null, empty or invalid,
69 // MS creates Microsoft Sans Serif font.
70 try {
71 family = new FontFamily (familyName);
73 catch (Exception){
74 family = FontFamily.GenericSansSerif;
77 setProperties (family, emSize, style, unit, charSet, isVertical);
78 Status status = GDIPlus.GdipCreateFont (family.NativeObject, emSize, style, unit, out fontObject);
80 if (status == Status.FontStyleNotFound)
81 throw new ArgumentException (Locale.GetText ("Style {0} isn't supported by font {1}.", style.ToString (), familyName));
83 GDIPlus.CheckStatus (status);
86 private Font (SerializationInfo info, StreamingContext context)
88 string name;
89 float size;
90 FontStyle style;
91 GraphicsUnit unit;
93 name = (string)info.GetValue("Name", typeof(string));
94 size = (float)info.GetValue("Size", typeof(float));
95 style = (FontStyle)info.GetValue("Style", typeof(FontStyle));
96 unit = (GraphicsUnit)info.GetValue("Unit", typeof(GraphicsUnit));
98 CreateFont(name, size, style, unit, DefaultCharSet, false);
101 void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context)
103 si.AddValue("Name", Name);
104 si.AddValue ("Size", Size);
105 si.AddValue ("Style", Style);
106 si.AddValue ("Unit", Unit);
109 ~Font()
111 Dispose ();
114 public void Dispose ()
116 if (fontObject != IntPtr.Zero) {
117 Status status = GDIPlus.GdipDeleteFont (fontObject);
118 fontObject = IntPtr.Zero;
119 GC.SuppressFinalize (this);
120 // check the status code (throw) at the last step
121 GDIPlus.CheckStatus (status);
125 internal void unitConversion (GraphicsUnit fromUnit, GraphicsUnit toUnit, float nSrc, out float nTrg)
127 float inchs = 0;
128 nTrg = 0;
130 switch (fromUnit) {
131 case GraphicsUnit.Display:
132 inchs = nSrc / 75f;
133 break;
134 case GraphicsUnit.Document:
135 inchs = nSrc / 300f;
136 break;
137 case GraphicsUnit.Inch:
138 inchs = nSrc;
139 break;
140 case GraphicsUnit.Millimeter:
141 inchs = nSrc / 25.4f;
142 break;
143 case GraphicsUnit.Pixel:
144 case GraphicsUnit.World:
145 inchs = nSrc / Graphics.systemDpiX;
146 break;
147 case GraphicsUnit.Point:
148 inchs = nSrc / 72f;
149 break;
150 default:
151 throw new ArgumentException("Invalid GraphicsUnit");
154 switch (toUnit) {
155 case GraphicsUnit.Display:
156 nTrg = inchs * 75;
157 break;
158 case GraphicsUnit.Document:
159 nTrg = inchs * 300;
160 break;
161 case GraphicsUnit.Inch:
162 nTrg = inchs;
163 break;
164 case GraphicsUnit.Millimeter:
165 nTrg = inchs * 25.4f;
166 break;
167 case GraphicsUnit.Pixel:
168 case GraphicsUnit.World:
169 nTrg = inchs * Graphics.systemDpiX;
170 break;
171 case GraphicsUnit.Point:
172 nTrg = inchs * 72;
173 break;
174 default:
175 throw new ArgumentException("Invalid GraphicsUnit");
179 internal void setProperties (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
181 _name = family.Name;
182 _fontFamily = family;
183 _size = emSize;
185 // MS throws ArgumentException, if unit is set to GraphicsUnit.Display
186 _unit = unit;
187 _style = style;
188 _gdiCharSet = charSet;
189 _gdiVerticalFont = isVertical;
191 unitConversion (unit, GraphicsUnit.Point, emSize, out _sizeInPoints);
193 _bold = _italic = _strikeout = _underline = false;
195 if ((style & FontStyle.Bold) == FontStyle.Bold)
196 _bold = true;
198 if ((style & FontStyle.Italic) == FontStyle.Italic)
199 _italic = true;
201 if ((style & FontStyle.Strikeout) == FontStyle.Strikeout)
202 _strikeout = true;
204 if ((style & FontStyle.Underline) == FontStyle.Underline)
205 _underline = true;
208 public static Font FromHfont (IntPtr hfont)
210 IntPtr newObject;
211 IntPtr hdc;
212 FontStyle newStyle = FontStyle.Regular;
213 float newSize;
214 LOGFONT lf = new LOGFONT ();
216 // Sanity. Should we throw an exception?
217 if (hfont == IntPtr.Zero) {
218 Font result = new Font ("Arial", (float)10.0, FontStyle.Regular);
219 return(result);
222 if (GDIPlus.RunningOnUnix ()) {
223 // If we're on Unix we use our private gdiplus API to avoid Wine
224 // dependencies in S.D
225 Status s = GDIPlus.GdipCreateFontFromHfont (hfont, out newObject, ref lf);
226 GDIPlus.CheckStatus (s);
227 } else {
229 // This needs testing
230 // GetDC, SelectObject, ReleaseDC GetTextMetric and
231 // GetFontFace are not really GDIPlus, see gdipFunctions.cs
233 newStyle = FontStyle.Regular;
235 hdc = GDIPlus.GetDC (IntPtr.Zero);
236 try {
237 return FromLogFont (lf, hdc);
239 finally {
240 GDIPlus.ReleaseDC (IntPtr.Zero, hdc);
244 if (lf.lfItalic != 0) {
245 newStyle |= FontStyle.Italic;
248 if (lf.lfUnderline != 0) {
249 newStyle |= FontStyle.Underline;
252 if (lf.lfStrikeOut != 0) {
253 newStyle |= FontStyle.Strikeout;
256 if (lf.lfWeight > 400) {
257 newStyle |= FontStyle.Bold;
260 if (lf.lfHeight < 0) {
261 newSize = lf.lfHeight * -1;
262 } else {
263 newSize = lf.lfHeight;
266 return (new Font (newObject, lf.lfFaceName, newStyle, newSize));
269 public IntPtr ToHfont ()
271 if (fontObject == IntPtr.Zero)
272 throw new ArgumentException (Locale.GetText ("Object has been disposed."));
274 if (GDIPlus.RunningOnUnix ())
275 return fontObject;
277 // win32 specific code
278 if (olf == null) {
279 olf = new LOGFONT ();
280 ToLogFont(olf);
282 LOGFONT lf = (LOGFONT)olf;
283 return GDIPlus.CreateFontIndirect (ref lf);
286 internal Font (IntPtr newFontObject, string familyName, FontStyle style, float size)
288 FontFamily fontFamily;
290 try {
291 fontFamily = new FontFamily (familyName);
293 catch (Exception){
294 fontFamily = FontFamily.GenericSansSerif;
297 setProperties (fontFamily, size, style, GraphicsUnit.Pixel, 0, false);
298 fontObject = newFontObject;
301 public Font (Font prototype, FontStyle newStyle)
303 // no null checks, MS throws a NullReferenceException if original is null
304 setProperties (prototype.FontFamily, prototype.Size, newStyle, prototype.Unit, prototype.GdiCharSet, prototype.GdiVerticalFont);
306 Status status = GDIPlus.GdipCreateFont (_fontFamily.NativeObject, Size, Style, Unit, out fontObject);
307 GDIPlus.CheckStatus (status);
310 public Font (FontFamily family, float emSize, GraphicsUnit unit)
311 : this (family, emSize, FontStyle.Regular, unit, DefaultCharSet, false)
315 public Font (string familyName, float emSize, GraphicsUnit unit)
316 : this (new FontFamily (familyName), emSize, FontStyle.Regular, unit, DefaultCharSet, false)
320 public Font (FontFamily family, float emSize)
321 : this (family, emSize, FontStyle.Regular, GraphicsUnit.Point, DefaultCharSet, false)
325 public Font (FontFamily family, float emSize, FontStyle style)
326 : this (family, emSize, style, GraphicsUnit.Point, DefaultCharSet, false)
330 public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit)
331 : this (family, emSize, style, unit, DefaultCharSet, false)
335 public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet)
336 : this (family, emSize, style, unit, gdiCharSet, false)
340 public Font (FontFamily family, float emSize, FontStyle style,
341 GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont)
343 if (family == null)
344 throw new ArgumentNullException ("family");
346 Status status;
347 setProperties (family, emSize, style, unit, gdiCharSet, gdiVerticalFont );
348 status = GDIPlus.GdipCreateFont (family.NativeObject, emSize, style, unit, out fontObject);
349 GDIPlus.CheckStatus (status);
352 public Font (string familyName, float emSize)
353 : this (familyName, emSize, FontStyle.Regular, GraphicsUnit.Point, DefaultCharSet, false)
357 public Font (string familyName, float emSize, FontStyle style)
358 : this (familyName, emSize, style, GraphicsUnit.Point, DefaultCharSet, false)
362 public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit)
363 : this (familyName, emSize, style, unit, DefaultCharSet, false)
367 public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet)
368 : this (familyName, emSize, style, unit, gdiCharSet, false)
372 public Font (string familyName, float emSize, FontStyle style,
373 GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont )
375 CreateFont (familyName, emSize, style, unit, gdiCharSet, gdiVerticalFont );
377 #if NET_2_0
378 internal Font (string familyName, float emSize, string systemName)
379 : this (familyName, emSize, FontStyle.Regular, GraphicsUnit.Point, DefaultCharSet, false)
381 systemFontName = systemName;
383 #endif
384 public object Clone ()
386 return new Font (this, Style);
389 internal IntPtr NativeObject {
390 get {
391 return fontObject;
395 private bool _bold;
397 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
398 public bool Bold {
399 get {
400 return _bold;
404 private FontFamily _fontFamily;
406 [Browsable (false)]
407 public FontFamily FontFamily {
408 get {
409 return _fontFamily;
413 private byte _gdiCharSet;
415 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
416 public byte GdiCharSet {
417 get {
418 return _gdiCharSet;
422 private bool _gdiVerticalFont;
424 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
425 public bool GdiVerticalFont {
426 get {
427 return _gdiVerticalFont;
431 [Browsable (false)]
432 public int Height {
433 get {
434 return (int) Math.Ceiling (GetHeight ());
438 #if NET_2_0
439 [Browsable(false)]
440 public bool IsSystemFont {
441 get {
442 if (systemFontName == null)
443 return false;
445 return StringComparer.InvariantCulture.Compare (systemFontName, string.Empty) != 0;
448 #endif
450 private bool _italic;
452 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
453 public bool Italic {
454 get {
455 return _italic;
459 private string _name;
461 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
462 [Editor ("System.Drawing.Design.FontNameEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
463 [TypeConverter (typeof (FontConverter.FontNameConverter))]
464 public string Name {
465 get {
466 return _name;
470 public float Size {
471 get {
472 return _size;
476 private float _sizeInPoints;
478 [Browsable (false)]
479 public float SizeInPoints {
480 get {
481 return _sizeInPoints;
485 private bool _strikeout;
487 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
488 public bool Strikeout {
489 get {
490 return _strikeout;
494 private FontStyle _style;
496 [Browsable (false)]
497 public FontStyle Style {
498 get {
499 return _style;
503 #if NET_2_0
504 [Browsable(false)]
505 public string SystemFontName {
506 get {
507 return systemFontName;
511 [Browsable(false)]
512 public string OriginalFontName {
513 get {
514 return originalFontName;
517 #endif
518 private bool _underline;
520 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
521 public bool Underline {
522 get {
523 return _underline;
527 private GraphicsUnit _unit;
529 [TypeConverter (typeof (FontConverter.FontUnitConverter))]
530 public GraphicsUnit Unit {
531 get {
532 return _unit;
536 public override bool Equals (object obj)
538 Font fnt = (obj as Font);
539 if (fnt == null)
540 return false;
542 if (fnt.FontFamily.Equals (FontFamily) && fnt.Size == Size &&
543 fnt.Style == Style && fnt.Unit == Unit &&
544 fnt.GdiCharSet == GdiCharSet &&
545 fnt.GdiVerticalFont == GdiVerticalFont)
546 return true;
547 else
548 return false;
551 public override int GetHashCode ()
553 return _name.GetHashCode () ^ FontFamily.GetHashCode () ^ _size.GetHashCode () ^ _style.GetHashCode () ^
554 _gdiCharSet ^ _gdiVerticalFont.GetHashCode ();
557 [MonoTODO ("The hdc parameter has no direct equivalent in libgdiplus.")]
558 public static Font FromHdc (IntPtr hdc)
560 throw new NotImplementedException ();
563 [MonoTODO ("The returned font may not have all it's properties initialized correctly.")]
564 public static Font FromLogFont (object lf, IntPtr hdc)
566 IntPtr newObject;
567 LOGFONT o = (LOGFONT)lf;
568 Status status = GDIPlus.GdipCreateFontFromLogfont (hdc, ref o, out newObject);
569 GDIPlus.CheckStatus (status);
570 return new Font (newObject, "Microsoft Sans Serif", FontStyle.Regular, 10);
573 public float GetHeight ()
575 return GetHeight (Graphics.systemDpiY);
578 public static Font FromLogFont (object lf)
580 if (GDIPlus.RunningOnUnix ())
581 return FromLogFont(lf, IntPtr.Zero);
583 // win32 specific code
584 IntPtr hDC = IntPtr.Zero;
585 try {
586 hDC = GDIPlus.GetDC(IntPtr.Zero);
587 return FromLogFont (lf, hDC);
589 finally {
590 GDIPlus.ReleaseDC (IntPtr.Zero, hDC);
594 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
595 public void ToLogFont (object logFont)
597 if (GDIPlus.RunningOnUnix ()) {
598 // Unix - We don't have a window we could associate the DC with
599 // so we use an image instead
600 using (Bitmap img = new Bitmap (1, 1, Imaging.PixelFormat.Format32bppArgb)) {
601 using (Graphics g = Graphics.FromImage (img)) {
602 ToLogFont (logFont, g);
605 } else {
606 // Windows
607 IntPtr hDC = GDIPlus.GetDC (IntPtr.Zero);
608 try {
609 using (Graphics g = Graphics.FromHdc (hDC)) {
610 ToLogFont (logFont, g);
613 finally {
614 GDIPlus.ReleaseDC (IntPtr.Zero, hDC);
619 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
620 public void ToLogFont (object logFont, Graphics graphics)
622 if (graphics == null)
623 throw new ArgumentNullException ("graphics");
625 if (logFont == null) {
626 #if NET_2_0
627 throw new AccessViolationException ("logFont");
628 #else
629 throw new NullReferenceException ("logFont");
630 #endif
633 Type st = logFont.GetType ();
634 if (!st.IsLayoutSequential)
635 throw new ArgumentException ("logFont", Locale.GetText ("Layout must be sequential."));
637 // note: there is no exception if 'logFont' isn't big enough
638 Type lf = typeof (LOGFONT);
639 int size = Marshal.SizeOf (logFont);
640 if (size >= Marshal.SizeOf (lf)) {
641 Status status;
642 IntPtr copy = Marshal.AllocHGlobal (size);
643 try {
644 Marshal.StructureToPtr (logFont, copy, false);
646 status = GDIPlus.GdipGetLogFont (NativeObject, graphics.NativeObject, logFont);
647 if (status != Status.Ok) {
648 // reset to original values
649 Marshal.PtrToStructure (copy, logFont);
652 finally {
653 Marshal.FreeHGlobal (copy);
656 if (CharSetOffset == -1) {
657 // not sure why this methods returns an IntPtr since it's an offset
658 // anyway there's no issue in downcasting the result into an int32
659 CharSetOffset = (int) Marshal.OffsetOf (lf, "lfCharSet");
662 // note: Marshal.WriteByte(object,*) methods are unimplemented on Mono
663 GCHandle gch = GCHandle.Alloc (logFont, GCHandleType.Pinned);
664 try {
665 IntPtr ptr = gch.AddrOfPinnedObject ();
666 // if GDI+ lfCharSet is 0, then we return (S.D.) 1, otherwise the value is unchanged
667 if (Marshal.ReadByte (ptr, CharSetOffset) == 0) {
668 // set lfCharSet to 1
669 Marshal.WriteByte (ptr, CharSetOffset, 1);
672 finally {
673 gch.Free ();
676 // now we can throw, if required
677 GDIPlus.CheckStatus (status);
681 public float GetHeight (Graphics graphics)
683 if (graphics == null)
684 throw new ArgumentNullException ("graphics");
686 float size;
687 Status status = GDIPlus.GdipGetFontHeight (fontObject, graphics.NativeObject, out size);
688 GDIPlus.CheckStatus (status);
689 return size;
692 public float GetHeight (float dpi)
694 float size;
695 Status status = GDIPlus.GdipGetFontHeightGivenDPI (fontObject, dpi, out size);
696 GDIPlus.CheckStatus (status);
697 return size;
700 public override String ToString ()
702 return String.Format ("[Font: Name={0}, Size={1}, Units={2}, GdiCharSet={3}, GdiVerticalFont={4}]", _name, Size, (int)_unit, _gdiCharSet, _gdiVerticalFont);