    /**
     * Component layout for buttons
     * @private
     */
    Ext.define('Ext.layout.component.Button', {

        /* Begin Definitions */

        alias: ['layout.button'],

        extend: 'Ext.layout.component.Auto',

        /* End Definitions */

        type: 'button',

        htmlRE: /<.*>/,

        beginLayout: function(ownerContext) {
            var me = this,
                owner = me.owner,
                text = owner.text;

            me.callParent(arguments);
            ownerContext.btnWrapContext = ownerContext.getEl('btnWrap');
            ownerContext.btnElContext = ownerContext.getEl('btnEl');
            ownerContext.btnInnerElContext = ownerContext.getEl('btnInnerEl');
            ownerContext.btnIconElContext = ownerContext.getEl('btnIconEl');

            if (text && me.htmlRE.test(text)) {
                ownerContext.isHtmlText = true;
                // If the text contains HTML tag(s) we need to account for the possibility
                // of multi-line-text. We have to remove the default line-height set by the
                // stylesheet so that we can allow the browser to measure the natural
                // height of the html content.
                owner.btnInnerEl.setStyle('line-height', 'normal');
                owner.btnInnerEl.setStyle('padding-top', '');
            }
        },

        beginLayoutCycle: function(ownerContext) {
            var owner = this.owner,
                lastWidthModel = this.lastWidthModel;

            this.callParent(arguments);

            if (lastWidthModel && !this.lastWidthModel.shrinkWrap &&
                ownerContext.widthModel.shrinkWrap) {
                // clear any heights we set last time around if needed
                owner.btnWrap.setStyle('height', '');
                owner.btnEl.setStyle('height', '');
                owner.btnInnerEl.setStyle('line-height', '');
            }
        },

        calculate: function(ownerContext) {
            var me = this,
                owner = me.owner,
                btnElContext = ownerContext.btnElContext,
                btnInnerElContext = ownerContext.btnInnerElContext,
                btnWrapContext = ownerContext.btnWrapContext,
                mmax = Math.max,
                ownerHeight, contentHeight, btnElHeight, innerElHeight;

            me.callParent(arguments);

            if (ownerContext.heightModel.shrinkWrap) {
                // Buttons that have a shrink-wrapped height usually do not need any layout
                // adjustments beause their layout is handled in CSS. An exception is made
                // for buttons that contain html tags in their "text".  These buttons need
                // special handling to vertically center the inner element inside the button.

                // measure the btnEl (the anchor element) to determine the available
                // height for centering the inner element.
                btnElHeight = owner.btnEl.getHeight();
                if (ownerContext.isHtmlText) {
                    me.centerInnerEl(
                        ownerContext,
                        btnElHeight
                    );
                    me.ieCenterIcon(ownerContext, btnElHeight);
                }
            } else {
                // Buttons with configured or calculated heights may need to stretch their
                // inner elements to fit.
                ownerHeight = ownerContext.getProp('height');

                // If height is 0, skip out all this
                if (ownerHeight) {
                    // contentHeight is the total available height inside the button's padding
                    // and framing
                    contentHeight = ownerHeight - ownerContext.getFrameInfo().height - ownerContext.getPaddingInfo().height;

                    // The btnElHeight is the total available height to be shared by the button's
                    // icon and text.  For standard buttons this is the same as the contentHeight
                    // but must be adjusted for arrow height if the button has an arrow.
                    btnElHeight = contentHeight;
                    if ((owner.menu || owner.split) && owner.arrowAlign === 'bottom') {
                        // If the button has an arrow, subtract its size from the btnElHeight
                        // padding to account for the possibility of an arrow
                        btnElHeight -= btnWrapContext.getPaddingInfo().bottom;
                    }

                    // The innerElHeight is the total vertical space available for vertically
                    // centering the button text.  By default this is the same as btnElHeight
                    // but it must be adjusted by the icon size if the button has a top
                    // or bottom icon.
                    innerElHeight = btnElHeight;
                    if ((owner.icon || owner.iconCls || owner.glyph) &&
                        (owner.iconAlign === 'top' || owner.iconAlign === 'bottom')) {
                        innerElHeight -= btnInnerElContext.getPaddingInfo().height;
                    }

                    btnWrapContext.setProp('height', mmax(0, contentHeight));
                    btnElContext.setProp('height', mmax(0, btnElHeight));
                    // ensure the button's text is vertically centered
                    if (ownerContext.isHtmlText) {
                        // if the button text contains html it must be vertically centered
                        // by measuring it and adding top padding.
                        me.centerInnerEl(ownerContext, btnElHeight);
                    } else {
                        // if the button text does not contain html we can just center it
                        // using line-height to avoid the extra measurement that happens
                        // inside of centerInnerEl() since multi-line text is not a possiblity
                        btnInnerElContext.setProp('line-height', mmax(0, innerElHeight) + 'px');
                    }
                    me.ieCenterIcon(ownerContext, btnElHeight);
                } else if (ownerHeight !== 0) {
                    // Only fail if height was undefined, since it could be 0
                    me.done = false;
                }
            }
        },

        centerInnerEl: function(ownerContext, btnElHeight) {
            var me = this,
                btnInnerElContext = ownerContext.btnInnerElContext,
                innerElHeight = me.owner.btnInnerEl.getHeight();

            if (ownerContext.heightModel.shrinkWrap && (btnElHeight < innerElHeight)) {
                // if the natural height of the html content is greater than the height
                // of the button element (the anchor el), then expand the button element
                // to fit
                ownerContext.btnElContext.setHeight(innerElHeight);
            } else if (btnElHeight > innerElHeight) {
                // if the natural height of the html content is smaller than the height
                // of the button element then we need to pad the top of the btnInnerEl
                // so that it is vertically centered within the btnEl
                btnInnerElContext.setProp(
                    'padding-top',
                    Math.round((btnElHeight - innerElHeight) / 2) +
                        // if the inner element already has top padding, as is the case
                        // when the button has a top-aligned icon, then add the existing
                        // padding to the padding adjustment.
                        btnInnerElContext.getPaddingInfo().top
                );
            }
        },

        ieCenterIcon: function(ownerContext, btnElHeight) {
            var iconAlign = this.owner.iconAlign;

            if ((Ext.isIEQuirks || Ext.isIE6) &&
                (iconAlign === 'left' || iconAlign === 'right')) {
                // Normally right/left aligned icon elements are vertically stretched using
                // top:0, bottom:0, and the icon is vertically centered inside this element
                // using background-position.  This technique for vertical centering does not
                // work in IE6 and IE quirks, so the stylesheet sets a fixed height on the
                // icon element in these browsers.  If the layout changes the height of the
                // button the height of the icon element must also be modified.
                ownerContext.btnIconElContext.setHeight(btnElHeight);
            }
        },

        publishInnerWidth: function(ownerContext, width) {
            if (this.owner.getFrameInfo().table) {
                // if the framing template uses a table, we need to set the width of the
                // inner element.  Otherwise long text may stretch the element past its
                // allowable width in IE.
                ownerContext.btnInnerElContext.setWidth(
                    width -
                    // the inner el must be sized inside the owner's framing and padding
                    ownerContext.getFrameInfo().width - ownerContext.getPaddingInfo().width -
                    // There may also be padding on the btnWrap el, e.g. tab with close icon
                    // or button with arrow. This reduces the inner el size even further.
                    ownerContext.btnWrapContext.getPaddingInfo().width
                );
            }
        }

    });