tdf#136094 Handle background color in drawNativeControl

Make gtk3's 'GtkSalGraphics::drawNativeControl'
take into account a control's background color,
if any is explicitly set:

Set background/fill color (in 'Edit::ApplySettings')
also for the case where the control is drawn "natively",
but don't draw the background in the generic 'Window::Erase'
method for the case of native drawing; instead handle it when
drawing the control itself.

This adds an additional parameter to pass the background color to the
relevant '{d,D}rawNativeControl' methods (defaulting to 'COL_AUTO')
and implements the required handling to apply the background color
for the gtk3 case.

qt5/kf5 will probably be handled in an upcoming commit as well.

Windows as well as the "gen" VCL plugin were not affected by the
issue, so remain unchanged and just ignore the new parameter.

In a quick test on on macOS, the rendering of the controls
in the sample doc was broken beyond just the missing background
colors (s. screenshot attached to tdf#136094); the behavior there
also remains unchanged by this patch, the new parameter is ignored
for now.

Change-Id: I01923a504fea2367ae96032104f09099e35f410e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101284
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Tested-by: Michael Weghorn <m.weghorn@posteo.de>
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index df9acf7..d3a1668 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1979,7 +1979,8 @@ public:
                                    const tools::Rectangle& rControlRegion,
                                    ControlState nState,
                                    const ImplControlValue& aValue,
                                    const OUString& aCaption );
                                    const OUString& aCaption,
                                    const Color& rBackgroundColor = COL_AUTO );

    /** Query the native control's actual drawing region (including adornment)
     */
diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx
index f937c9c..42febb1df 100644
--- a/include/vcl/window.hxx
+++ b/include/vcl/window.hxx
@@ -412,6 +412,7 @@ const char* ImplDbgCheckWindow( const void* pObj );
namespace vcl { class Window; }
namespace vcl { class Cursor; }
class Dialog;
class Edit;
class WindowImpl;
class PaintHelper;
class VclSizeGroup;
@@ -477,6 +478,7 @@ class VCL_DLLPUBLIC Window : public ::OutputDevice
    friend class ::SystemWindow;
    friend class ::WorkWindow;
    friend class ::Dialog;
    friend class ::Edit;
    friend class ::MessBox;
    friend class ::MessageDialog;
    friend class ::DockingWindow;
diff --git a/vcl/headless/CustomWidgetDraw.cxx b/vcl/headless/CustomWidgetDraw.cxx
index 6a1346a..5259b2a 100644
--- a/vcl/headless/CustomWidgetDraw.cxx
+++ b/vcl/headless/CustomWidgetDraw.cxx
@@ -70,7 +70,8 @@ bool CustomWidgetDraw::hitTestNativeControl(ControlType /*eType*/, ControlPart /
bool CustomWidgetDraw::drawNativeControl(ControlType eType, ControlPart ePart,
                                         const tools::Rectangle& rControlRegion,
                                         ControlState eState, const ImplControlValue& rValue,
                                         const OUString& /*aCaptions*/)
                                         const OUString& /*aCaptions*/,
                                         const Color& /*rBackgroundColor*/)
{
    if (!s_pWidgetImplementation)
        return false;
diff --git a/vcl/inc/FileDefinitionWidgetDraw.hxx b/vcl/inc/FileDefinitionWidgetDraw.hxx
index c69d3fb..68f5d34 100644
--- a/vcl/inc/FileDefinitionWidgetDraw.hxx
+++ b/vcl/inc/FileDefinitionWidgetDraw.hxx
@@ -42,7 +42,8 @@ public:

    bool drawNativeControl(ControlType eType, ControlPart ePart,
                           const tools::Rectangle& rBoundingControlRegion, ControlState eState,
                           const ImplControlValue& aValue, const OUString& aCaptions) override;
                           const ImplControlValue& aValue, const OUString& aCaptions,
                           const Color& rBackgroundColor) override;

    bool getNativeControlRegion(ControlType eType, ControlPart ePart,
                                const tools::Rectangle& rBoundingControlRegion, ControlState eState,
diff --git a/vcl/inc/WidgetDrawInterface.hxx b/vcl/inc/WidgetDrawInterface.hxx
index 2c88295..78d5d76 100644
--- a/vcl/inc/WidgetDrawInterface.hxx
+++ b/vcl/inc/WidgetDrawInterface.hxx
@@ -58,12 +58,13 @@ public:
     * @param [in] eState The general state of the control (enabled, focused, etc.).
     * @param [in] aValue Addition control specific information.
     * @param [in] aCaption  A caption or title string (like button text etc.).
     * @param [in] rBackgroundColor Background color for the control (may be COL_AUTO)
     * @return true, if the control could be drawn.
     */
    virtual inline bool drawNativeControl(ControlType eType, ControlPart ePart,
                                          const tools::Rectangle& rBoundingControlRegion,
                                          ControlState eState, const ImplControlValue& aValue,
                                          const OUString& aCaptions);
                                          const OUString& aCaptions, const Color& rBackgroundColor);

    /**
     * Get the native control regions for the control part.
@@ -103,7 +104,8 @@ bool WidgetDrawInterface::hitTestNativeControl(ControlType, ControlPart, const t
}

bool WidgetDrawInterface::drawNativeControl(ControlType, ControlPart, const tools::Rectangle&,
                                            ControlState, const ImplControlValue&, const OUString&)
                                            ControlState, const ImplControlValue&, const OUString&,
                                            const Color& /*rBackgroundColor*/)
{
    return false;
}
diff --git a/vcl/inc/headless/CustomWidgetDraw.hxx b/vcl/inc/headless/CustomWidgetDraw.hxx
index 1248aec..f30488c 100644
--- a/vcl/inc/headless/CustomWidgetDraw.hxx
+++ b/vcl/inc/headless/CustomWidgetDraw.hxx
@@ -37,7 +37,8 @@ public:

    bool drawNativeControl(ControlType eType, ControlPart ePart,
                           const tools::Rectangle& rBoundingControlRegion, ControlState eState,
                           const ImplControlValue& aValue, const OUString& aCaptions) override;
                           const ImplControlValue& aValue, const OUString& aCaptions,
                           const Color& rBackgroundColor) override;

    bool getNativeControlRegion(ControlType eType, ControlPart ePart,
                                const tools::Rectangle& rBoundingControlRegion, ControlState eState,
diff --git a/vcl/inc/qt5/Qt5Graphics_Controls.hxx b/vcl/inc/qt5/Qt5Graphics_Controls.hxx
index 04503c7..325e5c3 100644
--- a/vcl/inc/qt5/Qt5Graphics_Controls.hxx
+++ b/vcl/inc/qt5/Qt5Graphics_Controls.hxx
@@ -50,7 +50,8 @@ public:
                              bool& rIsInside) override;
    bool drawNativeControl(ControlType nType, ControlPart nPart,
                           const tools::Rectangle& rControlRegion, ControlState nState,
                           const ImplControlValue& aValue, const OUString& aCaption) override;
                           const ImplControlValue& aValue, const OUString& aCaption,
                           const Color& rBackgroundColor) override;
    bool getNativeControlRegion(ControlType nType, ControlPart nPart,
                                const tools::Rectangle& rControlRegion, ControlState nState,
                                const ImplControlValue& aValue, const OUString& aCaption,
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index 5e0222b..a5c74c1 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -303,7 +303,7 @@ protected:
                                                  const Point& aPos, bool& rIsInside ) override;
    virtual bool            drawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion,
                                               ControlState nState, const ImplControlValue& aValue,
                                               const OUString& aCaption ) override;
                                               const OUString& aCaption, const Color& rBackgroundColor ) override;
    virtual bool            getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState,
                                                    const ImplControlValue& aValue, const OUString& aCaption,
                                                    tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion ) override;
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index 6e772d2..d2b92c6 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -362,7 +362,8 @@ public:
                                    ControlState nState,
                                    const ImplControlValue& aValue,
                                    const OUString& aCaption,
                                    const OutputDevice *pOutDev );
                                    const OutputDevice *pOutDev,
                                    const Color& rBackgroundColor = COL_AUTO );

    /**
     * @see WidgetDrawInterface::getNativeControlRegion
diff --git a/vcl/inc/unx/gtk/gtkgdi.hxx b/vcl/inc/unx/gtk/gtkgdi.hxx
index 5e25976..430bab5 100644
--- a/vcl/inc/unx/gtk/gtkgdi.hxx
+++ b/vcl/inc/unx/gtk/gtkgdi.hxx
@@ -105,7 +105,8 @@ protected:
    virtual bool        drawNativeControl( ControlType nType, ControlPart nPart,
                                               const tools::Rectangle& rControlRegion,
                                               ControlState nState, const ImplControlValue& aValue,
                                               const OUString& rCaption ) override;
                                               const OUString& rCaption,
                                               const Color& rBackgroundColor ) override;
    virtual bool        getNativeControlRegion( ControlType nType, ControlPart nPart,
                                                    const tools::Rectangle& rControlRegion,
                                                    ControlState nState,
@@ -274,7 +275,7 @@ protected:
                                              const Point& aPos, bool& rIsInside ) override;
    virtual bool        drawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion,
                                           ControlState nState, const ImplControlValue& aValue,
                                           const OUString& rCaption ) override;
                                           const OUString& rCaption, const Color& rBackgroundColor ) override;
    virtual bool        getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState,
                                                const ImplControlValue& aValue, const OUString& rCaption,
                                                tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion ) override;
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 4d10291..5fe6645 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -283,7 +283,7 @@ protected:
                                              const Point& aPos, bool& rIsInside ) override;
    virtual bool        drawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion,
                                           ControlState nState, const ImplControlValue& aValue,
                                           const OUString& aCaption ) override;
                                           const OUString& aCaption, const Color& rBackgroundColor ) override;
    virtual bool        getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState,
                                                const ImplControlValue& aValue, const OUString& aCaption,
                                                tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion ) override;
diff --git a/vcl/osx/salnativewidgets.cxx b/vcl/osx/salnativewidgets.cxx
index 940fd41..e01470a 100644
--- a/vcl/osx/salnativewidgets.cxx
+++ b/vcl/osx/salnativewidgets.cxx
@@ -260,7 +260,8 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
                                        const tools::Rectangle &rControlRegion,
                                        ControlState nState,
                                        const ImplControlValue &aValue,
                                        const OUString &)
                                        const OUString &,
                                        const Color&)
{
    bool bOK = false;
    if (!CheckContext())
diff --git a/vcl/qt5/Qt5Graphics_Controls.cxx b/vcl/qt5/Qt5Graphics_Controls.cxx
index 6f54e6f..dce9c16 100644
--- a/vcl/qt5/Qt5Graphics_Controls.cxx
+++ b/vcl/qt5/Qt5Graphics_Controls.cxx
@@ -224,7 +224,8 @@ void Qt5Graphics_Controls::fullQStyleOptionTabWidgetFrame(QStyleOptionTabWidgetF
bool Qt5Graphics_Controls::drawNativeControl(ControlType type, ControlPart part,
                                             const tools::Rectangle& rControlRegion,
                                             ControlState nControlState,
                                             const ImplControlValue& value, const OUString&)
                                             const ImplControlValue& value, const OUString&,
                                             const Color& /*rBackgroundColor*/)
{
    bool nativeSupport = isNativeControlSupported(type, part);
    if (!nativeSupport)
diff --git a/vcl/source/control/edit.cxx b/vcl/source/control/edit.cxx
index 91ee92f..8d8bb1b 100644
--- a/vcl/source/control/edit.cxx
+++ b/vcl/source/control/edit.cxx
@@ -373,17 +373,23 @@ void Edit::ApplySettings(vcl::RenderContext& rRenderContext)
    Color aTextColor = rStyleSettings.GetFieldTextColor();
    ApplyControlForeground(rRenderContext, aTextColor);

    if (ImplUseNativeBorder(rRenderContext, GetStyle()))
    if (IsControlBackground())
    {
        rRenderContext.SetBackground(GetControlBackground());
        rRenderContext.SetFillColor(GetControlBackground());

        if (ImplUseNativeBorder(rRenderContext, GetStyle()))
        {
            // indicates that no non-native drawing of background should take place
            mpWindowImpl->mnNativeBackground = ControlPart::Entire;
        }
    }
    else if (ImplUseNativeBorder(rRenderContext, GetStyle()))
    {
        // Transparent background
        rRenderContext.SetBackground();
        rRenderContext.SetFillColor();
    }
    else if (IsControlBackground())
    {
        rRenderContext.SetBackground(GetControlBackground());
        rRenderContext.SetFillColor(GetControlBackground());
    }
    else
    {
        rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
diff --git a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx
index ba7cce2..82dbb49 100644
--- a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx
+++ b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx
@@ -540,7 +540,8 @@ bool FileDefinitionWidgetDraw::drawNativeControl(ControlType eType, ControlPart 
                                                 const tools::Rectangle& rControlRegion,
                                                 ControlState eState,
                                                 const ImplControlValue& rValue,
                                                 const OUString& /*aCaptions*/)
                                                 const OUString& /*aCaptions*/,
                                                 const Color& /*rBackgroundColor*/)
{
    bool bOldAA = m_rGraphics.getAntiAliasB2DDraw();
    m_rGraphics.setAntiAliasB2DDraw(true);
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
index 6875419..21844bf 100644
--- a/vcl/source/gdi/salgdilayout.cxx
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -759,7 +759,8 @@ void SalGraphics::mirror( ImplControlValue& rVal, const OutputDevice* pOutDev ) 

bool SalGraphics::DrawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion,
                                                ControlState nState, const ImplControlValue& aValue,
                                                const OUString& aCaption, const OutputDevice *pOutDev)
                                                const OUString& aCaption, const OutputDevice *pOutDev,
                                                const Color& rBackgroundColor)
{
    bool bRet = false;
    tools::Rectangle aControlRegion(rControlRegion);
@@ -771,10 +772,10 @@ bool SalGraphics::DrawNativeControl( ControlType nType, ControlPart nPart, const
        mirror(aControlRegion, pOutDev);
        std::unique_ptr< ImplControlValue > mirrorValue( aValue.clone());
        mirror( *mirrorValue, pOutDev );
        bRet = forWidget()->drawNativeControl(nType, nPart, aControlRegion, nState, *mirrorValue, aCaption);
        bRet = forWidget()->drawNativeControl(nType, nPart, aControlRegion, nState, *mirrorValue, aCaption, rBackgroundColor);
    }
    else
        bRet = forWidget()->drawNativeControl(nType, nPart, aControlRegion, nState, aValue, aCaption);
        bRet = forWidget()->drawNativeControl(nType, nPart, aControlRegion, nState, aValue, aCaption, rBackgroundColor);

    if (bRet && m_pWidgetDraw)
        handleDamage(aControlRegion);
diff --git a/vcl/source/outdev/nativecontrols.cxx b/vcl/source/outdev/nativecontrols.cxx
index 847cbeb..14ad647 100644
--- a/vcl/source/outdev/nativecontrols.cxx
+++ b/vcl/source/outdev/nativecontrols.cxx
@@ -289,7 +289,8 @@ bool OutputDevice::DrawNativeControl( ControlType nType,
                            const tools::Rectangle& rControlRegion,
                            ControlState nState,
                            const ImplControlValue& aValue,
                            const OUString& aCaption )
                            const OUString& aCaption,
                            const Color& rBackgroundColor )
{
    assert(!is_double_buffered_window());

@@ -315,7 +316,7 @@ bool OutputDevice::DrawNativeControl( ControlType nType,
    std::shared_ptr< ImplControlValue > aScreenCtrlValue( TransformControlValue( aValue, *this ) );
    tools::Rectangle screenRegion( ImplLogicToDevicePixel( rControlRegion ) );

    bool bRet = mpGraphics->DrawNativeControl(nType, nPart, screenRegion, nState, *aScreenCtrlValue, aCaption, this );
    bool bRet = mpGraphics->DrawNativeControl(nType, nPart, screenRegion, nState, *aScreenCtrlValue, aCaption, this, rBackgroundColor );

    return bRet;
}
diff --git a/vcl/source/window/brdwin.cxx b/vcl/source/window/brdwin.cxx
index 1d9d6cb..e59f258 100644
--- a/vcl/source/window/brdwin.cxx
+++ b/vcl/source/window/brdwin.cxx
@@ -701,7 +701,10 @@ void ImplSmallBorderWindowView::DrawWindow(vcl::RenderContext& rRenderContext, c
            aCtrlRegion=aContentRgn;
        }

        bNativeOK = rRenderContext.DrawNativeControl(aCtrlType, aCtrlPart, aCtrlRegion, nState, aControlValue, OUString());
        Color aBackgroundColor = COL_AUTO;
        if (pCtrl->IsControlBackground())
            aBackgroundColor = pCtrl->GetBackgroundColor();
        bNativeOK = rRenderContext.DrawNativeControl(aCtrlType, aCtrlPart, aCtrlRegion, nState, aControlValue, OUString(), aBackgroundColor);

        // if the native theme draws the spinbuttons in one call, make sure the proper settings
        // are passed, this might force a redraw though... (TODO: improve)
diff --git a/vcl/source/window/paint.cxx b/vcl/source/window/paint.cxx
index 670909e..80b2f85 100644
--- a/vcl/source/window/paint.cxx
+++ b/vcl/source/window/paint.cxx
@@ -1603,7 +1603,13 @@ void Window::Erase(vcl::RenderContext& rRenderContext)
    bool bNativeOK = false;

    ControlPart aCtrlPart = ImplGetWindowImpl()->mnNativeBackground;
    if (aCtrlPart != ControlPart::NONE && ! IsControlBackground())

    if (aCtrlPart == ControlPart::Entire && IsControlBackground())
    {
        // nothing to do here; background is drawn in corresponding drawNativeControl implementation
        bNativeOK = true;
    }
    else if (aCtrlPart != ControlPart::NONE && ! IsControlBackground())
    {
        tools::Rectangle aCtrlRegion(Point(), GetOutputSizePixel());
        ControlState nState = ControlState::NONE;
diff --git a/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx b/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx
index 465ce68..44d1ac9 100644
--- a/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx
+++ b/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx
@@ -2317,7 +2317,7 @@ void GtkSalGraphics::handleDamage(const tools::Rectangle& rDamagedRegion)

bool GtkSalGraphics::drawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion,
                                            ControlState nState, const ImplControlValue& rValue,
                                            const OUString&)
                                            const OUString&, const Color& rBackgroundColor)
{
    RenderType renderType = nPart == ControlPart::Focus ? RenderType::Focus : RenderType::BackgroundAndFrame;
    GtkStyleContext *context = nullptr;
@@ -2568,6 +2568,20 @@ bool GtkSalGraphics::drawNativeControl( ControlType nType, ControlPart nPart, co
        gtk_style_context_add_class(context, styleClass);
    }

    // apply background in style, if explicitly set
    // note: for more complex controls that use multiple styles for their elements,
    // background may have to be applied for more of those as well (s. case RenderType::Combobox below)
    GtkCssProvider* pBgCssProvider = nullptr;
    if (rBackgroundColor != COL_AUTO)
    {
        const OUString sColorCss = "* { background-color: #" + rBackgroundColor.AsRGBHexString() + "; }";
        const OString aResult = OUStringToOString(sColorCss, RTL_TEXTENCODING_UTF8);
        pBgCssProvider =  gtk_css_provider_new();
        gtk_css_provider_load_from_data(pBgCssProvider, aResult.getStr(), aResult.getLength(), nullptr);
        gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(pBgCssProvider),
                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    }

    switch(renderType)
    {
    case RenderType::Background:
@@ -2619,7 +2633,16 @@ bool GtkSalGraphics::drawNativeControl( ControlType nType, ControlPart nPart, co
        PaintSpinButton(flags, cr, rControlRegion, nPart, rValue);
        break;
    case RenderType::Combobox:
        if (pBgCssProvider)
        {
            gtk_style_context_add_provider(mpComboboxEntryStyle, GTK_STYLE_PROVIDER(pBgCssProvider),
                                           GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
        }
        PaintCombobox(flags, cr, rControlRegion, nType, nPart);
        if (pBgCssProvider)
        {
            gtk_style_context_remove_provider(mpComboboxEntryStyle, GTK_STYLE_PROVIDER(pBgCssProvider));
        }
        break;
    case RenderType::Icon:
        gtk_style_context_save (context);
@@ -2698,6 +2721,10 @@ bool GtkSalGraphics::drawNativeControl( ControlType nType, ControlPart nPart, co
    {
        gtk_style_context_remove_class(context, styleClass);
    }
    if (pBgCssProvider)
    {
        gtk_style_context_remove_provider(context, GTK_STYLE_PROVIDER(pBgCssProvider));
    }
    aContextState.restore();

    cairo_destroy(cr); // unref
diff --git a/vcl/win/gdi/salnativewidgets-luna.cxx b/vcl/win/gdi/salnativewidgets-luna.cxx
index f5ac28e..68a18b0 100644
--- a/vcl/win/gdi/salnativewidgets-luna.cxx
+++ b/vcl/win/gdi/salnativewidgets-luna.cxx
@@ -1154,7 +1154,8 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
                                        const tools::Rectangle& rControlRegion,
                                        ControlState nState,
                                        const ImplControlValue& aValue,
                                        const OUString& aCaption )
                                        const OUString& aCaption,
                                        const Color& /*rBackgroundColor*/ )
{
    bool bOk = false;
    HTHEME hTheme = nullptr;