vcl/inc/printdlg.hxx | 6 - vcl/source/window/printdlg.cxx | 176 +++++++++++++++++++++++++++++------------ 2 files changed, 129 insertions(+), 53 deletions(-)
New commits: commit f886ddd7764acf6f7d523ebec3905af86fbd4876 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Wed Apr 4 12:31:08 2018 +0200 PrintPreviewWindow dynamic preview Bitmap III Corrected condition for test if maximum is reached Change-Id: I24795dfa15093fe0f4eb71d94e18b9f0a33a6891 Reviewed-on: https://gerrit.libreoffice.org/52372 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Armin Le Grand <armin.le.gr...@cib.de> diff --git a/vcl/source/window/printdlg.cxx b/vcl/source/window/printdlg.cxx index bc7ef63434f2..4761ab68e8c2 100644 --- a/vcl/source/window/printdlg.cxx +++ b/vcl/source/window/printdlg.cxx @@ -331,7 +331,7 @@ void PrintDialog::PrintPreviewWindow::preparePreviewBitmap() const double fPreviewSizeSquare(static_cast<double>(maPreviewBitmap.GetSizePixel().getWidth() * maPreviewBitmap.GetSizePixel().getHeight())); // test as equal up to 0.1% (0.001) - if(fabs((fScaledSizeSquare / fPreviewSizeSquare) - 1.0) < 0.001) + if(fPreviewSizeSquare != 0.0 && fabs((fScaledSizeSquare / fPreviewSizeSquare) - 1.0) < 0.001) { // maximum is reached, avoid bigger scaling return; commit 5e4822f6f9a7c346c192fa1832344d8eb4a4ded5 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Mon Apr 2 15:44:45 2018 +0200 PrintPreviewWindow dynamic preview Bitmap II Added reset of PreviewBitmap when new/different Metafile gets set Change-Id: Ib8053c21fc868607adfff4f1a75f005d29ce356b diff --git a/vcl/source/window/printdlg.cxx b/vcl/source/window/printdlg.cxx index d7686e367625..bc7ef63434f2 100644 --- a/vcl/source/window/printdlg.cxx +++ b/vcl/source/window/printdlg.cxx @@ -243,6 +243,10 @@ void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile& i_rNewPrevi aBuf.appendAscii( eUnit == MAP_MM ? "mm" : "in" ); maVertDim->SetText( aBuf.makeStringAndClear() ); + // We have a new Metafile and evtl. a new page, so we need to reset + // the PreviewBitmap to force new creation + maPreviewBitmap = Bitmap(); + // sets/calculates e.g. maPreviewSize // also triggers preparePreviewBitmap() Resize(); commit 18c4dd445520c1a0dbae0d9118ff392373123843 Author: Armin Le Grand <armin.le.gr...@cib.de (CIB)> Date: Fri Mar 30 13:02:02 2018 +0200 PrintPreviewWindow dynamic preview Bitmap The PrintDialog includes a preview (PrintPreviewWindow) that currently used a fixed-pixel-size preview that takes the aspect ratio into account (which may already explode due to just growing vertically - try a much higher than wide page). It is not dynamic and by using the high-quality scale (BmpScaleFlag::BestQuality) for output it can get rather slow in repainting. Also holds the VDev for creating the preview all the time without need. Made that process dynamic and responding to real resizing, thus not using that huge number of pixels from the start. Also use a VDev only temporary and use intelligent size management. Still keeping the high-quality scale due to ::DrawBitmap with a target size not scaling well (still) and also ::DrawOutDev not good in quality. Those two should work better nowadays, but adaption would be risky. Change-Id: I211412a063def33a4e8f40c7442702770cd11a8e Reviewed-on: https://gerrit.libreoffice.org/52150 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Armin Le Grand <armin.le.gr...@cib.de> diff --git a/vcl/inc/printdlg.hxx b/vcl/inc/printdlg.hxx index be7641109f64..1017f509c78b 100644 --- a/vcl/inc/printdlg.hxx +++ b/vcl/inc/printdlg.hxx @@ -39,12 +39,11 @@ namespace vcl public: class PrintPreviewWindow : public vcl::Window { - static const sal_Int32 PREVIEW_BITMAP_WIDTH; - GDIMetaFile maMtf; Size maOrigSize; Size maPreviewSize; - VclPtr<VirtualDevice> maPageVDev; + sal_Int32 mnDPIX; + sal_Int32 mnDPIY; Bitmap maPreviewBitmap; OUString maReplacementString; OUString maToolTipString; @@ -62,7 +61,6 @@ namespace vcl virtual void Paint( vcl::RenderContext& rRenderContext, const Rectangle& rRect ) override; virtual void Command( const CommandEvent& ) override; virtual void Resize() override; - virtual void DataChanged( const DataChangedEvent& ) override; void setPreview( const GDIMetaFile&, const Size& i_rPaperSize, const OUString& i_rPaperName, diff --git a/vcl/source/window/printdlg.cxx b/vcl/source/window/printdlg.cxx index bf819aebf351..d7686e367625 100644 --- a/vcl/source/window/printdlg.cxx +++ b/vcl/source/window/printdlg.cxx @@ -66,16 +66,20 @@ VCL_BUILDER_DECL_FACTORY(ShowNupOrderWindow) PrintDialog::PrintPreviewWindow::PrintPreviewWindow( vcl::Window* i_pParent ) : Window( i_pParent, 0 ) + , maMtf() , maOrigSize( 10, 10 ) - , maPageVDev( VclPtr<VirtualDevice>::Create(*this) ) - , maToolTipString(VclResId( SV_PRINT_PRINTPREVIEW_TXT).toString()) + , maPreviewSize() + , mnDPIX(Application::GetDefaultDevice()->GetDPIX()) + , mnDPIY(Application::GetDefaultDevice()->GetDPIY()) + , maPreviewBitmap() + , maReplacementString() + , maToolTipString(VclResId( SV_PRINT_PRINTPREVIEW_TXT)) , mbGreyscale( false ) , maHorzDim(VclPtr<FixedLine>::Create(this, WB_HORZ | WB_CENTER)) , maVertDim(VclPtr<FixedLine>::Create(this, WB_VERT | WB_VCENTER)) { SetPaintTransparent( true ); SetBackground(); - maPageVDev->SetBackground( Color( COL_WHITE ) ); maHorzDim->Show(); maVertDim->Show(); @@ -92,22 +96,9 @@ void PrintDialog::PrintPreviewWindow::dispose() { maHorzDim.disposeAndClear(); maVertDim.disposeAndClear(); - maPageVDev.disposeAndClear(); Window::dispose(); } -const sal_Int32 PrintDialog::PrintPreviewWindow::PREVIEW_BITMAP_WIDTH = 1600; - -void PrintDialog::PrintPreviewWindow::DataChanged( const DataChangedEvent& i_rDCEvt ) -{ - // react on settings changed - if( i_rDCEvt.GetType() == DataChangedEventType::SETTINGS ) - { - maPageVDev->SetBackground( Color( COL_WHITE ) ); - } - Window::DataChanged( i_rDCEvt ); -} - void PrintDialog::PrintPreviewWindow::Resize() { Size aNewSize( GetSizePixel() ); @@ -141,19 +132,6 @@ void PrintDialog::PrintPreviewWindow::Resize() maPreviewSize = aScaledSize; - // #i104784# if we render the page too small then rounding issues result in - // layout artifacts looking really bad. So scale the page unto a device that is not - // full page size but not too small either. This also results in much better visual - // quality of the preview, e.g. when its height approaches the number of text lines - // find a good scaling factor - - double aAspectRatio = aScaledSize.Height() / (double) aScaledSize.Width(); - - aScaledSize.Width() = PREVIEW_BITMAP_WIDTH; - aScaledSize.Height() = PREVIEW_BITMAP_WIDTH * aAspectRatio; - - maPageVDev->SetOutputSizePixel( aScaledSize, false ); - // position dimension lines Point aRef( nTextHeight + (aNewSize.Width() - maPreviewSize.Width())/2, nTextHeight + (aNewSize.Height() - maPreviewSize.Height())/2 ); @@ -162,6 +140,8 @@ void PrintDialog::PrintPreviewWindow::Resize() maVertDim->SetPosSizePixel( Point( aRef.X() - nTextHeight, aRef.Y() ), Size( nTextHeight, maPreviewSize.Height() ) ); + // check and evtl. recreate preview bitmap + preparePreviewBitmap(); } void PrintDialog::PrintPreviewWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle&) @@ -186,6 +166,11 @@ void PrintDialog::PrintPreviewWindow::Paint(vcl::RenderContext& rRenderContext, else { Bitmap aPreviewBitmap(maPreviewBitmap); + + // This explicit force-to-scale allows us to get the + // mentioned best quality here. Unfortunately this is + // currently not sure when using just ::DrawBitmap with + // a defined size or ::DrawOutDev aPreviewBitmap.Scale(maPreviewSize, BmpScaleFlag::BestQuality); rRenderContext.DrawBitmap(aOffset, aPreviewBitmap); } @@ -224,12 +209,11 @@ void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile& i_rNewPrevi aBuf.append( maToolTipString ); SetQuickHelpText( aBuf.makeStringAndClear() ); maMtf = i_rNewPreview; - + mnDPIX = i_nDPIX; + mnDPIY = i_nDPIY; maOrigSize = i_rOrigSize; maReplacementString = i_rReplacement; mbGreyscale = i_bGreyscale; - maPageVDev->SetReferenceDevice( i_nDPIX, i_nDPIY ); - maPageVDev->EnableOutput(); // use correct measurements const LocaleDataWrapper& rLocWrap( GetSettings().GetLocaleDataWrapper() ); @@ -259,17 +243,107 @@ void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile& i_rNewPrevi aBuf.appendAscii( eUnit == MAP_MM ? "mm" : "in" ); maVertDim->SetText( aBuf.makeStringAndClear() ); + // sets/calculates e.g. maPreviewSize + // also triggers preparePreviewBitmap() Resize(); - preparePreviewBitmap(); + Invalidate(); } void PrintDialog::PrintPreviewWindow::preparePreviewBitmap() { + if(maPreviewSize.getWidth() < 0 || maPreviewSize.getHeight() < 0) + { + // not yet fully initialized, no need to prepare anything + return; + } + + // define an allowed number of pixels, also see + // defaults for primitive renderers and similar. This + // might be centralized and made dependent of 32/64bit + const sal_uInt32 nMaxSquarePixels(500000); + + // check how big (squarePixels) the preview is currently (with + // max value of MaxSquarePixels) + const sal_uInt32 nCurrentSquarePixels( + std::min( + nMaxSquarePixels, + static_cast<sal_uInt32>(maPreviewBitmap.GetSizePixel().getWidth()) + * static_cast<sal_uInt32>(maPreviewBitmap.GetSizePixel().getHeight()))); + + // check how big (squarePixels) the preview needs to be (with + // max value of MaxSquarePixels) + const sal_uInt32 nRequiredSquarePixels( + std::min( + nMaxSquarePixels, + static_cast<sal_uInt32>(maPreviewSize.getWidth()) + * static_cast<sal_uInt32>(maPreviewSize.getHeight()))); + + // check if preview is big enough. Use a scaling value in + // the comparison to not get bigger at the last possible moment + // what may look awkward and pixelated (again). This means + // to use a percentage value - if we have at least + // that value of required pixels, we are good. + static double fPreventAwkwardFactor(1.35); // 35% + if(nCurrentSquarePixels >= static_cast<sal_uInt32>(nRequiredSquarePixels * fPreventAwkwardFactor)) + { + // at this place we also could add a mechanism to let the preview + // bitmap 'shrink' again if it is currently 'too big' -> bigger + // than required. I think this is not necessary for now. + + // already sufficient, done. + return; + } + + // check if we have enough square pixels e.g for 8x8 pixels + if(nRequiredSquarePixels < 64) + { + // too small preview - let it empty + return; + } + + // Calculate nPlannedSquarePixels which is the required size + // expanded by a percentage (with max value of MaxSquarePixels) + static double fExtraSpaceFactor(1.65); // 65% + const sal_uInt32 nPlannedSquarePixels( + std::min( + nMaxSquarePixels, + static_cast<sal_uInt32>(maPreviewSize.getWidth() * fExtraSpaceFactor) + * static_cast<sal_uInt32>(maPreviewSize.getHeight() * fExtraSpaceFactor))); + + // calculate back new width and height - it might have been + // truncated by MaxSquarePixels. + // We know that w*h == nPlannedSquarePixels and w/h == ratio + const double fRatio(static_cast<double>(maPreviewSize.getWidth()) / static_cast<double>(maPreviewSize.getHeight())); + const double fNewWidth(sqrt(static_cast<double>(nPlannedSquarePixels) * fRatio)); + const double fNewHeight(sqrt(static_cast<double>(nPlannedSquarePixels) / fRatio)); + const Size aScaledSize(basegfx::fround(fNewWidth), basegfx::fround(fNewHeight)); + + // check if this eventual maximum is already reached + // due to having hit the MaxSquarePixels. Due to using + // an integer AspectRatio, we cannot make a numeric exact + // comparison - we need to compare if we are close + const double fScaledSizeSquare(static_cast<double>(aScaledSize.getWidth() * aScaledSize.getHeight())); + const double fPreviewSizeSquare(static_cast<double>(maPreviewBitmap.GetSizePixel().getWidth() * maPreviewBitmap.GetSizePixel().getHeight())); + + // test as equal up to 0.1% (0.001) + if(fabs((fScaledSizeSquare / fPreviewSizeSquare) - 1.0) < 0.001) + { + // maximum is reached, avoid bigger scaling + return; + } + + // create temporary VDev and render to it + ScopedVclPtrInstance<VirtualDevice> pPrerenderVDev(*Application::GetDefaultDevice()); + pPrerenderVDev->SetOutputSizePixel(aScaledSize, false); + pPrerenderVDev->SetReferenceDevice( mnDPIX, mnDPIY ); + pPrerenderVDev->EnableOutput(); + pPrerenderVDev->SetBackground( Wallpaper(COL_WHITE) ); + GDIMetaFile aMtf( maMtf ); - Size aVDevSize( maPageVDev->GetOutputSizePixel() ); - const Size aLogicSize( maPageVDev->PixelToLogic( aVDevSize, MapMode( MAP_100TH_MM ) ) ); + Size aVDevSize( pPrerenderVDev->GetOutputSizePixel() ); + const Size aLogicSize( pPrerenderVDev->PixelToLogic( aVDevSize, MapMode( MAP_100TH_MM ) ) ); Size aOrigSize( maOrigSize ); if( aOrigSize.Width() < 1 ) aOrigSize.Width() = aLogicSize.Width(); @@ -277,31 +351,31 @@ void PrintDialog::PrintPreviewWindow::preparePreviewBitmap() aOrigSize.Height() = aLogicSize.Height(); double fScale = double(aLogicSize.Width())/double(aOrigSize.Width()); - maPageVDev->Erase(); - maPageVDev->Push(); - maPageVDev->SetMapMode( MAP_100TH_MM ); - DrawModeFlags nOldDrawMode = maPageVDev->GetDrawMode(); + pPrerenderVDev->Erase(); + pPrerenderVDev->Push(); + pPrerenderVDev->SetMapMode(MapMode(MAP_100TH_MM)); + DrawModeFlags nOldDrawMode = pPrerenderVDev->GetDrawMode(); if( mbGreyscale ) - maPageVDev->SetDrawMode( maPageVDev->GetDrawMode() | + pPrerenderVDev->SetDrawMode( pPrerenderVDev->GetDrawMode() | ( DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient ) ); aMtf.WindStart(); aMtf.Scale( fScale, fScale ); aMtf.WindStart(); - const AntialiasingFlags nOriginalAA(maPageVDev->GetAntialiasing()); - maPageVDev->SetAntialiasing(nOriginalAA | AntialiasingFlags::EnableB2dDraw); - aMtf.Play( maPageVDev.get(), Point( 0, 0 ), aLogicSize ); - maPageVDev->SetAntialiasing(nOriginalAA); + const AntialiasingFlags nOriginalAA(pPrerenderVDev->GetAntialiasing()); + pPrerenderVDev->SetAntialiasing(nOriginalAA | AntialiasingFlags::EnableB2dDraw); + aMtf.Play( pPrerenderVDev.get(), Point( 0, 0 ), aLogicSize ); + pPrerenderVDev->SetAntialiasing(nOriginalAA); - maPageVDev->Pop(); + pPrerenderVDev->Pop(); - SetMapMode( MAP_PIXEL ); - maPageVDev->SetMapMode( MAP_PIXEL ); + SetMapMode(MAP_PIXEL); + pPrerenderVDev->SetMapMode(MAP_PIXEL); - maPreviewBitmap = Bitmap(maPageVDev->GetBitmap(Point(0, 0), aVDevSize)); + maPreviewBitmap = pPrerenderVDev->GetBitmap(Point(0, 0), aVDevSize); - maPageVDev->SetDrawMode( nOldDrawMode ); + pPrerenderVDev->SetDrawMode( nOldDrawMode ); } PrintDialog::ShowNupOrderWindow::ShowNupOrderWindow( vcl::Window* i_pParent ) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits