tdf#134065, tdf#147998: fix thumbnail generation code
This moves the code drawing thumbnails and overlay icons away from
RecentDocsView to RecentDocsViewItem, where the final size of the
thumbnail is defined, so that no scaling of pre-painted icon would
happen.
This also restores the SFX_FILE_THUMBNAIL_* to state before commit
d43c6fa220524a09c0b24cbb5bc03c4456cd2515, and introduces a new set
of SFX_FILE_OVERLAY_* to be used for the overlay icons. This fixes
the display when RecentDocsThumbnail is disabled.
Change-Id: I5eb4aed5325459ddec7e196300cf6c2f9ddf80b7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131610
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/sfx2/inc/bitmaps.hlst b/sfx2/inc/bitmaps.hlst
index c3fb205..af7f970 100644
--- a/sfx2/inc/bitmaps.hlst
+++ b/sfx2/inc/bitmaps.hlst
@@ -43,13 +43,23 @@ inline constexpr OUStringLiteral SFX_THUMBNAIL_TEXT = u"res/ott_96_8.png";
inline constexpr OUStringLiteral SFX_THUMBNAIL_SHEET = u"res/ots_96_8.png";
inline constexpr OUStringLiteral SFX_THUMBNAIL_PRESENTATION = u"res/otp_96_8.png";
inline constexpr OUStringLiteral SFX_THUMBNAIL_DRAWING = u"res/otg_96_8.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_TEXT = u"res/odt_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_SHEET = u"res/ods_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_PRESENTATION = u"res/odp_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_DRAWING = u"res/odg_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_DATABASE = u"res/odb_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_MATH = u"res/odf_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_DEFAULT = u"res/mainapp_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_TEXT = u"res/writer128.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_SHEET = u"res/calc128.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_PRESENTATION = u"res/impress128.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_DRAWING = u"res/draw128.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_DATABASE = u"res/base128.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_MATH = u"res/math128.png";
inline constexpr OUStringLiteral SFX_FILE_THUMBNAIL_DEFAULT = u"res/main128.png";
inline constexpr OUStringLiteral SFX_FILE_OVERLAY_TEXT = u"res/odt_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_OVERLAY_SHEET = u"res/ods_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_OVERLAY_PRESENTATION = u"res/odp_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_OVERLAY_DRAWING = u"res/odg_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_OVERLAY_DATABASE = u"res/odb_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_OVERLAY_MATH = u"res/odf_48_8.png";
inline constexpr OUStringLiteral SFX_FILE_OVERLAY_DEFAULT = u"res/mainapp_48_8.png";
inline constexpr OUStringLiteral SFX_THUMBNAIL_BASE_192 = u"res/base_thumbnail_192.png";
inline constexpr OUStringLiteral SFX_THUMBNAIL_BASE_256 = u"res/base_thumbnail_256.png";
diff --git a/sfx2/inc/recentdocsview.hxx b/sfx2/inc/recentdocsview.hxx
index 44cda47..28b1f77 100644
--- a/sfx2/inc/recentdocsview.hxx
+++ b/sfx2/inc/recentdocsview.hxx
@@ -17,6 +17,7 @@
#include <com/sun/star/util/URL.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
class INetURLObject;
struct ImplSVEvent;
namespace com::sun::star::frame { class XDispatch; }
@@ -62,10 +63,9 @@ public:
RecentDocsView(std::unique_ptr<weld::ScrolledWindow> xWindow, std::unique_ptr<weld::Menu> xMenu);
virtual ~RecentDocsView() override;
void insertItem(const OUString &rURL, const OUString &rTitle, const BitmapEx &rThumbnail, sal_uInt16 nId);
void insertItem(const OUString &rURL, const OUString &rTitle, const OUString& rThumbnail, sal_uInt16 nId);
static bool typeMatchesExtension(ApplicationType type, std::u16string_view rExt);
static BitmapEx getDefaultThumbnail(const OUString &rURL, bool bCheckEncrypted = true);
ApplicationType mnFileTypes;
@@ -91,7 +91,7 @@ private:
virtual void LoseFocus() override;
bool isAcceptedFile(const OUString &rURL) const;
bool isAcceptedFile(const INetURLObject& rURL) const;
DECL_LINK( ExecuteHdl_Impl, void*, void );
diff --git a/sfx2/source/control/recentdocsview.cxx b/sfx2/source/control/recentdocsview.cxx
index 0957cab..3c6110c 100644
--- a/sfx2/source/control/recentdocsview.cxx
+++ b/sfx2/source/control/recentdocsview.cxx
@@ -18,25 +18,16 @@
*/
#include <sal/log.hxx>
#include <comphelper/base64.hxx>
#include <recentdocsview.hxx>
#include <sfx2/sfxresid.hxx>
#include <tools/diagnose_ex.h>
#include <unotools/historyoptions.hxx>
#include <vcl/event.hxx>
#include <vcl/filter/PngImageReader.hxx>
#include <vcl/ptrstyle.hxx>
#include <vcl/svapp.hxx>
#include <tools/stream.hxx>
#include <tools/urlobj.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/embed/StorageFactory.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/XStorage.hpp>
#include <com/sun/star/frame/XDispatch.hpp>
#include <sfx2/strings.hrc>
#include <bitmaps.hlst>
#include <vcl/virdev.hxx>
#include "recentdocsviewitem.hxx"
#include <sfx2/app.hxx>
@@ -59,64 +50,11 @@ void SetMessageFont(vcl::RenderContext& rRenderContext)
rRenderContext.SetFont(aFont);
}
bool IsDocEncrypted(const OUString& rURL)
{
uno::Reference< uno::XComponentContext > xContext(::comphelper::getProcessComponentContext());
bool bIsEncrypted = false;
try
{
uno::Reference<lang::XSingleServiceFactory> xStorageFactory = embed::StorageFactory::create(xContext);
uno::Sequence<uno::Any> aArgs{ uno::Any(rURL), uno::Any(embed::ElementModes::READ) };
uno::Reference<embed::XStorage> xDocStorage (
xStorageFactory->createInstanceWithArguments(aArgs),
uno::UNO_QUERY);
uno::Reference< beans::XPropertySet > xStorageProps( xDocStorage, uno::UNO_QUERY );
if ( xStorageProps.is() )
{
try
{
xStorageProps->getPropertyValue("HasEncryptedEntries")
>>= bIsEncrypted;
} catch( uno::Exception& ) {}
}
}
catch (const uno::Exception&)
{
TOOLS_WARN_EXCEPTION("sfx",
"caught exception trying to find out if doc <" << rURL << "> is encrypted:");
}
return bIsEncrypted;
}
}
namespace sfx2
{
static std::map<ApplicationType,OUString> BitmapForExtension =
{
{ ApplicationType::TYPE_WRITER, SFX_FILE_THUMBNAIL_TEXT },
{ ApplicationType::TYPE_CALC, SFX_FILE_THUMBNAIL_SHEET },
{ ApplicationType::TYPE_IMPRESS, SFX_FILE_THUMBNAIL_PRESENTATION },
{ ApplicationType::TYPE_DRAW, SFX_FILE_THUMBNAIL_DRAWING },
{ ApplicationType::TYPE_DATABASE, SFX_FILE_THUMBNAIL_DATABASE },
{ ApplicationType::TYPE_MATH, SFX_FILE_THUMBNAIL_MATH }
};
static std::map<ApplicationType,OUString> EncryptedBitmapForExtension =
{
{ ApplicationType::TYPE_WRITER, BMP_128X128_WRITER_DOC },
{ ApplicationType::TYPE_CALC, BMP_128X128_CALC_DOC },
{ ApplicationType::TYPE_IMPRESS, BMP_128X128_IMPRESS_DOC },
{ ApplicationType::TYPE_DRAW, BMP_128X128_DRAW_DOC },
// FIXME: icon for encrypted db doc doesn't exist
{ ApplicationType::TYPE_DATABASE, BMP_128X128_CALC_DOC },
{ ApplicationType::TYPE_MATH, BMP_128X128_MATH_DOC }
};
constexpr tools::Long gnTextHeight = 30;
constexpr tools::Long gnItemPadding = 5;
@@ -193,10 +131,9 @@ bool RecentDocsView::typeMatchesExtension(ApplicationType type, std::u16string_v
return bRet;
}
bool RecentDocsView::isAcceptedFile(const OUString &rURL) const
bool RecentDocsView::isAcceptedFile(const INetURLObject& rURL) const
{
INetURLObject aUrl(rURL);
OUString aExt = aUrl.getExtension();
const OUString aExt = rURL.getExtension();
return (mnFileTypes & ApplicationType::TYPE_WRITER && typeMatchesExtension(ApplicationType::TYPE_WRITER, aExt)) ||
(mnFileTypes & ApplicationType::TYPE_CALC && typeMatchesExtension(ApplicationType::TYPE_CALC, aExt)) ||
(mnFileTypes & ApplicationType::TYPE_IMPRESS && typeMatchesExtension(ApplicationType::TYPE_IMPRESS, aExt)) ||
@@ -206,31 +143,7 @@ bool RecentDocsView::isAcceptedFile(const OUString &rURL) const
(mnFileTypes & ApplicationType::TYPE_OTHER && typeMatchesExtension(ApplicationType::TYPE_OTHER, aExt));
}
BitmapEx RecentDocsView::getDefaultThumbnail(const OUString &rURL, bool bCheckEncrypted)
{
BitmapEx aImg;
INetURLObject aUrl(rURL);
OUString aExt = aUrl.getExtension();
// tdf#131850: avoid reading the file to check if it's encrypted,
// if we only need its generic "module" thumbnail
const std::map<ApplicationType,OUString>& rWhichMap = bCheckEncrypted && IsDocEncrypted(rURL) ?
EncryptedBitmapForExtension : BitmapForExtension;
std::map<ApplicationType,OUString>::const_iterator mIt =
std::find_if( rWhichMap.begin(), rWhichMap.end(),
[aExt] ( const std::pair<ApplicationType,OUString>& aEntry )
{ return typeMatchesExtension( aEntry.first, aExt); } );
if (mIt != rWhichMap.end())
aImg = BitmapEx(mIt->second);
else
aImg = BitmapEx(SFX_FILE_THUMBNAIL_DEFAULT);
return aImg;
}
void RecentDocsView::insertItem(const OUString &rURL, const OUString &rTitle, const BitmapEx &rThumbnail, sal_uInt16 nId)
void RecentDocsView::insertItem(const OUString &rURL, const OUString &rTitle, const OUString& rThumbnail, sal_uInt16 nId)
{
AppendItem( std::make_unique<RecentDocsViewItem>(*this, rURL, rTitle, rThumbnail, nId, mnItemMaxSize) );
}
@@ -245,54 +158,15 @@ void RecentDocsView::Reload()
const SvtHistoryOptions::HistoryItem& rRecentEntry = aHistoryList[i];
OUString aURL = rRecentEntry.sURL;
OUString aTitle;
BitmapEx aThumbnail;
BitmapEx aModule;
const INetURLObject aURLObj(aURL);
//fdo#74834: only load thumbnail if the corresponding option is not disabled in the configuration
if (officecfg::Office::Common::History::RecentDocsThumbnail::get())
{
OUString aBase64 = rRecentEntry.sThumbnail;
if (!aBase64.isEmpty())
{
Sequence<sal_Int8> aDecoded;
comphelper::Base64::decode(aDecoded, aBase64);
if (!isAcceptedFile(aURLObj))
continue;
SvMemoryStream aStream(aDecoded.getArray(), aDecoded.getLength(), StreamMode::READ);
vcl::PngImageReader aReader(aStream);
aThumbnail = aReader.read();
} else
{
INetURLObject aUrl(aURL);
if (mnFileTypes & ApplicationType::TYPE_DATABASE && typeMatchesExtension(ApplicationType::TYPE_DATABASE, aUrl.getExtension()))
{
aThumbnail = BitmapEx(ThumbnailView::ItemHeight() > 192 ? SFX_THUMBNAIL_BASE_256 : SFX_THUMBNAIL_BASE_192);
}
}
}
//Remove extension from url's last segment and use it as title
const OUString aTitle = aURLObj.GetBase(); //DecodeMechanism::WithCharset
aModule = getDefaultThumbnail(aURL, false); // We don't need an "encrypted" icon here
if (!aModule.IsEmpty() && !aThumbnail.IsEmpty()) {
ScopedVclPtr<VirtualDevice> m_pVirDev(VclPtr<VirtualDevice>::Create());
Size aSize(aThumbnail.GetSizePixel());
m_pVirDev->SetOutputSizePixel(aSize);
m_pVirDev->DrawBitmapEx(Point(), aThumbnail);
m_pVirDev->DrawBitmapEx(Point(aSize.Width()-53,aSize.Height()-53), Size(48, 48), aModule);
aThumbnail = m_pVirDev->GetBitmapEx(Point(), aSize);
m_pVirDev.disposeAndClear();
}
if(!aURL.isEmpty())
{
INetURLObject aURLObj( aURL );
//Remove extension from url's last segment and use it as title
aTitle = aURLObj.GetBase(); //DecodeMechanism::WithCharset
}
if (isAcceptedFile(aURL))
{
insertItem(aURL, aTitle, aThumbnail, i+1);
}
insertItem(aURL, aTitle, rRecentEntry.sThumbnail, i+1);
}
CalculateItemPositions();
diff --git a/sfx2/source/control/recentdocsviewitem.cxx b/sfx2/source/control/recentdocsviewitem.cxx
index 5741f59..d58f1a4 100644
--- a/sfx2/source/control/recentdocsviewitem.cxx
+++ b/sfx2/source/control/recentdocsviewitem.cxx
@@ -7,9 +7,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/StorageFactory.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/util/URLTransformer.hpp>
#include <comphelper/base64.hxx>
#include <comphelper/propertyvalue.hxx>
#include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
@@ -17,10 +21,16 @@
#include <officecfg/Office/Common.hxx>
#include <recentdocsview.hxx>
#include <sfx2/templatelocalview.hxx>
#include <tools/diagnose_ex.h>
#include <tools/stream.hxx>
#include <tools/urlobj.hxx>
#include <unotools/historyoptions.hxx>
#include <vcl/event.hxx>
#include <vcl/filter/PngImageReader.hxx>
#include <vcl/ptrstyle.hxx>
#include <vcl/virdev.hxx>
#include <map>
#include <bitmaps.hlst>
#include "recentdocsviewitem.hxx"
@@ -31,8 +41,87 @@ using namespace com::sun::star::uno;
using namespace drawinglayer::primitive2d;
using namespace drawinglayer::processor2d;
namespace
{
bool IsDocEncrypted(const OUString& rURL)
{
bool bIsEncrypted = false;
try
{
auto xFactory = embed::StorageFactory::create(comphelper::getProcessComponentContext());
auto xStorage(xFactory->createInstanceWithArguments(
{ uno::Any(rURL), uno::Any(embed::ElementModes::READ) }));
if (uno::Reference<beans::XPropertySet> xStorageProps{ xStorage, uno::UNO_QUERY })
{
try
{
xStorageProps->getPropertyValue("HasEncryptedEntries") >>= bIsEncrypted;
}
catch (uno::Exception&)
{
}
}
}
catch (const uno::Exception&)
{
TOOLS_WARN_EXCEPTION("sfx", "caught exception trying to find out if doc <"
<< rURL << "> is encrypted:");
}
return bIsEncrypted;
}
using Ext2IconMap = std::map<sfx2::ApplicationType, OUString>;
BitmapEx Url2Icon(const OUString& rURL, const Ext2IconMap& rExtToIcon, const OUString& sDefault)
{
auto it = std::find_if(rExtToIcon.begin(), rExtToIcon.end(),
[aExt = INetURLObject(rURL).getExtension()](const auto& r)
{ return sfx2::RecentDocsView::typeMatchesExtension(r.first, aExt); });
return BitmapEx(it != rExtToIcon.end() ? it->second : sDefault);
};
BitmapEx getDefaultThumbnail(const OUString& rURL)
{
static const Ext2IconMap BitmapForExtension
= { { sfx2::ApplicationType::TYPE_WRITER, SFX_FILE_THUMBNAIL_TEXT },
{ sfx2::ApplicationType::TYPE_CALC, SFX_FILE_THUMBNAIL_SHEET },
{ sfx2::ApplicationType::TYPE_IMPRESS, SFX_FILE_THUMBNAIL_PRESENTATION },
{ sfx2::ApplicationType::TYPE_DRAW, SFX_FILE_THUMBNAIL_DRAWING },
{ sfx2::ApplicationType::TYPE_DATABASE, SFX_FILE_THUMBNAIL_DATABASE },
{ sfx2::ApplicationType::TYPE_MATH, SFX_FILE_THUMBNAIL_MATH } };
static const Ext2IconMap EncryptedBitmapForExtension
= { { sfx2::ApplicationType::TYPE_WRITER, BMP_128X128_WRITER_DOC },
{ sfx2::ApplicationType::TYPE_CALC, BMP_128X128_CALC_DOC },
{ sfx2::ApplicationType::TYPE_IMPRESS, BMP_128X128_IMPRESS_DOC },
{ sfx2::ApplicationType::TYPE_DRAW, BMP_128X128_DRAW_DOC },
// You can't save a database file with encryption -> no respective icon
{ sfx2::ApplicationType::TYPE_MATH, BMP_128X128_MATH_DOC } };
const std::map<sfx2::ApplicationType, OUString>& rWhichMap
= IsDocEncrypted(rURL) ? EncryptedBitmapForExtension : BitmapForExtension;
return Url2Icon(rURL, rWhichMap, SFX_FILE_THUMBNAIL_DEFAULT);
}
BitmapEx getModuleOverlay(const OUString& rURL)
{
static const Ext2IconMap OverlayBitmapForExtension
= { { sfx2::ApplicationType::TYPE_WRITER, SFX_FILE_OVERLAY_TEXT },
{ sfx2::ApplicationType::TYPE_CALC, SFX_FILE_OVERLAY_SHEET },
{ sfx2::ApplicationType::TYPE_IMPRESS, SFX_FILE_OVERLAY_PRESENTATION },
{ sfx2::ApplicationType::TYPE_DRAW, SFX_FILE_OVERLAY_DRAWING },
{ sfx2::ApplicationType::TYPE_DATABASE, SFX_FILE_OVERLAY_DATABASE },
{ sfx2::ApplicationType::TYPE_MATH, SFX_FILE_OVERLAY_MATH } };
return Url2Icon(rURL, OverlayBitmapForExtension, SFX_FILE_OVERLAY_DEFAULT);
}
};
RecentDocsViewItem::RecentDocsViewItem(sfx2::RecentDocsView &rView, const OUString &rURL,
const OUString &rTitle, const BitmapEx &rThumbnail, sal_uInt16 nId, tools::Long nThumbnailSize)
const OUString &rTitle, std::u16string_view sThumbnailBase64, sal_uInt16 nId, tools::Long nThumbnailSize)
: ThumbnailViewItem(rView, nId),
mrParentView(rView),
maURL(rURL),
@@ -51,16 +140,32 @@ RecentDocsViewItem::RecentDocsViewItem(sfx2::RecentDocsView &rView, const OUStri
if (aTitle.isEmpty())
aTitle = aURLObj.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
BitmapEx aThumbnail(rThumbnail);
BitmapEx aThumbnail;
//fdo#74834: only load thumbnail if the corresponding option is not disabled in the configuration
if (aThumbnail.IsEmpty() && aURLObj.GetProtocol() == INetProtocol::File &&
officecfg::Office::Common::History::RecentDocsThumbnail::get())
aThumbnail = ThumbnailView::readThumbnail(rURL);
if (officecfg::Office::Common::History::RecentDocsThumbnail::get())
{
if (!sThumbnailBase64.empty())
{
Sequence<sal_Int8> aDecoded;
comphelper::Base64::decode(aDecoded, sThumbnailBase64);
SvMemoryStream aStream(aDecoded.getArray(), aDecoded.getLength(), StreamMode::READ);
vcl::PngImageReader aReader(aStream);
aThumbnail = aReader.read();
}
else if (sfx2::RecentDocsView::typeMatchesExtension(sfx2::ApplicationType::TYPE_DATABASE,
aURLObj.getExtension()))
{
aThumbnail
= BitmapEx(nThumbnailSize > 192 ? SFX_THUMBNAIL_BASE_256 : SFX_THUMBNAIL_BASE_192);
}
}
if (aThumbnail.IsEmpty())
{
// Use the default thumbnail if we have nothing else
BitmapEx aExt(sfx2::RecentDocsView::getDefaultThumbnail(rURL));
// 1. Thumbnail absent: get the default thumbnail, checking for encryption.
BitmapEx aExt(getDefaultThumbnail(rURL));
Size aExtSize(aExt.GetSizePixel());
// attempt to make it appear as if it is on a piece of paper
@@ -98,9 +203,29 @@ RecentDocsViewItem::RecentDocsViewItem(sfx2::RecentDocsView &rView, const OUStri
::tools::Rectangle(Point(0, 0), aExtSize),
&aExt);
}
else
{
// 2. Thumbnail present: it's unencrypted document -> add a module overlay.
// Pre-scale the thumbnail to the final size before applying the overlay
aThumbnail = TemplateLocalView::scaleImg(aThumbnail, nThumbnailSize, nThumbnailSize);
BitmapEx aModule = getModuleOverlay(rURL);
if (!aModule.IsEmpty())
{
const Size aSize(aThumbnail.GetSizePixel());
const Size aOverlaySize(aModule.GetSizePixel());
ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create());
pVirDev->SetOutputSizePixel(aSize);
pVirDev->DrawBitmapEx(Point(), aThumbnail);
pVirDev->DrawBitmapEx(Point(aSize.Width() - aOverlaySize.Width() - 5,
aSize.Height() - aOverlaySize.Height() - 5),
aModule);
aThumbnail = pVirDev->GetBitmapEx(Point(), aSize);
}
}
maTitle = aTitle;
maPreview1 = TemplateLocalView::scaleImg(aThumbnail, nThumbnailSize, nThumbnailSize);
maPreview1 = aThumbnail;
}
::tools::Rectangle RecentDocsViewItem::updateHighlight(bool bVisible, const Point& rPoint)
diff --git a/sfx2/source/control/recentdocsviewitem.hxx b/sfx2/source/control/recentdocsviewitem.hxx
index 4d06d91..41225e6 100644
--- a/sfx2/source/control/recentdocsviewitem.hxx
+++ b/sfx2/source/control/recentdocsviewitem.hxx
@@ -21,7 +21,7 @@ class RecentDocsViewItem final : public ThumbnailViewItem
{
public:
RecentDocsViewItem(sfx2::RecentDocsView &rView, const OUString &rURL,
const OUString &rTitle, const BitmapEx& rThumbnail, sal_uInt16 nId, tools::Long nThumbnailSize);
const OUString &rTitle, std::u16string_view sThumbnailBase64, sal_uInt16 nId, tools::Long nThumbnailSize);
/** Updates own highlight status based on the aPoint position.
diff --git a/sfx2/source/control/templatelocalview.cxx b/sfx2/source/control/templatelocalview.cxx
index 45802f7..d3a355b 100644
--- a/sfx2/source/control/templatelocalview.cxx
+++ b/sfx2/source/control/templatelocalview.cxx
@@ -841,7 +841,7 @@ BitmapEx TemplateLocalView::scaleImg (const BitmapEx &rImg, tools::Long width, t
// make the picture fit the given width/height constraints
double nRatio = std::min(double(width)/double(aSize.Width()), double(height)/double(aSize.Height()));
aImg.Scale(Size(aSize.Width() * nRatio, aSize.Height() * nRatio));
aImg.Scale(nRatio, nRatio);
}
return aImg;