diff options
author | Oliver Bolte <obo@openoffice.org> | 2007-07-17 13:53:24 +0000 |
---|---|---|
committer | Oliver Bolte <obo@openoffice.org> | 2007-07-17 13:53:24 +0000 |
commit | 59ac0dc59bfd686430c1c0ea71f34b3e63b765ee (patch) | |
tree | 3ec8b485017d4839797f167e94d158c0bfc6e31a /slideshow/source/engine/shapes/gdimtftools.cxx | |
parent | INTEGRATION: CWS presfixes12 (1.1.2); FILE ADDED (diff) | |
download | core-59ac0dc59bfd686430c1c0ea71f34b3e63b765ee.tar.gz core-59ac0dc59bfd686430c1c0ea71f34b3e63b765ee.zip |
INTEGRATION: CWS presfixes12 (1.1.2); FILE ADDED
2007/01/29 14:02:07 thb 1.1.2.1: Issue number: #i37778#
Larger slideshow refactoring. Wrote design and coding style manifest,
and adapted the code to actually conform to this. In detail:
- cleaned up ownership/disposable/weak_ptr story. removed hacks and
explicit Disposable implementations, where workaround were available
- removed object mutices, where superfluous
- reworked EventMultiplexer (using templatized listener class now), added
more events. EventMultiplexer now serves as a true blackboard
- reworked directory structure: disjunct parts are now physically separated
into directories, instantiation happens via factories & abstract interfaces
- added CursorManager, to make setting mouse cursor less hackish
- reworked DrawShape, to implement SeparateListener pattern
- reworked IntrinsicAnimationActivity, to avoid cyclic references
- modified hyperlink & shape cursor handling to communicate via
EventMultiplexer
- renamed & cleaned up files (presentation.cxx now named slideshowimpl.cxx,
etc.)
- added first version of the z-order fix to layer/layermanager
- cleaned up include guards and include syntax
Diffstat (limited to 'slideshow/source/engine/shapes/gdimtftools.cxx')
-rw-r--r-- | slideshow/source/engine/shapes/gdimtftools.cxx | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/slideshow/source/engine/shapes/gdimtftools.cxx b/slideshow/source/engine/shapes/gdimtftools.cxx new file mode 100644 index 000000000000..57c058dc23d9 --- /dev/null +++ b/slideshow/source/engine/shapes/gdimtftools.cxx @@ -0,0 +1,543 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: gdimtftools.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: obo $ $Date: 2007-07-17 14:53:13 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_slideshow.hxx" + +// must be first +#include <canvas/debug.hxx> +#include <gdimtftools.hxx> + +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/graphic/XGraphicRenderer.hpp> +#include <com/sun/star/drawing/XShape.hpp> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase1.hxx> + +#include <comphelper/uno3.hxx> +#include <cppuhelper/implbase1.hxx> + +#include <tools/stream.hxx> +#include <vcl/svapp.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/metaact.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/metaact.hxx> +#include <vcl/animate.hxx> +#include <vcl/graph.hxx> + +#include <unotools/streamwrap.hxx> + +#include "tools.hxx" + +using namespace ::com::sun::star; + + +// free support functions +// ====================== + +namespace slideshow +{ +namespace internal +{ +// TODO(E2): Detect the case when svx/drawing layer is not +// in-process, or even not on the same machine, and +// fallback to metafile streaming! + +// For fixing #i48102#, have to be a _lot_ more selective +// on which metafiles to convert to bitmaps. The problem +// here is that we _always_ get the shape content as a +// metafile, even if we have a bitmap graphic shape. Thus, +// calling GetBitmapEx on such a Graphic (see below) will +// result in one poorly scaled bitmap into another, +// somewhat arbitrarily sized bitmap. +bool hasUnsupportedActions( const GDIMetaFile& rMtf ) +{ + // search metafile for RasterOp action + MetaAction* pCurrAct; + + // TODO(Q3): avoid const-cast + for( pCurrAct = const_cast<GDIMetaFile&>(rMtf).FirstAction(); + pCurrAct; + pCurrAct = const_cast<GDIMetaFile&>(rMtf).NextAction() ) + { + switch( pCurrAct->GetType() ) + { + case META_RASTEROP_ACTION: + // overpaint is okay - that's the default, anyway + if( ROP_OVERPAINT == + static_cast<MetaRasterOpAction*>(pCurrAct)->GetRasterOp() ) + { + break; + } + // FALLTHROUGH intended + case META_MOVECLIPREGION_ACTION: + // FALLTHROUGH intended + case META_REFPOINT_ACTION: + // FALLTHROUGH intended + case META_WALLPAPER_ACTION: + return true; // at least one unsupported + // action encountered + } + } + + return false; // no unsupported action found +} + +namespace { + +typedef ::cppu::WeakComponentImplHelper1< graphic::XGraphicRenderer > DummyRenderer_Base; + +class DummyRenderer : + public DummyRenderer_Base, + public cppu::BaseMutex +{ +public: + DummyRenderer() : + DummyRenderer_Base( m_aMutex ), + mxGraphic() + { + } + + //--- XGraphicRenderer ----------------------------------- + virtual void SAL_CALL render( const uno::Reference< graphic::XGraphic >& rGraphic ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + mxGraphic = rGraphic; + } + + /** Retrieve GDIMetaFile from renderer + + @param bForeignSource + When true, the source of the metafile might be a + foreign application. The metafile is checked + against unsupported content, and, if necessary, + returned as a pre-rendererd bitmap. + */ + GDIMetaFile getMtf( bool bForeignSource ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Graphic aGraphic( mxGraphic ); + + if( aGraphic.GetType() == GRAPHIC_BITMAP || + (bForeignSource && + hasUnsupportedActions(aGraphic.GetGDIMetaFile()) ) ) + { + // wrap bitmap into GDIMetafile + GDIMetaFile aMtf; + ::Point aEmptyPoint; + + ::BitmapEx aBmpEx( aGraphic.GetBitmapEx() ); + + aMtf.AddAction( new MetaBmpExAction( aEmptyPoint, + aBmpEx ) ); + aMtf.SetPrefSize( aBmpEx.GetPrefSize() ); + aMtf.SetPrefMapMode( aBmpEx.GetPrefMapMode() ); + + return aMtf; + } + else + { + return aGraphic.GetGDIMetaFile(); + } + } + +private: + uno::Reference< graphic::XGraphic > mxGraphic; +}; + +} // anon namespace + +// Quick'n'dirty way: tunnel Graphic (only works for +// in-process slideshow, of course) +bool getMetaFile( const uno::Reference< lang::XComponent >& xSource, + const uno::Reference< drawing::XDrawPage >& xContainingPage, + GDIMetaFile& rMtf, + int mtfLoadFlags, + const uno::Reference< uno::XComponentContext >& rxContext ) +{ + ENSURE_AND_RETURN( rxContext.is(), + "getMetaFile(): Invalid context" ); + + // create dummy XGraphicRenderer, which receives the + // generated XGraphic from the GraphicExporter + + // TODO(P3): Move creation of DummyRenderer out of the + // loop! Either by making it static, or transforming + // the whole thing here into a class. + DummyRenderer* pRenderer( new DummyRenderer() ); + uno::Reference< graphic::XGraphicRenderer > xRenderer( pRenderer ); + + // -> stuff that into UnoGraphicExporter. + uno::Reference<lang::XMultiComponentFactory> xFactory( + rxContext->getServiceManager() ); + + OSL_ENSURE( xFactory.is(), "### no UNO?!" ); + if( !xFactory.is() ) + return false; + + // creating the graphic exporter + uno::Reference< document::XExporter > xExporter( + xFactory->createInstanceWithContext( + OUSTR("com.sun.star.drawing.GraphicExportFilter"), + rxContext), + uno::UNO_QUERY ); + uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY ); + + OSL_ENSURE( xExporter.is() && xFilter.is(), "### no graphic exporter?!" ); + if( !xExporter.is() || !xFilter.is() ) + return false; + + uno::Sequence< beans::PropertyValue > aProps(3); + aProps[0].Name = OUSTR("FilterName"); + aProps[0].Value <<= OUSTR("SVM"); + + aProps[1].Name = OUSTR("GraphicRenderer"); + aProps[1].Value <<= xRenderer; + + uno::Sequence< beans::PropertyValue > aFilterData(5); + aFilterData[0].Name = OUSTR("VerboseComments"); + aFilterData[0].Value <<= ((mtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0); + + aFilterData[1].Name = OUSTR("ScrollText"); + aFilterData[1].Value <<= ((mtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != 0); + + aFilterData[2].Name = OUSTR("ExportOnlyBackground"); + aFilterData[2].Value <<= ((mtfLoadFlags & MTF_LOAD_BACKGROUND_ONLY) != 0); + + aFilterData[3].Name = OUSTR("Version"); + aFilterData[3].Value <<= static_cast<sal_Int32>( SOFFICE_FILEFORMAT_50 ); + + aFilterData[4].Name = OUSTR("CurrentPage"); + aFilterData[4].Value <<= uno::Reference< uno::XInterface >( xContainingPage, + uno::UNO_QUERY_THROW ); + + aProps[2].Name = OUSTR("FilterData"); + aProps[2].Value <<= aFilterData; + + xExporter->setSourceDocument( xSource ); + if( !xFilter->filter( aProps ) ) + return false; + + rMtf = pRenderer->getMtf( (mtfLoadFlags & MTF_LOAD_FOREIGN_SOURCE) != 0 ); + + // pRenderer is automatically destroyed when xRenderer + // goes out of scope + + // TODO(E3): Error handling. Exporter might have + // generated nothing, a bitmap, threw an exception, + // whatever. + return true; +} + +void removeTextActions( GDIMetaFile& rMtf ) +{ + // search metafile for text output + MetaAction* pCurrAct; + + int nActionIndex(0); + pCurrAct = rMtf.FirstAction(); + while( pCurrAct ) + { + switch( pCurrAct->GetType() ) + { + case META_TEXTCOLOR_ACTION: + case META_TEXTFILLCOLOR_ACTION: + case META_TEXTLINECOLOR_ACTION: + case META_TEXTALIGN_ACTION: + case META_FONT_ACTION: + case META_LAYOUTMODE_ACTION: + case META_TEXT_ACTION: + case META_TEXTARRAY_ACTION: + case META_TEXTRECT_ACTION: + case META_STRETCHTEXT_ACTION: + case META_TEXTLINE_ACTION: + { + // remove every text-related actions + pCurrAct = rMtf.NextAction(); + + rMtf.RemoveAction( nActionIndex ); + break; + } + + default: + pCurrAct = rMtf.NextAction(); + ++nActionIndex; + break; + } + } +} + +sal_Int32 getNextActionOffset( MetaAction * pCurrAct ) +{ + // Special handling for actions that represent + // more than one indexable action + // =========================================== + + switch (pCurrAct->GetType()) { + case META_TEXT_ACTION: { + MetaTextAction * pAct = static_cast<MetaTextAction *>(pCurrAct); + return (pAct->GetLen() == (USHORT)STRING_LEN + ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen()); + } + case META_TEXTARRAY_ACTION: { + MetaTextArrayAction * pAct = + static_cast<MetaTextArrayAction *>(pCurrAct); + return (pAct->GetLen() == (USHORT)STRING_LEN + ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen()); + } + case META_STRETCHTEXT_ACTION: { + MetaStretchTextAction * pAct = + static_cast<MetaStretchTextAction *>(pCurrAct); + return (pAct->GetLen() == (USHORT)STRING_LEN + ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen()); + } + case META_FLOATTRANSPARENT_ACTION: { + MetaFloatTransparentAction * pAct = + static_cast<MetaFloatTransparentAction*>(pCurrAct); + // TODO(F2): Recurse into action metafile + // (though this is currently not used from the + // DrawingLayer - shape transparency gradients + // don't affect shape text) + return pAct->GetGDIMetaFile().GetActionCount(); + } + default: + return 1; + } +} + +bool getAnimationFromGraphic( VectorOfMtfAnimationFrames& o_rFrames, + ::std::size_t& o_rLoopCount, + CycleMode& o_eCycleMode, + const Graphic& rGraphic ) +{ + o_rFrames.clear(); + + if( !rGraphic.IsAnimated() ) + return false; + + // some loop invariants + Animation aAnimation( rGraphic.GetAnimation() ); + const Point aEmptyPoint; + const Size aAnimSize( aAnimation.GetDisplaySizePixel() ); + + // setup VDev, into which all bitmaps are painted (want to + // normalize animations to n bitmaps of same size. An Animation, + // though, can contain bitmaps of varying sizes and different + // update modes) + VirtualDevice aVDev; + aVDev.SetOutputSizePixel( aAnimSize ); + aVDev.EnableMapMode( FALSE ); + + // setup mask VDev (alpha VDev is currently rather slow) + VirtualDevice aVDevMask; + aVDevMask.SetOutputSizePixel( aAnimSize ); + aVDevMask.EnableMapMode( FALSE ); + + switch( aAnimation.GetCycleMode() ) + { + case CYCLE_NOT: + o_rLoopCount = 1; + o_eCycleMode = CYCLE_LOOP; + break; + + case CYCLE_FALLBACK: + // FALLTHROUGH intended + case CYCLE_NORMAL: + o_rLoopCount = aAnimation.GetLoopCount(); + o_eCycleMode = CYCLE_LOOP; + break; + + case CYCLE_REVERS: + // FALLTHROUGH intended + case CYCLE_REVERS_FALLBACK: + o_rLoopCount = aAnimation.GetLoopCount(); + o_eCycleMode = CYCLE_PINGPONGLOOP; + break; + + default: + ENSURE_AND_RETURN(false, + "getAnimationFromGraphic(): Unexpected case" ); + break; + } + + for( USHORT i=0, nCount=aAnimation.Count(); i<nCount; ++i ) + { + const AnimationBitmap& rAnimBmp( aAnimation.Get(i) ); + switch(rAnimBmp.eDisposal) + { + case DISPOSE_NOT: + { + aVDev.DrawBitmapEx(rAnimBmp.aPosPix, + rAnimBmp.aBmpEx); + Bitmap aMask = rAnimBmp.aBmpEx.GetMask(); + + if( aMask.IsEmpty() ) + { + const Point aEmpty; + const Rectangle aRect(aEmptyPoint, + aVDevMask.GetOutputSizePixel()); + const Wallpaper aWallpaper(COL_BLACK); + aVDevMask.DrawWallpaper(aRect, + aWallpaper); + } + else + { + BitmapEx aTmpMask = BitmapEx(aMask, + aMask); + aVDevMask.DrawBitmapEx(rAnimBmp.aPosPix, + aTmpMask ); + } + break; + } + + case DISPOSE_BACK: + { + aVDevMask.Erase(); + aVDev.DrawBitmap(rAnimBmp.aPosPix, + rAnimBmp.aBmpEx.GetBitmap()); + aVDevMask.DrawBitmap(rAnimBmp.aPosPix, + rAnimBmp.aBmpEx.GetMask()); + break; + } + + case DISPOSE_FULL: + { + aVDev.DrawBitmapEx(rAnimBmp.aPosPix, + rAnimBmp.aBmpEx); + break; + } + + case DISPOSE_PREVIOUS : + { + aVDev.DrawBitmapEx(rAnimBmp.aPosPix, + rAnimBmp.aBmpEx); + aVDevMask.DrawBitmap(rAnimBmp.aPosPix, + rAnimBmp.aBmpEx.GetMask()); + break; + } + } + + // extract current aVDev content into a new animation + // frame + GDIMetaFileSharedPtr pMtf( new GDIMetaFile() ); + pMtf->AddAction( + new MetaBmpExAction( aEmptyPoint, + BitmapEx( + aVDev.GetBitmap( + aEmptyPoint, + aAnimSize ), + aVDevMask.GetBitmap( + aEmptyPoint, + aAnimSize )))); + + // setup mtf dimensions and pref map mode (for + // simplicity, keep it all in pixel. the metafile + // renderer scales it down to (1, 1) box anyway) + pMtf->SetPrefMapMode( MapMode() ); + pMtf->SetPrefSize( aAnimSize ); + + // #115934# + // Take care of special value for MultiPage TIFFs. ATM these shall just + // show their first page for _quite_ some time. + sal_Int32 nWaitTime100thSeconds( rAnimBmp.nWait ); + if( ANIMATION_TIMEOUT_ON_CLICK == nWaitTime100thSeconds ) + { + // ATM the huge value would block the timer, so use a long + // time to show first page (whole day) + nWaitTime100thSeconds = 100 * 60 * 60 * 24; + } + + // There are animated GIFs with no WaitTime set. Take 1 sec, then. + if( nWaitTime100thSeconds == 0 ) + nWaitTime100thSeconds = 100; + + o_rFrames.push_back( MtfAnimationFrame( pMtf, + nWaitTime100thSeconds / 100.0 ) ); + } + + return !o_rFrames.empty(); +} + +bool getRectanglesFromScrollMtf( ::basegfx::B2DRectangle& o_rScrollRect, + ::basegfx::B2DRectangle& o_rPaintRect, + const GDIMetaFileSharedPtr& rMtf ) +{ + // extract bounds: scroll rect, paint rect + bool bScrollRectSet(false); + bool bPaintRectSet(false); + + for ( MetaAction * pCurrAct = rMtf->FirstAction(); + pCurrAct != 0; pCurrAct = rMtf->NextAction() ) + { + if (pCurrAct->GetType() == META_COMMENT_ACTION) + { + MetaCommentAction * pAct = + static_cast<MetaCommentAction *>(pCurrAct); + // skip comment if not a special XTEXT comment + if (pAct->GetComment().CompareIgnoreCaseToAscii( + RTL_CONSTASCII_STRINGPARAM("XTEXT") ) == COMPARE_EQUAL) + { + if (pAct->GetComment().CompareIgnoreCaseToAscii( + "XTEXT_SCROLLRECT" ) == COMPARE_EQUAL) { + o_rScrollRect = ::vcl::unotools::b2DRectangleFromRectangle( + *reinterpret_cast<Rectangle const *>( + pAct->GetData() ) ); + + bScrollRectSet = true; + } + else if (pAct->GetComment().CompareIgnoreCaseToAscii( + "XTEXT_PAINTRECT" ) == COMPARE_EQUAL) { + o_rPaintRect = ::vcl::unotools::b2DRectangleFromRectangle( + *reinterpret_cast<Rectangle const *>( + pAct->GetData() ) ); + + bPaintRectSet = true; + } + } + } + } + + return bScrollRectSet && bPaintRectSet; +} + +} +} + |