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