fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / filter / source / flash / swfwriter2.cxx
blob766b02a340258d394937c5864ad3473caa059c43
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "swfwriter.hxx"
21 #include <vcl/virdev.hxx>
22 #include <basegfx/matrix/b2dhommatrixtools.hxx>
24 #include <math.h>
26 using namespace ::swf;
27 using namespace ::std;
28 using namespace ::com::sun::star::uno;
29 using namespace ::com::sun::star::io;
31 // -----------------------------------------------------------------------------
33 sal_uInt16 getMaxBitsUnsigned( sal_uInt32 nValue )
35 sal_uInt16 nBits = 0;
37 while( nValue )
39 nBits++;
40 nValue >>= 1;
43 return nBits;
46 // -----------------------------------------------------------------------------
48 sal_uInt16 getMaxBitsSigned( sal_Int32 nValue )
50 if( nValue < 0 )
51 nValue *= -1;
53 return getMaxBitsUnsigned( static_cast< sal_uInt32 >(nValue) ) + 1;
56 // -----------------------------------------------------------------------------
58 BitStream::BitStream()
60 mnBitPos = 8;
61 mnCurrentByte = 0;
64 // -----------------------------------------------------------------------------
66 void BitStream::writeUB( sal_uInt32 nValue, sal_uInt16 nBits )
68 while( nBits != 0 )
70 mnCurrentByte |= nValue << (32 - nBits) >> (32 - mnBitPos);
72 if ( nBits > mnBitPos )
74 nBits = nBits - mnBitPos;
75 mnBitPos = 0;
77 else
79 mnBitPos = sal::static_int_cast<sal_uInt8>( mnBitPos - nBits );
80 nBits = 0;
83 if( 0 == mnBitPos )
84 pad();
88 // -----------------------------------------------------------------------------
90 void BitStream::writeSB( sal_Int32 nValue, sal_uInt16 nBits )
92 writeUB( static_cast< sal_uInt32 >(nValue), nBits );
95 // -----------------------------------------------------------------------------
97 void BitStream::writeFB( sal_uInt32 nValue, sal_uInt16 nBits )
99 writeUB( nValue, nBits );
102 // -----------------------------------------------------------------------------
104 void BitStream::pad()
106 if( 8 != mnBitPos )
108 maData.push_back( mnCurrentByte );
109 mnCurrentByte = 0;
110 mnBitPos = 8;
114 // -----------------------------------------------------------------------------
116 void BitStream::writeTo( SvStream& out )
118 pad();
120 vector< sal_uInt8 >::iterator aIter( maData.begin() );
121 const vector< sal_uInt8>::iterator aEnd( maData.end() );
122 while(aIter != aEnd)
124 out << (*aIter++);
128 // -----------------------------------------------------------------------------
130 sal_uInt32 BitStream::getOffset() const
132 return maData.size();
135 ////////////////////////////////////////////////////////////////////////////////
137 Tag::Tag( sal_uInt8 nTagId )
139 mnTagId = nTagId;
142 // -----------------------------------------------------------------------------
144 void Tag::write( SvStream &out )
146 Seek( STREAM_SEEK_TO_END );
147 sal_uInt32 nSz = Tell();
148 Seek( STREAM_SEEK_TO_BEGIN );
150 if( mnTagId != 0xff )
152 bool bLarge = nSz > 62;
154 sal_uInt16 nCode = ( mnTagId << 6 ) | ( bLarge ? 0x3f : _uInt16(nSz) );
156 out << (sal_uInt8)nCode;
157 out << (sal_uInt8)(nCode >> 8);
159 if( bLarge )
161 sal_uInt32 nTmp = nSz;
163 out << (sal_uInt8)nTmp;
164 nTmp >>= 8;
165 out << (sal_uInt8)nTmp;
166 nTmp >>= 8;
167 out << (sal_uInt8)nTmp;
168 nTmp >>= 8;
169 out << (sal_uInt8)nTmp;
173 out.Write( GetData(), nSz );
175 #if 0
176 // -----------------------------------------------------------------------------
178 void Tag::addI32( sal_Int32 nValue )
180 addUI32( static_cast<sal_uInt32>( nValue ) );
182 #endif
183 // -----------------------------------------------------------------------------
185 void Tag::addUI32( sal_uInt32 nValue )
187 *this << nValue;
189 #if 0
190 // -----------------------------------------------------------------------------
192 void Tag::addI16( sal_Int16 nValue )
194 addUI16( static_cast<sal_uInt16>( nValue ) );
196 #endif
197 // -----------------------------------------------------------------------------
199 void Tag::addUI16( sal_uInt16 nValue )
201 *this << (sal_uInt8)nValue;
202 *this << (sal_uInt8)(nValue >> 8);
205 // -----------------------------------------------------------------------------
207 void Tag::addUI8( sal_uInt8 nValue )
209 *this << (sal_uInt8)nValue;
212 // -----------------------------------------------------------------------------
214 void Tag::addBits( BitStream& rIn )
216 rIn.writeTo( *this );
219 // -----------------------------------------------------------------------------
221 void Tag::addRGBA( const Color& rColor )
223 addUI8( rColor.GetRed() );
224 addUI8( rColor.GetGreen() );
225 addUI8( rColor.GetBlue() );
226 addUI8( 0xff - rColor.GetTransparency() );
229 // -----------------------------------------------------------------------------
231 void Tag::addRGB( const Color& rColor )
233 addUI8( rColor.GetRed() );
234 addUI8( rColor.GetGreen() );
235 addUI8( rColor.GetBlue() );
238 // -----------------------------------------------------------------------------
240 void Tag::addRect( const Rectangle& rRect )
242 writeRect( *this, rRect );
245 // -----------------------------------------------------------------------------
247 void Tag::writeRect( SvStream& rOut, const Rectangle& rRect )
249 BitStream aBits;
251 sal_Int32 minX, minY, maxX, maxY;
253 if( rRect.Left() < rRect.Right() )
255 minX = rRect.Left();
256 maxX = rRect.Right();
258 else
260 maxX = rRect.Left();
261 minX = rRect.Right();
265 if( rRect.Top() < rRect.Bottom() )
267 minY = rRect.Top();
268 maxY = rRect.Bottom();
270 else
272 maxY = rRect.Top();
273 minY = rRect.Bottom();
276 // AS: Figure out the maximum nubmer of bits required to represent any of the
277 // rectangle coordinates. Since minX or minY could be negative, they could
278 // actually require more bits than maxX or maxY.
279 // AS: Christian, can they be negative, or is that a wasted check?
280 // CL: I think so, f.e. for shapes that have the top and/or left edge outside
281 // the page origin
282 sal_uInt8 nBits1 = sal::static_int_cast<sal_uInt8>( max( getMaxBitsSigned( minX ), getMaxBitsSigned( minY ) ) );
283 sal_uInt8 nBits2 = sal::static_int_cast<sal_uInt8>( max( getMaxBitsSigned( maxX ), getMaxBitsSigned( maxY ) ) );
284 sal_uInt8 nBitsMax = max( nBits1, nBits2 );
286 aBits.writeUB( nBitsMax, 5 );
287 aBits.writeSB( minX, nBitsMax );
288 aBits.writeSB( maxX, nBitsMax );
289 aBits.writeSB( minY, nBitsMax );
290 aBits.writeSB( maxY, nBitsMax );
292 aBits.writeTo( rOut );
295 // -----------------------------------------------------------------------------
297 void Tag::addMatrix( const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
299 writeMatrix( *this, rMatrix );
302 // -----------------------------------------------------------------------------
304 void Tag::writeMatrix( SvStream& rOut, const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
307 BitStream aBits;
309 const sal_uInt8 bHasScale = rMatrix.get(0, 0) != 1.0 || rMatrix.get(1, 1) != 1.0;
311 aBits.writeUB( bHasScale, 1 );
313 if( bHasScale )
315 sal_uInt8 nScaleBits = 31;
317 aBits.writeUB( nScaleBits, 5 );
318 aBits.writeFB( getFixed( rMatrix.get(0, 0) ), nScaleBits ); // Scale X
319 aBits.writeFB( getFixed( rMatrix.get(1, 1) ), nScaleBits ); // Scale Y
322 const sal_uInt8 bHasRotate = rMatrix.get(0, 1) != 0.0 || rMatrix.get(1, 0) != 0.0;
324 aBits.writeUB( bHasRotate, 1 );
326 if( bHasRotate )
328 sal_uInt8 nRotateBits = 31;
330 aBits.writeUB( nRotateBits, 5 );
331 aBits.writeFB( getFixed( rMatrix.get(0, 1) ), nRotateBits ); // RotateSkew0
332 aBits.writeFB( getFixed( rMatrix.get(1, 0) ), nRotateBits ); // RotateSkew1
335 sal_uInt8 nTranslateBits = 16;
337 aBits.writeUB( nTranslateBits, 5 );
338 aBits.writeSB( (sal_Int16)rMatrix.get(0, 2), nTranslateBits ); // Translate X
339 aBits.writeSB( (sal_Int16)rMatrix.get(1, 2), nTranslateBits ); // Translate Y
341 aBits.writeTo( rOut );
344 // -----------------------------------------------------------------------------
346 void Tag::addString( const char* pString )
348 if( pString )
350 while( *pString )
351 addUI8( *pString++ );
354 addUI8( 0 );
357 // -----------------------------------------------------------------------------
359 void Tag::addStream( SvStream& rIn )
361 *this << rIn;
364 ////////////////////////////////////////////////////////////////////////////////
366 Sprite::Sprite( sal_uInt16 nId )
367 : mnId( nId ), mnFrames(0)
371 // -----------------------------------------------------------------------------
373 Sprite::~Sprite()
375 for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); ++i)
376 delete *i;
379 // -----------------------------------------------------------------------------
381 void Sprite::write( SvStream& out )
383 SvMemoryStream aTmp;
384 for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); ++i)
385 (*i)->write( aTmp );
387 if( !mnFrames )
388 mnFrames = 1;
390 aTmp.Seek(0);
392 Tag aTag( TAG_DEFINESPRITE );
393 aTag.addUI16( mnId );
394 aTag.addUI16( _uInt16( mnFrames ) );
395 aTag.addStream( aTmp );
396 aTag.write( out );
399 // -----------------------------------------------------------------------------
401 void Sprite::addTag( Tag* pNewTag )
403 if( pNewTag )
405 if( pNewTag->getTagId() == TAG_SHOWFRAME )
406 mnFrames++;
408 maTags.push_back( pNewTag );
412 /////////////////////////////////////////////////////////////////////////////////
414 sal_uInt32 swf::getFixed( double fValue )
416 sal_Int16 nUpper = (sal_Int16)floor(fValue);
417 sal_uInt16 nLower = (sal_uInt16)((fValue - floor(fValue))*0x10000);
419 sal_uInt32 temp = ((sal_Int32)nUpper)<<16;
420 temp |= nLower;
422 return temp;
425 /////////////////////////////////////////////////////////////////////////////////
427 /** constructs a new flash font for the given VCL Font */
428 FlashFont::FlashFont( const Font& rFont, sal_uInt16 nId )
429 : maFont( rFont ), mnNextIndex(0), mnId( nId )
433 // -----------------------------------------------------------------------------
435 FlashFont::~FlashFont()
439 // -----------------------------------------------------------------------------
441 /** gets the glyph id for the given character. The glyphs are created on demand */
442 sal_uInt16 FlashFont::getGlyph( sal_uInt16 nChar, VirtualDevice* pVDev )
444 // see if we already created a glyph for this character
445 std::map<sal_uInt16, sal_uInt16, ltuint16>::iterator aIter( maGlyphIndex.find(nChar) );
446 if( aIter != maGlyphIndex.end() )
448 return aIter->second;
451 // if not, we create one now
453 maGlyphIndex[nChar] = mnNextIndex;
455 Font aOldFont( pVDev->GetFont() );
456 Font aNewFont( aOldFont );
457 aNewFont.SetAlign( ALIGN_BASELINE );
458 pVDev->SetFont( aNewFont );
459 aOldFont.SetOrientation(0);
461 // let the virtual device convert the character to polygons
462 PolyPolygon aPolyPoly;
463 pVDev->GetTextOutline( aPolyPoly, OUString(nChar) );
465 maGlyphOffsets.push_back( _uInt16( maGlyphData.getOffset() ) );
467 // Number of fill and line index bits set to 1
468 maGlyphData.writeUB( 0x11, 8 );
470 const sal_uInt16 nCount = aPolyPoly.Count();
471 sal_uInt16 i,n;
472 for( i = 0; i < nCount; i++ )
474 Polygon& rPoly = aPolyPoly[ i ];
476 const sal_uInt16 nSize = rPoly.GetSize();
477 if( nSize )
479 // convert polygon to flash EM_SQUARE (1024x1024)
480 for( n = 0; n < nSize; n++ )
482 Point aPoint( rPoly[n] );
483 aPoint.X() = static_cast<long>((double(aPoint.X()) * 1024.0 ) / double(aOldFont.GetHeight()));
484 aPoint.Y() = static_cast<long>((double(aPoint.Y()) * 1024.0 ) / double(aOldFont.GetHeight()));
485 rPoly[n] = aPoint;
487 Writer::Impl_addPolygon( maGlyphData, rPoly, true );
490 Writer::Impl_addEndShapeRecord( maGlyphData );
492 maGlyphData.pad();
494 pVDev->SetFont( aOldFont );
496 return mnNextIndex++;
499 // -----------------------------------------------------------------------------
501 void FlashFont::write( SvStream& out )
503 Tag aTag( TAG_DEFINEFONT );
505 aTag.addUI16( mnId );
507 sal_uInt16 nGlyphs = _uInt16( maGlyphOffsets.size() );
508 sal_uInt16 nOffset = nGlyphs * sizeof( sal_uInt16 );
510 for(vector< sal_uInt16 >::iterator i = maGlyphOffsets.begin(); i != maGlyphOffsets.end(); ++i)
511 aTag.addUI16( nOffset + (*i) );
513 aTag.addBits( maGlyphData );
515 aTag.write( out );
518 ////////////////////////////////////////////////////////////////////////////////
520 /** this c'tor creates a solid fill style */
521 FillStyle::FillStyle( const Color& rSolidColor )
522 : meType( solid ),
523 maColor( rSolidColor )
527 // -----------------------------------------------------------------------------
529 /** this c'tor creates a tiled or clipped bitmap fill style */
530 FillStyle::FillStyle( sal_uInt16 nBitmapId, bool bClipped, const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
531 : meType( bClipped ? clipped_bitmap : tiled_bitmap ),
532 maMatrix( rMatrix ),
533 mnBitmapId( nBitmapId )
537 // -----------------------------------------------------------------------------
539 FillStyle::FillStyleType Impl_getFillStyleType( const Gradient& rGradient )
541 switch( rGradient.GetStyle() )
543 case GradientStyle_ELLIPTICAL:
544 case GradientStyle_RADIAL:
545 return FillStyle::radial_gradient;
546 // case GradientStyle_AXIAL:
547 // case GradientStyle_SQUARE:
548 // case GradientStyle_RECT:
549 // case GradientStyle_LINEAR:
550 default:
551 return FillStyle::linear_gradient;
555 // -----------------------------------------------------------------------------
557 /** this c'tor creates a linear or radial gradient fill style */
558 FillStyle::FillStyle( const Rectangle& rBoundRect, const Gradient& rGradient )
559 : meType( Impl_getFillStyleType( rGradient ) ),
560 maGradient( rGradient ),
561 maBoundRect( rBoundRect )
565 // -----------------------------------------------------------------------------
567 void FillStyle::addTo( Tag* pTag ) const
569 pTag->addUI8( sal::static_int_cast<sal_uInt8>( meType ) );
570 switch( meType )
572 case solid:
573 pTag->addRGBA( maColor );
574 break;
575 case linear_gradient:
576 case radial_gradient:
577 Impl_addGradient( pTag );
578 break;
579 case tiled_bitmap:
580 case clipped_bitmap:
581 pTag->addUI16( mnBitmapId );
582 pTag->addMatrix( maMatrix );
583 break;
587 // -----------------------------------------------------------------------------
589 struct GradRecord
591 sal_uInt8 mnRatio;
592 Color maColor;
594 GradRecord( sal_uInt8 nRatio, const Color& rColor ) : mnRatio( nRatio ), maColor( rColor ) {}
597 // TODO: better emulation of our gradients
598 void FillStyle::Impl_addGradient( Tag* pTag ) const
600 vector< struct GradRecord > aGradientRecords;
601 basegfx::B2DHomMatrix m(basegfx::tools::createRotateB2DHomMatrix((maGradient.GetAngle() - 900) * F_PI1800));
603 switch( maGradient.GetStyle() )
605 case GradientStyle_ELLIPTICAL:
606 case GradientStyle_RADIAL:
608 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) );
609 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetStartColor() ) );
611 double tx = ( maGradient.GetOfsX() * 32768.0 ) / 100.0;
612 double ty = ( maGradient.GetOfsY() * 32768.0 ) / 100.0;
613 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
614 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
616 m.scale( 1.2, 1.2 );
618 if( scalex > scaley )
620 double scale_move = scaley / scalex;
622 m.translate( tx, scale_move * ty );
625 m.scale( scalex, scalex );
627 else
629 double scale_move = scalex / scaley;
631 m.translate( scale_move * tx, ty );
634 m.scale( scaley, scaley );
638 break;
639 case GradientStyle_AXIAL:
641 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) );
642 aGradientRecords.push_back( GradRecord( 0x80, maGradient.GetStartColor() ) );
643 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) );
644 double tx = ( 32768.0 / 2.0 );
645 double ty = ( 32768.0 / 2.0 );
646 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
647 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
649 m.translate( tx, ty );
650 m.scale( scalex, scaley );
652 break;
653 case GradientStyle_SQUARE:
654 case GradientStyle_RECT:
655 case GradientStyle_LINEAR:
657 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetStartColor() ) );
658 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) );
659 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
660 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
662 m.scale( scalex, scaley );
664 m.translate( maBoundRect.GetWidth() / 2.0, maBoundRect.GetHeight() / 2.0 );
666 break;
667 case GradientStyle_FORCE_EQUAL_SIZE: break;
670 m.translate( maBoundRect.Left(), maBoundRect.Top() );
672 pTag->addMatrix( m );
674 DBG_ASSERT( aGradientRecords.size() < 8, "Illegal FlashGradient!" );
676 pTag->addUI8( static_cast<sal_uInt8>( aGradientRecords.size() ) );
678 for(std::vector< GradRecord >::iterator i = aGradientRecords.begin(); i != aGradientRecords.end(); ++i)
680 pTag->addUI8( (*i).mnRatio );
681 pTag->addRGBA( (*i).maColor );
685 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */