1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_slideshow.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir // must be first
32*cdf0e10cSrcweir #include <canvas/debug.hxx>
33*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
34*cdf0e10cSrcweir #include <gdimtftools.hxx>
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include <com/sun/star/document/XExporter.hpp>
37*cdf0e10cSrcweir #include <com/sun/star/document/XFilter.hpp>
38*cdf0e10cSrcweir #include <com/sun/star/graphic/XGraphic.hpp>
39*cdf0e10cSrcweir #include <com/sun/star/graphic/XGraphicRenderer.hpp>
40*cdf0e10cSrcweir #include <com/sun/star/drawing/XShape.hpp>
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir #include <cppuhelper/basemutex.hxx>
43*cdf0e10cSrcweir #include <cppuhelper/compbase1.hxx>
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir #include <comphelper/uno3.hxx>
46*cdf0e10cSrcweir #include <cppuhelper/implbase1.hxx>
47*cdf0e10cSrcweir 
48*cdf0e10cSrcweir #include <tools/stream.hxx>
49*cdf0e10cSrcweir #include <vcl/svapp.hxx>
50*cdf0e10cSrcweir #include <vcl/canvastools.hxx>
51*cdf0e10cSrcweir #include <vcl/metaact.hxx>
52*cdf0e10cSrcweir #include <vcl/virdev.hxx>
53*cdf0e10cSrcweir #include <vcl/gdimtf.hxx>
54*cdf0e10cSrcweir #include <vcl/metaact.hxx>
55*cdf0e10cSrcweir #include <vcl/animate.hxx>
56*cdf0e10cSrcweir #include <vcl/graph.hxx>
57*cdf0e10cSrcweir 
58*cdf0e10cSrcweir #include <unotools/streamwrap.hxx>
59*cdf0e10cSrcweir 
60*cdf0e10cSrcweir #include "tools.hxx"
61*cdf0e10cSrcweir 
62*cdf0e10cSrcweir using namespace ::com::sun::star;
63*cdf0e10cSrcweir 
64*cdf0e10cSrcweir 
65*cdf0e10cSrcweir // free support functions
66*cdf0e10cSrcweir // ======================
67*cdf0e10cSrcweir 
68*cdf0e10cSrcweir namespace slideshow
69*cdf0e10cSrcweir {
70*cdf0e10cSrcweir namespace internal
71*cdf0e10cSrcweir {
72*cdf0e10cSrcweir // TODO(E2): Detect the case when svx/drawing layer is not
73*cdf0e10cSrcweir // in-process, or even not on the same machine, and
74*cdf0e10cSrcweir // fallback to metafile streaming!
75*cdf0e10cSrcweir 
76*cdf0e10cSrcweir // For fixing #i48102#, have to be a _lot_ more selective
77*cdf0e10cSrcweir // on which metafiles to convert to bitmaps. The problem
78*cdf0e10cSrcweir // here is that we _always_ get the shape content as a
79*cdf0e10cSrcweir // metafile, even if we have a bitmap graphic shape. Thus,
80*cdf0e10cSrcweir // calling GetBitmapEx on such a Graphic (see below) will
81*cdf0e10cSrcweir // result in one poorly scaled bitmap into another,
82*cdf0e10cSrcweir // somewhat arbitrarily sized bitmap.
83*cdf0e10cSrcweir bool hasUnsupportedActions( const GDIMetaFile& rMtf )
84*cdf0e10cSrcweir {
85*cdf0e10cSrcweir     // search metafile for RasterOp action
86*cdf0e10cSrcweir     MetaAction* pCurrAct;
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir     // TODO(Q3): avoid const-cast
89*cdf0e10cSrcweir     for( pCurrAct = const_cast<GDIMetaFile&>(rMtf).FirstAction();
90*cdf0e10cSrcweir          pCurrAct;
91*cdf0e10cSrcweir          pCurrAct = const_cast<GDIMetaFile&>(rMtf).NextAction() )
92*cdf0e10cSrcweir     {
93*cdf0e10cSrcweir         switch( pCurrAct->GetType() )
94*cdf0e10cSrcweir         {
95*cdf0e10cSrcweir             case META_RASTEROP_ACTION:
96*cdf0e10cSrcweir                 // overpaint is okay - that's the default, anyway
97*cdf0e10cSrcweir                 if( ROP_OVERPAINT ==
98*cdf0e10cSrcweir                     static_cast<MetaRasterOpAction*>(pCurrAct)->GetRasterOp() )
99*cdf0e10cSrcweir                 {
100*cdf0e10cSrcweir                     break;
101*cdf0e10cSrcweir                 }
102*cdf0e10cSrcweir                 // FALLTHROUGH intended
103*cdf0e10cSrcweir             case META_MOVECLIPREGION_ACTION:
104*cdf0e10cSrcweir                 // FALLTHROUGH intended
105*cdf0e10cSrcweir             case META_REFPOINT_ACTION:
106*cdf0e10cSrcweir                 // FALLTHROUGH intended
107*cdf0e10cSrcweir             case META_WALLPAPER_ACTION:
108*cdf0e10cSrcweir                 return true; // at least one unsupported
109*cdf0e10cSrcweir                              // action encountered
110*cdf0e10cSrcweir         }
111*cdf0e10cSrcweir     }
112*cdf0e10cSrcweir 
113*cdf0e10cSrcweir     return false; // no unsupported action found
114*cdf0e10cSrcweir }
115*cdf0e10cSrcweir 
116*cdf0e10cSrcweir namespace {
117*cdf0e10cSrcweir 
118*cdf0e10cSrcweir typedef ::cppu::WeakComponentImplHelper1< graphic::XGraphicRenderer > DummyRenderer_Base;
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir class DummyRenderer :
121*cdf0e10cSrcweir         public DummyRenderer_Base,
122*cdf0e10cSrcweir         public cppu::BaseMutex
123*cdf0e10cSrcweir {
124*cdf0e10cSrcweir public:
125*cdf0e10cSrcweir     DummyRenderer() :
126*cdf0e10cSrcweir         DummyRenderer_Base( m_aMutex ),
127*cdf0e10cSrcweir         mxGraphic()
128*cdf0e10cSrcweir         {
129*cdf0e10cSrcweir         }
130*cdf0e10cSrcweir 
131*cdf0e10cSrcweir     //---  XGraphicRenderer  -----------------------------------
132*cdf0e10cSrcweir     virtual void SAL_CALL render( const uno::Reference< graphic::XGraphic >& rGraphic ) throw (uno::RuntimeException)
133*cdf0e10cSrcweir         {
134*cdf0e10cSrcweir             ::osl::MutexGuard aGuard( m_aMutex );
135*cdf0e10cSrcweir             mxGraphic = rGraphic;
136*cdf0e10cSrcweir         }
137*cdf0e10cSrcweir 
138*cdf0e10cSrcweir     /** Retrieve GDIMetaFile from renderer
139*cdf0e10cSrcweir 
140*cdf0e10cSrcweir         @param bForeignSource
141*cdf0e10cSrcweir         When true, the source of the metafile might be a
142*cdf0e10cSrcweir         foreign application. The metafile is checked
143*cdf0e10cSrcweir         against unsupported content, and, if necessary,
144*cdf0e10cSrcweir         returned as a pre-rendererd bitmap.
145*cdf0e10cSrcweir     */
146*cdf0e10cSrcweir     GDIMetaFile getMtf( bool bForeignSource ) const
147*cdf0e10cSrcweir     {
148*cdf0e10cSrcweir         ::osl::MutexGuard aGuard( m_aMutex );
149*cdf0e10cSrcweir 
150*cdf0e10cSrcweir         Graphic aGraphic( mxGraphic );
151*cdf0e10cSrcweir 
152*cdf0e10cSrcweir         if( aGraphic.GetType() == GRAPHIC_BITMAP ||
153*cdf0e10cSrcweir             (bForeignSource &&
154*cdf0e10cSrcweir              hasUnsupportedActions(aGraphic.GetGDIMetaFile()) ) )
155*cdf0e10cSrcweir         {
156*cdf0e10cSrcweir             // wrap bitmap into GDIMetafile
157*cdf0e10cSrcweir             GDIMetaFile 	aMtf;
158*cdf0e10cSrcweir             ::Point			aEmptyPoint;
159*cdf0e10cSrcweir 
160*cdf0e10cSrcweir             ::BitmapEx		aBmpEx( aGraphic.GetBitmapEx() );
161*cdf0e10cSrcweir 
162*cdf0e10cSrcweir             aMtf.AddAction( new MetaBmpExAction( aEmptyPoint,
163*cdf0e10cSrcweir                                                  aBmpEx ) );
164*cdf0e10cSrcweir             aMtf.SetPrefSize( aBmpEx.GetPrefSize() );
165*cdf0e10cSrcweir             aMtf.SetPrefMapMode( aBmpEx.GetPrefMapMode() );
166*cdf0e10cSrcweir 
167*cdf0e10cSrcweir             return aMtf;
168*cdf0e10cSrcweir         }
169*cdf0e10cSrcweir         else
170*cdf0e10cSrcweir         {
171*cdf0e10cSrcweir             return aGraphic.GetGDIMetaFile();
172*cdf0e10cSrcweir         }
173*cdf0e10cSrcweir     }
174*cdf0e10cSrcweir 
175*cdf0e10cSrcweir private:
176*cdf0e10cSrcweir     uno::Reference< graphic::XGraphic >	mxGraphic;
177*cdf0e10cSrcweir };
178*cdf0e10cSrcweir 
179*cdf0e10cSrcweir } // anon namespace
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir // Quick'n'dirty way: tunnel Graphic (only works for
182*cdf0e10cSrcweir // in-process slideshow, of course)
183*cdf0e10cSrcweir bool getMetaFile( const uno::Reference< lang::XComponent >& 	  xSource,
184*cdf0e10cSrcweir                   const uno::Reference< drawing::XDrawPage >&     xContainingPage,
185*cdf0e10cSrcweir                   GDIMetaFile&                                    rMtf,
186*cdf0e10cSrcweir                   int                                             mtfLoadFlags,
187*cdf0e10cSrcweir                   const uno::Reference< uno::XComponentContext >& rxContext )
188*cdf0e10cSrcweir {
189*cdf0e10cSrcweir     ENSURE_OR_RETURN_FALSE( rxContext.is(),
190*cdf0e10cSrcweir                        "getMetaFile(): Invalid context" );
191*cdf0e10cSrcweir 
192*cdf0e10cSrcweir     // create dummy XGraphicRenderer, which receives the
193*cdf0e10cSrcweir     // generated XGraphic from the GraphicExporter
194*cdf0e10cSrcweir 
195*cdf0e10cSrcweir     // TODO(P3): Move creation of DummyRenderer out of the
196*cdf0e10cSrcweir     // loop! Either by making it static, or transforming
197*cdf0e10cSrcweir     // the whole thing here into a class.
198*cdf0e10cSrcweir     DummyRenderer*						 		pRenderer( new DummyRenderer() );
199*cdf0e10cSrcweir     uno::Reference< graphic::XGraphicRenderer > xRenderer( pRenderer );
200*cdf0e10cSrcweir 
201*cdf0e10cSrcweir     // -> stuff that into UnoGraphicExporter.
202*cdf0e10cSrcweir     uno::Reference<lang::XMultiComponentFactory> xFactory(
203*cdf0e10cSrcweir         rxContext->getServiceManager() );
204*cdf0e10cSrcweir 
205*cdf0e10cSrcweir     OSL_ENSURE( xFactory.is(), "### no UNO?!" );
206*cdf0e10cSrcweir     if( !xFactory.is() )
207*cdf0e10cSrcweir         return false;
208*cdf0e10cSrcweir 
209*cdf0e10cSrcweir     // creating the graphic exporter
210*cdf0e10cSrcweir     uno::Reference< document::XExporter > xExporter(
211*cdf0e10cSrcweir         xFactory->createInstanceWithContext(
212*cdf0e10cSrcweir             OUSTR("com.sun.star.drawing.GraphicExportFilter"),
213*cdf0e10cSrcweir             rxContext),
214*cdf0e10cSrcweir         uno::UNO_QUERY );
215*cdf0e10cSrcweir     uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY );
216*cdf0e10cSrcweir 
217*cdf0e10cSrcweir     OSL_ENSURE( xExporter.is() && xFilter.is(), "### no graphic exporter?!" );
218*cdf0e10cSrcweir     if( !xExporter.is() || !xFilter.is() )
219*cdf0e10cSrcweir         return false;
220*cdf0e10cSrcweir 
221*cdf0e10cSrcweir     uno::Sequence< beans::PropertyValue > aProps(3);
222*cdf0e10cSrcweir     aProps[0].Name = OUSTR("FilterName");
223*cdf0e10cSrcweir     aProps[0].Value <<= OUSTR("SVM");
224*cdf0e10cSrcweir 
225*cdf0e10cSrcweir     aProps[1].Name = OUSTR("GraphicRenderer");
226*cdf0e10cSrcweir     aProps[1].Value <<= xRenderer;
227*cdf0e10cSrcweir 
228*cdf0e10cSrcweir     uno::Sequence< beans::PropertyValue > aFilterData(5);
229*cdf0e10cSrcweir     aFilterData[0].Name = OUSTR("VerboseComments");
230*cdf0e10cSrcweir     aFilterData[0].Value <<= ((mtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0);
231*cdf0e10cSrcweir 
232*cdf0e10cSrcweir     aFilterData[1].Name = OUSTR("ScrollText");
233*cdf0e10cSrcweir     aFilterData[1].Value <<= ((mtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != 0);
234*cdf0e10cSrcweir 
235*cdf0e10cSrcweir     aFilterData[2].Name = OUSTR("ExportOnlyBackground");
236*cdf0e10cSrcweir     aFilterData[2].Value <<= ((mtfLoadFlags & MTF_LOAD_BACKGROUND_ONLY) != 0);
237*cdf0e10cSrcweir 
238*cdf0e10cSrcweir     aFilterData[3].Name = OUSTR("Version");
239*cdf0e10cSrcweir     aFilterData[3].Value <<= static_cast<sal_Int32>( SOFFICE_FILEFORMAT_50 );
240*cdf0e10cSrcweir 
241*cdf0e10cSrcweir     aFilterData[4].Name = OUSTR("CurrentPage");
242*cdf0e10cSrcweir     aFilterData[4].Value <<= uno::Reference< uno::XInterface >( xContainingPage,
243*cdf0e10cSrcweir                                                                 uno::UNO_QUERY_THROW );
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir     aProps[2].Name = OUSTR("FilterData");
246*cdf0e10cSrcweir     aProps[2].Value <<= aFilterData;
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir     xExporter->setSourceDocument( xSource );
249*cdf0e10cSrcweir     if( !xFilter->filter( aProps ) )
250*cdf0e10cSrcweir         return false;
251*cdf0e10cSrcweir 
252*cdf0e10cSrcweir     rMtf = pRenderer->getMtf( (mtfLoadFlags & MTF_LOAD_FOREIGN_SOURCE) != 0 );
253*cdf0e10cSrcweir 
254*cdf0e10cSrcweir     // pRenderer is automatically destroyed when xRenderer
255*cdf0e10cSrcweir     // goes out of scope
256*cdf0e10cSrcweir 
257*cdf0e10cSrcweir     // TODO(E3): Error handling. Exporter might have
258*cdf0e10cSrcweir     // generated nothing, a bitmap, threw an exception,
259*cdf0e10cSrcweir     // whatever.
260*cdf0e10cSrcweir     return true;
261*cdf0e10cSrcweir }
262*cdf0e10cSrcweir 
263*cdf0e10cSrcweir void removeTextActions( GDIMetaFile& rMtf )
264*cdf0e10cSrcweir {
265*cdf0e10cSrcweir     // search metafile for text output
266*cdf0e10cSrcweir     MetaAction* pCurrAct;
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir     int nActionIndex(0);
269*cdf0e10cSrcweir     pCurrAct = rMtf.FirstAction();
270*cdf0e10cSrcweir     while( pCurrAct )
271*cdf0e10cSrcweir     {
272*cdf0e10cSrcweir         switch( pCurrAct->GetType() )
273*cdf0e10cSrcweir         {
274*cdf0e10cSrcweir         case META_TEXTCOLOR_ACTION:
275*cdf0e10cSrcweir         case META_TEXTFILLCOLOR_ACTION:
276*cdf0e10cSrcweir         case META_TEXTLINECOLOR_ACTION:
277*cdf0e10cSrcweir         case META_TEXTALIGN_ACTION:
278*cdf0e10cSrcweir         case META_FONT_ACTION:
279*cdf0e10cSrcweir         case META_LAYOUTMODE_ACTION:
280*cdf0e10cSrcweir         case META_TEXT_ACTION:
281*cdf0e10cSrcweir         case META_TEXTARRAY_ACTION:
282*cdf0e10cSrcweir         case META_TEXTRECT_ACTION:
283*cdf0e10cSrcweir         case META_STRETCHTEXT_ACTION:
284*cdf0e10cSrcweir         case META_TEXTLINE_ACTION:
285*cdf0e10cSrcweir         {
286*cdf0e10cSrcweir             // remove every text-related actions
287*cdf0e10cSrcweir             pCurrAct = rMtf.NextAction();
288*cdf0e10cSrcweir 
289*cdf0e10cSrcweir             rMtf.RemoveAction( nActionIndex );
290*cdf0e10cSrcweir             break;
291*cdf0e10cSrcweir         }
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir         default:
294*cdf0e10cSrcweir             pCurrAct = rMtf.NextAction();
295*cdf0e10cSrcweir             ++nActionIndex;
296*cdf0e10cSrcweir             break;
297*cdf0e10cSrcweir         }
298*cdf0e10cSrcweir     }
299*cdf0e10cSrcweir }
300*cdf0e10cSrcweir 
301*cdf0e10cSrcweir sal_Int32 getNextActionOffset( MetaAction * pCurrAct )
302*cdf0e10cSrcweir {
303*cdf0e10cSrcweir     // Special handling for actions that represent
304*cdf0e10cSrcweir     // more than one indexable action
305*cdf0e10cSrcweir     // ===========================================
306*cdf0e10cSrcweir 
307*cdf0e10cSrcweir     switch (pCurrAct->GetType()) {
308*cdf0e10cSrcweir     case META_TEXT_ACTION: {
309*cdf0e10cSrcweir         MetaTextAction * pAct = static_cast<MetaTextAction *>(pCurrAct);
310*cdf0e10cSrcweir         return (pAct->GetLen() == (sal_uInt16)STRING_LEN
311*cdf0e10cSrcweir                 ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
312*cdf0e10cSrcweir     }
313*cdf0e10cSrcweir     case META_TEXTARRAY_ACTION: {
314*cdf0e10cSrcweir         MetaTextArrayAction * pAct =
315*cdf0e10cSrcweir             static_cast<MetaTextArrayAction *>(pCurrAct);
316*cdf0e10cSrcweir         return (pAct->GetLen() == (sal_uInt16)STRING_LEN
317*cdf0e10cSrcweir                 ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
318*cdf0e10cSrcweir     }
319*cdf0e10cSrcweir     case META_STRETCHTEXT_ACTION: {
320*cdf0e10cSrcweir         MetaStretchTextAction * pAct =
321*cdf0e10cSrcweir             static_cast<MetaStretchTextAction *>(pCurrAct);
322*cdf0e10cSrcweir         return (pAct->GetLen() == (sal_uInt16)STRING_LEN
323*cdf0e10cSrcweir                 ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
324*cdf0e10cSrcweir     }
325*cdf0e10cSrcweir     case META_FLOATTRANSPARENT_ACTION: {
326*cdf0e10cSrcweir         MetaFloatTransparentAction * pAct =
327*cdf0e10cSrcweir             static_cast<MetaFloatTransparentAction*>(pCurrAct);
328*cdf0e10cSrcweir         // TODO(F2): Recurse into action metafile
329*cdf0e10cSrcweir         // (though this is currently not used from the
330*cdf0e10cSrcweir         // DrawingLayer - shape transparency gradients
331*cdf0e10cSrcweir         // don't affect shape text)
332*cdf0e10cSrcweir         return pAct->GetGDIMetaFile().GetActionCount();
333*cdf0e10cSrcweir     }
334*cdf0e10cSrcweir     default:
335*cdf0e10cSrcweir         return 1;
336*cdf0e10cSrcweir     }
337*cdf0e10cSrcweir }
338*cdf0e10cSrcweir 
339*cdf0e10cSrcweir bool getAnimationFromGraphic( VectorOfMtfAnimationFrames&   o_rFrames,
340*cdf0e10cSrcweir                               ::std::size_t&                o_rLoopCount,
341*cdf0e10cSrcweir                               CycleMode&                    o_eCycleMode,
342*cdf0e10cSrcweir                               const Graphic&                rGraphic )
343*cdf0e10cSrcweir {
344*cdf0e10cSrcweir     o_rFrames.clear();
345*cdf0e10cSrcweir 
346*cdf0e10cSrcweir     if( !rGraphic.IsAnimated() )
347*cdf0e10cSrcweir         return false;
348*cdf0e10cSrcweir 
349*cdf0e10cSrcweir     // some loop invariants
350*cdf0e10cSrcweir     Animation 	aAnimation( rGraphic.GetAnimation() );
351*cdf0e10cSrcweir     const Point aEmptyPoint;
352*cdf0e10cSrcweir     const Size  aAnimSize( aAnimation.GetDisplaySizePixel() );
353*cdf0e10cSrcweir 
354*cdf0e10cSrcweir     // setup VDev, into which all bitmaps are painted (want to
355*cdf0e10cSrcweir     // normalize animations to n bitmaps of same size. An Animation,
356*cdf0e10cSrcweir     // though, can contain bitmaps of varying sizes and different
357*cdf0e10cSrcweir     // update modes)
358*cdf0e10cSrcweir     VirtualDevice aVDev;
359*cdf0e10cSrcweir     aVDev.SetOutputSizePixel( aAnimSize );
360*cdf0e10cSrcweir     aVDev.EnableMapMode( sal_False );
361*cdf0e10cSrcweir 
362*cdf0e10cSrcweir     // setup mask VDev (alpha VDev is currently rather slow)
363*cdf0e10cSrcweir     VirtualDevice aVDevMask;
364*cdf0e10cSrcweir     aVDevMask.SetOutputSizePixel( aAnimSize );
365*cdf0e10cSrcweir     aVDevMask.EnableMapMode( sal_False );
366*cdf0e10cSrcweir 
367*cdf0e10cSrcweir     switch( aAnimation.GetCycleMode() )
368*cdf0e10cSrcweir     {
369*cdf0e10cSrcweir         case CYCLE_NOT:
370*cdf0e10cSrcweir             o_rLoopCount = 1;
371*cdf0e10cSrcweir             o_eCycleMode = CYCLE_LOOP;
372*cdf0e10cSrcweir             break;
373*cdf0e10cSrcweir 
374*cdf0e10cSrcweir         case CYCLE_FALLBACK:
375*cdf0e10cSrcweir             // FALLTHROUGH intended
376*cdf0e10cSrcweir         case CYCLE_NORMAL:
377*cdf0e10cSrcweir             o_rLoopCount = aAnimation.GetLoopCount();
378*cdf0e10cSrcweir             o_eCycleMode = CYCLE_LOOP;
379*cdf0e10cSrcweir             break;
380*cdf0e10cSrcweir 
381*cdf0e10cSrcweir         case CYCLE_REVERS:
382*cdf0e10cSrcweir             // FALLTHROUGH intended
383*cdf0e10cSrcweir         case CYCLE_REVERS_FALLBACK:
384*cdf0e10cSrcweir             o_rLoopCount = aAnimation.GetLoopCount();
385*cdf0e10cSrcweir             o_eCycleMode = CYCLE_PINGPONGLOOP;
386*cdf0e10cSrcweir             break;
387*cdf0e10cSrcweir 
388*cdf0e10cSrcweir         default:
389*cdf0e10cSrcweir             ENSURE_OR_RETURN_FALSE(false,
390*cdf0e10cSrcweir                               "getAnimationFromGraphic(): Unexpected case" );
391*cdf0e10cSrcweir             break;
392*cdf0e10cSrcweir     }
393*cdf0e10cSrcweir 
394*cdf0e10cSrcweir     for( sal_uInt16 i=0, nCount=aAnimation.Count(); i<nCount; ++i )
395*cdf0e10cSrcweir     {
396*cdf0e10cSrcweir         const AnimationBitmap& rAnimBmp( aAnimation.Get(i) );
397*cdf0e10cSrcweir         switch(rAnimBmp.eDisposal)
398*cdf0e10cSrcweir         {
399*cdf0e10cSrcweir             case DISPOSE_NOT:
400*cdf0e10cSrcweir             {
401*cdf0e10cSrcweir                 aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
402*cdf0e10cSrcweir                                    rAnimBmp.aBmpEx);
403*cdf0e10cSrcweir                 Bitmap aMask = rAnimBmp.aBmpEx.GetMask();
404*cdf0e10cSrcweir 
405*cdf0e10cSrcweir                 if( aMask.IsEmpty() )
406*cdf0e10cSrcweir                 {
407*cdf0e10cSrcweir                     const Point aEmpty;
408*cdf0e10cSrcweir                     const Rectangle aRect(aEmptyPoint,
409*cdf0e10cSrcweir                                           aVDevMask.GetOutputSizePixel());
410*cdf0e10cSrcweir                     const Wallpaper aWallpaper(COL_BLACK);
411*cdf0e10cSrcweir                     aVDevMask.DrawWallpaper(aRect,
412*cdf0e10cSrcweir                                             aWallpaper);
413*cdf0e10cSrcweir                 }
414*cdf0e10cSrcweir                 else
415*cdf0e10cSrcweir                 {
416*cdf0e10cSrcweir                     BitmapEx aTmpMask = BitmapEx(aMask,
417*cdf0e10cSrcweir                                                  aMask);
418*cdf0e10cSrcweir                     aVDevMask.DrawBitmapEx(rAnimBmp.aPosPix,
419*cdf0e10cSrcweir                                            aTmpMask );
420*cdf0e10cSrcweir                 }
421*cdf0e10cSrcweir                 break;
422*cdf0e10cSrcweir             }
423*cdf0e10cSrcweir 
424*cdf0e10cSrcweir             case DISPOSE_BACK:
425*cdf0e10cSrcweir             {
426*cdf0e10cSrcweir 				// #i70772# react on no mask
427*cdf0e10cSrcweir 				const Bitmap aMask(rAnimBmp.aBmpEx.GetMask());
428*cdf0e10cSrcweir 				const Bitmap aContent(rAnimBmp.aBmpEx.GetBitmap());
429*cdf0e10cSrcweir 
430*cdf0e10cSrcweir 				aVDevMask.Erase();
431*cdf0e10cSrcweir 				aVDev.DrawBitmap(rAnimBmp.aPosPix, aContent);
432*cdf0e10cSrcweir 
433*cdf0e10cSrcweir 				if(aMask.IsEmpty())
434*cdf0e10cSrcweir 				{
435*cdf0e10cSrcweir 					const Rectangle aRect(rAnimBmp.aPosPix, aContent.GetSizePixel());
436*cdf0e10cSrcweir 					aVDevMask.SetFillColor(COL_BLACK);
437*cdf0e10cSrcweir 					aVDevMask.SetLineColor();
438*cdf0e10cSrcweir 					aVDevMask.DrawRect(aRect);
439*cdf0e10cSrcweir 				}
440*cdf0e10cSrcweir 				else
441*cdf0e10cSrcweir 				{
442*cdf0e10cSrcweir 					aVDevMask.DrawBitmap(rAnimBmp.aPosPix, aMask);
443*cdf0e10cSrcweir 				}
444*cdf0e10cSrcweir 				break;
445*cdf0e10cSrcweir             }
446*cdf0e10cSrcweir 
447*cdf0e10cSrcweir             case DISPOSE_FULL:
448*cdf0e10cSrcweir             {
449*cdf0e10cSrcweir                 aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
450*cdf0e10cSrcweir                                    rAnimBmp.aBmpEx);
451*cdf0e10cSrcweir                 break;
452*cdf0e10cSrcweir             }
453*cdf0e10cSrcweir 
454*cdf0e10cSrcweir             case DISPOSE_PREVIOUS :
455*cdf0e10cSrcweir             {
456*cdf0e10cSrcweir                 aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
457*cdf0e10cSrcweir                                    rAnimBmp.aBmpEx);
458*cdf0e10cSrcweir                 aVDevMask.DrawBitmap(rAnimBmp.aPosPix,
459*cdf0e10cSrcweir                                      rAnimBmp.aBmpEx.GetMask());
460*cdf0e10cSrcweir                 break;
461*cdf0e10cSrcweir             }
462*cdf0e10cSrcweir         }
463*cdf0e10cSrcweir 
464*cdf0e10cSrcweir         // extract current aVDev content into a new animation
465*cdf0e10cSrcweir         // frame
466*cdf0e10cSrcweir         GDIMetaFileSharedPtr pMtf( new GDIMetaFile() );
467*cdf0e10cSrcweir         pMtf->AddAction(
468*cdf0e10cSrcweir             new MetaBmpExAction( aEmptyPoint,
469*cdf0e10cSrcweir                                  BitmapEx(
470*cdf0e10cSrcweir                                      aVDev.GetBitmap(
471*cdf0e10cSrcweir                                          aEmptyPoint,
472*cdf0e10cSrcweir                                          aAnimSize ),
473*cdf0e10cSrcweir                                      aVDevMask.GetBitmap(
474*cdf0e10cSrcweir                                          aEmptyPoint,
475*cdf0e10cSrcweir                                          aAnimSize ))));
476*cdf0e10cSrcweir 
477*cdf0e10cSrcweir         // setup mtf dimensions and pref map mode (for
478*cdf0e10cSrcweir         // simplicity, keep it all in pixel. the metafile
479*cdf0e10cSrcweir         // renderer scales it down to (1, 1) box anyway)
480*cdf0e10cSrcweir         pMtf->SetPrefMapMode( MapMode() );
481*cdf0e10cSrcweir         pMtf->SetPrefSize( aAnimSize );
482*cdf0e10cSrcweir 
483*cdf0e10cSrcweir         // #115934#
484*cdf0e10cSrcweir         // Take care of special value for MultiPage TIFFs. ATM these shall just
485*cdf0e10cSrcweir         // show their first page for _quite_ some time.
486*cdf0e10cSrcweir         sal_Int32 nWaitTime100thSeconds( rAnimBmp.nWait );
487*cdf0e10cSrcweir         if( ANIMATION_TIMEOUT_ON_CLICK == nWaitTime100thSeconds )
488*cdf0e10cSrcweir         {
489*cdf0e10cSrcweir             // ATM the huge value would block the timer, so use a long
490*cdf0e10cSrcweir             // time to show first page (whole day)
491*cdf0e10cSrcweir             nWaitTime100thSeconds = 100 * 60 * 60 * 24;
492*cdf0e10cSrcweir         }
493*cdf0e10cSrcweir 
494*cdf0e10cSrcweir         // There are animated GIFs with no WaitTime set. Take 0.1 sec, the
495*cdf0e10cSrcweir         // same duration that is used by the edit view.
496*cdf0e10cSrcweir         if( nWaitTime100thSeconds == 0 )
497*cdf0e10cSrcweir             nWaitTime100thSeconds = 10;
498*cdf0e10cSrcweir 
499*cdf0e10cSrcweir         o_rFrames.push_back( MtfAnimationFrame( pMtf,
500*cdf0e10cSrcweir                                                 nWaitTime100thSeconds / 100.0 ) );
501*cdf0e10cSrcweir     }
502*cdf0e10cSrcweir 
503*cdf0e10cSrcweir     return !o_rFrames.empty();
504*cdf0e10cSrcweir }
505*cdf0e10cSrcweir 
506*cdf0e10cSrcweir bool getRectanglesFromScrollMtf( ::basegfx::B2DRectangle&       o_rScrollRect,
507*cdf0e10cSrcweir                                  ::basegfx::B2DRectangle&       o_rPaintRect,
508*cdf0e10cSrcweir                                  const GDIMetaFileSharedPtr&    rMtf )
509*cdf0e10cSrcweir {
510*cdf0e10cSrcweir     // extract bounds: scroll rect, paint rect
511*cdf0e10cSrcweir     bool bScrollRectSet(false);
512*cdf0e10cSrcweir     bool bPaintRectSet(false);
513*cdf0e10cSrcweir 
514*cdf0e10cSrcweir     for ( MetaAction * pCurrAct = rMtf->FirstAction();
515*cdf0e10cSrcweir           pCurrAct != 0; pCurrAct = rMtf->NextAction() )
516*cdf0e10cSrcweir     {
517*cdf0e10cSrcweir         if (pCurrAct->GetType() == META_COMMENT_ACTION)
518*cdf0e10cSrcweir         {
519*cdf0e10cSrcweir             MetaCommentAction * pAct =
520*cdf0e10cSrcweir                 static_cast<MetaCommentAction *>(pCurrAct);
521*cdf0e10cSrcweir             // skip comment if not a special XTEXT comment
522*cdf0e10cSrcweir             if (pAct->GetComment().CompareIgnoreCaseToAscii(
523*cdf0e10cSrcweir                     RTL_CONSTASCII_STRINGPARAM("XTEXT") ) == COMPARE_EQUAL)
524*cdf0e10cSrcweir             {
525*cdf0e10cSrcweir                 if (pAct->GetComment().CompareIgnoreCaseToAscii(
526*cdf0e10cSrcweir                         "XTEXT_SCROLLRECT" ) == COMPARE_EQUAL) {
527*cdf0e10cSrcweir                     o_rScrollRect = ::vcl::unotools::b2DRectangleFromRectangle(
528*cdf0e10cSrcweir                         *reinterpret_cast<Rectangle const *>(
529*cdf0e10cSrcweir                             pAct->GetData() ) );
530*cdf0e10cSrcweir 
531*cdf0e10cSrcweir                     bScrollRectSet = true;
532*cdf0e10cSrcweir                 }
533*cdf0e10cSrcweir                 else if (pAct->GetComment().CompareIgnoreCaseToAscii(
534*cdf0e10cSrcweir                              "XTEXT_PAINTRECT" ) == COMPARE_EQUAL) {
535*cdf0e10cSrcweir                     o_rPaintRect = ::vcl::unotools::b2DRectangleFromRectangle(
536*cdf0e10cSrcweir                         *reinterpret_cast<Rectangle const *>(
537*cdf0e10cSrcweir                             pAct->GetData() ) );
538*cdf0e10cSrcweir 
539*cdf0e10cSrcweir                     bPaintRectSet = true;
540*cdf0e10cSrcweir                 }
541*cdf0e10cSrcweir             }
542*cdf0e10cSrcweir         }
543*cdf0e10cSrcweir     }
544*cdf0e10cSrcweir 
545*cdf0e10cSrcweir     return bScrollRectSet && bPaintRectSet;
546*cdf0e10cSrcweir }
547*cdf0e10cSrcweir 
548*cdf0e10cSrcweir }
549*cdf0e10cSrcweir }
550*cdf0e10cSrcweir 
551