Update ooo320-m1
[ooovba.git] / filter / source / flash / swfwriter2.cxx
blobb45df6ac6040425c7ac89e160514b52a67cf2667
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swfwriter2.cxx,v $
10 * $Revision: 1.10 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_filter.hxx"
33 #include "swfwriter.hxx"
34 #include <vcl/virdev.hxx>
36 #include <math.h>
38 using namespace ::swf;
39 using namespace ::std;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::io;
42 using ::rtl::OUString;
43 using ::rtl::OString;
45 // -----------------------------------------------------------------------------
47 sal_uInt16 getMaxBitsUnsigned( sal_uInt32 nValue )
49 sal_uInt16 nBits = 0;
51 while( nValue )
53 nBits++;
54 nValue >>= 1;
57 return nBits;
60 // -----------------------------------------------------------------------------
62 sal_uInt16 getMaxBitsSigned( sal_Int32 nValue )
64 if( nValue < 0 )
65 nValue *= -1;
67 return getMaxBitsUnsigned( static_cast< sal_uInt32 >(nValue) ) + 1;
70 // -----------------------------------------------------------------------------
72 BitStream::BitStream()
74 mnBitPos = 8;
75 mnCurrentByte = 0;
78 // -----------------------------------------------------------------------------
80 void BitStream::writeUB( sal_uInt32 nValue, sal_uInt16 nBits )
82 while( nBits != 0 )
84 mnCurrentByte |= nValue << (32 - nBits) >> (32 - mnBitPos);
86 if ( nBits > mnBitPos )
88 nBits = nBits - mnBitPos;
89 mnBitPos = 0;
91 else
93 mnBitPos = sal::static_int_cast<sal_uInt8>( mnBitPos - nBits );
94 nBits = 0;
97 if( 0 == mnBitPos )
98 pad();
102 // -----------------------------------------------------------------------------
104 void BitStream::writeSB( sal_Int32 nValue, sal_uInt16 nBits )
106 writeUB( static_cast< sal_uInt32 >(nValue), nBits );
109 // -----------------------------------------------------------------------------
111 void BitStream::writeFB( sal_uInt32 nValue, sal_uInt16 nBits )
113 writeUB( nValue, nBits );
116 // -----------------------------------------------------------------------------
118 void BitStream::pad()
120 if( 8 != mnBitPos )
122 maData.push_back( mnCurrentByte );
123 mnCurrentByte = 0;
124 mnBitPos = 8;
128 // -----------------------------------------------------------------------------
130 void BitStream::writeTo( SvStream& out )
132 pad();
134 vector< sal_uInt8 >::iterator aIter( maData.begin() );
135 const vector< sal_uInt8>::iterator aEnd( maData.end() );
136 while(aIter != aEnd)
138 out << (*aIter++);
142 // -----------------------------------------------------------------------------
144 sal_uInt32 BitStream::getOffset() const
146 return maData.size();
149 ////////////////////////////////////////////////////////////////////////////////
151 Tag::Tag( sal_uInt8 nTagId )
153 mnTagId = nTagId;
156 // -----------------------------------------------------------------------------
158 void Tag::write( SvStream &out )
160 Seek( STREAM_SEEK_TO_END );
161 sal_uInt32 nSz = Tell();
162 Seek( STREAM_SEEK_TO_BEGIN );
164 if( mnTagId != 0xff )
166 bool bLarge = nSz > 62;
168 sal_uInt16 nCode = ( mnTagId << 6 ) | ( bLarge ? 0x3f : _uInt16(nSz) );
170 out << (sal_uInt8)nCode;
171 out << (sal_uInt8)(nCode >> 8);
173 if( bLarge )
175 sal_uInt32 nTmp = nSz;
177 out << (sal_uInt8)nTmp;
178 nTmp >>= 8;
179 out << (sal_uInt8)nTmp;
180 nTmp >>= 8;
181 out << (sal_uInt8)nTmp;
182 nTmp >>= 8;
183 out << (sal_uInt8)nTmp;
187 out.Write( GetData(), nSz );
189 #if 0
190 // -----------------------------------------------------------------------------
192 void Tag::addI32( sal_Int32 nValue )
194 addUI32( static_cast<sal_uInt32>( nValue ) );
196 #endif
197 // -----------------------------------------------------------------------------
199 void Tag::addUI32( sal_uInt32 nValue )
201 *this << nValue;
203 #if 0
204 // -----------------------------------------------------------------------------
206 void Tag::addI16( sal_Int16 nValue )
208 addUI16( static_cast<sal_uInt16>( nValue ) );
210 #endif
211 // -----------------------------------------------------------------------------
213 void Tag::addUI16( sal_uInt16 nValue )
215 *this << (sal_uInt8)nValue;
216 *this << (sal_uInt8)(nValue >> 8);
219 // -----------------------------------------------------------------------------
221 void Tag::addUI8( sal_uInt8 nValue )
223 *this << (sal_uInt8)nValue;
226 // -----------------------------------------------------------------------------
228 void Tag::addBits( BitStream& rIn )
230 rIn.writeTo( *this );
233 // -----------------------------------------------------------------------------
235 void Tag::addRGBA( const Color& rColor )
237 addUI8( rColor.GetRed() );
238 addUI8( rColor.GetGreen() );
239 addUI8( rColor.GetBlue() );
240 addUI8( 0xff - rColor.GetTransparency() );
243 // -----------------------------------------------------------------------------
245 void Tag::addRGB( const Color& rColor )
247 addUI8( rColor.GetRed() );
248 addUI8( rColor.GetGreen() );
249 addUI8( rColor.GetBlue() );
252 // -----------------------------------------------------------------------------
254 void Tag::addRect( const Rectangle& rRect )
256 writeRect( *this, rRect );
259 // -----------------------------------------------------------------------------
261 void Tag::writeRect( SvStream& rOut, const Rectangle& rRect )
263 BitStream aBits;
265 sal_Int32 minX, minY, maxX, maxY;
267 if( rRect.nLeft < rRect.nRight )
269 minX = rRect.nLeft; maxX = rRect.nRight;
271 else
273 maxX = rRect.nLeft; minX = rRect.nRight;
277 if( rRect.nTop < rRect.nBottom )
279 minY = rRect.nTop; maxY = rRect.nBottom;
281 else
283 maxY = rRect.nTop; minY = rRect.nBottom;
286 // AS: Figure out the maximum nubmer of bits required to represent any of the
287 // rectangle coordinates. Since minX or minY could be negative, they could
288 // actually require more bits than maxX or maxY.
289 // AS: Christian, can they be negative, or is that a wasted check?
290 // CL: I think so, f.e. for shapes that have the top and/or left edge outside
291 // the page origin
292 sal_uInt8 nBits1 = sal::static_int_cast<sal_uInt8>( max( getMaxBitsSigned( minX ), getMaxBitsSigned( minY ) ) );
293 sal_uInt8 nBits2 = sal::static_int_cast<sal_uInt8>( max( getMaxBitsSigned( maxX ), getMaxBitsSigned( maxY ) ) );
294 sal_uInt8 nBitsMax = max( nBits1, nBits2 );
296 aBits.writeUB( nBitsMax, 5 );
297 aBits.writeSB( minX, nBitsMax );
298 aBits.writeSB( maxX, nBitsMax );
299 aBits.writeSB( minY, nBitsMax );
300 aBits.writeSB( maxY, nBitsMax );
302 aBits.writeTo( rOut );
305 // -----------------------------------------------------------------------------
307 void Tag::addMatrix( const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
309 writeMatrix( *this, rMatrix );
312 // -----------------------------------------------------------------------------
314 void Tag::writeMatrix( SvStream& rOut, const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
317 BitStream aBits;
319 const sal_uInt8 bHasScale = rMatrix.get(0, 0) != 1.0 || rMatrix.get(1, 1) != 1.0;
321 aBits.writeUB( bHasScale, 1 );
323 if( bHasScale )
325 sal_uInt8 nScaleBits = 31;
327 aBits.writeUB( nScaleBits, 5 );
328 aBits.writeFB( getFixed( rMatrix.get(0, 0) ), nScaleBits ); // Scale X
329 aBits.writeFB( getFixed( rMatrix.get(1, 1) ), nScaleBits ); // Scale Y
332 const sal_uInt8 bHasRotate = rMatrix.get(0, 1) != 0.0 || rMatrix.get(1, 0) != 0.0;
334 aBits.writeUB( bHasRotate, 1 );
336 if( bHasRotate )
338 sal_uInt8 nRotateBits = 31;
340 aBits.writeUB( nRotateBits, 5 );
341 aBits.writeFB( getFixed( rMatrix.get(0, 1) ), nRotateBits ); // RotateSkew0
342 aBits.writeFB( getFixed( rMatrix.get(1, 0) ), nRotateBits ); // RotateSkew1
345 sal_uInt8 nTranslateBits = 16;
347 aBits.writeUB( nTranslateBits, 5 );
348 aBits.writeSB( (sal_Int16)rMatrix.get(0, 2), nTranslateBits ); // Translate X
349 aBits.writeSB( (sal_Int16)rMatrix.get(1, 2), nTranslateBits ); // Translate Y
351 aBits.writeTo( rOut );
354 // -----------------------------------------------------------------------------
356 void Tag::addString( const char* pString )
358 if( pString )
360 while( *pString )
361 addUI8( *pString++ );
364 addUI8( 0 );
367 // -----------------------------------------------------------------------------
369 void Tag::addStream( SvStream& rIn )
371 *this << rIn;
374 ////////////////////////////////////////////////////////////////////////////////
376 Sprite::Sprite( sal_uInt16 nId )
377 : mnId( nId ), mnFrames(0)
381 // -----------------------------------------------------------------------------
383 Sprite::~Sprite()
385 for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); i++)
386 delete *i;
389 // -----------------------------------------------------------------------------
391 void Sprite::write( SvStream& out )
393 SvMemoryStream aTmp;
394 for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); i++)
395 (*i)->write( aTmp );
397 if( !mnFrames )
398 mnFrames = 1;
400 aTmp.Seek(0);
402 Tag aTag( TAG_DEFINESPRITE );
403 aTag.addUI16( mnId );
404 aTag.addUI16( _uInt16( mnFrames ) );
405 aTag.addStream( aTmp );
406 aTag.write( out );
409 // -----------------------------------------------------------------------------
411 void Sprite::addTag( Tag* pNewTag )
413 if( pNewTag )
415 if( pNewTag->getTagId() == TAG_SHOWFRAME )
416 mnFrames++;
418 maTags.push_back( pNewTag );
422 /////////////////////////////////////////////////////////////////////////////////
424 sal_uInt32 swf::getFixed( double fValue )
426 sal_Int16 nUpper = (sal_Int16)floor(fValue);
427 sal_uInt16 nLower = (sal_uInt16)((fValue - floor(fValue))*0x10000);
429 sal_uInt32 temp = ((sal_Int32)nUpper)<<16;
430 temp |= nLower;
432 return temp;
435 /////////////////////////////////////////////////////////////////////////////////
437 /** constructs a new flash font for the given VCL Font */
438 FlashFont::FlashFont( const Font& rFont, sal_uInt16 nId )
439 : maFont( rFont ), mnNextIndex(0), mnId( nId )
443 // -----------------------------------------------------------------------------
445 FlashFont::~FlashFont()
449 // -----------------------------------------------------------------------------
451 /** gets the glyph id for the given character. The glyphs are created on demand */
452 sal_uInt16 FlashFont::getGlyph( sal_uInt16 nChar, VirtualDevice* pVDev )
454 // see if we already created a glyph for this character
455 std::map<sal_uInt16, sal_uInt16, ltuint16>::iterator aIter( maGlyphIndex.find(nChar) );
456 if( aIter != maGlyphIndex.end() )
458 return aIter->second;
461 // if not, we create one now
463 maGlyphIndex[nChar] = mnNextIndex;
465 Font aOldFont( pVDev->GetFont() );
466 Font aNewFont( aOldFont );
467 aNewFont.SetAlign( ALIGN_BASELINE );
468 pVDev->SetFont( aNewFont );
469 aOldFont.SetOrientation(0);
471 // let the virtual device convert the character to polygons
472 PolyPolygon aPolyPoly;
473 pVDev->GetTextOutline( aPolyPoly, nChar );
475 maGlyphOffsets.push_back( _uInt16( maGlyphData.getOffset() ) );
477 // Number of fill and line index bits set to 1
478 maGlyphData.writeUB( 0x11, 8 );
480 const sal_uInt16 nCount = aPolyPoly.Count();
481 sal_uInt16 i,n;
482 for( i = 0; i < nCount; i++ )
484 Polygon& rPoly = aPolyPoly[ i ];
486 const USHORT nSize = rPoly.GetSize();
487 if( nSize )
489 // convert polygon to flash EM_SQUARE (1024x1024)
490 for( n = 0; n < nSize; n++ )
492 Point aPoint( rPoly[n] );
493 aPoint.X() = static_cast<long>((double(aPoint.X()) * 1024.0 ) / double(aOldFont.GetHeight()));
494 aPoint.Y() = static_cast<long>((double(aPoint.Y()) * 1024.0 ) / double(aOldFont.GetHeight()));
495 rPoly[n] = aPoint;
497 Writer::Impl_addPolygon( maGlyphData, rPoly, true );
500 Writer::Impl_addEndShapeRecord( maGlyphData );
502 maGlyphData.pad();
504 pVDev->SetFont( aOldFont );
506 return mnNextIndex++;
509 // -----------------------------------------------------------------------------
511 void FlashFont::write( SvStream& out )
513 Tag aTag( TAG_DEFINEFONT );
515 aTag.addUI16( mnId );
517 sal_uInt16 nGlyphs = _uInt16( maGlyphOffsets.size() );
518 sal_uInt16 nOffset = nGlyphs * sizeof( sal_uInt16 );
520 for(vector< sal_uInt16 >::iterator i = maGlyphOffsets.begin(); i != maGlyphOffsets.end(); i++)
521 aTag.addUI16( nOffset + (*i) );
523 aTag.addBits( maGlyphData );
525 aTag.write( out );
528 ////////////////////////////////////////////////////////////////////////////////
530 /** this c'tor creates a solid fill style */
531 FillStyle::FillStyle( const Color& rSolidColor )
532 : meType( solid ),
533 maColor( rSolidColor )
537 // -----------------------------------------------------------------------------
539 /** this c'tor creates a tiled or clipped bitmap fill style */
540 FillStyle::FillStyle( sal_uInt16 nBitmapId, bool bClipped, const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
541 : meType( bClipped ? clipped_bitmap : tiled_bitmap ),
542 maMatrix( rMatrix ),
543 mnBitmapId( nBitmapId )
547 // -----------------------------------------------------------------------------
549 FillStyle::FillStyleType Impl_getFillStyleType( const Gradient& rGradient )
551 switch( rGradient.GetStyle() )
553 case GradientStyle_ELLIPTICAL:
554 case GradientStyle_RADIAL:
555 return FillStyle::radial_gradient;
556 // case GradientStyle_AXIAL:
557 // case GradientStyle_SQUARE:
558 // case GradientStyle_RECT:
559 // case GradientStyle_LINEAR:
560 default:
561 return FillStyle::linear_gradient;
565 // -----------------------------------------------------------------------------
567 /** this c'tor creates a linear or radial gradient fill style */
568 FillStyle::FillStyle( const Rectangle& rBoundRect, const Gradient& rGradient )
569 : meType( Impl_getFillStyleType( rGradient ) ),
570 maGradient( rGradient ),
571 maBoundRect( rBoundRect )
575 // -----------------------------------------------------------------------------
577 void FillStyle::addTo( Tag* pTag ) const
579 pTag->addUI8( sal::static_int_cast<sal_uInt8>( meType ) );
580 switch( meType )
582 case solid:
583 pTag->addRGBA( maColor );
584 break;
585 case linear_gradient:
586 case radial_gradient:
587 Impl_addGradient( pTag );
588 break;
589 case tiled_bitmap:
590 case clipped_bitmap:
591 pTag->addUI16( mnBitmapId );
592 pTag->addMatrix( maMatrix );
593 break;
597 // -----------------------------------------------------------------------------
599 struct GradRecord
601 sal_uInt8 mnRatio;
602 Color maColor;
604 GradRecord( sal_uInt8 nRatio, const Color& rColor ) : mnRatio( nRatio ), maColor( rColor ) {}
607 // TODO: better emulation of our gradients
608 void FillStyle::Impl_addGradient( Tag* pTag ) const
610 vector< struct GradRecord > aGradientRecords;
612 ::basegfx::B2DHomMatrix m; // #i73264#
614 m.rotate( (maGradient.GetAngle() - 900) * F_PI1800 );
616 switch( maGradient.GetStyle() )
618 case GradientStyle_ELLIPTICAL:
619 case GradientStyle_RADIAL:
621 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) );
622 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetStartColor() ) );
624 double tx = ( maGradient.GetOfsX() * 32768.0 ) / 100.0;
625 double ty = ( maGradient.GetOfsY() * 32768.0 ) / 100.0;
626 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
627 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
629 m.scale( 1.2, 1.2 );
631 if( scalex > scaley )
633 double scale_move = scaley / scalex;
635 m.translate( tx, scale_move * ty );
638 m.scale( scalex, scalex );
640 else
642 double scale_move = scalex / scaley;
644 m.translate( scale_move * tx, ty );
647 m.scale( scaley, scaley );
651 break;
652 case GradientStyle_AXIAL:
654 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) );
655 aGradientRecords.push_back( GradRecord( 0x80, maGradient.GetStartColor() ) );
656 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) );
657 double tx = ( 32768.0 / 2.0 );
658 double ty = ( 32768.0 / 2.0 );
659 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
660 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
662 m.translate( tx, ty );
663 m.scale( scalex, scaley );
665 break;
666 case GradientStyle_SQUARE:
667 case GradientStyle_RECT:
668 case GradientStyle_LINEAR:
670 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetStartColor() ) );
671 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) );
672 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
673 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
675 m.scale( scalex, scaley );
677 m.translate( maBoundRect.GetWidth() / 2.0, maBoundRect.GetHeight() / 2.0 );
679 break;
680 case GradientStyle_FORCE_EQUAL_SIZE: break;
683 m.translate( maBoundRect.nLeft, maBoundRect.nTop );
685 pTag->addMatrix( m );
687 DBG_ASSERT( aGradientRecords.size() < 8, "Illegal FlashGradient!" );
689 pTag->addUI8( static_cast<sal_uInt8>( aGradientRecords.size() ) );
691 for(std::vector< GradRecord >::iterator i = aGradientRecords.begin(); i != aGradientRecords.end(); i++)
693 pTag->addUI8( (*i).mnRatio );
694 pTag->addRGBA( (*i).maColor );