1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 #include "swfwriter.hxx"
27 #include <vcl/virdev.hxx>
28 #include <basegfx/matrix/b2dhommatrixtools.hxx>
29
30 #include <math.h>
31
32 using namespace ::swf;
33 using namespace ::std;
34 using namespace ::com::sun::star::uno;
35 using namespace ::com::sun::star::io;
36 using ::rtl::OUString;
37 using ::rtl::OString;
38
39 // -----------------------------------------------------------------------------
40
getMaxBitsUnsigned(sal_uInt32 nValue)41 sal_uInt16 getMaxBitsUnsigned( sal_uInt32 nValue )
42 {
43 sal_uInt16 nBits = 0;
44
45 while( nValue )
46 {
47 nBits++;
48 nValue >>= 1;
49 }
50
51 return nBits;
52 }
53
54 // -----------------------------------------------------------------------------
55
getMaxBitsSigned(sal_Int32 nValue)56 sal_uInt16 getMaxBitsSigned( sal_Int32 nValue )
57 {
58 if( nValue < 0 )
59 nValue *= -1;
60
61 return getMaxBitsUnsigned( static_cast< sal_uInt32 >(nValue) ) + 1;
62 }
63
64 // -----------------------------------------------------------------------------
65
BitStream()66 BitStream::BitStream()
67 {
68 mnBitPos = 8;
69 mnCurrentByte = 0;
70 }
71
72 // -----------------------------------------------------------------------------
73
writeUB(sal_uInt32 nValue,sal_uInt16 nBits)74 void BitStream::writeUB( sal_uInt32 nValue, sal_uInt16 nBits )
75 {
76 while( nBits != 0 )
77 {
78 mnCurrentByte |= nValue << (32 - nBits) >> (32 - mnBitPos);
79
80 if ( nBits > mnBitPos )
81 {
82 nBits = nBits - mnBitPos;
83 mnBitPos = 0;
84 }
85 else
86 {
87 mnBitPos = sal::static_int_cast<sal_uInt8>( mnBitPos - nBits );
88 nBits = 0;
89 }
90
91 if( 0 == mnBitPos )
92 pad();
93 }
94 }
95
96 // -----------------------------------------------------------------------------
97
writeSB(sal_Int32 nValue,sal_uInt16 nBits)98 void BitStream::writeSB( sal_Int32 nValue, sal_uInt16 nBits )
99 {
100 writeUB( static_cast< sal_uInt32 >(nValue), nBits );
101 }
102
103 // -----------------------------------------------------------------------------
104
writeFB(sal_uInt32 nValue,sal_uInt16 nBits)105 void BitStream::writeFB( sal_uInt32 nValue, sal_uInt16 nBits )
106 {
107 writeUB( nValue, nBits );
108 }
109
110 // -----------------------------------------------------------------------------
111
pad()112 void BitStream::pad()
113 {
114 if( 8 != mnBitPos )
115 {
116 maData.push_back( mnCurrentByte );
117 mnCurrentByte = 0;
118 mnBitPos = 8;
119 }
120 }
121
122 // -----------------------------------------------------------------------------
123
writeTo(SvStream & out)124 void BitStream::writeTo( SvStream& out )
125 {
126 pad();
127
128 vector< sal_uInt8 >::iterator aIter( maData.begin() );
129 const vector< sal_uInt8>::iterator aEnd( maData.end() );
130 while(aIter != aEnd)
131 {
132 out << (*aIter++);
133 }
134 }
135
136 // -----------------------------------------------------------------------------
137
getOffset() const138 sal_uInt32 BitStream::getOffset() const
139 {
140 return maData.size();
141 }
142
143 ////////////////////////////////////////////////////////////////////////////////
144
Tag(sal_uInt8 nTagId)145 Tag::Tag( sal_uInt8 nTagId )
146 {
147 mnTagId = nTagId;
148 }
149
150 // -----------------------------------------------------------------------------
151
write(SvStream & out)152 void Tag::write( SvStream &out )
153 {
154 Seek( STREAM_SEEK_TO_END );
155 sal_uInt32 nSz = Tell();
156 Seek( STREAM_SEEK_TO_BEGIN );
157
158 if( mnTagId != 0xff )
159 {
160 bool bLarge = nSz > 62;
161
162 sal_uInt16 nCode = ( mnTagId << 6 ) | ( bLarge ? 0x3f : _uInt16(nSz) );
163
164 out << (sal_uInt8)nCode;
165 out << (sal_uInt8)(nCode >> 8);
166
167 if( bLarge )
168 {
169 sal_uInt32 nTmp = nSz;
170
171 out << (sal_uInt8)nTmp;
172 nTmp >>= 8;
173 out << (sal_uInt8)nTmp;
174 nTmp >>= 8;
175 out << (sal_uInt8)nTmp;
176 nTmp >>= 8;
177 out << (sal_uInt8)nTmp;
178 }
179 }
180
181 out.Write( GetData(), nSz );
182 }
183 #if 0
184 // -----------------------------------------------------------------------------
185
186 void Tag::addI32( sal_Int32 nValue )
187 {
188 addUI32( static_cast<sal_uInt32>( nValue ) );
189 }
190 #endif
191 // -----------------------------------------------------------------------------
192
addUI32(sal_uInt32 nValue)193 void Tag::addUI32( sal_uInt32 nValue )
194 {
195 *this << nValue;
196 }
197 #if 0
198 // -----------------------------------------------------------------------------
199
200 void Tag::addI16( sal_Int16 nValue )
201 {
202 addUI16( static_cast<sal_uInt16>( nValue ) );
203 }
204 #endif
205 // -----------------------------------------------------------------------------
206
addUI16(sal_uInt16 nValue)207 void Tag::addUI16( sal_uInt16 nValue )
208 {
209 *this << (sal_uInt8)nValue;
210 *this << (sal_uInt8)(nValue >> 8);
211 }
212
213 // -----------------------------------------------------------------------------
214
addUI8(sal_uInt8 nValue)215 void Tag::addUI8( sal_uInt8 nValue )
216 {
217 *this << (sal_uInt8)nValue;
218 }
219
220 // -----------------------------------------------------------------------------
221
addBits(BitStream & rIn)222 void Tag::addBits( BitStream& rIn )
223 {
224 rIn.writeTo( *this );
225 }
226
227 // -----------------------------------------------------------------------------
228
addRGBA(const Color & rColor)229 void Tag::addRGBA( const Color& rColor )
230 {
231 addUI8( rColor.GetRed() );
232 addUI8( rColor.GetGreen() );
233 addUI8( rColor.GetBlue() );
234 addUI8( 0xff - rColor.GetTransparency() );
235 }
236
237 // -----------------------------------------------------------------------------
238
addRGB(const Color & rColor)239 void Tag::addRGB( const Color& rColor )
240 {
241 addUI8( rColor.GetRed() );
242 addUI8( rColor.GetGreen() );
243 addUI8( rColor.GetBlue() );
244 }
245
246 // -----------------------------------------------------------------------------
247
addRect(const Rectangle & rRect)248 void Tag::addRect( const Rectangle& rRect )
249 {
250 writeRect( *this, rRect );
251 }
252
253 // -----------------------------------------------------------------------------
254
writeRect(SvStream & rOut,const Rectangle & rRect)255 void Tag::writeRect( SvStream& rOut, const Rectangle& rRect )
256 {
257 BitStream aBits;
258
259 sal_Int32 minX, minY, maxX, maxY;
260
261 if( rRect.nLeft < rRect.nRight )
262 {
263 minX = rRect.nLeft; maxX = rRect.nRight;
264 }
265 else
266 {
267 maxX = rRect.nLeft; minX = rRect.nRight;
268 }
269
270
271 if( rRect.nTop < rRect.nBottom )
272 {
273 minY = rRect.nTop; maxY = rRect.nBottom;
274 }
275 else
276 {
277 maxY = rRect.nTop; minY = rRect.nBottom;
278 }
279
280 // AS: Figure out the maximum number of bits required to represent any of the
281 // rectangle coordinates. Since minX or minY could be negative, they could
282 // actually require more bits than maxX or maxY.
283 // AS: Christian, can they be negative, or is that a wasted check?
284 // CL: I think so, f.e. for shapes that have the top and/or left edge outside
285 // the page origin
286 sal_uInt8 nBits1 = sal::static_int_cast<sal_uInt8>( max( getMaxBitsSigned( minX ), getMaxBitsSigned( minY ) ) );
287 sal_uInt8 nBits2 = sal::static_int_cast<sal_uInt8>( max( getMaxBitsSigned( maxX ), getMaxBitsSigned( maxY ) ) );
288 sal_uInt8 nBitsMax = max( nBits1, nBits2 );
289
290 aBits.writeUB( nBitsMax, 5 );
291 aBits.writeSB( minX, nBitsMax );
292 aBits.writeSB( maxX, nBitsMax );
293 aBits.writeSB( minY, nBitsMax );
294 aBits.writeSB( maxY, nBitsMax );
295
296 aBits.writeTo( rOut );
297 }
298
299 // -----------------------------------------------------------------------------
300
addMatrix(const::basegfx::B2DHomMatrix & rMatrix)301 void Tag::addMatrix( const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
302 {
303 writeMatrix( *this, rMatrix );
304 }
305
306 // -----------------------------------------------------------------------------
307
writeMatrix(SvStream & rOut,const::basegfx::B2DHomMatrix & rMatrix)308 void Tag::writeMatrix( SvStream& rOut, const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
309 {
310
311 BitStream aBits;
312
313 const sal_uInt8 bHasScale = rMatrix.get(0, 0) != 1.0 || rMatrix.get(1, 1) != 1.0;
314
315 aBits.writeUB( bHasScale, 1 );
316
317 if( bHasScale )
318 {
319 sal_uInt8 nScaleBits = 31;
320
321 aBits.writeUB( nScaleBits, 5 );
322 aBits.writeFB( getFixed( rMatrix.get(0, 0) ), nScaleBits ); // Scale X
323 aBits.writeFB( getFixed( rMatrix.get(1, 1) ), nScaleBits ); // Scale Y
324 }
325
326 const sal_uInt8 bHasRotate = rMatrix.get(0, 1) != 0.0 || rMatrix.get(1, 0) != 0.0;
327
328 aBits.writeUB( bHasRotate, 1 );
329
330 if( bHasRotate )
331 {
332 sal_uInt8 nRotateBits = 31;
333
334 aBits.writeUB( nRotateBits, 5 );
335 aBits.writeFB( getFixed( rMatrix.get(0, 1) ), nRotateBits ); // RotateSkew0
336 aBits.writeFB( getFixed( rMatrix.get(1, 0) ), nRotateBits ); // RotateSkew1
337 }
338
339 sal_uInt8 nTranslateBits = 16;
340
341 aBits.writeUB( nTranslateBits, 5 );
342 aBits.writeSB( (sal_Int16)rMatrix.get(0, 2), nTranslateBits ); // Translate X
343 aBits.writeSB( (sal_Int16)rMatrix.get(1, 2), nTranslateBits ); // Translate Y
344
345 aBits.writeTo( rOut );
346 }
347
348 // -----------------------------------------------------------------------------
349
addString(const char * pString)350 void Tag::addString( const char* pString )
351 {
352 if( pString )
353 {
354 while( *pString )
355 addUI8( *pString++ );
356 }
357
358 addUI8( 0 );
359 }
360
361 // -----------------------------------------------------------------------------
362
addStream(SvStream & rIn)363 void Tag::addStream( SvStream& rIn )
364 {
365 *this << rIn;
366 }
367
368 ////////////////////////////////////////////////////////////////////////////////
369
Sprite(sal_uInt16 nId)370 Sprite::Sprite( sal_uInt16 nId )
371 : mnId( nId ), mnFrames(0)
372 {
373 }
374
375 // -----------------------------------------------------------------------------
376
~Sprite()377 Sprite::~Sprite()
378 {
379 for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); i++)
380 delete *i;
381 }
382
383 // -----------------------------------------------------------------------------
384
write(SvStream & out)385 void Sprite::write( SvStream& out )
386 {
387 SvMemoryStream aTmp;
388 for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); i++)
389 (*i)->write( aTmp );
390
391 if( !mnFrames )
392 mnFrames = 1;
393
394 aTmp.Seek(0);
395
396 Tag aTag( TAG_DEFINESPRITE );
397 aTag.addUI16( mnId );
398 aTag.addUI16( _uInt16( mnFrames ) );
399 aTag.addStream( aTmp );
400 aTag.write( out );
401 }
402
403 // -----------------------------------------------------------------------------
404
addTag(Tag * pNewTag)405 void Sprite::addTag( Tag* pNewTag )
406 {
407 if( pNewTag )
408 {
409 if( pNewTag->getTagId() == TAG_SHOWFRAME )
410 mnFrames++;
411
412 maTags.push_back( pNewTag );
413 }
414 }
415
416 /////////////////////////////////////////////////////////////////////////////////
417
getFixed(double fValue)418 sal_uInt32 swf::getFixed( double fValue )
419 {
420 sal_Int16 nUpper = (sal_Int16)floor(fValue);
421 sal_uInt16 nLower = (sal_uInt16)((fValue - floor(fValue))*0x10000);
422
423 sal_uInt32 temp = ((sal_Int32)nUpper)<<16;
424 temp |= nLower;
425
426 return temp;
427 }
428
429 /////////////////////////////////////////////////////////////////////////////////
430
431 /** constructs a new flash font for the given VCL Font */
FlashFont(const Font & rFont,sal_uInt16 nId)432 FlashFont::FlashFont( const Font& rFont, sal_uInt16 nId )
433 : maFont( rFont ), mnNextIndex(0), mnId( nId )
434 {
435 }
436
437 // -----------------------------------------------------------------------------
438
~FlashFont()439 FlashFont::~FlashFont()
440 {
441 }
442
443 // -----------------------------------------------------------------------------
444
445 /** gets the glyph id for the given character. The glyphs are created on demand */
getGlyph(sal_uInt16 nChar,VirtualDevice * pVDev)446 sal_uInt16 FlashFont::getGlyph( sal_uInt16 nChar, VirtualDevice* pVDev )
447 {
448 // see if we already created a glyph for this character
449 std::map<sal_uInt16, sal_uInt16, ltuint16>::iterator aIter( maGlyphIndex.find(nChar) );
450 if( aIter != maGlyphIndex.end() )
451 {
452 return aIter->second;
453 }
454
455 // if not, we create one now
456
457 maGlyphIndex[nChar] = mnNextIndex;
458
459 Font aOldFont( pVDev->GetFont() );
460 Font aNewFont( aOldFont );
461 aNewFont.SetAlign( ALIGN_BASELINE );
462 pVDev->SetFont( aNewFont );
463 aOldFont.SetOrientation(0);
464
465 // let the virtual device convert the character to polygons
466 PolyPolygon aPolyPoly;
467 pVDev->GetTextOutline( aPolyPoly, nChar );
468
469 maGlyphOffsets.push_back( _uInt16( maGlyphData.getOffset() ) );
470
471 // Number of fill and line index bits set to 1
472 maGlyphData.writeUB( 0x11, 8 );
473
474 const sal_uInt16 nCount = aPolyPoly.Count();
475 sal_uInt16 i,n;
476 for( i = 0; i < nCount; i++ )
477 {
478 Polygon& rPoly = aPolyPoly[ i ];
479
480 const sal_uInt16 nSize = rPoly.GetSize();
481 if( nSize )
482 {
483 // convert polygon to flash EM_SQUARE (1024x1024)
484 for( n = 0; n < nSize; n++ )
485 {
486 Point aPoint( rPoly[n] );
487 aPoint.X() = static_cast<long>((double(aPoint.X()) * 1024.0 ) / double(aOldFont.GetHeight()));
488 aPoint.Y() = static_cast<long>((double(aPoint.Y()) * 1024.0 ) / double(aOldFont.GetHeight()));
489 rPoly[n] = aPoint;
490 }
491 Writer::Impl_addPolygon( maGlyphData, rPoly, true );
492 }
493 }
494 Writer::Impl_addEndShapeRecord( maGlyphData );
495
496 maGlyphData.pad();
497
498 pVDev->SetFont( aOldFont );
499
500 return mnNextIndex++;
501 }
502
503 // -----------------------------------------------------------------------------
504
write(SvStream & out)505 void FlashFont::write( SvStream& out )
506 {
507 Tag aTag( TAG_DEFINEFONT );
508
509 aTag.addUI16( mnId );
510
511 sal_uInt16 nGlyphs = _uInt16( maGlyphOffsets.size() );
512 sal_uInt16 nOffset = nGlyphs * sizeof( sal_uInt16 );
513
514 for(vector< sal_uInt16 >::iterator i = maGlyphOffsets.begin(); i != maGlyphOffsets.end(); i++)
515 aTag.addUI16( nOffset + (*i) );
516
517 aTag.addBits( maGlyphData );
518
519 aTag.write( out );
520 }
521
522 ////////////////////////////////////////////////////////////////////////////////
523
524 /** this c'tor creates a solid fill style */
FillStyle(const Color & rSolidColor)525 FillStyle::FillStyle( const Color& rSolidColor )
526 : meType( solid ),
527 maColor( rSolidColor )
528 {
529 }
530
531 // -----------------------------------------------------------------------------
532
533 /** this c'tor creates a tiled or clipped bitmap fill style */
FillStyle(sal_uInt16 nBitmapId,bool bClipped,const::basegfx::B2DHomMatrix & rMatrix)534 FillStyle::FillStyle( sal_uInt16 nBitmapId, bool bClipped, const ::basegfx::B2DHomMatrix& rMatrix ) // #i73264#
535 : meType( bClipped ? clipped_bitmap : tiled_bitmap ),
536 maMatrix( rMatrix ),
537 mnBitmapId( nBitmapId )
538 {
539 }
540
541 // -----------------------------------------------------------------------------
542
Impl_getFillStyleType(const Gradient & rGradient)543 FillStyle::FillStyleType Impl_getFillStyleType( const Gradient& rGradient )
544 {
545 switch( rGradient.GetStyle() )
546 {
547 case GradientStyle_ELLIPTICAL:
548 case GradientStyle_RADIAL:
549 return FillStyle::radial_gradient;
550 // case GradientStyle_AXIAL:
551 // case GradientStyle_SQUARE:
552 // case GradientStyle_RECT:
553 // case GradientStyle_LINEAR:
554 default:
555 return FillStyle::linear_gradient;
556 }
557 }
558
559 // -----------------------------------------------------------------------------
560
561 /** this c'tor creates a linear or radial gradient fill style */
FillStyle(const Rectangle & rBoundRect,const Gradient & rGradient)562 FillStyle::FillStyle( const Rectangle& rBoundRect, const Gradient& rGradient )
563 : meType( Impl_getFillStyleType( rGradient ) ),
564 maGradient( rGradient ),
565 maBoundRect( rBoundRect )
566 {
567 }
568
569 // -----------------------------------------------------------------------------
570
addTo(Tag * pTag) const571 void FillStyle::addTo( Tag* pTag ) const
572 {
573 pTag->addUI8( sal::static_int_cast<sal_uInt8>( meType ) );
574 switch( meType )
575 {
576 case solid:
577 pTag->addRGBA( maColor );
578 break;
579 case linear_gradient:
580 case radial_gradient:
581 Impl_addGradient( pTag );
582 break;
583 case tiled_bitmap:
584 case clipped_bitmap:
585 pTag->addUI16( mnBitmapId );
586 pTag->addMatrix( maMatrix );
587 break;
588 }
589 }
590
591 // -----------------------------------------------------------------------------
592
593 struct GradRecord
594 {
595 sal_uInt8 mnRatio;
596 Color maColor;
597
GradRecordGradRecord598 GradRecord( sal_uInt8 nRatio, const Color& rColor ) : mnRatio( nRatio ), maColor( rColor ) {}
599 };
600
601 // TODO: better emulation of our gradients
Impl_addGradient(Tag * pTag) const602 void FillStyle::Impl_addGradient( Tag* pTag ) const
603 {
604 vector< struct GradRecord > aGradientRecords;
605 basegfx::B2DHomMatrix m(basegfx::tools::createRotateB2DHomMatrix((maGradient.GetAngle() - 900) * F_PI1800));
606
607 switch( maGradient.GetStyle() )
608 {
609 case GradientStyle_ELLIPTICAL:
610 case GradientStyle_RADIAL:
611 {
612 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) );
613 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetStartColor() ) );
614
615 double tx = ( maGradient.GetOfsX() * 32768.0 ) / 100.0;
616 double ty = ( maGradient.GetOfsY() * 32768.0 ) / 100.0;
617 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
618 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
619
620 m.scale( 1.2, 1.2 );
621
622 if( scalex > scaley )
623 {
624 double scale_move = scaley / scalex;
625
626 m.translate( tx, scale_move * ty );
627
628
629 m.scale( scalex, scalex );
630 }
631 else
632 {
633 double scale_move = scalex / scaley;
634
635 m.translate( scale_move * tx, ty );
636
637
638 m.scale( scaley, scaley );
639 }
640
641 }
642 break;
643 case GradientStyle_AXIAL:
644 {
645 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) );
646 aGradientRecords.push_back( GradRecord( 0x80, maGradient.GetStartColor() ) );
647 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) );
648 double tx = ( 32768.0 / 2.0 );
649 double ty = ( 32768.0 / 2.0 );
650 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
651 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
652
653 m.translate( tx, ty );
654 m.scale( scalex, scaley );
655 }
656 break;
657 case GradientStyle_SQUARE:
658 case GradientStyle_RECT:
659 case GradientStyle_LINEAR:
660 {
661 aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetStartColor() ) );
662 aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) );
663 double scalex = (double)maBoundRect.GetWidth() / 32768.0;
664 double scaley = (double)maBoundRect.GetHeight() / 32768.0;
665
666 m.scale( scalex, scaley );
667
668 m.translate( maBoundRect.GetWidth() / 2.0, maBoundRect.GetHeight() / 2.0 );
669 }
670 break;
671 case GradientStyle_FORCE_EQUAL_SIZE: break;
672 }
673
674 m.translate( maBoundRect.nLeft, maBoundRect.nTop );
675
676 pTag->addMatrix( m );
677
678 DBG_ASSERT( aGradientRecords.size() < 8, "Illegal FlashGradient!" );
679
680 pTag->addUI8( static_cast<sal_uInt8>( aGradientRecords.size() ) );
681
682 for(std::vector< GradRecord >::iterator i = aGradientRecords.begin(); i != aGradientRecords.end(); i++)
683 {
684 pTag->addUI8( (*i).mnRatio );
685 pTag->addRGBA( (*i).maColor );
686 }
687 }
688
689