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 <sal/config.h>
21 :
22 : #include <cstdlib>
23 :
24 : #include <vcl/bmpacc.hxx>
25 : #include <tools/poly.hxx>
26 : #include <vcl/outdev.hxx>
27 : #include <vcl/window.hxx>
28 : #include <vcl/gdimtf.hxx>
29 : #include <vcl/metaact.hxx>
30 : #include <vcl/metric.hxx>
31 : #include <vcl/animate.hxx>
32 : #include <vcl/alpha.hxx>
33 : #include <vcl/virdev.hxx>
34 : #include "grfcache.hxx"
35 : #include <svtools/grfmgr.hxx>
36 : #include <boost/scoped_array.hpp>
37 :
38 : // - defines -
39 :
40 :
41 : #define WATERMARK_LUM_OFFSET 50
42 : #define WATERMARK_CON_OFFSET -70
43 : #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L))
44 :
45 :
46 : // - GraphicManager -
47 :
48 :
49 198 : GraphicManager::GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ) :
50 : mnUsedSize(0),
51 198 : mpCache( new GraphicCache( nCacheSize, nMaxObjCacheSize ) )
52 : {
53 198 : }
54 :
55 210 : GraphicManager::~GraphicManager()
56 : {
57 105 : for( size_t i = 0, n = maObjList.size(); i < n; ++i )
58 0 : maObjList[ i ]->GraphicManagerDestroyed();
59 :
60 105 : delete mpCache;
61 105 : }
62 :
63 2 : void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize )
64 : {
65 2 : mpCache->SetMaxDisplayCacheSize( nNewCacheSize );
66 2 : }
67 :
68 4959 : sal_uLong GraphicManager::GetMaxCacheSize() const
69 : {
70 4959 : return mpCache->GetMaxDisplayCacheSize();
71 : }
72 :
73 0 : void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, bool bDestroyGreaterCached )
74 : {
75 0 : mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached );
76 0 : }
77 :
78 198 : void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds )
79 : {
80 198 : mpCache->SetCacheTimeout( nTimeoutSeconds );
81 198 : }
82 :
83 0 : bool GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt,
84 : const Size& rSz, const GraphicObject& rObj,
85 : const GraphicAttr& rAttr ) const
86 : {
87 0 : return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr );
88 : }
89 :
90 0 : bool GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
91 : GraphicObject& rObj, const GraphicAttr& rAttr,
92 : const GraphicManagerDrawFlags nFlags, bool& rCached )
93 : {
94 0 : Point aPt( rPt );
95 0 : Size aSz( rSz );
96 0 : bool bRet = false;
97 :
98 0 : rCached = false;
99 :
100 0 : if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) )
101 : {
102 : // create output and fill cache
103 :
104 0 : if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) ||
105 0 : ( !( nFlags & GraphicManagerDrawFlags::NO_SUBSTITUTE ) &&
106 0 : ( ( nFlags & GraphicManagerDrawFlags::SUBSTITUTE ) ||
107 0 : !( nFlags & GraphicManagerDrawFlags::CACHED ) ||
108 0 : ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) )
109 : {
110 : // simple output of transformed graphic
111 0 : const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
112 :
113 0 : if( aGraphic.IsSupportedGraphic() )
114 : {
115 0 : const sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
116 :
117 0 : if( nRot10 )
118 : {
119 0 : Polygon aPoly( Rectangle( aPt, aSz ) );
120 :
121 0 : aPoly.Rotate( aPt, nRot10 );
122 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
123 0 : aPt = aRotBoundRect.TopLeft();
124 0 : aSz = aRotBoundRect.GetSize();
125 : }
126 :
127 0 : aGraphic.Draw( pOut, aPt, aSz );
128 : }
129 :
130 0 : bRet = true;
131 : }
132 :
133 0 : if( !bRet )
134 : {
135 : // cached/direct drawing
136 0 : if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) )
137 0 : bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached );
138 : else
139 0 : bRet = rCached = true;
140 : }
141 : }
142 :
143 0 : return bRet;
144 : }
145 :
146 22846 : void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute,
147 : const OString* pID, const GraphicObject* pCopyObj )
148 : {
149 : assert(std::find(maObjList.begin(), maObjList.end(),
150 : const_cast<GraphicObject*>(&rObj)) == maObjList.end());
151 :
152 22846 : maObjList.push_back( const_cast<GraphicObject*>(&rObj) );
153 22846 : mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj );
154 22846 : if( !rObj.IsSwappedOut() )
155 22846 : mnUsedSize += rObj.maGraphic.GetSizeBytes();
156 22846 : }
157 :
158 22690 : void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj )
159 : {
160 22690 : mpCache->ReleaseGraphicObject( rObj );
161 22690 : if( !rObj.IsSwappedOut() )
162 : {
163 : assert(mnUsedSize >= rObj.maGraphic.GetSizeBytes());
164 22372 : mnUsedSize -= rObj.maGraphic.GetSizeBytes();
165 : }
166 188879 : for( GraphicObjectList_impl::iterator it = maObjList.begin(); it != maObjList.end(); ++it )
167 : {
168 188879 : if ( *it == &rObj ) {
169 22690 : maObjList.erase( it );
170 45380 : return;
171 : }
172 : }
173 : assert(false); // surely it should have been registered?
174 : }
175 :
176 441 : void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj )
177 : {
178 441 : mpCache->GraphicObjectWasSwappedOut( rObj );
179 : assert(mnUsedSize >= rObj.GetSizeBytes());
180 441 : mnUsedSize -= rObj.GetSizeBytes();
181 441 : }
182 :
183 2371 : OString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
184 : {
185 2371 : return mpCache->GetUniqueID( rObj );
186 : }
187 :
188 : namespace
189 : {
190 : struct simpleSortByDataChangeTimeStamp
191 : {
192 5427 : bool operator() (GraphicObject* p1, GraphicObject* p2) const
193 : {
194 5427 : return p1->GetDataChangeTimeStamp() < p2->GetDataChangeTimeStamp();
195 : }
196 : };
197 : } // end of anonymous namespace
198 :
199 4959 : void GraphicManager::ImplCheckSizeOfSwappedInGraphics(const GraphicObject* pGraphicToIgnore)
200 : {
201 : // detect maximum allowed memory footprint. Use the user-settings of MaxCacheSize (defaulted
202 : // to 200MB).
203 4959 : const sal_uLong nMaxCacheSize(GetMaxCacheSize());
204 :
205 4959 : if(mnUsedSize > nMaxCacheSize)
206 : {
207 : // Copy the object list for now, because maObjList can change in the meantime unexpectedly.
208 362 : std::vector< GraphicObject* > aCandidates(maObjList.begin(), maObjList.end());
209 : // if we use more currently, sort by last DataChangeTimeStamp
210 : // sort by DataChangeTimeStamp so that the oldest get removed first
211 362 : ::std::sort(aCandidates.begin(), aCandidates.end(), simpleSortByDataChangeTimeStamp());
212 :
213 3183 : for(sal_uInt32 a(0); mnUsedSize >= nMaxCacheSize && a < aCandidates.size(); a++)
214 : {
215 : // swap out until we have no more or the goal to use less than nMaxCacheSize
216 : // is reached
217 2821 : GraphicObject* pObj = aCandidates[a];
218 2821 : if( pObj == pGraphicToIgnore )
219 : {
220 508 : continue;
221 : }
222 2574 : if (std::find(maObjList.begin(), maObjList.end(), pObj) == maObjList.end())
223 : {
224 : // object has been deleted when swapping out another one
225 14 : continue;
226 : }
227 :
228 : // do not swap out when we have less than 16KB data objects
229 2560 : if(pObj->GetSizeBytes() >= (16 * 1024))
230 : {
231 697 : pObj->FireSwapOutRequest();
232 : }
233 362 : }
234 : }
235 4959 : }
236 :
237 181 : void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj )
238 : {
239 181 : mpCache->GraphicObjectWasSwappedIn( rObj );
240 181 : mnUsedSize += rObj.maGraphic.GetSizeBytes();
241 181 : }
242 :
243 0 : bool GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt,
244 : const Size& rSz, GraphicObject& rObj,
245 : const GraphicAttr& rAttr,
246 : const GraphicManagerDrawFlags nFlags, bool& rCached )
247 : {
248 0 : const Graphic& rGraphic = rObj.GetGraphic();
249 0 : bool bRet = false;
250 :
251 0 : if( rGraphic.IsSupportedGraphic() && !rObj.IsSwappedOut() )
252 : {
253 0 : if( GRAPHIC_BITMAP == rGraphic.GetType() )
254 : {
255 0 : const BitmapEx aSrcBmpEx( rGraphic.GetBitmapEx() );
256 :
257 : // #i46805# No point in caching a bitmap that is rendered
258 : // via RectFill on the OutDev
259 0 : if( !(pOut->GetDrawMode() & ( DrawModeFlags::BlackBitmap | DrawModeFlags::WhiteBitmap )) &&
260 0 : mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
261 : {
262 0 : BitmapEx aDstBmpEx;
263 :
264 0 : if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) )
265 : {
266 0 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
267 0 : bRet = true;
268 0 : }
269 : }
270 :
271 0 : if( !bRet )
272 0 : bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags );
273 : }
274 : else
275 : {
276 0 : const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile();
277 :
278 0 : if( mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
279 : {
280 0 : GDIMetaFile aDstMtf;
281 0 : BitmapEx aContainedBmpEx;
282 :
283 0 : if( ImplCreateOutput( pOut, rPt, rSz, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) )
284 : {
285 0 : if( !!aContainedBmpEx )
286 : {
287 : // Use bitmap output method, if metafile basically contains only a single
288 : // bitmap (allows caching the resulting pixmap).
289 0 : BitmapEx aDstBmpEx;
290 :
291 0 : if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) )
292 : {
293 0 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
294 0 : bRet = true;
295 0 : }
296 : }
297 : else
298 : {
299 0 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf );
300 0 : bRet = true;
301 : }
302 0 : }
303 : }
304 :
305 0 : if( !bRet )
306 : {
307 0 : const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
308 :
309 0 : if( aGraphic.IsSupportedGraphic() )
310 : {
311 0 : aGraphic.Draw( pOut, rPt, rSz );
312 0 : bRet = true;
313 0 : }
314 : }
315 : }
316 : }
317 :
318 0 : return bRet;
319 : }
320 :
321 0 : bool ImplCreateRotatedScaled( const BitmapEx& rBmpEx, const GraphicAttr& rAttributes,
322 : sal_uInt16 nRot10, const Size& rUnrotatedSzPix,
323 : long nStartX, long nEndX, long nStartY, long nEndY,
324 : BitmapEx& rOutBmpEx )
325 : {
326 0 : const long aUnrotatedWidth = rUnrotatedSzPix.Width();
327 0 : const long aUnrotatedHeight = rUnrotatedSzPix.Height();
328 0 : const long aBitmapWidth = rBmpEx.GetSizePixel().Width();
329 0 : const long aBitmapHeight = rBmpEx.GetSizePixel().Height();
330 :
331 : long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY, nTmp;
332 : double fTmp;
333 :
334 0 : bool bHMirr( rAttributes.GetMirrorFlags() & BmpMirrorFlags::Horizontal );
335 0 : bool bVMirr( rAttributes.GetMirrorFlags() & BmpMirrorFlags::Vertical );
336 :
337 0 : boost::scoped_array<long> pMapIX(new long[ aUnrotatedWidth ]);
338 0 : boost::scoped_array<long> pMapFX(new long[ aUnrotatedWidth ]);
339 0 : boost::scoped_array<long> pMapIY(new long[ aUnrotatedHeight ]);
340 0 : boost::scoped_array<long> pMapFY(new long[ aUnrotatedHeight ]);
341 :
342 : double fRevScaleX;
343 : double fRevScaleY;
344 :
345 0 : bool scaleByAveraging = false;
346 : int x,y;
347 :
348 0 : if(aBitmapWidth > 1 && aUnrotatedWidth > 1)
349 : {
350 0 : fRevScaleX = (double) ( aBitmapWidth - 1 ) / (double)( aUnrotatedWidth - 1 );
351 : // create horizontal mapping table
352 0 : for( x = 0, nTmpX = aBitmapWidth - 1L, nTmp = aBitmapWidth - 2L >= 0 ? aBitmapWidth -2L : 0L; x < aUnrotatedWidth; x++ )
353 : {
354 0 : fTmp = x * fRevScaleX;
355 :
356 0 : if( bHMirr )
357 0 : fTmp = nTmpX - fTmp;
358 :
359 0 : pMapIX[ x ] = MinMax( fTmp, 0, nTmp );
360 0 : pMapFX[ x ] = (long) ( ( fTmp - pMapIX[ x ] ) * 1048576.0 );
361 : }
362 0 : scaleByAveraging |= fRevScaleX > 5.0/3.0;
363 : }
364 : else
365 : {
366 0 : if(aBitmapWidth == 1)
367 : {
368 0 : fRevScaleX = 1.0 / (double)( aUnrotatedWidth );
369 0 : for ( x = 0; x < aUnrotatedWidth ; x++)
370 : {
371 0 : pMapIX[x] = 0;
372 0 : pMapFX[x] = 0;
373 : }
374 0 : scaleByAveraging = true;
375 : }
376 : else
377 : {
378 0 : fRevScaleX = (double) aBitmapWidth / (double)( aUnrotatedWidth);
379 0 : fTmp = (double)aBitmapWidth / 2.0;
380 :
381 0 : pMapIX[ 0 ] = (long)fTmp;
382 0 : pMapFX[ 0 ] = (long)( ( fTmp - pMapIX[ 0 ] ) * 1048576.0 );
383 0 : scaleByAveraging = true;
384 : }
385 : }
386 0 : if(aBitmapHeight > 1 && aUnrotatedHeight > 1)
387 : {
388 0 : fRevScaleY = (double) ( aBitmapHeight - 1 ) / (double)( aUnrotatedHeight - 1 );
389 : // create vertical mapping table
390 0 : for( y = 0, nTmpY = aBitmapHeight - 1L, nTmp = aBitmapHeight - 2L >= 0 ? aBitmapHeight - 2L : 0L; y < aUnrotatedHeight; y++ )
391 : {
392 0 : fTmp = y * fRevScaleY;
393 :
394 0 : if( bVMirr )
395 0 : fTmp = nTmpY - fTmp;
396 :
397 0 : pMapIY[ y ] = MinMax( fTmp, 0, nTmp );
398 0 : pMapFY[ y ] = (long) ( ( fTmp - pMapIY[ y ] ) * 1048576.0 );
399 : }
400 0 : scaleByAveraging |= fRevScaleY > 5.0/3.0;
401 : }
402 : else
403 : {
404 0 : if(aBitmapHeight == 1)
405 : {
406 0 : fRevScaleY = 1.0 / (double)( aUnrotatedHeight);
407 0 : for (y = 0; y < aUnrotatedHeight; ++y)
408 : {
409 0 : pMapIY[y] = 0;
410 0 : pMapFY[y] = 0;
411 : }
412 0 : scaleByAveraging = true;
413 : }
414 : else
415 : {
416 0 : fRevScaleY = (double) aBitmapHeight / (double)( aUnrotatedHeight);
417 0 : fTmp = (double)aBitmapHeight / 2.0;
418 :
419 0 : pMapIY[ 0 ] = (long)fTmp;
420 0 : pMapFY[ 0 ] = (long)( ( fTmp - pMapIY[ 0 ] ) * 1048576.0 );
421 0 : scaleByAveraging = true;
422 : }
423 : }
424 :
425 0 : Bitmap aBmp( rBmpEx.GetBitmap() );
426 0 : Bitmap aOutBmp;
427 0 : BitmapReadAccess* pReadAccess = aBmp.AcquireReadAccess();
428 : BitmapWriteAccess* pWriteAccess;
429 :
430 0 : const double fCosAngle = cos( nRot10 * F_PI1800 );
431 0 : const double fSinAngle = sin( nRot10 * F_PI1800 );
432 0 : const long aTargetWidth = nEndX - nStartX + 1L;
433 0 : const long aTargetHeight = nEndY - nStartY + 1L;
434 0 : boost::scoped_array<long> pCosX(new long[ aTargetWidth ]);
435 0 : boost::scoped_array<long> pSinX(new long[ aTargetWidth ]);
436 0 : boost::scoped_array<long> pCosY(new long[ aTargetHeight ]);
437 0 : boost::scoped_array<long> pSinY(new long[ aTargetHeight ]);
438 : long nUnRotX, nUnRotY, nSinY, nCosY;
439 : sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1;
440 0 : bool bRet = false;
441 :
442 0 : Polygon aPoly( Rectangle( Point(), rUnrotatedSzPix ) );
443 0 : aPoly.Rotate( Point(), nRot10 );
444 0 : Rectangle aNewBound( aPoly.GetBoundRect() );
445 :
446 : // create horizontal mapping table
447 0 : for( x = 0, nTmpX = aNewBound.Left() + nStartX; x < aTargetWidth; x++ )
448 : {
449 0 : pCosX[ x ] = FRound( fCosAngle * ( fTmp = nTmpX++ << 8 ) );
450 0 : pSinX[ x ] = FRound( fSinAngle * fTmp );
451 : }
452 :
453 : // create vertical mapping table
454 0 : for( y = 0, nTmpY = aNewBound.Top() + nStartY; y < aTargetHeight; y++ )
455 : {
456 0 : pCosY[ y ] = FRound( fCosAngle * ( fTmp = nTmpY++ << 8 ) );
457 0 : pSinY[ y ] = FRound( fSinAngle * fTmp );
458 : }
459 :
460 0 : if( pReadAccess )
461 : {
462 0 : aOutBmp = Bitmap( Size( aTargetWidth, aTargetHeight ), 24 );
463 0 : pWriteAccess = aOutBmp.AcquireWriteAccess();
464 :
465 0 : if( pWriteAccess )
466 : {
467 0 : BitmapColor aColRes;
468 :
469 0 : if ( !scaleByAveraging )
470 : {
471 0 : if( pReadAccess->HasPalette() )
472 : {
473 0 : for( y = 0; y < aTargetHeight; y++ )
474 : {
475 0 : nSinY = pSinY[ y ];
476 0 : nCosY = pCosY[ y ];
477 :
478 0 : for( x = 0; x < aTargetWidth; x++ )
479 : {
480 0 : nUnRotX = ( pCosX[ x ] - nSinY ) >> 8;
481 0 : nUnRotY = ( pSinX[ x ] + nCosY ) >> 8;
482 :
483 0 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
484 0 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
485 : {
486 0 : nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
487 0 : nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
488 :
489 0 : const BitmapColor& rCol0 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, nTmpX ) );
490 0 : const BitmapColor& rCol1 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, ++nTmpX ) );
491 0 : cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
492 0 : cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
493 0 : cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
494 :
495 0 : const BitmapColor& rCol3 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( ++nTmpY, nTmpX ) );
496 0 : const BitmapColor& rCol2 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, --nTmpX ) );
497 0 : cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
498 0 : cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
499 0 : cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
500 :
501 0 : aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
502 0 : aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
503 0 : aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
504 0 : pWriteAccess->SetPixel( y, x, aColRes );
505 : }
506 : }
507 : }
508 : }
509 : else
510 : {
511 0 : BitmapColor aCol0, aCol1;
512 :
513 0 : for( y = 0; y < aTargetHeight; y++ )
514 : {
515 0 : nSinY = pSinY[ y ];
516 0 : nCosY = pCosY[ y ];
517 :
518 0 : for( x = 0; x < aTargetWidth; x++ )
519 : {
520 0 : nUnRotX = ( pCosX[ x ] - nSinY ) >> 8;
521 0 : nUnRotY = ( pSinX[ x ] + nCosY ) >> 8;
522 :
523 0 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
524 0 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
525 : {
526 0 : nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
527 0 : nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
528 :
529 0 : aCol0 = pReadAccess->GetPixel( nTmpY, nTmpX );
530 0 : aCol1 = pReadAccess->GetPixel( nTmpY, ++nTmpX );
531 0 : cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
532 0 : cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
533 0 : cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
534 :
535 0 : aCol1 = pReadAccess->GetPixel( ++nTmpY, nTmpX );
536 0 : aCol0 = pReadAccess->GetPixel( nTmpY, --nTmpX );
537 0 : cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
538 0 : cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
539 0 : cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
540 :
541 0 : aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
542 0 : aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
543 0 : aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
544 0 : pWriteAccess->SetPixel( y, x, aColRes );
545 : }
546 : }
547 0 : }
548 : }
549 : }
550 : else // scaleByAveraging
551 : {
552 : double aSumRed, aSumGreen, aSumBlue, aCount;
553 0 : BitmapColor aColor;
554 0 : BitmapColor aResultColor;
555 :
556 0 : for( y = 0; y < aTargetHeight; y++ )
557 : {
558 0 : nSinY = pSinY[ y ];
559 0 : nCosY = pCosY[ y ];
560 :
561 0 : for( x = 0; x < aTargetWidth; x++ )
562 : {
563 0 : double aUnrotatedX = ( pCosX[ x ] - nSinY ) / 256.0;
564 0 : double aUnrotatedY = ( pSinX[ x ] + nCosY ) / 256.0;
565 :
566 0 : if ( bHMirr )
567 0 : aUnrotatedX = aUnrotatedWidth - aUnrotatedX - 1;
568 0 : if ( bVMirr )
569 0 : aUnrotatedY = aUnrotatedHeight - aUnrotatedY - 1;
570 :
571 0 : if( ( aUnrotatedX >= 0 ) && ( aUnrotatedX < aUnrotatedWidth ) &&
572 0 : ( aUnrotatedY >= 0 ) && ( aUnrotatedY < aUnrotatedHeight ) )
573 : {
574 0 : double dYStart = ((aUnrotatedY + 0.5) * fRevScaleY) - 0.5;
575 0 : double dYEnd = ((aUnrotatedY + 1.5) * fRevScaleY) - 0.5;
576 :
577 0 : int yStart = MinMax( dYStart, 0, aBitmapHeight - 1);
578 0 : int yEnd = MinMax( dYEnd, 0, aBitmapHeight - 1);
579 :
580 0 : double dXStart = ((aUnrotatedX + 0.5) * fRevScaleX) - 0.5;
581 0 : double dXEnd = ((aUnrotatedX + 1.5) * fRevScaleX) - 0.5;
582 :
583 0 : int xStart = MinMax( dXStart, 0, aBitmapWidth - 1);
584 0 : int xEnd = MinMax( dXEnd, 0, aBitmapWidth - 1);
585 :
586 0 : aSumRed = aSumGreen = aSumBlue = 0.0;
587 0 : aCount = 0;
588 :
589 0 : for (int yIn = yStart; yIn <= yEnd; yIn++)
590 : {
591 0 : for (int xIn = xStart; xIn <= xEnd; xIn++)
592 : {
593 0 : if( pReadAccess->HasPalette() )
594 0 : aColor = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( yIn, xIn ) );
595 : else
596 0 : aColor = pReadAccess->GetPixel( yIn, xIn );
597 :
598 0 : aSumRed += aColor.GetRed();
599 0 : aSumGreen += aColor.GetGreen();
600 0 : aSumBlue += aColor.GetBlue();
601 :
602 0 : aCount++;
603 : }
604 : }
605 :
606 0 : aResultColor.SetRed( MinMax( aSumRed / aCount, 0, 255) );
607 0 : aResultColor.SetGreen( MinMax( aSumGreen / aCount, 0, 255) );
608 0 : aResultColor.SetBlue( MinMax( aSumBlue / aCount, 0, 255) );
609 :
610 0 : pWriteAccess->SetPixel( y, x, aResultColor );
611 : }
612 : }
613 0 : }
614 : }
615 :
616 0 : Bitmap::ReleaseAccess( pWriteAccess );
617 0 : bRet = true;
618 : }
619 :
620 0 : Bitmap::ReleaseAccess( pReadAccess );
621 : }
622 :
623 : // mask processing
624 0 : if( bRet && ( rBmpEx.IsTransparent() || ( nRot10 != 0 && nRot10 != 900 && nRot10 != 1800 && nRot10 != 2700 ) ) )
625 : {
626 0 : bRet = false;
627 :
628 0 : if( rBmpEx.IsAlpha() )
629 : {
630 0 : AlphaMask aAlpha( rBmpEx.GetAlpha() );
631 0 : AlphaMask aOutAlpha;
632 :
633 0 : pReadAccess = aAlpha.AcquireReadAccess();
634 :
635 0 : if( pReadAccess )
636 : {
637 0 : aOutAlpha = AlphaMask( Size( aTargetWidth, aTargetHeight ) );
638 0 : pWriteAccess = aOutAlpha.AcquireWriteAccess();
639 :
640 0 : if( pWriteAccess )
641 : {
642 0 : if( pReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
643 0 : pWriteAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
644 : {
645 0 : if ( !scaleByAveraging )
646 : {
647 : Scanline pLine0, pLine1, pLineW;
648 :
649 0 : for( nY = 0; nY < aTargetHeight; nY++ )
650 : {
651 0 : nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
652 0 : pLineW = pWriteAccess->GetScanline( nY );
653 :
654 0 : for( nX = 0; nX < aTargetWidth; nX++ )
655 : {
656 0 : nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
657 0 : nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
658 :
659 0 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
660 0 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
661 : {
662 0 : nTmpX = pMapIX[ nUnRotX ], nTmpFX = pMapFX[ nUnRotX ];
663 0 : nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
664 :
665 0 : pLine0 = pReadAccess->GetScanline( nTmpY++ );
666 0 : pLine1 = pReadAccess->GetScanline( nTmpY );
667 :
668 0 : const long nAlpha0 = pLine0[ nTmpX ];
669 0 : const long nAlpha2 = pLine1[ nTmpX++ ];
670 0 : const long nAlpha1 = pLine0[ nTmpX ];
671 0 : const long nAlpha3 = pLine1[ nTmpX ];
672 0 : const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
673 0 : const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
674 :
675 0 : *pLineW++ = MAP( n0, n1, nTmpFY );
676 : }
677 : else
678 0 : *pLineW++ = 255;
679 : }
680 : }
681 : }
682 : else // scaleByAveraging
683 : {
684 0 : const BitmapColor aTrans( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
685 0 : BitmapColor aResultColor( 0 );
686 : double aSum, aCount;
687 :
688 0 : for( y = 0; y < aTargetHeight; y++ )
689 : {
690 0 : nSinY = pSinY[ y ];
691 0 : nCosY = pCosY[ y ];
692 :
693 0 : for( x = 0; x < aTargetWidth; x++ )
694 : {
695 :
696 0 : double aUnrotatedX = ( pCosX[ x ] - nSinY ) / 256.0;
697 0 : double aUnrotatedY = ( pSinX[ x ] + nCosY ) / 256.0;
698 :
699 0 : if ( bHMirr )
700 0 : aUnrotatedX = aUnrotatedWidth - aUnrotatedX - 1;
701 0 : if ( bVMirr )
702 0 : aUnrotatedY = aUnrotatedHeight - aUnrotatedY - 1;
703 :
704 0 : if( ( aUnrotatedX >= 0 ) && ( aUnrotatedX < aUnrotatedWidth ) &&
705 0 : ( aUnrotatedY >= 0 ) && ( aUnrotatedY < aUnrotatedHeight ) )
706 : {
707 0 : double dYStart = ((aUnrotatedY + 0.5) * fRevScaleY) - 0.5;
708 0 : double dYEnd = ((aUnrotatedY + 1.5) * fRevScaleY) - 0.5;
709 :
710 0 : int yStart = MinMax( dYStart, 0, aBitmapHeight - 1);
711 0 : int yEnd = MinMax( dYEnd, 0, aBitmapHeight - 1);
712 :
713 0 : double dXStart = ((aUnrotatedX + 0.5) * fRevScaleX) - 0.5;
714 0 : double dXEnd = ((aUnrotatedX + 1.5) * fRevScaleX) - 0.5;
715 :
716 0 : int xStart = MinMax( dXStart, 0, aBitmapWidth - 1);
717 0 : int xEnd = MinMax( dXEnd, 0, aBitmapWidth - 1);
718 :
719 0 : aSum = 0.0;
720 0 : aCount = 0;
721 :
722 0 : for (int yIn = yStart; yIn <= yEnd; yIn++)
723 : {
724 0 : for (int xIn = xStart; xIn <= xEnd; xIn++)
725 : {
726 0 : aSum += pReadAccess->GetPixel( yIn, xIn ).GetIndex();
727 0 : aCount++;
728 : }
729 : }
730 0 : aResultColor.SetIndex( MinMax( aSum / aCount, 0, 255) );
731 0 : pWriteAccess->SetPixel( y, x, aResultColor );
732 : }
733 : else
734 : {
735 0 : pWriteAccess->SetPixel( y, x, aTrans );
736 : }
737 : }
738 0 : }
739 : }
740 : }
741 : else
742 : {
743 0 : const BitmapColor aTrans( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
744 0 : BitmapColor aAlphaVal( 0 );
745 :
746 0 : for( nY = 0; nY < aTargetHeight; nY++ )
747 : {
748 0 : nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
749 :
750 0 : for( nX = 0; nX < aTargetWidth; nX++ )
751 : {
752 0 : nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
753 0 : nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
754 :
755 0 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
756 0 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
757 : {
758 0 : nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
759 0 : nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
760 :
761 0 : const long nAlpha0 = pReadAccess->GetPixel( nTmpY, nTmpX ).GetIndex();
762 0 : const long nAlpha1 = pReadAccess->GetPixel( nTmpY, ++nTmpX ).GetIndex();
763 0 : const long nAlpha3 = pReadAccess->GetPixel( ++nTmpY, nTmpX ).GetIndex();
764 0 : const long nAlpha2 = pReadAccess->GetPixel( nTmpY, --nTmpX ).GetIndex();
765 0 : const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
766 0 : const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
767 :
768 0 : aAlphaVal.SetIndex( MAP( n0, n1, nTmpFY ) );
769 0 : pWriteAccess->SetPixel( nY, nX, aAlphaVal );
770 : }
771 : else
772 0 : pWriteAccess->SetPixel( nY, nX, aTrans );
773 : }
774 0 : }
775 : }
776 :
777 0 : aOutAlpha.ReleaseAccess( pWriteAccess );
778 0 : bRet = true;
779 : }
780 :
781 0 : aAlpha.ReleaseAccess( pReadAccess );
782 : }
783 :
784 0 : if( bRet )
785 0 : rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
786 : }
787 : else
788 : {
789 0 : Bitmap aOutMsk( Size( aTargetWidth, aTargetHeight ), 1 );
790 0 : pWriteAccess = aOutMsk.AcquireWriteAccess();
791 :
792 0 : if( pWriteAccess )
793 : {
794 0 : Bitmap aMsk( rBmpEx.GetMask() );
795 0 : const BitmapColor aB( pWriteAccess->GetBestMatchingColor( Color( COL_BLACK ) ) );
796 0 : const BitmapColor aW( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
797 0 : BitmapReadAccess* pMAcc = NULL;
798 :
799 0 : if( !aMsk || ( ( pMAcc = aMsk.AcquireReadAccess() ) != NULL ) )
800 : {
801 0 : boost::scoped_array<long> pMapLX(new long[ aUnrotatedWidth ]);
802 0 : boost::scoped_array<long> pMapLY(new long[ aUnrotatedHeight ]);
803 0 : BitmapColor aTestB;
804 :
805 0 : if( pMAcc )
806 0 : aTestB = pMAcc->GetBestMatchingColor( Color( COL_BLACK ) );
807 :
808 : // create new horizontal mapping table
809 0 : for( nX = 0UL; nX < aUnrotatedWidth; nX++ )
810 0 : pMapLX[ nX ] = FRound( (double) pMapIX[ nX ] + pMapFX[ nX ] / 1048576.0 );
811 :
812 : // create new vertical mapping table
813 0 : for( nY = 0UL; nY < aUnrotatedHeight; nY++ )
814 0 : pMapLY[ nY ] = FRound( (double) pMapIY[ nY ] + pMapFY[ nY ] / 1048576.0 );
815 :
816 : // do mask rotation
817 0 : for( nY = 0; nY < aTargetHeight; nY++ )
818 : {
819 0 : nSinY = pSinY[ nY ];
820 0 : nCosY = pCosY[ nY ];
821 :
822 0 : for( nX = 0; nX < aTargetWidth; nX++ )
823 : {
824 0 : nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
825 0 : nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
826 :
827 0 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
828 0 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
829 : {
830 0 : if( pMAcc )
831 : {
832 0 : if( pMAcc->GetPixel( pMapLY[ nUnRotY ], pMapLX[ nUnRotX ] ) == aTestB )
833 0 : pWriteAccess->SetPixel( nY, nX, aB );
834 : else
835 0 : pWriteAccess->SetPixel( nY, nX, aW );
836 : }
837 : else
838 0 : pWriteAccess->SetPixel( nY, nX, aB );
839 : }
840 : else
841 0 : pWriteAccess->SetPixel( nY, nX, aW );
842 : }
843 : }
844 :
845 0 : pMapLX.reset();
846 0 : pMapLY.reset();
847 :
848 0 : if( pMAcc )
849 0 : Bitmap::ReleaseAccess( pMAcc );
850 :
851 0 : bRet = true;
852 : }
853 :
854 0 : Bitmap::ReleaseAccess( pWriteAccess );
855 : }
856 :
857 0 : if( bRet )
858 0 : rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
859 : }
860 :
861 0 : if( !bRet )
862 0 : rOutBmpEx = aOutBmp;
863 : }
864 : else
865 0 : rOutBmpEx = aOutBmp;
866 :
867 0 : return bRet;
868 : }
869 :
870 0 : bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice,
871 : const Point& rPoint, const Size& rSize,
872 : const BitmapEx& rBitmapEx, const GraphicAttr& rAttributes,
873 : const GraphicManagerDrawFlags /*nFlags*/, BitmapEx* pBmpEx )
874 : {
875 0 : sal_uInt16 nRot10 = rAttributes.GetRotation() % 3600;
876 :
877 0 : Point aOutputPointPix;
878 0 : Size aOutputSizePix;
879 0 : Point aUnrotatedPointPix( pOutputDevice->LogicToPixel( rPoint ) );
880 0 : Size aUnrotatedSizePix( pOutputDevice->LogicToPixel( rSize ) );
881 :
882 0 : bool bRet = false;
883 :
884 0 : if( nRot10 )
885 : {
886 0 : Polygon aPoly( Rectangle( rPoint, rSize ) );
887 0 : aPoly.Rotate( rPoint, nRot10 );
888 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
889 0 : aOutputPointPix = pOutputDevice->LogicToPixel( aRotBoundRect.TopLeft() );
890 0 : aOutputSizePix = pOutputDevice->LogicToPixel( aRotBoundRect.GetSize() );
891 : }
892 : else
893 : {
894 0 : aOutputPointPix = aUnrotatedPointPix;
895 0 : aOutputSizePix = aUnrotatedSizePix;
896 : }
897 :
898 0 : if( aUnrotatedSizePix.Width() && aUnrotatedSizePix.Height() )
899 : {
900 0 : BitmapEx aBmpEx( rBitmapEx );
901 0 : BitmapEx aOutBmpEx;
902 0 : Point aOutPoint;
903 0 : Size aOutSize;
904 0 : const Size& rBmpSzPix = rBitmapEx.GetSizePixel();
905 0 : const long nW = rBmpSzPix.Width();
906 0 : const long nH = rBmpSzPix.Height();
907 0 : long nStartX = -1, nStartY = -1, nEndX = -1, nEndY = -1;
908 0 : bool bHMirr( rAttributes.GetMirrorFlags() & BmpMirrorFlags::Horizontal );
909 0 : bool bVMirr( rAttributes.GetMirrorFlags() & BmpMirrorFlags::Vertical );
910 :
911 : // calculate output sizes
912 0 : if( !pBmpEx )
913 : {
914 0 : Point aPt;
915 0 : Rectangle aOutRect( aPt, pOutputDevice->GetOutputSizePixel() );
916 0 : Rectangle aBmpRect( aOutputPointPix, aOutputSizePix );
917 :
918 0 : if( pOutputDevice->GetOutDevType() == OUTDEV_WINDOW )
919 : {
920 0 : const vcl::Region aPaintRgn( static_cast<vcl::Window*>( pOutputDevice )->GetPaintRegion() );
921 0 : if( !aPaintRgn.IsNull() )
922 0 : aOutRect.Intersection( pOutputDevice->LogicToPixel( aPaintRgn.GetBoundRect() ) );
923 : }
924 :
925 0 : aOutRect.Intersection( aBmpRect );
926 :
927 0 : if( !aOutRect.IsEmpty() )
928 : {
929 0 : aOutPoint = pOutputDevice->PixelToLogic( aOutRect.TopLeft() );
930 0 : aOutSize = pOutputDevice->PixelToLogic( aOutRect.GetSize() );
931 0 : nStartX = aOutRect.Left() - aBmpRect.Left();
932 0 : nStartY = aOutRect.Top() - aBmpRect.Top();
933 0 : nEndX = aOutRect.Right() - aBmpRect.Left();
934 0 : nEndY = aOutRect.Bottom() - aBmpRect.Top();
935 : }
936 : else
937 : {
938 0 : nStartX = -1L; // invalid
939 : }
940 : }
941 : else
942 : {
943 0 : aOutPoint = pOutputDevice->PixelToLogic( aOutputPointPix );
944 0 : aOutSize = pOutputDevice->PixelToLogic( aOutputSizePix );
945 0 : nStartX = nStartY = 0;
946 0 : nEndX = aOutputSizePix.Width() - 1L;
947 0 : nEndY = aOutputSizePix.Height() - 1L;
948 : }
949 :
950 : // do transformation
951 0 : if( nStartX >= 0L )
952 : {
953 0 : const bool bSimple = ( 1 == nW || 1 == nH );
954 :
955 0 : if( nRot10 )
956 : {
957 0 : if( bSimple )
958 : {
959 0 : bRet = ( aOutBmpEx = aBmpEx ).Scale( aUnrotatedSizePix );
960 :
961 0 : if( bRet )
962 0 : aOutBmpEx.Rotate( nRot10, COL_TRANSPARENT );
963 : }
964 : else
965 : {
966 : bRet = ImplCreateRotatedScaled( aBmpEx, rAttributes,
967 : nRot10, aUnrotatedSizePix,
968 : nStartX, nEndX, nStartY, nEndY,
969 0 : aOutBmpEx );
970 : }
971 : }
972 : else
973 : {
974 0 : if( !bHMirr && !bVMirr && aOutputSizePix == rBmpSzPix )
975 : {
976 0 : aOutPoint = pOutputDevice->PixelToLogic( aOutputPointPix );
977 0 : aOutSize = pOutputDevice->PixelToLogic( aOutputSizePix );
978 0 : aOutBmpEx = aBmpEx;
979 0 : bRet = true;
980 : }
981 : else
982 : {
983 0 : if( bSimple )
984 : {
985 0 : bRet = ( aOutBmpEx = aBmpEx ).Scale( Size( nEndX - nStartX + 1, nEndY - nStartY + 1 ) );
986 : }
987 : else
988 : {
989 : bRet = ImplCreateRotatedScaled( aBmpEx, rAttributes,
990 : nRot10, aUnrotatedSizePix,
991 : nStartX, nEndX, nStartY, nEndY,
992 0 : aOutBmpEx );
993 : }
994 : }
995 : }
996 :
997 0 : if( bRet )
998 : {
999 : // Attribute adjustment if necessary
1000 0 : if( rAttributes.IsSpecialDrawMode() || rAttributes.IsAdjusted() || rAttributes.IsTransparent() )
1001 0 : ImplAdjust( aOutBmpEx, rAttributes, GraphicAdjustmentFlags::DRAWMODE | GraphicAdjustmentFlags::COLORS | GraphicAdjustmentFlags::TRANSPARENCY );
1002 :
1003 : // OutDev adjustment if necessary
1004 0 : if( pOutputDevice->GetOutDevType() != OUTDEV_PRINTER && pOutputDevice->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 )
1005 0 : aOutBmpEx.Dither( BmpDitherFlags::Matrix );
1006 : }
1007 : }
1008 :
1009 : // Create output
1010 0 : if( bRet )
1011 : {
1012 0 : if( !pBmpEx )
1013 0 : pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, aOutBmpEx );
1014 : else
1015 : {
1016 0 : if( !rAttributes.IsTransparent() && !aOutBmpEx.IsAlpha() )
1017 0 : aOutBmpEx = BitmapEx( aOutBmpEx.GetBitmap().CreateDisplayBitmap( pOutputDevice ), aOutBmpEx.GetMask() );
1018 :
1019 0 : pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, *pBmpEx = aOutBmpEx );
1020 : }
1021 0 : }
1022 : }
1023 :
1024 0 : return bRet;
1025 : }
1026 :
1027 : // This function checks whether the bitmap is usable for skipping
1028 : // mtf rendering by using just this one bitmap (i.e. in case the metafile
1029 : // contains just this one pixmap that covers the entire metafile area).
1030 0 : static BitmapEx checkMetadataBitmap( const BitmapEx& rBmpEx,
1031 : Point rSrcPoint,
1032 : Size rSrcSize,
1033 : const Point& rDestPoint,
1034 : const Size& rDestSize,
1035 : const Size& rRefSize,
1036 : bool& o_rbNonBitmapActionEncountered )
1037 : {
1038 : // NOTE: If you do changes in this function, change checkMetadataBitmap() in grfcache.cxx too.
1039 0 : BitmapEx aBmpEx;
1040 0 : if( rSrcSize == Size())
1041 0 : rSrcSize = rBmpEx.GetSizePixel();
1042 :
1043 0 : if( rDestPoint != Point( 0, 0 ))
1044 : { // The pixmap in the metafile has an offset (and so would not cover)
1045 : // the entire result -> fall back to mtf rendering.
1046 0 : o_rbNonBitmapActionEncountered = true;
1047 0 : return aBmpEx;
1048 : }
1049 0 : if( rDestSize != rRefSize )
1050 : { // The pixmap is not fullscale (does not cover the entire metafile area).
1051 : // HACK: The code here should refuse to use the bitmap directly
1052 : // and fall back to mtf rendering, but there seem to be metafiles
1053 : // that do not specify exactly their area (the Windows API requires apps
1054 : // the specify it manually, the rectangle is specified as topleft/bottomright
1055 : // rather than topleft/size [which may be confusing], and the docs
1056 : // on the exact meaning are somewhat confusing as well), so if it turns
1057 : // out this metafile really contains just one bitmap and no other painting,
1058 : // and if the sizes almost match, just use the pixmap (which will be scaled
1059 : // to fit exactly the requested size, so there should not be any actual problem
1060 : // caused by this small difference). This will allow caching of the resulting
1061 : // (scaled) pixmap, which can make a noticeable performance difference.
1062 0 : if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100
1063 0 : && std::abs( rDestSize.Width() - rRefSize.Width()) < 5
1064 0 : && std::abs( rDestSize.Height() - rRefSize.Height()) < 5 )
1065 : ; // ok, assume it's close enough
1066 : else
1067 : { // fall back to mtf rendering
1068 0 : o_rbNonBitmapActionEncountered = true;
1069 0 : return aBmpEx;
1070 : }
1071 : }
1072 :
1073 0 : aBmpEx = rBmpEx;
1074 :
1075 0 : if( (rSrcPoint.X() != 0 && rSrcPoint.Y() != 0) ||
1076 0 : rSrcSize != rBmpEx.GetSizePixel() )
1077 : {
1078 : // crop bitmap to given source rectangle (no
1079 : // need to copy and convert the whole bitmap)
1080 : const Rectangle aCropRect( rSrcPoint,
1081 0 : rSrcSize );
1082 0 : aBmpEx.Crop( aCropRect );
1083 : }
1084 :
1085 0 : return aBmpEx;
1086 : }
1087 :
1088 0 : bool GraphicManager::ImplCreateOutput( OutputDevice* pOut,
1089 : const Point& rPt, const Size& rSz,
1090 : const GDIMetaFile& rMtf, const GraphicAttr& rAttr,
1091 : const GraphicManagerDrawFlags /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx )
1092 : {
1093 0 : const Size aNewSize( rMtf.GetPrefSize() );
1094 :
1095 0 : rOutMtf = rMtf;
1096 :
1097 : // Count bitmap actions, and flag actions that paint, but
1098 : // are no bitmaps.
1099 0 : sal_Int32 nNumBitmaps(0);
1100 0 : bool bNonBitmapActionEncountered(false);
1101 0 : if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
1102 : {
1103 0 : const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height();
1104 0 : const double fOutWH = (double) rSz.Width() / rSz.Height();
1105 :
1106 0 : const double fScaleX = fOutWH / fGrfWH;
1107 0 : const double fScaleY = 1.0;
1108 :
1109 0 : const MapMode rPrefMapMode( rMtf.GetPrefMapMode() );
1110 0 : const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) );
1111 :
1112 : // NOTE: If you do changes in this function, check GraphicDisplayCacheEntry::IsCacheableAsBitmap
1113 : // in grfcache.cxx too.
1114 :
1115 : // Determine whether the metafile basically displays
1116 : // a single bitmap (in which case that bitmap is simply used directly
1117 : // instead of playing the metafile). Note that
1118 : // the solution, as implemented here, is quite suboptimal (the
1119 : // cases where a mtf consisting basically of a single bitmap,
1120 : // that fail to pass the test below, are probably frequent). A
1121 : // better solution would involve FSAA, but that's currently
1122 : // expensive, and might trigger bugs on display drivers, if
1123 : // VDevs get bigger than the actual screen.
1124 : sal_uInt32 nCurPos;
1125 : MetaAction* pAct;
1126 0 : for( nCurPos = 0, pAct = rOutMtf.FirstAction(); pAct;
1127 : pAct = rOutMtf.NextAction(), nCurPos++ )
1128 : {
1129 0 : MetaAction* pModAct = NULL;
1130 0 : switch( pAct->GetType() )
1131 : {
1132 : case MetaActionType::FONT:
1133 : {
1134 : // taking care of font width default if scaling metafile.
1135 0 : MetaFontAction* pA = static_cast<MetaFontAction*>(pAct);
1136 0 : vcl::Font aFont( pA->GetFont() );
1137 0 : if ( !aFont.GetWidth() )
1138 : {
1139 0 : FontMetric aFontMetric( pOut->GetFontMetric( aFont ) );
1140 0 : aFont.SetWidth( aFontMetric.GetWidth() );
1141 0 : pModAct = new MetaFontAction( aFont );
1142 0 : }
1143 : }
1144 : // FALLTHROUGH intended
1145 : case MetaActionType::NONE:
1146 : // FALLTHROUGH intended
1147 :
1148 : // OutDev state changes (which don't affect bitmap
1149 : // output)
1150 : case MetaActionType::LINECOLOR:
1151 : // FALLTHROUGH intended
1152 : case MetaActionType::FILLCOLOR:
1153 : // FALLTHROUGH intended
1154 : case MetaActionType::TEXTCOLOR:
1155 : // FALLTHROUGH intended
1156 : case MetaActionType::TEXTFILLCOLOR:
1157 : // FALLTHROUGH intended
1158 : case MetaActionType::TEXTALIGN:
1159 : // FALLTHROUGH intended
1160 : case MetaActionType::TEXTLINECOLOR:
1161 : // FALLTHROUGH intended
1162 : case MetaActionType::TEXTLINE:
1163 : // FALLTHROUGH intended
1164 : case MetaActionType::PUSH:
1165 : // FALLTHROUGH intended
1166 : case MetaActionType::POP:
1167 : // FALLTHROUGH intended
1168 : case MetaActionType::LAYOUTMODE:
1169 : // FALLTHROUGH intended
1170 : case MetaActionType::TEXTLANGUAGE:
1171 : // FALLTHROUGH intended
1172 : case MetaActionType::COMMENT:
1173 0 : break;
1174 :
1175 : // bitmap output methods
1176 : case MetaActionType::BMP:
1177 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1178 : {
1179 0 : MetaBmpAction* pAction = static_cast<MetaBmpAction*>(pAct);
1180 :
1181 0 : rOutBmpEx = checkMetadataBitmap(
1182 0 : BitmapEx( pAction->GetBitmap()),
1183 : Point(), Size(),
1184 0 : pOut->LogicToPixel( pAction->GetPoint(),
1185 : rPrefMapMode ),
1186 0 : pAction->GetBitmap().GetSizePixel(),
1187 : rSizePix,
1188 0 : bNonBitmapActionEncountered );
1189 : }
1190 0 : ++nNumBitmaps;
1191 0 : break;
1192 :
1193 : case MetaActionType::BMPSCALE:
1194 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1195 : {
1196 0 : MetaBmpScaleAction* pAction = static_cast<MetaBmpScaleAction*>(pAct);
1197 :
1198 0 : rOutBmpEx = checkMetadataBitmap(
1199 0 : BitmapEx( pAction->GetBitmap()),
1200 : Point(), Size(),
1201 0 : pOut->LogicToPixel( pAction->GetPoint(),
1202 : rPrefMapMode ),
1203 0 : pOut->LogicToPixel( pAction->GetSize(),
1204 : rPrefMapMode ),
1205 : rSizePix,
1206 0 : bNonBitmapActionEncountered );
1207 : }
1208 0 : ++nNumBitmaps;
1209 0 : break;
1210 :
1211 : case MetaActionType::BMPSCALEPART:
1212 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1213 : {
1214 0 : MetaBmpScalePartAction* pAction = static_cast<MetaBmpScalePartAction*>(pAct);
1215 :
1216 0 : rOutBmpEx = checkMetadataBitmap(
1217 0 : BitmapEx( pAction->GetBitmap() ),
1218 0 : pAction->GetSrcPoint(),
1219 0 : pAction->GetSrcSize(),
1220 0 : pOut->LogicToPixel( pAction->GetDestPoint(),
1221 : rPrefMapMode ),
1222 0 : pOut->LogicToPixel( pAction->GetDestSize(),
1223 : rPrefMapMode ),
1224 : rSizePix,
1225 0 : bNonBitmapActionEncountered );
1226 : }
1227 0 : ++nNumBitmaps;
1228 0 : break;
1229 :
1230 : case MetaActionType::BMPEX:
1231 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1232 : {
1233 0 : MetaBmpExAction* pAction = static_cast<MetaBmpExAction*>(pAct);
1234 :
1235 0 : rOutBmpEx = checkMetadataBitmap(
1236 0 : pAction->GetBitmapEx(),
1237 : Point(), Size(),
1238 0 : pOut->LogicToPixel( pAction->GetPoint(),
1239 : rPrefMapMode ),
1240 0 : pAction->GetBitmapEx().GetSizePixel(),
1241 : rSizePix,
1242 0 : bNonBitmapActionEncountered );
1243 : }
1244 0 : ++nNumBitmaps;
1245 0 : break;
1246 :
1247 : case MetaActionType::BMPEXSCALE:
1248 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1249 : {
1250 0 : MetaBmpExScaleAction* pAction = static_cast<MetaBmpExScaleAction*>(pAct);
1251 :
1252 0 : rOutBmpEx = checkMetadataBitmap(
1253 0 : pAction->GetBitmapEx(),
1254 : Point(), Size(),
1255 0 : pOut->LogicToPixel( pAction->GetPoint(),
1256 : rPrefMapMode ),
1257 0 : pOut->LogicToPixel( pAction->GetSize(),
1258 : rPrefMapMode ),
1259 : rSizePix,
1260 0 : bNonBitmapActionEncountered );
1261 : }
1262 0 : ++nNumBitmaps;
1263 0 : break;
1264 :
1265 : case MetaActionType::BMPEXSCALEPART:
1266 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1267 : {
1268 0 : MetaBmpExScalePartAction* pAction = static_cast<MetaBmpExScalePartAction*>(pAct);
1269 :
1270 0 : rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(),
1271 0 : pAction->GetSrcPoint(),
1272 0 : pAction->GetSrcSize(),
1273 0 : pOut->LogicToPixel( pAction->GetDestPoint(),
1274 : rPrefMapMode ),
1275 0 : pOut->LogicToPixel( pAction->GetDestSize(),
1276 : rPrefMapMode ),
1277 : rSizePix,
1278 0 : bNonBitmapActionEncountered );
1279 : }
1280 0 : ++nNumBitmaps;
1281 0 : break;
1282 :
1283 : // these actions actually output something (that's
1284 : // different from a bitmap)
1285 : case MetaActionType::RASTEROP:
1286 0 : if( static_cast<MetaRasterOpAction*>(pAct)->GetRasterOp() == ROP_OVERPAINT )
1287 0 : break;
1288 : // FALLTHROUGH intended
1289 : case MetaActionType::PIXEL:
1290 : // FALLTHROUGH intended
1291 : case MetaActionType::POINT:
1292 : // FALLTHROUGH intended
1293 : case MetaActionType::LINE:
1294 : // FALLTHROUGH intended
1295 : case MetaActionType::RECT:
1296 : // FALLTHROUGH intended
1297 : case MetaActionType::ROUNDRECT:
1298 : // FALLTHROUGH intended
1299 : case MetaActionType::ELLIPSE:
1300 : // FALLTHROUGH intended
1301 : case MetaActionType::ARC:
1302 : // FALLTHROUGH intended
1303 : case MetaActionType::PIE:
1304 : // FALLTHROUGH intended
1305 : case MetaActionType::CHORD:
1306 : // FALLTHROUGH intended
1307 : case MetaActionType::POLYLINE:
1308 : // FALLTHROUGH intended
1309 : case MetaActionType::POLYGON:
1310 : // FALLTHROUGH intended
1311 : case MetaActionType::POLYPOLYGON:
1312 : // FALLTHROUGH intended
1313 :
1314 : case MetaActionType::TEXT:
1315 : // FALLTHROUGH intended
1316 : case MetaActionType::TEXTARRAY:
1317 : // FALLTHROUGH intended
1318 : case MetaActionType::STRETCHTEXT:
1319 : // FALLTHROUGH intended
1320 : case MetaActionType::TEXTRECT:
1321 : // FALLTHROUGH intended
1322 :
1323 : case MetaActionType::MASK:
1324 : // FALLTHROUGH intended
1325 : case MetaActionType::MASKSCALE:
1326 : // FALLTHROUGH intended
1327 : case MetaActionType::MASKSCALEPART:
1328 : // FALLTHROUGH intended
1329 :
1330 : case MetaActionType::GRADIENT:
1331 : // FALLTHROUGH intended
1332 : case MetaActionType::HATCH:
1333 : // FALLTHROUGH intended
1334 : case MetaActionType::WALLPAPER:
1335 : // FALLTHROUGH intended
1336 :
1337 : case MetaActionType::Transparent:
1338 : // FALLTHROUGH intended
1339 : case MetaActionType::EPS:
1340 : // FALLTHROUGH intended
1341 : case MetaActionType::FLOATTRANSPARENT:
1342 : // FALLTHROUGH intended
1343 : case MetaActionType::GRADIENTEX:
1344 : // FALLTHROUGH intended
1345 :
1346 : // OutDev state changes that _do_ affect bitmap
1347 : // output
1348 : case MetaActionType::CLIPREGION:
1349 : // FALLTHROUGH intended
1350 : case MetaActionType::ISECTRECTCLIPREGION:
1351 : // FALLTHROUGH intended
1352 : case MetaActionType::ISECTREGIONCLIPREGION:
1353 : // FALLTHROUGH intended
1354 : case MetaActionType::MOVECLIPREGION:
1355 : // FALLTHROUGH intended
1356 :
1357 : case MetaActionType::MAPMODE:
1358 : // FALLTHROUGH intended
1359 : case MetaActionType::REFPOINT:
1360 : // FALLTHROUGH intended
1361 : default:
1362 0 : bNonBitmapActionEncountered = true;
1363 0 : break;
1364 : }
1365 0 : if ( pModAct )
1366 : {
1367 0 : MetaAction* pDeleteAction = rOutMtf.ReplaceAction( pModAct, nCurPos );
1368 : assert(pDeleteAction);
1369 0 : pDeleteAction->Delete();
1370 : }
1371 : else
1372 : {
1373 0 : if( pAct->GetRefCount() > 1 )
1374 : {
1375 0 : MetaAction* pDeleteAction = rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos );
1376 : assert(pDeleteAction);
1377 0 : pDeleteAction->Delete();
1378 : }
1379 : else
1380 0 : pModAct = pAct;
1381 : }
1382 0 : pModAct->Scale( fScaleX, fScaleY );
1383 : }
1384 0 : rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ),
1385 0 : FRound( aNewSize.Height() * fScaleY ) ) );
1386 : }
1387 :
1388 0 : if( nNumBitmaps != 1 || bNonBitmapActionEncountered )
1389 : {
1390 0 : if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() )
1391 0 : ImplAdjust( rOutMtf, rAttr, GraphicAdjustmentFlags::ALL );
1392 :
1393 0 : ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr );
1394 0 : rOutBmpEx = BitmapEx();
1395 : }
1396 :
1397 0 : return true;
1398 : }
1399 :
1400 0 : void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags )
1401 : {
1402 0 : GraphicAttr aAttr( rAttr );
1403 :
1404 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1405 : {
1406 0 : switch( aAttr.GetDrawMode() )
1407 : {
1408 : case( GRAPHICDRAWMODE_MONO ):
1409 0 : rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1410 0 : break;
1411 :
1412 : case( GRAPHICDRAWMODE_GREYS ):
1413 0 : rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
1414 0 : break;
1415 :
1416 : case( GRAPHICDRAWMODE_WATERMARK ):
1417 : {
1418 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1419 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1420 : }
1421 0 : break;
1422 :
1423 : default:
1424 0 : break;
1425 : }
1426 : }
1427 :
1428 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() )
1429 : {
1430 0 : rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1431 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1432 0 : aAttr.GetGamma(), aAttr.IsInvert() );
1433 : }
1434 :
1435 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() )
1436 : {
1437 0 : rBmpEx.Mirror( aAttr.GetMirrorFlags() );
1438 : }
1439 :
1440 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() )
1441 : {
1442 0 : rBmpEx.Rotate( aAttr.GetRotation(), Color( COL_TRANSPARENT ) );
1443 : }
1444 :
1445 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() )
1446 : {
1447 0 : AlphaMask aAlpha;
1448 0 : sal_uInt8 cTrans = aAttr.GetTransparency();
1449 :
1450 0 : if( !rBmpEx.IsTransparent() )
1451 0 : aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans );
1452 0 : else if( !rBmpEx.IsAlpha() )
1453 : {
1454 0 : aAlpha = rBmpEx.GetMask();
1455 0 : aAlpha.Replace( 0, cTrans );
1456 : }
1457 : else
1458 : {
1459 0 : aAlpha = rBmpEx.GetAlpha();
1460 0 : BitmapWriteAccess* pA = aAlpha.AcquireWriteAccess();
1461 :
1462 0 : if( pA )
1463 : {
1464 0 : sal_uLong nTrans = cTrans, nNewTrans;
1465 0 : const long nWidth = pA->Width(), nHeight = pA->Height();
1466 :
1467 0 : if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1468 : {
1469 0 : for( long nY = 0; nY < nHeight; nY++ )
1470 : {
1471 0 : Scanline pAScan = pA->GetScanline( nY );
1472 :
1473 0 : for( long nX = 0; nX < nWidth; nX++ )
1474 : {
1475 0 : nNewTrans = nTrans + *pAScan;
1476 0 : *pAScan++ = (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans );
1477 : }
1478 : }
1479 : }
1480 : else
1481 : {
1482 0 : BitmapColor aAlphaValue( 0 );
1483 :
1484 0 : for( long nY = 0; nY < nHeight; nY++ )
1485 : {
1486 0 : for( long nX = 0; nX < nWidth; nX++ )
1487 : {
1488 0 : nNewTrans = nTrans + pA->GetPixel( nY, nX ).GetIndex();
1489 0 : aAlphaValue.SetIndex( (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) );
1490 0 : pA->SetPixel( nY, nX, aAlphaValue );
1491 : }
1492 0 : }
1493 : }
1494 :
1495 0 : aAlpha.ReleaseAccess( pA );
1496 : }
1497 : }
1498 :
1499 0 : rBmpEx = BitmapEx( rBmpEx.GetBitmap(), aAlpha );
1500 0 : }
1501 0 : }
1502 :
1503 0 : void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags )
1504 : {
1505 0 : GraphicAttr aAttr( rAttr );
1506 :
1507 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1508 : {
1509 0 : switch( aAttr.GetDrawMode() )
1510 : {
1511 : case( GRAPHICDRAWMODE_MONO ):
1512 0 : rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD );
1513 0 : break;
1514 :
1515 : case( GRAPHICDRAWMODE_GREYS ):
1516 0 : rMtf.Convert( MTF_CONVERSION_8BIT_GREYS );
1517 0 : break;
1518 :
1519 : case( GRAPHICDRAWMODE_WATERMARK ):
1520 : {
1521 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1522 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1523 : }
1524 0 : break;
1525 :
1526 : default:
1527 0 : break;
1528 : }
1529 : }
1530 :
1531 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() )
1532 : {
1533 0 : rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1534 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1535 0 : aAttr.GetGamma(), aAttr.IsInvert() );
1536 : }
1537 :
1538 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() )
1539 : {
1540 0 : rMtf.Mirror( aAttr.GetMirrorFlags() );
1541 : }
1542 :
1543 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() )
1544 : {
1545 0 : rMtf.Rotate( aAttr.GetRotation() );
1546 : }
1547 :
1548 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() )
1549 : {
1550 : OSL_FAIL( "Missing implementation: Mtf-Transparency" );
1551 0 : }
1552 0 : }
1553 :
1554 0 : void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags )
1555 : {
1556 0 : GraphicAttr aAttr( rAttr );
1557 :
1558 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1559 : {
1560 0 : switch( aAttr.GetDrawMode() )
1561 : {
1562 : case( GRAPHICDRAWMODE_MONO ):
1563 0 : rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1564 0 : break;
1565 :
1566 : case( GRAPHICDRAWMODE_GREYS ):
1567 0 : rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS );
1568 0 : break;
1569 :
1570 : case( GRAPHICDRAWMODE_WATERMARK ):
1571 : {
1572 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1573 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1574 : }
1575 0 : break;
1576 :
1577 : default:
1578 0 : break;
1579 : }
1580 : }
1581 :
1582 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() )
1583 : {
1584 0 : rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1585 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1586 0 : aAttr.GetGamma(), aAttr.IsInvert() );
1587 : }
1588 :
1589 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() )
1590 : {
1591 0 : rAnimation.Mirror( aAttr.GetMirrorFlags() );
1592 : }
1593 :
1594 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() )
1595 : {
1596 : OSL_FAIL( "Missing implementation: Animation-Rotation" );
1597 : }
1598 :
1599 0 : if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() )
1600 : {
1601 : OSL_FAIL( "Missing implementation: Animation-Transparency" );
1602 0 : }
1603 0 : }
1604 :
1605 0 : void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1606 : const GDIMetaFile& rMtf, const GraphicAttr& rAttr )
1607 : {
1608 0 : sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
1609 0 : Point aOutPt( rPt );
1610 0 : Size aOutSz( rSz );
1611 :
1612 0 : if( nRot10 )
1613 : {
1614 0 : Polygon aPoly( Rectangle( aOutPt, aOutSz ) );
1615 :
1616 0 : aPoly.Rotate( aOutPt, nRot10 );
1617 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
1618 0 : aOutPt = aRotBoundRect.TopLeft();
1619 0 : aOutSz = aRotBoundRect.GetSize();
1620 : }
1621 :
1622 0 : pOut->Push( PushFlags::CLIPREGION );
1623 0 : pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) );
1624 :
1625 0 : ( (GDIMetaFile&) rMtf ).WindStart();
1626 0 : ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz );
1627 0 : ( (GDIMetaFile&) rMtf ).WindStart();
1628 :
1629 0 : pOut->Pop();
1630 0 : }
1631 :
1632 : struct ImplTileInfo
1633 : {
1634 0 : ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
1635 :
1636 : Point aTileTopLeft; // top, left position of the rendered tile
1637 : Point aNextTileTopLeft; // top, left position for next recursion
1638 : // level's tile
1639 : Size aTileSizePixel; // size of the generated tile (might
1640 : // differ from
1641 : // aNextTileTopLeft-aTileTopLeft, because
1642 : // this is nExponent*prevTileSize. The
1643 : // generated tile is always nExponent
1644 : // times the previous tile, such that it
1645 : // can be used in the next stage. The
1646 : // required area coverage is often
1647 : // less. The extraneous area covered is
1648 : // later overwritten by the next stage)
1649 : int nTilesEmptyX; // number of original tiles empty right of
1650 : // this tile. This counts from
1651 : // aNextTileTopLeft, i.e. the additional
1652 : // area covered by aTileSizePixel is not
1653 : // considered here. This is for
1654 : // unification purposes, as the iterative
1655 : // calculation of the next level's empty
1656 : // tiles has to be based on this value.
1657 : int nTilesEmptyY; // as above, for Y
1658 : };
1659 :
1660 :
1661 0 : bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent,
1662 : int nNumTilesX, int nNumTilesY,
1663 : const Size& rTileSizePixel,
1664 : const GraphicAttr* pAttr, GraphicManagerDrawFlags nFlags )
1665 : {
1666 0 : if( nExponent <= 1 )
1667 0 : return false;
1668 :
1669 : // determine MSB factor
1670 0 : int nMSBFactor( 1 );
1671 0 : while( nNumTilesX / nMSBFactor != 0 ||
1672 0 : nNumTilesY / nMSBFactor != 0 )
1673 : {
1674 0 : nMSBFactor *= nExponent;
1675 : }
1676 :
1677 : // one less
1678 0 : nMSBFactor /= nExponent;
1679 :
1680 0 : ImplTileInfo aTileInfo;
1681 :
1682 : // #105229# Switch off mapping (converting to logic and back to
1683 : // pixel might cause roundoff errors)
1684 0 : bool bOldMap( rVDev.IsMapModeEnabled() );
1685 0 : rVDev.EnableMapMode( false );
1686 :
1687 : bool bRet( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor, nNumTilesX, nNumTilesY,
1688 0 : nNumTilesX, nNumTilesY, rTileSizePixel, pAttr, nFlags, aTileInfo ) );
1689 :
1690 0 : rVDev.EnableMapMode( bOldMap );
1691 :
1692 0 : return bRet;
1693 : }
1694 :
1695 : // define for debug drawings
1696 : //#define DBG_TEST
1697 :
1698 : // see header comment. this works similar to base conversion of a
1699 : // number, i.e. if the exponent is 10, then the number for every tile
1700 : // size is given by the decimal place of the corresponding decimal
1701 : // representation.
1702 0 : bool GraphicObject::ImplRenderTileRecursive( VirtualDevice& rVDev, int nExponent, int nMSBFactor,
1703 : int nNumOrigTilesX, int nNumOrigTilesY,
1704 : int nRemainderTilesX, int nRemainderTilesY,
1705 : const Size& rTileSizePixel, const GraphicAttr* pAttr,
1706 : GraphicManagerDrawFlags nFlags, ImplTileInfo& rTileInfo )
1707 : {
1708 : // gets loaded with our tile bitmap
1709 0 : GraphicObject aTmpGraphic;
1710 :
1711 : // stores a flag that renders the zero'th tile position
1712 : // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the
1713 : // recursion stack. All other position already have that tile
1714 : // rendered, because the lower levels painted their generated tile
1715 : // there.
1716 0 : bool bNoFirstTileDraw( false );
1717 :
1718 : // what's left when we're done with our tile size
1719 0 : const int nNewRemainderX( nRemainderTilesX % nMSBFactor );
1720 0 : const int nNewRemainderY( nRemainderTilesY % nMSBFactor );
1721 :
1722 : // gets filled out from the recursive call with info of what's
1723 : // been generated
1724 0 : ImplTileInfo aTileInfo;
1725 :
1726 : // current output position while drawing
1727 0 : Point aCurrPos;
1728 : int nX, nY;
1729 :
1730 : // check for recursion's end condition: LSB place reached?
1731 0 : if( nMSBFactor == 1 )
1732 : {
1733 0 : aTmpGraphic = *this;
1734 :
1735 : // set initial tile size -> orig size
1736 0 : aTileInfo.aTileSizePixel = rTileSizePixel;
1737 0 : aTileInfo.nTilesEmptyX = nNumOrigTilesX;
1738 0 : aTileInfo.nTilesEmptyY = nNumOrigTilesY;
1739 : }
1740 0 : else if( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor/nExponent,
1741 : nNumOrigTilesX, nNumOrigTilesY,
1742 : nNewRemainderX, nNewRemainderY,
1743 0 : rTileSizePixel, pAttr, nFlags, aTileInfo ) )
1744 : {
1745 : // extract generated tile -> see comment on the first loop below
1746 0 : BitmapEx aTileBitmap( rVDev.GetBitmap( aTileInfo.aTileTopLeft, aTileInfo.aTileSizePixel ) );
1747 :
1748 0 : aTmpGraphic = GraphicObject( aTileBitmap );
1749 :
1750 : // fill stripes left over from upstream levels:
1751 :
1752 : // x0000
1753 : // 0
1754 : // 0
1755 : // 0
1756 : // 0
1757 :
1758 : // where x denotes the place filled by our recursive predecessors
1759 :
1760 : // check whether we have to fill stripes here. Although not
1761 : // obvious, there is one case where we can skip this step: if
1762 : // the previous recursion level (the one who filled our
1763 : // aTileInfo) had zero area to fill, then there are no white
1764 : // stripes left, naturally. This happens if the digit
1765 : // associated to that level has a zero, and can be checked via
1766 : // aTileTopLeft==aNextTileTopLeft.
1767 0 : if( aTileInfo.aTileTopLeft != aTileInfo.aNextTileTopLeft )
1768 : {
1769 : // now fill one row from aTileInfo.aNextTileTopLeft.X() all
1770 : // the way to the right
1771 0 : aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
1772 0 : aCurrPos.Y() = aTileInfo.aTileTopLeft.Y();
1773 0 : for( nX=0; nX < aTileInfo.nTilesEmptyX; nX += nMSBFactor )
1774 : {
1775 0 : if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1776 0 : return false;
1777 :
1778 0 : aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
1779 : }
1780 :
1781 : #ifdef DBG_TEST
1782 : // rVDev.SetFillColor( COL_WHITE );
1783 : rVDev.SetFillColor();
1784 : rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
1785 : rVDev.DrawEllipse( Rectangle(aTileInfo.aNextTileTopLeft.X(), aTileInfo.aTileTopLeft.Y(),
1786 : aTileInfo.aNextTileTopLeft.X() - 1 + (aTileInfo.nTilesEmptyX/nMSBFactor)*aTileInfo.aTileSizePixel.Width(),
1787 : aTileInfo.aTileTopLeft.Y() + aTileInfo.aTileSizePixel.Height() - 1) );
1788 : #endif
1789 :
1790 : // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
1791 : // the way to the bottom
1792 0 : aCurrPos.X() = aTileInfo.aTileTopLeft.X();
1793 0 : aCurrPos.Y() = aTileInfo.aNextTileTopLeft.Y();
1794 0 : for( nY=0; nY < aTileInfo.nTilesEmptyY; nY += nMSBFactor )
1795 : {
1796 0 : if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1797 0 : return false;
1798 :
1799 0 : aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
1800 : }
1801 :
1802 : #ifdef DBG_TEST
1803 : rVDev.DrawEllipse( Rectangle(aTileInfo.aTileTopLeft.X(), aTileInfo.aNextTileTopLeft.Y(),
1804 : aTileInfo.aTileTopLeft.X() + aTileInfo.aTileSizePixel.Width() - 1,
1805 : aTileInfo.aNextTileTopLeft.Y() - 1 + (aTileInfo.nTilesEmptyY/nMSBFactor)*aTileInfo.aTileSizePixel.Height()) );
1806 : #endif
1807 : }
1808 : else
1809 : {
1810 : // Thought that aTileInfo.aNextTileTopLeft tile has always
1811 : // been drawn already, but that's wrong: typically,
1812 : // _parts_ of that tile have been drawn, since the
1813 : // previous level generated the tile there. But when
1814 : // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the
1815 : // difference between these two values is missing in the
1816 : // lower right corner of this first tile. So, can do that
1817 : // only here.
1818 0 : bNoFirstTileDraw = true;
1819 0 : }
1820 : }
1821 : else
1822 : {
1823 0 : return false;
1824 : }
1825 :
1826 : // calc number of original tiles in our drawing area without
1827 : // remainder
1828 0 : nRemainderTilesX -= nNewRemainderX;
1829 0 : nRemainderTilesY -= nNewRemainderY;
1830 :
1831 : // fill tile info for calling method
1832 0 : rTileInfo.aTileTopLeft = aTileInfo.aNextTileTopLeft;
1833 0 : rTileInfo.aNextTileTopLeft = Point( rTileInfo.aTileTopLeft.X() + rTileSizePixel.Width()*nRemainderTilesX,
1834 0 : rTileInfo.aTileTopLeft.Y() + rTileSizePixel.Height()*nRemainderTilesY );
1835 0 : rTileInfo.aTileSizePixel = Size( rTileSizePixel.Width()*nMSBFactor*nExponent,
1836 0 : rTileSizePixel.Height()*nMSBFactor*nExponent );
1837 0 : rTileInfo.nTilesEmptyX = aTileInfo.nTilesEmptyX - nRemainderTilesX;
1838 0 : rTileInfo.nTilesEmptyY = aTileInfo.nTilesEmptyY - nRemainderTilesY;
1839 :
1840 : // init output position
1841 0 : aCurrPos = aTileInfo.aNextTileTopLeft;
1842 :
1843 : // fill our drawing area. Fill possibly more, to create the next
1844 : // bigger tile size -> see bitmap extraction above. This does no
1845 : // harm, since everything right or below our actual area is
1846 : // overdrawn by our caller. Just in case we're in the last level,
1847 : // we don't draw beyond the right or bottom border.
1848 0 : for( nY=0; nY < aTileInfo.nTilesEmptyY && nY < nExponent*nMSBFactor; nY += nMSBFactor )
1849 : {
1850 0 : aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
1851 :
1852 0 : for( nX=0; nX < aTileInfo.nTilesEmptyX && nX < nExponent*nMSBFactor; nX += nMSBFactor )
1853 : {
1854 0 : if( bNoFirstTileDraw )
1855 0 : bNoFirstTileDraw = false; // don't draw first tile position
1856 0 : else if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1857 0 : return false;
1858 :
1859 0 : aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
1860 : }
1861 :
1862 0 : aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
1863 : }
1864 :
1865 : #ifdef DBG_TEST
1866 : // rVDev.SetFillColor( COL_WHITE );
1867 : rVDev.SetFillColor();
1868 : rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
1869 : rVDev.DrawRect( Rectangle((rTileInfo.aTileTopLeft.X())*rTileSizePixel.Width(),
1870 : (rTileInfo.aTileTopLeft.Y())*rTileSizePixel.Height(),
1871 : (rTileInfo.aNextTileTopLeft.X())*rTileSizePixel.Width()-1,
1872 : (rTileInfo.aNextTileTopLeft.Y())*rTileSizePixel.Height()-1) );
1873 : #endif
1874 :
1875 0 : return true;
1876 : }
1877 :
1878 0 : bool GraphicObject::ImplDrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSizePixel,
1879 : const Size& rOffset, const GraphicAttr* pAttr, GraphicManagerDrawFlags nFlags, int nTileCacheSize1D )
1880 : {
1881 : // how many tiles to generate per recursion step
1882 : enum{ SubdivisionExponent=2 };
1883 :
1884 0 : const MapMode aOutMapMode( pOut->GetMapMode() );
1885 0 : const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
1886 0 : bool bRet( false );
1887 :
1888 : // #i42643# Casting to Int64, to avoid integer overflow for
1889 : // huge-DPI output devices
1890 0 : if( GetGraphic().GetType() == GRAPHIC_BITMAP &&
1891 0 : static_cast<sal_Int64>(rSizePixel.Width()) * rSizePixel.Height() <
1892 0 : static_cast<sal_Int64>(nTileCacheSize1D)*nTileCacheSize1D )
1893 : {
1894 : // First combine very small bitmaps into a larger tile
1895 :
1896 :
1897 0 : ScopedVclPtrInstance< VirtualDevice > aVDev;
1898 0 : const int nNumTilesInCacheX( (nTileCacheSize1D + rSizePixel.Width()-1) / rSizePixel.Width() );
1899 0 : const int nNumTilesInCacheY( (nTileCacheSize1D + rSizePixel.Height()-1) / rSizePixel.Height() );
1900 :
1901 0 : aVDev->SetOutputSizePixel( Size( nNumTilesInCacheX*rSizePixel.Width(),
1902 0 : nNumTilesInCacheY*rSizePixel.Height() ) );
1903 0 : aVDev->SetMapMode( aMapMode );
1904 :
1905 : // draw bitmap content
1906 0 : if( ImplRenderTempTile( *aVDev.get(), SubdivisionExponent, nNumTilesInCacheX,
1907 : nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
1908 : {
1909 0 : BitmapEx aTileBitmap( aVDev->GetBitmap( Point(0,0), aVDev->GetOutputSize() ) );
1910 :
1911 : // draw alpha content, if any
1912 0 : if( IsTransparent() )
1913 : {
1914 0 : GraphicObject aAlphaGraphic;
1915 :
1916 0 : if( GetGraphic().IsAlpha() )
1917 0 : aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
1918 : else
1919 0 : aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
1920 :
1921 0 : if( aAlphaGraphic.ImplRenderTempTile( *aVDev.get(), SubdivisionExponent, nNumTilesInCacheX,
1922 : nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
1923 : {
1924 : // Combine bitmap and alpha/mask
1925 0 : if( GetGraphic().IsAlpha() )
1926 0 : aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
1927 0 : AlphaMask( aVDev->GetBitmap( Point(0,0), aVDev->GetOutputSize() ) ) );
1928 : else
1929 0 : aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
1930 0 : aVDev->GetBitmap( Point(0,0), aVDev->GetOutputSize() ).CreateMask( Color(COL_WHITE) ) );
1931 0 : }
1932 : }
1933 :
1934 : // paint generated tile
1935 0 : GraphicObject aTmpGraphic( aTileBitmap );
1936 : bRet = aTmpGraphic.ImplDrawTiled( pOut, rArea,
1937 0 : aTileBitmap.GetSizePixel(),
1938 0 : rOffset, pAttr, nFlags, nTileCacheSize1D );
1939 0 : }
1940 : }
1941 : else
1942 : {
1943 0 : const Size aOutOffset( pOut->LogicToPixel( rOffset, aOutMapMode ) );
1944 0 : const Rectangle aOutArea( pOut->LogicToPixel( rArea, aOutMapMode ) );
1945 :
1946 : // number of invisible (because out-of-area) tiles
1947 : int nInvisibleTilesX;
1948 : int nInvisibleTilesY;
1949 :
1950 : // round towards -infty for negative offset
1951 0 : if( aOutOffset.Width() < 0 )
1952 0 : nInvisibleTilesX = (aOutOffset.Width() - rSizePixel.Width() + 1) / rSizePixel.Width();
1953 : else
1954 0 : nInvisibleTilesX = aOutOffset.Width() / rSizePixel.Width();
1955 :
1956 : // round towards -infty for negative offset
1957 0 : if( aOutOffset.Height() < 0 )
1958 0 : nInvisibleTilesY = (aOutOffset.Height() - rSizePixel.Height() + 1) / rSizePixel.Height();
1959 : else
1960 0 : nInvisibleTilesY = aOutOffset.Height() / rSizePixel.Height();
1961 :
1962 : // origin from where to 'virtually' start drawing in pixel
1963 0 : const Point aOutOrigin( pOut->LogicToPixel( Point( rArea.Left() - rOffset.Width(),
1964 0 : rArea.Top() - rOffset.Height() ) ) );
1965 : // position in pixel from where to really start output
1966 0 : const Point aOutStart( aOutOrigin.X() + nInvisibleTilesX*rSizePixel.Width(),
1967 0 : aOutOrigin.Y() + nInvisibleTilesY*rSizePixel.Height() );
1968 :
1969 0 : pOut->Push( PushFlags::CLIPREGION );
1970 0 : pOut->IntersectClipRegion( rArea );
1971 :
1972 : // Paint all tiles
1973 :
1974 :
1975 : bRet = ImplDrawTiled( *pOut, aOutStart,
1976 0 : (aOutArea.GetWidth() + aOutArea.Left() - aOutStart.X() + rSizePixel.Width() - 1) / rSizePixel.Width(),
1977 0 : (aOutArea.GetHeight() + aOutArea.Top() - aOutStart.Y() + rSizePixel.Height() - 1) / rSizePixel.Height(),
1978 0 : rSizePixel, pAttr, nFlags );
1979 :
1980 0 : pOut->Pop();
1981 : }
1982 :
1983 0 : return bRet;
1984 : }
1985 :
1986 0 : bool GraphicObject::ImplDrawTiled( OutputDevice& rOut, const Point& rPosPixel,
1987 : int nNumTilesX, int nNumTilesY,
1988 : const Size& rTileSizePixel, const GraphicAttr* pAttr, GraphicManagerDrawFlags nFlags )
1989 : {
1990 0 : Point aCurrPos( rPosPixel );
1991 0 : Size aTileSizeLogic( rOut.PixelToLogic( rTileSizePixel ) );
1992 : int nX, nY;
1993 :
1994 : // #107607# Use logical coordinates for metafile playing, too
1995 0 : bool bDrawInPixel( rOut.GetConnectMetaFile() == NULL && GRAPHIC_BITMAP == GetType() );
1996 0 : bool bRet = false;
1997 :
1998 : // #105229# Switch off mapping (converting to logic and back to
1999 : // pixel might cause roundoff errors)
2000 0 : bool bOldMap( rOut.IsMapModeEnabled() );
2001 :
2002 0 : if( bDrawInPixel )
2003 0 : rOut.EnableMapMode( false );
2004 :
2005 0 : for( nY=0; nY < nNumTilesY; ++nY )
2006 : {
2007 0 : aCurrPos.X() = rPosPixel.X();
2008 :
2009 0 : for( nX=0; nX < nNumTilesX; ++nX )
2010 : {
2011 : // #105229# work with pixel coordinates here, mapping is disabled!
2012 : // #104004# don't disable mapping for metafile recordings
2013 : // #108412# don't quit the loop if one draw fails
2014 :
2015 : // update return value. This method should return true, if
2016 : // at least one of the looped Draws succeeded.
2017 : bRet |= Draw( &rOut,
2018 : bDrawInPixel ? aCurrPos : rOut.PixelToLogic( aCurrPos ),
2019 : bDrawInPixel ? rTileSizePixel : aTileSizeLogic,
2020 0 : pAttr, nFlags );
2021 :
2022 0 : aCurrPos.X() += rTileSizePixel.Width();
2023 : }
2024 :
2025 0 : aCurrPos.Y() += rTileSizePixel.Height();
2026 : }
2027 :
2028 0 : if( bDrawInPixel )
2029 0 : rOut.EnableMapMode( bOldMap );
2030 :
2031 0 : return bRet;
2032 : }
2033 :
2034 0 : void GraphicObject::ImplTransformBitmap( BitmapEx& rBmpEx,
2035 : const GraphicAttr& rAttr,
2036 : const Size& rCropLeftTop,
2037 : const Size& rCropRightBottom,
2038 : const Rectangle& rCropRect,
2039 : const Size& rDstSize,
2040 : bool bEnlarge ) const
2041 : {
2042 : // #107947# Extracted from svdograf.cxx
2043 :
2044 : // #104115# Crop the bitmap
2045 0 : if( rAttr.IsCropped() )
2046 : {
2047 0 : rBmpEx.Crop( rCropRect );
2048 :
2049 : // #104115# Negative crop sizes mean: enlarge bitmap and pad
2050 0 : if( bEnlarge && (
2051 0 : rCropLeftTop.Width() < 0 ||
2052 0 : rCropLeftTop.Height() < 0 ||
2053 0 : rCropRightBottom.Width() < 0 ||
2054 0 : rCropRightBottom.Height() < 0 ) )
2055 : {
2056 0 : Size aBmpSize( rBmpEx.GetSizePixel() );
2057 0 : sal_Int32 nPadLeft( rCropLeftTop.Width() < 0 ? -rCropLeftTop.Width() : 0 );
2058 0 : sal_Int32 nPadTop( rCropLeftTop.Height() < 0 ? -rCropLeftTop.Height() : 0 );
2059 0 : sal_Int32 nPadTotalWidth( aBmpSize.Width() + nPadLeft + (rCropRightBottom.Width() < 0 ? -rCropRightBottom.Width() : 0) );
2060 0 : sal_Int32 nPadTotalHeight( aBmpSize.Height() + nPadTop + (rCropRightBottom.Height() < 0 ? -rCropRightBottom.Height() : 0) );
2061 :
2062 0 : BitmapEx aBmpEx2;
2063 :
2064 0 : if( rBmpEx.IsTransparent() )
2065 : {
2066 0 : if( rBmpEx.IsAlpha() )
2067 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetAlpha() );
2068 : else
2069 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetMask() );
2070 : }
2071 : else
2072 : {
2073 : // #104115# Generate mask bitmap and init to zero
2074 0 : Bitmap aMask( aBmpSize, 1 );
2075 0 : aMask.Erase( Color(0,0,0) );
2076 :
2077 : // #104115# Always generate transparent bitmap, we need the border transparent
2078 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask );
2079 :
2080 : // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
2081 0 : rBmpEx = aBmpEx2;
2082 : }
2083 :
2084 0 : aBmpEx2.SetSizePixel( Size(nPadTotalWidth, nPadTotalHeight) );
2085 0 : aBmpEx2.Erase( Color(0xFF,0,0,0) );
2086 0 : aBmpEx2.CopyPixel( Rectangle( Point(nPadLeft, nPadTop), aBmpSize ), Rectangle( Point(0, 0), aBmpSize ), &rBmpEx );
2087 0 : rBmpEx = aBmpEx2;
2088 : }
2089 : }
2090 :
2091 0 : const Size aSizePixel( rBmpEx.GetSizePixel() );
2092 :
2093 0 : if( rAttr.GetRotation() != 0 && !IsAnimated() )
2094 : {
2095 0 : if( aSizePixel.Width() && aSizePixel.Height() && rDstSize.Width() && rDstSize.Height() )
2096 : {
2097 0 : double fSrcWH = (double) aSizePixel.Width() / aSizePixel.Height();
2098 0 : double fDstWH = (double) rDstSize.Width() / rDstSize.Height();
2099 0 : double fScaleX = 1.0, fScaleY = 1.0;
2100 :
2101 : // always choose scaling to shrink bitmap
2102 0 : if( fSrcWH < fDstWH )
2103 0 : fScaleY = aSizePixel.Width() / ( fDstWH * aSizePixel.Height() );
2104 : else
2105 0 : fScaleX = fDstWH * aSizePixel.Height() / aSizePixel.Width();
2106 :
2107 0 : rBmpEx.Scale( fScaleX, fScaleY );
2108 : }
2109 : }
2110 0 : }
2111 :
2112 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|