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_vcl.hxx"
26 #include <vos/macros.hxx>
27 #include <rtl/crc.h>
28 #include <tools/stream.hxx>
29 #include <tools/vcompat.hxx>
30 #include <vcl/metaact.hxx>
31 #include <vcl/salbtype.hxx>
32 #include <vcl/outdev.hxx>
33 #include <vcl/window.hxx>
34 #ifndef _SV_CVTSVM_HXX
35 #include <vcl/cvtsvm.hxx>
36 #endif
37 #include <vcl/virdev.hxx>
38 #include <vcl/gdimtf.hxx>
39 #include <vcl/graphictools.hxx>
40 #include <basegfx/polygon/b2dpolygon.hxx>
41
42 // -----------
43 // - Defines -
44 // -----------
45
46 #define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
47
48 // --------------------------
49 // - Color exchange structs -
50 // --------------------------
51
52 struct ImplColAdjustParam
53 {
54 sal_uInt8* pMapR;
55 sal_uInt8* pMapG;
56 sal_uInt8* pMapB;
57 };
58
59 struct ImplBmpAdjustParam
60 {
61 short nLuminancePercent;
62 short nContrastPercent;
63 short nChannelRPercent;
64 short nChannelGPercent;
65 short nChannelBPercent;
66 double fGamma;
67 sal_Bool bInvert;
68 };
69
70 // -----------------------------------------------------------------------------
71
72 struct ImplColConvertParam
73 {
74 MtfConversion eConversion;
75 };
76
77 struct ImplBmpConvertParam
78 {
79 BmpConversion eConversion;
80 };
81
82 // -----------------------------------------------------------------------------
83
84 struct ImplColMonoParam
85 {
86 Color aColor;
87 };
88
89 struct ImplBmpMonoParam
90 {
91 Color aColor;
92 };
93
94 // -----------------------------------------------------------------------------
95
96 struct ImplColReplaceParam
97 {
98 sal_uLong* pMinR;
99 sal_uLong* pMaxR;
100 sal_uLong* pMinG;
101 sal_uLong* pMaxG;
102 sal_uLong* pMinB;
103 sal_uLong* pMaxB;
104 const Color* pDstCols;
105 sal_uLong nCount;
106 };
107
108 struct ImplBmpReplaceParam
109 {
110 const Color* pSrcCols;
111 const Color* pDstCols;
112 sal_uLong nCount;
113 const sal_uLong* pTols;
114 };
115
116
117 // ---------
118 // - Label -
119 // ---------
120
121 struct ImpLabel
122 {
123 String aLabelName;
124 sal_uLong nActionPos;
125
ImpLabelImpLabel126 ImpLabel( const String& rLabelName, sal_uLong _nActionPos ) :
127 aLabelName( rLabelName ),
128 nActionPos( _nActionPos ) {}
129 };
130
131 // -------------
132 // - LabelList -
133 // -------------
134
135 class ImpLabelList : private List
136 {
137 public:
138
ImpLabelList()139 ImpLabelList() : List( 8, 4, 4 ) {}
140 ImpLabelList( const ImpLabelList& rList );
141 ~ImpLabelList();
142
ImplInsert(ImpLabel * p)143 void ImplInsert( ImpLabel* p ) { Insert( p, LIST_APPEND ); }
ImplRemove(sal_uLong nPos)144 ImpLabel* ImplRemove( sal_uLong nPos ) { return (ImpLabel*) Remove( nPos ); }
ImplReplace(ImpLabel * p)145 void ImplReplace( ImpLabel* p ) { Replace( (void*)p ); }
ImplFirst()146 ImpLabel* ImplFirst() { return (ImpLabel*) First(); }
ImplNext()147 ImpLabel* ImplNext() { return (ImpLabel*) Next(); }
ImplGetLabel(sal_uLong nPos) const148 ImpLabel* ImplGetLabel( sal_uLong nPos ) const { return (ImpLabel*) GetObject( nPos ); }
149 sal_uLong ImplGetLabelPos( const String& rLabelName );
ImplCount() const150 sal_uLong ImplCount() const { return Count(); }
151 };
152
153 // ------------------------------------------------------------------------
154
ImpLabelList(const ImpLabelList & rList)155 ImpLabelList::ImpLabelList( const ImpLabelList& rList ) :
156 List( rList )
157 {
158 for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
159 ImplReplace( new ImpLabel( *pLabel ) );
160 }
161
162 // ------------------------------------------------------------------------
163
~ImpLabelList()164 ImpLabelList::~ImpLabelList()
165 {
166 for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
167 delete pLabel;
168 }
169
170 // ------------------------------------------------------------------------
171
ImplGetLabelPos(const String & rLabelName)172 sal_uLong ImpLabelList::ImplGetLabelPos( const String& rLabelName )
173 {
174 sal_uLong nLabelPos = METAFILE_LABEL_NOTFOUND;
175
176 for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
177 {
178 if ( rLabelName == pLabel->aLabelName )
179 {
180 nLabelPos = GetCurPos();
181 break;
182 }
183 }
184
185 return nLabelPos;
186 }
187
188 // ---------------
189 // - GDIMetaFile -
190 // ---------------
191
GDIMetaFile()192 GDIMetaFile::GDIMetaFile() :
193 List ( 0x3EFF, 64, 64 ),
194 aPrefSize ( 1, 1 ),
195 pPrev ( NULL ),
196 pNext ( NULL ),
197 pOutDev ( NULL ),
198 pLabelList ( NULL ),
199 bPause ( sal_False ),
200 bRecord ( sal_False )
201 {
202 }
203
204 // ------------------------------------------------------------------------
205
GDIMetaFile(const GDIMetaFile & rMtf)206 GDIMetaFile::GDIMetaFile( const GDIMetaFile& rMtf ) :
207 List ( rMtf ),
208 aPrefMapMode ( rMtf.aPrefMapMode ),
209 aPrefSize ( rMtf.aPrefSize ),
210 aHookHdlLink ( rMtf.aHookHdlLink ),
211 pPrev ( rMtf.pPrev ),
212 pNext ( rMtf.pNext ),
213 pOutDev ( NULL ),
214 bPause ( sal_False ),
215 bRecord ( sal_False )
216 {
217 // RefCount der MetaActions erhoehen
218 for( void* pAct = First(); pAct; pAct = Next() )
219 ( (MetaAction*) pAct )->Duplicate();
220
221 if( rMtf.pLabelList )
222 pLabelList = new ImpLabelList( *rMtf.pLabelList );
223 else
224 pLabelList = NULL;
225
226 if( rMtf.bRecord )
227 {
228 Record( rMtf.pOutDev );
229
230 if ( rMtf.bPause )
231 Pause( sal_True );
232 }
233 }
234
235 // ------------------------------------------------------------------------
236
~GDIMetaFile()237 GDIMetaFile::~GDIMetaFile()
238 {
239 Clear();
240 }
241
242 // ------------------------------------------------------------------------
243
operator =(const GDIMetaFile & rMtf)244 GDIMetaFile& GDIMetaFile::operator=( const GDIMetaFile& rMtf )
245 {
246 if( this != &rMtf )
247 {
248 Clear();
249
250 List::operator=( rMtf );
251
252 // RefCount der MetaActions erhoehen
253 for( void* pAct = First(); pAct; pAct = Next() )
254 ( (MetaAction*) pAct )->Duplicate();
255
256 if( rMtf.pLabelList )
257 pLabelList = new ImpLabelList( *rMtf.pLabelList );
258 else
259 pLabelList = NULL;
260
261 aPrefMapMode = rMtf.aPrefMapMode;
262 aPrefSize = rMtf.aPrefSize;
263 aHookHdlLink = rMtf.aHookHdlLink;
264 pPrev = rMtf.pPrev;
265 pNext = rMtf.pNext;
266 pOutDev = NULL;
267 bPause = sal_False;
268 bRecord = sal_False;
269
270 if( rMtf.bRecord )
271 {
272 Record( rMtf.pOutDev );
273
274 if( rMtf.bPause )
275 Pause( sal_True );
276 }
277 }
278
279 return *this;
280 }
281
282 // ------------------------------------------------------------------------
283
operator ==(const GDIMetaFile & rMtf) const284 sal_Bool GDIMetaFile::operator==( const GDIMetaFile& rMtf ) const
285 {
286 const sal_uLong nObjCount = Count();
287 sal_Bool bRet = sal_False;
288
289 if( this == &rMtf )
290 bRet = sal_True;
291 else if( rMtf.GetActionCount() == nObjCount &&
292 rMtf.GetPrefSize() == aPrefSize &&
293 rMtf.GetPrefMapMode() == aPrefMapMode )
294 {
295 bRet = sal_True;
296
297 for( sal_uLong n = 0UL; n < nObjCount; n++ )
298 {
299 if( GetObject( n ) != rMtf.GetObject( n ) )
300 {
301 bRet = sal_False;
302 break;
303 }
304 }
305 }
306
307 return bRet;
308 }
309
310 // ------------------------------------------------------------------------
311
IsEqual(const GDIMetaFile & rMtf) const312 sal_Bool GDIMetaFile::IsEqual( const GDIMetaFile& rMtf ) const
313 {
314 const sal_uLong nObjCount = Count();
315 sal_Bool bRet = sal_False;
316
317 if( this == &rMtf )
318 bRet = sal_True;
319 else if( rMtf.GetActionCount() == nObjCount &&
320 rMtf.GetPrefSize() == aPrefSize &&
321 rMtf.GetPrefMapMode() == aPrefMapMode )
322 {
323 bRet = sal_True;
324
325 for( sal_uLong n = 0UL; n < nObjCount; n++ )
326 {
327 if(!((MetaAction*)GetObject( n ))->IsEqual(*((MetaAction*)rMtf.GetObject( n ))))
328 {
329 bRet = sal_False;
330 break;
331 }
332 }
333 }
334
335 return bRet;
336 }
337
338 // ------------------------------------------------------------------------
339
Clear()340 void GDIMetaFile::Clear()
341 {
342 if( bRecord )
343 Stop();
344
345 for( void* pAct = First(); pAct; pAct = Next() )
346 ( (MetaAction*) pAct )->Delete();
347
348 List::Clear();
349
350 delete pLabelList;
351 pLabelList = NULL;
352 }
353
354 // ------------------------------------------------------------------------
355
Linker(OutputDevice * pOut,sal_Bool bLink)356 void GDIMetaFile::Linker( OutputDevice* pOut, sal_Bool bLink )
357 {
358 if( bLink )
359 {
360 pNext = NULL;
361 pPrev = pOut->GetConnectMetaFile();
362 pOut->SetConnectMetaFile( this );
363
364 if( pPrev )
365 pPrev->pNext = this;
366 }
367 else
368 {
369 if( pNext )
370 {
371 pNext->pPrev = pPrev;
372
373 if( pPrev )
374 pPrev->pNext = pNext;
375 }
376 else
377 {
378 if( pPrev )
379 pPrev->pNext = NULL;
380
381 pOut->SetConnectMetaFile( pPrev );
382 }
383
384 pPrev = NULL;
385 pNext = NULL;
386 }
387 }
388
389 // ------------------------------------------------------------------------
390
Hook()391 long GDIMetaFile::Hook()
392 {
393 return aHookHdlLink.Call( this );
394 }
395
396 // ------------------------------------------------------------------------
397
Record(OutputDevice * pOut)398 void GDIMetaFile::Record( OutputDevice* pOut )
399 {
400 if( bRecord )
401 Stop();
402
403 Last();
404 pOutDev = pOut;
405 bRecord = sal_True;
406 Linker( pOut, sal_True );
407 }
408
409 // ------------------------------------------------------------------------
410
Play(GDIMetaFile & rMtf,sal_uLong nPos)411 void GDIMetaFile::Play( GDIMetaFile& rMtf, sal_uLong nPos )
412 {
413 if ( !bRecord && !rMtf.bRecord )
414 {
415 MetaAction* pAction = GetCurAction();
416 const sal_uLong nObjCount = Count();
417
418 if( nPos > nObjCount )
419 nPos = nObjCount;
420
421 for( sal_uLong nCurPos = GetCurPos(); nCurPos < nPos; nCurPos++ )
422 {
423 if( !Hook() )
424 {
425 pAction->Duplicate();
426 rMtf.AddAction( pAction );
427 }
428
429 pAction = (MetaAction*) Next();
430 }
431 }
432 }
433
434 // ------------------------------------------------------------------------
435
Play(OutputDevice * pOut,sal_uLong nPos)436 void GDIMetaFile::Play( OutputDevice* pOut, sal_uLong nPos )
437 {
438 if( !bRecord )
439 {
440 MetaAction* pAction = GetCurAction();
441 const sal_uLong nObjCount = Count();
442 sal_uLong i = 0, nSyncCount = ( pOut->GetOutDevType() == OUTDEV_WINDOW ) ? 0x000000ff : 0xffffffff;
443
444 if( nPos > nObjCount )
445 nPos = nObjCount;
446
447 // #i23407# Set backwards-compatible text language and layout mode
448 // This is necessary, since old metafiles don't even know of these
449 // recent add-ons. Newer metafiles must of course explicitely set
450 // those states.
451 pOut->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE );
452 pOut->SetLayoutMode( 0 );
453 pOut->SetDigitLanguage( 0 );
454
455 for( sal_uLong nCurPos = GetCurPos(); nCurPos < nPos; nCurPos++ )
456 {
457 if( !Hook() )
458 {
459 pAction->Execute( pOut );
460
461 // flush output from time to time
462 if( i++ > nSyncCount )
463 ( (Window*) pOut )->Flush(), i = 0;
464 }
465
466 pAction = (MetaAction*) Next();
467 }
468
469 pOut->Pop();
470 }
471 }
472
473 // ------------------------------------------------------------------------
474
Play(OutputDevice * pOut,const Point & rPos,const Size & rSize,sal_uLong nPos)475 void GDIMetaFile::Play( OutputDevice* pOut, const Point& rPos,
476 const Size& rSize, sal_uLong nPos )
477 {
478 Region aDrawClipRegion;
479 MapMode aDrawMap( GetPrefMapMode() );
480 Size aDestSize( pOut->LogicToPixel( rSize ) );
481
482 if( aDestSize.Width() && aDestSize.Height() )
483 {
484 Size aTmpPrefSize( pOut->LogicToPixel( GetPrefSize(), aDrawMap ) );
485 GDIMetaFile* pMtf = pOut->GetConnectMetaFile();
486
487 if( !aTmpPrefSize.Width() )
488 aTmpPrefSize.Width() = aDestSize.Width();
489
490 if( !aTmpPrefSize.Height() )
491 aTmpPrefSize.Height() = aDestSize.Height();
492
493 Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() );
494 Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() );
495
496 aScaleX *= aDrawMap.GetScaleX(); aDrawMap.SetScaleX( aScaleX );
497 aScaleY *= aDrawMap.GetScaleY(); aDrawMap.SetScaleY( aScaleY );
498
499 // #i47260# Convert logical output position to offset within
500 // the metafile's mapmode. Therefore, disable pixel offset on
501 // outdev, it's inverse mnOutOffLogicX/Y is calculated for a
502 // different mapmode (the one currently set on pOut, that is)
503 // - thus, aDrawMap's origin would generally be wrong. And
504 // even _if_ aDrawMap is similar to pOutDev's current mapmode,
505 // it's _still_ undesirable to have pixel offset unequal zero,
506 // because one would still get round-off errors (the
507 // round-trip error for LogicToPixel( PixelToLogic() ) was the
508 // reason for having pixel offset in the first place).
509 const Size& rOldOffset( pOut->GetPixelOffset() );
510 const Size aEmptySize;
511 pOut->SetPixelOffset( aEmptySize );
512 aDrawMap.SetOrigin( pOut->PixelToLogic( pOut->LogicToPixel( rPos ), aDrawMap ) );
513 pOut->SetPixelOffset( rOldOffset );
514
515 pOut->Push();
516
517 if ( pMtf && pMtf->IsRecord() && ( pOut->GetOutDevType() != OUTDEV_PRINTER ) )
518 pOut->SetRelativeMapMode( aDrawMap );
519 else
520 pOut->SetMapMode( aDrawMap );
521
522 // #i23407# Set backwards-compatible text language and layout mode
523 // This is necessary, since old metafiles don't even know of these
524 // recent add-ons. Newer metafiles must of course explicitely set
525 // those states.
526 pOut->SetLayoutMode( 0 );
527 pOut->SetDigitLanguage( 0 );
528
529 Play( pOut, nPos );
530
531 pOut->Pop();
532 }
533 }
534
535 // ------------------------------------------------------------------------
536
Pause(sal_Bool _bPause)537 void GDIMetaFile::Pause( sal_Bool _bPause )
538 {
539 if( bRecord )
540 {
541 if( _bPause )
542 {
543 if( !bPause )
544 Linker( pOutDev, sal_False );
545 }
546 else
547 {
548 if( bPause )
549 Linker( pOutDev, sal_True );
550 }
551
552 bPause = _bPause;
553 }
554 }
555
556 // ------------------------------------------------------------------------
557
Stop()558 void GDIMetaFile::Stop()
559 {
560 if( bRecord )
561 {
562 bRecord = sal_False;
563
564 if( !bPause )
565 Linker( pOutDev, sal_False );
566 else
567 bPause = sal_False;
568 }
569 }
570
571 // ------------------------------------------------------------------------
572
WindStart()573 void GDIMetaFile::WindStart()
574 {
575 if( !bRecord )
576 First();
577 }
578
579 // ------------------------------------------------------------------------
580
WindEnd()581 void GDIMetaFile::WindEnd()
582 {
583 if( !bRecord )
584 Last();
585 }
586
587 // ------------------------------------------------------------------------
588
Wind(sal_uLong nActionPos)589 void GDIMetaFile::Wind( sal_uLong nActionPos )
590 {
591 if( !bRecord )
592 Seek( nActionPos );
593 }
594
595 // ------------------------------------------------------------------------
596
WindPrev()597 void GDIMetaFile::WindPrev()
598 {
599 if( !bRecord )
600 Prev();
601 }
602
603 // ------------------------------------------------------------------------
604
WindNext()605 void GDIMetaFile::WindNext()
606 {
607 if( !bRecord )
608 Next();
609 }
610
611 // ------------------------------------------------------------------------
612
AddAction(MetaAction * pAction)613 void GDIMetaFile::AddAction( MetaAction* pAction )
614 {
615 Insert( pAction, LIST_APPEND );
616
617 if( pPrev )
618 {
619 pAction->Duplicate();
620 pPrev->AddAction( pAction );
621 }
622 }
623
624 // ------------------------------------------------------------------------
625
AddAction(MetaAction * pAction,sal_uLong nPos)626 void GDIMetaFile::AddAction( MetaAction* pAction, sal_uLong nPos )
627 {
628 Insert( pAction, nPos );
629
630 if( pPrev )
631 {
632 pAction->Duplicate();
633 pPrev->AddAction( pAction, nPos );
634 }
635 }
636
637 // ------------------------------------------------------------------------
638
639 // @since #110496#
RemoveAction(sal_uLong nPos)640 void GDIMetaFile::RemoveAction( sal_uLong nPos )
641 {
642 Remove( nPos );
643
644 if( pPrev )
645 pPrev->RemoveAction( nPos );
646 }
647
648 // ------------------------------------------------------------------------
649
CopyAction(sal_uLong nPos) const650 MetaAction* GDIMetaFile::CopyAction( sal_uLong nPos ) const
651 {
652 return ( (MetaAction*) GetObject( nPos ) )->Clone();
653 }
654
655 // ------------------------------------------------------------------------
656
GetActionPos(const String & rLabel)657 sal_uLong GDIMetaFile::GetActionPos( const String& rLabel )
658 {
659 ImpLabel* pLabel = NULL;
660
661 if( pLabelList )
662 pLabel = pLabelList->ImplGetLabel( pLabelList->ImplGetLabelPos( rLabel ) );
663 else
664 pLabel = NULL;
665
666 return( pLabel ? pLabel->nActionPos : METAFILE_LABEL_NOTFOUND );
667 }
668
669 // ------------------------------------------------------------------------
670
InsertLabel(const String & rLabel,sal_uLong nActionPos)671 sal_Bool GDIMetaFile::InsertLabel( const String& rLabel, sal_uLong nActionPos )
672 {
673 sal_Bool bRet = sal_False;
674
675 if( !pLabelList )
676 pLabelList = new ImpLabelList;
677
678 if( pLabelList->ImplGetLabelPos( rLabel ) == METAFILE_LABEL_NOTFOUND )
679 {
680 pLabelList->ImplInsert( new ImpLabel( rLabel, nActionPos ) );
681 bRet = sal_True;
682 }
683
684 return bRet;
685 }
686
687 // ------------------------------------------------------------------------
688
RemoveLabel(const String & rLabel)689 void GDIMetaFile::RemoveLabel( const String& rLabel )
690 {
691 if( pLabelList )
692 {
693 const sal_uLong nLabelPos = pLabelList->ImplGetLabelPos( rLabel );
694
695 if( nLabelPos != METAFILE_LABEL_NOTFOUND )
696 delete pLabelList->ImplRemove( nLabelPos );
697 }
698 }
699
700 // ------------------------------------------------------------------------
701
RenameLabel(const String & rLabel,const String & rNewLabel)702 void GDIMetaFile::RenameLabel( const String& rLabel, const String& rNewLabel )
703 {
704 if( pLabelList )
705 {
706 const sal_uLong nLabelPos = pLabelList->ImplGetLabelPos( rLabel );
707
708 if ( nLabelPos != METAFILE_LABEL_NOTFOUND )
709 pLabelList->ImplGetLabel( nLabelPos )->aLabelName = rNewLabel;
710 }
711 }
712
713 // ------------------------------------------------------------------------
714
GetLabelCount() const715 sal_uLong GDIMetaFile::GetLabelCount() const
716 {
717 return( pLabelList ? pLabelList->ImplCount() : 0UL );
718 }
719
720 // ------------------------------------------------------------------------
721
GetLabel(sal_uLong nLabel)722 String GDIMetaFile::GetLabel( sal_uLong nLabel )
723 {
724 String aString;
725
726 if( pLabelList )
727 {
728 const ImpLabel* pLabel = pLabelList->ImplGetLabel( nLabel );
729
730 if( pLabel )
731 aString = pLabel->aLabelName;
732 }
733
734 return aString;
735 }
736
737 // ------------------------------------------------------------------------
738
SaveStatus()739 sal_Bool GDIMetaFile::SaveStatus()
740 {
741 if ( bRecord )
742 {
743 if ( bPause )
744 Linker( pOutDev, sal_True );
745
746 AddAction( new MetaLineColorAction( pOutDev->GetLineColor(),
747 pOutDev->IsLineColor() ) );
748 AddAction( new MetaFillColorAction( pOutDev->GetFillColor(),
749 pOutDev->IsFillColor() ) );
750 AddAction( new MetaFontAction( pOutDev->GetFont() ) );
751 AddAction( new MetaTextColorAction( pOutDev->GetTextColor() ) );
752 AddAction( new MetaTextFillColorAction( pOutDev->GetTextFillColor(),
753 pOutDev->IsTextFillColor() ) );
754 AddAction( new MetaTextLineColorAction( pOutDev->GetTextLineColor(),
755 pOutDev->IsTextLineColor() ) );
756 AddAction( new MetaOverlineColorAction( pOutDev->GetOverlineColor(),
757 pOutDev->IsOverlineColor() ) );
758 AddAction( new MetaTextAlignAction( pOutDev->GetTextAlign() ) );
759 AddAction( new MetaRasterOpAction( pOutDev->GetRasterOp() ) );
760 AddAction( new MetaMapModeAction( pOutDev->GetMapMode() ) );
761 AddAction( new MetaClipRegionAction( pOutDev->GetClipRegion(),
762 pOutDev->IsClipRegion() ) );
763
764 if ( bPause )
765 Linker( pOutDev, sal_False );
766
767 return sal_True;
768 }
769 else
770 return sal_False;
771 }
772
773 // ------------------------------------------------------------------------
774
Mirror(sal_uLong nMirrorFlags)775 sal_Bool GDIMetaFile::Mirror( sal_uLong nMirrorFlags )
776 {
777 const Size aOldPrefSize( GetPrefSize() );
778 long nMoveX, nMoveY;
779 double fScaleX, fScaleY;
780 sal_Bool bRet;
781
782 if( nMirrorFlags & MTF_MIRROR_HORZ )
783 nMoveX = VOS_ABS( aOldPrefSize.Width() ) - 1, fScaleX = -1.0;
784 else
785 nMoveX = 0, fScaleX = 1.0;
786
787 if( nMirrorFlags & MTF_MIRROR_VERT )
788 nMoveY = VOS_ABS( aOldPrefSize.Height() ) - 1, fScaleY = -1.0;
789 else
790 nMoveY = 0, fScaleY = 1.0;
791
792 if( ( fScaleX != 1.0 ) || ( fScaleY != 1.0 ) )
793 {
794 Scale( fScaleX, fScaleY );
795 Move( nMoveX, nMoveY );
796 SetPrefSize( aOldPrefSize );
797 bRet = sal_True;
798 }
799 else
800 bRet = sal_False;
801
802 return bRet;
803 }
804
805 // ------------------------------------------------------------------------
806
Move(long nX,long nY)807 void GDIMetaFile::Move( long nX, long nY )
808 {
809 const Size aBaseOffset( nX, nY );
810 Size aOffset( aBaseOffset );
811 VirtualDevice aMapVDev;
812
813 aMapVDev.EnableOutput( sal_False );
814 aMapVDev.SetMapMode( GetPrefMapMode() );
815
816 for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
817 {
818 const long nType = pAct->GetType();
819 MetaAction* pModAct;
820
821 if( pAct->GetRefCount() > 1 )
822 {
823 Replace( pModAct = pAct->Clone(), GetCurPos() );
824 pAct->Delete();
825 }
826 else
827 pModAct = pAct;
828
829 if( ( META_MAPMODE_ACTION == nType ) ||
830 ( META_PUSH_ACTION == nType ) ||
831 ( META_POP_ACTION == nType ) )
832 {
833 pModAct->Execute( &aMapVDev );
834 aOffset = aMapVDev.LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev.GetMapMode() );
835 }
836
837 pModAct->Move( aOffset.Width(), aOffset.Height() );
838 }
839 }
840
Move(long nX,long nY,long nDPIX,long nDPIY)841 void GDIMetaFile::Move( long nX, long nY, long nDPIX, long nDPIY )
842 {
843 const Size aBaseOffset( nX, nY );
844 Size aOffset( aBaseOffset );
845 VirtualDevice aMapVDev;
846
847 aMapVDev.EnableOutput( sal_False );
848 aMapVDev.SetReferenceDevice( nDPIX, nDPIY );
849 aMapVDev.SetMapMode( GetPrefMapMode() );
850
851 for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
852 {
853 const long nType = pAct->GetType();
854 MetaAction* pModAct;
855
856 if( pAct->GetRefCount() > 1 )
857 {
858 Replace( pModAct = pAct->Clone(), GetCurPos() );
859 pAct->Delete();
860 }
861 else
862 pModAct = pAct;
863
864 if( ( META_MAPMODE_ACTION == nType ) ||
865 ( META_PUSH_ACTION == nType ) ||
866 ( META_POP_ACTION == nType ) )
867 {
868 pModAct->Execute( &aMapVDev );
869 if( aMapVDev.GetMapMode().GetMapUnit() == MAP_PIXEL )
870 {
871 aOffset = aMapVDev.LogicToPixel( aBaseOffset, GetPrefMapMode() );
872 MapMode aMap( aMapVDev.GetMapMode() );
873 aOffset.Width() = static_cast<long>(aOffset.Width() * (double)aMap.GetScaleX());
874 aOffset.Height() = static_cast<long>(aOffset.Height() * (double)aMap.GetScaleY());
875 }
876 else
877 aOffset = aMapVDev.LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev.GetMapMode() );
878 }
879
880 pModAct->Move( aOffset.Width(), aOffset.Height() );
881 }
882 }
883
884 // ------------------------------------------------------------------------
885
Scale(double fScaleX,double fScaleY)886 void GDIMetaFile::Scale( double fScaleX, double fScaleY )
887 {
888 for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
889 {
890 MetaAction* pModAct;
891
892 if( pAct->GetRefCount() > 1 )
893 {
894 Replace( pModAct = pAct->Clone(), GetCurPos() );
895 pAct->Delete();
896 }
897 else
898 pModAct = pAct;
899
900 pModAct->Scale( fScaleX, fScaleY );
901 }
902
903 aPrefSize.Width() = FRound( aPrefSize.Width() * fScaleX );
904 aPrefSize.Height() = FRound( aPrefSize.Height() * fScaleY );
905 }
906
907 // ------------------------------------------------------------------------
908
Scale(const Fraction & rScaleX,const Fraction & rScaleY)909 void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY )
910 {
911 Scale( (double) rScaleX, (double) rScaleY );
912 }
913
914 // ------------------------------------------------------------------------
915
Clip(const Rectangle & i_rClipRect)916 void GDIMetaFile::Clip( const Rectangle& i_rClipRect )
917 {
918 Rectangle aCurRect( i_rClipRect );
919 VirtualDevice aMapVDev;
920
921 aMapVDev.EnableOutput( sal_False );
922 aMapVDev.SetMapMode( GetPrefMapMode() );
923
924 for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
925 {
926 const long nType = pAct->GetType();
927
928 if( ( META_MAPMODE_ACTION == nType ) ||
929 ( META_PUSH_ACTION == nType ) ||
930 ( META_POP_ACTION == nType ) )
931 {
932 pAct->Execute( &aMapVDev );
933 aCurRect = aMapVDev.LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev.GetMapMode() );
934 }
935 else if( nType == META_CLIPREGION_ACTION )
936 {
937 MetaClipRegionAction* pOldAct = (MetaClipRegionAction*)pAct;
938 Region aNewReg( aCurRect );
939 if( pOldAct->IsClipping() )
940 aNewReg.Intersect( pOldAct->GetRegion() );
941 MetaClipRegionAction* pNewAct = new MetaClipRegionAction( aNewReg, sal_True );
942 Replace( pNewAct, GetCurPos() );
943 pOldAct->Delete();
944 }
945 }
946 }
947
948 // ------------------------------------------------------------------------
949
ImplGetRotatedPoint(const Point & rPt,const Point & rRotatePt,const Size & rOffset,double fSin,double fCos)950 Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt,
951 const Size& rOffset, double fSin, double fCos )
952 {
953 const long nX = rPt.X() - rRotatePt.X();
954 const long nY = rPt.Y() - rRotatePt.Y();
955
956 return Point( FRound( fCos * nX + fSin * nY ) + rRotatePt.X() + rOffset.Width(),
957 -FRound( fSin * nX - fCos * nY ) + rRotatePt.Y() + rOffset.Height() );
958 }
959
960 // ------------------------------------------------------------------------
961
ImplGetRotatedPolygon(const Polygon & rPoly,const Point & rRotatePt,const Size & rOffset,double fSin,double fCos)962 Polygon GDIMetaFile::ImplGetRotatedPolygon( const Polygon& rPoly, const Point& rRotatePt,
963 const Size& rOffset, double fSin, double fCos )
964 {
965 Polygon aRet( rPoly );
966
967 aRet.Rotate( rRotatePt, fSin, fCos );
968 aRet.Move( rOffset.Width(), rOffset.Height() );
969
970 return aRet;
971 }
972
973 // ------------------------------------------------------------------------
974
ImplGetRotatedPolyPolygon(const PolyPolygon & rPolyPoly,const Point & rRotatePt,const Size & rOffset,double fSin,double fCos)975 PolyPolygon GDIMetaFile::ImplGetRotatedPolyPolygon( const PolyPolygon& rPolyPoly, const Point& rRotatePt,
976 const Size& rOffset, double fSin, double fCos )
977 {
978 PolyPolygon aRet( rPolyPoly );
979
980 aRet.Rotate( rRotatePt, fSin, fCos );
981 aRet.Move( rOffset.Width(), rOffset.Height() );
982
983 return aRet;
984 }
985
986 // ------------------------------------------------------------------------
987
ImplAddGradientEx(GDIMetaFile & rMtf,const OutputDevice & rMapDev,const PolyPolygon & rPolyPoly,const Gradient & rGrad)988 void GDIMetaFile::ImplAddGradientEx( GDIMetaFile& rMtf,
989 const OutputDevice& rMapDev,
990 const PolyPolygon& rPolyPoly,
991 const Gradient& rGrad )
992 {
993 // #105055# Generate comment, GradientEx and Gradient actions
994 // (within DrawGradient)
995 VirtualDevice aVDev( rMapDev, 0 );
996 aVDev.EnableOutput( sal_False );
997 GDIMetaFile aGradMtf;
998
999 aGradMtf.Record( &aVDev );
1000 aVDev.DrawGradient( rPolyPoly, rGrad );
1001 aGradMtf.Stop();
1002
1003 int i, nAct( aGradMtf.GetActionCount() );
1004 for( i=0; i<nAct; ++i )
1005 {
1006 MetaAction* pMetaAct = aGradMtf.GetAction(i);
1007 pMetaAct->Duplicate();
1008 rMtf.AddAction( pMetaAct );
1009 }
1010 }
1011
1012 // ------------------------------------------------------------------------
1013
Rotate(long nAngle10)1014 void GDIMetaFile::Rotate( long nAngle10 )
1015 {
1016 nAngle10 %= 3600L;
1017 nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10;
1018
1019 if( nAngle10 )
1020 {
1021 GDIMetaFile aMtf;
1022 VirtualDevice aMapVDev;
1023 const double fAngle = F_PI1800 * nAngle10;
1024 const double fSin = sin( fAngle );
1025 const double fCos = cos( fAngle );
1026 Rectangle aRect=Rectangle( Point(), GetPrefSize() );
1027 Polygon aPoly( aRect );
1028
1029 aPoly.Rotate( Point(), fSin, fCos );
1030
1031 aMapVDev.EnableOutput( sal_False );
1032 aMapVDev.SetMapMode( GetPrefMapMode() );
1033
1034 const Rectangle aNewBound( aPoly.GetBoundRect() );
1035
1036 const Point aOrigin( GetPrefMapMode().GetOrigin().X(), GetPrefMapMode().GetOrigin().Y() );
1037 const Size aOffset( -aNewBound.Left(), -aNewBound.Top() );
1038
1039 Point aRotAnchor( aOrigin );
1040 Size aRotOffset( aOffset );
1041
1042 for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
1043 {
1044 const sal_uInt16 nActionType = pAction->GetType();
1045
1046 switch( nActionType )
1047 {
1048 case( META_PIXEL_ACTION ):
1049 {
1050 MetaPixelAction* pAct = (MetaPixelAction*) pAction;
1051 aMtf.AddAction( new MetaPixelAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1052 pAct->GetColor() ) );
1053 }
1054 break;
1055
1056 case( META_POINT_ACTION ):
1057 {
1058 MetaPointAction* pAct = (MetaPointAction*) pAction;
1059 aMtf.AddAction( new MetaPointAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1060 }
1061 break;
1062
1063 case( META_LINE_ACTION ):
1064 {
1065 MetaLineAction* pAct = (MetaLineAction*) pAction;
1066 aMtf.AddAction( new MetaLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1067 ImplGetRotatedPoint( pAct->GetEndPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1068 pAct->GetLineInfo() ) );
1069 }
1070 break;
1071
1072 case( META_RECT_ACTION ):
1073 {
1074 MetaRectAction* pAct = (MetaRectAction*) pAction;
1075 aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1076 }
1077 break;
1078
1079 case( META_ROUNDRECT_ACTION ):
1080 {
1081 MetaRoundRectAction* pAct = (MetaRoundRectAction*) pAction;
1082 const Polygon aRoundRectPoly( pAct->GetRect(), pAct->GetHorzRound(), pAct->GetVertRound() );
1083
1084 aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aRoundRectPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1085 }
1086 break;
1087
1088 case( META_ELLIPSE_ACTION ):
1089 {
1090 MetaEllipseAction* pAct = (MetaEllipseAction*) pAction;
1091 const Polygon aEllipsePoly( pAct->GetRect().Center(), pAct->GetRect().GetWidth() >> 1, pAct->GetRect().GetHeight() >> 1 );
1092
1093 aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aEllipsePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1094 }
1095 break;
1096
1097 case( META_ARC_ACTION ):
1098 {
1099 MetaArcAction* pAct = (MetaArcAction*) pAction;
1100 const Polygon aArcPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_ARC );
1101
1102 aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aArcPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1103 }
1104 break;
1105
1106 case( META_PIE_ACTION ):
1107 {
1108 MetaPieAction* pAct = (MetaPieAction*) pAction;
1109 const Polygon aPiePoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_PIE );
1110
1111 aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aPiePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1112 }
1113 break;
1114
1115 case( META_CHORD_ACTION ):
1116 {
1117 MetaChordAction* pAct = (MetaChordAction*) pAction;
1118 const Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_CHORD );
1119
1120 aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aChordPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1121 }
1122 break;
1123
1124 case( META_POLYLINE_ACTION ):
1125 {
1126 MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction;
1127 aMtf.AddAction( new MetaPolyLineAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->GetLineInfo() ) );
1128 }
1129 break;
1130
1131 case( META_POLYGON_ACTION ):
1132 {
1133 MetaPolygonAction* pAct = (MetaPolygonAction*) pAction;
1134 aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1135 }
1136 break;
1137
1138 case( META_POLYPOLYGON_ACTION ):
1139 {
1140 MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction;
1141 aMtf.AddAction( new MetaPolyPolygonAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1142 }
1143 break;
1144
1145 case( META_TEXT_ACTION ):
1146 {
1147 MetaTextAction* pAct = (MetaTextAction*) pAction;
1148 aMtf.AddAction( new MetaTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1149 pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
1150 }
1151 break;
1152
1153 case( META_TEXTARRAY_ACTION ):
1154 {
1155 MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction;
1156 aMtf.AddAction( new MetaTextArrayAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1157 pAct->GetText(), pAct->GetDXArray(), pAct->GetIndex(), pAct->GetLen() ) );
1158 }
1159 break;
1160
1161 case( META_STRETCHTEXT_ACTION ):
1162 {
1163 MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction;
1164 aMtf.AddAction( new MetaStretchTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1165 pAct->GetWidth(), pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
1166 }
1167 break;
1168
1169 case( META_TEXTLINE_ACTION ):
1170 {
1171 MetaTextLineAction* pAct = (MetaTextLineAction*) pAction;
1172 aMtf.AddAction( new MetaTextLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1173 pAct->GetWidth(), pAct->GetStrikeout(), pAct->GetUnderline(), pAct->GetOverline() ) );
1174 }
1175 break;
1176
1177 case( META_BMPSCALE_ACTION ):
1178 {
1179 MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
1180 Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1181 Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
1182 BitmapEx aBmpEx( pAct->GetBitmap() );
1183
1184 aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
1185 aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(),
1186 aBmpEx ) );
1187 }
1188 break;
1189
1190 case( META_BMPSCALEPART_ACTION ):
1191 {
1192 MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
1193 Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1194 Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
1195 BitmapEx aBmpEx( pAct->GetBitmap() );
1196
1197 aBmpEx.Crop( Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
1198 aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
1199
1200 aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1201 }
1202 break;
1203
1204 case( META_BMPEXSCALE_ACTION ):
1205 {
1206 MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
1207 Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1208 Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
1209 BitmapEx aBmpEx( pAct->GetBitmapEx() );
1210
1211 aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
1212
1213 aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1214 }
1215 break;
1216
1217 case( META_BMPEXSCALEPART_ACTION ):
1218 {
1219 MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
1220 Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1221 Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
1222 BitmapEx aBmpEx( pAct->GetBitmapEx() );
1223
1224 aBmpEx.Crop( Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
1225 aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
1226
1227 aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1228 }
1229 break;
1230
1231 case( META_GRADIENT_ACTION ):
1232 {
1233 MetaGradientAction* pAct = (MetaGradientAction*) pAction;
1234
1235 ImplAddGradientEx( aMtf, aMapVDev,
1236 ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ),
1237 pAct->GetGradient() );
1238 }
1239 break;
1240
1241 case( META_GRADIENTEX_ACTION ):
1242 {
1243 MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
1244 aMtf.AddAction( new MetaGradientExAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1245 pAct->GetGradient() ) );
1246 }
1247 break;
1248
1249 // #105055# Handle gradientex comment block correctly
1250 case( META_COMMENT_ACTION ):
1251 {
1252 MetaCommentAction* pCommentAct = (MetaCommentAction*) pAction;
1253 if( pCommentAct->GetComment().Equals( "XGRAD_SEQ_BEGIN" ) )
1254 {
1255 int nBeginComments( 1 );
1256 pAction = (MetaAction*) Next();
1257
1258 // skip everything, except gradientex action
1259 while( pAction )
1260 {
1261 const sal_uInt16 nType = pAction->GetType();
1262
1263 if( META_GRADIENTEX_ACTION == nType )
1264 {
1265 // Add rotated gradientex
1266 MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
1267 ImplAddGradientEx( aMtf, aMapVDev,
1268 ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1269 pAct->GetGradient() );
1270 }
1271 else if( META_COMMENT_ACTION == nType)
1272 {
1273 MetaCommentAction* pAct = (MetaCommentAction*) pAction;
1274 if( pAct->GetComment().Equals( "XGRAD_SEQ_END" ) )
1275 {
1276 // handle nested blocks
1277 --nBeginComments;
1278
1279 // gradientex comment block: end reached, done.
1280 if( !nBeginComments )
1281 break;
1282 }
1283 else if( pAct->GetComment().Equals( "XGRAD_SEQ_BEGIN" ) )
1284 {
1285 // handle nested blocks
1286 ++nBeginComments;
1287 }
1288
1289 }
1290
1291 pAction = (MetaAction*) Next();
1292 }
1293 }
1294 else
1295 {
1296 sal_Bool bPathStroke = pCommentAct->GetComment().Equals( "XPATHSTROKE_SEQ_BEGIN" );
1297 if ( bPathStroke || pCommentAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) )
1298 {
1299 if ( pCommentAct->GetDataSize() )
1300 {
1301 SvMemoryStream aMemStm( (void*)pCommentAct->GetData(), pCommentAct->GetDataSize(), STREAM_READ );
1302 SvMemoryStream aDest;
1303 if ( bPathStroke )
1304 {
1305 SvtGraphicStroke aStroke;
1306 aMemStm >> aStroke;
1307 Polygon aPath;
1308 aStroke.getPath( aPath );
1309 aStroke.setPath( ImplGetRotatedPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
1310 aDest << aStroke;
1311 aMtf.AddAction( new MetaCommentAction( "XPATHSTROKE_SEQ_BEGIN", 0,
1312 static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) );
1313 }
1314 else
1315 {
1316 SvtGraphicFill aFill;
1317 aMemStm >> aFill;
1318 PolyPolygon aPath;
1319 aFill.getPath( aPath );
1320 aFill.setPath( ImplGetRotatedPolyPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
1321 aDest << aFill;
1322 aMtf.AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
1323 static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) );
1324 }
1325 }
1326 }
1327 else if ( pCommentAct->GetComment().Equals( "XPATHSTROKE_SEQ_END" )
1328 || pCommentAct->GetComment().Equals( "XPATHFILL_SEQ_END" ) )
1329 {
1330 pAction->Execute( &aMapVDev );
1331 pAction->Duplicate();
1332 aMtf.AddAction( pAction );
1333 }
1334 }
1335 }
1336 break;
1337
1338 case( META_HATCH_ACTION ):
1339 {
1340 MetaHatchAction* pAct = (MetaHatchAction*) pAction;
1341 Hatch aHatch( pAct->GetHatch() );
1342
1343 aHatch.SetAngle( aHatch.GetAngle() + (sal_uInt16) nAngle10 );
1344 aMtf.AddAction( new MetaHatchAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1345 aHatch ) );
1346 }
1347 break;
1348
1349 case( META_TRANSPARENT_ACTION ):
1350 {
1351 MetaTransparentAction* pAct = (MetaTransparentAction*) pAction;
1352 aMtf.AddAction( new MetaTransparentAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1353 pAct->GetTransparence() ) );
1354 }
1355 break;
1356
1357 case( META_FLOATTRANSPARENT_ACTION ):
1358 {
1359 MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
1360 GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
1361 Polygon aMtfPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1362 Rectangle aMtfRect( aMtfPoly.GetBoundRect() );
1363
1364 aTransMtf.Rotate( nAngle10 );
1365 aMtf.AddAction( new MetaFloatTransparentAction( aTransMtf, aMtfRect.TopLeft(), aMtfRect.GetSize(),
1366 pAct->GetGradient() ) );
1367 }
1368 break;
1369
1370 case( META_EPS_ACTION ):
1371 {
1372 MetaEPSAction* pAct = (MetaEPSAction*) pAction;
1373 GDIMetaFile aEPSMtf( pAct->GetSubstitute() );
1374 Polygon aEPSPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1375 Rectangle aEPSRect( aEPSPoly.GetBoundRect() );
1376
1377 aEPSMtf.Rotate( nAngle10 );
1378 aMtf.AddAction( new MetaEPSAction( aEPSRect.TopLeft(), aEPSRect.GetSize(),
1379 pAct->GetLink(), aEPSMtf ) );
1380 }
1381 break;
1382
1383 case( META_CLIPREGION_ACTION ):
1384 {
1385 MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction;
1386
1387 if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygonOrB2DPolyPolygon() )
1388 aMtf.AddAction( new MetaClipRegionAction( Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), sal_True ) );
1389 else
1390 {
1391 pAction->Duplicate();
1392 aMtf.AddAction( pAction );
1393 }
1394 }
1395 break;
1396
1397 case( META_ISECTRECTCLIPREGION_ACTION ):
1398 {
1399 MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction;
1400 aMtf.AddAction( new MetaISectRegionClipRegionAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1401 }
1402 break;
1403
1404 case( META_ISECTREGIONCLIPREGION_ACTION ):
1405 {
1406 MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction;
1407 const Region& rRegion = pAct->GetRegion();
1408
1409 if( rRegion.HasPolyPolygonOrB2DPolyPolygon() )
1410 aMtf.AddAction( new MetaISectRegionClipRegionAction( Region( ImplGetRotatedPolyPolygon( rRegion.GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) );
1411 else
1412 {
1413 pAction->Duplicate();
1414 aMtf.AddAction( pAction );
1415 }
1416 }
1417 break;
1418
1419 case( META_REFPOINT_ACTION ):
1420 {
1421 MetaRefPointAction* pAct = (MetaRefPointAction*) pAction;
1422 aMtf.AddAction( new MetaRefPointAction( ImplGetRotatedPoint( pAct->GetRefPoint(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->IsSetting() ) );
1423 }
1424 break;
1425
1426 case( META_FONT_ACTION ):
1427 {
1428 MetaFontAction* pAct = (MetaFontAction*) pAction;
1429 Font aFont( pAct->GetFont() );
1430
1431 aFont.SetOrientation( aFont.GetOrientation() + (sal_uInt16) nAngle10 );
1432 aMtf.AddAction( new MetaFontAction( aFont ) );
1433 }
1434 break;
1435
1436 case( META_BMP_ACTION ):
1437 case( META_BMPEX_ACTION ):
1438 case( META_MASK_ACTION ):
1439 case( META_MASKSCALE_ACTION ):
1440 case( META_MASKSCALEPART_ACTION ):
1441 case( META_WALLPAPER_ACTION ):
1442 case( META_TEXTRECT_ACTION ):
1443 case( META_MOVECLIPREGION_ACTION ):
1444 {
1445 DBG_ERROR( "GDIMetaFile::Rotate(): unsupported action" );
1446 }
1447 break;
1448
1449 default:
1450 {
1451 pAction->Execute( &aMapVDev );
1452 pAction->Duplicate();
1453 aMtf.AddAction( pAction );
1454
1455 // update rotation point and offset, if necessary
1456 if( ( META_MAPMODE_ACTION == nActionType ) ||
1457 ( META_PUSH_ACTION == nActionType ) ||
1458 ( META_POP_ACTION == nActionType ) )
1459 {
1460 aRotAnchor = aMapVDev.LogicToLogic( aOrigin, aPrefMapMode, aMapVDev.GetMapMode() );
1461 aRotOffset = aMapVDev.LogicToLogic( aOffset, aPrefMapMode, aMapVDev.GetMapMode() );
1462 }
1463 }
1464 break;
1465 }
1466 }
1467
1468 aMtf.aPrefMapMode = aPrefMapMode;
1469 aMtf.aPrefSize = aNewBound.GetSize();
1470
1471 *this = aMtf;
1472 }
1473 }
1474
1475 // ------------------------------------------------------------------------
1476
ImplActionBounds(Rectangle & o_rOutBounds,const Rectangle & i_rInBounds,const std::vector<Rectangle> & i_rClipStack,Rectangle * o_pHairline)1477 static void ImplActionBounds( Rectangle& o_rOutBounds,
1478 const Rectangle& i_rInBounds,
1479 const std::vector<Rectangle>& i_rClipStack,
1480 Rectangle* o_pHairline )
1481 {
1482 Rectangle aBounds( i_rInBounds );
1483 if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! i_rClipStack.back().IsEmpty() )
1484 aBounds.Intersection( i_rClipStack.back() );
1485 if( ! aBounds.IsEmpty() )
1486 {
1487 if( ! o_rOutBounds.IsEmpty() )
1488 o_rOutBounds.Union( aBounds );
1489 else
1490 o_rOutBounds = aBounds;
1491
1492 if(o_pHairline)
1493 {
1494 if( ! o_pHairline->IsEmpty() )
1495 o_pHairline->Union( aBounds );
1496 else
1497 *o_pHairline = aBounds;
1498 }
1499 }
1500 }
1501
GetBoundRect(OutputDevice & i_rReference,Rectangle * pHairline) const1502 Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference, Rectangle* pHairline ) const
1503 {
1504 GDIMetaFile aMtf;
1505 VirtualDevice aMapVDev( i_rReference );
1506
1507 aMapVDev.EnableOutput( sal_False );
1508 aMapVDev.SetMapMode( GetPrefMapMode() );
1509
1510 std::vector<Rectangle> aClipStack( 1, Rectangle() );
1511 std::vector<sal_uInt16> aPushFlagStack;
1512
1513 Rectangle aBound;
1514
1515 if(pHairline)
1516 {
1517 *pHairline = Rectangle();
1518 }
1519
1520 const sal_uLong nActionCount(GetActionCount());
1521
1522 for(sal_uLong a(0); a < nActionCount; a++)
1523 {
1524 MetaAction* pAction = GetAction(a);
1525 const sal_uInt16 nActionType = pAction->GetType();
1526 Rectangle* pUseHairline = (pHairline && aMapVDev.IsLineColor()) ? pHairline : 0;
1527
1528 switch( nActionType )
1529 {
1530 case( META_PIXEL_ACTION ):
1531 {
1532 MetaPixelAction* pAct = (MetaPixelAction*) pAction;
1533 ImplActionBounds( aBound,
1534 Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ),
1535 aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
1536 aClipStack, pUseHairline );
1537 }
1538 break;
1539
1540 case( META_POINT_ACTION ):
1541 {
1542 MetaPointAction* pAct = (MetaPointAction*) pAction;
1543 ImplActionBounds( aBound,
1544 Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ),
1545 aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
1546 aClipStack, pUseHairline );
1547 }
1548 break;
1549
1550 case( META_LINE_ACTION ):
1551 {
1552 MetaLineAction* pAct = (MetaLineAction*) pAction;
1553 Point aP1( pAct->GetStartPoint() ), aP2( pAct->GetEndPoint() );
1554 Rectangle aRect( aP1, aP2 );
1555 aRect.Justify();
1556
1557 if(pUseHairline)
1558 {
1559 const LineInfo& rLineInfo = pAct->GetLineInfo();
1560
1561 if(0 != rLineInfo.GetWidth())
1562 {
1563 pUseHairline = 0;
1564 }
1565 }
1566
1567 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1568 }
1569 break;
1570
1571 case( META_RECT_ACTION ):
1572 {
1573 MetaRectAction* pAct = (MetaRectAction*) pAction;
1574 ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1575 }
1576 break;
1577
1578 case( META_ROUNDRECT_ACTION ):
1579 {
1580 MetaRoundRectAction* pAct = (MetaRoundRectAction*) pAction;
1581 ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1582 }
1583 break;
1584
1585 case( META_ELLIPSE_ACTION ):
1586 {
1587 MetaEllipseAction* pAct = (MetaEllipseAction*) pAction;
1588 ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1589 }
1590 break;
1591
1592 case( META_ARC_ACTION ):
1593 {
1594 MetaArcAction* pAct = (MetaArcAction*) pAction;
1595 // FIXME: this is imprecise
1596 // e.g. for small arcs the whole rectangle is WAY too large
1597 ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1598 }
1599 break;
1600
1601 case( META_PIE_ACTION ):
1602 {
1603 MetaPieAction* pAct = (MetaPieAction*) pAction;
1604 // FIXME: this is imprecise
1605 // e.g. for small arcs the whole rectangle is WAY too large
1606 ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1607 }
1608 break;
1609
1610 case( META_CHORD_ACTION ):
1611 {
1612 MetaChordAction* pAct = (MetaChordAction*) pAction;
1613 // FIXME: this is imprecise
1614 // e.g. for small arcs the whole rectangle is WAY too large
1615 ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1616 }
1617 break;
1618
1619 case( META_POLYLINE_ACTION ):
1620 {
1621 MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction;
1622 Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
1623
1624 if(pUseHairline)
1625 {
1626 const LineInfo& rLineInfo = pAct->GetLineInfo();
1627
1628 if(0 != rLineInfo.GetWidth())
1629 {
1630 pUseHairline = 0;
1631 }
1632 }
1633
1634 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1635 }
1636 break;
1637
1638 case( META_POLYGON_ACTION ):
1639 {
1640 MetaPolygonAction* pAct = (MetaPolygonAction*) pAction;
1641 Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
1642 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1643 }
1644 break;
1645
1646 case( META_POLYPOLYGON_ACTION ):
1647 {
1648 MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction;
1649 Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1650 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1651 }
1652 break;
1653
1654 case( META_TEXT_ACTION ):
1655 {
1656 MetaTextAction* pAct = (MetaTextAction*) pAction;
1657 Rectangle aRect;
1658 // hdu said base = index
1659 aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() );
1660 Point aPt( pAct->GetPoint() );
1661 aRect.Move( aPt.X(), aPt.Y() );
1662 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1663 }
1664 break;
1665
1666 case( META_TEXTARRAY_ACTION ):
1667 {
1668 MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction;
1669 Rectangle aRect;
1670 // hdu said base = index
1671 aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
1672 0, pAct->GetDXArray() );
1673 Point aPt( pAct->GetPoint() );
1674 aRect.Move( aPt.X(), aPt.Y() );
1675 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1676 }
1677 break;
1678
1679 case( META_STRETCHTEXT_ACTION ):
1680 {
1681 MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction;
1682 Rectangle aRect;
1683 // hdu said base = index
1684 aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
1685 pAct->GetWidth(), NULL );
1686 Point aPt( pAct->GetPoint() );
1687 aRect.Move( aPt.X(), aPt.Y() );
1688 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1689 }
1690 break;
1691
1692 case( META_TEXTLINE_ACTION ):
1693 {
1694 MetaTextLineAction* pAct = (MetaTextLineAction*) pAction;
1695 // measure a test string to get ascend and descent right
1696 static const sal_Unicode pStr[] = { 0xc4, 0x67, 0 };
1697 String aStr( pStr );
1698
1699 Rectangle aRect;
1700 aMapVDev.GetTextBoundRect( aRect, aStr, 0, 0, aStr.Len(), 0, NULL );
1701 Point aPt( pAct->GetStartPoint() );
1702 aRect.Move( aPt.X(), aPt.Y() );
1703 aRect.Right() = aRect.Left() + pAct->GetWidth();
1704 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1705 }
1706 break;
1707
1708 case( META_BMPSCALE_ACTION ):
1709 {
1710 MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
1711 Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1712 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1713 }
1714 break;
1715
1716 case( META_BMPSCALEPART_ACTION ):
1717 {
1718 MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
1719 Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1720 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1721 }
1722 break;
1723
1724 case( META_BMPEXSCALE_ACTION ):
1725 {
1726 MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
1727 Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1728 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1729 }
1730 break;
1731
1732 case( META_BMPEXSCALEPART_ACTION ):
1733 {
1734 MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
1735 Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1736 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1737 }
1738 break;
1739
1740 case( META_GRADIENT_ACTION ):
1741 {
1742 MetaGradientAction* pAct = (MetaGradientAction*) pAction;
1743 Rectangle aRect( pAct->GetRect() );
1744 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1745 }
1746 break;
1747
1748 case( META_GRADIENTEX_ACTION ):
1749 {
1750 MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
1751 Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1752 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1753 }
1754 break;
1755
1756 case( META_COMMENT_ACTION ):
1757 {
1758 // nothing to do
1759 };
1760 break;
1761
1762 case( META_HATCH_ACTION ):
1763 {
1764 MetaHatchAction* pAct = (MetaHatchAction*) pAction;
1765 Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1766 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1767 }
1768 break;
1769
1770 case( META_TRANSPARENT_ACTION ):
1771 {
1772 MetaTransparentAction* pAct = (MetaTransparentAction*) pAction;
1773 Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1774 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1775 }
1776 break;
1777
1778 case( META_FLOATTRANSPARENT_ACTION ):
1779 {
1780 MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
1781 // MetaFloatTransparentAction is defined limiting it's content Metafile
1782 // to it's geometry definition(Point, Size), so use these directly
1783 const Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1784 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1785 }
1786 break;
1787
1788 case( META_EPS_ACTION ):
1789 {
1790 MetaEPSAction* pAct = (MetaEPSAction*) pAction;
1791 Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1792 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1793 }
1794 break;
1795
1796 case( META_CLIPREGION_ACTION ):
1797 {
1798 MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction;
1799 if( pAct->IsClipping() )
1800 aClipStack.back() = aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() );
1801 else
1802 aClipStack.back() = Rectangle();
1803 }
1804 break;
1805
1806 case( META_ISECTRECTCLIPREGION_ACTION ):
1807 {
1808 MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction;
1809 Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) );
1810 if( aClipStack.back().IsEmpty() )
1811 aClipStack.back() = aRect;
1812 else
1813 aClipStack.back().Intersection( aRect );
1814 }
1815 break;
1816
1817 case( META_ISECTREGIONCLIPREGION_ACTION ):
1818 {
1819 MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction;
1820 Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) );
1821 if( aClipStack.back().IsEmpty() )
1822 aClipStack.back() = aRect;
1823 else
1824 aClipStack.back().Intersection( aRect );
1825 }
1826 break;
1827
1828 case( META_BMP_ACTION ):
1829 {
1830 MetaBmpAction* pAct = (MetaBmpAction*) pAction;
1831 Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
1832 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1833 }
1834 break;
1835
1836 case( META_BMPEX_ACTION ):
1837 {
1838 MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
1839 Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmapEx().GetSizePixel() ) );
1840 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1841 }
1842 break;
1843
1844 case( META_MASK_ACTION ):
1845 {
1846 MetaMaskAction* pAct = (MetaMaskAction*) pAction;
1847 Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
1848 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1849 }
1850 break;
1851
1852 case( META_MASKSCALE_ACTION ):
1853 {
1854 MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
1855 Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1856 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1857 }
1858 break;
1859
1860 case( META_MASKSCALEPART_ACTION ):
1861 {
1862 MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
1863 Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1864 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1865 }
1866 break;
1867
1868 case( META_WALLPAPER_ACTION ):
1869 {
1870 MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction;
1871 Rectangle aRect( pAct->GetRect() );
1872 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1873 }
1874 break;
1875
1876 case( META_TEXTRECT_ACTION ):
1877 {
1878 MetaTextRectAction* pAct = (MetaTextRectAction*) pAction;
1879 Rectangle aRect( pAct->GetRect() );
1880 ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1881 }
1882 break;
1883
1884 case( META_MOVECLIPREGION_ACTION ):
1885 {
1886 MetaMoveClipRegionAction* pAct = (MetaMoveClipRegionAction*) pAction;
1887 if( ! aClipStack.back().IsEmpty() )
1888 {
1889 Size aDelta( pAct->GetHorzMove(), pAct->GetVertMove() );
1890 aDelta = aMapVDev.LogicToLogic( aDelta, aMapVDev.GetMapMode(), GetPrefMapMode() );
1891 aClipStack.back().Move( aDelta.Width(), aDelta.Width() );
1892 }
1893 }
1894 break;
1895
1896 default:
1897 {
1898 pAction->Execute( &aMapVDev );
1899
1900 if( nActionType == META_PUSH_ACTION )
1901 {
1902 MetaPushAction* pAct = (MetaPushAction*) pAction;
1903 aPushFlagStack.push_back( pAct->GetFlags() );
1904 if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 )
1905 {
1906 Rectangle aRect( aClipStack.back() );
1907 aClipStack.push_back( aRect );
1908 }
1909 }
1910 else if( nActionType == META_POP_ACTION )
1911 {
1912 // sanity check
1913 if( ! aPushFlagStack.empty() )
1914 {
1915 if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 )
1916 {
1917 if( aClipStack.size() > 1 )
1918 aClipStack.pop_back();
1919 }
1920 aPushFlagStack.pop_back();
1921 }
1922 }
1923 }
1924 break;
1925 }
1926 }
1927 return aBound;
1928 }
1929
1930 // ------------------------------------------------------------------------
1931
ImplColAdjustFnc(const Color & rColor,const void * pColParam)1932 Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam )
1933 {
1934 return Color( rColor.GetTransparency(),
1935 ( (const ImplColAdjustParam*) pColParam )->pMapR[ rColor.GetRed() ],
1936 ( (const ImplColAdjustParam*) pColParam )->pMapG[ rColor.GetGreen() ],
1937 ( (const ImplColAdjustParam*) pColParam )->pMapB[ rColor.GetBlue() ] );
1938
1939 }
1940
1941 // ------------------------------------------------------------------------
1942
ImplBmpAdjustFnc(const BitmapEx & rBmpEx,const void * pBmpParam)1943 BitmapEx GDIMetaFile::ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1944 {
1945 const ImplBmpAdjustParam* p = (const ImplBmpAdjustParam*) pBmpParam;
1946 BitmapEx aRet( rBmpEx );
1947
1948 aRet.Adjust( p->nLuminancePercent, p->nContrastPercent,
1949 p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent,
1950 p->fGamma, p->bInvert );
1951
1952 return aRet;
1953 }
1954
1955 // ------------------------------------------------------------------------
1956
ImplColConvertFnc(const Color & rColor,const void * pColParam)1957 Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam )
1958 {
1959 sal_uInt8 cLum = rColor.GetLuminance();
1960
1961 if( MTF_CONVERSION_1BIT_THRESHOLD == ( (const ImplColConvertParam*) pColParam )->eConversion )
1962 cLum = ( cLum < 128 ) ? 0 : 255;
1963
1964 return Color( rColor.GetTransparency(), cLum, cLum, cLum );
1965 }
1966
1967 // ------------------------------------------------------------------------
1968
ImplBmpConvertFnc(const BitmapEx & rBmpEx,const void * pBmpParam)1969 BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1970 {
1971 BitmapEx aRet( rBmpEx );
1972
1973 aRet.Convert( ( (const ImplBmpConvertParam*) pBmpParam )->eConversion );
1974
1975 return aRet;
1976 }
1977
1978 // ------------------------------------------------------------------------
1979
ImplColMonoFnc(const Color &,const void * pColParam)1980 Color GDIMetaFile::ImplColMonoFnc( const Color&, const void* pColParam )
1981 {
1982 return( ( (const ImplColMonoParam*) pColParam )->aColor );
1983 }
1984
1985 // ------------------------------------------------------------------------
1986
ImplBmpMonoFnc(const BitmapEx & rBmpEx,const void * pBmpParam)1987 BitmapEx GDIMetaFile::ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1988 {
1989 BitmapPalette aPal( 3 );
1990
1991 aPal[ 0 ] = Color( COL_BLACK );
1992 aPal[ 1 ] = Color( COL_WHITE );
1993 aPal[ 2 ] = ( (const ImplBmpMonoParam*) pBmpParam )->aColor;
1994
1995 Bitmap aBmp( rBmpEx.GetSizePixel(), 4, &aPal );
1996 aBmp.Erase( ( (const ImplBmpMonoParam*) pBmpParam )->aColor );
1997
1998 if( rBmpEx.IsAlpha() )
1999 return BitmapEx( aBmp, rBmpEx.GetAlpha() );
2000 else if( rBmpEx.IsTransparent() )
2001 return BitmapEx( aBmp, rBmpEx.GetMask() );
2002 else
2003 return aBmp;
2004 }
2005
2006 // ------------------------------------------------------------------------
2007
ImplColReplaceFnc(const Color & rColor,const void * pColParam)2008 Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam )
2009 {
2010 const sal_uLong nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue();
2011
2012 for( sal_uLong i = 0; i < ( (const ImplColReplaceParam*) pColParam )->nCount; i++ )
2013 {
2014 if( ( ( (const ImplColReplaceParam*) pColParam )->pMinR[ i ] <= nR ) &&
2015 ( ( (const ImplColReplaceParam*) pColParam )->pMaxR[ i ] >= nR ) &&
2016 ( ( (const ImplColReplaceParam*) pColParam )->pMinG[ i ] <= nG ) &&
2017 ( ( (const ImplColReplaceParam*) pColParam )->pMaxG[ i ] >= nG ) &&
2018 ( ( (const ImplColReplaceParam*) pColParam )->pMinB[ i ] <= nB ) &&
2019 ( ( (const ImplColReplaceParam*) pColParam )->pMaxB[ i ] >= nB ) )
2020 {
2021 return( ( (const ImplColReplaceParam*) pColParam )->pDstCols[ i ] );
2022 }
2023 }
2024
2025 return rColor;
2026 }
2027
2028 // ------------------------------------------------------------------------
2029
ImplBmpReplaceFnc(const BitmapEx & rBmpEx,const void * pBmpParam)2030 BitmapEx GDIMetaFile::ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
2031 {
2032 const ImplBmpReplaceParam* p = (const ImplBmpReplaceParam*) pBmpParam;
2033 BitmapEx aRet( rBmpEx );
2034
2035 aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount, p->pTols );
2036
2037 return aRet;
2038 }
2039
2040 // ------------------------------------------------------------------------
2041
ImplExchangeColors(ColorExchangeFnc pFncCol,const void * pColParam,BmpExchangeFnc pFncBmp,const void * pBmpParam)2042 void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam,
2043 BmpExchangeFnc pFncBmp, const void* pBmpParam )
2044 {
2045 GDIMetaFile aMtf;
2046
2047 aMtf.aPrefSize = aPrefSize;
2048 aMtf.aPrefMapMode = aPrefMapMode;
2049
2050 for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
2051 {
2052 const sal_uInt16 nType = pAction->GetType();
2053
2054 switch( nType )
2055 {
2056 case( META_PIXEL_ACTION ):
2057 {
2058 MetaPixelAction* pAct = (MetaPixelAction*) pAction;
2059 aMtf.Insert( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND );
2060 }
2061 break;
2062
2063 case( META_LINECOLOR_ACTION ):
2064 {
2065 MetaLineColorAction* pAct = (MetaLineColorAction*) pAction;
2066
2067 if( !pAct->IsSetting() )
2068 pAct->Duplicate();
2069 else
2070 pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2071
2072 aMtf.Insert( pAct, LIST_APPEND );
2073 }
2074 break;
2075
2076 case( META_FILLCOLOR_ACTION ):
2077 {
2078 MetaFillColorAction* pAct = (MetaFillColorAction*) pAction;
2079
2080 if( !pAct->IsSetting() )
2081 pAct->Duplicate();
2082 else
2083 pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2084
2085 aMtf.Insert( pAct, LIST_APPEND );
2086 }
2087 break;
2088
2089 case( META_TEXTCOLOR_ACTION ):
2090 {
2091 MetaTextColorAction* pAct = (MetaTextColorAction*) pAction;
2092 aMtf.Insert( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND );
2093 }
2094 break;
2095
2096 case( META_TEXTFILLCOLOR_ACTION ):
2097 {
2098 MetaTextFillColorAction* pAct = (MetaTextFillColorAction*) pAction;
2099
2100 if( !pAct->IsSetting() )
2101 pAct->Duplicate();
2102 else
2103 pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2104
2105 aMtf.Insert( pAct, LIST_APPEND );
2106 }
2107 break;
2108
2109 case( META_TEXTLINECOLOR_ACTION ):
2110 {
2111 MetaTextLineColorAction* pAct = (MetaTextLineColorAction*) pAction;
2112
2113 if( !pAct->IsSetting() )
2114 pAct->Duplicate();
2115 else
2116 pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2117
2118 aMtf.Insert( pAct, LIST_APPEND );
2119 }
2120 break;
2121
2122 case( META_OVERLINECOLOR_ACTION ):
2123 {
2124 MetaOverlineColorAction* pAct = (MetaOverlineColorAction*) pAction;
2125
2126 if( !pAct->IsSetting() )
2127 pAct->Duplicate();
2128 else
2129 pAct = new MetaOverlineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2130
2131 aMtf.Insert( pAct, LIST_APPEND );
2132 }
2133 break;
2134
2135 case( META_FONT_ACTION ):
2136 {
2137 MetaFontAction* pAct = (MetaFontAction*) pAction;
2138 Font aFont( pAct->GetFont() );
2139
2140 aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) );
2141 aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) );
2142 aMtf.Insert( new MetaFontAction( aFont ), LIST_APPEND );
2143 }
2144 break;
2145
2146 case( META_WALLPAPER_ACTION ):
2147 {
2148 MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction;
2149 Wallpaper aWall( pAct->GetWallpaper() );
2150 const Rectangle& rRect = pAct->GetRect();
2151
2152 aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) );
2153
2154 if( aWall.IsBitmap() )
2155 aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) );
2156
2157 if( aWall.IsGradient() )
2158 {
2159 Gradient aGradient( aWall.GetGradient() );
2160
2161 aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2162 aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2163 aWall.SetGradient( aGradient );
2164 }
2165
2166 aMtf.Insert( new MetaWallpaperAction( rRect, aWall ), LIST_APPEND );
2167 }
2168 break;
2169
2170 case( META_BMP_ACTION ):
2171 case( META_BMPEX_ACTION ):
2172 case( META_MASK_ACTION ):
2173 {
2174 DBG_ERROR( "Don't use bitmap actions of this type in metafiles!" );
2175 }
2176 break;
2177
2178 case( META_BMPSCALE_ACTION ):
2179 {
2180 MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
2181 aMtf.Insert( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(),
2182 pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ),
2183 LIST_APPEND );
2184 }
2185 break;
2186
2187 case( META_BMPSCALEPART_ACTION ):
2188 {
2189 MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
2190 aMtf.Insert( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2191 pAct->GetSrcPoint(), pAct->GetSrcSize(),
2192 pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ),
2193 LIST_APPEND );
2194 }
2195 break;
2196
2197 case( META_BMPEXSCALE_ACTION ):
2198 {
2199 MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
2200 aMtf.Insert( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(),
2201 pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ),
2202 LIST_APPEND );
2203 }
2204 break;
2205
2206 case( META_BMPEXSCALEPART_ACTION ):
2207 {
2208 MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
2209 aMtf.Insert( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2210 pAct->GetSrcPoint(), pAct->GetSrcSize(),
2211 pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ),
2212 LIST_APPEND );
2213 }
2214 break;
2215
2216 case( META_MASKSCALE_ACTION ):
2217 {
2218 MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
2219 aMtf.Insert( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(),
2220 pAct->GetBitmap(),
2221 pFncCol( pAct->GetColor(), pColParam ) ),
2222 LIST_APPEND );
2223 }
2224 break;
2225
2226 case( META_MASKSCALEPART_ACTION ):
2227 {
2228 MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
2229 aMtf.Insert( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2230 pAct->GetSrcPoint(), pAct->GetSrcSize(),
2231 pAct->GetBitmap(),
2232 pFncCol( pAct->GetColor(), pColParam ) ),
2233 LIST_APPEND );
2234 }
2235 break;
2236
2237 case( META_GRADIENT_ACTION ):
2238 {
2239 MetaGradientAction* pAct = (MetaGradientAction*) pAction;
2240 Gradient aGradient( pAct->GetGradient() );
2241
2242 aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2243 aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2244 aMtf.Insert( new MetaGradientAction( pAct->GetRect(), aGradient ), LIST_APPEND );
2245 }
2246 break;
2247
2248 case( META_GRADIENTEX_ACTION ):
2249 {
2250 MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
2251 Gradient aGradient( pAct->GetGradient() );
2252
2253 aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2254 aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2255 aMtf.Insert( new MetaGradientExAction( pAct->GetPolyPolygon(), aGradient ), LIST_APPEND );
2256 }
2257 break;
2258
2259 case( META_HATCH_ACTION ):
2260 {
2261 MetaHatchAction* pAct = (MetaHatchAction*) pAction;
2262 Hatch aHatch( pAct->GetHatch() );
2263
2264 aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) );
2265 aMtf.Insert( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ), LIST_APPEND );
2266 }
2267 break;
2268
2269 case( META_FLOATTRANSPARENT_ACTION ):
2270 {
2271 MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
2272 GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
2273
2274 aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
2275 aMtf.Insert( new MetaFloatTransparentAction( aTransMtf,
2276 pAct->GetPoint(), pAct->GetSize(),
2277 pAct->GetGradient() ),
2278 LIST_APPEND );
2279 }
2280 break;
2281
2282 case( META_EPS_ACTION ):
2283 {
2284 MetaEPSAction* pAct = (MetaEPSAction*) pAction;
2285 GDIMetaFile aSubst( pAct->GetSubstitute() );
2286
2287 aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
2288 aMtf.Insert( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(),
2289 pAct->GetLink(), aSubst ),
2290 LIST_APPEND );
2291 }
2292 break;
2293
2294 default:
2295 {
2296 pAction->Duplicate();
2297 aMtf.Insert( pAction, LIST_APPEND );
2298 }
2299 break;
2300 }
2301 }
2302
2303 *this = aMtf;
2304 }
2305
2306 // ------------------------------------------------------------------------
2307
Adjust(short nLuminancePercent,short nContrastPercent,short nChannelRPercent,short nChannelGPercent,short nChannelBPercent,double fGamma,sal_Bool bInvert)2308 void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent,
2309 short nChannelRPercent, short nChannelGPercent,
2310 short nChannelBPercent, double fGamma, sal_Bool bInvert )
2311 {
2312 // nothing to do? => return quickly
2313 if( nLuminancePercent || nContrastPercent ||
2314 nChannelRPercent || nChannelGPercent || nChannelBPercent ||
2315 ( fGamma != 1.0 ) || bInvert )
2316 {
2317 double fM, fROff, fGOff, fBOff, fOff;
2318 ImplColAdjustParam aColParam;
2319 ImplBmpAdjustParam aBmpParam;
2320
2321 aColParam.pMapR = new sal_uInt8[ 256 ];
2322 aColParam.pMapG = new sal_uInt8[ 256 ];
2323 aColParam.pMapB = new sal_uInt8[ 256 ];
2324
2325 // calculate slope
2326 if( nContrastPercent >= 0 )
2327 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2328 else
2329 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2330
2331 // total offset = luminance offset + contrast offset
2332 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2333
2334 // channel offset = channel offset + total offset
2335 fROff = nChannelRPercent * 2.55 + fOff;
2336 fGOff = nChannelGPercent * 2.55 + fOff;
2337 fBOff = nChannelBPercent * 2.55 + fOff;
2338
2339 // calculate gamma value
2340 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2341 const sal_Bool bGamma = ( fGamma != 1.0 );
2342
2343 // create mapping table
2344 for( long nX = 0L; nX < 256L; nX++ )
2345 {
2346 aColParam.pMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2347 aColParam.pMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2348 aColParam.pMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2349
2350 if( bGamma )
2351 {
2352 aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma );
2353 aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma );
2354 aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma );
2355 }
2356
2357 if( bInvert )
2358 {
2359 aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ];
2360 aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ];
2361 aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ];
2362 }
2363 }
2364
2365 aBmpParam.nLuminancePercent = nLuminancePercent;
2366 aBmpParam.nContrastPercent = nContrastPercent;
2367 aBmpParam.nChannelRPercent = nChannelRPercent;
2368 aBmpParam.nChannelGPercent = nChannelGPercent;
2369 aBmpParam.nChannelBPercent = nChannelBPercent;
2370 aBmpParam.fGamma = fGamma;
2371 aBmpParam.bInvert = bInvert;
2372
2373 // do color adjustment
2374 ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam );
2375
2376 delete[] aColParam.pMapR;
2377 delete[] aColParam.pMapG;
2378 delete[] aColParam.pMapB;
2379 }
2380 }
2381
2382 // ------------------------------------------------------------------------
2383
Convert(MtfConversion eConversion)2384 void GDIMetaFile::Convert( MtfConversion eConversion )
2385 {
2386 // nothing to do? => return quickly
2387 if( eConversion != MTF_CONVERSION_NONE )
2388 {
2389 ImplColConvertParam aColParam;
2390 ImplBmpConvertParam aBmpParam;
2391
2392 aColParam.eConversion = eConversion;
2393 aBmpParam.eConversion = ( MTF_CONVERSION_1BIT_THRESHOLD == eConversion ) ? BMP_CONVERSION_1BIT_THRESHOLD : BMP_CONVERSION_8BIT_GREYS;
2394
2395 ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam );
2396 }
2397 }
2398
2399 // ------------------------------------------------------------------------
2400
ReplaceColors(const Color & rSearchColor,const Color & rReplaceColor,sal_uLong nTol)2401 void GDIMetaFile::ReplaceColors( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
2402 {
2403 ReplaceColors( &rSearchColor, &rReplaceColor, 1, &nTol );
2404 }
2405
2406 // ------------------------------------------------------------------------
2407
ReplaceColors(const Color * pSearchColors,const Color * pReplaceColors,sal_uLong nColorCount,sal_uLong * pTols)2408 void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, sal_uLong* pTols )
2409 {
2410 ImplColReplaceParam aColParam;
2411 ImplBmpReplaceParam aBmpParam;
2412
2413 aColParam.pMinR = new sal_uLong[ nColorCount ];
2414 aColParam.pMaxR = new sal_uLong[ nColorCount ];
2415 aColParam.pMinG = new sal_uLong[ nColorCount ];
2416 aColParam.pMaxG = new sal_uLong[ nColorCount ];
2417 aColParam.pMinB = new sal_uLong[ nColorCount ];
2418 aColParam.pMaxB = new sal_uLong[ nColorCount ];
2419
2420 for( sal_uLong i = 0; i < nColorCount; i++ )
2421 {
2422 const long nTol = pTols ? ( pTols[ i ] * 255 ) / 100 : 0;
2423 long nVal;
2424
2425 nVal = pSearchColors[ i ].GetRed();
2426 aColParam.pMinR[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2427 aColParam.pMaxR[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2428
2429 nVal = pSearchColors[ i ].GetGreen();
2430 aColParam.pMinG[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2431 aColParam.pMaxG[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2432
2433 nVal = pSearchColors[ i ].GetBlue();
2434 aColParam.pMinB[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2435 aColParam.pMaxB[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2436 }
2437
2438 aColParam.pDstCols = pReplaceColors;
2439 aColParam.nCount = nColorCount;
2440
2441 aBmpParam.pSrcCols = pSearchColors;
2442 aBmpParam.pDstCols = pReplaceColors;
2443 aBmpParam.nCount = nColorCount;
2444 aBmpParam.pTols = pTols;
2445
2446 ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam );
2447
2448 delete[] aColParam.pMinR;
2449 delete[] aColParam.pMaxR;
2450 delete[] aColParam.pMinG;
2451 delete[] aColParam.pMaxG;
2452 delete[] aColParam.pMinB;
2453 delete[] aColParam.pMaxB;
2454 };
2455
2456 // ------------------------------------------------------------------------
2457
GetMonochromeMtf(const Color & rColor) const2458 GDIMetaFile GDIMetaFile::GetMonochromeMtf( const Color& rColor ) const
2459 {
2460 GDIMetaFile aRet( *this );
2461
2462 ImplColMonoParam aColParam;
2463 ImplBmpMonoParam aBmpParam;
2464
2465 aColParam.aColor = rColor;
2466 aBmpParam.aColor = rColor;
2467
2468 aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam );
2469
2470 return aRet;
2471 }
2472
2473 // ------------------------------------------------------------------------
2474
GetChecksum() const2475 sal_uLong GDIMetaFile::GetChecksum() const
2476 {
2477 GDIMetaFile aMtf;
2478 SvMemoryStream aMemStm( 65535, 65535 );
2479 ImplMetaWriteData aWriteData;
2480 SVBT16 aBT16;
2481 SVBT32 aBT32;
2482 sal_uLong nCrc = 0;
2483
2484 aWriteData.meActualCharSet = aMemStm.GetStreamCharSet();
2485
2486 for( sal_uLong i = 0, nObjCount = GetActionCount(); i < nObjCount; i++ )
2487 {
2488 MetaAction* pAction = GetAction( i );
2489
2490 switch( pAction->GetType() )
2491 {
2492 case( META_BMP_ACTION ):
2493 {
2494 MetaBmpAction* pAct = (MetaBmpAction*) pAction;
2495
2496 ShortToSVBT16( pAct->GetType(), aBT16 );
2497 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2498
2499 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2500 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2501
2502 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2503 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2504
2505 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2506 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2507 }
2508 break;
2509
2510 case( META_BMPSCALE_ACTION ):
2511 {
2512 MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
2513
2514 ShortToSVBT16( pAct->GetType(), aBT16 );
2515 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2516
2517 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2518 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2519
2520 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2521 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2522
2523 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2524 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2525
2526 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2527 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2528
2529 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2530 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2531 }
2532 break;
2533
2534 case( META_BMPSCALEPART_ACTION ):
2535 {
2536 MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
2537
2538 ShortToSVBT16( pAct->GetType(), aBT16 );
2539 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2540
2541 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2542 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2543
2544 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2545 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2546
2547 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2548 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2549
2550 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2551 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2552
2553 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2554 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2555
2556 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2557 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2558
2559 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2560 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2561
2562 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2563 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2564
2565 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2566 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2567 }
2568 break;
2569
2570 case( META_BMPEX_ACTION ):
2571 {
2572 MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
2573
2574 ShortToSVBT16( pAct->GetType(), aBT16 );
2575 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2576
2577 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2578 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2579
2580 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2581 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2582
2583 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2584 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2585 }
2586 break;
2587
2588 case( META_BMPEXSCALE_ACTION ):
2589 {
2590 MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
2591
2592 ShortToSVBT16( pAct->GetType(), aBT16 );
2593 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2594
2595 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2596 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2597
2598 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2599 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2600
2601 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2602 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2603
2604 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2605 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2606
2607 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2608 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2609 }
2610 break;
2611
2612 case( META_BMPEXSCALEPART_ACTION ):
2613 {
2614 MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
2615
2616 ShortToSVBT16( pAct->GetType(), aBT16 );
2617 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2618
2619 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2620 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2621
2622 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2623 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2624
2625 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2626 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2627
2628 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2629 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2630
2631 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2632 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2633
2634 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2635 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2636
2637 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2638 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2639
2640 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2641 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2642
2643 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2644 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2645 }
2646 break;
2647
2648 case( META_MASK_ACTION ):
2649 {
2650 MetaMaskAction* pAct = (MetaMaskAction*) pAction;
2651
2652 ShortToSVBT16( pAct->GetType(), aBT16 );
2653 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2654
2655 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2656 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2657
2658 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2659 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2660
2661 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2662 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2663
2664 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2665 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2666 }
2667 break;
2668
2669 case( META_MASKSCALE_ACTION ):
2670 {
2671 MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
2672
2673 ShortToSVBT16( pAct->GetType(), aBT16 );
2674 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2675
2676 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2677 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2678
2679 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2680 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2681
2682 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2683 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2684
2685 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2686 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2687
2688 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2689 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2690
2691 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2692 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2693 }
2694 break;
2695
2696 case( META_MASKSCALEPART_ACTION ):
2697 {
2698 MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
2699
2700 ShortToSVBT16( pAct->GetType(), aBT16 );
2701 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2702
2703 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2704 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2705
2706 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2707 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2708
2709 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2710 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2711
2712 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2713 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2714
2715 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2716 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2717
2718 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2719 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2720
2721 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2722 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2723
2724 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2725 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2726
2727 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2728 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2729
2730 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2731 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2732 }
2733 break;
2734
2735 case META_EPS_ACTION :
2736 {
2737 MetaEPSAction* pAct = (MetaEPSAction*) pAction;
2738 nCrc = rtl_crc32( nCrc, pAct->GetLink().GetData(), pAct->GetLink().GetDataSize() );
2739 }
2740 break;
2741
2742 case META_CLIPREGION_ACTION :
2743 {
2744 MetaClipRegionAction* pAct = dynamic_cast< MetaClipRegionAction* >(pAction);
2745 const Region& rRegion = pAct->GetRegion();
2746
2747 if(rRegion.HasPolyPolygonOrB2DPolyPolygon())
2748 {
2749 // It has shown that this is a possible bottleneck for checksum calculation.
2750 // In worst case a very expensive RegionHandle representation gets created.
2751 // In this case it's cheaper to use the PolyPolygon
2752 const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetAsB2DPolyPolygon());
2753 const sal_uInt32 nPolyCount(aPolyPolygon.count());
2754 SVBT64 aSVBT64;
2755
2756 for(sal_uInt32 a(0); a < nPolyCount; a++)
2757 {
2758 const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(a));
2759 const sal_uInt32 nPointCount(aPolygon.count());
2760 const bool bControl(aPolygon.areControlPointsUsed());
2761
2762 for(sal_uInt32 b(0); b < nPointCount; b++)
2763 {
2764 const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(b));
2765
2766 DoubleToSVBT64(aPoint.getX(), aSVBT64);
2767 nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2768 DoubleToSVBT64(aPoint.getY(), aSVBT64);
2769 nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2770
2771 if(bControl)
2772 {
2773 if(aPolygon.isPrevControlPointUsed(b))
2774 {
2775 const basegfx::B2DPoint aCtrl(aPolygon.getPrevControlPoint(b));
2776
2777 DoubleToSVBT64(aCtrl.getX(), aSVBT64);
2778 nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2779 DoubleToSVBT64(aCtrl.getY(), aSVBT64);
2780 nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2781 }
2782
2783 if(aPolygon.isNextControlPointUsed(b))
2784 {
2785 const basegfx::B2DPoint aCtrl(aPolygon.getNextControlPoint(b));
2786
2787 DoubleToSVBT64(aCtrl.getX(), aSVBT64);
2788 nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2789 DoubleToSVBT64(aCtrl.getY(), aSVBT64);
2790 nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2791 }
2792 }
2793 }
2794 }
2795
2796 SVBT8 aSVBT8;
2797 ByteToSVBT8((sal_uInt8)pAct->IsClipping(), aSVBT8);
2798 nCrc = rtl_crc32(nCrc, aSVBT8, 1);
2799 }
2800 else
2801 {
2802 pAction->Write( aMemStm, &aWriteData );
2803 nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() );
2804 aMemStm.Seek( 0 );
2805 }
2806 }
2807 break;
2808
2809 default:
2810 {
2811 pAction->Write( aMemStm, &aWriteData );
2812 nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() );
2813 aMemStm.Seek( 0 );
2814 }
2815 break;
2816 }
2817 }
2818
2819 return nCrc;
2820 }
2821
2822 // ------------------------------------------------------------------------
2823
GetSizeBytes() const2824 sal_uLong GDIMetaFile::GetSizeBytes() const
2825 {
2826 sal_uLong nSizeBytes = 0;
2827
2828 for( sal_uLong i = 0, nObjCount = GetActionCount(); i < nObjCount; ++i )
2829 {
2830 MetaAction* pAction = GetAction( i );
2831
2832 // default action size is set to 32 (=> not the exact value)
2833 nSizeBytes += 32;
2834
2835 // add sizes for large action content
2836 switch( pAction->GetType() )
2837 {
2838 case( META_BMP_ACTION ): nSizeBytes += ( (MetaBmpAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2839 case( META_BMPSCALE_ACTION ): nSizeBytes += ( (MetaBmpScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2840 case( META_BMPSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2841
2842 case( META_BMPEX_ACTION ): nSizeBytes += ( (MetaBmpExAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2843 case( META_BMPEXSCALE_ACTION ): nSizeBytes += ( (MetaBmpExScaleAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2844 case( META_BMPEXSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpExScalePartAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2845
2846 case( META_MASK_ACTION ): nSizeBytes += ( (MetaMaskAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2847 case( META_MASKSCALE_ACTION ): nSizeBytes += ( (MetaMaskScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2848 case( META_MASKSCALEPART_ACTION ): nSizeBytes += ( (MetaMaskScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2849
2850 case( META_POLYLINE_ACTION ): nSizeBytes += ( ( (MetaPolyLineAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break;
2851 case( META_POLYGON_ACTION ): nSizeBytes += ( ( (MetaPolygonAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break;
2852 case( META_POLYPOLYGON_ACTION ):
2853 {
2854 const PolyPolygon& rPolyPoly = ( (MetaPolyPolygonAction*) pAction )->GetPolyPolygon();
2855
2856 for( sal_uInt16 n = 0; n < rPolyPoly.Count(); ++n )
2857 nSizeBytes += ( rPolyPoly[ n ].GetSize() * sizeof( Point ) );
2858 }
2859 break;
2860
2861 case( META_TEXT_ACTION ): nSizeBytes += ( ( (MetaTextAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2862 case( META_STRETCHTEXT_ACTION ): nSizeBytes += ( ( (MetaStretchTextAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2863 case( META_TEXTRECT_ACTION ): nSizeBytes += ( ( (MetaTextRectAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2864 case( META_TEXTARRAY_ACTION ):
2865 {
2866 MetaTextArrayAction* pTextArrayAction = (MetaTextArrayAction*) pAction;
2867
2868 nSizeBytes += ( pTextArrayAction->GetText().Len() * sizeof( sal_Unicode ) );
2869
2870 if( pTextArrayAction->GetDXArray() )
2871 nSizeBytes += ( pTextArrayAction->GetLen() << 2 );
2872 }
2873 break;
2874 }
2875 }
2876
2877 return( nSizeBytes );
2878 }
2879
2880 // ------------------------------------------------------------------------
2881
operator >>(SvStream & rIStm,GDIMetaFile & rGDIMetaFile)2882 SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile )
2883 {
2884 if( !rIStm.GetError() )
2885 {
2886 char aId[ 7 ];
2887 sal_uLong nStmPos = rIStm.Tell();
2888 sal_uInt16 nOldFormat = rIStm.GetNumberFormatInt();
2889
2890 rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
2891
2892 aId[ 0 ] = 0;
2893 aId[ 6 ] = 0;
2894 rIStm.Read( aId, 6 );
2895
2896 if ( !strcmp( aId, "VCLMTF" ) )
2897 {
2898 // new format
2899 VersionCompat* pCompat;
2900 MetaAction* pAction;
2901 sal_uInt32 nStmCompressMode = 0;
2902 sal_uInt32 nCount = 0;
2903
2904 pCompat = new VersionCompat( rIStm, STREAM_READ );
2905
2906 rIStm >> nStmCompressMode;
2907 rIStm >> rGDIMetaFile.aPrefMapMode;
2908 rIStm >> rGDIMetaFile.aPrefSize;
2909 rIStm >> nCount;
2910
2911 delete pCompat;
2912
2913 ImplMetaReadData aReadData;
2914 aReadData.meActualCharSet = rIStm.GetStreamCharSet();
2915
2916 for( sal_uInt32 nAction = 0UL; ( nAction < nCount ) && !rIStm.IsEof(); nAction++ )
2917 {
2918 pAction = MetaAction::ReadMetaAction( rIStm, &aReadData );
2919
2920 if( pAction )
2921 rGDIMetaFile.AddAction( pAction );
2922 }
2923 }
2924 else
2925 {
2926 // to avoid possible compiler optimizations => new/delete
2927 rIStm.Seek( nStmPos );
2928 delete( new SVMConverter( rIStm, rGDIMetaFile, CONVERT_FROM_SVM1 ) );
2929 }
2930
2931 // check for errors
2932 if( rIStm.GetError() )
2933 {
2934 rGDIMetaFile.Clear();
2935 rIStm.Seek( nStmPos );
2936 }
2937
2938 rIStm.SetNumberFormatInt( nOldFormat );
2939 }
2940
2941 return rIStm;
2942 }
2943
2944 // ------------------------------------------------------------------------
2945
operator <<(SvStream & rOStm,const GDIMetaFile & rGDIMetaFile)2946 SvStream& operator<<( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile )
2947 {
2948 if( !rOStm.GetError() )
2949 {
2950 static const char* pEnableSVM1 = getenv( "SAL_ENABLE_SVM1" );
2951 static const bool bNoSVM1 = (NULL == pEnableSVM1 ) || ( '0' == *pEnableSVM1 );
2952
2953 if( bNoSVM1 || rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 )
2954 {
2955 const_cast< GDIMetaFile& >( rGDIMetaFile ).Write( rOStm );
2956 }
2957 else
2958 {
2959 delete( new SVMConverter( rOStm, const_cast< GDIMetaFile& >( rGDIMetaFile ), CONVERT_TO_SVM1 ) );
2960 }
2961
2962 #ifdef DEBUG
2963 if( !bNoSVM1 && rOStm.GetVersion() < SOFFICE_FILEFORMAT_50 )
2964 {
2965 OSL_TRACE( \
2966 "GDIMetaFile would normally be written in old SVM1 format by this call. \
2967 The current implementation always writes in VCLMTF format. \
2968 Please set environment variable SAL_ENABLE_SVM1 to '1' to reenable old behavior" );
2969 }
2970 #endif // DEBUG
2971 }
2972
2973 return rOStm;
2974 }
2975
2976 // ------------------------------------------------------------------------
2977
Read(SvStream & rIStm)2978 SvStream& GDIMetaFile::Read( SvStream& rIStm )
2979 {
2980 Clear();
2981 rIStm >> *this;
2982
2983 return rIStm;
2984 }
2985
2986 // ------------------------------------------------------------------------
2987
Write(SvStream & rOStm)2988 SvStream& GDIMetaFile::Write( SvStream& rOStm )
2989 {
2990 VersionCompat* pCompat;
2991 const sal_uInt32 nStmCompressMode = rOStm.GetCompressMode();
2992 sal_uInt16 nOldFormat = rOStm.GetNumberFormatInt();
2993
2994 rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
2995 rOStm.Write( "VCLMTF", 6 );
2996
2997 pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 );
2998
2999 rOStm << nStmCompressMode;
3000 rOStm << aPrefMapMode;
3001 rOStm << aPrefSize;
3002 rOStm << (sal_uInt32) GetActionCount();
3003
3004 delete pCompat;
3005
3006 ImplMetaWriteData aWriteData;
3007 aWriteData.meActualCharSet = rOStm.GetStreamCharSet();
3008
3009 MetaAction* pAct = (MetaAction*)First();
3010 while ( pAct )
3011 {
3012 pAct->Write( rOStm, &aWriteData );
3013 pAct = (MetaAction*)Next();
3014 }
3015
3016 rOStm.SetNumberFormatInt( nOldFormat );
3017
3018 return rOStm;
3019 }
3020
3021 // ------------------------------------------------------------------------
3022
CreateThumbnail(sal_uInt32 nMaximumExtent,BitmapEx & rBmpEx,const BitmapEx * pOverlay,const Rectangle * pOverlayRect) const3023 sal_Bool GDIMetaFile::CreateThumbnail( sal_uInt32 nMaximumExtent,
3024 BitmapEx& rBmpEx,
3025 const BitmapEx* pOverlay,
3026 const Rectangle* pOverlayRect ) const
3027 {
3028 // the implementation is provided by KA
3029
3030 // initialization seems to be complicated but is used to avoid rounding errors
3031 VirtualDevice aVDev;
3032 const Point aNullPt;
3033 const Point aTLPix( aVDev.LogicToPixel( aNullPt, GetPrefMapMode() ) );
3034 const Point aBRPix( aVDev.LogicToPixel( Point( GetPrefSize().Width() - 1, GetPrefSize().Height() - 1 ), GetPrefMapMode() ) );
3035 Size aDrawSize( aVDev.LogicToPixel( GetPrefSize(), GetPrefMapMode() ) );
3036 Size aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
3037 Point aPosPix;
3038
3039 if ( !rBmpEx.IsEmpty() )
3040 rBmpEx.SetEmpty();
3041
3042 // determine size that has the same aspect ratio as image size and
3043 // fits into the rectangle determined by nMaximumExtent
3044 if ( aSizePix.Width() && aSizePix.Height()
3045 && ( sal::static_int_cast< unsigned long >(aSizePix.Width()) >
3046 nMaximumExtent ||
3047 sal::static_int_cast< unsigned long >(aSizePix.Height()) >
3048 nMaximumExtent ) )
3049 {
3050 const Size aOldSizePix( aSizePix );
3051 double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height();
3052
3053 if ( fWH <= 1.0 )
3054 {
3055 aSizePix.Width() = FRound( nMaximumExtent * fWH );
3056 aSizePix.Height() = nMaximumExtent;
3057 }
3058 else
3059 {
3060 aSizePix.Width() = nMaximumExtent;
3061 aSizePix.Height() = FRound( nMaximumExtent / fWH );
3062 }
3063
3064 aDrawSize.Width() = FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() );
3065 aDrawSize.Height() = FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() );
3066 }
3067
3068 Size aFullSize;
3069 Point aBackPosPix;
3070 Rectangle aOverlayRect;
3071
3072 // calculate addigtional positions and sizes if an overlay image is used
3073 if ( pOverlay )
3074 {
3075 aFullSize = Size( nMaximumExtent, nMaximumExtent );
3076 aOverlayRect = Rectangle( aNullPt, aFullSize );
3077
3078 aOverlayRect.Intersection( pOverlayRect ? *pOverlayRect : Rectangle( aNullPt, pOverlay->GetSizePixel() ) );
3079
3080 if ( !aOverlayRect.IsEmpty() )
3081 aBackPosPix = Point( ( nMaximumExtent - aSizePix.Width() ) >> 1, ( nMaximumExtent - aSizePix.Height() ) >> 1 );
3082 else
3083 pOverlay = NULL;
3084 }
3085 else
3086 {
3087 aFullSize = aSizePix;
3088 pOverlay = NULL;
3089 }
3090
3091 // draw image(s) into VDev and get resulting image
3092 if ( aVDev.SetOutputSizePixel( aFullSize ) )
3093 {
3094 // draw metafile into VDev
3095 const_cast<GDIMetaFile *>(this)->WindStart();
3096 const_cast<GDIMetaFile *>(this)->Play( &aVDev, aBackPosPix, aDrawSize );
3097
3098 // draw overlay if neccessary
3099 if ( pOverlay )
3100 aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), *pOverlay );
3101
3102 // get paint bitmap
3103 Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
3104
3105 // assure that we have a true color image
3106 if ( aBmp.GetBitCount() != 24 )
3107 aBmp.Convert( BMP_CONVERSION_24BIT );
3108
3109 // create resulting mask bitmap with metafile output set to black
3110 GDIMetaFile aMonchromeMtf( GetMonochromeMtf( COL_BLACK ) );
3111 aVDev.DrawWallpaper( Rectangle( aNullPt, aSizePix ), Wallpaper( Color( COL_WHITE ) ) );
3112 aMonchromeMtf.WindStart();
3113 aMonchromeMtf.Play( &aVDev, aBackPosPix, aDrawSize );
3114
3115 // watch for overlay mask
3116 if ( pOverlay )
3117 {
3118 Bitmap aOverlayMergeBmp( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ) );
3119
3120 // create ANDed resulting mask at overlay area
3121 if ( pOverlay->IsTransparent() )
3122 aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), pOverlay->GetMask() );
3123 else
3124 {
3125 aVDev.SetLineColor( COL_BLACK );
3126 aVDev.SetFillColor( COL_BLACK );
3127 aVDev.DrawRect( aOverlayRect);
3128 }
3129
3130 aOverlayMergeBmp.CombineSimple( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ), BMP_COMBINE_AND );
3131 aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), aOverlayMergeBmp );
3132 }
3133
3134 rBmpEx = BitmapEx( aBmp, aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
3135 }
3136
3137 return !rBmpEx.IsEmpty();
3138 }
3139