1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
)
46 // -----------------------------------------------------------------------------
48 sal_uInt16
getMaxBitsSigned( sal_Int32 nValue
)
53 return getMaxBitsUnsigned( static_cast< sal_uInt32
>(nValue
) ) + 1;
56 // -----------------------------------------------------------------------------
58 BitStream::BitStream()
64 // -----------------------------------------------------------------------------
66 void BitStream::writeUB( sal_uInt32 nValue
, sal_uInt16 nBits
)
70 mnCurrentByte
|= nValue
<< (32 - nBits
) >> (32 - mnBitPos
);
72 if ( nBits
> mnBitPos
)
74 nBits
= nBits
- mnBitPos
;
79 mnBitPos
= sal::static_int_cast
<sal_uInt8
>( mnBitPos
- nBits
);
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()
108 maData
.push_back( mnCurrentByte
);
114 // -----------------------------------------------------------------------------
116 void BitStream::writeTo( SvStream
& out
)
120 vector
< sal_uInt8
>::iterator
aIter( maData
.begin() );
121 const vector
< sal_uInt8
>::iterator
aEnd( maData
.end() );
128 // -----------------------------------------------------------------------------
130 sal_uInt32
BitStream::getOffset() const
132 return maData
.size();
135 ////////////////////////////////////////////////////////////////////////////////
137 Tag::Tag( sal_uInt8 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);
161 sal_uInt32 nTmp
= nSz
;
163 out
<< (sal_uInt8
)nTmp
;
165 out
<< (sal_uInt8
)nTmp
;
167 out
<< (sal_uInt8
)nTmp
;
169 out
<< (sal_uInt8
)nTmp
;
173 out
.Write( GetData(), nSz
);
176 // -----------------------------------------------------------------------------
178 void Tag::addI32( sal_Int32 nValue
)
180 addUI32( static_cast<sal_uInt32
>( nValue
) );
183 // -----------------------------------------------------------------------------
185 void Tag::addUI32( sal_uInt32 nValue
)
190 // -----------------------------------------------------------------------------
192 void Tag::addI16( sal_Int16 nValue
)
194 addUI16( static_cast<sal_uInt16
>( nValue
) );
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
)
251 sal_Int32 minX
, minY
, maxX
, maxY
;
253 if( rRect
.Left() < rRect
.Right() )
256 maxX
= rRect
.Right();
261 minX
= rRect
.Right();
265 if( rRect
.Top() < rRect
.Bottom() )
268 maxY
= rRect
.Bottom();
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
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#
309 const sal_uInt8 bHasScale
= rMatrix
.get(0, 0) != 1.0 || rMatrix
.get(1, 1) != 1.0;
311 aBits
.writeUB( bHasScale
, 1 );
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 );
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
)
351 addUI8( *pString
++ );
357 // -----------------------------------------------------------------------------
359 void Tag::addStream( SvStream
& rIn
)
364 ////////////////////////////////////////////////////////////////////////////////
366 Sprite::Sprite( sal_uInt16 nId
)
367 : mnId( nId
), mnFrames(0)
371 // -----------------------------------------------------------------------------
375 for(vector
< Tag
* >::iterator i
= maTags
.begin(); i
!= maTags
.end(); ++i
)
379 // -----------------------------------------------------------------------------
381 void Sprite::write( SvStream
& out
)
384 for(vector
< Tag
* >::iterator i
= maTags
.begin(); i
!= maTags
.end(); ++i
)
392 Tag
aTag( TAG_DEFINESPRITE
);
393 aTag
.addUI16( mnId
);
394 aTag
.addUI16( _uInt16( mnFrames
) );
395 aTag
.addStream( aTmp
);
399 // -----------------------------------------------------------------------------
401 void Sprite::addTag( Tag
* pNewTag
)
405 if( pNewTag
->getTagId() == TAG_SHOWFRAME
)
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;
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();
472 for( i
= 0; i
< nCount
; i
++ )
474 Polygon
& rPoly
= aPolyPoly
[ i
];
476 const sal_uInt16 nSize
= rPoly
.GetSize();
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()));
487 Writer::Impl_addPolygon( maGlyphData
, rPoly
, true );
490 Writer::Impl_addEndShapeRecord( maGlyphData
);
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
);
518 ////////////////////////////////////////////////////////////////////////////////
520 /** this c'tor creates a solid fill style */
521 FillStyle::FillStyle( const Color
& rSolidColor
)
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
),
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:
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
) );
573 pTag
->addRGBA( maColor
);
575 case linear_gradient
:
576 case radial_gradient
:
577 Impl_addGradient( pTag
);
581 pTag
->addUI16( mnBitmapId
);
582 pTag
->addMatrix( maMatrix
);
587 // -----------------------------------------------------------------------------
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;
618 if( scalex
> scaley
)
620 double scale_move
= scaley
/ scalex
;
622 m
.translate( tx
, scale_move
* ty
);
625 m
.scale( scalex
, scalex
);
629 double scale_move
= scalex
/ scaley
;
631 m
.translate( scale_move
* tx
, ty
);
634 m
.scale( scaley
, scaley
);
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
);
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 );
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: */