1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/bmpacc.hxx>
21 #include <tools/poly.hxx>
22 #include <vcl/outdev.hxx>
23 #include <vcl/window.hxx>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/metaact.hxx>
26 #include <vcl/metric.hxx>
27 #include <vcl/animate.hxx>
28 #include <vcl/alpha.hxx>
29 #include <vcl/virdev.hxx>
30 #include "grfcache.hxx"
31 #include <svtools/grfmgr.hxx>
37 #define WATERMARK_LUM_OFFSET 50
38 #define WATERMARK_CON_OFFSET -70
39 #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L))
45 GraphicManager::GraphicManager( sal_uLong nCacheSize
, sal_uLong nMaxObjCacheSize
) :
46 mpCache( new GraphicCache( nCacheSize
, nMaxObjCacheSize
) )
50 GraphicManager::~GraphicManager()
52 for( size_t i
= 0, n
= maObjList
.size(); i
< n
; ++i
)
53 maObjList
[ i
]->GraphicManagerDestroyed();
58 void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize
)
60 mpCache
->SetMaxDisplayCacheSize( nNewCacheSize
);
63 void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize
, sal_Bool bDestroyGreaterCached
)
65 mpCache
->SetMaxObjDisplayCacheSize( nNewMaxObjSize
, bDestroyGreaterCached
);
68 void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds
)
70 mpCache
->SetCacheTimeout( nTimeoutSeconds
);
73 void GraphicManager::ReleaseFromCache( const GraphicObject
& /*rObj*/ )
78 sal_Bool
GraphicManager::IsInCache( OutputDevice
* pOut
, const Point
& rPt
,
79 const Size
& rSz
, const GraphicObject
& rObj
,
80 const GraphicAttr
& rAttr
) const
82 return mpCache
->IsInDisplayCache( pOut
, rPt
, rSz
, rObj
, rAttr
);
85 sal_Bool
GraphicManager::DrawObj( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
86 GraphicObject
& rObj
, const GraphicAttr
& rAttr
,
87 const sal_uLong nFlags
, sal_Bool
& rCached
)
91 sal_Bool bRet
= sal_False
;
95 if( ( rObj
.GetType() == GRAPHIC_BITMAP
) || ( rObj
.GetType() == GRAPHIC_GDIMETAFILE
) )
97 // create output and fill cache
99 if( rObj
.IsAnimated() || ( pOut
->GetOutDevType() == OUTDEV_PRINTER
) ||
100 ( !( nFlags
& GRFMGR_DRAW_NO_SUBSTITUTE
) &&
101 ( ( nFlags
& GRFMGR_DRAW_SUBSTITUTE
) ||
102 !( nFlags
& GRFMGR_DRAW_CACHED
) ||
103 ( pOut
->GetConnectMetaFile() && !pOut
->IsOutputEnabled() ) ) ) )
105 // simple output of transformed graphic
106 const Graphic
aGraphic( rObj
.GetTransformedGraphic( &rAttr
) );
108 if( aGraphic
.IsSupportedGraphic() )
110 const sal_uInt16 nRot10
= rAttr
.GetRotation() % 3600;
114 Polygon
aPoly( Rectangle( aPt
, aSz
) );
116 aPoly
.Rotate( aPt
, nRot10
);
117 const Rectangle
aRotBoundRect( aPoly
.GetBoundRect() );
118 aPt
= aRotBoundRect
.TopLeft();
119 aSz
= aRotBoundRect
.GetSize();
122 aGraphic
.Draw( pOut
, aPt
, aSz
);
130 // cached/direct drawing
131 if( !mpCache
->DrawDisplayCacheObj( pOut
, aPt
, aSz
, rObj
, rAttr
) )
132 bRet
= ImplDraw( pOut
, aPt
, aSz
, rObj
, rAttr
, nFlags
, rCached
);
134 bRet
= rCached
= sal_True
;
141 void GraphicManager::ImplRegisterObj( const GraphicObject
& rObj
, Graphic
& rSubstitute
,
142 const OString
* pID
, const GraphicObject
* pCopyObj
)
144 maObjList
.push_back( (GraphicObject
*)&rObj
);
145 mpCache
->AddGraphicObject( rObj
, rSubstitute
, pID
, pCopyObj
);
148 void GraphicManager::ImplUnregisterObj( const GraphicObject
& rObj
)
150 mpCache
->ReleaseGraphicObject( rObj
);
151 for( GraphicObjectList_impl::iterator it
= maObjList
.begin(); it
!= maObjList
.end(); ++it
)
153 if ( *it
== &rObj
) {
154 maObjList
.erase( it
);
160 void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject
& rObj
)
162 mpCache
->GraphicObjectWasSwappedOut( rObj
);
165 OString
GraphicManager::ImplGetUniqueID( const GraphicObject
& rObj
) const
167 return mpCache
->GetUniqueID( rObj
);
170 sal_Bool
GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject
& rObj
, Graphic
& rSubstitute
)
172 return( mpCache
->FillSwappedGraphicObject( rObj
, rSubstitute
) );
175 void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject
& rObj
)
177 mpCache
->GraphicObjectWasSwappedIn( rObj
);
180 sal_Bool
GraphicManager::ImplDraw( OutputDevice
* pOut
, const Point
& rPt
,
181 const Size
& rSz
, GraphicObject
& rObj
,
182 const GraphicAttr
& rAttr
,
183 const sal_uLong nFlags
, sal_Bool
& rCached
)
185 const Graphic
& rGraphic
= rObj
.GetGraphic();
186 sal_Bool bRet
= sal_False
;
188 if( rGraphic
.IsSupportedGraphic() && !rGraphic
.IsSwapOut() )
190 if( GRAPHIC_BITMAP
== rGraphic
.GetType() )
192 const BitmapEx
aSrcBmpEx( rGraphic
.GetBitmapEx() );
194 // #i46805# No point in caching a bitmap that is rendered
195 // via RectFill on the OutDev
196 if( !(pOut
->GetDrawMode() & ( DRAWMODE_BLACKBITMAP
| DRAWMODE_WHITEBITMAP
)) &&
197 mpCache
->IsDisplayCacheable( pOut
, rPt
, rSz
, rObj
, rAttr
) )
201 if( ImplCreateOutput( pOut
, rPt
, rSz
, aSrcBmpEx
, rAttr
, nFlags
, &aDstBmpEx
) )
203 rCached
= mpCache
->CreateDisplayCacheObj( pOut
, rPt
, rSz
, rObj
, rAttr
, aDstBmpEx
);
209 bRet
= ImplCreateOutput( pOut
, rPt
, rSz
, aSrcBmpEx
, rAttr
, nFlags
);
213 const GDIMetaFile
& rSrcMtf
= rGraphic
.GetGDIMetaFile();
215 if( mpCache
->IsDisplayCacheable( pOut
, rPt
, rSz
, rObj
, rAttr
) )
218 BitmapEx aContainedBmpEx
;
220 if( ImplCreateOutput( pOut
, rPt
, rSz
, rSrcMtf
, rAttr
, nFlags
, aDstMtf
, aContainedBmpEx
) )
222 if( !!aContainedBmpEx
)
224 // Use bitmap output method, if metafile basically contains only a single
225 // bitmap (allows caching the resulting pixmap).
228 if( ImplCreateOutput( pOut
, rPt
, rSz
, aContainedBmpEx
, rAttr
, nFlags
, &aDstBmpEx
) )
230 rCached
= mpCache
->CreateDisplayCacheObj( pOut
, rPt
, rSz
, rObj
, rAttr
, aDstBmpEx
);
236 rCached
= mpCache
->CreateDisplayCacheObj( pOut
, rPt
, rSz
, rObj
, rAttr
, aDstMtf
);
244 const Graphic
aGraphic( rObj
.GetTransformedGraphic( &rAttr
) );
246 if( aGraphic
.IsSupportedGraphic() )
248 aGraphic
.Draw( pOut
, rPt
, rSz
);
258 sal_Bool
ImplCreateRotatedScaled( const BitmapEx
& rBmpEx
, const GraphicAttr
& rAttributes
,
259 sal_uInt16 nRot10
, const Size
& rUnrotatedSzPix
,
260 long nStartX
, long nEndX
, long nStartY
, long nEndY
,
261 BitmapEx
& rOutBmpEx
)
263 const long aUnrotatedWidth
= rUnrotatedSzPix
.Width();
264 const long aUnrotatedHeight
= rUnrotatedSzPix
.Height();
265 const long aBitmapWidth
= rBmpEx
.GetSizePixel().Width();
266 const long aBitmapHeight
= rBmpEx
.GetSizePixel().Height();
268 long nX
, nY
, nTmpX
, nTmpY
, nTmpFX
, nTmpFY
, nTmp
;
271 bool bHMirr
= ( rAttributes
.GetMirrorFlags() & BMP_MIRROR_HORZ
) != 0;
272 bool bVMirr
= ( rAttributes
.GetMirrorFlags() & BMP_MIRROR_VERT
) != 0;
274 long* pMapIX
= new long[ aUnrotatedWidth
];
275 long* pMapFX
= new long[ aUnrotatedWidth
];
276 long* pMapIY
= new long[ aUnrotatedHeight
];
277 long* pMapFY
= new long[ aUnrotatedHeight
];
282 bool scaleByAveraging
= false;
285 if(aBitmapWidth
> 1 && aUnrotatedWidth
> 1)
287 fRevScaleX
= (double) ( aBitmapWidth
- 1 ) / (double)( aUnrotatedWidth
- 1 );
288 // create horizontal mapping table
289 for( x
= 0, nTmpX
= aBitmapWidth
- 1L, nTmp
= aBitmapWidth
- 2L >= 0 ? aBitmapWidth
-2L : 0L; x
< aUnrotatedWidth
; x
++ )
291 fTmp
= x
* fRevScaleX
;
296 pMapIX
[ x
] = MinMax( fTmp
, 0, nTmp
);
297 pMapFX
[ x
] = (long) ( ( fTmp
- pMapIX
[ x
] ) * 1048576.0 );
299 scaleByAveraging
|= fRevScaleX
> 5.0/3.0;
303 if(aBitmapWidth
== 1)
305 fRevScaleX
= 1.0 / (double)( aUnrotatedWidth
);
306 for ( x
= 0; x
< aUnrotatedWidth
; x
++)
311 scaleByAveraging
= true;
315 fRevScaleX
= (double) aBitmapWidth
/ (double)( aUnrotatedWidth
);
316 fTmp
= (double)aBitmapWidth
/ 2.0;
318 pMapIX
[ 0 ] = (long)fTmp
;
319 pMapFX
[ 0 ] = (long)( ( fTmp
- pMapIX
[ 0 ] ) * 1048576.0 );
320 scaleByAveraging
= true;
323 if(aBitmapHeight
> 1 && aUnrotatedHeight
> 1)
325 fRevScaleY
= (double) ( aBitmapHeight
- 1 ) / (double)( aUnrotatedHeight
- 1 );
326 // create vertical mapping table
327 for( y
= 0, nTmpY
= aBitmapHeight
- 1L, nTmp
= aBitmapHeight
- 2L >= 0 ? aBitmapHeight
- 2L : 0L; y
< aUnrotatedHeight
; y
++ )
329 fTmp
= y
* fRevScaleY
;
334 pMapIY
[ y
] = MinMax( fTmp
, 0, nTmp
);
335 pMapFY
[ y
] = (long) ( ( fTmp
- pMapIY
[ y
] ) * 1048576.0 );
337 scaleByAveraging
|= fRevScaleY
> 5.0/3.0;
341 if(aBitmapHeight
== 1)
343 fRevScaleY
= 1.0 / (double)( aUnrotatedHeight
);
344 for (y
= 0; y
< aUnrotatedHeight
; ++y
)
349 scaleByAveraging
= true;
353 fRevScaleY
= (double) aBitmapHeight
/ (double)( aUnrotatedHeight
);
354 fTmp
= (double)aBitmapHeight
/ 2.0;
356 pMapIY
[ 0 ] = (long)fTmp
;
357 pMapFY
[ 0 ] = (long)( ( fTmp
- pMapIY
[ 0 ] ) * 1048576.0 );
358 scaleByAveraging
= true;
362 Bitmap
aBmp( rBmpEx
.GetBitmap() );
364 BitmapReadAccess
* pReadAccess
= aBmp
.AcquireReadAccess();
365 BitmapWriteAccess
* pWriteAccess
;
367 const double fCosAngle
= cos( nRot10
* F_PI1800
);
368 const double fSinAngle
= sin( nRot10
* F_PI1800
);
369 const long aTargetWidth
= nEndX
- nStartX
+ 1L;
370 const long aTargetHeight
= nEndY
- nStartY
+ 1L;
371 long* pCosX
= new long[ aTargetWidth
];
372 long* pSinX
= new long[ aTargetWidth
];
373 long* pCosY
= new long[ aTargetHeight
];
374 long* pSinY
= new long[ aTargetHeight
];
375 long nUnRotX
, nUnRotY
, nSinY
, nCosY
;
376 sal_uInt8 cR0
, cG0
, cB0
, cR1
, cG1
, cB1
;
379 Polygon
aPoly( Rectangle( Point(), rUnrotatedSzPix
) );
380 aPoly
.Rotate( Point(), nRot10
);
381 Rectangle
aNewBound( aPoly
.GetBoundRect() );
383 // create horizontal mapping table
384 for( x
= 0, nTmpX
= aNewBound
.Left() + nStartX
; x
< aTargetWidth
; x
++ )
386 pCosX
[ x
] = FRound( fCosAngle
* ( fTmp
= nTmpX
++ << 8 ) );
387 pSinX
[ x
] = FRound( fSinAngle
* fTmp
);
390 // create vertical mapping table
391 for( y
= 0, nTmpY
= aNewBound
.Top() + nStartY
; y
< aTargetHeight
; y
++ )
393 pCosY
[ y
] = FRound( fCosAngle
* ( fTmp
= nTmpY
++ << 8 ) );
394 pSinY
[ y
] = FRound( fSinAngle
* fTmp
);
399 aOutBmp
= Bitmap( Size( aTargetWidth
, aTargetHeight
), 24 );
400 pWriteAccess
= aOutBmp
.AcquireWriteAccess();
406 if ( !scaleByAveraging
)
408 if( pReadAccess
->HasPalette() )
410 for( y
= 0; y
< aTargetHeight
; y
++ )
415 for( x
= 0; x
< aTargetWidth
; x
++ )
417 nUnRotX
= ( pCosX
[ x
] - nSinY
) >> 8;
418 nUnRotY
= ( pSinX
[ x
] + nCosY
) >> 8;
420 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< aUnrotatedWidth
) &&
421 ( nUnRotY
>= 0L ) && ( nUnRotY
< aUnrotatedHeight
) )
423 nTmpX
= pMapIX
[ nUnRotX
]; nTmpFX
= pMapFX
[ nUnRotX
];
424 nTmpY
= pMapIY
[ nUnRotY
], nTmpFY
= pMapFY
[ nUnRotY
];
426 const BitmapColor
& rCol0
= pReadAccess
->GetPaletteColor( pReadAccess
->GetPixelIndex( nTmpY
, nTmpX
) );
427 const BitmapColor
& rCol1
= pReadAccess
->GetPaletteColor( pReadAccess
->GetPixelIndex( nTmpY
, ++nTmpX
) );
428 cR0
= MAP( rCol0
.GetRed(), rCol1
.GetRed(), nTmpFX
);
429 cG0
= MAP( rCol0
.GetGreen(), rCol1
.GetGreen(), nTmpFX
);
430 cB0
= MAP( rCol0
.GetBlue(), rCol1
.GetBlue(), nTmpFX
);
432 const BitmapColor
& rCol3
= pReadAccess
->GetPaletteColor( pReadAccess
->GetPixelIndex( ++nTmpY
, nTmpX
) );
433 const BitmapColor
& rCol2
= pReadAccess
->GetPaletteColor( pReadAccess
->GetPixelIndex( nTmpY
, --nTmpX
) );
434 cR1
= MAP( rCol2
.GetRed(), rCol3
.GetRed(), nTmpFX
);
435 cG1
= MAP( rCol2
.GetGreen(), rCol3
.GetGreen(), nTmpFX
);
436 cB1
= MAP( rCol2
.GetBlue(), rCol3
.GetBlue(), nTmpFX
);
438 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
439 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
440 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
441 pWriteAccess
->SetPixel( y
, x
, aColRes
);
448 BitmapColor aCol0
, aCol1
;
450 for( y
= 0; y
< aTargetHeight
; y
++ )
455 for( x
= 0; x
< aTargetWidth
; x
++ )
457 nUnRotX
= ( pCosX
[ x
] - nSinY
) >> 8;
458 nUnRotY
= ( pSinX
[ x
] + nCosY
) >> 8;
460 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< aUnrotatedWidth
) &&
461 ( nUnRotY
>= 0L ) && ( nUnRotY
< aUnrotatedHeight
) )
463 nTmpX
= pMapIX
[ nUnRotX
]; nTmpFX
= pMapFX
[ nUnRotX
];
464 nTmpY
= pMapIY
[ nUnRotY
], nTmpFY
= pMapFY
[ nUnRotY
];
466 aCol0
= pReadAccess
->GetPixel( nTmpY
, nTmpX
);
467 aCol1
= pReadAccess
->GetPixel( nTmpY
, ++nTmpX
);
468 cR0
= MAP( aCol0
.GetRed(), aCol1
.GetRed(), nTmpFX
);
469 cG0
= MAP( aCol0
.GetGreen(), aCol1
.GetGreen(), nTmpFX
);
470 cB0
= MAP( aCol0
.GetBlue(), aCol1
.GetBlue(), nTmpFX
);
472 aCol1
= pReadAccess
->GetPixel( ++nTmpY
, nTmpX
);
473 aCol0
= pReadAccess
->GetPixel( nTmpY
, --nTmpX
);
474 cR1
= MAP( aCol0
.GetRed(), aCol1
.GetRed(), nTmpFX
);
475 cG1
= MAP( aCol0
.GetGreen(), aCol1
.GetGreen(), nTmpFX
);
476 cB1
= MAP( aCol0
.GetBlue(), aCol1
.GetBlue(), nTmpFX
);
478 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
479 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
480 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
481 pWriteAccess
->SetPixel( y
, x
, aColRes
);
487 else // scaleByAveraging
489 double aSumRed
, aSumGreen
, aSumBlue
, aCount
;
491 BitmapColor aResultColor
;
493 for( y
= 0; y
< aTargetHeight
; y
++ )
498 for( x
= 0; x
< aTargetWidth
; x
++ )
500 double aUnrotatedX
= ( pCosX
[ x
] - nSinY
) / 256.0;
501 double aUnrotatedY
= ( pSinX
[ x
] + nCosY
) / 256.0;
504 aUnrotatedX
= aUnrotatedWidth
- aUnrotatedX
- 1;
506 aUnrotatedY
= aUnrotatedHeight
- aUnrotatedY
- 1;
508 if( ( aUnrotatedX
>= 0 ) && ( aUnrotatedX
< aUnrotatedWidth
) &&
509 ( aUnrotatedY
>= 0 ) && ( aUnrotatedY
< aUnrotatedHeight
) )
511 double dYStart
= ((aUnrotatedY
+ 0.5) * fRevScaleY
) - 0.5;
512 double dYEnd
= ((aUnrotatedY
+ 1.5) * fRevScaleY
) - 0.5;
514 int yStart
= MinMax( dYStart
, 0, aBitmapHeight
- 1);
515 int yEnd
= MinMax( dYEnd
, 0, aBitmapHeight
- 1);
517 double dXStart
= ((aUnrotatedX
+ 0.5) * fRevScaleX
) - 0.5;
518 double dXEnd
= ((aUnrotatedX
+ 1.5) * fRevScaleX
) - 0.5;
520 int xStart
= MinMax( dXStart
, 0, aBitmapWidth
- 1);
521 int xEnd
= MinMax( dXEnd
, 0, aBitmapWidth
- 1);
523 aSumRed
= aSumGreen
= aSumBlue
= 0.0;
526 for (int yIn
= yStart
; yIn
<= yEnd
; yIn
++)
528 for (int xIn
= xStart
; xIn
<= xEnd
; xIn
++)
530 if( pReadAccess
->HasPalette() )
531 aColor
= pReadAccess
->GetPaletteColor( pReadAccess
->GetPixelIndex( yIn
, xIn
) );
533 aColor
= pReadAccess
->GetPixel( yIn
, xIn
);
535 aSumRed
+= aColor
.GetRed();
536 aSumGreen
+= aColor
.GetGreen();
537 aSumBlue
+= aColor
.GetBlue();
543 aResultColor
.SetRed( MinMax( aSumRed
/ aCount
, 0, 255) );
544 aResultColor
.SetGreen( MinMax( aSumGreen
/ aCount
, 0, 255) );
545 aResultColor
.SetBlue( MinMax( aSumBlue
/ aCount
, 0, 255) );
547 pWriteAccess
->SetPixel( y
, x
, aResultColor
);
553 aOutBmp
.ReleaseAccess( pWriteAccess
);
557 aBmp
.ReleaseAccess( pReadAccess
);
561 if( bRet
&& ( rBmpEx
.IsTransparent() || ( nRot10
!= 0 && nRot10
!= 900 && nRot10
!= 1800 && nRot10
!= 2700 ) ) )
565 if( rBmpEx
.IsAlpha() )
567 AlphaMask
aAlpha( rBmpEx
.GetAlpha() );
570 pReadAccess
= aAlpha
.AcquireReadAccess();
574 aOutAlpha
= AlphaMask( Size( aTargetWidth
, aTargetHeight
) );
575 pWriteAccess
= aOutAlpha
.AcquireWriteAccess();
579 if( pReadAccess
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
&&
580 pWriteAccess
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
582 if ( !scaleByAveraging
)
584 Scanline pLine0
, pLine1
, pLineW
;
586 for( nY
= 0; nY
< aTargetHeight
; nY
++ )
588 nSinY
= pSinY
[ nY
], nCosY
= pCosY
[ nY
];
589 pLineW
= pWriteAccess
->GetScanline( nY
);
591 for( nX
= 0; nX
< aTargetWidth
; nX
++ )
593 nUnRotX
= ( pCosX
[ nX
] - nSinY
) >> 8;
594 nUnRotY
= ( pSinX
[ nX
] + nCosY
) >> 8;
596 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< aUnrotatedWidth
) &&
597 ( nUnRotY
>= 0L ) && ( nUnRotY
< aUnrotatedHeight
) )
599 nTmpX
= pMapIX
[ nUnRotX
], nTmpFX
= pMapFX
[ nUnRotX
];
600 nTmpY
= pMapIY
[ nUnRotY
], nTmpFY
= pMapFY
[ nUnRotY
];
602 pLine0
= pReadAccess
->GetScanline( nTmpY
++ );
603 pLine1
= pReadAccess
->GetScanline( nTmpY
);
605 const long nAlpha0
= pLine0
[ nTmpX
];
606 const long nAlpha2
= pLine1
[ nTmpX
++ ];
607 const long nAlpha1
= pLine0
[ nTmpX
];
608 const long nAlpha3
= pLine1
[ nTmpX
];
609 const long n0
= MAP( nAlpha0
, nAlpha1
, nTmpFX
);
610 const long n1
= MAP( nAlpha2
, nAlpha3
, nTmpFX
);
612 *pLineW
++ = MAP( n0
, n1
, nTmpFY
);
619 else // scaleByAveraging
621 const BitmapColor
aTrans( pWriteAccess
->GetBestMatchingColor( Color( COL_WHITE
) ) );
622 BitmapColor
aResultColor( 0 );
625 for( y
= 0; y
< aTargetHeight
; y
++ )
630 for( x
= 0; x
< aTargetWidth
; x
++ )
633 double aUnrotatedX
= ( pCosX
[ x
] - nSinY
) / 256.0;
634 double aUnrotatedY
= ( pSinX
[ x
] + nCosY
) / 256.0;
637 aUnrotatedX
= aUnrotatedWidth
- aUnrotatedX
- 1;
639 aUnrotatedY
= aUnrotatedHeight
- aUnrotatedY
- 1;
641 if( ( aUnrotatedX
>= 0 ) && ( aUnrotatedX
< aUnrotatedWidth
) &&
642 ( aUnrotatedY
>= 0 ) && ( aUnrotatedY
< aUnrotatedHeight
) )
644 double dYStart
= ((aUnrotatedY
+ 0.5) * fRevScaleY
) - 0.5;
645 double dYEnd
= ((aUnrotatedY
+ 1.5) * fRevScaleY
) - 0.5;
647 int yStart
= MinMax( dYStart
, 0, aBitmapHeight
- 1);
648 int yEnd
= MinMax( dYEnd
, 0, aBitmapHeight
- 1);
650 double dXStart
= ((aUnrotatedX
+ 0.5) * fRevScaleX
) - 0.5;
651 double dXEnd
= ((aUnrotatedX
+ 1.5) * fRevScaleX
) - 0.5;
653 int xStart
= MinMax( dXStart
, 0, aBitmapWidth
- 1);
654 int xEnd
= MinMax( dXEnd
, 0, aBitmapWidth
- 1);
659 for (int yIn
= yStart
; yIn
<= yEnd
; yIn
++)
661 for (int xIn
= xStart
; xIn
<= xEnd
; xIn
++)
663 aSum
+= pReadAccess
->GetPixel( yIn
, xIn
).GetIndex();
667 aResultColor
.SetIndex( MinMax( aSum
/ aCount
, 0, 255) );
668 pWriteAccess
->SetPixel( y
, x
, aResultColor
);
672 pWriteAccess
->SetPixel( y
, x
, aTrans
);
680 const BitmapColor
aTrans( pWriteAccess
->GetBestMatchingColor( Color( COL_WHITE
) ) );
681 BitmapColor
aAlphaVal( 0 );
683 for( nY
= 0; nY
< aTargetHeight
; nY
++ )
685 nSinY
= pSinY
[ nY
], nCosY
= pCosY
[ nY
];
687 for( nX
= 0; nX
< aTargetWidth
; nX
++ )
689 nUnRotX
= ( pCosX
[ nX
] - nSinY
) >> 8;
690 nUnRotY
= ( pSinX
[ nX
] + nCosY
) >> 8;
692 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< aUnrotatedWidth
) &&
693 ( nUnRotY
>= 0L ) && ( nUnRotY
< aUnrotatedHeight
) )
695 nTmpX
= pMapIX
[ nUnRotX
]; nTmpFX
= pMapFX
[ nUnRotX
];
696 nTmpY
= pMapIY
[ nUnRotY
], nTmpFY
= pMapFY
[ nUnRotY
];
698 const long nAlpha0
= pReadAccess
->GetPixel( nTmpY
, nTmpX
).GetIndex();
699 const long nAlpha1
= pReadAccess
->GetPixel( nTmpY
, ++nTmpX
).GetIndex();
700 const long nAlpha3
= pReadAccess
->GetPixel( ++nTmpY
, nTmpX
).GetIndex();
701 const long nAlpha2
= pReadAccess
->GetPixel( nTmpY
, --nTmpX
).GetIndex();
702 const long n0
= MAP( nAlpha0
, nAlpha1
, nTmpFX
);
703 const long n1
= MAP( nAlpha2
, nAlpha3
, nTmpFX
);
705 aAlphaVal
.SetIndex( MAP( n0
, n1
, nTmpFY
) );
706 pWriteAccess
->SetPixel( nY
, nX
, aAlphaVal
);
709 pWriteAccess
->SetPixel( nY
, nX
, aTrans
);
714 aOutAlpha
.ReleaseAccess( pWriteAccess
);
718 aAlpha
.ReleaseAccess( pReadAccess
);
722 rOutBmpEx
= BitmapEx( aOutBmp
, aOutAlpha
);
726 Bitmap
aOutMsk( Size( aTargetWidth
, aTargetHeight
), 1 );
727 pWriteAccess
= aOutMsk
.AcquireWriteAccess();
731 Bitmap
aMsk( rBmpEx
.GetMask() );
732 const BitmapColor
aB( pWriteAccess
->GetBestMatchingColor( Color( COL_BLACK
) ) );
733 const BitmapColor
aW( pWriteAccess
->GetBestMatchingColor( Color( COL_WHITE
) ) );
734 BitmapReadAccess
* pMAcc
= NULL
;
736 if( !aMsk
|| ( ( pMAcc
= aMsk
.AcquireReadAccess() ) != NULL
) )
738 long* pMapLX
= new long[ aUnrotatedWidth
];
739 long* pMapLY
= new long[ aUnrotatedHeight
];
743 aTestB
= pMAcc
->GetBestMatchingColor( Color( COL_BLACK
) );
745 // create new horizontal mapping table
746 for( nX
= 0UL; nX
< aUnrotatedWidth
; nX
++ )
747 pMapLX
[ nX
] = FRound( (double) pMapIX
[ nX
] + pMapFX
[ nX
] / 1048576.0 );
749 // create new vertical mapping table
750 for( nY
= 0UL; nY
< aUnrotatedHeight
; nY
++ )
751 pMapLY
[ nY
] = FRound( (double) pMapIY
[ nY
] + pMapFY
[ nY
] / 1048576.0 );
754 for( nY
= 0; nY
< aTargetHeight
; nY
++ )
759 for( nX
= 0; nX
< aTargetWidth
; nX
++ )
761 nUnRotX
= ( pCosX
[ nX
] - nSinY
) >> 8;
762 nUnRotY
= ( pSinX
[ nX
] + nCosY
) >> 8;
764 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< aUnrotatedWidth
) &&
765 ( nUnRotY
>= 0L ) && ( nUnRotY
< aUnrotatedHeight
) )
769 if( pMAcc
->GetPixel( pMapLY
[ nUnRotY
], pMapLX
[ nUnRotX
] ) == aTestB
)
770 pWriteAccess
->SetPixel( nY
, nX
, aB
);
772 pWriteAccess
->SetPixel( nY
, nX
, aW
);
775 pWriteAccess
->SetPixel( nY
, nX
, aB
);
778 pWriteAccess
->SetPixel( nY
, nX
, aW
);
786 aMsk
.ReleaseAccess( pMAcc
);
791 aOutMsk
.ReleaseAccess( pWriteAccess
);
795 rOutBmpEx
= BitmapEx( aOutBmp
, aOutMsk
);
817 sal_Bool
GraphicManager::ImplCreateOutput( OutputDevice
* pOutputDevice
,
818 const Point
& rPoint
, const Size
& rSize
,
819 const BitmapEx
& rBitmapEx
, const GraphicAttr
& rAttributes
,
820 const sal_uLong
/*nFlags*/, BitmapEx
* pBmpEx
)
822 sal_uInt16 nRot10
= rAttributes
.GetRotation() % 3600;
824 Point aOutputPointPix
;
826 Point
aUnrotatedPointPix( pOutputDevice
->LogicToPixel( rPoint
) );
827 Size
aUnrotatedSizePix( pOutputDevice
->LogicToPixel( rSize
) );
833 Polygon
aPoly( Rectangle( rPoint
, rSize
) );
834 aPoly
.Rotate( rPoint
, nRot10
);
835 const Rectangle
aRotBoundRect( aPoly
.GetBoundRect() );
836 aOutputPointPix
= pOutputDevice
->LogicToPixel( aRotBoundRect
.TopLeft() );
837 aOutputSizePix
= pOutputDevice
->LogicToPixel( aRotBoundRect
.GetSize() );
841 aOutputPointPix
= aUnrotatedPointPix
;
842 aOutputSizePix
= aUnrotatedSizePix
;
845 if( aUnrotatedSizePix
.Width() && aUnrotatedSizePix
.Height() )
847 BitmapEx
aBmpEx( rBitmapEx
);
851 const Size
& rBmpSzPix
= rBitmapEx
.GetSizePixel();
852 const long nW
= rBmpSzPix
.Width();
853 const long nH
= rBmpSzPix
.Height();
854 long nStartX
= -1, nStartY
= -1, nEndX
= -1, nEndY
= -1;
855 bool bHMirr
= ( rAttributes
.GetMirrorFlags() & BMP_MIRROR_HORZ
) != 0;
856 bool bVMirr
= ( rAttributes
.GetMirrorFlags() & BMP_MIRROR_VERT
) != 0;
858 // calculate output sizes
862 Rectangle
aOutRect( aPt
, pOutputDevice
->GetOutputSizePixel() );
863 Rectangle
aBmpRect( aOutputPointPix
, aOutputSizePix
);
865 if( pOutputDevice
->GetOutDevType() == OUTDEV_WINDOW
)
867 const Region
aPaintRgn( ( (Window
*) pOutputDevice
)->GetPaintRegion() );
868 if( !aPaintRgn
.IsNull() )
869 aOutRect
.Intersection( pOutputDevice
->LogicToPixel( aPaintRgn
.GetBoundRect() ) );
872 aOutRect
.Intersection( aBmpRect
);
874 if( !aOutRect
.IsEmpty() )
876 aOutPoint
= pOutputDevice
->PixelToLogic( aOutRect
.TopLeft() );
877 aOutSize
= pOutputDevice
->PixelToLogic( aOutRect
.GetSize() );
878 nStartX
= aOutRect
.Left() - aBmpRect
.Left();
879 nStartY
= aOutRect
.Top() - aBmpRect
.Top();
880 nEndX
= aOutRect
.Right() - aBmpRect
.Left();
881 nEndY
= aOutRect
.Bottom() - aBmpRect
.Top();
885 nStartX
= -1L; // invalid
890 aOutPoint
= pOutputDevice
->PixelToLogic( aOutputPointPix
);
891 aOutSize
= pOutputDevice
->PixelToLogic( aOutputSizePix
);
892 nStartX
= nStartY
= 0;
893 nEndX
= aOutputSizePix
.Width() - 1L;
894 nEndY
= aOutputSizePix
.Height() - 1L;
900 const bool bSimple
= ( 1 == nW
|| 1 == nH
);
906 bRet
= ( aOutBmpEx
= aBmpEx
).Scale( aUnrotatedSizePix
);
909 aOutBmpEx
.Rotate( nRot10
, COL_TRANSPARENT
);
913 bRet
= ImplCreateRotatedScaled( aBmpEx
, rAttributes
,
914 nRot10
, aUnrotatedSizePix
,
915 nStartX
, nEndX
, nStartY
, nEndY
,
921 if( !bHMirr
&& !bVMirr
&& aOutputSizePix
== rBmpSzPix
)
923 aOutPoint
= pOutputDevice
->PixelToLogic( aOutputPointPix
);
924 aOutSize
= pOutputDevice
->PixelToLogic( aOutputSizePix
);
932 bRet
= ( aOutBmpEx
= aBmpEx
).Scale( Size( nEndX
- nStartX
+ 1, nEndY
- nStartY
+ 1 ) );
936 bRet
= ImplCreateRotatedScaled( aBmpEx
, rAttributes
,
937 nRot10
, aUnrotatedSizePix
,
938 nStartX
, nEndX
, nStartY
, nEndY
,
946 // Attribute adjustment if necessary
947 if( rAttributes
.IsSpecialDrawMode() || rAttributes
.IsAdjusted() || rAttributes
.IsTransparent() )
948 ImplAdjust( aOutBmpEx
, rAttributes
, ADJUSTMENT_DRAWMODE
| ADJUSTMENT_COLORS
| ADJUSTMENT_TRANSPARENCY
);
950 // OutDev adjustment if necessary
951 if( pOutputDevice
->GetOutDevType() != OUTDEV_PRINTER
&& pOutputDevice
->GetBitCount() <= 8 && aOutBmpEx
.GetBitCount() >= 8 )
952 aOutBmpEx
.Dither( BMP_DITHER_MATRIX
);
960 pOutputDevice
->DrawBitmapEx( aOutPoint
, aOutSize
, aOutBmpEx
);
963 if( !rAttributes
.IsTransparent() && !aOutBmpEx
.IsAlpha() )
964 aOutBmpEx
= BitmapEx( aOutBmpEx
.GetBitmap().CreateDisplayBitmap( pOutputDevice
), aOutBmpEx
.GetMask() );
966 pOutputDevice
->DrawBitmapEx( aOutPoint
, aOutSize
, *pBmpEx
= aOutBmpEx
);
974 // This function checks whether the bitmap is usable for skipping
975 // mtf rendering by using just this one bitmap (i.e. in case the metafile
976 // contains just this one pixmap that covers the entire metafile area).
977 static BitmapEx
checkMetadataBitmap( const BitmapEx
& rBmpEx
,
980 const Point
& rDestPoint
,
981 const Size
& rDestSize
,
982 const Size
& rRefSize
,
983 bool& o_rbNonBitmapActionEncountered
)
985 // NOTE: If you do changes in this function, change checkMetadataBitmap() in grfcache.cxx too.
987 if( rSrcSize
== Size())
988 rSrcSize
= rBmpEx
.GetSizePixel();
990 if( rDestPoint
!= Point( 0, 0 ))
991 { // The pixmap in the metafile has an offset (and so would not cover)
992 // the entire result -> fall back to mtf rendering.
993 o_rbNonBitmapActionEncountered
= true;
996 if( rDestSize
!= rRefSize
)
997 { // The pixmap is not fullscale (does not cover the entire metafile area).
998 // HACK: The code here should refuse to use the bitmap directly
999 // and fall back to mtf rendering, but there seem to be metafiles
1000 // that do not specify exactly their area (the Windows API requires apps
1001 // the specify it manually, the rectangle is specified as topleft/bottomright
1002 // rather than topleft/size [which may be confusing], and the docs
1003 // on the exact meaning are somewhat confusing as well), so if it turns
1004 // out this metafile really contains just one bitmap and no other painting,
1005 // and if the sizes almost match, just use the pixmap (which will be scaled
1006 // to fit exactly the requested size, so there should not be any actual problem
1007 // caused by this small difference). This will allow caching of the resulting
1008 // (scaled) pixmap, which can make a noticeable performance difference.
1009 if( rBmpEx
.GetSizePixel().Width() > 100 && rBmpEx
.GetSizePixel().Height() > 100
1010 && abs( rDestSize
.Width() - rRefSize
.Width()) < 5
1011 && abs( rDestSize
.Height() - rRefSize
.Height()) < 5 )
1012 ; // ok, assume it's close enough
1014 { // fall back to mtf rendering
1015 o_rbNonBitmapActionEncountered
= true;
1022 if( (rSrcPoint
.X() != 0 && rSrcPoint
.Y() != 0) ||
1023 rSrcSize
!= rBmpEx
.GetSizePixel() )
1025 // crop bitmap to given source rectangle (no
1026 // need to copy and convert the whole bitmap)
1027 const Rectangle
aCropRect( rSrcPoint
,
1029 aBmpEx
.Crop( aCropRect
);
1035 sal_Bool
GraphicManager::ImplCreateOutput( OutputDevice
* pOut
,
1036 const Point
& rPt
, const Size
& rSz
,
1037 const GDIMetaFile
& rMtf
, const GraphicAttr
& rAttr
,
1038 const sal_uLong
/*nFlags*/, GDIMetaFile
& rOutMtf
, BitmapEx
& rOutBmpEx
)
1040 const Size
aNewSize( rMtf
.GetPrefSize() );
1044 // Count bitmap actions, and flag actions that paint, but
1046 sal_Int32
nNumBitmaps(0);
1047 bool bNonBitmapActionEncountered(false);
1048 if( aNewSize
.Width() && aNewSize
.Height() && rSz
.Width() && rSz
.Height() )
1050 const double fGrfWH
= (double) aNewSize
.Width() / aNewSize
.Height();
1051 const double fOutWH
= (double) rSz
.Width() / rSz
.Height();
1053 const double fScaleX
= fOutWH
/ fGrfWH
;
1054 const double fScaleY
= 1.0;
1056 const MapMode
rPrefMapMode( rMtf
.GetPrefMapMode() );
1057 const Size
rSizePix( pOut
->LogicToPixel( aNewSize
, rPrefMapMode
) );
1059 // NOTE: If you do changes in this function, check GraphicDisplayCacheEntry::IsCacheableAsBitmap
1060 // in grfcache.cxx too.
1062 // Determine whether the metafile basically displays
1063 // a single bitmap (in which case that bitmap is simply used directly
1064 // instead of playing the metafile). Note that
1065 // the solution, as implemented here, is quite suboptimal (the
1066 // cases where a mtf consisting basically of a single bitmap,
1067 // that fail to pass the test below, are probably frequent). A
1068 // better solution would involve FSAA, but that's currently
1069 // expensive, and might trigger bugs on display drivers, if
1070 // VDevs get bigger than the actual screen.
1073 for( nCurPos
= 0, pAct
= (MetaAction
*)rOutMtf
.FirstAction(); pAct
;
1074 pAct
= (MetaAction
*)rOutMtf
.NextAction(), nCurPos
++ )
1076 MetaAction
* pModAct
= NULL
;
1077 switch( pAct
->GetType() )
1079 case META_FONT_ACTION
:
1081 // taking care of font width default if scaling metafile.
1082 MetaFontAction
* pA
= (MetaFontAction
*)pAct
;
1083 Font
aFont( pA
->GetFont() );
1084 if ( !aFont
.GetWidth() )
1086 FontMetric
aFontMetric( pOut
->GetFontMetric( aFont
) );
1087 aFont
.SetWidth( aFontMetric
.GetWidth() );
1088 pModAct
= new MetaFontAction( aFont
);
1091 // FALLTHROUGH intended
1092 case META_NULL_ACTION
:
1093 // FALLTHROUGH intended
1095 // OutDev state changes (which don't affect bitmap
1097 case META_LINECOLOR_ACTION
:
1098 // FALLTHROUGH intended
1099 case META_FILLCOLOR_ACTION
:
1100 // FALLTHROUGH intended
1101 case META_TEXTCOLOR_ACTION
:
1102 // FALLTHROUGH intended
1103 case META_TEXTFILLCOLOR_ACTION
:
1104 // FALLTHROUGH intended
1105 case META_TEXTALIGN_ACTION
:
1106 // FALLTHROUGH intended
1107 case META_TEXTLINECOLOR_ACTION
:
1108 // FALLTHROUGH intended
1109 case META_TEXTLINE_ACTION
:
1110 // FALLTHROUGH intended
1111 case META_PUSH_ACTION
:
1112 // FALLTHROUGH intended
1113 case META_POP_ACTION
:
1114 // FALLTHROUGH intended
1115 case META_LAYOUTMODE_ACTION
:
1116 // FALLTHROUGH intended
1117 case META_TEXTLANGUAGE_ACTION
:
1118 // FALLTHROUGH intended
1119 case META_COMMENT_ACTION
:
1122 // bitmap output methods
1123 case META_BMP_ACTION
:
1124 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
1126 MetaBmpAction
* pAction
= (MetaBmpAction
*)pAct
;
1128 rOutBmpEx
= checkMetadataBitmap(
1129 BitmapEx( pAction
->GetBitmap()),
1131 pOut
->LogicToPixel( pAction
->GetPoint(),
1133 pAction
->GetBitmap().GetSizePixel(),
1135 bNonBitmapActionEncountered
);
1140 case META_BMPSCALE_ACTION
:
1141 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
1143 MetaBmpScaleAction
* pAction
= (MetaBmpScaleAction
*)pAct
;
1145 rOutBmpEx
= checkMetadataBitmap(
1146 BitmapEx( pAction
->GetBitmap()),
1148 pOut
->LogicToPixel( pAction
->GetPoint(),
1150 pOut
->LogicToPixel( pAction
->GetSize(),
1153 bNonBitmapActionEncountered
);
1158 case META_BMPSCALEPART_ACTION
:
1159 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
1161 MetaBmpScalePartAction
* pAction
= (MetaBmpScalePartAction
*)pAct
;
1163 rOutBmpEx
= checkMetadataBitmap(
1164 BitmapEx( pAction
->GetBitmap() ),
1165 pAction
->GetSrcPoint(),
1166 pAction
->GetSrcSize(),
1167 pOut
->LogicToPixel( pAction
->GetDestPoint(),
1169 pOut
->LogicToPixel( pAction
->GetDestSize(),
1172 bNonBitmapActionEncountered
);
1177 case META_BMPEX_ACTION
:
1178 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
1180 MetaBmpExAction
* pAction
= (MetaBmpExAction
*)pAct
;
1182 rOutBmpEx
= checkMetadataBitmap(
1183 pAction
->GetBitmapEx(),
1185 pOut
->LogicToPixel( pAction
->GetPoint(),
1187 pAction
->GetBitmapEx().GetSizePixel(),
1189 bNonBitmapActionEncountered
);
1194 case META_BMPEXSCALE_ACTION
:
1195 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
1197 MetaBmpExScaleAction
* pAction
= (MetaBmpExScaleAction
*)pAct
;
1199 rOutBmpEx
= checkMetadataBitmap(
1200 pAction
->GetBitmapEx(),
1202 pOut
->LogicToPixel( pAction
->GetPoint(),
1204 pOut
->LogicToPixel( pAction
->GetSize(),
1207 bNonBitmapActionEncountered
);
1212 case META_BMPEXSCALEPART_ACTION
:
1213 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
1215 MetaBmpExScalePartAction
* pAction
= (MetaBmpExScalePartAction
*)pAct
;
1217 rOutBmpEx
= checkMetadataBitmap( pAction
->GetBitmapEx(),
1218 pAction
->GetSrcPoint(),
1219 pAction
->GetSrcSize(),
1220 pOut
->LogicToPixel( pAction
->GetDestPoint(),
1222 pOut
->LogicToPixel( pAction
->GetDestSize(),
1225 bNonBitmapActionEncountered
);
1230 // these actions actually output something (that's
1231 // different from a bitmap)
1232 case META_RASTEROP_ACTION
:
1233 if( ((MetaRasterOpAction
*)pAct
)->GetRasterOp() == ROP_OVERPAINT
)
1235 // FALLTHROUGH intended
1236 case META_PIXEL_ACTION
:
1237 // FALLTHROUGH intended
1238 case META_POINT_ACTION
:
1239 // FALLTHROUGH intended
1240 case META_LINE_ACTION
:
1241 // FALLTHROUGH intended
1242 case META_RECT_ACTION
:
1243 // FALLTHROUGH intended
1244 case META_ROUNDRECT_ACTION
:
1245 // FALLTHROUGH intended
1246 case META_ELLIPSE_ACTION
:
1247 // FALLTHROUGH intended
1248 case META_ARC_ACTION
:
1249 // FALLTHROUGH intended
1250 case META_PIE_ACTION
:
1251 // FALLTHROUGH intended
1252 case META_CHORD_ACTION
:
1253 // FALLTHROUGH intended
1254 case META_POLYLINE_ACTION
:
1255 // FALLTHROUGH intended
1256 case META_POLYGON_ACTION
:
1257 // FALLTHROUGH intended
1258 case META_POLYPOLYGON_ACTION
:
1259 // FALLTHROUGH intended
1261 case META_TEXT_ACTION
:
1262 // FALLTHROUGH intended
1263 case META_TEXTARRAY_ACTION
:
1264 // FALLTHROUGH intended
1265 case META_STRETCHTEXT_ACTION
:
1266 // FALLTHROUGH intended
1267 case META_TEXTRECT_ACTION
:
1268 // FALLTHROUGH intended
1270 case META_MASK_ACTION
:
1271 // FALLTHROUGH intended
1272 case META_MASKSCALE_ACTION
:
1273 // FALLTHROUGH intended
1274 case META_MASKSCALEPART_ACTION
:
1275 // FALLTHROUGH intended
1277 case META_GRADIENT_ACTION
:
1278 // FALLTHROUGH intended
1279 case META_HATCH_ACTION
:
1280 // FALLTHROUGH intended
1281 case META_WALLPAPER_ACTION
:
1282 // FALLTHROUGH intended
1284 case META_TRANSPARENT_ACTION
:
1285 // FALLTHROUGH intended
1286 case META_EPS_ACTION
:
1287 // FALLTHROUGH intended
1288 case META_FLOATTRANSPARENT_ACTION
:
1289 // FALLTHROUGH intended
1290 case META_GRADIENTEX_ACTION
:
1291 // FALLTHROUGH intended
1293 // OutDev state changes that _do_ affect bitmap
1295 case META_CLIPREGION_ACTION
:
1296 // FALLTHROUGH intended
1297 case META_ISECTRECTCLIPREGION_ACTION
:
1298 // FALLTHROUGH intended
1299 case META_ISECTREGIONCLIPREGION_ACTION
:
1300 // FALLTHROUGH intended
1301 case META_MOVECLIPREGION_ACTION
:
1302 // FALLTHROUGH intended
1304 case META_MAPMODE_ACTION
:
1305 // FALLTHROUGH intended
1306 case META_REFPOINT_ACTION
:
1307 // FALLTHROUGH intended
1309 bNonBitmapActionEncountered
= true;
1314 MetaAction
* pDeleteAction
= rOutMtf
.ReplaceAction( pModAct
, nCurPos
);
1315 assert(pDeleteAction
);
1316 pDeleteAction
->Delete();
1320 if( pAct
->GetRefCount() > 1 )
1322 MetaAction
* pDeleteAction
= rOutMtf
.ReplaceAction( pModAct
= pAct
->Clone(), nCurPos
);
1323 assert(pDeleteAction
);
1324 pDeleteAction
->Delete();
1329 pModAct
->Scale( fScaleX
, fScaleY
);
1331 rOutMtf
.SetPrefSize( Size( FRound( aNewSize
.Width() * fScaleX
),
1332 FRound( aNewSize
.Height() * fScaleY
) ) );
1335 if( nNumBitmaps
!= 1 || bNonBitmapActionEncountered
)
1337 if( rAttr
.IsSpecialDrawMode() || rAttr
.IsAdjusted() || rAttr
.IsMirrored() || rAttr
.IsRotated() || rAttr
.IsTransparent() )
1338 ImplAdjust( rOutMtf
, rAttr
, ADJUSTMENT_ALL
);
1340 ImplDraw( pOut
, rPt
, rSz
, rOutMtf
, rAttr
);
1341 rOutBmpEx
= BitmapEx();
1347 void GraphicManager::ImplAdjust( BitmapEx
& rBmpEx
, const GraphicAttr
& rAttr
, sal_uLong nAdjustmentFlags
)
1349 GraphicAttr
aAttr( rAttr
);
1351 if( ( nAdjustmentFlags
& ADJUSTMENT_DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
1353 switch( aAttr
.GetDrawMode() )
1355 case( GRAPHICDRAWMODE_MONO
):
1356 rBmpEx
.Convert( BMP_CONVERSION_1BIT_THRESHOLD
);
1359 case( GRAPHICDRAWMODE_GREYS
):
1360 rBmpEx
.Convert( BMP_CONVERSION_8BIT_GREYS
);
1363 case( GRAPHICDRAWMODE_WATERMARK
):
1365 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
1366 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
1375 if( ( nAdjustmentFlags
& ADJUSTMENT_COLORS
) && aAttr
.IsAdjusted() )
1377 rBmpEx
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
1378 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
1379 aAttr
.GetGamma(), aAttr
.IsInvert() );
1382 if( ( nAdjustmentFlags
& ADJUSTMENT_MIRROR
) && aAttr
.IsMirrored() )
1384 rBmpEx
.Mirror( aAttr
.GetMirrorFlags() );
1387 if( ( nAdjustmentFlags
& ADJUSTMENT_ROTATE
) && aAttr
.IsRotated() )
1389 rBmpEx
.Rotate( aAttr
.GetRotation(), Color( COL_TRANSPARENT
) );
1392 if( ( nAdjustmentFlags
& ADJUSTMENT_TRANSPARENCY
) && aAttr
.IsTransparent() )
1395 sal_uInt8 cTrans
= aAttr
.GetTransparency();
1397 if( !rBmpEx
.IsTransparent() )
1398 aAlpha
= AlphaMask( rBmpEx
.GetSizePixel(), &cTrans
);
1399 else if( !rBmpEx
.IsAlpha() )
1401 aAlpha
= rBmpEx
.GetMask();
1402 aAlpha
.Replace( 0, cTrans
);
1406 aAlpha
= rBmpEx
.GetAlpha();
1407 BitmapWriteAccess
* pA
= aAlpha
.AcquireWriteAccess();
1411 sal_uLong nTrans
= cTrans
, nNewTrans
;
1412 const long nWidth
= pA
->Width(), nHeight
= pA
->Height();
1414 if( pA
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
1416 for( long nY
= 0; nY
< nHeight
; nY
++ )
1418 Scanline pAScan
= pA
->GetScanline( nY
);
1420 for( long nX
= 0; nX
< nWidth
; nX
++ )
1422 nNewTrans
= nTrans
+ *pAScan
;
1423 *pAScan
++ = (sal_uInt8
) ( ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
);
1429 BitmapColor
aAlphaValue( 0 );
1431 for( long nY
= 0; nY
< nHeight
; nY
++ )
1433 for( long nX
= 0; nX
< nWidth
; nX
++ )
1435 nNewTrans
= nTrans
+ pA
->GetPixel( nY
, nX
).GetIndex();
1436 aAlphaValue
.SetIndex( (sal_uInt8
) ( ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
) );
1437 pA
->SetPixel( nY
, nX
, aAlphaValue
);
1442 aAlpha
.ReleaseAccess( pA
);
1446 rBmpEx
= BitmapEx( rBmpEx
.GetBitmap(), aAlpha
);
1450 void GraphicManager::ImplAdjust( GDIMetaFile
& rMtf
, const GraphicAttr
& rAttr
, sal_uLong nAdjustmentFlags
)
1452 GraphicAttr
aAttr( rAttr
);
1454 if( ( nAdjustmentFlags
& ADJUSTMENT_DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
1456 switch( aAttr
.GetDrawMode() )
1458 case( GRAPHICDRAWMODE_MONO
):
1459 rMtf
.Convert( MTF_CONVERSION_1BIT_THRESHOLD
);
1462 case( GRAPHICDRAWMODE_GREYS
):
1463 rMtf
.Convert( MTF_CONVERSION_8BIT_GREYS
);
1466 case( GRAPHICDRAWMODE_WATERMARK
):
1468 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
1469 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
1478 if( ( nAdjustmentFlags
& ADJUSTMENT_COLORS
) && aAttr
.IsAdjusted() )
1480 rMtf
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
1481 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
1482 aAttr
.GetGamma(), aAttr
.IsInvert() );
1485 if( ( nAdjustmentFlags
& ADJUSTMENT_MIRROR
) && aAttr
.IsMirrored() )
1487 rMtf
.Mirror( aAttr
.GetMirrorFlags() );
1490 if( ( nAdjustmentFlags
& ADJUSTMENT_ROTATE
) && aAttr
.IsRotated() )
1492 rMtf
.Rotate( aAttr
.GetRotation() );
1495 if( ( nAdjustmentFlags
& ADJUSTMENT_TRANSPARENCY
) && aAttr
.IsTransparent() )
1497 OSL_FAIL( "Missing implementation: Mtf-Transparency" );
1501 void GraphicManager::ImplAdjust( Animation
& rAnimation
, const GraphicAttr
& rAttr
, sal_uLong nAdjustmentFlags
)
1503 GraphicAttr
aAttr( rAttr
);
1505 if( ( nAdjustmentFlags
& ADJUSTMENT_DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
1507 switch( aAttr
.GetDrawMode() )
1509 case( GRAPHICDRAWMODE_MONO
):
1510 rAnimation
.Convert( BMP_CONVERSION_1BIT_THRESHOLD
);
1513 case( GRAPHICDRAWMODE_GREYS
):
1514 rAnimation
.Convert( BMP_CONVERSION_8BIT_GREYS
);
1517 case( GRAPHICDRAWMODE_WATERMARK
):
1519 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
1520 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
1529 if( ( nAdjustmentFlags
& ADJUSTMENT_COLORS
) && aAttr
.IsAdjusted() )
1531 rAnimation
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
1532 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
1533 aAttr
.GetGamma(), aAttr
.IsInvert() );
1536 if( ( nAdjustmentFlags
& ADJUSTMENT_MIRROR
) && aAttr
.IsMirrored() )
1538 rAnimation
.Mirror( aAttr
.GetMirrorFlags() );
1541 if( ( nAdjustmentFlags
& ADJUSTMENT_ROTATE
) && aAttr
.IsRotated() )
1543 OSL_FAIL( "Missing implementation: Animation-Rotation" );
1546 if( ( nAdjustmentFlags
& ADJUSTMENT_TRANSPARENCY
) && aAttr
.IsTransparent() )
1548 OSL_FAIL( "Missing implementation: Animation-Transparency" );
1552 void GraphicManager::ImplDraw( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
1553 const GDIMetaFile
& rMtf
, const GraphicAttr
& rAttr
)
1555 sal_uInt16 nRot10
= rAttr
.GetRotation() % 3600;
1556 Point
aOutPt( rPt
);
1561 Polygon
aPoly( Rectangle( aOutPt
, aOutSz
) );
1563 aPoly
.Rotate( aOutPt
, nRot10
);
1564 const Rectangle
aRotBoundRect( aPoly
.GetBoundRect() );
1565 aOutPt
= aRotBoundRect
.TopLeft();
1566 aOutSz
= aRotBoundRect
.GetSize();
1569 pOut
->Push( PUSH_CLIPREGION
);
1570 pOut
->IntersectClipRegion( Rectangle( aOutPt
, aOutSz
) );
1572 ( (GDIMetaFile
&) rMtf
).WindStart();
1573 ( (GDIMetaFile
&) rMtf
).Play( pOut
, aOutPt
, aOutSz
);
1574 ( (GDIMetaFile
&) rMtf
).WindStart();
1581 ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
1583 Point aTileTopLeft
; // top, left position of the rendered tile
1584 Point aNextTileTopLeft
; // top, left position for next recursion
1586 Size aTileSizePixel
; // size of the generated tile (might
1588 // aNextTileTopLeft-aTileTopLeft, because
1589 // this is nExponent*prevTileSize. The
1590 // generated tile is always nExponent
1591 // times the previous tile, such that it
1592 // can be used in the next stage. The
1593 // required area coverage is often
1594 // less. The extraneous area covered is
1595 // later overwritten by the next stage)
1596 int nTilesEmptyX
; // number of original tiles empty right of
1597 // this tile. This counts from
1598 // aNextTileTopLeft, i.e. the additional
1599 // area covered by aTileSizePixel is not
1600 // considered here. This is for
1601 // unification purposes, as the iterative
1602 // calculation of the next level's empty
1603 // tiles has to be based on this value.
1604 int nTilesEmptyY
; // as above, for Y
1608 bool GraphicObject::ImplRenderTempTile( VirtualDevice
& rVDev
, int nExponent
,
1609 int nNumTilesX
, int nNumTilesY
,
1610 const Size
& rTileSizePixel
,
1611 const GraphicAttr
* pAttr
, sal_uLong nFlags
)
1613 if( nExponent
<= 1 )
1616 // determine MSB factor
1617 int nMSBFactor( 1 );
1618 while( nNumTilesX
/ nMSBFactor
!= 0 ||
1619 nNumTilesY
/ nMSBFactor
!= 0 )
1621 nMSBFactor
*= nExponent
;
1625 nMSBFactor
/= nExponent
;
1627 ImplTileInfo aTileInfo
;
1629 // #105229# Switch off mapping (converting to logic and back to
1630 // pixel might cause roundoff errors)
1631 sal_Bool
bOldMap( rVDev
.IsMapModeEnabled() );
1632 rVDev
.EnableMapMode( sal_False
);
1634 bool bRet( ImplRenderTileRecursive( rVDev
, nExponent
, nMSBFactor
, nNumTilesX
, nNumTilesY
,
1635 nNumTilesX
, nNumTilesY
, rTileSizePixel
, pAttr
, nFlags
, aTileInfo
) );
1637 rVDev
.EnableMapMode( bOldMap
);
1642 // define for debug drawings
1645 // see header comment. this works similar to base conversion of a
1646 // number, i.e. if the exponent is 10, then the number for every tile
1647 // size is given by the decimal place of the corresponding decimal
1649 bool GraphicObject::ImplRenderTileRecursive( VirtualDevice
& rVDev
, int nExponent
, int nMSBFactor
,
1650 int nNumOrigTilesX
, int nNumOrigTilesY
,
1651 int nRemainderTilesX
, int nRemainderTilesY
,
1652 const Size
& rTileSizePixel
, const GraphicAttr
* pAttr
,
1653 sal_uLong nFlags
, ImplTileInfo
& rTileInfo
)
1655 // gets loaded with our tile bitmap
1656 GraphicObject aTmpGraphic
;
1658 // stores a flag that renders the zero'th tile position
1659 // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the
1660 // recursion stack. All other position already have that tile
1661 // rendered, because the lower levels painted their generated tile
1663 bool bNoFirstTileDraw( false );
1665 // what's left when we're done with our tile size
1666 const int nNewRemainderX( nRemainderTilesX
% nMSBFactor
);
1667 const int nNewRemainderY( nRemainderTilesY
% nMSBFactor
);
1669 // gets filled out from the recursive call with info of what's
1671 ImplTileInfo aTileInfo
;
1673 // current output position while drawing
1677 // check for recursion's end condition: LSB place reached?
1678 if( nMSBFactor
== 1 )
1680 aTmpGraphic
= *this;
1682 // set initial tile size -> orig size
1683 aTileInfo
.aTileSizePixel
= rTileSizePixel
;
1684 aTileInfo
.nTilesEmptyX
= nNumOrigTilesX
;
1685 aTileInfo
.nTilesEmptyY
= nNumOrigTilesY
;
1687 else if( ImplRenderTileRecursive( rVDev
, nExponent
, nMSBFactor
/nExponent
,
1688 nNumOrigTilesX
, nNumOrigTilesY
,
1689 nNewRemainderX
, nNewRemainderY
,
1690 rTileSizePixel
, pAttr
, nFlags
, aTileInfo
) )
1692 // extract generated tile -> see comment on the first loop below
1693 BitmapEx
aTileBitmap( rVDev
.GetBitmap( aTileInfo
.aTileTopLeft
, aTileInfo
.aTileSizePixel
) );
1695 aTmpGraphic
= GraphicObject( aTileBitmap
);
1697 // fill stripes left over from upstream levels:
1705 // where x denotes the place filled by our recursive predecessors
1707 // check whether we have to fill stripes here. Although not
1708 // obvious, there is one case where we can skip this step: if
1709 // the previous recursion level (the one who filled our
1710 // aTileInfo) had zero area to fill, then there are no white
1711 // stripes left, naturally. This happens if the digit
1712 // associated to that level has a zero, and can be checked via
1713 // aTileTopLeft==aNextTileTopLeft.
1714 if( aTileInfo
.aTileTopLeft
!= aTileInfo
.aNextTileTopLeft
)
1716 // now fill one row from aTileInfo.aNextTileTopLeft.X() all
1717 // the way to the right
1718 aCurrPos
.X() = aTileInfo
.aNextTileTopLeft
.X();
1719 aCurrPos
.Y() = aTileInfo
.aTileTopLeft
.Y();
1720 for( nX
=0; nX
< aTileInfo
.nTilesEmptyX
; nX
+= nMSBFactor
)
1722 if( !aTmpGraphic
.Draw( &rVDev
, aCurrPos
, aTileInfo
.aTileSizePixel
, pAttr
, nFlags
) )
1725 aCurrPos
.X() += aTileInfo
.aTileSizePixel
.Width();
1729 // rVDev.SetFillColor( COL_WHITE );
1730 rVDev
.SetFillColor();
1731 rVDev
.SetLineColor( Color( 255 * nExponent
/ nMSBFactor
, 255 - 255 * nExponent
/ nMSBFactor
, 128 - 255 * nExponent
/ nMSBFactor
) );
1732 rVDev
.DrawEllipse( Rectangle(aTileInfo
.aNextTileTopLeft
.X(), aTileInfo
.aTileTopLeft
.Y(),
1733 aTileInfo
.aNextTileTopLeft
.X() - 1 + (aTileInfo
.nTilesEmptyX
/nMSBFactor
)*aTileInfo
.aTileSizePixel
.Width(),
1734 aTileInfo
.aTileTopLeft
.Y() + aTileInfo
.aTileSizePixel
.Height() - 1) );
1737 // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
1738 // the way to the bottom
1739 aCurrPos
.X() = aTileInfo
.aTileTopLeft
.X();
1740 aCurrPos
.Y() = aTileInfo
.aNextTileTopLeft
.Y();
1741 for( nY
=0; nY
< aTileInfo
.nTilesEmptyY
; nY
+= nMSBFactor
)
1743 if( !aTmpGraphic
.Draw( &rVDev
, aCurrPos
, aTileInfo
.aTileSizePixel
, pAttr
, nFlags
) )
1746 aCurrPos
.Y() += aTileInfo
.aTileSizePixel
.Height();
1750 rVDev
.DrawEllipse( Rectangle(aTileInfo
.aTileTopLeft
.X(), aTileInfo
.aNextTileTopLeft
.Y(),
1751 aTileInfo
.aTileTopLeft
.X() + aTileInfo
.aTileSizePixel
.Width() - 1,
1752 aTileInfo
.aNextTileTopLeft
.Y() - 1 + (aTileInfo
.nTilesEmptyY
/nMSBFactor
)*aTileInfo
.aTileSizePixel
.Height()) );
1757 // Thought that aTileInfo.aNextTileTopLeft tile has always
1758 // been drawn already, but that's wrong: typically,
1759 // _parts_ of that tile have been drawn, since the
1760 // previous level generated the tile there. But when
1761 // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the
1762 // difference between these two values is missing in the
1763 // lower right corner of this first tile. So, can do that
1765 bNoFirstTileDraw
= true;
1773 // calc number of original tiles in our drawing area without
1775 nRemainderTilesX
-= nNewRemainderX
;
1776 nRemainderTilesY
-= nNewRemainderY
;
1778 // fill tile info for calling method
1779 rTileInfo
.aTileTopLeft
= aTileInfo
.aNextTileTopLeft
;
1780 rTileInfo
.aNextTileTopLeft
= Point( rTileInfo
.aTileTopLeft
.X() + rTileSizePixel
.Width()*nRemainderTilesX
,
1781 rTileInfo
.aTileTopLeft
.Y() + rTileSizePixel
.Height()*nRemainderTilesY
);
1782 rTileInfo
.aTileSizePixel
= Size( rTileSizePixel
.Width()*nMSBFactor
*nExponent
,
1783 rTileSizePixel
.Height()*nMSBFactor
*nExponent
);
1784 rTileInfo
.nTilesEmptyX
= aTileInfo
.nTilesEmptyX
- nRemainderTilesX
;
1785 rTileInfo
.nTilesEmptyY
= aTileInfo
.nTilesEmptyY
- nRemainderTilesY
;
1787 // init output position
1788 aCurrPos
= aTileInfo
.aNextTileTopLeft
;
1790 // fill our drawing area. Fill possibly more, to create the next
1791 // bigger tile size -> see bitmap extraction above. This does no
1792 // harm, since everything right or below our actual area is
1793 // overdrawn by our caller. Just in case we're in the last level,
1794 // we don't draw beyond the right or bottom border.
1795 for( nY
=0; nY
< aTileInfo
.nTilesEmptyY
&& nY
< nExponent
*nMSBFactor
; nY
+= nMSBFactor
)
1797 aCurrPos
.X() = aTileInfo
.aNextTileTopLeft
.X();
1799 for( nX
=0; nX
< aTileInfo
.nTilesEmptyX
&& nX
< nExponent
*nMSBFactor
; nX
+= nMSBFactor
)
1801 if( bNoFirstTileDraw
)
1802 bNoFirstTileDraw
= false; // don't draw first tile position
1803 else if( !aTmpGraphic
.Draw( &rVDev
, aCurrPos
, aTileInfo
.aTileSizePixel
, pAttr
, nFlags
) )
1806 aCurrPos
.X() += aTileInfo
.aTileSizePixel
.Width();
1809 aCurrPos
.Y() += aTileInfo
.aTileSizePixel
.Height();
1813 // rVDev.SetFillColor( COL_WHITE );
1814 rVDev
.SetFillColor();
1815 rVDev
.SetLineColor( Color( 255 * nExponent
/ nMSBFactor
, 255 - 255 * nExponent
/ nMSBFactor
, 128 - 255 * nExponent
/ nMSBFactor
) );
1816 rVDev
.DrawRect( Rectangle((rTileInfo
.aTileTopLeft
.X())*rTileSizePixel
.Width(),
1817 (rTileInfo
.aTileTopLeft
.Y())*rTileSizePixel
.Height(),
1818 (rTileInfo
.aNextTileTopLeft
.X())*rTileSizePixel
.Width()-1,
1819 (rTileInfo
.aNextTileTopLeft
.Y())*rTileSizePixel
.Height()-1) );
1825 bool GraphicObject::ImplDrawTiled( OutputDevice
* pOut
, const Rectangle
& rArea
, const Size
& rSizePixel
,
1826 const Size
& rOffset
, const GraphicAttr
* pAttr
, sal_uLong nFlags
, int nTileCacheSize1D
)
1828 // how many tiles to generate per recursion step
1829 enum{ SubdivisionExponent
=2 };
1831 const MapMode
aOutMapMode( pOut
->GetMapMode() );
1832 const MapMode
aMapMode( aOutMapMode
.GetMapUnit(), Point(), aOutMapMode
.GetScaleX(), aOutMapMode
.GetScaleY() );
1835 // #i42643# Casting to Int64, to avoid integer overflow for
1836 // huge-DPI output devices
1837 if( GetGraphic().GetType() == GRAPHIC_BITMAP
&&
1838 static_cast<sal_Int64
>(rSizePixel
.Width()) * rSizePixel
.Height() <
1839 static_cast<sal_Int64
>(nTileCacheSize1D
)*nTileCacheSize1D
)
1841 // First combine very small bitmaps into a larger tile
1842 // ===================================================
1844 VirtualDevice aVDev
;
1845 const int nNumTilesInCacheX( (nTileCacheSize1D
+ rSizePixel
.Width()-1) / rSizePixel
.Width() );
1846 const int nNumTilesInCacheY( (nTileCacheSize1D
+ rSizePixel
.Height()-1) / rSizePixel
.Height() );
1848 aVDev
.SetOutputSizePixel( Size( nNumTilesInCacheX
*rSizePixel
.Width(),
1849 nNumTilesInCacheY
*rSizePixel
.Height() ) );
1850 aVDev
.SetMapMode( aMapMode
);
1852 // draw bitmap content
1853 if( ImplRenderTempTile( aVDev
, SubdivisionExponent
, nNumTilesInCacheX
,
1854 nNumTilesInCacheY
, rSizePixel
, pAttr
, nFlags
) )
1856 BitmapEx
aTileBitmap( aVDev
.GetBitmap( Point(0,0), aVDev
.GetOutputSize() ) );
1858 // draw alpha content, if any
1859 if( IsTransparent() )
1861 GraphicObject aAlphaGraphic
;
1863 if( GetGraphic().IsAlpha() )
1864 aAlphaGraphic
.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
1866 aAlphaGraphic
.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
1868 if( aAlphaGraphic
.ImplRenderTempTile( aVDev
, SubdivisionExponent
, nNumTilesInCacheX
,
1869 nNumTilesInCacheY
, rSizePixel
, pAttr
, nFlags
) )
1871 // Combine bitmap and alpha/mask
1872 if( GetGraphic().IsAlpha() )
1873 aTileBitmap
= BitmapEx( aTileBitmap
.GetBitmap(),
1874 AlphaMask( aVDev
.GetBitmap( Point(0,0), aVDev
.GetOutputSize() ) ) );
1876 aTileBitmap
= BitmapEx( aTileBitmap
.GetBitmap(),
1877 aVDev
.GetBitmap( Point(0,0), aVDev
.GetOutputSize() ).CreateMask( Color(COL_WHITE
) ) );
1881 // paint generated tile
1882 GraphicObject
aTmpGraphic( aTileBitmap
);
1883 bRet
= aTmpGraphic
.ImplDrawTiled( pOut
, rArea
,
1884 aTileBitmap
.GetSizePixel(),
1885 rOffset
, pAttr
, nFlags
, nTileCacheSize1D
);
1890 const Size
aOutOffset( pOut
->LogicToPixel( rOffset
, aOutMapMode
) );
1891 const Rectangle
aOutArea( pOut
->LogicToPixel( rArea
, aOutMapMode
) );
1893 // number of invisible (because out-of-area) tiles
1894 int nInvisibleTilesX
;
1895 int nInvisibleTilesY
;
1897 // round towards -infty for negative offset
1898 if( aOutOffset
.Width() < 0 )
1899 nInvisibleTilesX
= (aOutOffset
.Width() - rSizePixel
.Width() + 1) / rSizePixel
.Width();
1901 nInvisibleTilesX
= aOutOffset
.Width() / rSizePixel
.Width();
1903 // round towards -infty for negative offset
1904 if( aOutOffset
.Height() < 0 )
1905 nInvisibleTilesY
= (aOutOffset
.Height() - rSizePixel
.Height() + 1) / rSizePixel
.Height();
1907 nInvisibleTilesY
= aOutOffset
.Height() / rSizePixel
.Height();
1909 // origin from where to 'virtually' start drawing in pixel
1910 const Point
aOutOrigin( pOut
->LogicToPixel( Point( rArea
.Left() - rOffset
.Width(),
1911 rArea
.Top() - rOffset
.Height() ) ) );
1912 // position in pixel from where to really start output
1913 const Point
aOutStart( aOutOrigin
.X() + nInvisibleTilesX
*rSizePixel
.Width(),
1914 aOutOrigin
.Y() + nInvisibleTilesY
*rSizePixel
.Height() );
1916 pOut
->Push( PUSH_CLIPREGION
);
1917 pOut
->IntersectClipRegion( rArea
);
1922 bRet
= ImplDrawTiled( *pOut
, aOutStart
,
1923 (aOutArea
.GetWidth() + aOutArea
.Left() - aOutStart
.X() + rSizePixel
.Width() - 1) / rSizePixel
.Width(),
1924 (aOutArea
.GetHeight() + aOutArea
.Top() - aOutStart
.Y() + rSizePixel
.Height() - 1) / rSizePixel
.Height(),
1925 rSizePixel
, pAttr
, nFlags
);
1933 bool GraphicObject::ImplDrawTiled( OutputDevice
& rOut
, const Point
& rPosPixel
,
1934 int nNumTilesX
, int nNumTilesY
,
1935 const Size
& rTileSizePixel
, const GraphicAttr
* pAttr
, sal_uLong nFlags
)
1937 Point
aCurrPos( rPosPixel
);
1938 Size
aTileSizeLogic( rOut
.PixelToLogic( rTileSizePixel
) );
1941 // #107607# Use logical coordinates for metafile playing, too
1942 bool bDrawInPixel( rOut
.GetConnectMetaFile() == NULL
&& GRAPHIC_BITMAP
== GetType() );
1945 // #105229# Switch off mapping (converting to logic and back to
1946 // pixel might cause roundoff errors)
1947 bool bOldMap( rOut
.IsMapModeEnabled() );
1950 rOut
.EnableMapMode( sal_False
);
1952 for( nY
=0; nY
< nNumTilesY
; ++nY
)
1954 aCurrPos
.X() = rPosPixel
.X();
1956 for( nX
=0; nX
< nNumTilesX
; ++nX
)
1958 // #105229# work with pixel coordinates here, mapping is disabled!
1959 // #104004# don't disable mapping for metafile recordings
1960 // #108412# don't quit the loop if one draw fails
1962 // update return value. This method should return true, if
1963 // at least one of the looped Draws succeeded.
1964 bRet
|= Draw( &rOut
,
1965 bDrawInPixel
? aCurrPos
: rOut
.PixelToLogic( aCurrPos
),
1966 bDrawInPixel
? rTileSizePixel
: aTileSizeLogic
,
1969 aCurrPos
.X() += rTileSizePixel
.Width();
1972 aCurrPos
.Y() += rTileSizePixel
.Height();
1976 rOut
.EnableMapMode( bOldMap
);
1981 void GraphicObject::ImplTransformBitmap( BitmapEx
& rBmpEx
,
1982 const GraphicAttr
& rAttr
,
1983 const Size
& rCropLeftTop
,
1984 const Size
& rCropRightBottom
,
1985 const Rectangle
& rCropRect
,
1986 const Size
& rDstSize
,
1987 sal_Bool bEnlarge
) const
1989 // #107947# Extracted from svdograf.cxx
1991 // #104115# Crop the bitmap
1992 if( rAttr
.IsCropped() )
1994 rBmpEx
.Crop( rCropRect
);
1996 // #104115# Negative crop sizes mean: enlarge bitmap and pad
1998 rCropLeftTop
.Width() < 0 ||
1999 rCropLeftTop
.Height() < 0 ||
2000 rCropRightBottom
.Width() < 0 ||
2001 rCropRightBottom
.Height() < 0 ) )
2003 Size
aBmpSize( rBmpEx
.GetSizePixel() );
2004 sal_Int32
nPadLeft( rCropLeftTop
.Width() < 0 ? -rCropLeftTop
.Width() : 0 );
2005 sal_Int32
nPadTop( rCropLeftTop
.Height() < 0 ? -rCropLeftTop
.Height() : 0 );
2006 sal_Int32
nPadTotalWidth( aBmpSize
.Width() + nPadLeft
+ (rCropRightBottom
.Width() < 0 ? -rCropRightBottom
.Width() : 0) );
2007 sal_Int32
nPadTotalHeight( aBmpSize
.Height() + nPadTop
+ (rCropRightBottom
.Height() < 0 ? -rCropRightBottom
.Height() : 0) );
2011 if( rBmpEx
.IsTransparent() )
2013 if( rBmpEx
.IsAlpha() )
2014 aBmpEx2
= BitmapEx( rBmpEx
.GetBitmap(), rBmpEx
.GetAlpha() );
2016 aBmpEx2
= BitmapEx( rBmpEx
.GetBitmap(), rBmpEx
.GetMask() );
2020 // #104115# Generate mask bitmap and init to zero
2021 Bitmap
aMask( aBmpSize
, 1 );
2022 aMask
.Erase( Color(0,0,0) );
2024 // #104115# Always generate transparent bitmap, we need the border transparent
2025 aBmpEx2
= BitmapEx( rBmpEx
.GetBitmap(), aMask
);
2027 // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
2031 aBmpEx2
.SetSizePixel( Size(nPadTotalWidth
, nPadTotalHeight
) );
2032 aBmpEx2
.Erase( Color(0xFF,0,0,0) );
2033 aBmpEx2
.CopyPixel( Rectangle( Point(nPadLeft
, nPadTop
), aBmpSize
), Rectangle( Point(0, 0), aBmpSize
), &rBmpEx
);
2038 const Size
aSizePixel( rBmpEx
.GetSizePixel() );
2040 if( rAttr
.GetRotation() != 0 && !IsAnimated() )
2042 if( aSizePixel
.Width() && aSizePixel
.Height() && rDstSize
.Width() && rDstSize
.Height() )
2044 double fSrcWH
= (double) aSizePixel
.Width() / aSizePixel
.Height();
2045 double fDstWH
= (double) rDstSize
.Width() / rDstSize
.Height();
2046 double fScaleX
= 1.0, fScaleY
= 1.0;
2048 // always choose scaling to shrink bitmap
2049 if( fSrcWH
< fDstWH
)
2050 fScaleY
= aSizePixel
.Width() / ( fDstWH
* aSizePixel
.Height() );
2052 fScaleX
= fDstWH
* aSizePixel
.Height() / aSizePixel
.Width();
2054 rBmpEx
.Scale( fScaleX
, fScaleY
);
2059 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */