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