* ListView.cs: When doing layout calculations don't use a ref
[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 NET_2_0
144                         if (dc == null)
145                                 throw new ArgumentNullException ("dc");
146
147                         if (string.IsNullOrEmpty (text))
148                                 return;
149
150                         // We use MS GDI API's unless told not to, or we aren't on Windows
151                         if (!useDrawString && !XplatUI.RunningOnUnix) {
152                                 if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter || (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
153                                         flags |= TextFormatFlags.SingleLine;
154
155                                 // Calculate the text bounds (there is often padding added)
156                                 Rectangle new_bounds = PadRectangle (bounds, flags);
157                                 new_bounds.Offset ((int)(dc as Graphics).Transform.OffsetX, (int)(dc as Graphics).Transform.OffsetY);
158
159                                 IntPtr hdc = IntPtr.Zero;
160                                 bool clear_clip_region = false;
161                                 
162                                 // If we need to use the graphics clipping region, add it to our hdc
163                                 if ((flags & TextFormatFlags.PreserveGraphicsClipping) == TextFormatFlags.PreserveGraphicsClipping) {
164                                         Graphics graphics = (Graphics)dc;
165                                         Region clip_region = graphics.Clip;
166                                         
167                                         if (!clip_region.IsInfinite (graphics)) {
168                                                 IntPtr hrgn = clip_region.GetHrgn (graphics);
169                                                 hdc = dc.GetHdc ();
170                                                 SelectClipRgn (hdc, hrgn);
171                                                 clip_region.ReleaseHrgn (hrgn);
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                                 dc.ReleaseHdc ();
210                         }
211                         // Use Graphics.DrawString as a fallback method
212                         else {
213 #endif
214                         Graphics g;
215
216 #if NET_2_0
217                                 if (dc is Graphics)
218                                         g = (Graphics)dc;
219                                 else
220                                         g = Graphics.FromHdc (dc.GetHdc ());
221 #else
222                                         g = (Graphics)dc;
223
224 #endif
225
226                                 StringFormat sf = FlagsToStringFormat (flags);
227
228                                 Rectangle new_bounds = PadDrawStringRectangle (bounds, flags);
229
230                                 g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (foreColor), new_bounds, sf);
231
232 #if NET_2_0
233                                 if (!(dc is Graphics)) {
234                                         g.Dispose ();
235                                         dc.ReleaseHdc ();
236                                 }
237                         }
238 #endif
239                 }
240
241 #if NET_2_0
242                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
243 #else
244                 internal static Size MeasureTextInternal (Graphics dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
245 #endif
246                 {
247 #if NET_2_0
248                         if (!useMeasureString && !XplatUI.RunningOnUnix) {
249                                 // Tell DrawText to calculate size instead of draw
250                                 flags |= (TextFormatFlags)1024;         // DT_CALCRECT
251
252                                 IntPtr hdc = dc.GetHdc ();
253
254                                 XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new Rectangle (Point.Empty, proposedSize));
255
256                                 IntPtr prevobj;
257
258                                 if (font != null) {
259                                         prevobj = SelectObject (hdc, font.ToHfont ());
260                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
261                                         prevobj = SelectObject (hdc, prevobj);
262                                         DeleteObject (prevobj);
263                                 }
264                                 else {
265                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
266                                 }
267
268                                 dc.ReleaseHdc ();
269
270                                 // Really, I am just making something up here, which as far as I can tell, MS
271                                 // just makes something up as well.  This will require lots of tweaking to match MS.  :(
272                                 Size retval = r.ToRectangle ().Size;
273
274                                 if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0) {
275                                         retval.Width += 6;
276                                         retval.Width += (int)retval.Height / 8;
277                                 }
278
279                                 return retval;
280                         }
281                         else {
282 #endif
283                         StringFormat sf = FlagsToStringFormat (flags);
284
285                                 Size retval;
286                                 
287 #if NET_2_0
288                                 if (dc is Graphics)
289                                         retval = (dc as Graphics).MeasureString (text, font, Int32.MaxValue, sf).ToSize ();
290                                 else
291                                         retval = TextRenderer.MeasureString (text, font, Int32.MaxValue, sf).ToSize ();
292 #else
293                                 retval = dc.MeasureString (text, font, Int32.MaxValue, sf).ToSize ();
294 #endif
295
296                                 if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0)
297                                         retval.Width += 9;
298
299                                 return retval;
300                         }
301 #if NET_2_0
302                 }
303 #endif
304                 #endregion
305
306 #region Internal Methods That Are Just Overloads
307 #if NET_2_0
308                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, bool useDrawString)
309                 {
310                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, useDrawString);
311                 }
312
313                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, bool useDrawString)
314                 {
315                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
316                 }
317
318                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, bool useDrawString)
319                 {
320                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, useDrawString);
321                 }
322
323                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags, bool useDrawString)
324                 {
325                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, useDrawString);
326                 }
327
328                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, bool useDrawString)
329                 {
330                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
331                 }
332
333                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
334 #else
335                 internal static void DrawTextInternal (Graphics dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
336 #endif
337                 {
338                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, useDrawString);
339                 }
340
341                 internal static Size MeasureTextInternal (string text, Font font, bool useMeasureString)
342                 {
343                         return MeasureTextInternal (StaticGraphics, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
344                 }
345
346 #if NET_2_0
347                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
348                 {
349                         Size sz = MeasureTextInternal (dc, text, font, useDrawString);
350                         DrawTextInternal (dc, text, font, new Rectangle (pt, sz), foreColor, backColor, flags, useDrawString);
351                 }
352
353                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, bool useMeasureString)
354                 {
355                         return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
356                 }
357
358                 internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, bool useMeasureString)
359                 {
360                         return MeasureTextInternal (StaticGraphics, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
361                 }
362
363                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, bool useMeasureString)
364                 {
365                         return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
366                 }
367
368 #endif
369                 internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
370                 {
371                         return MeasureTextInternal (StaticGraphics, text, font, proposedSize, flags, useMeasureString);
372                 }
373 #endregion
374
375                 #region Thread-Safe Static Graphics Methods
376                 internal static SizeF MeasureString (string text, Font font)
377                 {
378                         return StaticGraphics.MeasureString (text, font);
379                 }
380
381                 internal static SizeF MeasureString (string text, Font font, int width)
382                 {
383                         return StaticGraphics.MeasureString (text, font, width);
384                 }
385
386                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea)
387                 {
388                         return StaticGraphics.MeasureString (text, font, layoutArea);
389                 }
390
391                 internal static SizeF MeasureString (string text, Font font, int width, StringFormat format)
392                 {
393                         return StaticGraphics.MeasureString (text, font, width, format);
394                 }
395
396                 internal static SizeF MeasureString (string text, Font font, PointF origin, StringFormat stringFormat)
397                 {
398                         return StaticGraphics.MeasureString (text, font, origin, stringFormat);
399                 }
400
401                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat)
402                 {
403                         return StaticGraphics.MeasureString (text, font, layoutArea, stringFormat);
404                 }
405
406                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat, out int charactersFitted, out int linesFilled)
407                 {
408                         return StaticGraphics.MeasureString (text, font, layoutArea, stringFormat, out charactersFitted, out linesFilled);
409                 }
410
411                 internal static Region[] MeasureCharacterRanges (string text, Font font, RectangleF layoutRect, StringFormat stringFormat)
412                 {
413                         return StaticGraphics.MeasureCharacterRanges (text, font, layoutRect, stringFormat);
414                 }
415                 
416                 internal static SizeF GetDpi ()
417                 {
418                         return new SizeF (StaticGraphics.DpiX, StaticGraphics.DpiY);
419                 }
420                 
421                 internal static Bitmap StaticBitmap {
422                         get {
423                                 if (static_bitmap == null)
424                                         static_bitmap = new Bitmap (1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
425                                 
426                                 return static_bitmap;
427                         }
428                 }
429                 
430                 internal static Graphics StaticGraphics {
431                         get {
432                                 if (static_graphics == null)
433                                         static_graphics = Graphics.FromImage (StaticBitmap);
434                                         
435                                 return static_graphics;
436                         }
437                 }
438                 #endregion
439                 
440 #region Private Methods
441                 private static StringFormat FlagsToStringFormat (TextFormatFlags flags)
442                 {
443                         StringFormat sf = new StringFormat ();
444
445                         // Translation table: http://msdn.microsoft.com/msdnmag/issues/06/03/TextRendering/default.aspx?fig=true#fig4
446
447                         // Horizontal Alignment
448                         if ((flags & TextFormatFlags.HorizontalCenter) == TextFormatFlags.HorizontalCenter)
449                                 sf.Alignment = StringAlignment.Center;
450                         else if ((flags & TextFormatFlags.Right) == TextFormatFlags.Right)
451                                 sf.Alignment = StringAlignment.Far;
452                         else
453                                 sf.Alignment = StringAlignment.Near;
454
455                         // Vertical Alignment
456                         if ((flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
457                                 sf.LineAlignment = StringAlignment.Far;
458                         else if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter)
459                                 sf.LineAlignment = StringAlignment.Center;
460                         else
461                                 sf.LineAlignment = StringAlignment.Near;
462
463                         // Ellipsis
464                         if ((flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis)
465                                 sf.Trimming = StringTrimming.EllipsisCharacter;
466                         else if ((flags & TextFormatFlags.PathEllipsis) == TextFormatFlags.PathEllipsis)
467                                 sf.Trimming = StringTrimming.EllipsisPath;
468                         else if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis)
469                                 sf.Trimming = StringTrimming.EllipsisWord;
470                         else
471                                 sf.Trimming = StringTrimming.Character;
472
473                         // Hotkey Prefix
474                         if ((flags & TextFormatFlags.NoPrefix) == TextFormatFlags.NoPrefix)
475                                 sf.HotkeyPrefix = HotkeyPrefix.None;
476                         else if ((flags & TextFormatFlags.HidePrefix) == TextFormatFlags.HidePrefix)
477                                 sf.HotkeyPrefix = HotkeyPrefix.Hide;
478                         else
479                                 sf.HotkeyPrefix = HotkeyPrefix.Show;
480
481                         // Text Padding
482                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding)
483                                 sf.FormatFlags |= StringFormatFlags.FitBlackBox;
484
485                         // Text Wrapping
486                         if ((flags & TextFormatFlags.SingleLine) == TextFormatFlags.SingleLine)
487                                 sf.FormatFlags |= StringFormatFlags.NoWrap;
488                         else if ((flags & TextFormatFlags.TextBoxControl) == TextFormatFlags.TextBoxControl)
489                                 sf.FormatFlags |= StringFormatFlags.LineLimit;
490
491                         // Other Flags
492                         //if ((flags & TextFormatFlags.RightToLeft) == TextFormatFlags.RightToLeft)
493                         //        sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
494                         if ((flags & TextFormatFlags.NoClipping) == TextFormatFlags.NoClipping)
495                                 sf.FormatFlags |= StringFormatFlags.NoClip;
496
497                         return sf;
498                 }
499 #if NET_2_0
500                 private static Rectangle PadRectangle (Rectangle r, TextFormatFlags flags)
501                 {
502                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
503                                 r.X += 3;
504                                 r.Width -= 3;
505                         }
506                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
507                                 r.Width -= 4;
508                         }
509                         if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
510                                 r.X += 2;
511                                 r.Width -= 2;
512                         }
513                         if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
514                                 r.Width -= 4;
515                         }
516                         if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
517                                 r.Y += 1;
518                         }
519
520                         return r;
521                 }
522 #endif
523                 private static Rectangle PadDrawStringRectangle (Rectangle r, TextFormatFlags flags)
524                 {
525                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
526                                 r.X += 1;
527                                 r.Width -= 1;
528                         }
529                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
530                                 r.Width -= 4;
531                         }
532                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding) {
533                                 r.X -= 2;
534                         }
535                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom) {
536                                 r.Y += 1;
537                         }
538                         if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
539                                 r.X += 2;
540                                 r.Width -= 2;
541                         }
542                         if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
543                                 r.Width -= 4;
544                         }
545                         if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
546                                 r.Y += 1;
547                         }
548
549                         return r;
550                 }
551 #endregion
552
553 #region DllImports (Windows)
554 #if NET_2_0
555                 [DllImport ("user32", CharSet = CharSet.Unicode, EntryPoint = "DrawText")]
556                 static extern int Win32DrawText (IntPtr hdc, string lpStr, int nCount, ref XplatUIWin32.RECT lpRect, int wFormat);
557
558                 [DllImport ("gdi32")]
559                 static extern int SetTextColor (IntPtr hdc, int crColor);
560
561                 [DllImport ("gdi32")]
562                 static extern IntPtr SelectObject (IntPtr hDC, IntPtr hObject);
563
564                 [DllImport ("gdi32")]
565                 static extern int SetBkColor (IntPtr hdc, int crColor);
566
567                 [DllImport ("gdi32")]
568                 static extern int SetBkMode (IntPtr hdc, int iBkMode);
569
570                 [DllImport ("gdi32")]
571                 static extern bool DeleteObject (IntPtr objectHandle);
572
573                 [DllImport("gdi32")]
574                 static extern bool SelectClipRgn(IntPtr hdc, IntPtr hrgn);
575 #endif
576 #endregion
577         }
578 }