File: winforms\Managed\System\WinForms\ButtonInternal\ButtonBaseAdapter.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="ButtonBase.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Windows.Forms.ButtonInternal {
    using System;
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.Drawing;
    using System.Windows.Forms.Internal;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.Drawing.Text;
    using System.Windows.Forms;
    using System.Windows.Forms.Layout;
    using System.Runtime.Versioning;
    using Runtime.CompilerServices;
 
    /// <devdoc>
    ///                  PLEASE READ
    ///                  -----------
    /// This class is used for more than just Button:
    /// it's used for things that derive from ButtonBase, 
    /// parts of ToolStripItem, and parts of the DataGridView.
    /// </devdoc>
    internal abstract class ButtonBaseAdapter {
        private ButtonBase control;
 
        // SystemInformation.Border3DSize + 2 pixels for focus rect
        protected static int buttonBorderSize = 4;
 
        internal ButtonBaseAdapter(ButtonBase control) {
            this.control = control;
        }
 
        protected ButtonBase Control {
            get { return this.control; }
        }
 
        internal void Paint(PaintEventArgs pevent) {
            if (Control.MouseIsDown) {
                PaintDown(pevent, CheckState.Unchecked);
            }
            else if (Control.MouseIsOver) {
                PaintOver(pevent, CheckState.Unchecked);
            }
            else {
                PaintUp(pevent, CheckState.Unchecked);  
            }
        }
 
        internal virtual Size GetPreferredSizeCore(Size proposedSize) {
            // this is a shared cached graphics, therefore it does not require dispose.
            using (Graphics measurementGraphics = WindowsFormsUtils.CreateMeasurementGraphics()) {
                using (PaintEventArgs pe = new PaintEventArgs(measurementGraphics, new Rectangle())) {
                    LayoutOptions options = Layout(pe);
                    return options.GetPreferredSizeCore(proposedSize);
                }
            }            
        }
 
        protected abstract LayoutOptions Layout(PaintEventArgs e);
 
        internal abstract void PaintUp(PaintEventArgs e, CheckState state);
 
        internal abstract void PaintDown(PaintEventArgs e, CheckState state);
 
        internal abstract void PaintOver(PaintEventArgs e, CheckState state);
 
        #region Accessibility Helpers
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected bool IsHighContrastHighlighted() {
            return AccessibilityImprovements.Level1 && IsHighContrastHighlightedInternal();
        }
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected bool IsHighContrastHighlighted2() {
            return AccessibilityImprovements.Level2 && IsHighContrastHighlightedInternal();
        }
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private bool IsHighContrastHighlightedInternal() {
            return SystemInformation.HighContrast && Application.RenderWithVisualStyles &&
                (Control.Focused || Control.MouseIsOver || (Control.IsDefault && Control.Enabled));
        }
 
#endregion
 
        #region Drawing Helpers
 
        internal static Color MixedColor(Color color1, Color color2) {
            byte a1 = color1.A;
            byte r1 = color1.R;
            byte g1 = color1.G;
            byte b1 = color1.B;
 
            byte a2 = color2.A;
            byte r2 = color2.R;
            byte g2 = color2.G;
            byte b2 = color2.B;
 
            int a3 = (a1 + a2) / 2;
            int r3 = (r1 + r2) / 2;
            int g3 = (g1 + g2) / 2;
            int b3 = (b1 + b2) / 2;
 
            return Color.FromArgb(a3, r3, g3, b3);
        }
 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process | ResourceScope.Machine, ResourceScope.Machine)]
        internal static Brush CreateDitherBrush(Color color1, Color color2) {
 
            // Note: Don't dispose the bitmap here. The texture brush will take ownership
            // of the bitmap. So the bitmap will get disposed by the brush's Dispose().
 
            using (Bitmap b = new Bitmap(2, 2)) {
                b.SetPixel(0, 0, color1);
                b.SetPixel(0, 1, color2);
                b.SetPixel(1, 1, color1);
                b.SetPixel(1, 0, color2);
 
                return new TextureBrush(b);
            }
        }
 
        /// <devdoc>
        ///     Get StringFormat object for rendering text using GDI+ (Graphics).
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        internal virtual StringFormat CreateStringFormat() {
            return ControlPaint.CreateStringFormat( Control, Control.TextAlign, Control.ShowToolTip, Control.UseMnemonic );
        }
 
        /// <devdoc>
        ///     Get TextFormatFlags flags for rendering text using GDI (TextRenderer).
        /// </devdoc>
        internal virtual TextFormatFlags CreateTextFormatFlags(){
            return ControlPaint.CreateTextFormatFlags( Control, Control.TextAlign, Control.ShowToolTip, Control.UseMnemonic );
        }
 
        internal static void DrawDitheredFill(Graphics g, Color color1, Color color2, Rectangle bounds) {
            using (Brush brush = CreateDitherBrush(color1, color2)) {
                g.FillRectangle(brush, bounds);
            }
        }
 
        protected void Draw3DBorder(Graphics g, Rectangle bounds, ColorData colors, bool raised) {
            if (Control.BackColor != SystemColors.Control && SystemInformation.HighContrast) {
                if (raised) {
                    Draw3DBorderHighContrastRaised(g, ref bounds, colors);
                }
                else {
                    ControlPaint.DrawBorder(g, bounds, ControlPaint.Dark(Control.BackColor), ButtonBorderStyle.Solid);
                }
            }
            else {
                if (raised) {
                    Draw3DBorderRaised(g, ref bounds, colors);
                }
                else {
                    Draw3DBorderNormal(g, ref bounds, colors);
                }
            }
        }
        
 
        private void Draw3DBorderHighContrastRaised(Graphics g, ref Rectangle bounds, ColorData colors) {
            bool stockColor = colors.buttonFace.ToKnownColor() == SystemColors.Control.ToKnownColor();
            bool disabledHighContrast = (!Control.Enabled) && SystemInformation.HighContrast && AccessibilityImprovements.Level1;
 
            using ( WindowsGraphics wg = WindowsGraphics.FromGraphics(g) ) {
            
                // Draw counter-clock-wise.
                Point p1 = new Point(bounds.X + bounds.Width - 1, bounds.Y );  // upper inner right.
                Point p2 = new Point(bounds.X                   , bounds.Y );  // upper left.
                Point p3 = new Point(bounds.X                   , bounds.Y + bounds.Height - 1 );  // bottom inner left.
                Point p4 = new Point(bounds.X + bounds.Width - 1, bounds.Y + bounds.Height - 1 );  // inner bottom right.
 
                WindowsPen penTopLeft = null;
                WindowsPen penBottomRight = null;
                WindowsPen insetPen = null;
                WindowsPen bottomRightInsetPen = null;
 
                try {
                    // top + left
                    if (disabledHighContrast) {
                        penTopLeft = new WindowsPen(wg.DeviceContext, colors.windowDisabled);
                    }
                    else {
                        penTopLeft = stockColor ? new WindowsPen(wg.DeviceContext, SystemColors.ControlLightLight) : new WindowsPen(wg.DeviceContext, colors.highlight);
                    }
                    wg.DrawLine(penTopLeft, p1, p2); // top  (right-left)
                    wg.DrawLine(penTopLeft, p2, p3); // left (up-down)
 
                    // bottom + right
                    if (disabledHighContrast) {
                        penBottomRight = new WindowsPen(wg.DeviceContext, colors.windowDisabled);
                    }
                    else {
                        penBottomRight = stockColor ? new WindowsPen(wg.DeviceContext, SystemColors.ControlDarkDark) : new WindowsPen(wg.DeviceContext, colors.buttonShadowDark);
                    }
                    p1.Offset(0,-1); // need to paint last pixel too.
                    wg.DrawLine(penBottomRight, p3, p4);  // bottom (left-right)
                    wg.DrawLine(penBottomRight, p4, p1);  // right  (bottom-up )
 
                    // Draw inset using the background color to make the top and left lines thinner
                    if (stockColor) {
                        if (SystemInformation.HighContrast) {
                            insetPen = new WindowsPen(wg.DeviceContext, SystemColors.ControlLight);
                        }
                        else {
                            insetPen = new WindowsPen(wg.DeviceContext, SystemColors.Control);
                        }
                    }
                    else {
                        if (SystemInformation.HighContrast) {
                            insetPen = new WindowsPen(wg.DeviceContext, colors.highlight);
                        }
                        else {
                            insetPen = new WindowsPen(wg.DeviceContext, colors.buttonFace);
                        }
                    }
 
                    p1.Offset(-1, 2); 
                    p2.Offset( 1, 1);
                    p3.Offset( 1,-1);
                    p4.Offset(-1,-1);
 
                    // top + left inset
                    wg.DrawLine(insetPen, p1, p2); // top (right-left)
                    wg.DrawLine(insetPen, p2, p3); // left( up-down)
                
                    // Bottom + right inset           
                    if (disabledHighContrast) {
                        bottomRightInsetPen = new WindowsPen(wg.DeviceContext, colors.windowDisabled);
                    }
                    else {
                        bottomRightInsetPen = stockColor ? new WindowsPen(wg.DeviceContext, SystemColors.ControlDark) : new WindowsPen(wg.DeviceContext, colors.buttonShadow);
                    }
                    p1.Offset(0,-1); // need to paint last pixel too.
                    wg.DrawLine(bottomRightInsetPen, p3, p4); // bottom (left-right)
                    wg.DrawLine(bottomRightInsetPen, p4, p1); // right  (bottom-up)
                }
                finally {
                    if (penTopLeft != null) {
                        penTopLeft.Dispose();
                    }
 
                    if (penBottomRight != null) {
                        penBottomRight.Dispose();
                    }
 
                    if (insetPen != null) {
                        insetPen.Dispose();
                    }
 
                    if (bottomRightInsetPen != null) {
                        bottomRightInsetPen.Dispose();
                    }
                }
            }
        }
        
        private void Draw3DBorderNormal(Graphics g, ref Rectangle bounds, ColorData colors) {
            using( WindowsGraphics wg = WindowsGraphics.FromGraphics(g) ) {
 
                // Draw counter-clock-wise.
                Point p1 = new Point(bounds.X + bounds.Width - 1, bounds.Y );  // upper inner right.
                Point p2 = new Point(bounds.X                   , bounds.Y );  // upper left.
                Point p3 = new Point(bounds.X                   , bounds.Y + bounds.Height - 1 );  // bottom inner left.
                Point p4 = new Point(bounds.X + bounds.Width - 1, bounds.Y + bounds.Height - 1 );  // inner bottom right.
 
                // top + left
                WindowsPen pen = new WindowsPen(wg.DeviceContext, colors.buttonShadowDark);
                try {
                    wg.DrawLine(pen, p1, p2); // top (right-left)
                    wg.DrawLine(pen, p2, p3); // left(up-down)
                }
                finally {
                    pen.Dispose();    
                }
            
                // bottom + right
                pen = new WindowsPen(wg.DeviceContext, colors.highlight);
                try {
                    p1.Offset(0,-1); // need to paint last pixel too.
                    wg.DrawLine(pen, p3, p4); // bottom(left-right)
                    wg.DrawLine(pen, p4, p1); // right (bottom-up)
                }
                finally {
                    pen.Dispose();
                }
 
                // Draw inset
 
                pen = new WindowsPen(wg.DeviceContext, colors.buttonFace);
 
                p1.Offset(-1, 2); 
                p2.Offset( 1, 1);
                p3.Offset( 1,-1);
                p4.Offset(-1,-1);
 
                // top + left inset
                try {
                    wg.DrawLine(pen, p1, p2); // top (right-left)
                    wg.DrawLine(pen, p2, p3); // left(up-down)
                }
                finally {
                    pen.Dispose();    
                }
 
                // bottom + right inset
                if (colors.buttonFace.ToKnownColor() == SystemColors.Control.ToKnownColor()) {
                    pen = new WindowsPen(wg.DeviceContext, SystemColors.ControlLight);
                }
                else {
                    pen = new WindowsPen(wg.DeviceContext, colors.buttonFace);
                }
 
                try {
                    p1.Offset(0,-1); // need to paint last pixel too.
                    wg.DrawLine(pen, p3, p4); // bottom(left-right)
                    wg.DrawLine(pen, p4, p1); // right (bottom-up)
                }
                finally {
                    pen.Dispose();
                }
            }
        }
        
        private void Draw3DBorderRaised(Graphics g, ref Rectangle bounds, ColorData colors) {
            bool stockColor = colors.buttonFace.ToKnownColor() == SystemColors.Control.ToKnownColor();
            bool disabledHighContrast = (!Control.Enabled) && SystemInformation.HighContrast && AccessibilityImprovements.Level1;
 
            using( WindowsGraphics wg = WindowsGraphics.FromGraphics(g) ) {
 
                // Draw counter-clock-wise.
                Point p1 = new Point(bounds.X + bounds.Width - 1, bounds.Y );  // upper inner right.
                Point p2 = new Point(bounds.X                   , bounds.Y );  // upper left.
                Point p3 = new Point(bounds.X                   , bounds.Y + bounds.Height - 1 );  // bottom inner left.
                Point p4 = new Point(bounds.X + bounds.Width - 1, bounds.Y + bounds.Height - 1 );  // inner bottom right.
 
                // Draw counter-clock-wise.
 
                // top + left
                WindowsPen pen;
                if (disabledHighContrast) {
                    pen = new WindowsPen(wg.DeviceContext, colors.windowDisabled);
                }
                else if (stockColor) {
                    pen = new WindowsPen(wg.DeviceContext, SystemColors.ControlLightLight);
                }
                else  {
                    pen = new WindowsPen(wg.DeviceContext, colors.highlight);
                }
 
                try {
                    wg.DrawLine(pen, p1, p2);   // top (right-left)
                    wg.DrawLine(pen, p2, p3);   // left(up-down)
                }
                finally {
                    pen.Dispose();
                }
 
                // bottom + right
                if (disabledHighContrast) {
                    pen = new WindowsPen(wg.DeviceContext, colors.windowDisabled);
                }
                else if (stockColor) {
                    pen = new WindowsPen(wg.DeviceContext, SystemColors.ControlDarkDark);
                }
                else {
                    pen = new WindowsPen(wg.DeviceContext, colors.buttonShadowDark);
                }
 
                try {
                    p1.Offset(0, -1); // need to paint last pixel too.
                    wg.DrawLine(pen, p3, p4);    // bottom(left-right)
                    wg.DrawLine(pen, p4, p1);    // right (bottom-up)
                }
                finally {
                    pen.Dispose();
                }
 
                // Draw inset - use the back ground color here to have a thinner border 
                p1.Offset(-1, 2);
                p2.Offset(1, 1);
                p3.Offset(1, -1);
                p4.Offset(-1, -1);
 
                if (stockColor) {
                    if (SystemInformation.HighContrast) {
                        pen = new WindowsPen(wg.DeviceContext, SystemColors.ControlLight);
                    }
                    else {
                        pen = new WindowsPen(wg.DeviceContext, SystemColors.Control);
                    }
                }
                else {
                    pen = new WindowsPen(wg.DeviceContext, colors.buttonFace);
                }
 
                // top + left inset
                try {
                    wg.DrawLine(pen, p1, p2); // top (right-left)
                    wg.DrawLine(pen, p2, p3); // left(up-down)
                }
                finally {
                    pen.Dispose();
                }
 
                // Bottom + right inset                        
                if (disabledHighContrast) {
                    pen = new WindowsPen(wg.DeviceContext, colors.windowDisabled);
                }
                else if (stockColor) {
                    pen = new WindowsPen(wg.DeviceContext, SystemColors.ControlDark);
                }
                else {
                    pen = new WindowsPen(wg.DeviceContext, colors.buttonShadow);
                }
 
                try {
                    p1.Offset(0, -1); // need to paint last pixel too.
                    wg.DrawLine(pen, p3, p4);  // bottom(left-right)
                    wg.DrawLine(pen, p4, p1);  // right (bottom-up)
                }
                finally {
                    pen.Dispose();
                }
            }
        }
 
        /// <devdoc>
        ///     Draws a border for the in the 3D style of the popup button.
        /// </devdoc>
        protected internal static void Draw3DLiteBorder(Graphics g, Rectangle r, ColorData colors, bool up) {
            using( WindowsGraphics wg = WindowsGraphics.FromGraphics(g) ) {
 
                // Draw counter-clock-wise.
                Point p1 = new Point(r.Right - 1, r.Top );  // upper inner right.
                Point p2 = new Point(r.Left     , r.Top );  // upper left.
                Point p3 = new Point(r.Left     , r.Bottom - 1);  // bottom inner left.
                Point p4 = new Point(r.Right - 1, r.Bottom - 1);  // inner bottom right.
 
 
                // top, left
                WindowsPen pen = up ? new WindowsPen(wg.DeviceContext, colors.highlight) : new WindowsPen(wg.DeviceContext, colors.buttonShadow);
 
                try {
                    wg.DrawLine(pen, p1, p2); // top (right-left)
                    wg.DrawLine(pen, p2, p3); // left (top-down)
                }
                finally {
                    pen.Dispose();
                }
 
                // bottom, right
                pen = up ? new WindowsPen(wg.DeviceContext, colors.buttonShadow) : new WindowsPen(wg.DeviceContext, colors.highlight);
 
                try {
                    p1.Offset(0,-1); // need to paint last pixel too.
                    wg.DrawLine(pen, p3, p4); // bottom (left-right)
                    wg.DrawLine(pen, p4, p1); // right(bottom-up)
                }
                finally {
                    pen.Dispose();
                }
            }
        }
        
        internal static void DrawFlatBorder(Graphics g, Rectangle r, Color c) {
            ControlPaint.DrawBorder(g, r, c, ButtonBorderStyle.Solid);
        }
        
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Draws the flat border with specified bordersize. 
        ///       This function gets called only for Flatstyle == Flatstyle.Flat.
        ///    </para>
        /// </devdoc>
        internal static void DrawFlatBorderWithSize(Graphics g, Rectangle r, Color c, int size) {
            bool stockBorder = c.IsSystemColor;
            SolidBrush brush = null;
            
            if (size > 1) {
                brush = new SolidBrush(c);
            }
            else {
                if (stockBorder) {
                    brush = (SolidBrush)SystemBrushes.FromSystemColor(c);
                }
                else  {
                    brush = new SolidBrush(c);
                }
            }
 
            try {
                size = System.Math.Min(size, System.Math.Min(r.Width, r.Height));
                // ...truncate pen width to button size, to avoid overflow if border size is huge!
 
                //Left Border
                g.FillRectangle(brush, r.X, r.Y, size, r.Height);
 
                //Right Border
                g.FillRectangle(brush, (r.X + r.Width - size), r.Y, size, r.Height);
 
                //Top Border
                g.FillRectangle(brush, (r.X + size), r.Y, (r.Width - size * 2), size);
 
                //Bottom Border
                g.FillRectangle(brush, (r.X + size), (r.Y + r.Height - size), (r.Width - size * 2), size);
            }
            finally {
                if (!stockBorder && brush != null) {
                    brush.Dispose();
                }
            }
        }
 
        internal static void DrawFlatFocus(Graphics g, Rectangle r, Color c) {
            using(WindowsGraphics wg = WindowsGraphics.FromGraphics(g)) {
                using (WindowsPen focus = new WindowsPen(wg.DeviceContext, c))  {
                    wg.DrawRectangle(focus, r);
                }
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Draws the focus rectangle if the control has focus.
        ///       
        ///    </para>
        /// </devdoc>
        void DrawFocus(Graphics g, Rectangle r) {
            if (Control.Focused && Control.ShowFocusCues) {
                ControlPaint.DrawFocusRectangle(g, r, Control.ForeColor, Control.BackColor);
            }
        }
        
        /// <devdoc>
        ///     Draws the button's image.
        /// </devdoc>
        void DrawImage(Graphics graphics, LayoutData layout) {
            if (Control.Image != null) {
                //setup new clip region & draw
                DrawImageCore(graphics, Control.Image, layout.imageBounds, layout.imageStart, layout);
            }
        }
 
        // here for DropDownButton
        internal virtual void DrawImageCore(Graphics graphics, Image image, Rectangle imageBounds, Point imageStart, LayoutData layout) {
            Region oldClip = graphics.Clip;
            
            if (!layout.options.everettButtonCompat) { // FOR EVERETT COMPATIBILITY - DO NOT CHANGE
                Rectangle bounds = new Rectangle(buttonBorderSize, buttonBorderSize, this.Control.Width - (2 * buttonBorderSize), this.Control.Height - (2 * buttonBorderSize));
 
                Region newClip = oldClip.Clone();
                newClip.Intersect(bounds);
 
                // If we don't do this, DrawImageUnscaled will happily draw the entire image, even though imageBounds
                // is smaller than the image size.
                newClip.Intersect(imageBounds);
                graphics.Clip = newClip;
            }
            else {
                // FOR EVERETT COMPATIBILITY - DO NOT CHANGE
                imageBounds.Width += 1;
                imageBounds.Height +=1;
                imageBounds.X = imageStart.X + 1;
                imageBounds.Y = imageStart.Y + 1;
            }
 
 
            try {
                if (!Control.Enabled)
                    // need to specify width and height
                    ControlPaint.DrawImageDisabled(graphics, image, imageBounds, Control.BackColor, true /* unscaled image*/);
                else {
                    graphics.DrawImage(image, imageBounds.X, imageBounds.Y, image.Width, image.Height);
                }
            }
 
            finally {
                if (!layout.options.everettButtonCompat) {// FOR EVERETT COMPATIBILITY - DO NOT CHANGE                              
                    graphics.Clip = oldClip;
                }
            }
        }
 
        internal static void DrawDefaultBorder(Graphics g, Rectangle r, Color c, bool isDefault) {
            if (isDefault) {
                r.Inflate(1, 1);
 
                Pen pen;
                if (c.IsSystemColor) {
                    pen = SystemPens.FromSystemColor(c);
                }
                else {
                    pen = new Pen(c);
                }
                g.DrawRectangle(pen, r.X, r.Y, r.Width - 1, r.Height - 1);
                if (!c.IsSystemColor) {
                    pen.Dispose();
                }
            }
        }
 
        /// <devdoc>
        ///     Draws the button's text. Color c is the foreground color set with enabled/disabled state in mind.
        /// </devdoc>
        void DrawText(Graphics g, LayoutData layout, Color c, ColorData colors)
        {
            Rectangle r = layout.textBounds;
            bool disabledText3D = layout.options.shadowedText;
 
            if (Control.UseCompatibleTextRendering) { // Draw text using GDI+
                using (StringFormat stringFormat = CreateStringFormat()) {
                    // DrawString doesn't seem to draw where it says it does
                    if ((Control.TextAlign & LayoutUtils.AnyCenter) == 0) {
                        r.X -= 1;
                    }
                    r.Width += 1;
                    if (disabledText3D && !Control.Enabled && 
                            (!AccessibilityImprovements.Level1 || (!colors.options.highContrast && AccessibilityImprovements.Level1))) {
                        using (SolidBrush brush = new SolidBrush(colors.highlight)) {
                            r.Offset(1, 1);
                            g.DrawString(Control.Text, Control.Font, brush, r, stringFormat);
 
                            r.Offset(-1, -1);
                            brush.Color = colors.buttonShadow;
                            g.DrawString(Control.Text, Control.Font, brush, r, stringFormat);
                        }
                    }
                    else {
                        Brush brush;
 
                        if (c.IsSystemColor) {
                            brush = SystemBrushes.FromSystemColor(c);
                        }
                        else {
                            brush = new SolidBrush(c);
                        }
                        g.DrawString(Control.Text, Control.Font, brush, r, stringFormat);
 
                        if (!c.IsSystemColor) {
                            brush.Dispose();
                        }
                    }
                }
            }
            else { // Draw text using GDI (Whidbey+ feature).
                TextFormatFlags formatFlags = CreateTextFormatFlags();
                if (disabledText3D && !Control.Enabled && (!AccessibilityImprovements.Level1 || (!colors.options.highContrast && AccessibilityImprovements.Level1))) {
                    if (Application.RenderWithVisualStyles) {
                        //don't draw chiseled text if themed as win32 app does.
                        TextRenderer.DrawText(g, Control.Text, Control.Font, r, colors.buttonShadow, formatFlags);
                    }
                    else {
                        r.Offset(1, 1);
                        TextRenderer.DrawText(g, Control.Text, Control.Font, r, colors.highlight, formatFlags);
 
                        r.Offset(-1, -1);
                        TextRenderer.DrawText(g, Control.Text, Control.Font, r, colors.buttonShadow, formatFlags);
                    }
                }
                else {
                    TextRenderer.DrawText(g, Control.Text, Control.Font, r, c, formatFlags);
                }
            }
        }
 
#endregion Drawing Helpers
 
#region Draw Content Helpers
 
        // the DataGridViewButtonCell uses this method
        internal static void PaintButtonBackground(WindowsGraphics wg, Rectangle bounds, WindowsBrush background) {
            wg.FillRectangle(background, bounds);
        }
 
        internal void PaintButtonBackground(PaintEventArgs e, Rectangle bounds, Brush background) {
            if (background == null) {
                Control.PaintBackground(e, bounds);
            }
            else {
                e.Graphics.FillRectangle(background, bounds);
            }
        }
 
        internal void PaintField(PaintEventArgs e, 
                                 LayoutData layout, 
                                 ColorData colors,
                                 Color foreColor, 
                                 bool drawFocus) {
 
            Graphics g = e.Graphics;
 
            Rectangle maxFocus = layout.focus;
 
            DrawText(g, layout, foreColor, colors);
 
            if (drawFocus) {
                DrawFocus(g, maxFocus);
            }
        }
        
        internal void PaintImage(PaintEventArgs e, LayoutData layout) {
            Graphics g = e.Graphics;
 
            DrawImage(g, layout);
        }
 
#endregion
 
#region Color
 
        internal class ColorOptions {
            internal Color backColor;
            internal Color foreColor;
            internal bool enabled;
            internal bool highContrast;
            internal Graphics graphics;
 
            internal ColorOptions(Graphics graphics, Color foreColor, Color backColor) {
                this.graphics = graphics;
                this.backColor = backColor;
                this.foreColor = foreColor;
                highContrast = SystemInformation.HighContrast;
            }
 
            internal static int Adjust255(float percentage, int value) {
                int v = (int)(percentage * value);
                if (v > 255) {
                    return 255;
                }
                return v;
            }
            
            internal ColorData Calculate() {
                ColorData colors = new ColorData(this);
                
                colors.buttonFace = backColor;
 
                if (backColor == SystemColors.Control) {
                    colors.buttonShadow = SystemColors.ControlDark;
                    colors.buttonShadowDark = SystemColors.ControlDarkDark;
                    colors.highlight = SystemColors.ControlLightLight;
                }
                else {
                    if (!highContrast) {
                        colors.buttonShadow = ControlPaint.Dark(backColor);
                        colors.buttonShadowDark = ControlPaint.DarkDark(backColor);
                        colors.highlight = ControlPaint.LightLight(backColor);
                    }
                    else {
                        colors.buttonShadow = ControlPaint.Dark(backColor);
                        colors.buttonShadowDark = ControlPaint.LightLight(backColor);
                        colors.highlight = ControlPaint.LightLight(backColor);
                    }
                }
                colors.windowDisabled = (highContrast && AccessibilityImprovements.Level1) ? SystemColors.GrayText : colors.buttonShadow;
 
                const float lowlight = .1f;
                float adjust = 1 - lowlight;
 
                if (colors.buttonFace.GetBrightness() < .5) {
                    adjust = 1 + lowlight * 2;
                }
                colors.lowButtonFace = Color.FromArgb(Adjust255(adjust, colors.buttonFace.R), 
                                                    Adjust255(adjust, colors.buttonFace.G), 
                                                    Adjust255(adjust, colors.buttonFace.B));
 
                adjust = 1 - lowlight;
                if (colors.highlight.GetBrightness() < .5) {
                    adjust = 1 + lowlight * 2;
                }
                colors.lowHighlight = Color.FromArgb(Adjust255(adjust, colors.highlight.R), 
                                                   Adjust255(adjust, colors.highlight.G), 
                                                   Adjust255(adjust, colors.highlight.B));
                
                if (highContrast && backColor != SystemColors.Control) {
                    colors.highlight = colors.lowHighlight;
                }
 
                colors.windowFrame = foreColor;
 
 
                /* debug * /
                colors.buttonFace = Color.Yellow;
                colors.buttonShadow = Color.Blue;
                colors.highlight = Color.Brown;
                colors.lowButtonFace = Color.Beige;
                colors.lowHighlight = Color.Cyan;
                colors.windowFrame = Color.Red;
                colors.windowText = Color.Green;
                / * debug */
 
 
                if (colors.buttonFace.GetBrightness() < .5) {
                    colors.constrastButtonShadow = colors.lowHighlight;
                }
                else {
                    colors.constrastButtonShadow = colors.buttonShadow;
                }
                
                if (!enabled) {
                    colors.windowText = colors.windowDisabled;
                    if (highContrast && AccessibilityImprovements.Level1) {
                        colors.windowFrame = colors.windowDisabled;
                        colors.buttonShadow = colors.windowDisabled;
                    }
                }
                else {
                    colors.windowText = colors.windowFrame;
                }
 
                IntPtr hdc = this.graphics.GetHdc();
 
                try
                {
                    using (WindowsGraphics wg = WindowsGraphics.FromHdc(hdc)) {
                        colors.buttonFace = wg.GetNearestColor(colors.buttonFace);
                        colors.buttonShadow = wg.GetNearestColor(colors.buttonShadow);
                        colors.buttonShadowDark = wg.GetNearestColor(colors.buttonShadowDark);
                        colors.constrastButtonShadow = wg.GetNearestColor(colors.constrastButtonShadow);
                        colors.windowText = wg.GetNearestColor(colors.windowText);
                        colors.highlight = wg.GetNearestColor(colors.highlight);
                        colors.lowHighlight = wg.GetNearestColor(colors.lowHighlight);
                        colors.lowButtonFace = wg.GetNearestColor(colors.lowButtonFace);
                        colors.windowFrame = wg.GetNearestColor(colors.windowFrame);
                        colors.windowDisabled = wg.GetNearestColor(colors.windowDisabled);
                    }
                }
                finally
                {
                    this.graphics.ReleaseHdc();
                }
 
                return colors;
            }
        }
 
        internal class ColorData {
            internal Color buttonFace;
            internal Color buttonShadow;
            internal Color buttonShadowDark;
            internal Color constrastButtonShadow;
            internal Color windowText;
            internal Color windowDisabled;
            internal Color highlight;
            internal Color lowHighlight;
            internal Color lowButtonFace;
            internal Color windowFrame;
 
            internal ColorOptions options;
 
            internal ColorData(ColorOptions options) {
                this.options = options;
            }
        }
 
#endregion
 
#region Layout
 
        internal class LayoutOptions {
            internal Rectangle client;
            internal bool growBorderBy1PxWhenDefault;
            internal bool isDefault;
            internal int borderSize;
            internal int paddingSize;
            internal bool maxFocus;
            internal bool focusOddEvenFixup;
            internal Font font;
            internal string text;
            internal Size imageSize;
            internal int checkSize;
            internal int checkPaddingSize;
            internal ContentAlignment checkAlign;
            internal ContentAlignment imageAlign;
            internal ContentAlignment textAlign;
            internal TextImageRelation textImageRelation;
            internal bool hintTextUp;
            internal bool textOffset;
            internal bool shadowedText;
            internal bool layoutRTL;
            internal bool verticalText = false;
            internal bool useCompatibleTextRendering = false;
            internal bool everettButtonCompat = true;
            internal TextFormatFlags gdiTextFormatFlags =  TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl;
            internal StringFormatFlags gdipFormatFlags;
            internal StringTrimming gdipTrimming;
            internal HotkeyPrefix gdipHotkeyPrefix;
            internal StringAlignment gdipAlignment; // horizontal alignment.
            internal StringAlignment gdipLineAlignment; // vertical alignment.
            private bool disableWordWrapping;
 
            /// <devdoc>
            ///     We don't cache the StringFormat itself because we don't have a deterministic way of disposing it, instead
            ///     we cache the flags that make it up and create it on demand so it can be disposed by calling code.
            /// </devdoc>
            public StringFormat StringFormat {
                [ResourceExposure(ResourceScope.Process)]
                [ResourceConsumption(ResourceScope.Process)]
                get {
                    StringFormat format = new StringFormat();
 
                    format.FormatFlags   = this.gdipFormatFlags;
                    format.Trimming      = this.gdipTrimming;
                    format.HotkeyPrefix  = this.gdipHotkeyPrefix;
                    format.Alignment     = this.gdipAlignment;
                    format.LineAlignment = this.gdipLineAlignment;
 
                    if (disableWordWrapping) {
                        format.FormatFlags |= StringFormatFlags.NoWrap;
                    }
 
                    return format;
                }
                set {
                    this.gdipFormatFlags    = value.FormatFlags;
                    this.gdipTrimming       = value.Trimming;
                    this.gdipHotkeyPrefix   = value.HotkeyPrefix;
                    this.gdipAlignment      = value.Alignment;
                    this.gdipLineAlignment  = value.LineAlignment;
                }
            }
 
            /// <devdoc>
            /// </devdoc>
            public TextFormatFlags TextFormatFlags {
                get {
                    if (disableWordWrapping) {
                        return gdiTextFormatFlags & ~TextFormatFlags.WordBreak;
                    }
 
                    return gdiTextFormatFlags;
                }
                //set {
                //    this.gdiTextFormatFlags = value;
                //}
            }
 
            // textImageInset compensates for two factors: 3d text when the button is disabled,
            // and moving text on 3d-look buttons. These factors make the text require a couple
            // more pixels of space.  We inset image by the same amount so they line up.
            internal int textImageInset = 2;
 
            internal Padding padding;
            
            #region PreferredSize
            private static readonly int combineCheck = BitVector32.CreateMask();
            private static readonly int combineImageText = BitVector32.CreateMask(combineCheck);
 
            private enum Composition {
                NoneCombined = 0x00,
                CheckCombined = 0x01,
                TextImageCombined = 0x02,
                AllCombined = 0x03
            }
 
            // Uses checkAlign, imageAlign, and textAlign to figure out how to compose 
            // checkSize, imageSize, and textSize into the preferredSize.
            private Size Compose(Size checkSize, Size imageSize, Size textSize) {
                Composition hComposition = GetHorizontalComposition();
                Composition vComposition = GetVerticalComposition();
                return new Size(
                    xCompose(hComposition, checkSize.Width, imageSize.Width, textSize.Width),
                    xCompose(vComposition, checkSize.Height, imageSize.Height, textSize.Height)
                );
            }
 
            private int xCompose(Composition composition, int checkSize, int imageSize, int textSize) {
                switch(composition) {
                    case Composition.NoneCombined:
                        return checkSize + imageSize + textSize;
                    case Composition.CheckCombined:
                        return Math.Max(checkSize, imageSize + textSize);
                    case Composition.TextImageCombined:
                        return Math.Max(imageSize, textSize) + checkSize;
                    case Composition.AllCombined:
                        return Math.Max(Math.Max(checkSize, imageSize), textSize);
                    default:
                        Debug.Fail(SR.GetString(SR.InvalidArgument, "composition", composition.ToString()));
                        return -7107;
                }
            }
 
            // Uses checkAlign, imageAlign, and textAlign to figure out how to decompose 
            // proposedSize into just the space left over for text.
            private Size Decompose(Size checkSize, Size imageSize, Size proposedSize) {
                Composition hComposition = GetHorizontalComposition();
                Composition vComposition = GetVerticalComposition();
                return new Size(
                    xDecompose(hComposition, checkSize.Width, imageSize.Width, proposedSize.Width),
                    xDecompose(vComposition, checkSize.Height, imageSize.Height, proposedSize.Height)
                );
            }
            
            private int xDecompose(Composition composition, int checkSize, int imageSize, int proposedSize) {
                switch(composition) {
                    case Composition.NoneCombined:
                        return proposedSize - (checkSize + imageSize);
                    case Composition.CheckCombined:
                        return proposedSize - imageSize;
                    case Composition.TextImageCombined:
                        return proposedSize - checkSize;
                    case Composition.AllCombined:
                        return proposedSize;
                    default:
                        Debug.Fail(SR.GetString(SR.InvalidArgument, "composition", composition.ToString()));
                        return -7109;
                }
            }
 
            private Composition GetHorizontalComposition() {
                BitVector32 action = new BitVector32();
 
                // Checks reserve space horizontally if possible, so only AnyLeft/AnyRight prevents combination.
                action[combineCheck] = checkAlign == ContentAlignment.MiddleCenter || !LayoutUtils.IsHorizontalAlignment(checkAlign);
                action[combineImageText] = !LayoutUtils.IsHorizontalRelation(textImageRelation);
                return (Composition) action.Data;
            }
 
            internal Size GetPreferredSizeCore(Size proposedSize) {
                // Get space required for border and padding
                //
                int linearBorderAndPadding = borderSize*2 + paddingSize*2;
                if(growBorderBy1PxWhenDefault) {
                    linearBorderAndPadding += 2;
                }
                Size bordersAndPadding = new Size(linearBorderAndPadding, linearBorderAndPadding);
                proposedSize -= bordersAndPadding;
 
                // Get space required for Check
                //
                int checkSizeLinear = FullCheckSize;
                Size checkSize = checkSizeLinear > 0 ? new Size(checkSizeLinear + 1, checkSizeLinear) : Size.Empty;
 
                // Get space required for Image - textImageInset compensated for by expanding image.
                //
                Size textImageInsetSize = new Size(textImageInset * 2, textImageInset * 2);
                Size requiredImageSize = (imageSize != Size.Empty) ? imageSize + textImageInsetSize : Size.Empty;
 
                // Pack Text into remaning space
                //
                proposedSize -= textImageInsetSize;
                proposedSize = Decompose(checkSize, requiredImageSize, proposedSize);
 
                Size textSize = Size.Empty;
 
                if (!string.IsNullOrEmpty(text)) {
                    // When Button.AutoSizeMode is set to GrowOnly TableLayoutPanel expects buttons not to automatically wrap on word break. If
                    // there's enough room for the text to word-wrap then it will happen but the layout would not be adjusted to allow text wrapping.
                    // If someone has a carriage return in the text we'll honor that for preferred size, but we wont wrap based on constraints.
                    // See VSW#542448,537840,515227.
                    try {
                        this.disableWordWrapping = true;
                        textSize = GetTextSize(proposedSize) + textImageInsetSize;
                    }
                    finally {
                        this.disableWordWrapping = false;
                    }
                }
 
                // Combine pieces to get final preferred size
                //
                Size requiredSize = Compose(checkSize, imageSize, textSize);
                requiredSize += bordersAndPadding;
 
                return requiredSize;
            }
 
            private Composition GetVerticalComposition() {
                BitVector32 action = new BitVector32();
 
                // Checks reserve space horizontally if possible, so only Top/Bottom prevents combination.
                action[combineCheck] = checkAlign == ContentAlignment.MiddleCenter || !LayoutUtils.IsVerticalAlignment(checkAlign);
                action[combineImageText] = !LayoutUtils.IsVerticalRelation(textImageRelation);
                return (Composition) action.Data;
            }
            #endregion PreferredSize
 
            private int FullBorderSize {
                get {
                    int result = borderSize;
                    if (OnePixExtraBorder) {
                        borderSize++;
                    }
                    return borderSize;
                }
            }
 
            private bool OnePixExtraBorder {
                get { return growBorderBy1PxWhenDefault && isDefault; }
            }
 
            internal LayoutData Layout() {
                LayoutData layout = new LayoutData(this);
                layout.client = this.client;
 
                // subtract border size from layout area
                int fullBorderSize = FullBorderSize;
                layout.face = Rectangle.Inflate(layout.client, -fullBorderSize, -fullBorderSize);
                
                // checkBounds, checkArea, field
                //
                CalcCheckmarkRectangle(layout);
 
                // imageBounds, imageLocation, textBounds
                LayoutTextAndImage(layout);
 
                // focus
                //
                if (maxFocus) {
                    layout.focus = layout.field;
                    layout.focus.Inflate(-1, -1);
 
                    // Adjust for padding. VSWhidbey #387208
                    layout.focus = LayoutUtils.InflateRect(layout.focus, this.padding);
                }
                else {
                    Rectangle textAdjusted = new Rectangle(layout.textBounds.X - 1, layout.textBounds.Y - 1,
                                                           layout.textBounds.Width + 2, layout.textBounds.Height + 3);
                    if (imageSize != Size.Empty) {
                        layout.focus = Rectangle.Union(textAdjusted, layout.imageBounds);
                    }
                    else {
                        layout.focus = textAdjusted;
                    }
                }
                if (focusOddEvenFixup) {
                    if (layout.focus.Height % 2 == 0) {
                        layout.focus.Y++;
                        layout.focus.Height--;
                    }
                    if (layout.focus.Width % 2 == 0) {
                        layout.focus.X++;
                        layout.focus.Width--;
                    }
                }
 
 
                return layout;
            }
 
            TextImageRelation RtlTranslateRelation(TextImageRelation relation) {
                // If RTL, we swap ImageBeforeText and TextBeforeImage
                if (layoutRTL) {
                    switch(relation) {
                        case TextImageRelation.ImageBeforeText:
                            return TextImageRelation.TextBeforeImage;
                        case TextImageRelation.TextBeforeImage:
                            return TextImageRelation.ImageBeforeText;
                    }
                }
                return relation;
            }
 
            internal ContentAlignment RtlTranslateContent(ContentAlignment align) {
            
                if (layoutRTL) {
                    ContentAlignment[][] mapping = new ContentAlignment[3][];
                    mapping[0] = new ContentAlignment[2] { ContentAlignment.TopLeft, ContentAlignment.TopRight };
                    mapping[1] = new ContentAlignment[2] { ContentAlignment.MiddleLeft, ContentAlignment.MiddleRight };
                    mapping[2] = new ContentAlignment[2] { ContentAlignment.BottomLeft, ContentAlignment.BottomRight };
                         
                    for(int i=0; i < 3; ++i) {
                        if (mapping[i][0] == align) {
                            return mapping[i][1];
                        }
                        else if (mapping[i][1] == align) {
                            return mapping[i][0];
                        }
                    }
                }
                return align;
            }
 
            private int FullCheckSize {
                get {
                    return checkSize + checkPaddingSize;
                }
            }
 
            void CalcCheckmarkRectangle(LayoutData layout) {
                int checkSizeFull = FullCheckSize;
                layout.checkBounds = new Rectangle(client.X, client.Y, checkSizeFull, checkSizeFull);
 
                // Translate checkAlign for Rtl applications
                ContentAlignment align = RtlTranslateContent(checkAlign);
 
                Rectangle field = Rectangle.Inflate(layout.face, -paddingSize, -paddingSize);
 
                layout.field = field;
 
                if (checkSizeFull > 0) {
                    if ((align & LayoutUtils.AnyRight) != 0) {
                        layout.checkBounds.X = (field.X+field.Width) - layout.checkBounds.Width;
                    }
                    else if ((align & LayoutUtils.AnyCenter) != 0) {
                        layout.checkBounds.X = field.X + (field.Width - layout.checkBounds.Width)/2;
                    }
 
                    if ((align & LayoutUtils.AnyBottom) != 0) {
                        layout.checkBounds.Y = (field.Y+field.Height)-layout.checkBounds.Height;
                    }
                    else if ((align & LayoutUtils.AnyTop) != 0) {
                        layout.checkBounds.Y = field.Y + 2; // + 2: this needs to be aligned to the text (bug 87483)
                    }
                    else {
                        layout.checkBounds.Y = field.Y + (field.Height - layout.checkBounds.Height)/2;
                    }
 
                    switch (align) {
                        case ContentAlignment.TopLeft:
                        case ContentAlignment.MiddleLeft:
                        case ContentAlignment.BottomLeft:
                            layout.checkArea.X = field.X;
                            layout.checkArea.Width = checkSizeFull + 1;
 
                            layout.checkArea.Y = field.Y;
                            layout.checkArea.Height = field.Height;
 
                            layout.field.X += checkSizeFull + 1;
                            layout.field.Width -= checkSizeFull + 1;
                            break;
                        case ContentAlignment.TopRight:
                        case ContentAlignment.MiddleRight:
                        case ContentAlignment.BottomRight:
                            layout.checkArea.X = field.X + field.Width - checkSizeFull;
                            layout.checkArea.Width = checkSizeFull + 1;
 
                            layout.checkArea.Y = field.Y;
                            layout.checkArea.Height = field.Height;
 
                            layout.field.Width -= checkSizeFull + 1;
                            break;
                        case ContentAlignment.TopCenter:
                            layout.checkArea.X = field.X;
                            layout.checkArea.Width = field.Width;
 
                            layout.checkArea.Y = field.Y;
                            layout.checkArea.Height = checkSizeFull;
 
                            layout.field.Y += checkSizeFull;
                            layout.field.Height -= checkSizeFull;
                            break;
 
                        case ContentAlignment.BottomCenter:
                            layout.checkArea.X = field.X;
                            layout.checkArea.Width = field.Width;
 
                            layout.checkArea.Y = field.Y + field.Height - checkSizeFull;
                            layout.checkArea.Height = checkSizeFull;
 
                            layout.field.Height -= checkSizeFull;
                            break;
 
                        case ContentAlignment.MiddleCenter:
                            layout.checkArea = layout.checkBounds;
                            break;
                    }
 
                    layout.checkBounds.Width -= checkPaddingSize;
                    layout.checkBounds.Height -= checkPaddingSize;
                }
            }
 
            // Maps an image align to the set of TextImageRelations that represent the same edge.
            // For example, imageAlign = TopLeft maps to TextImageRelations ImageAboveText (top)
            // and ImageBeforeText (left).
            private static readonly TextImageRelation[] _imageAlignToRelation = new TextImageRelation[] {
                /* TopLeft = */       TextImageRelation.ImageAboveText | TextImageRelation.ImageBeforeText,
                /* TopCenter = */     TextImageRelation.ImageAboveText,
                /* TopRight = */      TextImageRelation.ImageAboveText | TextImageRelation.TextBeforeImage,
                /* Invalid */         0,
                /* MiddleLeft = */    TextImageRelation.ImageBeforeText,
                /* MiddleCenter = */  0,
                /* MiddleRight = */   TextImageRelation.TextBeforeImage,
                /* Invalid */         0,
                /* BottomLeft = */    TextImageRelation.TextAboveImage | TextImageRelation.ImageBeforeText,
                /* BottomCenter = */  TextImageRelation.TextAboveImage,
                /* BottomRight = */   TextImageRelation.TextAboveImage | TextImageRelation.TextBeforeImage
            };
 
            private static TextImageRelation ImageAlignToRelation(ContentAlignment alignment) {
                return _imageAlignToRelation[LayoutUtils.ContentAlignmentToIndex(alignment)];
            }
 
            private static TextImageRelation TextAlignToRelation(ContentAlignment alignment) {
                return LayoutUtils.GetOppositeTextImageRelation(ImageAlignToRelation(alignment));
            }
 
            internal void LayoutTextAndImage(LayoutData layout) {
                // Translate for Rtl applications.  This intentially shadows the member variables.
                ContentAlignment imageAlign = RtlTranslateContent(this.imageAlign);
                ContentAlignment textAlign = RtlTranslateContent(this.textAlign);
                TextImageRelation textImageRelation = RtlTranslateRelation(this.textImageRelation);
 
                // Figure out the maximum bounds for text & image
                Rectangle maxBounds = Rectangle.Inflate(layout.field, -textImageInset, -textImageInset);
                if(OnePixExtraBorder) {
                    maxBounds.Inflate(1, 1);
                }
 
                // Compute the final image and text bounds.
                if(imageSize == Size.Empty || text == null || text.Length == 0 || textImageRelation == TextImageRelation.Overlay) {
                    // Do not worry about text/image overlaying
                    Size textSize = GetTextSize(maxBounds.Size);
 
                    // FOR EVERETT COMPATIBILITY - DO NOT CHANGE
                    Size size = imageSize;
                    if (layout.options.everettButtonCompat && imageSize != Size.Empty) {
                        size = new Size(size.Width + 1, size.Height + 1);
                    }
                    
                    layout.imageBounds = LayoutUtils.Align(size, maxBounds, imageAlign);
                    layout.textBounds = LayoutUtils.Align(textSize, maxBounds, textAlign);
 
                } else {
                    // Rearrage text/image to prevent overlay.  Pack text into maxBounds - space reserved for image
                    Size maxTextSize = LayoutUtils.SubAlignedRegion(maxBounds.Size, imageSize, textImageRelation);
                    Size textSize = GetTextSize(maxTextSize);
                    Rectangle maxCombinedBounds = maxBounds;
 
                    // Combine text & image into one rectangle that we center within maxBounds.
                    Size combinedSize = LayoutUtils.AddAlignedRegion(textSize, imageSize, textImageRelation);
                    maxCombinedBounds.Size = LayoutUtils.UnionSizes(maxCombinedBounds.Size, combinedSize);
                    Rectangle combinedBounds = LayoutUtils.Align(combinedSize, maxCombinedBounds, ContentAlignment.MiddleCenter);
 
                    // imageEdge indicates whether the combination of imageAlign and textImageRelation place
                    // the image along the edge of the control.  If so, we can increase the space for text.
                    bool imageEdge = (AnchorStyles)(ImageAlignToRelation(imageAlign) & textImageRelation) != AnchorStyles.None;
 
                    // textEdge indicates whether the combination of textAlign and textImageRelation place
                    // the text along the edge of the control.  If so, we can increase the space for image.
                    bool textEdge = (AnchorStyles)(TextAlignToRelation(textAlign) & textImageRelation) != AnchorStyles.None;
 
                    if(imageEdge) {
                        // If imageEdge, just split imageSize off of maxCombinedBounds.
                        LayoutUtils.SplitRegion(maxCombinedBounds, imageSize, (AnchorStyles) textImageRelation, out layout.imageBounds, out layout.textBounds);
                    } else if(textEdge) {
                        // Else if textEdge, just split textSize off of maxCombinedBounds.
                        LayoutUtils.SplitRegion(maxCombinedBounds, textSize, (AnchorStyles) LayoutUtils.GetOppositeTextImageRelation(textImageRelation), out layout.textBounds, out layout.imageBounds);
                    } else {                        
                        // Expand the adjacent regions to maxCombinedBounds (centered) and split the rectangle into imageBounds and textBounds.
                        LayoutUtils.SplitRegion(combinedBounds, imageSize, (AnchorStyles) textImageRelation, out layout.imageBounds, out layout.textBounds);
                        LayoutUtils.ExpandRegionsToFillBounds(maxCombinedBounds, (AnchorStyles) textImageRelation, ref layout.imageBounds, ref layout.textBounds);
                    }
 
                    // align text/image within their regions.
                    layout.imageBounds = LayoutUtils.Align(imageSize, layout.imageBounds, imageAlign);
                    layout.textBounds = LayoutUtils.Align(textSize, layout.textBounds, textAlign);
                }
                 
                //Don't call "layout.imageBounds = Rectangle.Intersect(layout.imageBounds, maxBounds);"
                // because that is a breaking change that causes images to be scaled to the dimensions of the control.
                //adjust textBounds so that the text is still visible even if the image is larger than the button's size
                //fixes Whidbey 234985
                //why do we intersect with layout.field for textBounds while we intersect with maxBounds for imageBounds?
                //this is because there are some legacy code which squeezes the button so small that text will get clipped
                //if we intersect with maxBounds. Have to do this for backward compatibility.
                //See Whidbey 341480
                if (textImageRelation == TextImageRelation.TextBeforeImage || textImageRelation == TextImageRelation.ImageBeforeText) {
                    //adjust the vertical position of textBounds so that the text doesn't fall off the boundary of the button
                    int textBottom = Math.Min(layout.textBounds.Bottom, layout.field.Bottom);
                    layout.textBounds.Y = Math.Max(Math.Min(layout.textBounds.Y, layout.field.Y + (layout.field.Height - layout.textBounds.Height)/2), layout.field.Y);
                    layout.textBounds.Height = textBottom - layout.textBounds.Y;
                }
                if (textImageRelation == TextImageRelation.TextAboveImage || textImageRelation == TextImageRelation.ImageAboveText) {
                    //adjust the horizontal position of textBounds so that the text doesn't fall off the boundary of the button
                    int textRight = Math.Min(layout.textBounds.Right, layout.field.Right);
                    layout.textBounds.X = Math.Max(Math.Min(layout.textBounds.X, layout.field.X + (layout.field.Width - layout.textBounds.Width)/2), layout.field.X);
                    layout.textBounds.Width = textRight - layout.textBounds.X;
                }
                if (textImageRelation == TextImageRelation.ImageBeforeText && layout.imageBounds.Size.Width != 0) {
                    //squeezes imageBounds.Width so that text is visible
                    layout.imageBounds.Width = Math.Max(0, Math.Min(maxBounds.Width - layout.textBounds.Width, layout.imageBounds.Width));
                    layout.textBounds.X = layout.imageBounds.X + layout.imageBounds.Width;
                }
                if (textImageRelation == TextImageRelation.ImageAboveText && layout.imageBounds.Size.Height != 0) {
                    //squeezes imageBounds.Height so that the text is visible
                    layout.imageBounds.Height = Math.Max(0, Math.Min(maxBounds.Height - layout.textBounds.Height, layout.imageBounds.Height));
                    layout.textBounds.Y = layout.imageBounds.Y + layout.imageBounds.Height;
                }
                //make sure that textBound is contained in layout.field
                layout.textBounds = Rectangle.Intersect(layout.textBounds, layout.field);
                if (hintTextUp) {
                    layout.textBounds.Y--;
                }
                if (textOffset) {
                    layout.textBounds.Offset(1, 1);
                }
                
                // FOR EVERETT COMPATIBILITY - DO NOT CHANGE
                if (layout.options.everettButtonCompat) {
                    layout.imageStart = layout.imageBounds.Location;
                    layout.imageBounds = Rectangle.Intersect(layout.imageBounds, layout.field);
                }
                else if (!Application.RenderWithVisualStyles) {
                    // Not sure why this is here, but we can't remove it, since it might break
                    // ToolStrips on non-themed machines
                    layout.textBounds.X++;
                }
 
                // clip
                //
                int bottom;
                // If we are using GDI to measure text, then we can get into a situation, where
                // the proposed height is ignore. In this case, we want to clip it against
                // maxbounds. VSWhidbey #480670
                if (!useCompatibleTextRendering) {
                    bottom = Math.Min(layout.textBounds.Bottom, maxBounds.Bottom);
                    layout.textBounds.Y = Math.Max(layout.textBounds.Y, maxBounds.Y);
                }
                else {
                    // If we are using GDI+ (like Everett), then use the old Everett code
                    // This ensures that we have pixel-level rendering compatibility
                    bottom = Math.Min(layout.textBounds.Bottom, layout.field.Bottom);
                    layout.textBounds.Y = Math.Max(layout.textBounds.Y, layout.field.Y);
                }
                layout.textBounds.Height = bottom - layout.textBounds.Y;                
                
                //This causes a breaking change because images get shrunk to the new clipped size instead of clipped.
                //********** bottom = Math.Min(layout.imageBounds.Bottom, maxBounds.Bottom);
                //********** layout.imageBounds.Y = Math.Max(layout.imageBounds.Y, maxBounds.Y);
                //********** layout.imageBounds.Height = bottom - layout.imageBounds.Y;                
 
            }
 
            protected virtual Size GetTextSize(Size proposedSize) {
                //set the Prefix field of TextFormatFlags 
                proposedSize = LayoutUtils.FlipSizeIf(verticalText, proposedSize);
                Size textSize = Size.Empty;
 
                if (useCompatibleTextRendering) { // GDI+ text rendering.
                    using (Graphics g = WindowsFormsUtils.CreateMeasurementGraphics()) {
                        using ( StringFormat gdipStringFormat = this.StringFormat ) {
                            textSize = Size.Ceiling(g.MeasureString(text, font, new SizeF(proposedSize.Width, proposedSize.Height), gdipStringFormat));
                        }
                    }
                }
                else if (!string.IsNullOrEmpty(text)) { // GDI text rendering (Whidbey feature).
                    textSize = TextRenderer.MeasureText(text, font, proposedSize, this.TextFormatFlags);
                }
                //else skip calling MeasureText, it should return 0,0
 
                return LayoutUtils.FlipSizeIf(verticalText, textSize);
               
            }
 
#if DEBUG
            public override string ToString() {
                return 
                    "{ client = " + client + "\n" + 
                    "OnePixExtraBorder = " + OnePixExtraBorder + "\n" + 
                    "borderSize = " + borderSize + "\n" + 
                    "paddingSize = " + paddingSize + "\n" + 
                    "maxFocus = " + maxFocus + "\n" + 
                    "font = " + font + "\n" + 
                    "text = " + text + "\n" + 
                    "imageSize = " + imageSize + "\n" + 
                    "checkSize = " + checkSize + "\n" + 
                    "checkPaddingSize = " + checkPaddingSize + "\n" + 
                    "checkAlign = " + checkAlign + "\n" + 
                    "imageAlign = " + imageAlign + "\n" + 
                    "textAlign = " + textAlign + "\n" + 
                    "textOffset = " + textOffset + "\n" + 
                    "shadowedText = " + shadowedText + "\n" + 
                    "textImageRelation = " + textImageRelation + "\n" + 
                    "layoutRTL = " + layoutRTL + " }";
            }
#endif            
        }
 
        internal class LayoutData {
            internal Rectangle client;
            internal Rectangle face;
            internal Rectangle checkArea;
            internal Rectangle checkBounds;
            internal Rectangle textBounds;
            internal Rectangle field;
            internal Rectangle focus;
            internal Rectangle imageBounds;
            internal Point imageStart; // FOR EVERETT COMPATIBILITY - DO NOT CHANGE                      
            internal LayoutOptions options;
 
            internal LayoutData(LayoutOptions options) {
                Debug.Assert(options != null, "must have options");
                this.options = options;
            }
        }
 
#endregion
 
#region Layout
 
        // used by the DataGridViewButtonCell
        internal static LayoutOptions CommonLayout(Rectangle clientRectangle, Padding padding, bool isDefault, Font font, string text, bool enabled, ContentAlignment textAlign, RightToLeft rtl)
        {
            LayoutOptions layout = new LayoutOptions();
            layout.client             = LayoutUtils.DeflateRect(clientRectangle, padding);
            layout.padding            = padding;
            layout.growBorderBy1PxWhenDefault = true;
            layout.isDefault          = isDefault;
            layout.borderSize         = 2;
            layout.paddingSize        = 0;
            layout.maxFocus           = true;
            layout.focusOddEvenFixup  = false;
            layout.font               = font;
            layout.text               = text;
            layout.imageSize          = Size.Empty;
            layout.checkSize          = 0;
            layout.checkPaddingSize   = 0;
            layout.checkAlign         = ContentAlignment.TopLeft;
            layout.imageAlign         = ContentAlignment.MiddleCenter;
            layout.textAlign          = textAlign;
            layout.hintTextUp         = false;
            layout.shadowedText       = !enabled;
            layout.layoutRTL          = RightToLeft.Yes == rtl;
            layout.textImageRelation  = TextImageRelation.Overlay;
            layout.useCompatibleTextRendering = false;
            return layout;
        }
 
        internal virtual LayoutOptions CommonLayout() {
            LayoutOptions layout = new LayoutOptions();
            layout.client             = LayoutUtils.DeflateRect(Control.ClientRectangle, Control.Padding);
            layout.padding            = Control.Padding;
            layout.growBorderBy1PxWhenDefault = true;
            layout.isDefault          = Control.IsDefault;
            layout.borderSize         = 2;
            layout.paddingSize        = 0;
            layout.maxFocus           = true;
            layout.focusOddEvenFixup  = false;
            layout.font               = Control.Font;
            layout.text               = Control.Text;
            layout.imageSize          = (Control.Image == null) ? Size.Empty : Control.Image.Size;
            layout.checkSize          = 0;
            layout.checkPaddingSize   = 0;
            layout.checkAlign         = ContentAlignment.TopLeft;
            layout.imageAlign         = Control.ImageAlign;
            layout.textAlign          = Control.TextAlign;
            layout.hintTextUp         = false;
            layout.shadowedText       = !Control.Enabled;
            layout.layoutRTL          = RightToLeft.Yes == Control.RightToLeft;
            layout.textImageRelation  = Control.TextImageRelation;
            layout.useCompatibleTextRendering = Control.UseCompatibleTextRendering;
 
            if( Control.FlatStyle != FlatStyle.System ) {
                if( layout.useCompatibleTextRendering ) {
                    using( StringFormat format = Control.CreateStringFormat() ) {
                        layout.StringFormat = format;
                    }
                }
                else {
                    layout.gdiTextFormatFlags = Control.CreateTextFormatFlags();
                }
            }
            
            return layout;
        }
 
        // used by the DataGridViewButtonCell
        static ColorOptions CommonRender(Graphics g, Color foreColor, Color backColor, bool enabled) {
            ColorOptions colors = new ColorOptions(g, foreColor, backColor);
            colors.enabled = enabled;
            return colors;
        }
 
        ColorOptions CommonRender(Graphics g) {
            ColorOptions colors = new ColorOptions(g, Control.ForeColor, Control.BackColor);
            colors.enabled = Control.Enabled;
            return colors;
        }
 
        protected ColorOptions PaintRender(Graphics g) {
            return CommonRender(g);
        }
 
        // used by the DataGridViewButtonCell
        internal static ColorOptions PaintFlatRender(Graphics g, Color foreColor, Color backColor, bool enabled) {
            return CommonRender(g, foreColor, backColor, enabled);
        }
 
        protected ColorOptions PaintFlatRender(Graphics g) {
            return CommonRender(g);
        }
 
        // used by the DataGridViewButtonCell
        internal static ColorOptions PaintPopupRender(Graphics g, Color foreColor, Color backColor, bool enabled) {
            return CommonRender(g, foreColor, backColor, enabled);
        }
 
        protected ColorOptions PaintPopupRender(Graphics g) {
            return CommonRender(g);
        }
 
#endregion
 
    }
}