diff options
Diffstat (limited to 'filter/source/flash/swfwriter2.cxx')
-rw-r--r-- | filter/source/flash/swfwriter2.cxx | 692 |
1 files changed, 692 insertions, 0 deletions
diff --git a/filter/source/flash/swfwriter2.cxx b/filter/source/flash/swfwriter2.cxx new file mode 100644 index 000000000000..a2638b13e629 --- /dev/null +++ b/filter/source/flash/swfwriter2.cxx @@ -0,0 +1,692 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_filter.hxx" +#include "swfwriter.hxx" +#include <vcl/virdev.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include <math.h> + +using namespace ::swf; +using namespace ::std; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using ::rtl::OUString; +using ::rtl::OString; + +// ----------------------------------------------------------------------------- + +sal_uInt16 getMaxBitsUnsigned( sal_uInt32 nValue ) +{ + sal_uInt16 nBits = 0; + + while( nValue ) + { + nBits++; + nValue >>= 1; + } + + return nBits; +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 getMaxBitsSigned( sal_Int32 nValue ) +{ + if( nValue < 0 ) + nValue *= -1; + + return getMaxBitsUnsigned( static_cast< sal_uInt32 >(nValue) ) + 1; +} + +// ----------------------------------------------------------------------------- + +BitStream::BitStream() +{ + mnBitPos = 8; + mnCurrentByte = 0; +} + +// ----------------------------------------------------------------------------- + +void BitStream::writeUB( sal_uInt32 nValue, sal_uInt16 nBits ) +{ + while( nBits != 0 ) + { + mnCurrentByte |= nValue << (32 - nBits) >> (32 - mnBitPos); + + if ( nBits > mnBitPos ) + { + nBits = nBits - mnBitPos; + mnBitPos = 0; + } + else + { + mnBitPos = sal::static_int_cast<sal_uInt8>( mnBitPos - nBits ); + nBits = 0; + } + + if( 0 == mnBitPos ) + pad(); + } +} + +// ----------------------------------------------------------------------------- + +void BitStream::writeSB( sal_Int32 nValue, sal_uInt16 nBits ) +{ + writeUB( static_cast< sal_uInt32 >(nValue), nBits ); +} + +// ----------------------------------------------------------------------------- + +void BitStream::writeFB( sal_uInt32 nValue, sal_uInt16 nBits ) +{ + writeUB( nValue, nBits ); +} + +// ----------------------------------------------------------------------------- + +void BitStream::pad() +{ + if( 8 != mnBitPos ) + { + maData.push_back( mnCurrentByte ); + mnCurrentByte = 0; + mnBitPos = 8; + } +} + +// ----------------------------------------------------------------------------- + +void BitStream::writeTo( SvStream& out ) +{ + pad(); + + vector< sal_uInt8 >::iterator aIter( maData.begin() ); + const vector< sal_uInt8>::iterator aEnd( maData.end() ); + while(aIter != aEnd) + { + out << (*aIter++); + } +} + +// ----------------------------------------------------------------------------- + +sal_uInt32 BitStream::getOffset() const +{ + return maData.size(); +} + +//////////////////////////////////////////////////////////////////////////////// + +Tag::Tag( sal_uInt8 nTagId ) +{ + mnTagId = nTagId; +} + +// ----------------------------------------------------------------------------- + +void Tag::write( SvStream &out ) +{ + Seek( STREAM_SEEK_TO_END ); + sal_uInt32 nSz = Tell(); + Seek( STREAM_SEEK_TO_BEGIN ); + + if( mnTagId != 0xff ) + { + bool bLarge = nSz > 62; + + sal_uInt16 nCode = ( mnTagId << 6 ) | ( bLarge ? 0x3f : _uInt16(nSz) ); + + out << (sal_uInt8)nCode; + out << (sal_uInt8)(nCode >> 8); + + if( bLarge ) + { + sal_uInt32 nTmp = nSz; + + out << (sal_uInt8)nTmp; + nTmp >>= 8; + out << (sal_uInt8)nTmp; + nTmp >>= 8; + out << (sal_uInt8)nTmp; + nTmp >>= 8; + out << (sal_uInt8)nTmp; + } + } + + out.Write( GetData(), nSz ); +} +#if 0 +// ----------------------------------------------------------------------------- + +void Tag::addI32( sal_Int32 nValue ) +{ + addUI32( static_cast<sal_uInt32>( nValue ) ); +} +#endif +// ----------------------------------------------------------------------------- + +void Tag::addUI32( sal_uInt32 nValue ) +{ + *this << nValue; +} +#if 0 +// ----------------------------------------------------------------------------- + +void Tag::addI16( sal_Int16 nValue ) +{ + addUI16( static_cast<sal_uInt16>( nValue ) ); +} +#endif +// ----------------------------------------------------------------------------- + +void Tag::addUI16( sal_uInt16 nValue ) +{ + *this << (sal_uInt8)nValue; + *this << (sal_uInt8)(nValue >> 8); +} + +// ----------------------------------------------------------------------------- + +void Tag::addUI8( sal_uInt8 nValue ) +{ + *this << (sal_uInt8)nValue; +} + +// ----------------------------------------------------------------------------- + +void Tag::addBits( BitStream& rIn ) +{ + rIn.writeTo( *this ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addRGBA( const Color& rColor ) +{ + addUI8( rColor.GetRed() ); + addUI8( rColor.GetGreen() ); + addUI8( rColor.GetBlue() ); + addUI8( 0xff - rColor.GetTransparency() ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addRGB( const Color& rColor ) +{ + addUI8( rColor.GetRed() ); + addUI8( rColor.GetGreen() ); + addUI8( rColor.GetBlue() ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addRect( const Rectangle& rRect ) +{ + writeRect( *this, rRect ); +} + +// ----------------------------------------------------------------------------- + +void Tag::writeRect( SvStream& rOut, const Rectangle& rRect ) +{ + BitStream aBits; + + sal_Int32 minX, minY, maxX, maxY; + + if( rRect.nLeft < rRect.nRight ) + { + minX = rRect.nLeft; maxX = rRect.nRight; + } + else + { + maxX = rRect.nLeft; minX = rRect.nRight; + } + + + if( rRect.nTop < rRect.nBottom ) + { + minY = rRect.nTop; maxY = rRect.nBottom; + } + else + { + maxY = rRect.nTop; minY = rRect.nBottom; + } + + // AS: Figure out the maximum nubmer of bits required to represent any of the + // rectangle coordinates. Since minX or minY could be negative, they could + // actually require more bits than maxX or maxY. + // AS: Christian, can they be negative, or is that a wasted check? + // CL: I think so, f.e. for shapes that have the top and/or left edge outside + // the page origin + sal_uInt8 nBits1 = sal::static_int_cast<sal_uInt8>( max( getMaxBitsSigned( minX ), getMaxBitsSigned( minY ) ) ); + sal_uInt8 nBits2 = sal::static_int_cast<sal_uInt8>( max( getMaxBitsSigned( maxX ), getMaxBitsSigned( maxY ) ) ); + sal_uInt8 nBitsMax = max( nBits1, nBits2 ); + + aBits.writeUB( nBitsMax, 5 ); + aBits.writeSB( minX, nBitsMax ); + aBits.writeSB( maxX, nBitsMax ); + aBits.writeSB( minY, nBitsMax ); + aBits.writeSB( maxY, nBitsMax ); + + aBits.writeTo( rOut ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addMatrix( const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264# +{ + writeMatrix( *this, rMatrix ); +} + +// ----------------------------------------------------------------------------- + +void Tag::writeMatrix( SvStream& rOut, const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264# +{ + + BitStream aBits; + + const sal_uInt8 bHasScale = rMatrix.get(0, 0) != 1.0 || rMatrix.get(1, 1) != 1.0; + + aBits.writeUB( bHasScale, 1 ); + + if( bHasScale ) + { + sal_uInt8 nScaleBits = 31; + + aBits.writeUB( nScaleBits, 5 ); + aBits.writeFB( getFixed( rMatrix.get(0, 0) ), nScaleBits ); // Scale X + aBits.writeFB( getFixed( rMatrix.get(1, 1) ), nScaleBits ); // Scale Y + } + + const sal_uInt8 bHasRotate = rMatrix.get(0, 1) != 0.0 || rMatrix.get(1, 0) != 0.0; + + aBits.writeUB( bHasRotate, 1 ); + + if( bHasRotate ) + { + sal_uInt8 nRotateBits = 31; + + aBits.writeUB( nRotateBits, 5 ); + aBits.writeFB( getFixed( rMatrix.get(0, 1) ), nRotateBits ); // RotateSkew0 + aBits.writeFB( getFixed( rMatrix.get(1, 0) ), nRotateBits ); // RotateSkew1 + } + + sal_uInt8 nTranslateBits = 16; + + aBits.writeUB( nTranslateBits, 5 ); + aBits.writeSB( (sal_Int16)rMatrix.get(0, 2), nTranslateBits ); // Translate X + aBits.writeSB( (sal_Int16)rMatrix.get(1, 2), nTranslateBits ); // Translate Y + + aBits.writeTo( rOut ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addString( const char* pString ) +{ + if( pString ) + { + while( *pString ) + addUI8( *pString++ ); + } + + addUI8( 0 ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addStream( SvStream& rIn ) +{ + *this << rIn; +} + +//////////////////////////////////////////////////////////////////////////////// + +Sprite::Sprite( sal_uInt16 nId ) +: mnId( nId ), mnFrames(0) +{ +} + +// ----------------------------------------------------------------------------- + +Sprite::~Sprite() +{ + for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); i++) + delete *i; +} + +// ----------------------------------------------------------------------------- + +void Sprite::write( SvStream& out ) +{ + SvMemoryStream aTmp; + for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); i++) + (*i)->write( aTmp ); + + if( !mnFrames ) + mnFrames = 1; + + aTmp.Seek(0); + + Tag aTag( TAG_DEFINESPRITE ); + aTag.addUI16( mnId ); + aTag.addUI16( _uInt16( mnFrames ) ); + aTag.addStream( aTmp ); + aTag.write( out ); +} + +// ----------------------------------------------------------------------------- + +void Sprite::addTag( Tag* pNewTag ) +{ + if( pNewTag ) + { + if( pNewTag->getTagId() == TAG_SHOWFRAME ) + mnFrames++; + + maTags.push_back( pNewTag ); + } +} + +///////////////////////////////////////////////////////////////////////////////// + +sal_uInt32 swf::getFixed( double fValue ) +{ + sal_Int16 nUpper = (sal_Int16)floor(fValue); + sal_uInt16 nLower = (sal_uInt16)((fValue - floor(fValue))*0x10000); + + sal_uInt32 temp = ((sal_Int32)nUpper)<<16; + temp |= nLower; + + return temp; +} + +///////////////////////////////////////////////////////////////////////////////// + +/** constructs a new flash font for the given VCL Font */ +FlashFont::FlashFont( const Font& rFont, sal_uInt16 nId ) +: maFont( rFont ), mnNextIndex(0), mnId( nId ) +{ +} + +// ----------------------------------------------------------------------------- + +FlashFont::~FlashFont() +{ +} + +// ----------------------------------------------------------------------------- + +/** gets the glyph id for the given character. The glyphs are created on demand */ +sal_uInt16 FlashFont::getGlyph( sal_uInt16 nChar, VirtualDevice* pVDev ) +{ + // see if we already created a glyph for this character + std::map<sal_uInt16, sal_uInt16, ltuint16>::iterator aIter( maGlyphIndex.find(nChar) ); + if( aIter != maGlyphIndex.end() ) + { + return aIter->second; + } + + // if not, we create one now + + maGlyphIndex[nChar] = mnNextIndex; + + Font aOldFont( pVDev->GetFont() ); + Font aNewFont( aOldFont ); + aNewFont.SetAlign( ALIGN_BASELINE ); + pVDev->SetFont( aNewFont ); + aOldFont.SetOrientation(0); + + // let the virtual device convert the character to polygons + PolyPolygon aPolyPoly; + pVDev->GetTextOutline( aPolyPoly, nChar ); + + maGlyphOffsets.push_back( _uInt16( maGlyphData.getOffset() ) ); + + // Number of fill and line index bits set to 1 + maGlyphData.writeUB( 0x11, 8 ); + + const sal_uInt16 nCount = aPolyPoly.Count(); + sal_uInt16 i,n; + for( i = 0; i < nCount; i++ ) + { + Polygon& rPoly = aPolyPoly[ i ]; + + const USHORT nSize = rPoly.GetSize(); + if( nSize ) + { + // convert polygon to flash EM_SQUARE (1024x1024) + for( n = 0; n < nSize; n++ ) + { + Point aPoint( rPoly[n] ); + aPoint.X() = static_cast<long>((double(aPoint.X()) * 1024.0 ) / double(aOldFont.GetHeight())); + aPoint.Y() = static_cast<long>((double(aPoint.Y()) * 1024.0 ) / double(aOldFont.GetHeight())); + rPoly[n] = aPoint; + } + Writer::Impl_addPolygon( maGlyphData, rPoly, true ); + } + } + Writer::Impl_addEndShapeRecord( maGlyphData ); + + maGlyphData.pad(); + + pVDev->SetFont( aOldFont ); + + return mnNextIndex++; +} + +// ----------------------------------------------------------------------------- + +void FlashFont::write( SvStream& out ) +{ + Tag aTag( TAG_DEFINEFONT ); + + aTag.addUI16( mnId ); + + sal_uInt16 nGlyphs = _uInt16( maGlyphOffsets.size() ); + sal_uInt16 nOffset = nGlyphs * sizeof( sal_uInt16 ); + + for(vector< sal_uInt16 >::iterator i = maGlyphOffsets.begin(); i != maGlyphOffsets.end(); i++) + aTag.addUI16( nOffset + (*i) ); + + aTag.addBits( maGlyphData ); + + aTag.write( out ); +} + +//////////////////////////////////////////////////////////////////////////////// + +/** this c'tor creates a solid fill style */ +FillStyle::FillStyle( const Color& rSolidColor ) +: meType( solid ), + maColor( rSolidColor ) +{ +} + +// ----------------------------------------------------------------------------- + +/** this c'tor creates a tiled or clipped bitmap fill style */ +FillStyle::FillStyle( sal_uInt16 nBitmapId, bool bClipped, const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264# +: meType( bClipped ? clipped_bitmap : tiled_bitmap ), + maMatrix( rMatrix ), + mnBitmapId( nBitmapId ) +{ +} + +// ----------------------------------------------------------------------------- + +FillStyle::FillStyleType Impl_getFillStyleType( const Gradient& rGradient ) +{ + switch( rGradient.GetStyle() ) + { + case GradientStyle_ELLIPTICAL: + case GradientStyle_RADIAL: + return FillStyle::radial_gradient; +// case GradientStyle_AXIAL: +// case GradientStyle_SQUARE: +// case GradientStyle_RECT: +// case GradientStyle_LINEAR: + default: + return FillStyle::linear_gradient; + } +} + +// ----------------------------------------------------------------------------- + +/** this c'tor creates a linear or radial gradient fill style */ +FillStyle::FillStyle( const Rectangle& rBoundRect, const Gradient& rGradient ) +: meType( Impl_getFillStyleType( rGradient ) ), + maGradient( rGradient ), + maBoundRect( rBoundRect ) +{ +} + +// ----------------------------------------------------------------------------- + +void FillStyle::addTo( Tag* pTag ) const +{ + pTag->addUI8( sal::static_int_cast<sal_uInt8>( meType ) ); + switch( meType ) + { + case solid: + pTag->addRGBA( maColor ); + break; + case linear_gradient: + case radial_gradient: + Impl_addGradient( pTag ); + break; + case tiled_bitmap: + case clipped_bitmap: + pTag->addUI16( mnBitmapId ); + pTag->addMatrix( maMatrix ); + break; + } +} + +// ----------------------------------------------------------------------------- + +struct GradRecord +{ + sal_uInt8 mnRatio; + Color maColor; + + GradRecord( sal_uInt8 nRatio, const Color& rColor ) : mnRatio( nRatio ), maColor( rColor ) {} +}; + +// TODO: better emulation of our gradients +void FillStyle::Impl_addGradient( Tag* pTag ) const +{ + vector< struct GradRecord > aGradientRecords; + basegfx::B2DHomMatrix m(basegfx::tools::createRotateB2DHomMatrix((maGradient.GetAngle() - 900) * F_PI1800)); + + switch( maGradient.GetStyle() ) + { + case GradientStyle_ELLIPTICAL: + case GradientStyle_RADIAL: + { + aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) ); + aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetStartColor() ) ); + + double tx = ( maGradient.GetOfsX() * 32768.0 ) / 100.0; + double ty = ( maGradient.GetOfsY() * 32768.0 ) / 100.0; + double scalex = (double)maBoundRect.GetWidth() / 32768.0; + double scaley = (double)maBoundRect.GetHeight() / 32768.0; + + m.scale( 1.2, 1.2 ); + + if( scalex > scaley ) + { + double scale_move = scaley / scalex; + + m.translate( tx, scale_move * ty ); + + + m.scale( scalex, scalex ); + } + else + { + double scale_move = scalex / scaley; + + m.translate( scale_move * tx, ty ); + + + m.scale( scaley, scaley ); + } + + } + break; + case GradientStyle_AXIAL: + { + aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) ); + aGradientRecords.push_back( GradRecord( 0x80, maGradient.GetStartColor() ) ); + aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) ); + double tx = ( 32768.0 / 2.0 ); + double ty = ( 32768.0 / 2.0 ); + double scalex = (double)maBoundRect.GetWidth() / 32768.0; + double scaley = (double)maBoundRect.GetHeight() / 32768.0; + + m.translate( tx, ty ); + m.scale( scalex, scaley ); + } + break; + case GradientStyle_SQUARE: + case GradientStyle_RECT: + case GradientStyle_LINEAR: + { + aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetStartColor() ) ); + aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) ); + double scalex = (double)maBoundRect.GetWidth() / 32768.0; + double scaley = (double)maBoundRect.GetHeight() / 32768.0; + + m.scale( scalex, scaley ); + + m.translate( maBoundRect.GetWidth() / 2.0, maBoundRect.GetHeight() / 2.0 ); + } + break; + case GradientStyle_FORCE_EQUAL_SIZE: break; + } + + m.translate( maBoundRect.nLeft, maBoundRect.nTop ); + + pTag->addMatrix( m ); + + DBG_ASSERT( aGradientRecords.size() < 8, "Illegal FlashGradient!" ); + + pTag->addUI8( static_cast<sal_uInt8>( aGradientRecords.size() ) ); + + for(std::vector< GradRecord >::iterator i = aGradientRecords.begin(); i != aGradientRecords.end(); i++) + { + pTag->addUI8( (*i).mnRatio ); + pTag->addRGBA( (*i).maColor ); + } +} + |