2008-03-27 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[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                 private TextRenderer ()
54                 {
55                 }
56
57                 #region Public Methods
58 #if NET_2_0
59                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor)
60                 {
61                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, false);
62                 }
63
64                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor)
65                 {
66                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false);
67                 }
68
69                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor)
70                 {
71                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, false);
72                 }
73
74                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags)
75                 {
76                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, false);
77                 }
78
79                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor)
80                 {
81                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false);
82                 }
83
84                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags)
85                 {
86                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, false);
87                 }
88
89                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags)
90                 {
91                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, flags, false);
92                 }
93
94                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags)
95                 {
96                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, flags, false);
97                 }
98
99                 public static Size MeasureText (string text, Font font)
100                 {
101                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, Size.Empty, TextFormatFlags.Default, false);
102                 }
103
104                 public static Size MeasureText (IDeviceContext dc, string text, Font font)
105                 {
106                         return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, false);
107                 }
108
109                 public static Size MeasureText (string text, Font font, Size proposedSize)
110                 {
111                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, TextFormatFlags.Default, false);
112                 }
113
114                 public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize)
115                 {
116                         return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, false);
117                 }
118
119                 public static Size MeasureText (string text, Font font, Size proposedSize, TextFormatFlags flags)
120                 {
121                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, flags, false);
122                 }
123
124                 public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags)
125                 {
126                         return MeasureTextInternal (dc, text, font, proposedSize, flags, false);
127                 }
128 #endif
129                 #endregion
130
131                 #region Internal Methods That Do Stuff
132 #if NET_2_0
133                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
134 #else
135                 internal static void DrawTextInternal (Graphics dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
136 #endif
137                 {
138                         if (dc == null)
139                                 throw new ArgumentNullException ("dc");
140
141                         if (text == null || text.Length == 0)
142                                 return;
143
144                         // We use MS GDI API's unless told not to, or we aren't on Windows
145                         if (!useDrawString && !XplatUI.RunningOnUnix) {
146                                 if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter || (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
147                                         flags |= TextFormatFlags.SingleLine;
148
149                                 // Calculate the text bounds (there is often padding added)
150                                 Rectangle new_bounds = PadRectangle (bounds, flags);
151                                 new_bounds.Offset ((int)(dc as Graphics).Transform.OffsetX, (int)(dc as Graphics).Transform.OffsetY);
152
153                                 IntPtr hdc = IntPtr.Zero;
154                                 bool clear_clip_region = false;
155                                 
156                                 // If we need to use the graphics clipping region, add it to our hdc
157                                 if ((flags & TextFormatFlags.PreserveGraphicsClipping) == TextFormatFlags.PreserveGraphicsClipping) {
158                                         Graphics graphics = (Graphics)dc;
159                                         Region clip_region = graphics.Clip;
160                                         
161                                         if (!clip_region.IsInfinite (graphics)) {
162                                                 IntPtr hrgn = clip_region.GetHrgn (graphics);
163                                                 hdc = dc.GetHdc ();
164                                                 SelectClipRgn (hdc, hrgn);
165                                                 DeleteObject (hrgn);
166                                                 
167                                                 clear_clip_region = true;
168                                         }
169                                 }
170                                 
171                                 if (hdc == IntPtr.Zero)
172                                         hdc = dc.GetHdc ();
173                                         
174                                 // Set the fore color
175                                 if (foreColor != Color.Empty)
176                                         SetTextColor (hdc, ColorTranslator.ToWin32 (foreColor));
177
178                                 // Set the back color
179                                 if (backColor != Color.Transparent && backColor != Color.Empty) {
180                                         SetBkMode (hdc, 2);     //1-Transparent, 2-Opaque
181                                         SetBkColor (hdc, ColorTranslator.ToWin32 (backColor));
182                                 }
183                                 else {
184                                         SetBkMode (hdc, 1);     //1-Transparent, 2-Opaque
185                                 }
186
187                                 XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new_bounds);
188
189                                 IntPtr prevobj;
190
191                                 if (font != null) {
192                                         prevobj = SelectObject (hdc, font.ToHfont ());
193                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
194                                         prevobj = SelectObject (hdc, prevobj);
195                                         DeleteObject (prevobj);
196                                 }
197                                 else {
198                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
199                                 }
200
201                                 if (clear_clip_region)
202                                         SelectClipRgn (hdc, IntPtr.Zero);
203
204 #if NET_2_0
205                                 dc.ReleaseHdc ();
206 #else
207                                 dc.ReleaseHdc (hdc);
208 #endif
209                         }
210                         // Use Graphics.DrawString as a fallback method
211                         else {
212                                 Graphics g;
213                                 IntPtr hdc = IntPtr.Zero;
214                                 
215                                 if (dc is Graphics)
216                                         g = (Graphics)dc;
217                                 else {
218                                         hdc = dc.GetHdc ();
219                                         g = Graphics.FromHdc (hdc);
220                                 }
221
222                                 StringFormat sf = FlagsToStringFormat (flags);
223
224                                 Rectangle new_bounds = PadDrawStringRectangle (bounds, flags);
225
226                                 g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (foreColor), new_bounds, sf);
227
228                                 if (!(dc is Graphics)) {
229                                         g.Dispose ();
230 #if NET_2_0
231                                         dc.ReleaseHdc ();
232 #else
233                                         if (hdc != IntPtr.Zero) dc.ReleaseHdc (hdc);
234 #endif
235                                 }
236                         }
237                 }
238
239 #if NET_2_0
240                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
241 #else
242                 internal static Size MeasureTextInternal (Graphics dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
243 #endif
244                 {
245                         if (!useMeasureString && !XplatUI.RunningOnUnix) {
246                                 // Tell DrawText to calculate size instead of draw
247                                 flags |= (TextFormatFlags)1024;         // DT_CALCRECT
248
249                                 IntPtr hdc = dc.GetHdc ();
250
251                                 XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new Rectangle (Point.Empty, proposedSize));
252
253                                 IntPtr prevobj;
254
255                                 if (font != null) {
256                                         prevobj = SelectObject (hdc, font.ToHfont ());
257                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
258                                         prevobj = SelectObject (hdc, prevobj);
259                                         DeleteObject (prevobj);
260                                 }
261                                 else {
262                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
263                                 }
264
265 #if NET_2_0
266                                 dc.ReleaseHdc ();
267 #else
268                                 dc.ReleaseHdc (hdc);
269 #endif
270
271                                 // Really, I am just making something up here, which as far as I can tell, MS
272                                 // just makes something up as well.  This will require lots of tweaking to match MS.  :(
273                                 Size retval = r.ToRectangle ().Size;
274
275                                 if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0) {
276                                         retval.Width += 6;
277                                         retval.Width += (int)retval.Height / 8;
278                                 }
279
280                                 return retval;
281                         }
282                         else {
283                         StringFormat sf = FlagsToStringFormat (flags);
284
285                                 Size retval;
286                                 
287                                 if (dc is Graphics)
288                                         retval = (dc as Graphics).MeasureString (text, font, proposedSize.Width == 0 ? Int32.MaxValue : proposedSize.Width, sf).ToSize ();
289                                 else
290                                         retval = TextRenderer.MeasureString (text, font, proposedSize.Width == 0 ? Int32.MaxValue : proposedSize.Width, sf).ToSize ();
291
292                                 if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0)
293                                         retval.Width += 9;
294
295                                 return retval;
296                         }
297                 }
298                 #endregion
299
300 #region Internal Methods That Are Just Overloads
301 #if NET_2_0
302                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, bool useDrawString)
303                 {
304                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, useDrawString);
305                 }
306
307                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, bool useDrawString)
308                 {
309                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
310                 }
311
312                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, bool useDrawString)
313                 {
314                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, useDrawString);
315                 }
316
317                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags, bool useDrawString)
318                 {
319                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, useDrawString);
320                 }
321
322                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, bool useDrawString)
323                 {
324                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
325                 }
326
327                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
328 #else
329                 internal static void DrawTextInternal (Graphics dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
330 #endif
331                 {
332                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, useDrawString);
333                 }
334
335                 internal static Size MeasureTextInternal (string text, Font font, bool useMeasureString)
336                 {
337                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
338                 }
339
340 #if NET_2_0
341                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
342                 {
343                         Size sz = MeasureTextInternal (dc, text, font, useDrawString);
344                         DrawTextInternal (dc, text, font, new Rectangle (pt, sz), foreColor, backColor, flags, useDrawString);
345                 }
346
347                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, bool useMeasureString)
348                 {
349                         return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
350                 }
351
352                 internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, bool useMeasureString)
353                 {
354                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
355                 }
356
357                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, bool useMeasureString)
358                 {
359                         return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
360                 }
361
362 #endif
363                 internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
364                 {
365                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, flags, useMeasureString);
366                 }
367 #endregion
368
369                 #region Thread-Safe Static Graphics Methods
370                 internal static SizeF MeasureString (string text, Font font)
371                 {
372                         return Hwnd.GraphicsContext.MeasureString (text, font);
373                 }
374
375                 internal static SizeF MeasureString (string text, Font font, int width)
376                 {
377                         return Hwnd.GraphicsContext.MeasureString (text, font, width);
378                 }
379
380                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea)
381                 {
382                         return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea);
383                 }
384
385                 internal static SizeF MeasureString (string text, Font font, int width, StringFormat format)
386                 {
387                         return Hwnd.GraphicsContext.MeasureString (text, font, width, format);
388                 }
389
390                 internal static SizeF MeasureString (string text, Font font, PointF origin, StringFormat stringFormat)
391                 {
392                         return Hwnd.GraphicsContext.MeasureString (text, font, origin, stringFormat);
393                 }
394
395                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat)
396                 {
397                         return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea, stringFormat);
398                 }
399
400                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat, out int charactersFitted, out int linesFilled)
401                 {
402                         return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea, stringFormat, out charactersFitted, out linesFilled);
403                 }
404
405                 internal static Region[] MeasureCharacterRanges (string text, Font font, RectangleF layoutRect, StringFormat stringFormat)
406                 {
407                         return Hwnd.GraphicsContext.MeasureCharacterRanges (text, font, layoutRect, stringFormat);
408                 }
409                 
410                 internal static SizeF GetDpi ()
411                 {
412                         return new SizeF (Hwnd.GraphicsContext.DpiX, Hwnd.GraphicsContext.DpiY);
413                 }
414                 #endregion
415                 
416 #region Private Methods
417                 private static StringFormat FlagsToStringFormat (TextFormatFlags flags)
418                 {
419                         StringFormat sf = new StringFormat ();
420
421                         // Translation table: http://msdn.microsoft.com/msdnmag/issues/06/03/TextRendering/default.aspx?fig=true#fig4
422
423                         // Horizontal Alignment
424                         if ((flags & TextFormatFlags.HorizontalCenter) == TextFormatFlags.HorizontalCenter)
425                                 sf.Alignment = StringAlignment.Center;
426                         else if ((flags & TextFormatFlags.Right) == TextFormatFlags.Right)
427                                 sf.Alignment = StringAlignment.Far;
428                         else
429                                 sf.Alignment = StringAlignment.Near;
430
431                         // Vertical Alignment
432                         if ((flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
433                                 sf.LineAlignment = StringAlignment.Far;
434                         else if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter)
435                                 sf.LineAlignment = StringAlignment.Center;
436                         else
437                                 sf.LineAlignment = StringAlignment.Near;
438
439                         // Ellipsis
440                         if ((flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis)
441                                 sf.Trimming = StringTrimming.EllipsisCharacter;
442                         else if ((flags & TextFormatFlags.PathEllipsis) == TextFormatFlags.PathEllipsis)
443                                 sf.Trimming = StringTrimming.EllipsisPath;
444                         else if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis)
445                                 sf.Trimming = StringTrimming.EllipsisWord;
446                         else
447                                 sf.Trimming = StringTrimming.Character;
448
449                         // Hotkey Prefix
450                         if ((flags & TextFormatFlags.NoPrefix) == TextFormatFlags.NoPrefix)
451                                 sf.HotkeyPrefix = HotkeyPrefix.None;
452                         else if ((flags & TextFormatFlags.HidePrefix) == TextFormatFlags.HidePrefix)
453                                 sf.HotkeyPrefix = HotkeyPrefix.Hide;
454                         else
455                                 sf.HotkeyPrefix = HotkeyPrefix.Show;
456
457                         // Text Padding
458                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding)
459                                 sf.FormatFlags |= StringFormatFlags.FitBlackBox;
460
461                         // Text Wrapping
462                         if ((flags & TextFormatFlags.SingleLine) == TextFormatFlags.SingleLine)
463                                 sf.FormatFlags |= StringFormatFlags.NoWrap;
464                         else if ((flags & TextFormatFlags.TextBoxControl) == TextFormatFlags.TextBoxControl)
465                                 sf.FormatFlags |= StringFormatFlags.LineLimit;
466
467                         // Other Flags
468                         //if ((flags & TextFormatFlags.RightToLeft) == TextFormatFlags.RightToLeft)
469                         //        sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
470                         if ((flags & TextFormatFlags.NoClipping) == TextFormatFlags.NoClipping)
471                                 sf.FormatFlags |= StringFormatFlags.NoClip;
472
473                         return sf;
474                 }
475
476                 private static Rectangle PadRectangle (Rectangle r, TextFormatFlags flags)
477                 {
478                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
479                                 r.X += 3;
480                                 r.Width -= 3;
481                         }
482                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
483                                 r.Width -= 4;
484                         }
485                         if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
486                                 r.X += 2;
487                                 r.Width -= 2;
488                         }
489                         if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
490                                 r.Width -= 4;
491                         }
492                         if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
493                                 r.Y += 1;
494                         }
495
496                         return r;
497                 }
498
499                 private static Rectangle PadDrawStringRectangle (Rectangle r, TextFormatFlags flags)
500                 {
501                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
502                                 r.X += 1;
503                                 r.Width -= 1;
504                         }
505                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
506                                 r.Width -= 4;
507                         }
508                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding) {
509                                 r.X -= 2;
510                         }
511                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom) {
512                                 r.Y += 1;
513                         }
514                         if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
515                                 r.X += 2;
516                                 r.Width -= 2;
517                         }
518                         if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
519                                 r.Width -= 4;
520                         }
521                         if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
522                                 r.Y += 1;
523                         }
524
525                         return r;
526                 }
527 #endregion
528
529 #region DllImports (Windows)
530                 [DllImport ("user32", CharSet = CharSet.Unicode, EntryPoint = "DrawText")]
531                 static extern int Win32DrawText (IntPtr hdc, string lpStr, int nCount, ref XplatUIWin32.RECT lpRect, int wFormat);
532
533                 [DllImport ("gdi32")]
534                 static extern int SetTextColor (IntPtr hdc, int crColor);
535
536                 [DllImport ("gdi32")]
537                 static extern IntPtr SelectObject (IntPtr hDC, IntPtr hObject);
538
539                 [DllImport ("gdi32")]
540                 static extern int SetBkColor (IntPtr hdc, int crColor);
541
542                 [DllImport ("gdi32")]
543                 static extern int SetBkMode (IntPtr hdc, int iBkMode);
544
545                 [DllImport ("gdi32")]
546                 static extern bool DeleteObject (IntPtr objectHandle);
547
548                 [DllImport("gdi32")]
549                 static extern bool SelectClipRgn(IntPtr hdc, IntPtr hrgn);
550 #endregion
551         }
552 }