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