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