Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "swfwriter.hxx"
21 : #include <vcl/virdev.hxx>
22 : #include <vcl/gdimtf.hxx>
23 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
24 :
25 : using namespace ::swf;
26 : using namespace ::std;
27 : using namespace ::com::sun::star::uno;
28 : using namespace ::com::sun::star::io;
29 :
30 :
31 :
32 1 : static MapMode aTWIPSMode( MAP_TWIP );
33 1 : static MapMode a100thmmMode( MAP_100TH_MM );
34 :
35 0 : static sal_Int32 map100thmm( sal_Int32 n100thMM )
36 : {
37 0 : Point aPoint( n100thMM, n100thMM );
38 0 : sal_Int32 nX = OutputDevice::LogicToLogic( aPoint, a100thmmMode, aTWIPSMode ).X();
39 0 : return nX;
40 : }
41 :
42 :
43 :
44 0 : Writer::Writer( sal_Int32 nTWIPWidthOutput, sal_Int32 nTWIPHeightOutput, sal_Int32 nDocWidthInput, sal_Int32 nDocHeightInput, sal_Int32 nJPEGcompressMode )
45 : : mpClipPolyPolygon( NULL ),
46 : mpTag( NULL ),
47 : mpSprite( NULL ),
48 : mnNextId( 1 ),
49 : mnGlobalTransparency(0),
50 0 : mnJPEGCompressMode(nJPEGcompressMode)
51 : {
52 0 : mpVDev->EnableOutput( false );
53 :
54 0 : maMovieTempFile.EnableKillingFile();
55 0 : maFontsTempFile.EnableKillingFile();
56 :
57 0 : mpMovieStream = maMovieTempFile.GetStream( StreamMode::WRITE|StreamMode::TRUNC );
58 0 : mpFontsStream = maFontsTempFile.GetStream( StreamMode::WRITE|StreamMode::TRUNC );
59 :
60 0 : mnFrames = 0;
61 :
62 0 : mnDocWidth = map100thmm( nDocWidthInput );
63 0 : mnDocHeight = map100thmm( nDocHeightInput );
64 :
65 0 : mnDocXScale = (double)nTWIPWidthOutput / mnDocWidth;
66 0 : mnDocYScale = (double)nTWIPHeightOutput / mnDocHeight;
67 :
68 : // define an invisible button with the size of a page
69 0 : Rectangle aRect( 0, 0, (long)( mnDocWidth * mnDocXScale ), (long)( mnDocHeight * mnDocYScale ) );
70 0 : Polygon aPoly( aRect );
71 0 : FillStyle aFill = FillStyle( Color(COL_WHITE) );
72 0 : mnWhiteBackgroundShapeId = defineShape( aPoly, aFill );
73 :
74 0 : ::basegfx::B2DHomMatrix m; // #i73264#
75 0 : mnPageButtonId = createID();
76 0 : startTag( TAG_DEFINEBUTTON );
77 0 : mpTag->addUI16( mnPageButtonId ); // character id for button
78 :
79 : // button records
80 0 : mpTag->addUI8( 0x08 ); // only hit state
81 0 : mpTag->addUI16( mnWhiteBackgroundShapeId ); // shape id of background rectangle
82 0 : mpTag->addUI16( 0 ); // depth for button DANGER!
83 0 : mpTag->addMatrix( m ); // identity matrix
84 0 : mpTag->addUI8( 0 ); // empty color transform
85 :
86 : // mpTag->addUI8( 0 ); // end of button records
87 :
88 : // action records
89 0 : mpTag->addUI8( 0x06 ); // ActionPlay
90 0 : mpTag->addUI8( 0 ); // end of action records
91 :
92 0 : endTag();
93 :
94 : // place a shape that clips shapes depth 2-3 to document boundaries
95 : // placeShape( mnWhiteBackgroundShapeId, 1, 0, 0, 4 );
96 0 : }
97 :
98 :
99 :
100 0 : Writer::~Writer()
101 : {
102 0 : mpVDev.disposeAndClear();
103 0 : delete mpSprite;
104 0 : delete mpTag;
105 0 : }
106 :
107 :
108 :
109 0 : void ImplCopySvStreamToXOutputStream( SvStream& rIn, Reference< XOutputStream > &xOut )
110 : {
111 0 : sal_uInt32 nBufferSize = 64*1024;
112 :
113 0 : rIn.Seek( STREAM_SEEK_TO_END );
114 0 : sal_uInt32 nSize = rIn.Tell();
115 0 : rIn.Seek( STREAM_SEEK_TO_BEGIN );
116 :
117 0 : Sequence< sal_Int8 > aBuffer( min( nBufferSize, nSize ) );
118 :
119 0 : while( nSize )
120 : {
121 0 : if( nSize < nBufferSize )
122 : {
123 0 : nBufferSize = nSize;
124 0 : aBuffer.realloc( nSize );
125 : }
126 :
127 0 : sal_uInt32 nRead = rIn.Read( aBuffer.getArray(), nBufferSize );
128 : DBG_ASSERT( nRead == nBufferSize, "ImplCopySvStreamToXOutputStream failed!" );
129 0 : xOut->writeBytes( aBuffer );
130 :
131 0 : if( nRead == 0 )
132 0 : break;
133 :
134 0 : nSize -= nRead;
135 0 : }
136 0 : }
137 :
138 :
139 :
140 0 : void Writer::storeTo( Reference< XOutputStream > &xOutStream )
141 : {
142 0 : for(FontMap::iterator i = maFonts.begin(); i != maFonts.end(); ++i)
143 : {
144 0 : FlashFont* pFont = (*i);
145 0 : pFont->write( *mpFontsStream );
146 0 : delete pFont;
147 : }
148 :
149 : // Endtag
150 0 : mpMovieStream->WriteUInt16( 0 );
151 :
152 0 : Tag aHeader( 0xff );
153 :
154 0 : aHeader.addUI8( 'F' );
155 0 : aHeader.addUI8( 'W' );
156 0 : aHeader.addUI8( 'S' );
157 0 : aHeader.addUI8( 5 );
158 :
159 0 : sal_uInt32 nSizePos = aHeader.Tell();
160 :
161 0 : aHeader.WriteUInt32( 0 );
162 :
163 0 : Rectangle aDocRect( 0, 0, static_cast<long>(mnDocWidth*mnDocXScale), static_cast<long>(mnDocHeight*mnDocYScale) );
164 :
165 0 : aHeader.addRect( aDocRect );
166 :
167 : // frame delay in 8.8 fixed number of frames per second
168 0 : aHeader.addUI8( 0 );
169 0 : aHeader.addUI8( 12 );
170 :
171 0 : aHeader.addUI16( _uInt16(mnFrames) );
172 :
173 0 : const sal_uInt32 nSize = aHeader.Tell() + mpFontsStream->Tell() + mpMovieStream->Tell();
174 :
175 0 : aHeader.Seek( nSizePos );
176 0 : aHeader.WriteUInt32( nSize );
177 :
178 0 : ImplCopySvStreamToXOutputStream( aHeader, xOutStream );
179 0 : ImplCopySvStreamToXOutputStream( *mpFontsStream, xOutStream );
180 0 : ImplCopySvStreamToXOutputStream( *mpMovieStream, xOutStream );
181 0 : }
182 :
183 :
184 :
185 0 : sal_uInt16 Writer::startSprite()
186 : {
187 0 : sal_uInt16 nShapeId = createID();
188 0 : mvSpriteStack.push(mpSprite);
189 0 : mpSprite = new Sprite( nShapeId );
190 0 : return nShapeId;
191 : }
192 :
193 :
194 :
195 0 : void Writer::endSprite()
196 : {
197 0 : if( mpSprite )
198 : {
199 0 : startTag( TAG_END );
200 0 : endTag();
201 :
202 0 : mpSprite->write( *mpMovieStream );
203 0 : delete mpSprite;
204 :
205 0 : if (!mvSpriteStack.empty())
206 : {
207 0 : mpSprite = mvSpriteStack.top();
208 0 : mvSpriteStack.pop();
209 : }
210 : else
211 0 : mpSprite = NULL;
212 : }
213 0 : }
214 :
215 :
216 :
217 0 : void Writer::placeShape( sal_uInt16 nID, sal_uInt16 nDepth, sal_Int32 x, sal_Int32 y, sal_uInt16 nClip, const char* pName )
218 : {
219 0 : startTag( TAG_PLACEOBJECT2 );
220 :
221 0 : BitStream aBits;
222 :
223 0 : aBits.writeUB( sal_uInt32(nClip != 0), 1 ); // Has Clip Actions?
224 0 : aBits.writeUB( 0, 1 ); // reserved
225 0 : aBits.writeUB( sal_uInt32(pName != NULL), 1 ); // has a name
226 0 : aBits.writeUB( 0, 1 ); // no ratio
227 0 : aBits.writeUB( 0, 1 ); // no color transform
228 0 : aBits.writeUB( 1, 1 ); // has a matrix
229 0 : aBits.writeUB( 1, 1 ); // places a character
230 0 : aBits.writeUB( 0, 1 ); // does not define a character to be moved
231 :
232 0 : mpTag->addBits( aBits );
233 0 : mpTag->addUI16( nDepth ); // depth
234 0 : mpTag->addUI16( nID ); // character Id
235 :
236 : // #i73264#
237 : const basegfx::B2DHomMatrix aMatrix(basegfx::tools::createTranslateB2DHomMatrix(
238 0 : _Int16(static_cast<long>(map100thmm(x)*mnDocXScale)),
239 0 : _Int16(static_cast<long>(map100thmm(y)*mnDocYScale))));
240 0 : mpTag->addMatrix( aMatrix ); // transformation matrix
241 :
242 0 : if( pName )
243 0 : mpTag->addString( pName );
244 :
245 0 : if( nClip != 0 )
246 0 : mpTag->addUI16( nClip );
247 :
248 0 : endTag();
249 0 : }
250 :
251 :
252 :
253 0 : void Writer::removeShape( sal_uInt16 nDepth )
254 : {
255 0 : startTag( TAG_REMOVEOBJECT2 );
256 0 : mpTag->addUI16( nDepth ); // depth
257 0 : endTag();
258 0 : }
259 :
260 :
261 :
262 0 : void Writer::startTag( sal_uInt8 nTagId )
263 : {
264 : DBG_ASSERT( mpTag == NULL, "Last tag was not ended");
265 :
266 0 : mpTag = new Tag( nTagId );
267 0 : }
268 :
269 :
270 :
271 0 : void Writer::endTag()
272 : {
273 0 : sal_uInt8 nTag = mpTag->getTagId();
274 :
275 0 : if( mpSprite && ( (nTag == TAG_END) || (nTag == TAG_SHOWFRAME) || (nTag == TAG_DOACTION) || (nTag == TAG_STARTSOUND) || (nTag == TAG_PLACEOBJECT) || (nTag == TAG_PLACEOBJECT2) || (nTag == TAG_REMOVEOBJECT2) || (nTag == TAG_FRAMELABEL) ) )
276 : {
277 0 : mpSprite->addTag( mpTag );
278 0 : mpTag = NULL;
279 : }
280 : else
281 : {
282 0 : mpTag->write( *mpMovieStream );
283 0 : delete mpTag;
284 0 : mpTag = NULL;
285 : }
286 0 : }
287 :
288 :
289 :
290 0 : void Writer::showFrame()
291 : {
292 0 : startTag( TAG_SHOWFRAME );
293 0 : endTag();
294 :
295 0 : if(NULL == mpSprite)
296 0 : mnFrames++;
297 0 : }
298 :
299 :
300 :
301 0 : sal_uInt16 Writer::defineShape( const GDIMetaFile& rMtf, sal_Int16 x, sal_Int16 y )
302 : {
303 0 : mpVDev->SetMapMode( rMtf.GetPrefMapMode() );
304 0 : Impl_writeActions( rMtf );
305 :
306 0 : sal_uInt16 nId = 0;
307 : {
308 0 : CharacterIdVector::iterator aIter( maShapeIds.begin() );
309 0 : const CharacterIdVector::iterator aEnd( maShapeIds.end() );
310 :
311 0 : bool bHaveShapes = aIter != aEnd;
312 :
313 0 : if (bHaveShapes)
314 : {
315 0 : nId = startSprite();
316 :
317 0 : sal_uInt16 iDepth = 1;
318 0 : for(; aIter != aEnd; ++aIter)
319 : {
320 0 : placeShape( *aIter, iDepth++, x, y );
321 : }
322 :
323 0 : endSprite();
324 : }
325 : }
326 :
327 0 : maShapeIds.clear();
328 :
329 0 : return nId;
330 : }
331 :
332 :
333 :
334 0 : sal_uInt16 Writer::defineShape( const Polygon& rPoly, const FillStyle& rFillStyle )
335 : {
336 0 : const tools::PolyPolygon aPolyPoly( rPoly );
337 0 : return defineShape( aPolyPoly, rFillStyle );
338 : }
339 :
340 :
341 :
342 0 : sal_uInt16 Writer::defineShape( const tools::PolyPolygon& rPolyPoly, const FillStyle& rFillStyle )
343 : {
344 0 : sal_uInt16 nShapeId = createID();
345 :
346 : // start a DefineShape3 tag
347 0 : startTag( TAG_DEFINESHAPE3 );
348 :
349 0 : mpTag->addUI16( nShapeId );
350 0 : mpTag->addRect( rPolyPoly.GetBoundRect() );
351 :
352 :
353 : // FILLSTYLEARRAY
354 0 : mpTag->addUI8( 1 ); // FillStyleCount
355 :
356 : // FILLSTYLE
357 0 : rFillStyle.addTo( mpTag );
358 :
359 : // LINESTYLEARRAY
360 0 : mpTag->addUI8( 0 ); // LineStyleCount
361 :
362 : // Number of fill and line index bits to 1
363 0 : mpTag->addUI8( 0x11 );
364 :
365 0 : BitStream aBits;
366 :
367 0 : const sal_uInt16 nCount = rPolyPoly.Count();
368 : sal_uInt16 i;
369 0 : for( i = 0; i < nCount; i++ )
370 : {
371 0 : const Polygon& rPoly = rPolyPoly[ i ];
372 0 : if( rPoly.GetSize() )
373 0 : Impl_addPolygon( aBits, rPoly, true );
374 : }
375 :
376 0 : Impl_addEndShapeRecord( aBits );
377 :
378 0 : mpTag->addBits( aBits );
379 0 : endTag();
380 :
381 0 : return nShapeId;
382 : }
383 :
384 :
385 :
386 0 : sal_uInt16 Writer::defineShape( const tools::PolyPolygon& rPolyPoly, sal_uInt16 nLineWidth, const Color& rLineColor )
387 : {
388 0 : sal_uInt16 nShapeId = createID();
389 :
390 : // start a DefineShape3 tag
391 0 : startTag( TAG_DEFINESHAPE3 );
392 :
393 0 : mpTag->addUI16( nShapeId );
394 0 : mpTag->addRect( rPolyPoly.GetBoundRect() );
395 :
396 :
397 : // FILLSTYLEARRAY
398 0 : mpTag->addUI8( 0 ); // FillStyleCount
399 :
400 : // LINESTYLEARRAY
401 0 : mpTag->addUI8( 1 ); // LineStyleCount
402 :
403 : // LINESTYLE
404 0 : mpTag->addUI16( nLineWidth ); // Width of line in twips
405 0 : mpTag->addRGBA( rLineColor ); // Color
406 :
407 : // Number of fill and line index bits to 1
408 0 : mpTag->addUI8( 0x11 );
409 :
410 0 : BitStream aBits;
411 :
412 0 : const sal_uInt16 nCount = rPolyPoly.Count();
413 : sal_uInt16 i;
414 0 : for( i = 0; i < nCount; i++ )
415 : {
416 0 : const Polygon& rPoly = rPolyPoly[ i ];
417 0 : if( rPoly.GetSize() )
418 0 : Impl_addPolygon( aBits, rPoly, false );
419 : }
420 :
421 0 : Impl_addEndShapeRecord( aBits );
422 :
423 0 : mpTag->addBits( aBits );
424 0 : endTag();
425 :
426 0 : return nShapeId;
427 : }
428 :
429 :
430 :
431 :
432 0 : void Writer::stop()
433 : {
434 0 : startTag( TAG_DOACTION );
435 0 : mpTag->addUI8( 0x07 );
436 0 : mpTag->addUI8( 0 );
437 0 : endTag();
438 0 : }
439 :
440 :
441 :
442 0 : void Writer::waitOnClick( sal_uInt16 nDepth )
443 : {
444 0 : placeShape( _uInt16( mnPageButtonId ), nDepth, 0, 0 );
445 0 : stop();
446 0 : showFrame();
447 0 : removeShape( nDepth );
448 0 : }
449 :
450 :
451 :
452 : /** inserts a doaction tag with an ActionGotoFrame */
453 0 : void Writer::gotoFrame( sal_uInt16 nFrame )
454 : {
455 0 : startTag( TAG_DOACTION );
456 0 : mpTag->addUI8( 0x81 );
457 0 : mpTag->addUI16( 2 );
458 0 : mpTag->addUI16( nFrame );
459 0 : mpTag->addUI8( 0 );
460 0 : endTag();
461 3 : }
462 :
463 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|