diff options
author | Luboš Luňák <l.lunak@suse.cz> | 2012-06-22 13:57:39 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@suse.cz> | 2012-06-22 16:50:18 +0200 |
commit | 0c10b8ff9fa115ec2c315bd75a9eddc1cd4c0ac2 (patch) | |
tree | 7cd00463a87a473ce3595fbafb8fe3252c53e634 /svtools | |
parent | a83bf946d6e1f315a19ce6e6c9b5ddcb30926a22 (diff) |
make it possible to cache the resulting pixmap with a metafile
If the metafile contains just one single bitmap, the drawing code
optimizes by just using that one bitmap. It (=the resulting pixmap
after scaling etc.) however has not been cached so far, which means
smoothscaling (to be done) would be quite slow with every paint.
Change-Id: I30950c55fbadfddedc7df31283c66ed064b1a1a6
Diffstat (limited to 'svtools')
-rw-r--r-- | svtools/source/graphic/grfcache.cxx | 312 | ||||
-rw-r--r-- | svtools/source/graphic/grfmgr2.cxx | 4 |
2 files changed, 305 insertions, 11 deletions
diff --git a/svtools/source/graphic/grfcache.cxx b/svtools/source/graphic/grfcache.cxx index bfd9341d1374..bfb39e46178d 100644 --- a/svtools/source/graphic/grfcache.cxx +++ b/svtools/source/graphic/grfcache.cxx @@ -29,6 +29,7 @@ #include <salhelper/timer.hxx> #include <tools/debug.hxx> +#include <vcl/metaact.hxx> #include <vcl/outdev.hxx> #include <tools/poly.hxx> #include <rtl/strbuf.hxx> @@ -419,6 +420,8 @@ private: sal_uLong mnOutDevDrawMode; sal_uInt16 mnOutDevBitCount; + static bool IsCacheableAsBitmap( const GDIMetaFile& rMtf, OutputDevice* pOut, const Size& rSz ); + public: static sal_uLong GetNeededSize( OutputDevice* pOut, const Point& rPt, const Size& rSz, @@ -486,14 +489,305 @@ public: // ----------------------------------------------------------------------------- +// This whole function is based on checkMetadataBitmap() from grfmgr2.cxx, see that one for details. +// If you do changes here, change the original function too. +static void checkMetadataBitmap( const BitmapEx& rBmpEx, + Point /*rSrcPoint*/, + Size rSrcSize, + const Point& rDestPoint, + const Size& rDestSize, + const Size& rRefSize, + bool& o_rbNonBitmapActionEncountered ) +{ + if( rSrcSize == Size()) + rSrcSize = rBmpEx.GetSizePixel(); + + if( rDestPoint != Point( 0, 0 )) + { + o_rbNonBitmapActionEncountered = true; + return; + } + if( rDestSize != rRefSize ) + { if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100 + && abs( rDestSize.Width() - rRefSize.Width()) < 5 + && abs( rDestSize.Height() - rRefSize.Height()) < 5 ) + ; // ok, assume it's close enough + else + { // fall back to mtf rendering + o_rbNonBitmapActionEncountered = true; + return; + } + } +} + +// This function is based on GraphicManager::ImplCreateOutput(), in fact it mostly copies +// it, the difference is that this one does not create anything, it only checks if +// ImplCreateOutput() would use the optimization of using the single bitmap. +// If you do changes here, change the original function too. +bool GraphicDisplayCacheEntry::IsCacheableAsBitmap( const GDIMetaFile& rMtf, + OutputDevice* pOut, const Size& rSz ) +{ + const Size aNewSize( rMtf.GetPrefSize() ); + GDIMetaFile rOutMtf = rMtf; + + // Count bitmap actions, and flag actions that paint, but + // are no bitmaps. + sal_Int32 nNumBitmaps(0); + bool bNonBitmapActionEncountered(false); + if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() ) + { + const MapMode rPrefMapMode( rMtf.GetPrefMapMode() ); + const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) ); + + sal_uInt32 nCurPos; + MetaAction* pAct; + for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct; + pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ ) + { + switch( pAct->GetType() ) + { + case META_FONT_ACTION: + // FALLTHROUGH intended + case META_NULL_ACTION: + // FALLTHROUGH intended + + // OutDev state changes (which don't affect bitmap + // output) + case META_LINECOLOR_ACTION: + // FALLTHROUGH intended + case META_FILLCOLOR_ACTION: + // FALLTHROUGH intended + case META_TEXTCOLOR_ACTION: + // FALLTHROUGH intended + case META_TEXTFILLCOLOR_ACTION: + // FALLTHROUGH intended + case META_TEXTALIGN_ACTION: + // FALLTHROUGH intended + case META_TEXTLINECOLOR_ACTION: + // FALLTHROUGH intended + case META_TEXTLINE_ACTION: + // FALLTHROUGH intended + case META_PUSH_ACTION: + // FALLTHROUGH intended + case META_POP_ACTION: + // FALLTHROUGH intended + case META_LAYOUTMODE_ACTION: + // FALLTHROUGH intended + case META_TEXTLANGUAGE_ACTION: + // FALLTHROUGH intended + case META_COMMENT_ACTION: + break; + + // bitmap output methods + case META_BMP_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpAction* pAction = (MetaBmpAction*)pAct; + + checkMetadataBitmap( + BitmapEx( pAction->GetBitmap()), + Point(), Size(), + pOut->LogicToPixel( pAction->GetPoint(), + rPrefMapMode ), + pAction->GetBitmap().GetSizePixel(), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; + + case META_BMPSCALE_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct; + + checkMetadataBitmap( + BitmapEx( pAction->GetBitmap()), + Point(), Size(), + pOut->LogicToPixel( pAction->GetPoint(), + rPrefMapMode ), + pOut->LogicToPixel( pAction->GetSize(), + rPrefMapMode ), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; + + case META_BMPSCALEPART_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct; + + checkMetadataBitmap( BitmapEx( pAction->GetBitmap() ), + pAction->GetSrcPoint(), + pAction->GetSrcSize(), + pOut->LogicToPixel( pAction->GetDestPoint(), + rPrefMapMode ), + pOut->LogicToPixel( pAction->GetDestSize(), + rPrefMapMode ), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; + + case META_BMPEX_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpExAction* pAction = (MetaBmpExAction*)pAct; + + checkMetadataBitmap( + pAction->GetBitmapEx(), + Point(), Size(), + pOut->LogicToPixel( pAction->GetPoint(), + rPrefMapMode ), + pAction->GetBitmapEx().GetSizePixel(), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; + + case META_BMPEXSCALE_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct; + + checkMetadataBitmap( + pAction->GetBitmapEx(), + Point(), Size(), + pOut->LogicToPixel( pAction->GetPoint(), + rPrefMapMode ), + pOut->LogicToPixel( pAction->GetSize(), + rPrefMapMode ), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; + + case META_BMPEXSCALEPART_ACTION: + if( !nNumBitmaps && !bNonBitmapActionEncountered ) + { + MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct; + + checkMetadataBitmap( pAction->GetBitmapEx(), + pAction->GetSrcPoint(), + pAction->GetSrcSize(), + pOut->LogicToPixel( pAction->GetDestPoint(), + rPrefMapMode ), + pOut->LogicToPixel( pAction->GetDestSize(), + rPrefMapMode ), + rSizePix, + bNonBitmapActionEncountered ); + } + ++nNumBitmaps; + break; + + // these actions actually output something (that's + // different from a bitmap) + case META_RASTEROP_ACTION: + if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT ) + break; + // FALLTHROUGH intended + case META_PIXEL_ACTION: + // FALLTHROUGH intended + case META_POINT_ACTION: + // FALLTHROUGH intended + case META_LINE_ACTION: + // FALLTHROUGH intended + case META_RECT_ACTION: + // FALLTHROUGH intended + case META_ROUNDRECT_ACTION: + // FALLTHROUGH intended + case META_ELLIPSE_ACTION: + // FALLTHROUGH intended + case META_ARC_ACTION: + // FALLTHROUGH intended + case META_PIE_ACTION: + // FALLTHROUGH intended + case META_CHORD_ACTION: + // FALLTHROUGH intended + case META_POLYLINE_ACTION: + // FALLTHROUGH intended + case META_POLYGON_ACTION: + // FALLTHROUGH intended + case META_POLYPOLYGON_ACTION: + // FALLTHROUGH intended + + case META_TEXT_ACTION: + // FALLTHROUGH intended + case META_TEXTARRAY_ACTION: + // FALLTHROUGH intended + case META_STRETCHTEXT_ACTION: + // FALLTHROUGH intended + case META_TEXTRECT_ACTION: + // FALLTHROUGH intended + + case META_MASK_ACTION: + // FALLTHROUGH intended + case META_MASKSCALE_ACTION: + // FALLTHROUGH intended + case META_MASKSCALEPART_ACTION: + // FALLTHROUGH intended + + case META_GRADIENT_ACTION: + // FALLTHROUGH intended + case META_HATCH_ACTION: + // FALLTHROUGH intended + case META_WALLPAPER_ACTION: + // FALLTHROUGH intended + + case META_TRANSPARENT_ACTION: + // FALLTHROUGH intended + case META_EPS_ACTION: + // FALLTHROUGH intended + case META_FLOATTRANSPARENT_ACTION: + // FALLTHROUGH intended + case META_GRADIENTEX_ACTION: + // FALLTHROUGH intended + case META_RENDERGRAPHIC_ACTION: + // FALLTHROUGH intended + + // OutDev state changes that _do_ affect bitmap + // output + case META_CLIPREGION_ACTION: + // FALLTHROUGH intended + case META_ISECTRECTCLIPREGION_ACTION: + // FALLTHROUGH intended + case META_ISECTREGIONCLIPREGION_ACTION: + // FALLTHROUGH intended + case META_MOVECLIPREGION_ACTION: + // FALLTHROUGH intended + + case META_MAPMODE_ACTION: + // FALLTHROUGH intended + case META_REFPOINT_ACTION: + // FALLTHROUGH intended + default: + bNonBitmapActionEncountered = true; + break; + } + } + } + return nNumBitmaps == 1 && !bNonBitmapActionEncountered; +} + sal_uLong GraphicDisplayCacheEntry::GetNeededSize( OutputDevice* pOut, const Point& /*rPt*/, const Size& rSz, const GraphicObject& rObj, const GraphicAttr& rAttr ) { const Graphic& rGraphic = rObj.GetGraphic(); const GraphicType eType = rGraphic.GetType(); - sal_uLong nNeededSize; + bool canCacheAsBitmap = false; if( GRAPHIC_BITMAP == eType ) + canCacheAsBitmap = true; + else if( GRAPHIC_GDIMETAFILE == eType ) + canCacheAsBitmap = IsCacheableAsBitmap( rGraphic.GetGDIMetaFile(), pOut, rSz ); + else + return 0; + if( canCacheAsBitmap ) { const Size aOutSizePix( pOut->LogicToPixel( rSz ) ); const long nBitCount = pOut->GetBitCount(); @@ -501,27 +795,23 @@ sal_uLong GraphicDisplayCacheEntry::GetNeededSize( OutputDevice* pOut, const Poi if( ( aOutSizePix.Width() > MAX_BMP_EXTENT ) || ( aOutSizePix.Height() > MAX_BMP_EXTENT ) ) { - nNeededSize = ULONG_MAX; + return ULONG_MAX; } else if( nBitCount ) { - nNeededSize = aOutSizePix.Width() * aOutSizePix.Height() * nBitCount / 8; - + sal_uLong nNeededSize = aOutSizePix.Width() * aOutSizePix.Height() * nBitCount / 8; if( rObj.IsTransparent() || ( rAttr.GetRotation() % 3600 ) ) nNeededSize += nNeededSize / nBitCount; + return nNeededSize; } else { - OSL_FAIL( "GraphicDisplayCacheEntry::GetNeededSize(): pOut->GetBitCount() == 0" ); - nNeededSize = 256000; + OSL_FAIL( "GraphicDisplayCacheEntry::GetNeededSize(): pOut->GetBitCount() == 0" ); + return 256000; } } - else if( GRAPHIC_GDIMETAFILE == eType ) - nNeededSize = rGraphic.GetSizeBytes(); else - nNeededSize = 0; - - return nNeededSize; + return rGraphic.GetSizeBytes(); } // ----------------------------------------------------------------------------- diff --git a/svtools/source/graphic/grfmgr2.cxx b/svtools/source/graphic/grfmgr2.cxx index bd77e25326b6..a03c668f5de1 100644 --- a/svtools/source/graphic/grfmgr2.cxx +++ b/svtools/source/graphic/grfmgr2.cxx @@ -536,6 +536,7 @@ static BitmapEx checkMetadataBitmap( const BitmapEx& rBmpEx, const Size& rRefSize, bool& o_rbNonBitmapActionEncountered ) { +// NOTE: If you do changes in this function, change checkMetadataBitmap() in grfcache.cxx too. BitmapEx aBmpEx; if( rSrcSize == Size()) rSrcSize = rBmpEx.GetSizePixel(); @@ -609,6 +610,9 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut, const MapMode rPrefMapMode( rMtf.GetPrefMapMode() ); const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) ); +// NOTE: If you do changes in this function, check GraphicDisplayCacheEntry::IsCacheableAsBitmap +// in grfcache.cxx too. + // Determine whether the metafile basically displays // a single bitmap (in which case that bitmap is simply used directly // instead of playing the metafile). Note that |