Fix for the issue of getting occasional -5875 error on the server when
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TextRenderer.cs
1 //
2 // TextRenderer.cs
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 // Copyright (c) 2006 Novell, Inc.
24 //
25 // Authors:
26 //      Jonathan Pobst (monkey@jpobst.com)
27 //
28
29 // This has become a monster class for all things text measuring and drawing.
30 //
31 // The public API is MeasureText/DrawText, which uses GDI on Win32, and
32 // GDI+ on other platforms.
33 //
34 // There is an internal API MeasureTextInternal/DrawTextInternal, which allows
35 // you to pass a flag of whether to use GDI or GDI+.  This is used mainly for
36 // controls that have the UseCompatibleTextRendering flag.
37 //
38 // There are also thread-safe versions of MeasureString/MeasureCharacterRanges
39 // for things that want to measure strings without having a Graphics object.
40
41 using System.Drawing;
42 using System.Runtime.InteropServices;
43 using System.Text;
44 using System.Drawing.Text;
45
46 namespace System.Windows.Forms
47 {
48 #if NET_2_0
49         public sealed 
50 #endif
51         class TextRenderer
52         {
53                 [ThreadStatic]
54                 private static Bitmap static_bitmap;
55                 [ThreadStatic]
56                 private static Graphics static_graphics;
57
58                 private TextRenderer ()
59                 {
60                 }
61
62                 #region Public Methods
63 #if NET_2_0
64                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor)
65                 {
66                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, false);
67                 }
68
69                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor)
70                 {
71                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false);
72                 }
73
74                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor)
75                 {
76                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, false);
77                 }
78
79                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags)
80                 {
81                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, false);
82                 }
83
84                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor)
85                 {
86                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false);
87                 }
88
89                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags)
90                 {
91                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, false);
92                 }
93
94                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags)
95                 {
96                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, flags, false);
97                 }
98
99                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags)
100                 {
101                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, flags, false);
102                 }
103
104                 public static Size MeasureText (string text, Font font)
105                 {
106                         return MeasureTextInternal (StaticGraphics, text, font, Size.Empty, TextFormatFlags.Default, false);
107                 }
108
109                 public static Size MeasureText (IDeviceContext dc, string text, Font font)
110                 {
111                         return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, false);
112                 }
113
114                 public static Size MeasureText (string text, Font font, Size proposedSize)
115                 {
116                         return MeasureTextInternal (StaticGraphics, text, font, proposedSize, TextFormatFlags.Default, false);
117                 }
118
119                 public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize)
120                 {
121                         return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, false);
122                 }
123
124                 public static Size MeasureText (string text, Font font, Size proposedSize, TextFormatFlags flags)
125                 {
126                         return MeasureTextInternal (StaticGraphics, text, font, proposedSize, flags, false);
127                 }
128
129                 public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags)
130                 {
131                         return MeasureTextInternal (dc, text, font, proposedSize, flags, false);
132                 }
133 #endif
134                 #endregion
135
136                 #region Internal Methods That Do Stuff
137 #if NET_2_0
138                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
139 #else
140                 internal static void DrawTextInternal (Graphics dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
141 #endif
142                 {
143                         if (dc == null)
144                                 throw new ArgumentNullException ("dc");
145
146                         if (text == null || text.Length == 0)
147                                 return;
148
149                         // We use MS GDI API's unless told not to, or we aren't on Windows
150                         if (!useDrawString && !XplatUI.RunningOnUnix) {
151                                 if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter || (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
152                                         flags |= TextFormatFlags.SingleLine;
153
154                                 // Calculate the text bounds (there is often padding added)
155                                 Rectangle new_bounds = PadRectangle (bounds, flags);
156                                 new_bounds.Offset ((int)(dc as Graphics).Transform.OffsetX, (int)(dc as Graphics).Transform.OffsetY);
157
158                                 IntPtr hdc = IntPtr.Zero;
159                                 bool clear_clip_region = false;
160                                 
161                                 // If we need to use the graphics clipping region, add it to our hdc
162                                 if ((flags & TextFormatFlags.PreserveGraphicsClipping) == TextFormatFlags.PreserveGraphicsClipping) {
163                                         Graphics graphics = (Graphics)dc;
164                                         Region clip_region = graphics.Clip;
165                                         
166                                         if (!clip_region.IsInfinite (graphics)) {
167                                                 IntPtr hrgn = clip_region.GetHrgn (graphics);
168                                                 hdc = dc.GetHdc ();
169                                                 SelectClipRgn (hdc, hrgn);
170                                                 DeleteObject (hrgn);
171                                                 
172                                                 clear_clip_region = true;
173                                         }
174                                 }
175                                 
176                                 if (hdc == IntPtr.Zero)
177                                         hdc = dc.GetHdc ();
178                                         
179                                 // Set the fore color
180                                 if (foreColor != Color.Empty)
181                                         SetTextColor (hdc, ColorTranslator.ToWin32 (foreColor));
182
183                                 // Set the back color
184                                 if (backColor != Color.Transparent && backColor != Color.Empty) {
185                                         SetBkMode (hdc, 2);     //1-Transparent, 2-Opaque
186                                         SetBkColor (hdc, ColorTranslator.ToWin32 (backColor));
187                                 }
188                                 else {
189                                         SetBkMode (hdc, 1);     //1-Transparent, 2-Opaque
190                                 }
191
192                                 XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new_bounds);
193
194                                 IntPtr prevobj;
195
196                                 if (font != null) {
197                                         prevobj = SelectObject (hdc, font.ToHfont ());
198                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
199                                         prevobj = SelectObject (hdc, prevobj);
200                                         DeleteObject (prevobj);
201                                 }
202                                 else {
203                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
204                                 }
205
206                                 if (clear_clip_region)
207                                         SelectClipRgn (hdc, IntPtr.Zero);
208
209 #if NET_2_0
210                                 dc.ReleaseHdc ();
211 #else
212                                 dc.ReleaseHdc (hdc);
213 #endif
214                         }
215                         // Use Graphics.DrawString as a fallback method
216                         else {
217                                 Graphics g;
218                                 IntPtr hdc = IntPtr.Zero;
219                                 
220                                 if (dc is Graphics)
221                                         g = (Graphics)dc;
222                                 else {
223                                         hdc = dc.GetHdc ();
224                                         g = Graphics.FromHdc (hdc);
225                                 }
226
227                                 StringFormat sf = FlagsToStringFormat (flags);
228
229                                 Rectangle new_bounds = PadDrawStringRectangle (bounds, flags);
230
231                                 g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (foreColor), new_bounds, sf);
232
233                                 if (!(dc is Graphics)) {
234                                         g.Dispose ();
235 #if NET_2_0
236                                         dc.ReleaseHdc ();
237 #else
238                                         if (hdc != IntPtr.Zero) dc.ReleaseHdc (hdc);
239 #endif
240                                 }
241                         }
242                 }
243
244 #if NET_2_0
245                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
246 #else
247                 internal static Size MeasureTextInternal (Graphics dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
248 #endif
249                 {
250                         if (!useMeasureString && !XplatUI.RunningOnUnix) {
251                                 // Tell DrawText to calculate size instead of draw
252                                 flags |= (TextFormatFlags)1024;         // DT_CALCRECT
253
254                                 IntPtr hdc = dc.GetHdc ();
255
256                                 XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new Rectangle (Point.Empty, proposedSize));
257
258                                 IntPtr prevobj;
259
260                                 if (font != null) {
261                                         prevobj = SelectObject (hdc, font.ToHfont ());
262                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
263                                         prevobj = SelectObject (hdc, prevobj);
264                                         DeleteObject (prevobj);
265                                 }
266                                 else {
267                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
268                                 }
269
270 #if NET_2_0
271                                 dc.ReleaseHdc ();
272 #else
273                                 dc.ReleaseHdc (hdc);
274 #endif
275
276                                 // Really, I am just making something up here, which as far as I can tell, MS
277                                 // just makes something up as well.  This will require lots of tweaking to match MS.  :(
278                                 Size retval = r.ToRectangle ().Size;
279
280                                 if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0) {
281                                         retval.Width += 6;
282                                         retval.Width += (int)retval.Height / 8;
283                                 }
284
285                                 return retval;
286                         }
287                         else {
288                         StringFormat sf = FlagsToStringFormat (flags);
289
290                                 Size retval;
291                                 
292                                 if (dc is Graphics)
293                                         retval = (dc as Graphics).MeasureString (text, font, Int32.MaxValue, sf).ToSize ();
294                                 else
295                                         retval = TextRenderer.MeasureString (text, font, Int32.MaxValue, sf).ToSize ();
296
297                                 if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0)
298                                         retval.Width += 9;
299
300                                 return retval;
301                         }
302                 }
303                 #endregion
304
305 #region Internal Methods That Are Just Overloads
306 #if NET_2_0
307                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, bool useDrawString)
308                 {
309                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, useDrawString);
310                 }
311
312                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, bool useDrawString)
313                 {
314                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
315                 }
316
317                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, bool useDrawString)
318                 {
319                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, useDrawString);
320                 }
321
322                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags, bool useDrawString)
323                 {
324                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, useDrawString);
325                 }
326
327                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, bool useDrawString)
328                 {
329                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
330                 }
331
332                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
333 #else
334                 internal static void DrawTextInternal (Graphics dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
335 #endif
336                 {
337                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, useDrawString);
338                 }
339
340                 internal static Size MeasureTextInternal (string text, Font font, bool useMeasureString)
341                 {
342                         return MeasureTextInternal (StaticGraphics, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
343                 }
344
345 #if NET_2_0
346                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
347                 {
348                         Size sz = MeasureTextInternal (dc, text, font, useDrawString);
349                         DrawTextInternal (dc, text, font, new Rectangle (pt, sz), foreColor, backColor, flags, useDrawString);
350                 }
351
352                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, bool useMeasureString)
353                 {
354                         return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
355                 }
356
357                 internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, bool useMeasureString)
358                 {
359                         return MeasureTextInternal (StaticGraphics, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
360                 }
361
362                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, bool useMeasureString)
363                 {
364                         return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
365                 }
366
367 #endif
368                 internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
369                 {
370                         return MeasureTextInternal (StaticGraphics, text, font, proposedSize, flags, useMeasureString);
371                 }
372 #endregion
373
374                 #region Thread-Safe Static Graphics Methods
375                 internal static SizeF MeasureString (string text, Font font)
376                 {
377                         return StaticGraphics.MeasureString (text, font);
378                 }
379
380                 internal static SizeF MeasureString (string text, Font font, int width)
381                 {
382                         return StaticGraphics.MeasureString (text, font, width);
383                 }
384
385                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea)
386                 {
387                         return StaticGraphics.MeasureString (text, font, layoutArea);
388                 }
389
390                 internal static SizeF MeasureString (string text, Font font, int width, StringFormat format)
391                 {
392                         return StaticGraphics.MeasureString (text, font, width, format);
393                 }
394
395                 internal static SizeF MeasureString (string text, Font font, PointF origin, StringFormat stringFormat)
396                 {
397                         return StaticGraphics.MeasureString (text, font, origin, stringFormat);
398                 }
399
400                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat)
401                 {
402                         return StaticGraphics.MeasureString (text, font, layoutArea, stringFormat);
403                 }
404
405                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat, out int charactersFitted, out int linesFilled)
406                 {
407                         return StaticGraphics.MeasureString (text, font, layoutArea, stringFormat, out charactersFitted, out linesFilled);
408                 }
409
410                 internal static Region[] MeasureCharacterRanges (string text, Font font, RectangleF layoutRect, StringFormat stringFormat)
411                 {
412                         return StaticGraphics.MeasureCharacterRanges (text, font, layoutRect, stringFormat);
413                 }
414                 
415                 internal static SizeF GetDpi ()
416                 {
417                         return new SizeF (StaticGraphics.DpiX, StaticGraphics.DpiY);
418                 }
419                 
420                 internal static Bitmap StaticBitmap {
421                         get {
422                                 if (static_bitmap == null)
423                                         static_bitmap = new Bitmap (1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
424                                 
425                                 return static_bitmap;
426                         }
427                 }
428                 
429                 internal static Graphics StaticGraphics {
430                         get {
431                                 if (static_graphics == null)
432                                         static_graphics = Graphics.FromImage (StaticBitmap);
433                                         
434                                 return static_graphics;
435                         }
436                 }
437                 #endregion
438                 
439 #region Private Methods
440                 private static StringFormat FlagsToStringFormat (TextFormatFlags flags)
441                 {
442                         StringFormat sf = new StringFormat ();
443
444                         // Translation table: http://msdn.microsoft.com/msdnmag/issues/06/03/TextRendering/default.aspx?fig=true#fig4
445
446                         // Horizontal Alignment
447                         if ((flags & TextFormatFlags.HorizontalCenter) == TextFormatFlags.HorizontalCenter)
448                                 sf.Alignment = StringAlignment.Center;
449                         else if ((flags & TextFormatFlags.Right) == TextFormatFlags.Right)
450                                 sf.Alignment = StringAlignment.Far;
451                         else
452                                 sf.Alignment = StringAlignment.Near;
453
454                         // Vertical Alignment
455                         if ((flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
456                                 sf.LineAlignment = StringAlignment.Far;
457                         else if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter)
458                                 sf.LineAlignment = StringAlignment.Center;
459                         else
460                                 sf.LineAlignment = StringAlignment.Near;
461
462                         // Ellipsis
463                         if ((flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis)
464                                 sf.Trimming = StringTrimming.EllipsisCharacter;
465                         else if ((flags & TextFormatFlags.PathEllipsis) == TextFormatFlags.PathEllipsis)
466                                 sf.Trimming = StringTrimming.EllipsisPath;
467                         else if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis)
468                                 sf.Trimming = StringTrimming.EllipsisWord;
469                         else
470                                 sf.Trimming = StringTrimming.Character;
471
472                         // Hotkey Prefix
473                         if ((flags & TextFormatFlags.NoPrefix) == TextFormatFlags.NoPrefix)
474                                 sf.HotkeyPrefix = HotkeyPrefix.None;
475                         else if ((flags & TextFormatFlags.HidePrefix) == TextFormatFlags.HidePrefix)
476                                 sf.HotkeyPrefix = HotkeyPrefix.Hide;
477                         else
478                                 sf.HotkeyPrefix = HotkeyPrefix.Show;
479
480                         // Text Padding
481                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding)
482                                 sf.FormatFlags |= StringFormatFlags.FitBlackBox;
483
484                         // Text Wrapping
485                         if ((flags & TextFormatFlags.SingleLine) == TextFormatFlags.SingleLine)
486                                 sf.FormatFlags |= StringFormatFlags.NoWrap;
487                         else if ((flags & TextFormatFlags.TextBoxControl) == TextFormatFlags.TextBoxControl)
488                                 sf.FormatFlags |= StringFormatFlags.LineLimit;
489
490                         // Other Flags
491                         //if ((flags & TextFormatFlags.RightToLeft) == TextFormatFlags.RightToLeft)
492                         //        sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
493                         if ((flags & TextFormatFlags.NoClipping) == TextFormatFlags.NoClipping)
494                                 sf.FormatFlags |= StringFormatFlags.NoClip;
495
496                         return sf;
497                 }
498
499                 private static Rectangle PadRectangle (Rectangle r, TextFormatFlags flags)
500                 {
501                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
502                                 r.X += 3;
503                                 r.Width -= 3;
504                         }
505                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
506                                 r.Width -= 4;
507                         }
508                         if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
509                                 r.X += 2;
510                                 r.Width -= 2;
511                         }
512                         if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
513                                 r.Width -= 4;
514                         }
515                         if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
516                                 r.Y += 1;
517                         }
518
519                         return r;
520                 }
521
522                 private static Rectangle PadDrawStringRectangle (Rectangle r, TextFormatFlags flags)
523                 {
524                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
525                                 r.X += 1;
526                                 r.Width -= 1;
527                         }
528                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
529                                 r.Width -= 4;
530                         }
531                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding) {
532                                 r.X -= 2;
533                         }
534                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom) {
535                                 r.Y += 1;
536                         }
537                         if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
538                                 r.X += 2;
539                                 r.Width -= 2;
540                         }
541                         if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
542                                 r.Width -= 4;
543                         }
544                         if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
545                                 r.Y += 1;
546                         }
547
548                         return r;
549                 }
550 #endregion
551
552 #region DllImports (Windows)
553                 [DllImport ("user32", CharSet = CharSet.Unicode, EntryPoint = "DrawText")]
554                 static extern int Win32DrawText (IntPtr hdc, string lpStr, int nCount, ref XplatUIWin32.RECT lpRect, int wFormat);
555
556                 [DllImport ("gdi32")]
557                 static extern int SetTextColor (IntPtr hdc, int crColor);
558
559                 [DllImport ("gdi32")]
560                 static extern IntPtr SelectObject (IntPtr hDC, IntPtr hObject);
561
562                 [DllImport ("gdi32")]
563                 static extern int SetBkColor (IntPtr hdc, int crColor);
564
565                 [DllImport ("gdi32")]
566                 static extern int SetBkMode (IntPtr hdc, int iBkMode);
567
568                 [DllImport ("gdi32")]
569                 static extern bool DeleteObject (IntPtr objectHandle);
570
571                 [DllImport("gdi32")]
572                 static extern bool SelectClipRgn(IntPtr hdc, IntPtr hrgn);
573 #endregion
574         }
575 }