include/sfx2/objsh.hxx | 8 +++ sfx2/source/appl/sfxpicklist.cxx | 5 -- sfx2/source/doc/objcont.cxx | 83 +++++++++++++++++++++++++++++++-------- sfx2/source/doc/sfxbasemodel.cxx | 2 4 files changed, 77 insertions(+), 21 deletions(-)
New commits: commit 59cca1a28df4cdc94450d68cc1e247a8fb5ff6f3 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Oct 9 13:21:34 2020 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Oct 12 15:13:17 2020 +0200 render document thumbnail directly to bitmap, without metafile I don't see the point of taking the detour via GDIMetaFile and then immediately drawing using it to a bitmap. Simply draw directly to a bitmap. Especially given that when drawing to a metafile some fast cases are skipped, e.g. DrawTransformedBitmapEx() avoids DrawTransformBitmapExDirect() and resorts to using the slow BitmapEx::getTransformed(). E.g. with tdf#136223. this makes SfxPickListImpl::AddDocumentToPickList() go from 30% to 13% of the total document loading time. Change-Id: Ib1643eddfc2b75a3d7be60138fb5226352805826 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104114 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx index 78a1f3eb22e6..e106d7f3a367 100644 --- a/include/sfx2/objsh.hxx +++ b/include/sfx2/objsh.hxx @@ -26,6 +26,7 @@ #include <vcl/errcode.hxx> #include <com/sun/star/uno/Reference.h> #include <com/sun/star/uno/Sequence.hxx> +#include <vcl/bitmapex.hxx> #include <svl/poolitem.hxx> #include <sot/formats.hxx> @@ -64,6 +65,7 @@ class Color; class Fraction; class SvGlobalName; class InfobarData; +class VirtualDevice; enum class SfxModelFlags; enum class SfxEventHintId; @@ -445,6 +447,10 @@ public: Size GetFirstPageSize() const; bool DoClose(); std::shared_ptr<GDIMetaFile> GetPreviewMetaFile( bool bFullContent = false ) const; + BitmapEx GetPreviewBitmap( + bool bFullContent = false, + BmpConversion nColorConversion = BmpConversion::N24Bit, + BmpScaleFlag nScaleFlag = BmpScaleFlag::BestQuality) const; virtual void CancelTransfers(); bool GenerateAndStoreThumbnail( @@ -681,7 +687,7 @@ public: bool bShowCloseButton = true); std::vector<InfobarData>& getPendingInfobars(); - SAL_DLLPRIVATE std::shared_ptr<GDIMetaFile> CreatePreviewMetaFile_Impl(bool bFullContent) const; + SAL_DLLPRIVATE bool CreatePreview_Impl(bool bFullContent, VirtualDevice* pDevice, GDIMetaFile* pFile) const; SAL_DLLPRIVATE static bool IsPackageStorageFormat_Impl(const SfxMedium &); diff --git a/sfx2/source/appl/sfxpicklist.cxx b/sfx2/source/appl/sfxpicklist.cxx index ec32dd038d3d..82775fd9a328 100644 --- a/sfx2/source/appl/sfxpicklist.cxx +++ b/sfx2/source/appl/sfxpicklist.cxx @@ -118,9 +118,8 @@ void SfxPickListImpl::AddDocumentToPickList( const SfxObjectShell* pDocSh ) } else { - std::shared_ptr<GDIMetaFile> xMetaFile = pDocSh->GetPreviewMetaFile(); - BitmapEx aResultBitmap; - if (xMetaFile->CreateThumbnail(aResultBitmap)) + BitmapEx aResultBitmap = pDocSh->GetPreviewBitmap(); + if (!aResultBitmap.IsEmpty()) { SvMemoryStream aStream(65535, 65535); vcl::PNGWriter aWriter(aResultBitmap); diff --git a/sfx2/source/doc/objcont.cxx b/sfx2/source/doc/objcont.cxx index 0a98bab1263d..3159f6d7ac84 100644 --- a/sfx2/source/doc/objcont.cxx +++ b/sfx2/source/doc/objcont.cxx @@ -35,6 +35,7 @@ #include <unotools/securityoptions.hxx> #include <tools/datetime.hxx> #include <tools/diagnose_ex.h> +#include <tools/helpers.hxx> #include <rtl/uri.hxx> #include <unotools/useroptions.hxx> @@ -94,11 +95,32 @@ bool operator> (const util::DateTime& i_rLeft, const util::DateTime& i_rRight) std::shared_ptr<GDIMetaFile> SfxObjectShell::GetPreviewMetaFile( bool bFullContent ) const { - return CreatePreviewMetaFile_Impl( bFullContent ); + auto xFile = std::make_shared<GDIMetaFile>(); + ScopedVclPtrInstance< VirtualDevice > pDevice; + pDevice->EnableOutput( false ); + if(!CreatePreview_Impl(bFullContent, pDevice, xFile.get())) + return std::shared_ptr<GDIMetaFile>(); + return xFile; } -std::shared_ptr<GDIMetaFile> -SfxObjectShell::CreatePreviewMetaFile_Impl( bool bFullContent ) const +BitmapEx SfxObjectShell::GetPreviewBitmap( bool bFullContent, BmpConversion nColorConversion, + BmpScaleFlag nScaleFlag) const +{ + ScopedVclPtrInstance< VirtualDevice > pDevice; + pDevice->SetAntialiasing(AntialiasingFlags::Enable | pDevice->GetAntialiasing()); + if(!CreatePreview_Impl(bFullContent, pDevice, nullptr)) + return BitmapEx(); + Size size = pDevice->GetOutputSizePixel(); + BitmapEx aBitmap = pDevice->GetBitmapEx( Point(), size); + // Scale down the image to the desired size from the 4*size from CreatePreview_Impl(). + size = Size( size.Width() / 4, size.Height() / 4 ); + aBitmap.Scale(size, nScaleFlag); + if (!aBitmap.IsEmpty()) + aBitmap.Convert(nColorConversion); + return aBitmap; +} + +bool SfxObjectShell::CreatePreview_Impl( bool bFullContent, VirtualDevice* pDevice, GDIMetaFile* pFile) const { // DoDraw can only be called when no printing is done, otherwise // the printer may be turned off @@ -106,17 +128,9 @@ SfxObjectShell::CreatePreviewMetaFile_Impl( bool bFullContent ) const if ( pFrame && pFrame->GetViewShell() && pFrame->GetViewShell()->GetPrinter() && pFrame->GetViewShell()->GetPrinter()->IsPrinting() ) - return std::shared_ptr<GDIMetaFile>(); - - auto xFile = std::make_shared<GDIMetaFile>(); - - ScopedVclPtrInstance< VirtualDevice > pDevice; - pDevice->EnableOutput( false ); + return false; MapMode aMode( GetMapUnit() ); - pDevice->SetMapMode( aMode ); - xFile->SetPrefMapMode( aMode ); - Size aTmpSize; sal_Int8 nAspect; if ( bFullContent ) @@ -130,11 +144,47 @@ SfxObjectShell::CreatePreviewMetaFile_Impl( bool bFullContent ) const aTmpSize = GetFirstPageSize(); } - xFile->SetPrefSize( aTmpSize ); DBG_ASSERT( !aTmpSize.IsEmpty(), "size of first page is 0, override GetFirstPageSize or set visible-area!" ); - xFile->Record( pDevice ); + if(pFile) + { + pDevice->SetMapMode( aMode ); + pFile->SetPrefMapMode( aMode ); + pFile->SetPrefSize( aTmpSize ); + pFile->Record( pDevice ); + } + else + { + // Use pixel size, that's also what DoDraw() requires in this case, + // despite the metafile case (needlessly?) setting mapmode. + Size aSizePix = pDevice->LogicToPixel( aTmpSize, aMode ); + // Code based on GDIMetaFile::CreateThumbnail(). + sal_uInt32 nMaximumExtent = 256; + // determine size that has the same aspect ratio as image size and + // fits into the rectangle determined by nMaximumExtent + if ( aSizePix.Width() && aSizePix.Height() + && ( sal::static_int_cast< unsigned long >(aSizePix.Width()) > + nMaximumExtent || + sal::static_int_cast< unsigned long >(aSizePix.Height()) > + nMaximumExtent ) ) + { + double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height(); + if ( fWH <= 1.0 ) + { + aSizePix.setWidth( FRound( nMaximumExtent * fWH ) ); + aSizePix.setHeight( nMaximumExtent ); + } + else + { + aSizePix.setWidth( nMaximumExtent ); + aSizePix.setHeight( FRound( nMaximumExtent / fWH ) ); + } + } + // do it 4x larger to be able to scale it down & get beautiful antialias + aTmpSize = Size( aSizePix.Width() * 4, aSizePix.Height() * 4 ); + pDevice->SetOutputSizePixel( aTmpSize ); + } LanguageType eLang; SvtCTLOptions aCTLOptions; @@ -149,9 +199,10 @@ SfxObjectShell::CreatePreviewMetaFile_Impl( bool bFullContent ) const const_cast<SfxObjectShell*>(this)->DoDraw( pDevice, Point(0,0), aTmpSize, JobSetup(), nAspect ); - xFile->Stop(); + if(pFile) + pFile->Stop(); - return xFile; + return true; } diff --git a/sfx2/source/doc/sfxbasemodel.cxx b/sfx2/source/doc/sfxbasemodel.cxx index d1390a74bc6a..dcd5fd6a6aaa 100644 --- a/sfx2/source/doc/sfxbasemodel.cxx +++ b/sfx2/source/doc/sfxbasemodel.cxx @@ -2042,7 +2042,7 @@ Any SAL_CALL SfxBaseModel::getTransferData( const datatransfer::DataFlavor& aFla throw datatransfer::UnsupportedFlavorException(); std::shared_ptr<GDIMetaFile> xMetaFile = - m_pData->m_pObjectShell->CreatePreviewMetaFile_Impl( true ); + m_pData->m_pObjectShell->GetPreviewMetaFile( true ); if (xMetaFile) { _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits