    /**
     * @class Ext.layout.component.Component
     * @extends Ext.layout.Layout
     *
     * This class is intended to be extended or created via the {@link Ext.Component#componentLayout layout}
     * configuration property.  See {@link Ext.Component#componentLayout} for additional details.
     *
     * @private
     */
    Ext.define('Ext.layout.component.Component', {

        /* Begin Definitions */

        extend: 'Ext.layout.Layout',

        /* End Definitions */

        type: 'component',

        monitorChildren: true,

        initLayout : function() {
            var me = this,
                owner = me.owner,
                ownerEl = owner.el;

            if (!me.initialized) {
                if (owner.frameSize) {
                    me.frameSize = owner.frameSize;
                }
                else {
                    owner.frameSize = me.frameSize = {
                        top: 0,
                        left: 0,
                        bottom: 0,
                        right: 0
                    };
                }
            }
            me.callParent(arguments);
        },

        beforeLayout : function(width, height, isSetSize, callingContainer) {
            this.callParent(arguments);

            var me = this,
                owner = me.owner,
                ownerCt = owner.ownerCt,
                layout = owner.layout,
                isVisible = owner.isVisible(true),
                ownerElChild = owner.el.child,
                layoutCollection;

            // Cache the size we began with so we can see if there has been any effect.
            me.previousComponentSize = me.lastComponentSize;

            // Do not allow autoing of any dimensions which are fixed
            if (!isSetSize
                && ((!Ext.isNumber(width) && owner.isFixedWidth()) ||
                    (!Ext.isNumber(height) && owner.isFixedHeight()))
                // unless we are being told to do so by the ownerCt's layout
                && callingContainer && callingContainer !== ownerCt) {

                me.doContainerLayout();
                return false;
            }

            // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
            // If the owner itself is a directly hidden floater, set the needsLayout object on that for when it is shown.
            if (!isVisible && (owner.hiddenAncestor || owner.floating)) {
                if (owner.hiddenAncestor) {
                    layoutCollection = owner.hiddenAncestor.layoutOnShow;
                    layoutCollection.remove(owner);
                    layoutCollection.add(owner);
                }
                owner.needsLayout = {
                    width: width,
                    height: height,
                    isSetSize: false
                };
            }

            if (isVisible && this.needsLayout(width, height)) {
                return owner.beforeComponentLayout(width, height, isSetSize, callingContainer);
            }
            else {
                return false;
            }
        },

        /**
        * Check if the new size is different from the current size and only
        * trigger a layout if it is necessary.
        * @param {Number} width The new width to set.
        * @param {Number} height The new height to set.
        */
        needsLayout : function(width, height) {
            var me = this,
                widthBeingChanged,
                heightBeingChanged;
                me.lastComponentSize = me.lastComponentSize || {
                    width: -Infinity,
                    height: -Infinity
                };

            // If autoWidthing, or an explicitly different width is passed, then the width is being changed.
            widthBeingChanged  = !Ext.isDefined(width)  || me.lastComponentSize.width  !== width;

            // If autoHeighting, or an explicitly different height is passed, then the height is being changed.
            heightBeingChanged = !Ext.isDefined(height) || me.lastComponentSize.height !== height;

            // isSizing flag added to prevent redundant layouts when going up the layout chain
            return !me.isSizing && (me.childrenChanged || widthBeingChanged || heightBeingChanged);
        },

        /**
        * Set the size of any element supporting undefined, null, and values.
        * @param {Number} width The new width to set.
        * @param {Number} height The new height to set.
        */
        setElementSize: function(el, width, height) {
            if (width !== undefined && height !== undefined) {
                el.setSize(width, height);
            }
            else if (height !== undefined) {
                el.setHeight(height);
            }
            else if (width !== undefined) {
                el.setWidth(width);
            }
        },

        /**
         * Returns the owner component's resize element.
         * @return {Ext.Element}
         */
         getTarget : function() {
             return this.owner.el;
         },

        /**
         * <p>Returns the element into which rendering must take place. Defaults to the owner Component's encapsulating element.</p>
         * May be overridden in Component layout managers which implement an inner element.
         * @return {Ext.Element}
         */
        getRenderTarget : function() {
            return this.owner.el;
        },

        /**
        * Set the size of the target element.
        * @param {Number} width The new width to set.
        * @param {Number} height The new height to set.
        */
        setTargetSize : function(width, height) {
            var me = this;
            me.setElementSize(me.owner.el, width, height);

            if (me.owner.frameBody) {
                var targetInfo = me.getTargetInfo(),
                    padding = targetInfo.padding,
                    border = targetInfo.border,
                    frameSize = me.frameSize;

                me.setElementSize(me.owner.frameBody,
                    Ext.isNumber(width) ? (width - frameSize.left - frameSize.right - padding.left - padding.right - border.left - border.right) : width,
                    Ext.isNumber(height) ? (height - frameSize.top - frameSize.bottom - padding.top - padding.bottom - border.top - border.bottom) : height
                );
            }

            me.autoSized = {
                width: !Ext.isNumber(width),
                height: !Ext.isNumber(height)
            };

            me.lastComponentSize = {
                width: width,
                height: height
            };
        },

        getTargetInfo : function() {
            if (!this.targetInfo) {
                var target = this.getTarget(),
                    body = this.owner.getTargetEl();

                this.targetInfo = {
                    padding: {
                        top: target.getPadding('t'),
                        right: target.getPadding('r'),
                        bottom: target.getPadding('b'),
                        left: target.getPadding('l')
                    },
                    border: {
                        top: target.getBorderWidth('t'),
                        right: target.getBorderWidth('r'),
                        bottom: target.getBorderWidth('b'),
                        left: target.getBorderWidth('l')
                    },
                    bodyMargin: {
                        top: body.getMargin('t'),
                        right: body.getMargin('r'),
                        bottom: body.getMargin('b'),
                        left: body.getMargin('l')
                    }
                };
            }
            return this.targetInfo;
        },

        // Start laying out UP the ownerCt's layout when flagged to do so.
        doOwnerCtLayouts: function() {
            var owner = this.owner,
                ownerCt = owner.ownerCt,
                ownerCtComponentLayout, ownerCtContainerLayout,
                curSize = this.lastComponentSize,
                prevSize = this.previousComponentSize,
                widthChange  = (prevSize && curSize && Ext.isNumber(curSize.width )) ? curSize.width  !== prevSize.width  : true,
                heightChange = (prevSize && curSize && Ext.isNumber(curSize.height)) ? curSize.height !== prevSize.height : true;

            // If size has not changed, do not inform upstream layouts
            if (!ownerCt || (!widthChange && !heightChange)) {
                return;
            }

            ownerCtComponentLayout = ownerCt.componentLayout;
            ownerCtContainerLayout = ownerCt.layout;

            if (!owner.floating && ownerCtComponentLayout && ownerCtComponentLayout.monitorChildren && !ownerCtComponentLayout.layoutBusy) {
                if (!ownerCt.suspendLayout && ownerCtContainerLayout && !ownerCtContainerLayout.layoutBusy) {

                    // If the owning Container may be adjusted in any of the the dimension which have changed, perform its Component layout
                    if (((widthChange && !ownerCt.isFixedWidth()) || (heightChange && !ownerCt.isFixedHeight()))) {
                        // Set the isSizing flag so that the upstream Container layout (called after a Component layout) can omit this component from sizing operations
                        this.isSizing = true;
                        ownerCt.doComponentLayout();
                        this.isSizing = false;
                    }
                    // Execute upstream Container layout
                    else if (ownerCtContainerLayout.bindToOwnerCtContainer === true) {
                        ownerCtContainerLayout.layout();
                    }
                }
            }
        },

        doContainerLayout: function() {
            var me = this,
                owner = me.owner,
                ownerCt = owner.ownerCt,
                layout = owner.layout,
                ownerCtComponentLayout;

            // Run the container layout if it exists (layout for child items)
            // **Unless automatic laying out is suspended, or the layout is currently running**
            if (!owner.suspendLayout && layout && layout.isLayout && !layout.layoutBusy && !layout.isAutoDock) {
                layout.layout();
            }

            // Tell the ownerCt that it's child has changed and can be re-layed by ignoring the lastComponentSize cache.
            if (ownerCt && ownerCt.componentLayout) {
                ownerCtComponentLayout = ownerCt.componentLayout;
                if (!owner.floating && ownerCtComponentLayout.monitorChildren && !ownerCtComponentLayout.layoutBusy) {
                    ownerCtComponentLayout.childrenChanged = true;
                }
            }
        },

        afterLayout : function(width, height, isSetSize, layoutOwner) {
            this.doContainerLayout();
            this.owner.afterComponentLayout(width, height, isSetSize, layoutOwner);
        }
    });