Related: fdo#80633 cache optimal size

Change-Id: Ic2c3aefebd3061d294f339c6d262a3c3e381fbe4
diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx
index 3cf10320..2d68c7a 100644
--- a/include/vcl/window.hxx
+++ b/include/vcl/window.hxx
@@ -1127,6 +1127,19 @@ protected:
    virtual sal_uInt16                  getDefaultAccessibleRole() const;
    virtual OUString                    getDefaultAccessibleName() const;

    /*
     * Advisory Sizing - what is a good size for this widget
     *
     * Retrieves the preferred size of a widget ignoring
     * "width-request" and "height-request" properties.
     *
     * Implement this in sub-classes to tell layout
     * the preferred widget size.
     *
     * Use get_preferred_size to retrieve this value
     * mediated via height and width requests
     */
    virtual Size GetOptimalSize() const;
private:

    SAL_DLLPRIVATE bool                 ImplIsAccessibleCandidate() const;
@@ -1137,6 +1150,20 @@ private:
    SAL_DLLPRIVATE void                 ImplRevokeAccessibleNativeFrame();
    ///@}

    /*
     * Retrieves the preferred size of a widget taking
     * into account the "width-request" and "height-request" properties.
     *
     * Overrides the result of GetOptimalSize to honor the
     * width-request and height-request properties.
     *
     * So the same as get_ungrouped_preferred_size except
     * it ignores groups. A building block of get_preferred_size
     * that access the size cache
     *
     * @see get_preferred_size
     */
    Size get_ungrouped_preferred_size() const;
public:
    /// request XCanvas render interface for this window
    ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas >
