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

        /* Begin Definitions */

        alias: ['layout.button'],

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

        /* End Definitions */

        type: 'button',

        cellClsRE: /-btn-(tl|br)\b/,
        htmlRE: /<.*>/,

        beforeLayout: function() {
            return this.callParent(arguments) || this.lastText !== this.owner.text;
        },

        /**
         * Set the dimensions of the inner &lt;button&gt; element to match the
         * component dimensions.
         */
        onLayout: function(width, height) {
            var me = this,
                isNum = Ext.isNumber,
                owner = me.owner,
                ownerEl = owner.el,
                btnEl = owner.btnEl,
                btnInnerEl = owner.btnInnerEl,
                btnIconEl = owner.btnIconEl,
                sizeIconEl = (owner.icon || owner.iconCls) && (owner.iconAlign == "top" || owner.iconAlign == "bottom"),
                minWidth = owner.minWidth,
                maxWidth = owner.maxWidth,
                ownerWidth, btnFrameWidth, metrics;

            me.getTargetInfo();
            me.callParent(arguments);

            btnInnerEl.unclip();
            me.setTargetSize(width, height);

            if (!isNum(width)) {
                // In IE7 strict mode button elements with width:auto get strange extra side margins within
                // the wrapping table cell, but they go away if the width is explicitly set. So we measure
                // the size of the text and set the width to match.
                if (owner.text && Ext.isIE7 && Ext.isStrict && btnEl && btnEl.getWidth() > 20) {
                    btnFrameWidth = me.btnFrameWidth;
                    metrics = Ext.util.TextMetrics.measure(btnInnerEl, owner.text);
                    ownerEl.setWidth(metrics.width + btnFrameWidth + me.adjWidth);
                    btnEl.setWidth(metrics.width + btnFrameWidth);
                    btnInnerEl.setWidth(metrics.width + btnFrameWidth);

                    if (sizeIconEl) {
                        btnIconEl.setWidth(metrics.width + btnFrameWidth);
                    }
                } else {
                    // Remove any previous fixed widths
                    ownerEl.setWidth(null);
                    btnEl.setWidth(null);
                    btnInnerEl.setWidth(null);
                    btnIconEl.setWidth(null);
                }

                // Handle maxWidth/minWidth config
                if (minWidth || maxWidth) {
                    ownerWidth = ownerEl.getWidth();
                    if (minWidth && (ownerWidth < minWidth)) {
                        me.setTargetSize(minWidth, height);
                    }
                    else if (maxWidth && (ownerWidth > maxWidth)) {
                        btnInnerEl.clip();
                        me.setTargetSize(maxWidth, height);
                    }
                }
            }

            this.lastText = owner.text;
        },

        setTargetSize: function(width, height) {
            var me = this,
                owner = me.owner,
                isNum = Ext.isNumber,
                btnInnerEl = owner.btnInnerEl,
                btnWidth = (isNum(width) ? width - me.adjWidth : width),
                btnHeight = (isNum(height) ? height - me.adjHeight : height),
                btnFrameHeight = me.btnFrameHeight,
                text = owner.getText(),
                textHeight;

            me.callParent(arguments);
            me.setElementSize(owner.btnEl, btnWidth, btnHeight);
            me.setElementSize(btnInnerEl, btnWidth, btnHeight);
            if (isNum(btnHeight)) {
                btnInnerEl.setStyle('line-height', btnHeight - btnFrameHeight + 'px');
            }

            // Button text may contain markup that would force it to wrap to more than one line (e.g. 'Button<br>Label').
            // When this happens, we cannot use the line-height set above for vertical centering; we instead reset the
            // line-height to normal, measure the rendered text height, and add padding-top to center the text block
            // vertically within the button's height. This is more expensive than the basic line-height approach so
            // we only do it if the text contains markup.
            if (text && this.htmlRE.test(text)) {
                btnInnerEl.setStyle('line-height', 'normal');
                textHeight = Ext.util.TextMetrics.measure(btnInnerEl, text).height;
                btnInnerEl.setStyle('padding-top', me.btnFrameTop + Math.max(btnInnerEl.getHeight() - btnFrameHeight - textHeight, 0) / 2 + 'px');
                me.setElementSize(btnInnerEl, btnWidth, btnHeight);
            }
        },

        getTargetInfo: function() {
            var me = this,
                owner = me.owner,
                ownerEl = owner.el,
                frameSize = me.frameSize,
                frameBody = owner.frameBody,
                btnWrap = owner.btnWrap,
                innerEl = owner.btnInnerEl;

            if (!('adjWidth' in me)) {
                Ext.apply(me, {
                    // Width adjustment must take into account the arrow area. The btnWrap is the <em> which has padding to accommodate the arrow.
                    adjWidth: frameSize.left + frameSize.right + ownerEl.getBorderWidth('lr') + ownerEl.getPadding('lr') +
                              btnWrap.getPadding('lr') + (frameBody ? frameBody.getFrameWidth('lr') : 0),
                    adjHeight: frameSize.top + frameSize.bottom + ownerEl.getBorderWidth('tb') + ownerEl.getPadding('tb') +
                               btnWrap.getPadding('tb') + (frameBody ? frameBody.getFrameWidth('tb') : 0),
                    btnFrameWidth: innerEl.getFrameWidth('lr'),
                    btnFrameHeight: innerEl.getFrameWidth('tb'),
                    btnFrameTop: innerEl.getFrameWidth('t')
                });
            }

            return me.callParent();
        }
    });