merge -r 58784:58785
[mono.git] / mcs / class / System.Drawing / System.Drawing / Font.cs
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)
10 //
11 // Copyright (C) 2004 Ximian, Inc. (http://www.ximian.com)
12 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
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:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
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.
33 //
34
35 using System;
36 using System.Runtime.Serialization;
37 using System.Runtime.InteropServices;
38 using System.ComponentModel;
39
40 namespace System.Drawing
41 {
42         [Serializable]
43         [ComVisible (true)]
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
47         {
48                 private IntPtr  fontObject = IntPtr.Zero;
49
50                 private void CreateFont(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical) {
51                         Status          status;                  
52                         FontFamily      family;                      
53
54                         // NOTE: If family name is null, empty or invalid,
55                         // MS creates Microsoft Sans Serif font.
56                         try {
57                                 family = new FontFamily (familyName);
58                         }
59                         catch (Exception){
60                                 family = FontFamily.GenericSansSerif;
61                         }
62
63                         setProperties (family, emSize, style, unit, charSet, isVertical);           
64                         status = GDIPlus.GdipCreateFont (family.NativeObject, emSize,  style, unit, out fontObject);
65                         GDIPlus.CheckStatus (status);
66                 }
67
68                 private Font (SerializationInfo info, StreamingContext context)
69                 {
70                         string          name;
71                         float           size;
72                         FontStyle       style;
73                         GraphicsUnit    unit;
74
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));
79  
80                         CreateFont(name, size, style, unit, (byte)0, false);
81                 }
82
83                 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
84                 {
85                         info.AddValue("Name", Name);
86                         info.AddValue("Size", Size);
87                         info.AddValue("Style", Style);
88                         info.AddValue("Unit", Unit);
89                 }
90
91                 ~Font()
92                 {
93                         Dispose ();
94                 }
95
96                 public void Dispose ()
97                 {
98                         if (fontObject != IntPtr.Zero) {
99                                 GDIPlus.CheckStatus (GDIPlus.GdipDeleteFont (fontObject));
100                                 fontObject = IntPtr.Zero;
101                                 GC.SuppressFinalize (this);
102                         }
103                 }
104
105                 internal void unitConversion (GraphicsUnit fromUnit, GraphicsUnit toUnit, float nSrc, out float nTrg)
106                 {
107                         float inchs = 0;
108                         nTrg = 0;
109                         
110                         switch (fromUnit) {
111                         case GraphicsUnit.Display:
112                                 inchs = nSrc / 75f;
113                                 break;
114                         case GraphicsUnit.Document:
115                                 inchs = nSrc / 300f;
116                                 break;
117                         case GraphicsUnit.Inch:
118                                 inchs = nSrc;
119                                 break;
120                         case GraphicsUnit.Millimeter:
121                                 inchs = nSrc / 25.4f;
122                                 break;
123                         case GraphicsUnit.Pixel:
124                         case GraphicsUnit.World:
125                                 inchs = nSrc / Graphics.systemDpiX;
126                                 break;
127                         case GraphicsUnit.Point:
128                                 inchs = nSrc / 72f;
129                                 break;
130                         default:
131                                 throw new ArgumentException("Invalid GraphicsUnit");
132                         }
133
134                         switch (toUnit) {
135                         case GraphicsUnit.Display:
136                                 nTrg = inchs * 75;
137                                 break;
138                         case GraphicsUnit.Document:
139                                 nTrg = inchs * 300;
140                                 break;
141                         case GraphicsUnit.Inch:
142                                 nTrg = inchs;
143                                 break;
144                         case GraphicsUnit.Millimeter:
145                                 nTrg = inchs * 25.4f;
146                                 break;
147                         case GraphicsUnit.Pixel:
148                         case GraphicsUnit.World:
149                                 nTrg = inchs * Graphics.systemDpiX;
150                                 break;
151                         case GraphicsUnit.Point:
152                                 nTrg = inchs * 72;
153                                 break;
154                         default:
155                                 throw new ArgumentException("Invalid GraphicsUnit");
156                         }
157                 }
158
159                 internal void setProperties (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
160                 {
161                         _name = family.Name;
162                         _fontFamily = family;
163                         _size = emSize;
164
165                         // MS throws ArgumentException, if unit is set to GraphicsUnit.Display
166                         _unit = unit;
167                         _style = style;
168                         _gdiCharSet = charSet;
169                         _gdiVerticalFont = isVertical;
170                         
171                         unitConversion (unit, GraphicsUnit.Point, emSize, out  _sizeInPoints);
172                                                 
173                         _bold = _italic = _strikeout = _underline = false;
174
175                         if ((style & FontStyle.Bold) == FontStyle.Bold)
176                                 _bold = true;
177                                 
178                         if ((style & FontStyle.Italic) == FontStyle.Italic)
179                                _italic = true;
180
181                         if ((style & FontStyle.Strikeout) == FontStyle.Strikeout)
182                                 _strikeout = true;
183
184                         if ((style & FontStyle.Underline) == FontStyle.Underline)
185                                 _underline = true;                  
186                 }
187
188                 public static Font FromHfont (IntPtr Hfont)
189                 {
190                         OperatingSystem osInfo = Environment.OSVersion;
191                         IntPtr                  newObject;
192                         IntPtr                  hdc;                    
193                         FontStyle               newStyle = FontStyle.Regular;
194                         float                   newSize;
195                         LOGFONTA                lf = new LOGFONTA ();
196
197                         // Sanity. Should we throw an exception?
198                         if (Hfont == IntPtr.Zero) {
199                                 Font result = new Font ("Arial", (float)10.0, FontStyle.Regular);
200                                 return(result);
201                         }
202
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
206
207                                 Status s = GDIPlus.GdipCreateFontFromHfont (Hfont, out newObject, ref lf);
208                                 GDIPlus.CheckStatus (s);
209                                 
210                         } else {
211
212                                 // This needs testing
213                                 // GetDC, SelectObject, ReleaseDC GetTextMetric and
214                                 // GetFontFace are not really GDIPlus, see gdipFunctions.cs
215
216                                 newStyle = FontStyle.Regular;
217
218                                 hdc = GDIPlus.GetDC (IntPtr.Zero);
219                                 Font f = FromLogFont (lf, hdc);
220                                 GDIPlus.ReleaseDC (hdc);
221                                 return f;                               
222                         }
223
224                         if (lf.lfItalic != 0) {
225                                 newStyle |= FontStyle.Italic;
226                         }
227
228                         if (lf.lfUnderline != 0) {
229                                 newStyle |= FontStyle.Underline;
230                         }
231
232                         if (lf.lfStrikeOut != 0) {
233                                 newStyle |= FontStyle.Strikeout;
234                         }
235
236                         if (lf.lfWeight > 400) {
237                                 newStyle |= FontStyle.Bold;
238                         }
239
240                         if (lf.lfHeight < 0) {
241                                 newSize = lf.lfHeight * -1;
242                         } else {
243                                 newSize = lf.lfHeight;
244                         }
245
246                         return (new Font (newObject, lf.lfFaceName, newStyle, newSize));
247                 }
248
249                 public IntPtr ToHfont ()
250                 {
251                         IntPtr Hfont;
252                         OperatingSystem osInfo = Environment.OSVersion;
253
254                         // Sanity. Should we throw an exception?
255                         if (fontObject == IntPtr.Zero) {
256                                 return IntPtr.Zero;
257                         }
258
259                         if ((int) osInfo.Platform == 128 || (int) osInfo.Platform == 4) {
260                                 return fontObject;
261                         } else {
262                                 LOGFONTA lf = new LOGFONTA ();
263                                 ToLogFont(lf);
264                                 Hfont = GDIPlus.CreateFontIndirectA (ref lf);
265                         }
266                         return Hfont;
267                 }
268
269                 internal Font (IntPtr newFontObject, string familyName, FontStyle style, float size)
270                 {
271                         FontFamily fontFamily;                  
272                         
273                         try {
274                                 fontFamily = new FontFamily (familyName);
275                         }
276                         catch (Exception){
277                                 fontFamily = FontFamily.GenericSansSerif;
278                         }
279                         
280                         setProperties (fontFamily, size, style, GraphicsUnit.Pixel, 0, false);
281                         fontObject = newFontObject;
282                 }
283
284                 public Font (Font original, FontStyle style)
285                 {
286                         Status status;
287                         setProperties (original.FontFamily, original.Size, style, original.Unit, original.GdiCharSet, original.GdiVerticalFont);
288                                 
289                         status = GDIPlus.GdipCreateFont (_fontFamily.NativeObject,      Size,  Style,   Unit,  out fontObject);
290                         GDIPlus.CheckStatus (status);                   
291                 }
292
293                 public Font (FontFamily family, float emSize,  GraphicsUnit unit)
294                         : this (family, emSize, FontStyle.Regular, unit, (byte)0, false)
295                 {
296                 }
297
298                 public Font (string familyName, float emSize,  GraphicsUnit unit)
299                         : this (new FontFamily (familyName), emSize, FontStyle.Regular, unit, (byte)0, false)
300                 {
301                 }
302
303                 public Font (FontFamily family, float emSize)
304                         : this (family, emSize, FontStyle.Regular, GraphicsUnit.Point, (byte)0, false)
305                 {
306                 }
307
308                 public Font (FontFamily family, float emSize, FontStyle style)
309                         : this (family, emSize, style, GraphicsUnit.Point, (byte)0, false)
310                 {
311                 }
312
313                 public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit)
314                         : this (family, emSize, style, unit, (byte)0, false)
315                 {
316                 }
317
318                 public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet)
319                         : this (family, emSize, style, unit, charSet, false)
320                 {
321                 }
322
323                 public Font (FontFamily family, float emSize, FontStyle style,
324                                 GraphicsUnit unit, byte charSet, bool isVertical)
325                 {
326                         // MS does not accept null family
327                         Status status;
328                         setProperties (family, emSize, style, unit, charSet, isVertical);               
329                         status = GDIPlus.GdipCreateFont (family.NativeObject, emSize,  style,   unit,  out fontObject);
330                         GDIPlus.CheckStatus (status);
331                 }
332
333                 public Font (string familyName, float emSize)
334                         : this (familyName, emSize, FontStyle.Regular, GraphicsUnit.Point, (byte)0, false)
335                 {
336                 }
337
338                 public Font (string familyName, float emSize, FontStyle style)
339                         : this (familyName, emSize, style, GraphicsUnit.Point, (byte)0, false)
340                 {
341                 }
342
343                 public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit)
344                         : this (familyName, emSize, style, unit, (byte)0, false)
345                 {
346                 }
347
348                 public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet)
349                         : this (familyName, emSize, style, unit, charSet, false)
350                 {
351                 }
352
353                 public Font (string familyName, float emSize, FontStyle style,
354                                 GraphicsUnit unit, byte charSet, bool isVertical)
355                 {
356                         CreateFont(familyName, emSize, style, unit, charSet, isVertical);
357                 }
358
359                 public object Clone ()
360                 {
361                         return new Font (this, Style);
362                 }
363
364                 internal IntPtr NativeObject {            
365                         get {
366                                         return fontObject;
367                         }
368                         set {
369                                         fontObject = value;
370                         }
371                 }
372
373                 private bool _bold;
374
375                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
376                 public bool Bold {
377                         get {
378                                 return _bold;
379                         }
380                 }
381
382                 private FontFamily _fontFamily;
383
384                 [Browsable (false)]
385                 public FontFamily FontFamily {
386                         get {
387                                 return _fontFamily;
388                         }
389                 }
390
391                 private byte _gdiCharSet;
392
393                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
394                 public byte GdiCharSet {
395                         get {
396                                 return _gdiCharSet;
397                         }
398                 }
399
400                 private bool _gdiVerticalFont;
401
402                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
403                 public bool GdiVerticalFont {
404                         get {
405                                 return _gdiVerticalFont;
406                         }
407                 }
408
409                 [Browsable (false)]
410                 public int Height {
411                         get {
412                                 return (int) Math.Ceiling (GetHeight ());
413                         }
414                 }
415
416                 private bool _italic;
417
418                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
419                 public bool Italic {
420                         get {
421                                 return _italic;
422                         }
423                 }
424
425                 private string _name;
426
427                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
428                 [Editor ("System.Drawing.Design.FontNameEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
429                 [TypeConverter (typeof (FontConverter.FontNameConverter))]
430                 public string Name {
431                         get {
432                                 return _name;
433                         }
434                 }
435
436                 private float _size;
437                 public float Size {
438                         get {
439                                 return _size;
440                         }
441                 }
442
443                 private float _sizeInPoints;
444
445                 [Browsable (false)]
446                 public float SizeInPoints {
447                         get {
448                                 return _sizeInPoints;
449                         }
450                 }
451
452                 private bool _strikeout;
453
454                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
455                 public bool Strikeout {
456                         get {
457                                 return _strikeout;
458                         }
459                 }
460                 
461                 private FontStyle _style;
462
463                 [Browsable (false)]
464                 public FontStyle Style {
465                         get {
466                                 return _style;
467                         }
468                 }
469
470                 private bool _underline;
471
472                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
473                 public bool Underline {
474                         get {
475                                 return _underline;
476                         }
477                 }
478
479                 private GraphicsUnit _unit;
480
481                 [TypeConverter (typeof (FontConverter.FontUnitConverter))]
482                 public GraphicsUnit Unit {
483                         get {
484                                 return _unit;
485                         }
486                 }
487
488                 public override bool Equals (object obj)
489                 {
490                         if (! (obj is Font))
491                                 return false;
492                                 
493                         Font fnt = (Font) obj;                  
494                         
495                         if (fnt.FontFamily.Equals (FontFamily) && fnt.Size == Size &&
496                             fnt.Style == Style && fnt.Unit == Unit &&
497                             fnt.GdiCharSet == GdiCharSet && 
498                             fnt.GdiVerticalFont == GdiVerticalFont)
499                                 return true;
500                         else
501                                 return false;
502                 }
503
504                 public override int GetHashCode ()
505                 {
506                         return _name.GetHashCode ();
507                 }
508
509                 [MonoTODO]
510                 public static Font FromHdc (IntPtr hdc)
511                 {
512                         throw new NotImplementedException ();
513                 }
514
515                 [MonoTODO("This is temporary implementation")]
516                 public static Font FromLogFont (object lf,  IntPtr hdc)
517                 {
518                         IntPtr newObject;
519                         LOGFONTA o = (LOGFONTA)lf;
520                         GDIPlus.GdipCreateFontFromLogfontA (hdc, ref o, out newObject);
521                         return new Font (newObject, "Microsoft Sans Serif", FontStyle.Regular, 10);
522                 }
523
524                 public float GetHeight ()
525                 {
526                         return GetHeight (Graphics.systemDpiY);
527                 }
528
529                 [MonoTODO]
530                 public static Font FromLogFont (object lf)
531                 {
532                         throw new NotImplementedException ();
533                 }
534
535                 public void ToLogFont (object logFont)
536                 {
537                         using (Graphics g = Graphics.FromHdc (GDIPlus.GetDC (IntPtr.Zero))) {
538                                 ToLogFont (logFont, g);
539                         }
540                 }
541
542                 public void ToLogFont (object logFont, Graphics graphics)
543                 {
544                         if (graphics == null) {
545                                 throw new ArgumentNullException ("graphics");
546                         }
547
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));
551                 }
552
553                 public float GetHeight (Graphics graphics)
554                 {
555                         float height = GetHeight (graphics.DpiY);
556
557                         switch (graphics.PageUnit) {
558                                 case GraphicsUnit.Document:
559                                         height *= (300f / graphics.DpiY);
560                                         break;
561                                 case GraphicsUnit.Display:
562                                         height *= (75f / graphics.DpiY);
563                                         break;
564                                 case GraphicsUnit.Inch:
565                                         height /=  graphics.DpiY;
566                                         break;
567                                 case GraphicsUnit.Millimeter:
568                                         height *= (25.4f / graphics.DpiY);
569                                         break;
570                                 case GraphicsUnit.Point:
571                                         height *= (72f / graphics.DpiY);
572                                         break;
573
574                                 case GraphicsUnit.Pixel:
575                                 case GraphicsUnit.World:
576                                 default:
577                                         break;
578                         }
579
580                         return height;
581                 }
582
583                 public float GetHeight (float dpi)
584                 {
585                         float height;
586                         int emHeight = _fontFamily.GetEmHeight (_style);
587                         int lineSpacing = _fontFamily.GetLineSpacing (_style);
588
589                         height = lineSpacing * (_size / emHeight);
590
591                         switch (_unit) {
592                                 case GraphicsUnit.Document:
593                                         height *= (dpi / 300f);
594                                         break;
595                                 case GraphicsUnit.Display:
596                                         height *= (dpi / 75f);
597                                         break;
598                                 case GraphicsUnit.Inch:
599                                         height *= dpi;
600                                         break;
601                                 case GraphicsUnit.Millimeter:
602                                         height *= (dpi / 25.4f);
603                                         break;
604                                 case GraphicsUnit.Point:
605                                         height *= (dpi / 72f);
606                                         break;
607
608                                 case GraphicsUnit.Pixel:
609                                 case GraphicsUnit.World:
610                                 default:
611                                         break;
612                         }
613
614                         return height;
615                 }
616
617                 public override String ToString ()
618                 {
619                         return String.Format ("[Font: Name={0}, Size={1}, Units={2}, GdiCharSet={3}, GdiVerticalFont={4}]", _name, _size, (int)_unit, _gdiCharSet, _gdiVerticalFont);
620                 }
621         }
622 }