@@ -1168,17 +1195,6 @@ public:
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard > GetPrimarySelection();

    /*
     * Advisory Sizing - what is a good size for this widget
     *
     * Retrieves the preferred size of a widget ignoring
     * "width-request" and "height-request" properties.
     *
     * Implement this in sub-classes to tell layout
     * the preferred widget size.
     */
    virtual Size GetOptimalSize() const;

    /*
     * Widgets call this to inform their owner container that the widget wants
     * to renegotiate its size. Should be called when a widget has a new size
     * request. e.g. a FixedText Control gets a new label.
diff --git a/sfx2/source/sidebar/SidebarPanelBase.cxx b/sfx2/source/sidebar/SidebarPanelBase.cxx
index 5a0f3c4..77a34a0 100644
--- a/sfx2/source/sidebar/SidebarPanelBase.cxx
+++ b/sfx2/source/sidebar/SidebarPanelBase.cxx
@@ -218,7 +218,7 @@ ui::LayoutSize SAL_CALL SidebarPanelBase::getHeightForWidth (const sal_Int32 nWi
        if (isLayoutEnabled(mpControl))
        {
            // widget layout-based sidebar
            Size aSize(mpControl->GetOptimalSize());
            Size aSize(mpControl->get_preferred_size());
            return ui::LayoutSize(aSize.Height(), aSize.Height(), aSize.Height());
        }
        else if (pLayoutableWindow != NULL)
@@ -238,7 +238,7 @@ sal_Int32 SAL_CALL SidebarPanelBase::getMinimalWidth () throw(cssu::RuntimeExcep
    if (isLayoutEnabled(mpControl))
    {
        // widget layout-based sidebar
        Size aSize(mpControl->GetOptimalSize());
        Size aSize(mpControl->get_preferred_size());
        return aSize.Width();
    }
    return 0;
diff --git a/toolkit/source/awt/vclxwindow.cxx b/toolkit/source/awt/vclxwindow.cxx
index 96a663f..e264325 100644
--- a/toolkit/source/awt/vclxwindow.cxx
+++ b/toolkit/source/awt/vclxwindow.cxx
@@ -2167,7 +2167,7 @@ void VCLXWindow::setProperty( const OUString& PropertyName, const ::com::sun::st
            case WINDOW_SCROLLBARBOX:
                return VCLXScrollBar::implGetMinimumSize( GetWindow() );
            default:
                aSz = GetWindow()->GetOptimalSize();
                aSz = GetWindow()->get_preferred_size();
        }
    }

diff --git a/vcl/inc/window.h b/vcl/inc/window.h
index ccecb3d..e97eabc 100644
--- a/vcl/inc/window.h
+++ b/vcl/inc/window.h
@@ -242,6 +242,8 @@ public:
    sal_Int32           mnBottomBorder;
    sal_Int32           mnWidthRequest;
    sal_Int32           mnHeightRequest;
    sal_Int32           mnOptimalWidthCache;
    sal_Int32           mnOptimalHeightCache;
    long                mnX;
    long                mnY;
    long                mnAbsScreenX;
diff --git a/vcl/source/window/tabdlg.cxx b/vcl/source/window/tabdlg.cxx
index 3c36eae..7ce6136 100644
--- a/vcl/source/window/tabdlg.cxx
+++ b/vcl/source/window/tabdlg.cxx
@@ -50,7 +50,7 @@ void TabDialog::ImplPosControls()
                pTabControl = pChild;
            else if ( pTabControl )
            {
                Size aOptimalSize(pChild->GetOptimalSize());
                Size aOptimalSize(pChild->get_preferred_size());
                long nTxtWidth = aOptimalSize.Width();
                if ( nTxtWidth > aCtrlSize.Width() )
                    aCtrlSize.Width() = nTxtWidth;
@@ -80,7 +80,7 @@ void TabDialog::ImplPosControls()
        Point   aTabOffset( IMPL_DIALOG_OFFSET, IMPL_DIALOG_OFFSET+nOffY );

        if (isContainerWindow(*pTabControl))
            pTabControl->SetSizePixel(pTabControl->GetOptimalSize());
            pTabControl->SetSizePixel(pTabControl->get_preferred_size());

        Size    aTabSize = pTabControl->GetSizePixel();

diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
index af060f2..4699338 100644
--- a/vcl/source/window/window.cxx
+++ b/vcl/source/window/window.cxx
@@ -608,6 +608,8 @@ WindowImpl::WindowImpl( WindowType nType )
    mnBottomBorder                      = 0;                         // bottom border
    mnWidthRequest                      = -1;                        // width request
    mnHeightRequest                     = -1;                        // height request
    mnOptimalWidthCache                 = -1;                        // optimal width cache
    mnOptimalHeightCache                = -1;                        // optimal height cache
    mnX                                 = 0;                         // X-Position to Parent
    mnY                                 = 0;                         // Y-Position to Parent
    mnAbsScreenX                        = 0;                         // absolute X-position on screen, used for RTL window positioning
diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx
index 24ed6fa..52ccd62 100644
--- a/vcl/source/window/window2.cxx
+++ b/vcl/source/window/window2.cxx
@@ -1428,6 +1428,8 @@ void Window::queue_resize()
    bool bSomeoneCares = queue_ungrouped_resize(this);

    WindowImpl *pWindowImpl = mpWindowImpl->mpBorderWindow ? mpWindowImpl->mpBorderWindow->mpWindowImpl : mpWindowImpl;
    pWindowImpl->mnOptimalWidthCache = -1;
    pWindowImpl->mnOptimalHeightCache = -1;
    if (pWindowImpl->m_xSizeGroup && pWindowImpl->m_xSizeGroup->get_mode() != VCL_SIZE_GROUP_NONE)
    {
        std::set<Window*> &rWindows = pWindowImpl->m_xSizeGroup->get_widgets();
@@ -1689,26 +1691,31 @@ void Window::set_width_request(sal_Int32 nWidthRequest)
    }
}

namespace
Size Window::get_ungrouped_preferred_size() const
{
    Size get_ungrouped_preferred_size(const Window &rWindow)
    Size aRet(get_width_request(), get_height_request());
    if (aRet.Width() == -1 || aRet.Height() == -1)
    {
        Size aRet(rWindow.get_width_request(), rWindow.get_height_request());
        if (aRet.Width() == -1 || aRet.Height() == -1)
        //cache gets blown away by queue_resize
        WindowImpl *pWindowImpl = mpWindowImpl->mpBorderWindow ? mpWindowImpl->mpBorderWindow->mpWindowImpl : mpWindowImpl;
        if (pWindowImpl->mnOptimalWidthCache == -1 || pWindowImpl->mnOptimalHeightCache == -1)
        {
            Size aOptimal = rWindow.GetOptimalSize();
            if (aRet.Width() == -1)
                aRet.Width() = aOptimal.Width();
            if (aRet.Height() == -1)
                aRet.Height() = aOptimal.Height();
            Size aOptimal(GetOptimalSize());
            pWindowImpl->mnOptimalWidthCache = aOptimal.Width();
            pWindowImpl->mnOptimalHeightCache = aOptimal.Height();
        }
        return aRet;

        if (aRet.Width() == -1)
            aRet.Width() = pWindowImpl->mnOptimalWidthCache;
        if (aRet.Height() == -1)
            aRet.Height() = pWindowImpl->mnOptimalHeightCache;
    }
    return aRet;
}

Size Window::get_preferred_size() const
{
    Size aRet(get_ungrouped_preferred_size(*this));
    Size aRet(get_ungrouped_preferred_size());

    WindowImpl *pWindowImpl = mpWindowImpl->mpBorderWindow ? mpWindowImpl->mpBorderWindow->mpWindowImpl : mpWindowImpl;
    if (pWindowImpl->m_xSizeGroup)
@@ -1726,7 +1733,7 @@ Size Window::get_preferred_size() const
                    continue;
                if (bIgnoreInHidden && !pOther->IsVisible())
                    continue;
                Size aOtherSize = get_ungrouped_preferred_size(*pOther);
                Size aOtherSize = pOther->get_ungrouped_preferred_size();
                if (eMode == VCL_SIZE_GROUP_BOTH || eMode == VCL_SIZE_GROUP_HORIZONTAL)
                    aRet.Width() = std::max(aRet.Width(), aOtherSize.Width());
                if (eMode == VCL_SIZE_GROUP_BOTH || eMode == VCL_SIZE_GROUP_VERTICAL)