tdf#151898 if svgs are used in hidpi get a high quality GtkImage
this gets nice sidebar icons in this case
as far as I can see only gtk_image_new_from_file (or
gtk_image_new_from_resource) can support the use of a scaleable input
format to create a hidpi GtkImage, rather than an upscaled lodpi one so
forced to go via a file here
Change-Id: I665cd5be2c87f6fe8e264640be228263cdfc1fba
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142504
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
(cherry picked from commit 397f5daa850e59f0f4d3881cb99d110b50e34e3d)
and...
Related: tdf#151898 use more of the code path that can use scaled svgs
for hidpi
Change-Id: I1dfb072e294fd30ce027eb3c69781f1450709dc8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142540
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
(cherry picked from commit 758163bf5a754160e692dfff511f0a8a750b6bba)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142597
Reviewed-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
diff --git a/include/vcl/ImageTree.hxx b/include/vcl/ImageTree.hxx
index 85f05d7..4de20d7 100644
--- a/include/vcl/ImageTree.hxx
+++ b/include/vcl/ImageTree.hxx
@@ -43,6 +43,10 @@ namespace com::sun::star::container {
class XNameAccess;
}
namespace com::sun::star::io {
class XInputStream;
}
class ImplImageTree;
class BitmapEx;
class SvMemoryStream;
@@ -63,6 +67,9 @@ public:
VCL_DLLPUBLIC std::shared_ptr<SvMemoryStream> getImageStream(
OUString const & rName, OUString const & rStyle, OUString const & rLang);
VCL_DLLPUBLIC css::uno::Reference<css::io::XInputStream> getImageXInputStream(OUString const & rName,
OUString const & rStyle, OUString const & rLang);
VCL_DLLPUBLIC bool loadImage(
OUString const & name, OUString const & style,
BitmapEx & bitmap, bool localized,
diff --git a/vcl/inc/implimagetree.hxx b/vcl/inc/implimagetree.hxx
index e3389f7..79cde54 100644
--- a/vcl/inc/implimagetree.hxx
+++ b/vcl/inc/implimagetree.hxx
@@ -37,6 +37,10 @@ namespace com::sun::star::container {
class XNameAccess;
}
namespace com::sun::star::io {
class XInputStream;
}
struct ImageRequestParameters
{
OUString msName;
@@ -71,6 +75,9 @@ public:
OUString getImageUrl(
OUString const & name, OUString const & style, OUString const & lang);
css::uno::Reference<css::io::XInputStream> getImageXInputStream(OUString const & rName,
OUString const & rStyle, OUString const & rLang);
std::shared_ptr<SvMemoryStream> getImageStream(
OUString const & rName, OUString const & rStyle, OUString const & rLang);
diff --git a/vcl/source/image/ImageTree.cxx b/vcl/source/image/ImageTree.cxx
index 83e2962..fdc47cb 100644
--- a/vcl/source/image/ImageTree.cxx
+++ b/vcl/source/image/ImageTree.cxx
@@ -34,6 +34,11 @@ std::shared_ptr<SvMemoryStream> ImageTree::getImageStream(OUString const & rName
return mpImplImageTree->getImageStream(rName, rStyle, rLang);
}
css::uno::Reference<css::io::XInputStream> ImageTree::getImageXInputStream(OUString const & rName, OUString const & rStyle, OUString const & rLang)
{
return mpImplImageTree->getImageXInputStream(rName, rStyle, rLang);
}
bool ImageTree::loadImage(OUString const & rName, OUString const & rStyle,
BitmapEx & rBitmap, bool bLocalized,
sal_Int32 nScalePercentage,
diff --git a/vcl/source/image/ImplImageTree.cxx b/vcl/source/image/ImplImageTree.cxx
index 5f2d1e9..36ac5f4 100644
--- a/vcl/source/image/ImplImageTree.cxx
+++ b/vcl/source/image/ImplImageTree.cxx
@@ -274,7 +274,7 @@ OUString ImplImageTree::getImageUrl(OUString const & rName, OUString const & rSt
return OUString();
}
std::shared_ptr<SvMemoryStream> ImplImageTree::getImageStream(OUString const & rName, OUString const & rStyle, OUString const & rLang)
uno::Reference<io::XInputStream> ImplImageTree::getImageXInputStream(OUString const & rName, OUString const & rStyle, OUString const & rLang)
{
OUString aStyle(rStyle);
@@ -299,7 +299,7 @@ std::shared_ptr<SvMemoryStream> ImplImageTree::getImageStream(OUString const & r
bool ok = rNameAccess->getByName(rPath) >>= aStream;
assert(ok);
(void)ok; // prevent unused warning in release build
return wrapStream(aStream);
return aStream;
}
}
}
@@ -311,6 +311,14 @@ std::shared_ptr<SvMemoryStream> ImplImageTree::getImageStream(OUString const & r
aStyle = fallbackStyle(aStyle);
}
return nullptr;
}
std::shared_ptr<SvMemoryStream> ImplImageTree::getImageStream(OUString const & rName, OUString const & rStyle, OUString const & rLang)
{
uno::Reference<io::XInputStream> xStream = getImageXInputStream(rName, rStyle, rLang);
if (xStream)
return wrapStream(xStream);
return std::shared_ptr<SvMemoryStream>();
}
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 13c0a25..9995d85 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -60,6 +60,7 @@
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/io/XInputStream.hpp>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/propertyvalue.hxx>
@@ -78,6 +79,7 @@
#include <tools/fract.hxx>
#include <tools/stream.hxx>
#include <unotools/resmgr.hxx>
#include <unotools/tempfile.hxx>
#include <unx/gstsink.hxx>
#include <vcl/ImageTree.hxx>
#include <vcl/abstdlg.hxx>
@@ -4780,13 +4782,49 @@ namespace
return pixbuf;
}
std::shared_ptr<SvMemoryStream> get_icon_stream_by_name_theme_lang(const OUString& rIconName, const OUString& rIconTheme, const OUString& rUILang)
{
return ImageTree::get().getImageStream(rIconName, rIconTheme, rUILang);
}
GdkPixbuf* load_icon_by_name_theme_lang(const OUString& rIconName, const OUString& rIconTheme, const OUString& rUILang)
{
auto xMemStm = ImageTree::get().getImageStream(rIconName, rIconTheme, rUILang);
auto xMemStm = get_icon_stream_by_name_theme_lang(rIconName, rIconTheme, rUILang);
if (!xMemStm)
return nullptr;
return load_icon_from_stream(*xMemStm);
}
std::unique_ptr<utl::TempFile> get_icon_stream_as_file_by_name_theme_lang(const OUString& rIconName, const OUString& rIconTheme, const OUString& rUILang)
{
uno::Reference<io::XInputStream> xInputStream = ImageTree::get().getImageXInputStream(rIconName, rIconTheme, rUILang);
if (!xInputStream)
return nullptr;
std::unique_ptr<utl::TempFile> xRet(new utl::TempFile);
xRet->EnableKillingFile(true);
SvStream* pStream = xRet->GetStream(StreamMode::WRITE);
for (;;)
{
const sal_Int32 nSize(2048);
uno::Sequence<sal_Int8> aData(nSize);
sal_Int32 nRead = xInputStream->readBytes(aData, nSize);
pStream->WriteBytes(aData.getConstArray(), nRead);
if (nRead < nSize)
break;
}
xRet->CloseStream();
return xRet;
}
std::unique_ptr<utl::TempFile> get_icon_stream_as_file(const OUString& rIconName)
{
OUString sIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme();
OUString sUILang = Application::GetSettings().GetUILanguageTag().getBcp47();
return get_icon_stream_as_file_by_name_theme_lang(rIconName, sIconTheme, sUILang);
}
}
GdkPixbuf* load_icon_by_name(const OUString& rIconName)
@@ -4818,6 +4856,31 @@ namespace
return load_icon_from_stream(aMemStm);
}
// tdf#151898 as far as I can see only gtk_image_new_from_file (or gtk_image_new_from_resource) can support the use of a
// scaleable input format to create a hidpi GtkImage, rather than an upscaled lodpi one so forced to go via a file here
std::unique_ptr<utl::TempFile> getImageFile(const css::uno::Reference<css::graphic::XGraphic>& rImage)
{
Image aImage(rImage);
OUString sStock(aImage.GetStock());
if (!sStock.isEmpty())
return get_icon_stream_as_file(sStock);
std::unique_ptr<utl::TempFile> xRet(new utl::TempFile);
xRet->EnableKillingFile(true);
SvStream* pStream = xRet->GetStream(StreamMode::WRITE);
// We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed.
css::uno::Sequence<css::beans::PropertyValue> aFilterData{ comphelper::makePropertyValue(
"Compression", sal_Int32(1)) };
auto aBitmapEx = aImage.GetBitmapEx();
vcl::PNGWriter aWriter(aBitmapEx, &aFilterData);
aWriter.Write(*pStream);
xRet->CloseStream();
return xRet;
}
GdkPixbuf* getPixbuf(const VirtualDevice& rDevice)
{
Size aSize(rDevice.GetOutputSizePixel());
@@ -4967,13 +5030,44 @@ namespace
}
#endif
GtkWidget* image_new_from_xgraphic(const css::uno::Reference<css::graphic::XGraphic>& rIcon)
{
GtkWidget* pImage = nullptr;
if (auto xTempFile = getImageFile(rIcon))
pImage = gtk_image_new_from_file(OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
return pImage;
}
GtkWidget* image_new_from_icon_name(const OUString& rIconName)
{
GtkWidget* pImage = nullptr;
if (auto xTempFile = get_icon_stream_as_file(rIconName))
pImage = gtk_image_new_from_file(OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
return pImage;
}
GtkWidget* image_new_from_icon_name_theme_lang(const OUString& rIconName, const OUString& rIconTheme, const OUString& rUILang)
{
GtkWidget* pImage = nullptr;
if (auto xTempFile = get_icon_stream_as_file_by_name_theme_lang(rIconName, rIconTheme, rUILang))
pImage = gtk_image_new_from_file(OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
return pImage;
}
void image_set_from_icon_name(GtkImage* pImage, const OUString& rIconName)
{
GdkPixbuf* pixbuf = load_icon_by_name(rIconName);
gtk_image_set_from_pixbuf(pImage, pixbuf);
if (!pixbuf)
return;
g_object_unref(pixbuf);
if (auto xTempFile = get_icon_stream_as_file(rIconName))
gtk_image_set_from_file(pImage, OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
else
gtk_image_set_from_pixbuf(pImage, nullptr);
}
void image_set_from_icon_name_theme_lang(GtkImage* pImage, const OUString& rIconName, const OUString& rIconTheme, const OUString& rUILang)
{
if (auto xTempFile = get_icon_stream_as_file_by_name_theme_lang(rIconName, rIconTheme, rUILang))
gtk_image_set_from_file(pImage, OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
else
gtk_image_set_from_pixbuf(pImage, nullptr);
}
void image_set_from_virtual_device(GtkImage* pImage, const VirtualDevice* pDevice)
@@ -4987,19 +5081,27 @@ namespace
void image_set_from_xgraphic(GtkImage* pImage, const css::uno::Reference<css::graphic::XGraphic>& rImage)
{
GdkPixbuf* pixbuf = getPixbuf(rImage);
gtk_image_set_from_pixbuf(pImage, pixbuf);
if (pixbuf)
g_object_unref(pixbuf);
if (auto xTempFile = getImageFile(rImage))
gtk_image_set_from_file(pImage, OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
else
gtk_image_set_from_pixbuf(pImage, nullptr);
}
#if GTK_CHECK_VERSION(4, 0, 0)
void picture_set_from_icon_name(GtkPicture* pPicture, const OUString& rIconName)
{
GdkPixbuf* pixbuf = load_icon_by_name(rIconName);
gtk_picture_set_pixbuf(pPicture, pixbuf);
if (pixbuf)
g_object_unref(pixbuf);
if (auto xTempFile = get_icon_stream_as_file(rIconName))
gtk_picture_set_filename(pPicture, OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
else
gtk_picture_set_pixbuf(pPicture, nullptr);
}
void picture_set_from_icon_name_theme_lang(GtkPicture* pPicture, const OUString& rIconName, const OUString& rIconTheme, const OUString& rUILang)
{
if (auto xTempFile = get_icon_stream_as_file_by_name_theme_lang(rIconName, rIconTheme, rUILang))
gtk_picture_set_filename(pPicture, OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
else
gtk_picture_set_pixbuf(pPicture, nullptr);
}
void picture_set_from_virtual_device(GtkPicture* pPicture, const VirtualDevice* pDevice)
@@ -5012,10 +5114,10 @@ namespace
void picture_set_from_xgraphic(GtkPicture* pPicture, const css::uno::Reference<css::graphic::XGraphic>& rPicture)
{
GdkPixbuf* pixbuf = getPixbuf(rPicture);
gtk_picture_set_pixbuf(pPicture, pixbuf);
if (pixbuf)
g_object_unref(pixbuf);
if (auto xTempFile = getImageFile(rPicture, false))
gtk_picture_set_filename(pPicture, OUStringToOString(xTempFile->GetFileName(), osl_getThreadTextEncoding()).getStr());
else
gtk_picture_set_pixbuf(pPicture, nullptr);
}
#endif
@@ -5028,15 +5130,7 @@ namespace
return;
}
GdkPixbuf* pixbuf = load_icon_by_name(rIconName);
GtkWidget* pImage;
if (!pixbuf)
pImage = nullptr;
else
{
pImage = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
}
GtkWidget* pImage = image_new_from_icon_name(rIconName);
#if GTK_CHECK_VERSION(4, 0, 0)
gtk_button_set_child(pButton, pImage);
#else
@@ -5067,15 +5161,7 @@ namespace
return;
}
GdkPixbuf* pixbuf = getPixbuf(rImage);
GtkWidget* pImage;
if (!pixbuf)
pImage = nullptr;
else
{
pImage = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
}
GtkWidget* pImage = image_new_from_xgraphic(rImage);
#if GTK_CHECK_VERSION(4, 0, 0)
gtk_button_set_child(pButton, pImage);
#else
@@ -5351,14 +5437,7 @@ public:
#if !GTK_CHECK_VERSION(4, 0, 0)
GtkWidget* pImage = nullptr;
if (pIconName && !pIconName->isEmpty())
{
GdkPixbuf* pixbuf = load_icon_by_name(*pIconName);
if (!pixbuf)
{
pImage = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
}
}
pImage = image_new_from_icon_name(*pIconName);
else if (pImageSurface)
pImage = image_new_from_virtual_device(*pImageSurface);
@@ -11239,24 +11318,14 @@ public:
#if !GTK_CHECK_VERSION(4, 0, 0)
GtkWidget* pImage = nullptr;
if (pIconName)
{
if (GdkPixbuf* pixbuf = load_icon_by_name(*pIconName))
{
pImage = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
}
}
pImage = image_new_from_icon_name(*pIconName);
else if (pImageSurface)
{
pImage = image_new_from_virtual_device(*pImageSurface);
}
else if (rGraphic)
{
if (GdkPixbuf* pixbuf = getPixbuf(rGraphic))
{
pImage = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
}
pImage = image_new_from_xgraphic(rGraphic);
}
GtkWidget *pItem;
@@ -11609,15 +11678,9 @@ private:
static void set_item_image(GtkWidget* pItem, const css::uno::Reference<css::graphic::XGraphic>& rIcon)
#endif
{
GtkWidget* pImage = nullptr;
if (GdkPixbuf* pixbuf = getPixbuf(rIcon))
{
pImage = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
GtkWidget* pImage = image_new_from_xgraphic(rIcon);
if (pImage)
gtk_widget_show(pImage);
}
#if !GTK_CHECK_VERSION(4, 0, 0)
gtk_tool_button_set_icon_widget(pItem, pImage);
#else
@@ -11967,14 +12030,9 @@ public:
return;
#endif
GtkWidget* pImage = nullptr;
if (GdkPixbuf* pixbuf = getPixbuf(rIconName))
{
pImage = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
GtkWidget* pImage = image_new_from_icon_name(rIconName);
if (pImage)
gtk_widget_show(pImage);
}
#if !GTK_CHECK_VERSION(4, 0, 0)
gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(pItem), pImage);
@@ -22952,13 +23010,7 @@ private:
{
OUString aIconName(icon_name, strlen(icon_name), RTL_TEXTENCODING_UTF8);
if (!IsAllowedBuiltInIcon(aIconName))
{
if (GdkPixbuf* pixbuf = load_icon_by_name_theme_lang(aIconName, m_aIconTheme, m_aUILang))
{
gtk_image_set_from_pixbuf(pImage, pixbuf);
g_object_unref(pixbuf);
}
}
image_set_from_icon_name_theme_lang(pImage, aIconName, m_aIconTheme, m_aUILang);
}
}
#if GTK_CHECK_VERSION(4, 0, 0)
@@ -22972,11 +23024,7 @@ private:
g_free(icon_name);
assert(aIconName.startsWith("private:///graphicrepository/"));
aIconName.startsWith("private:///graphicrepository/", &aIconName);
if (GdkPixbuf* pixbuf = load_icon_by_name_theme_lang(aIconName, m_aIconTheme, m_aUILang))
{
gtk_picture_set_pixbuf(GTK_PICTURE(pWidget), pixbuf);
g_object_unref(pixbuf);
}
picture_set_from_icon_name_theme_lang(GTK_PICTURE(pWidget), aIconName, m_aIconTheme, m_aUILang);
}
}
#endif
@@ -22989,10 +23037,8 @@ private:
OUString aIconName(icon_name, strlen(icon_name), RTL_TEXTENCODING_UTF8);
if (!IsAllowedBuiltInIcon(aIconName))
{
if (GdkPixbuf* pixbuf = load_icon_by_name_theme_lang(aIconName, m_aIconTheme, m_aUILang))
if (GtkWidget* pImage = image_new_from_icon_name_theme_lang(aIconName, m_aIconTheme, m_aUILang))
{
GtkWidget* pImage = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
gtk_tool_button_set_icon_widget(pToolButton, pImage);
gtk_widget_show(pImage);
}
@@ -23015,12 +23061,10 @@ private:
OUString aIconName(icon_name, strlen(icon_name), RTL_TEXTENCODING_UTF8);
if (!IsAllowedBuiltInIcon(aIconName))
{
if (GdkPixbuf* pixbuf = load_icon_by_name_theme_lang(aIconName, m_aIconTheme, m_aUILang))
if (GtkWidget* pImage = image_new_from_icon_name_theme_lang(aIconName, m_aIconTheme, m_aUILang))
{
GtkWidget* pImage = gtk_image_new_from_pixbuf(pixbuf);
gtk_widget_set_halign(pImage, GTK_ALIGN_CENTER);
gtk_widget_set_valign(pImage, GTK_ALIGN_CENTER);
g_object_unref(pixbuf);
gtk_button_set_child(pButton, pImage);
gtk_widget_show(pImage);
}
@@ -23035,12 +23079,10 @@ private:
OUString aIconName(icon_name, strlen(icon_name), RTL_TEXTENCODING_UTF8);
if (!IsAllowedBuiltInIcon(aIconName))
{
if (GdkPixbuf* pixbuf = load_icon_by_name_theme_lang(aIconName, m_aIconTheme, m_aUILang))
if (GtkWidget* pImage = image_new_from_icon_name_theme_lang(aIconName, m_aIconTheme, m_aUILang))
{
GtkWidget* pImage = gtk_image_new_from_pixbuf(pixbuf);
gtk_widget_set_halign(pImage, GTK_ALIGN_CENTER);
gtk_widget_set_valign(pImage, GTK_ALIGN_CENTER);
g_object_unref(pixbuf);
// TODO after gtk 4.6 is released require that version and drop this
static auto menu_button_set_child = reinterpret_cast<void (*) (GtkMenuButton*, GtkWidget*)>(dlsym(nullptr, "gtk_menu_button_set_child"));
if (menu_button_set_child)