1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swfwriter2.cxx,v $
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>
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
;
45 // -----------------------------------------------------------------------------
47 sal_uInt16
getMaxBitsUnsigned( sal_uInt32 nValue
)
60 // -----------------------------------------------------------------------------
62 sal_uInt16
getMaxBitsSigned( sal_Int32 nValue
)
67 return getMaxBitsUnsigned( static_cast< sal_uInt32
>(nValue
) ) + 1;
70 // -----------------------------------------------------------------------------
72 BitStream::BitStream()
78 // -----------------------------------------------------------------------------
80 void BitStream::writeUB( sal_uInt32 nValue
, sal_uInt16 nBits
)
84 mnCurrentByte
|= nValue
<< (32 - nBits
) >> (32 - mnBitPos
);
86 if ( nBits
> mnBitPos
)
88 nBits
= nBits
- mnBitPos
;
93 mnBitPos
= sal::static_int_cast
<sal_uInt8
>( mnBitPos
- nBits
);
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()
122 maData
.push_back( mnCurrentByte
);
128 // -----------------------------------------------------------------------------
130 void BitStream::writeTo( SvStream
& out
)
134 vector
< sal_uInt8
>::iterator
aIter( maData
.begin() );
135 const vector
< sal_uInt8
>::iterator
aEnd( maData
.end() );
142 // -----------------------------------------------------------------------------
144 sal_uInt32
BitStream::getOffset() const
146 return maData
.size();
149 ////////////////////////////////////////////////////////////////////////////////
151 Tag::Tag( sal_uInt8 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);
175 sal_uInt32 nTmp
= nSz
;
177 out
<< (sal_uInt8
)nTmp
;
179 out
<< (sal_uInt8
)nTmp
;
181 out
<< (sal_uInt8
)nTmp
;
183 out
<< (sal_uInt8
)nTmp
;
187 out
.Write( GetData(), nSz
);
190 // -----------------------------------------------------------------------------
192 void Tag::addI32( sal_Int32 nValue
)
194 addUI32( static_cast<sal_uInt32
>( nValue
) );
197 // -----------------------------------------------------------------------------
199 void Tag::addUI32( sal_uInt32 nValue
)
204 // -----------------------------------------------------------------------------
206 void Tag::addI16( sal_Int16 nValue
)
208 addUI16( static_cast<sal_uInt16
>( nValue
) );
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
)
265 sal_Int32 minX
, minY
, maxX
, maxY
;
267 if( rRect
.nLeft
< rRect
.nRight
)
269 minX
= rRect
.nLeft
; maxX
= rRect
.nRight
;
273 maxX
= rRect
.nLeft
; minX
= rRect
.nRight
;
277 if( rRect
.nTop
< rRect
.nBottom
)
279 minY
= rRect
.nTop
; maxY
= rRect
.nBottom
;
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
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#
319 const sal_uInt8 bHasScale
= rMatrix
.get(0, 0) != 1.0 || rMatrix
.get(1, 1) != 1.0;
321 aBits
.writeUB( bHasScale
, 1 );
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 );
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
)
361 addUI8( *pString
++ );
367 // -----------------------------------------------------------------------------
369 void Tag::addStream( SvStream
& rIn
)
374 ////////////////////////////////////////////////////////////////////////////////
376 Sprite::Sprite( sal_uInt16 nId
)
377 : mnId( nId
), mnFrames(0)
381 // -----------------------------------------------------------------------------
385 for(vector
< Tag
* >::iterator i
= maTags
.begin(); i
!= maTags
.end(); i
++)
389 // -----------------------------------------------------------------------------
391 void Sprite::write( SvStream
& out
)
394 for(vector
< Tag
* >::iterator i
= maTags
.begin(); i
!= maTags
.end(); i
++)
402 Tag
aTag( TAG_DEFINESPRITE
);
403 aTag
.addUI16( mnId
);
404 aTag
.addUI16( _uInt16( mnFrames
) );
405 aTag
.addStream( aTmp
);
409 // -----------------------------------------------------------------------------
411 void Sprite::addTag( Tag
* pNewTag
)
415 if( pNewTag
->getTagId() == TAG_SHOWFRAME
)
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;
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();
482 for( i
= 0; i
< nCount
; i
++ )
484 Polygon
& rPoly
= aPolyPoly
[ i
];
486 const USHORT nSize
= rPoly
.GetSize();
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()));
497 Writer::Impl_addPolygon( maGlyphData
, rPoly
, true );
500 Writer::Impl_addEndShapeRecord( maGlyphData
);
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
);
528 ////////////////////////////////////////////////////////////////////////////////
530 /** this c'tor creates a solid fill style */
531 FillStyle::FillStyle( const Color
& rSolidColor
)
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
),
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:
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
) );
583 pTag
->addRGBA( maColor
);
585 case linear_gradient
:
586 case radial_gradient
:
587 Impl_addGradient( pTag
);
591 pTag
->addUI16( mnBitmapId
);
592 pTag
->addMatrix( maMatrix
);
597 // -----------------------------------------------------------------------------
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;
631 if( scalex
> scaley
)
633 double scale_move
= scaley
/ scalex
;
635 m
.translate( tx
, scale_move
* ty
);
638 m
.scale( scalex
, scalex
);
642 double scale_move
= scalex
/ scaley
;
644 m
.translate( scale_move
* tx
, ty
);
647 m
.scale( scaley
, scaley
);
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
);
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 );
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
);