1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: grfmgr2.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_goodies.hxx"
34 #include <vos/macros.hxx>
35 #include <vcl/bmpacc.hxx>
36 #include <tools/poly.hxx>
37 #include <vcl/outdev.hxx>
38 #include <vcl/window.hxx>
39 #include <vcl/gdimtf.hxx>
40 #include <vcl/metaact.hxx>
41 #include <vcl/metric.hxx>
42 #include <vcl/animate.hxx>
43 #include <vcl/alpha.hxx>
44 #include <vcl/virdev.hxx>
45 #include "grfcache.hxx"
52 #define MAX_PRINTER_EXT 1024
53 #define MAP( cVal0, cVal1, nFrac ) ((BYTE)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L))
54 #define WATERMARK_LUM_OFFSET 50
55 #define WATERMARK_CON_OFFSET -70
63 void muckWithBitmap( const Point
& rDestPoint
,
64 const Size
& rDestSize
,
66 bool& o_rbNonBitmapActionEncountered
)
68 const Point aEmptyPoint
;
70 if( aEmptyPoint
!= rDestPoint
||
71 rDestSize
!= rRefSize
)
73 // non-fullscale, or offsetted bmp -> fallback to mtf
75 o_rbNonBitmapActionEncountered
= true;
79 BitmapEx
muckWithBitmap( const BitmapEx
& rBmpEx
,
80 const Point
& rSrcPoint
,
82 const Point
& rDestPoint
,
83 const Size
& rDestSize
,
85 bool& o_rbNonBitmapActionEncountered
)
89 muckWithBitmap(rDestPoint
,
92 o_rbNonBitmapActionEncountered
);
94 if( o_rbNonBitmapActionEncountered
)
99 if( (rSrcPoint
.X() != 0 && rSrcPoint
.Y() != 0) ||
100 rSrcSize
!= rBmpEx
.GetSizePixel() )
102 // crop bitmap to given source rectangle (no
103 // need to copy and convert the whole bitmap)
104 const Rectangle
aCropRect( rSrcPoint
,
106 aBmpEx
.Crop( aCropRect
);
115 // ------------------
116 // - GraphicManager -
117 // ------------------
119 GraphicManager::GraphicManager( ULONG nCacheSize
, ULONG nMaxObjCacheSize
) :
120 mpCache( new GraphicCache( *this, nCacheSize
, nMaxObjCacheSize
) )
124 // -----------------------------------------------------------------------------
126 GraphicManager::~GraphicManager()
128 for( void* pObj
= maObjList
.First(); pObj
; pObj
= maObjList
.Next() )
129 ( (GraphicObject
*) pObj
)->GraphicManagerDestroyed();
134 // -----------------------------------------------------------------------------
136 void GraphicManager::SetMaxCacheSize( ULONG nNewCacheSize
)
138 mpCache
->SetMaxDisplayCacheSize( nNewCacheSize
);
141 // -----------------------------------------------------------------------------
143 ULONG
GraphicManager::GetMaxCacheSize() const
145 return mpCache
->GetMaxDisplayCacheSize();
148 // -----------------------------------------------------------------------------
150 void GraphicManager::SetMaxObjCacheSize( ULONG nNewMaxObjSize
, BOOL bDestroyGreaterCached
)
152 mpCache
->SetMaxObjDisplayCacheSize( nNewMaxObjSize
, bDestroyGreaterCached
);
155 // -----------------------------------------------------------------------------
157 ULONG
GraphicManager::GetMaxObjCacheSize() const
159 return mpCache
->GetMaxObjDisplayCacheSize();
162 // -----------------------------------------------------------------------------
164 ULONG
GraphicManager::GetUsedCacheSize() const
166 return mpCache
->GetUsedDisplayCacheSize();
169 // -----------------------------------------------------------------------------
171 ULONG
GraphicManager::GetFreeCacheSize() const
173 return mpCache
->GetFreeDisplayCacheSize();
176 // -----------------------------------------------------------------------------
178 void GraphicManager::SetCacheTimeout( ULONG nTimeoutSeconds
)
180 mpCache
->SetCacheTimeout( nTimeoutSeconds
);
183 // -----------------------------------------------------------------------------
185 ULONG
GraphicManager::GetCacheTimeout() const
187 return mpCache
->GetCacheTimeout();
190 // -----------------------------------------------------------------------------
192 void GraphicManager::ClearCache()
194 mpCache
->ClearDisplayCache();
197 // -----------------------------------------------------------------------------
199 void GraphicManager::ReleaseFromCache( const GraphicObject
& /*rObj*/ )
204 // -----------------------------------------------------------------------------
206 BOOL
GraphicManager::IsInCache( OutputDevice
* pOut
, const Point
& rPt
,
207 const Size
& rSz
, const GraphicObject
& rObj
,
208 const GraphicAttr
& rAttr
) const
210 return mpCache
->IsInDisplayCache( pOut
, rPt
, rSz
, rObj
, rAttr
);
213 // -----------------------------------------------------------------------------
215 BOOL
GraphicManager::DrawObj( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
216 GraphicObject
& rObj
, const GraphicAttr
& rAttr
,
217 const ULONG nFlags
, BOOL
& rCached
)
225 if( ( rObj
.GetType() == GRAPHIC_BITMAP
) || ( rObj
.GetType() == GRAPHIC_GDIMETAFILE
) )
227 // create output and fill cache
228 const Size
aOutSize( pOut
->GetOutputSizePixel() );
230 if( rObj
.IsAnimated() || ( pOut
->GetOutDevType() == OUTDEV_PRINTER
) ||
231 ( !( nFlags
& GRFMGR_DRAW_NO_SUBSTITUTE
) &&
232 ( ( nFlags
& GRFMGR_DRAW_SUBSTITUTE
) ||
233 !( nFlags
& GRFMGR_DRAW_CACHED
) ||
234 ( pOut
->GetConnectMetaFile() && !pOut
->IsOutputEnabled() ) ) ) )
236 // simple output of transformed graphic
237 const Graphic
aGraphic( rObj
.GetTransformedGraphic( &rAttr
) );
239 if( aGraphic
.IsSupportedGraphic() )
241 const USHORT nRot10
= rAttr
.GetRotation() % 3600;
245 Polygon
aPoly( Rectangle( aPt
, aSz
) );
247 aPoly
.Rotate( aPt
, nRot10
);
248 const Rectangle
aRotBoundRect( aPoly
.GetBoundRect() );
249 aPt
= aRotBoundRect
.TopLeft();
250 aSz
= aRotBoundRect
.GetSize();
253 aGraphic
.Draw( pOut
, aPt
, aSz
);
261 // cached/direct drawing
262 if( !mpCache
->DrawDisplayCacheObj( pOut
, aPt
, aSz
, rObj
, rAttr
) )
263 bRet
= ImplDraw( pOut
, aPt
, aSz
, rObj
, rAttr
, nFlags
, rCached
);
265 bRet
= rCached
= TRUE
;
272 // -----------------------------------------------------------------------------
274 void GraphicManager::ImplRegisterObj( const GraphicObject
& rObj
, Graphic
& rSubstitute
,
275 const ByteString
* pID
, const GraphicObject
* pCopyObj
)
277 maObjList
.Insert( (void*) &rObj
, LIST_APPEND
);
278 mpCache
->AddGraphicObject( rObj
, rSubstitute
, pID
, pCopyObj
);
281 // -----------------------------------------------------------------------------
283 void GraphicManager::ImplUnregisterObj( const GraphicObject
& rObj
)
285 mpCache
->ReleaseGraphicObject( rObj
);
286 maObjList
.Remove( (void*) &rObj
);
289 // -----------------------------------------------------------------------------
291 void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject
& rObj
)
293 mpCache
->GraphicObjectWasSwappedOut( rObj
);
296 // -----------------------------------------------------------------------------
298 ByteString
GraphicManager::ImplGetUniqueID( const GraphicObject
& rObj
) const
300 return mpCache
->GetUniqueID( rObj
);
303 // -----------------------------------------------------------------------------
305 BOOL
GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject
& rObj
, Graphic
& rSubstitute
)
307 return( mpCache
->FillSwappedGraphicObject( rObj
, rSubstitute
) );
310 // -----------------------------------------------------------------------------
312 void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject
& rObj
)
314 mpCache
->GraphicObjectWasSwappedIn( rObj
);
317 // -----------------------------------------------------------------------------
319 BOOL
GraphicManager::ImplDraw( OutputDevice
* pOut
, const Point
& rPt
,
320 const Size
& rSz
, GraphicObject
& rObj
,
321 const GraphicAttr
& rAttr
,
322 const ULONG nFlags
, BOOL
& rCached
)
324 const Graphic
& rGraphic
= rObj
.GetGraphic();
327 if( rGraphic
.IsSupportedGraphic() && !rGraphic
.IsSwapOut() )
329 if( GRAPHIC_BITMAP
== rGraphic
.GetType() )
331 const BitmapEx
aSrcBmpEx( rGraphic
.GetBitmapEx() );
333 // #i46805# No point in caching a bitmap that is rendered
334 // via RectFill on the OutDev
335 if( !(pOut
->GetDrawMode() & ( DRAWMODE_BLACKBITMAP
| DRAWMODE_WHITEBITMAP
)) &&
336 mpCache
->IsDisplayCacheable( pOut
, rPt
, rSz
, rObj
, rAttr
) )
340 if( ImplCreateOutput( pOut
, rPt
, rSz
, aSrcBmpEx
, rAttr
, nFlags
, &aDstBmpEx
) )
342 rCached
= mpCache
->CreateDisplayCacheObj( pOut
, rPt
, rSz
, rObj
, rAttr
, aDstBmpEx
);
348 bRet
= ImplCreateOutput( pOut
, rPt
, rSz
, aSrcBmpEx
, rAttr
, nFlags
);
352 const GDIMetaFile
& rSrcMtf
= rGraphic
.GetGDIMetaFile();
354 if( mpCache
->IsDisplayCacheable( pOut
, rPt
, rSz
, rObj
, rAttr
) )
357 BitmapEx aContainedBmpEx
;
359 if( ImplCreateOutput( pOut
, rPt
, rSz
, rSrcMtf
, rAttr
, nFlags
, aDstMtf
, aContainedBmpEx
) )
361 if( !!aContainedBmpEx
)
363 // #117889# Use bitmap output method, if
364 // metafile basically contains only a single
368 if( ImplCreateOutput( pOut
, rPt
, rSz
, aContainedBmpEx
, rAttr
, nFlags
, &aDstBmpEx
) )
370 rCached
= mpCache
->CreateDisplayCacheObj( pOut
, rPt
, rSz
, rObj
, rAttr
, aDstBmpEx
);
376 rCached
= mpCache
->CreateDisplayCacheObj( pOut
, rPt
, rSz
, rObj
, rAttr
, aDstMtf
);
384 const Graphic
aGraphic( rObj
.GetTransformedGraphic( &rAttr
) );
386 if( aGraphic
.IsSupportedGraphic() )
388 aGraphic
.Draw( pOut
, rPt
, rSz
);
398 // -----------------------------------------------------------------------------
400 BOOL
GraphicManager::ImplCreateOutput( OutputDevice
* pOut
,
401 const Point
& rPt
, const Size
& rSz
,
402 const BitmapEx
& rBmpEx
, const GraphicAttr
& rAttr
,
403 const ULONG nFlags
, BitmapEx
* pBmpEx
)
405 USHORT nRot10
= rAttr
.GetRotation() % 3600;
408 Size
aUnrotatedSzPix( pOut
->LogicToPixel( rSz
) );
413 Polygon
aPoly( Rectangle( rPt
, rSz
) );
415 aPoly
.Rotate( rPt
, nRot10
);
416 const Rectangle
aRotBoundRect( aPoly
.GetBoundRect() );
417 aOutPtPix
= pOut
->LogicToPixel( aRotBoundRect
.TopLeft() );
418 aOutSzPix
= pOut
->LogicToPixel( aRotBoundRect
.GetSize() );
422 aOutPtPix
= pOut
->LogicToPixel( rPt
);
423 aOutSzPix
= aUnrotatedSzPix
;
426 if( aUnrotatedSzPix
.Width() && aUnrotatedSzPix
.Height() )
428 BitmapEx
aBmpEx( rBmpEx
);
432 const Size
& rBmpSzPix
= rBmpEx
.GetSizePixel();
433 const long nW
= rBmpSzPix
.Width();
434 const long nH
= rBmpSzPix
.Height();
435 const long nNewW
= aUnrotatedSzPix
.Width();
436 const long nNewH
= aUnrotatedSzPix
.Height();
438 long* pMapIX
= new long[ nNewW
];
439 long* pMapFX
= new long[ nNewW
];
440 long* pMapIY
= new long[ nNewH
];
441 long* pMapFY
= new long[ nNewH
];
442 long nStartX
= -1, nStartY
= -1, nEndX
= -1, nEndY
= -1;
443 long nX
, nY
, nTmp
, nTmpX
, nTmpY
;
444 BOOL bHMirr
= ( rAttr
.GetMirrorFlags() & BMP_MIRROR_HORZ
) != 0;
445 BOOL bVMirr
= ( rAttr
.GetMirrorFlags() & BMP_MIRROR_VERT
) != 0;
447 if( nFlags
& GRFMGR_DRAW_BILINEAR
)
449 const double fRevScaleX
= ( nNewW
> 1L ) ? ( (double) ( nW
- 1L ) / ( nNewW
- 1L ) ) : 0.0;
450 const double fRevScaleY
= ( nNewH
> 1L ) ? ( (double) ( nH
- 1L ) / ( nNewH
- 1L ) ) : 0.0;
452 // create horizontal mapping table
453 for( nX
= 0L, nTmpX
= nW
- 1L, nTmp
= nW
- 2L; nX
< nNewW
; nX
++ )
455 fTmp
= nX
* fRevScaleX
;
460 pMapFX
[ nX
] = (long) ( ( fTmp
- ( pMapIX
[ nX
] = MinMax( (long) fTmp
, 0, nTmp
) ) ) * 1048576. );
463 // create vertical mapping table
464 for( nY
= 0L, nTmpY
= nH
- 1L, nTmp
= nH
- 2L; nY
< nNewH
; nY
++ )
466 fTmp
= nY
* fRevScaleY
;
471 pMapFY
[ nY
] = (long) ( ( fTmp
- ( pMapIY
[ nY
] = MinMax( (long) fTmp
, 0, nTmp
) ) ) * 1048576. );
476 // #98290# Use a different mapping for non-interpolating mode, to avoid missing rows/columns
477 const double fRevScaleX
= ( nNewW
> 1L ) ? ( (double) nW
/ nNewW
) : 0.0;
478 const double fRevScaleY
= ( nNewH
> 1L ) ? ( (double) nH
/ nNewH
) : 0.0;
480 // create horizontal mapping table
481 for( nX
= 0L, nTmpX
= nW
- 1L, nTmp
= nW
- 2L; nX
< nNewW
; nX
++ )
483 fTmp
= nX
* fRevScaleX
;
488 // #98290# Do not use round to zero, otherwise last column will be missing
489 pMapIX
[ nX
] = MinMax( (long) fTmp
, 0, nTmp
);
490 pMapFX
[ nX
] = fTmp
>= nTmp
+1 ? 1048576 : 0;
493 // create vertical mapping table
494 for( nY
= 0L, nTmpY
= nH
- 1L, nTmp
= nH
- 2L; nY
< nNewH
; nY
++ )
496 fTmp
= nY
* fRevScaleY
;
501 // #98290# Do not use round to zero, otherwise last row will be missing
502 pMapIY
[ nY
] = MinMax( (long) fTmp
, 0, nTmp
);
503 pMapFY
[ nY
] = fTmp
>= nTmp
+1 ? 1048576 : 0;
507 // calculate output sizes
511 Rectangle
aOutRect( aPt
, pOut
->GetOutputSizePixel() );
512 Rectangle
aBmpRect( aOutPtPix
, aOutSzPix
);
514 if( pOut
->GetOutDevType() == OUTDEV_WINDOW
)
516 const Region
aPaintRgn( ( (Window
*) pOut
)->GetPaintRegion() );
517 if( !aPaintRgn
.IsNull() )
518 aOutRect
.Intersection( pOut
->LogicToPixel( aPaintRgn
.GetBoundRect() ) );
521 aOutRect
.Intersection( aBmpRect
);
523 if( !aOutRect
.IsEmpty() )
525 aOutPt
= pOut
->PixelToLogic( aOutRect
.TopLeft() );
526 aOutSz
= pOut
->PixelToLogic( aOutRect
.GetSize() );
527 nStartX
= aOutRect
.Left() - aBmpRect
.Left();
528 nStartY
= aOutRect
.Top() - aBmpRect
.Top();
529 nEndX
= aOutRect
.Right() - aBmpRect
.Left();
530 nEndY
= aOutRect
.Bottom() - aBmpRect
.Top();
533 nStartX
= -1L; // invalid
537 aOutPt
= pOut
->PixelToLogic( aOutPtPix
);
538 aOutSz
= pOut
->PixelToLogic( aOutSzPix
);
539 nStartX
= nStartY
= 0;
540 nEndX
= aOutSzPix
.Width() - 1L;
541 nEndY
= aOutSzPix
.Height() - 1L;
547 const BOOL bSimple
= ( 1 == nW
|| 1 == nH
);
553 bRet
= ( aOutBmpEx
= aBmpEx
).Scale( aUnrotatedSzPix
);
556 aOutBmpEx
.Rotate( nRot10
, COL_TRANSPARENT
);
560 bRet
= ImplCreateRotatedScaled( aBmpEx
,
561 nRot10
, aOutSzPix
, aUnrotatedSzPix
,
562 pMapIX
, pMapFX
, pMapIY
, pMapFY
, nStartX
, nEndX
, nStartY
, nEndY
,
568 // #105229# Don't scale if output size equals bitmap size
569 // #107226# Copy through only if we're not mirroring
570 if( !bHMirr
&& !bVMirr
&& aOutSzPix
== rBmpSzPix
)
572 // #107226# Use original dimensions when just copying through
573 aOutPt
= pOut
->PixelToLogic( aOutPtPix
);
574 aOutSz
= pOut
->PixelToLogic( aOutSzPix
);
581 bRet
= ( aOutBmpEx
= aBmpEx
).Scale( Size( nEndX
- nStartX
+ 1, nEndY
- nStartY
+ 1 ) );
584 bRet
= ImplCreateScaled( aBmpEx
,
585 pMapIX
, pMapFX
, pMapIY
, pMapFY
,
586 nStartX
, nEndX
, nStartY
, nEndY
,
594 // attribute adjustment if neccessary
595 if( rAttr
.IsSpecialDrawMode() || rAttr
.IsAdjusted() || rAttr
.IsTransparent() )
596 ImplAdjust( aOutBmpEx
, rAttr
, ADJUSTMENT_DRAWMODE
| ADJUSTMENT_COLORS
| ADJUSTMENT_TRANSPARENCY
);
598 // OutDev adjustment if neccessary
599 if( pOut
->GetOutDevType() != OUTDEV_PRINTER
&& pOut
->GetBitCount() <= 8 && aOutBmpEx
.GetBitCount() >= 8 )
600 aOutBmpEx
.Dither( BMP_DITHER_MATRIX
);
604 // delete lookup tables
614 pOut
->DrawBitmapEx( aOutPt
, aOutSz
, aOutBmpEx
);
617 if( !rAttr
.IsTransparent() && !aOutBmpEx
.IsAlpha() )
618 aOutBmpEx
= BitmapEx( aOutBmpEx
.GetBitmap().CreateDisplayBitmap( pOut
), aOutBmpEx
.GetMask() );
620 pOut
->DrawBitmapEx( aOutPt
, aOutSz
, *pBmpEx
= aOutBmpEx
);
628 // -----------------------------------------------------------------------------
630 BOOL
GraphicManager::ImplCreateOutput( OutputDevice
* pOut
,
631 const Point
& rPt
, const Size
& rSz
,
632 const GDIMetaFile
& rMtf
, const GraphicAttr
& rAttr
,
633 const ULONG
/*nFlags*/, GDIMetaFile
& rOutMtf
, BitmapEx
& rOutBmpEx
)
635 const Size
aNewSize( rMtf
.GetPrefSize() );
639 // #117889# count bitmap actions, and flag actions that paint, but
641 sal_Int32
nNumBitmaps(0);
642 bool bNonBitmapActionEncountered(false);
643 if( aNewSize
.Width() && aNewSize
.Height() && rSz
.Width() && rSz
.Height() )
645 const double fGrfWH
= (double) aNewSize
.Width() / aNewSize
.Height();
646 const double fOutWH
= (double) rSz
.Width() / rSz
.Height();
648 const double fScaleX
= fOutWH
/ fGrfWH
;
649 const double fScaleY
= 1.0;
651 const MapMode
& rPrefMapMode( rMtf
.GetPrefMapMode() );
652 const Size
& rSizePix( pOut
->LogicToPixel( aNewSize
,
655 // taking care of font width default if scaling metafile.
656 // #117889# use existing metafile scan, to determine whether
657 // the metafile basically displays a single bitmap. Note that
658 // the solution, as implemented here, is quite suboptimal (the
659 // cases where a mtf consisting basically of a single bitmap,
660 // that fail to pass the test below, are probably frequent). A
661 // better solution would involve FSAA, but that's currently
662 // expensive, and might trigger bugs on display drivers, if
663 // VDevs get bigger than the actual screen.
666 for( nCurPos
= 0, pAct
= (MetaAction
*)rOutMtf
.FirstAction(); pAct
;
667 pAct
= (MetaAction
*)rOutMtf
.NextAction(), nCurPos
++ )
669 MetaAction
* pModAct
= NULL
;
670 switch( pAct
->GetType() )
672 case META_FONT_ACTION
:
674 MetaFontAction
* pA
= (MetaFontAction
*)pAct
;
675 Font
aFont( pA
->GetFont() );
676 if ( !aFont
.GetWidth() )
678 FontMetric
aFontMetric( pOut
->GetFontMetric( aFont
) );
679 aFont
.SetWidth( aFontMetric
.GetWidth() );
680 pModAct
= new MetaFontAction( aFont
);
683 // FALLTHROUGH intended
684 case META_NULL_ACTION
:
685 // FALLTHROUGH intended
687 // OutDev state changes (which don't affect bitmap
689 case META_LINECOLOR_ACTION
:
690 // FALLTHROUGH intended
691 case META_FILLCOLOR_ACTION
:
692 // FALLTHROUGH intended
693 case META_TEXTCOLOR_ACTION
:
694 // FALLTHROUGH intended
695 case META_TEXTFILLCOLOR_ACTION
:
696 // FALLTHROUGH intended
697 case META_TEXTALIGN_ACTION
:
698 // FALLTHROUGH intended
699 case META_TEXTLINECOLOR_ACTION
:
700 // FALLTHROUGH intended
701 case META_TEXTLINE_ACTION
:
702 // FALLTHROUGH intended
703 case META_PUSH_ACTION
:
704 // FALLTHROUGH intended
705 case META_POP_ACTION
:
706 // FALLTHROUGH intended
707 case META_LAYOUTMODE_ACTION
:
708 // FALLTHROUGH intended
709 case META_TEXTLANGUAGE_ACTION
:
710 // FALLTHROUGH intended
711 case META_COMMENT_ACTION
:
714 // bitmap output methods
715 case META_BMP_ACTION
:
716 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
718 MetaBmpAction
* pAction
= (MetaBmpAction
*)pAct
;
720 rOutBmpEx
= BitmapEx( pAction
->GetBitmap() );
721 muckWithBitmap( pOut
->LogicToPixel( pAction
->GetPoint(),
723 pAction
->GetBitmap().GetSizePixel(),
725 bNonBitmapActionEncountered
);
730 case META_BMPSCALE_ACTION
:
731 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
733 MetaBmpScaleAction
* pAction
= (MetaBmpScaleAction
*)pAct
;
735 rOutBmpEx
= BitmapEx( pAction
->GetBitmap() );
736 muckWithBitmap( pOut
->LogicToPixel( pAction
->GetPoint(),
738 pOut
->LogicToPixel( pAction
->GetSize(),
741 bNonBitmapActionEncountered
);
746 case META_BMPSCALEPART_ACTION
:
747 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
749 MetaBmpScalePartAction
* pAction
= (MetaBmpScalePartAction
*)pAct
;
751 rOutBmpEx
= muckWithBitmap( BitmapEx( pAction
->GetBitmap() ),
752 pAction
->GetSrcPoint(),
753 pAction
->GetSrcSize(),
754 pOut
->LogicToPixel( pAction
->GetDestPoint(),
756 pOut
->LogicToPixel( pAction
->GetDestSize(),
759 bNonBitmapActionEncountered
);
764 case META_BMPEX_ACTION
:
765 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
767 MetaBmpExAction
* pAction
= (MetaBmpExAction
*)pAct
;
769 rOutBmpEx
= pAction
->GetBitmapEx();
770 muckWithBitmap( pOut
->LogicToPixel( pAction
->GetPoint(),
772 pAction
->GetBitmapEx().GetSizePixel(),
774 bNonBitmapActionEncountered
);
779 case META_BMPEXSCALE_ACTION
:
780 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
782 MetaBmpExScaleAction
* pAction
= (MetaBmpExScaleAction
*)pAct
;
784 rOutBmpEx
= pAction
->GetBitmapEx();
785 muckWithBitmap( pOut
->LogicToPixel( pAction
->GetPoint(),
787 pOut
->LogicToPixel( pAction
->GetSize(),
790 bNonBitmapActionEncountered
);
795 case META_BMPEXSCALEPART_ACTION
:
796 if( !nNumBitmaps
&& !bNonBitmapActionEncountered
)
798 MetaBmpExScalePartAction
* pAction
= (MetaBmpExScalePartAction
*)pAct
;
800 rOutBmpEx
= muckWithBitmap( pAction
->GetBitmapEx(),
801 pAction
->GetSrcPoint(),
802 pAction
->GetSrcSize(),
803 pOut
->LogicToPixel( pAction
->GetDestPoint(),
805 pOut
->LogicToPixel( pAction
->GetDestSize(),
808 bNonBitmapActionEncountered
);
813 // these actions actually output something (that's
814 // different from a bitmap)
815 case META_RASTEROP_ACTION
:
816 if( ((MetaRasterOpAction
*)pAct
)->GetRasterOp() == ROP_OVERPAINT
)
818 // FALLTHROUGH intended
819 case META_PIXEL_ACTION
:
820 // FALLTHROUGH intended
821 case META_POINT_ACTION
:
822 // FALLTHROUGH intended
823 case META_LINE_ACTION
:
824 // FALLTHROUGH intended
825 case META_RECT_ACTION
:
826 // FALLTHROUGH intended
827 case META_ROUNDRECT_ACTION
:
828 // FALLTHROUGH intended
829 case META_ELLIPSE_ACTION
:
830 // FALLTHROUGH intended
831 case META_ARC_ACTION
:
832 // FALLTHROUGH intended
833 case META_PIE_ACTION
:
834 // FALLTHROUGH intended
835 case META_CHORD_ACTION
:
836 // FALLTHROUGH intended
837 case META_POLYLINE_ACTION
:
838 // FALLTHROUGH intended
839 case META_POLYGON_ACTION
:
840 // FALLTHROUGH intended
841 case META_POLYPOLYGON_ACTION
:
842 // FALLTHROUGH intended
844 case META_TEXT_ACTION
:
845 // FALLTHROUGH intended
846 case META_TEXTARRAY_ACTION
:
847 // FALLTHROUGH intended
848 case META_STRETCHTEXT_ACTION
:
849 // FALLTHROUGH intended
850 case META_TEXTRECT_ACTION
:
851 // FALLTHROUGH intended
853 case META_MASK_ACTION
:
854 // FALLTHROUGH intended
855 case META_MASKSCALE_ACTION
:
856 // FALLTHROUGH intended
857 case META_MASKSCALEPART_ACTION
:
858 // FALLTHROUGH intended
860 case META_GRADIENT_ACTION
:
861 // FALLTHROUGH intended
862 case META_HATCH_ACTION
:
863 // FALLTHROUGH intended
864 case META_WALLPAPER_ACTION
:
865 // FALLTHROUGH intended
867 case META_TRANSPARENT_ACTION
:
868 // FALLTHROUGH intended
869 case META_EPS_ACTION
:
870 // FALLTHROUGH intended
871 case META_FLOATTRANSPARENT_ACTION
:
872 // FALLTHROUGH intended
873 case META_GRADIENTEX_ACTION
:
874 // FALLTHROUGH intended
876 // OutDev state changes that _do_ affect bitmap
878 case META_CLIPREGION_ACTION
:
879 // FALLTHROUGH intended
880 case META_ISECTRECTCLIPREGION_ACTION
:
881 // FALLTHROUGH intended
882 case META_ISECTREGIONCLIPREGION_ACTION
:
883 // FALLTHROUGH intended
884 case META_MOVECLIPREGION_ACTION
:
885 // FALLTHROUGH intended
887 case META_MAPMODE_ACTION
:
888 // FALLTHROUGH intended
889 case META_REFPOINT_ACTION
:
890 // FALLTHROUGH intended
892 bNonBitmapActionEncountered
= true;
897 rOutMtf
.ReplaceAction( pModAct
, nCurPos
);
902 if( pAct
->GetRefCount() > 1 )
904 rOutMtf
.ReplaceAction( pModAct
= pAct
->Clone(), nCurPos
);
910 pModAct
->Scale( fScaleX
, fScaleY
);
912 rOutMtf
.SetPrefSize( Size( FRound( aNewSize
.Width() * fScaleX
),
913 FRound( aNewSize
.Height() * fScaleY
) ) );
916 if( nNumBitmaps
!= 1 || bNonBitmapActionEncountered
)
918 if( rAttr
.IsSpecialDrawMode() || rAttr
.IsAdjusted() || rAttr
.IsMirrored() || rAttr
.IsRotated() || rAttr
.IsTransparent() )
919 ImplAdjust( rOutMtf
, rAttr
, ADJUSTMENT_ALL
);
921 ImplDraw( pOut
, rPt
, rSz
, rOutMtf
, rAttr
);
922 rOutBmpEx
= BitmapEx();
928 // -----------------------------------------------------------------------------
930 BOOL
GraphicManager::ImplCreateScaled( const BitmapEx
& rBmpEx
,
931 long* pMapIX
, long* pMapFX
, long* pMapIY
, long* pMapFY
,
932 long nStartX
, long nEndX
, long nStartY
, long nEndY
,
933 BitmapEx
& rOutBmpEx
)
935 Bitmap
aBmp( rBmpEx
.GetBitmap() );
937 BitmapReadAccess
* pAcc
= aBmp
.AcquireReadAccess();
938 BitmapWriteAccess
* pWAcc
;
939 BitmapColor aCol0
, aCol1
, aColRes
;
940 const long nDstW
= nEndX
- nStartX
+ 1L;
941 const long nDstH
= nEndY
- nStartY
+ 1L;
942 long nX
, nY
, nTmpX
, nTmpY
, nTmpFX
, nTmpFY
;
944 BYTE cR0
, cG0
, cB0
, cR1
, cG1
, cB1
;
947 DBG_ASSERT( aBmp
.GetSizePixel() == rBmpEx
.GetSizePixel(),
948 "GraphicManager::ImplCreateScaled(): bmp size inconsistent" );
952 aOutBmp
= Bitmap( Size( nDstW
, nDstH
), 24 );
953 pWAcc
= aOutBmp
.AcquireWriteAccess();
957 if( pAcc
->HasPalette() )
959 if( pAcc
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
961 Scanline pLine0
, pLine1
;
963 for( nY
= nStartY
, nYDst
= 0L; nY
<= nEndY
; nY
++, nYDst
++ )
965 nTmpY
= pMapIY
[ nY
]; nTmpFY
= pMapFY
[ nY
];
966 pLine0
= pAcc
->GetScanline( nTmpY
);
967 pLine1
= pAcc
->GetScanline( ++nTmpY
);
969 for( nX
= nStartX
, nXDst
= 0L; nX
<= nEndX
; nX
++ )
971 nTmpX
= pMapIX
[ nX
]; nTmpFX
= pMapFX
[ nX
];
973 const BitmapColor
& rCol0
= pAcc
->GetPaletteColor( pLine0
[ nTmpX
] );
974 const BitmapColor
& rCol2
= pAcc
->GetPaletteColor( pLine1
[ nTmpX
] );
975 const BitmapColor
& rCol1
= pAcc
->GetPaletteColor( pLine0
[ ++nTmpX
] );
976 const BitmapColor
& rCol3
= pAcc
->GetPaletteColor( pLine1
[ nTmpX
] );
978 cR0
= MAP( rCol0
.GetRed(), rCol1
.GetRed(), nTmpFX
);
979 cG0
= MAP( rCol0
.GetGreen(), rCol1
.GetGreen(), nTmpFX
);
980 cB0
= MAP( rCol0
.GetBlue(), rCol1
.GetBlue(), nTmpFX
);
982 cR1
= MAP( rCol2
.GetRed(), rCol3
.GetRed(), nTmpFX
);
983 cG1
= MAP( rCol2
.GetGreen(), rCol3
.GetGreen(), nTmpFX
);
984 cB1
= MAP( rCol2
.GetBlue(), rCol3
.GetBlue(), nTmpFX
);
986 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
987 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
988 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
989 pWAcc
->SetPixel( nYDst
, nXDst
++, aColRes
);
995 for( nY
= nStartY
, nYDst
= 0L; nY
<= nEndY
; nY
++, nYDst
++ )
997 nTmpY
= pMapIY
[ nY
], nTmpFY
= pMapFY
[ nY
];
999 for( nX
= nStartX
, nXDst
= 0L; nX
<= nEndX
; nX
++ )
1001 nTmpX
= pMapIX
[ nX
]; nTmpFX
= pMapFX
[ nX
];
1003 aCol0
= pAcc
->GetPaletteColor( pAcc
->GetPixel( nTmpY
, nTmpX
) );
1004 aCol1
= pAcc
->GetPaletteColor( pAcc
->GetPixel( nTmpY
, ++nTmpX
) );
1005 cR0
= MAP( aCol0
.GetRed(), aCol1
.GetRed(), nTmpFX
);
1006 cG0
= MAP( aCol0
.GetGreen(), aCol1
.GetGreen(), nTmpFX
);
1007 cB0
= MAP( aCol0
.GetBlue(), aCol1
.GetBlue(), nTmpFX
);
1009 aCol1
= pAcc
->GetPaletteColor( pAcc
->GetPixel( ++nTmpY
, nTmpX
) );
1010 aCol0
= pAcc
->GetPaletteColor( pAcc
->GetPixel( nTmpY
--, --nTmpX
) );
1011 cR1
= MAP( aCol0
.GetRed(), aCol1
.GetRed(), nTmpFX
);
1012 cG1
= MAP( aCol0
.GetGreen(), aCol1
.GetGreen(), nTmpFX
);
1013 cB1
= MAP( aCol0
.GetBlue(), aCol1
.GetBlue(), nTmpFX
);
1015 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
1016 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
1017 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
1018 pWAcc
->SetPixel( nYDst
, nXDst
++, aColRes
);
1025 if( pAcc
->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR
)
1027 Scanline pLine0
, pLine1
, pTmp0
, pTmp1
;
1030 for( nY
= nStartY
, nYDst
= 0L; nY
<= nEndY
; nY
++, nYDst
++ )
1032 nTmpY
= pMapIY
[ nY
]; nTmpFY
= pMapFY
[ nY
];
1033 pLine0
= pAcc
->GetScanline( nTmpY
);
1034 pLine1
= pAcc
->GetScanline( ++nTmpY
);
1036 for( nX
= nStartX
, nXDst
= 0L; nX
<= nEndX
; nX
++ )
1038 nOff
= 3L * ( nTmpX
= pMapIX
[ nX
] );
1039 nTmpFX
= pMapFX
[ nX
];
1041 pTmp1
= ( pTmp0
= pLine0
+ nOff
) + 3L;
1042 cB0
= MAP( *pTmp0
, *pTmp1
, nTmpFX
); pTmp0
++; pTmp1
++;
1043 cG0
= MAP( *pTmp0
, *pTmp1
, nTmpFX
); pTmp0
++; pTmp1
++;
1044 cR0
= MAP( *pTmp0
, *pTmp1
, nTmpFX
);
1046 pTmp1
= ( pTmp0
= pLine1
+ nOff
) + 3L;
1047 cB1
= MAP( *pTmp0
, *pTmp1
, nTmpFX
); pTmp0
++; pTmp1
++;
1048 cG1
= MAP( *pTmp0
, *pTmp1
, nTmpFX
); pTmp0
++; pTmp1
++;
1049 cR1
= MAP( *pTmp0
, *pTmp1
, nTmpFX
);
1051 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
1052 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
1053 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
1054 pWAcc
->SetPixel( nYDst
, nXDst
++, aColRes
);
1058 else if( pAcc
->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB
)
1060 Scanline pLine0
, pLine1
, pTmp0
, pTmp1
;
1063 for( nY
= nStartY
, nYDst
= 0L; nY
<= nEndY
; nY
++, nYDst
++ )
1065 nTmpY
= pMapIY
[ nY
]; nTmpFY
= pMapFY
[ nY
];
1066 pLine0
= pAcc
->GetScanline( nTmpY
);
1067 pLine1
= pAcc
->GetScanline( ++nTmpY
);
1069 for( nX
= nStartX
, nXDst
= 0L; nX
<= nEndX
; nX
++ )
1071 nOff
= 3L * ( nTmpX
= pMapIX
[ nX
] );
1072 nTmpFX
= pMapFX
[ nX
];
1074 pTmp1
= ( pTmp0
= pLine0
+ nOff
) + 3L;
1075 cR0
= MAP( *pTmp0
, *pTmp1
, nTmpFX
); pTmp0
++; pTmp1
++;
1076 cG0
= MAP( *pTmp0
, *pTmp1
, nTmpFX
); pTmp0
++; pTmp1
++;
1077 cB0
= MAP( *pTmp0
, *pTmp1
, nTmpFX
);
1079 pTmp1
= ( pTmp0
= pLine1
+ nOff
) + 3L;
1080 cR1
= MAP( *pTmp0
, *pTmp1
, nTmpFX
); pTmp0
++; pTmp1
++;
1081 cG1
= MAP( *pTmp0
, *pTmp1
, nTmpFX
); pTmp0
++; pTmp1
++;
1082 cB1
= MAP( *pTmp0
, *pTmp1
, nTmpFX
);
1084 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
1085 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
1086 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
1087 pWAcc
->SetPixel( nYDst
, nXDst
++, aColRes
);
1093 for( nY
= nStartY
, nYDst
= 0L; nY
<= nEndY
; nY
++, nYDst
++ )
1095 nTmpY
= pMapIY
[ nY
]; nTmpFY
= pMapFY
[ nY
];
1097 for( nX
= nStartX
, nXDst
= 0L; nX
<= nEndX
; nX
++ )
1099 nTmpX
= pMapIX
[ nX
]; nTmpFX
= pMapFX
[ nX
];
1101 aCol0
= pAcc
->GetPixel( nTmpY
, nTmpX
);
1102 aCol1
= pAcc
->GetPixel( nTmpY
, ++nTmpX
);
1103 cR0
= MAP( aCol0
.GetRed(), aCol1
.GetRed(), nTmpFX
);
1104 cG0
= MAP( aCol0
.GetGreen(), aCol1
.GetGreen(), nTmpFX
);
1105 cB0
= MAP( aCol0
.GetBlue(), aCol1
.GetBlue(), nTmpFX
);
1107 aCol1
= pAcc
->GetPixel( ++nTmpY
, nTmpX
);
1108 aCol0
= pAcc
->GetPixel( nTmpY
--, --nTmpX
);
1109 cR1
= MAP( aCol0
.GetRed(), aCol1
.GetRed(), nTmpFX
);
1110 cG1
= MAP( aCol0
.GetGreen(), aCol1
.GetGreen(), nTmpFX
);
1111 cB1
= MAP( aCol0
.GetBlue(), aCol1
.GetBlue(), nTmpFX
);
1113 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
1114 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
1115 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
1116 pWAcc
->SetPixel( nYDst
, nXDst
++, aColRes
);
1122 aOutBmp
.ReleaseAccess( pWAcc
);
1126 aBmp
.ReleaseAccess( pAcc
);
1129 if( bRet
&& rBmpEx
.IsTransparent() )
1133 if( rBmpEx
.IsAlpha() )
1135 DBG_ASSERT( rBmpEx
.GetAlpha().GetSizePixel() == rBmpEx
.GetSizePixel(),
1136 "GraphicManager::ImplCreateScaled(): alpha mask size inconsistent" );
1138 AlphaMask
aAlpha( rBmpEx
.GetAlpha() );
1139 AlphaMask aOutAlpha
;
1141 pAcc
= aAlpha
.AcquireReadAccess();
1145 aOutAlpha
= AlphaMask( Size( nDstW
, nDstH
) );
1146 pWAcc
= aOutAlpha
.AcquireWriteAccess();
1150 if( pAcc
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
&&
1151 pWAcc
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
1153 Scanline pLine0
, pLine1
, pLineW
;
1155 for( nY
= nStartY
, nYDst
= 0L; nY
<= nEndY
; nY
++, nYDst
++ )
1157 nTmpY
= pMapIY
[ nY
]; nTmpFY
= pMapFY
[ nY
];
1158 pLine0
= pAcc
->GetScanline( nTmpY
);
1159 pLine1
= pAcc
->GetScanline( ++nTmpY
);
1160 pLineW
= pWAcc
->GetScanline( nYDst
);
1162 for( nX
= nStartX
, nXDst
= 0L; nX
<= nEndX
; nX
++, nXDst
++ )
1164 nTmpX
= pMapIX
[ nX
]; nTmpFX
= pMapFX
[ nX
];
1166 const long nAlpha0
= pLine0
[ nTmpX
];
1167 const long nAlpha2
= pLine1
[ nTmpX
];
1168 const long nAlpha1
= pLine0
[ ++nTmpX
];
1169 const long nAlpha3
= pLine1
[ nTmpX
];
1170 const long n0
= MAP( nAlpha0
, nAlpha1
, nTmpFX
);
1171 const long n1
= MAP( nAlpha2
, nAlpha3
, nTmpFX
);
1173 *pLineW
++ = MAP( n0
, n1
, nTmpFY
);
1179 BitmapColor
aAlphaValue( 0 );
1181 for( nY
= nStartY
, nYDst
= 0L; nY
<= nEndY
; nY
++, nYDst
++ )
1183 nTmpY
= pMapIY
[ nY
], nTmpFY
= pMapFY
[ nY
];
1185 for( nX
= nStartX
, nXDst
= 0L; nX
<= nEndX
; nX
++ )
1187 nTmpX
= pMapIX
[ nX
]; nTmpFX
= pMapFX
[ nX
];
1189 long nAlpha0
= pAcc
->GetPixel( nTmpY
, nTmpX
).GetIndex();
1190 long nAlpha1
= pAcc
->GetPixel( nTmpY
, ++nTmpX
).GetIndex();
1191 const long n0
= MAP( nAlpha0
, nAlpha1
, nTmpFX
);
1193 nAlpha1
= pAcc
->GetPixel( ++nTmpY
, nTmpX
).GetIndex();
1194 nAlpha0
= pAcc
->GetPixel( nTmpY
--, --nTmpX
).GetIndex();
1195 const long n1
= MAP( nAlpha0
, nAlpha1
, nTmpFX
);
1197 aAlphaValue
.SetIndex( MAP( n0
, n1
, nTmpFY
) );
1198 pWAcc
->SetPixel( nYDst
, nXDst
++, aAlphaValue
);
1203 aOutAlpha
.ReleaseAccess( pWAcc
);
1207 aAlpha
.ReleaseAccess( pAcc
);
1210 rOutBmpEx
= BitmapEx( aOutBmp
, aOutAlpha
);
1215 DBG_ASSERT( rBmpEx
.GetMask().GetSizePixel() == rBmpEx
.GetSizePixel(),
1216 "GraphicManager::ImplCreateScaled(): mask size inconsistent" );
1218 Bitmap
aMsk( rBmpEx
.GetMask() );
1221 pAcc
= aMsk
.AcquireReadAccess();
1225 // #i40115# Use the same palette for destination
1226 // bitmap. Otherwise, we'd have to color-map even the
1227 // case below, when both masks are one bit deep.
1228 if( pAcc
->HasPalette() )
1229 aOutMsk
= Bitmap( Size( nDstW
, nDstH
),
1231 &pAcc
->GetPalette() );
1233 aOutMsk
= Bitmap( Size( nDstW
, nDstH
), 1 );
1235 pWAcc
= aOutMsk
.AcquireWriteAccess();
1239 long* pMapLX
= new long[ nDstW
];
1240 long* pMapLY
= new long[ nDstH
];
1242 // create new horizontal mapping table
1243 for( nX
= 0UL, nTmpX
= nStartX
; nX
< nDstW
; nTmpX
++ )
1244 pMapLX
[ nX
++ ] = FRound( (double) pMapIX
[ nTmpX
] + pMapFX
[ nTmpX
] / 1048576. );
1246 // create new vertical mapping table
1247 for( nY
= 0UL, nTmpY
= nStartY
; nY
< nDstH
; nTmpY
++ )
1248 pMapLY
[ nY
++ ] = FRound( (double) pMapIY
[ nTmpY
] + pMapFY
[ nTmpY
] / 1048576. );
1250 // do normal scaling
1251 if( pAcc
->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL
&&
1252 pWAcc
->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL
)
1255 for( nY
= 0; nY
< nDstH
; nY
++ )
1257 Scanline pSrc
= pAcc
->GetScanline( pMapLY
[ nY
] );
1258 Scanline pDst
= pWAcc
->GetScanline( nY
);
1260 for( nX
= 0L; nX
< nDstW
; nX
++ )
1262 const long nSrcX
= pMapLX
[ nX
];
1264 if( pSrc
[ nSrcX
>> 3 ] & ( 1 << ( 7 - ( nSrcX
& 7 ) ) ) )
1265 pDst
[ nX
>> 3 ] |= 1 << ( 7 - ( nX
& 7 ) );
1267 pDst
[ nX
>> 3 ] &= ~( 1 << ( 7 - ( nX
& 7 ) ) );
1273 const BitmapColor
aB( pAcc
->GetBestMatchingColor( Color( COL_BLACK
) ) );
1274 const BitmapColor
aWB( pWAcc
->GetBestMatchingColor( Color( COL_BLACK
) ) );
1275 const BitmapColor
aWW( pWAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
1277 if( pAcc
->HasPalette() )
1279 for( nY
= 0L; nY
< nDstH
; nY
++ )
1281 for( nX
= 0L; nX
< nDstW
; nX
++ )
1283 if( pAcc
->GetPaletteColor( (BYTE
) pAcc
->GetPixel( pMapLY
[ nY
], pMapLX
[ nX
] ) ) == aB
)
1284 pWAcc
->SetPixel( nY
, nX
, aWB
);
1286 pWAcc
->SetPixel( nY
, nX
, aWW
);
1292 for( nY
= 0L; nY
< nDstH
; nY
++ )
1294 for( nX
= 0L; nX
< nDstW
; nX
++ )
1296 if( pAcc
->GetPixel( pMapLY
[ nY
], pMapLX
[ nX
] ) == aB
)
1297 pWAcc
->SetPixel( nY
, nX
, aWB
);
1299 pWAcc
->SetPixel( nY
, nX
, aWW
);
1307 aOutMsk
.ReleaseAccess( pWAcc
);
1311 aMsk
.ReleaseAccess( pAcc
);
1314 rOutBmpEx
= BitmapEx( aOutBmp
, aOutMsk
);
1319 rOutBmpEx
= aOutBmp
;
1322 rOutBmpEx
= aOutBmp
;
1327 // -----------------------------------------------------------------------------
1329 BOOL
GraphicManager::ImplCreateRotatedScaled( const BitmapEx
& rBmpEx
,
1330 USHORT nRot10
, const Size
& /*rOutSzPix*/, const Size
& rUnrotatedSzPix
,
1331 long* pMapIX
, long* pMapFX
, long* pMapIY
, long* pMapFY
,
1332 long nStartX
, long nEndX
, long nStartY
, long nEndY
,
1333 BitmapEx
& rOutBmpEx
)
1336 Bitmap
aBmp( rBmpEx
.GetBitmap() );
1338 BitmapReadAccess
* pAcc
= aBmp
.AcquireReadAccess();
1339 BitmapWriteAccess
* pWAcc
;
1340 Polygon
aPoly( Rectangle( aPt
, rUnrotatedSzPix
) ); aPoly
.Rotate( Point(), nRot10
);
1341 Rectangle
aNewBound( aPoly
.GetBoundRect() );
1342 const double fCosAngle
= cos( nRot10
* F_PI1800
), fSinAngle
= sin( nRot10
* F_PI1800
);
1344 const long nDstW
= nEndX
- nStartX
+ 1L;
1345 const long nDstH
= nEndY
- nStartY
+ 1L;
1346 const long nUnRotW
= rUnrotatedSzPix
.Width();
1347 const long nUnRotH
= rUnrotatedSzPix
.Height();
1348 long* pCosX
= new long[ nDstW
];
1349 long* pSinX
= new long[ nDstW
];
1350 long* pCosY
= new long[ nDstH
];
1351 long* pSinY
= new long[ nDstH
];
1352 long nX
, nY
, nTmpX
, nTmpY
, nTmpFX
, nTmpFY
, nUnRotX
, nUnRotY
, nSinY
, nCosY
;
1353 BYTE cR0
, cG0
, cB0
, cR1
, cG1
, cB1
;
1356 // create horizontal mapping table
1357 for( nX
= 0L, nTmpX
= aNewBound
.Left() + nStartX
; nX
< nDstW
; nX
++ )
1359 pCosX
[ nX
] = FRound( fCosAngle
* ( fTmp
= nTmpX
++ << 8 ) );
1360 pSinX
[ nX
] = FRound( fSinAngle
* fTmp
);
1363 // create vertical mapping table
1364 for( nY
= 0L, nTmpY
= aNewBound
.Top() + nStartY
; nY
< nDstH
; nY
++ )
1366 pCosY
[ nY
] = FRound( fCosAngle
* ( fTmp
= nTmpY
++ << 8 ) );
1367 pSinY
[ nY
] = FRound( fSinAngle
* fTmp
);
1372 aOutBmp
= Bitmap( Size( nDstW
, nDstH
), 24 );
1373 pWAcc
= aOutBmp
.AcquireWriteAccess();
1377 BitmapColor aColRes
;
1379 if( pAcc
->HasPalette() )
1381 for( nY
= 0; nY
< nDstH
; nY
++ )
1383 nSinY
= pSinY
[ nY
];
1384 nCosY
= pCosY
[ nY
];
1386 for( nX
= 0; nX
< nDstW
; nX
++ )
1388 nUnRotX
= ( pCosX
[ nX
] - nSinY
) >> 8;
1389 nUnRotY
= ( pSinX
[ nX
] + nCosY
) >> 8;
1391 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< nUnRotW
) &&
1392 ( nUnRotY
>= 0L ) && ( nUnRotY
< nUnRotH
) )
1394 nTmpX
= pMapIX
[ nUnRotX
]; nTmpFX
= pMapFX
[ nUnRotX
];
1395 nTmpY
= pMapIY
[ nUnRotY
], nTmpFY
= pMapFY
[ nUnRotY
];
1397 const BitmapColor
& rCol0
= pAcc
->GetPaletteColor( pAcc
->GetPixel( nTmpY
, nTmpX
) );
1398 const BitmapColor
& rCol1
= pAcc
->GetPaletteColor( pAcc
->GetPixel( nTmpY
, ++nTmpX
) );
1399 cR0
= MAP( rCol0
.GetRed(), rCol1
.GetRed(), nTmpFX
);
1400 cG0
= MAP( rCol0
.GetGreen(), rCol1
.GetGreen(), nTmpFX
);
1401 cB0
= MAP( rCol0
.GetBlue(), rCol1
.GetBlue(), nTmpFX
);
1403 const BitmapColor
& rCol3
= pAcc
->GetPaletteColor( pAcc
->GetPixel( ++nTmpY
, nTmpX
) );
1404 const BitmapColor
& rCol2
= pAcc
->GetPaletteColor( pAcc
->GetPixel( nTmpY
, --nTmpX
) );
1405 cR1
= MAP( rCol2
.GetRed(), rCol3
.GetRed(), nTmpFX
);
1406 cG1
= MAP( rCol2
.GetGreen(), rCol3
.GetGreen(), nTmpFX
);
1407 cB1
= MAP( rCol2
.GetBlue(), rCol3
.GetBlue(), nTmpFX
);
1409 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
1410 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
1411 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
1412 pWAcc
->SetPixel( nY
, nX
, aColRes
);
1419 BitmapColor aCol0
, aCol1
;
1421 for( nY
= 0; nY
< nDstH
; nY
++ )
1423 nSinY
= pSinY
[ nY
];
1424 nCosY
= pCosY
[ nY
];
1426 for( nX
= 0; nX
< nDstW
; nX
++ )
1428 nUnRotX
= ( pCosX
[ nX
] - nSinY
) >> 8;
1429 nUnRotY
= ( pSinX
[ nX
] + nCosY
) >> 8;
1431 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< nUnRotW
) &&
1432 ( nUnRotY
>= 0L ) && ( nUnRotY
< nUnRotH
) )
1434 nTmpX
= pMapIX
[ nUnRotX
]; nTmpFX
= pMapFX
[ nUnRotX
];
1435 nTmpY
= pMapIY
[ nUnRotY
], nTmpFY
= pMapFY
[ nUnRotY
];
1437 aCol0
= pAcc
->GetPixel( nTmpY
, nTmpX
);
1438 aCol1
= pAcc
->GetPixel( nTmpY
, ++nTmpX
);
1439 cR0
= MAP( aCol0
.GetRed(), aCol1
.GetRed(), nTmpFX
);
1440 cG0
= MAP( aCol0
.GetGreen(), aCol1
.GetGreen(), nTmpFX
);
1441 cB0
= MAP( aCol0
.GetBlue(), aCol1
.GetBlue(), nTmpFX
);
1443 aCol1
= pAcc
->GetPixel( ++nTmpY
, nTmpX
);
1444 aCol0
= pAcc
->GetPixel( nTmpY
, --nTmpX
);
1445 cR1
= MAP( aCol0
.GetRed(), aCol1
.GetRed(), nTmpFX
);
1446 cG1
= MAP( aCol0
.GetGreen(), aCol1
.GetGreen(), nTmpFX
);
1447 cB1
= MAP( aCol0
.GetBlue(), aCol1
.GetBlue(), nTmpFX
);
1449 aColRes
.SetRed( MAP( cR0
, cR1
, nTmpFY
) );
1450 aColRes
.SetGreen( MAP( cG0
, cG1
, nTmpFY
) );
1451 aColRes
.SetBlue( MAP( cB0
, cB1
, nTmpFY
) );
1452 pWAcc
->SetPixel( nY
, nX
, aColRes
);
1458 aOutBmp
.ReleaseAccess( pWAcc
);
1462 aBmp
.ReleaseAccess( pAcc
);
1466 if( bRet
&& ( rBmpEx
.IsTransparent() || ( nRot10
!= 900 && nRot10
!= 1800 && nRot10
!= 2700 ) ) )
1470 if( rBmpEx
.IsAlpha() )
1472 AlphaMask
aAlpha( rBmpEx
.GetAlpha() );
1473 AlphaMask aOutAlpha
;
1475 pAcc
= aAlpha
.AcquireReadAccess();
1479 aOutAlpha
= AlphaMask( Size( nDstW
, nDstH
) );
1480 pWAcc
= aOutAlpha
.AcquireWriteAccess();
1484 if( pAcc
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
&&
1485 pWAcc
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
1487 Scanline pLine0
, pLine1
, pLineW
;
1489 for( nY
= 0; nY
< nDstH
; nY
++ )
1491 nSinY
= pSinY
[ nY
], nCosY
= pCosY
[ nY
];
1492 pLineW
= pWAcc
->GetScanline( nY
);
1494 for( nX
= 0; nX
< nDstW
; nX
++ )
1496 nUnRotX
= ( pCosX
[ nX
] - nSinY
) >> 8;
1497 nUnRotY
= ( pSinX
[ nX
] + nCosY
) >> 8;
1499 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< nUnRotW
) &&
1500 ( nUnRotY
>= 0L ) && ( nUnRotY
< nUnRotH
) )
1502 nTmpX
= pMapIX
[ nUnRotX
], nTmpFX
= pMapFX
[ nUnRotX
];
1503 nTmpY
= pMapIY
[ nUnRotY
], nTmpFY
= pMapFY
[ nUnRotY
];
1505 pLine0
= pAcc
->GetScanline( nTmpY
++ );
1506 pLine1
= pAcc
->GetScanline( nTmpY
);
1508 const long nAlpha0
= pLine0
[ nTmpX
];
1509 const long nAlpha2
= pLine1
[ nTmpX
++ ];
1510 const long nAlpha1
= pLine0
[ nTmpX
];
1511 const long nAlpha3
= pLine1
[ nTmpX
];
1512 const long n0
= MAP( nAlpha0
, nAlpha1
, nTmpFX
);
1513 const long n1
= MAP( nAlpha2
, nAlpha3
, nTmpFX
);
1515 *pLineW
++ = MAP( n0
, n1
, nTmpFY
);
1524 const BitmapColor
aTrans( pWAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
1525 BitmapColor
aAlphaVal( 0 );
1527 for( nY
= 0; nY
< nDstH
; nY
++ )
1529 nSinY
= pSinY
[ nY
], nCosY
= pCosY
[ nY
];
1531 for( nX
= 0; nX
< nDstW
; nX
++ )
1533 nUnRotX
= ( pCosX
[ nX
] - nSinY
) >> 8;
1534 nUnRotY
= ( pSinX
[ nX
] + nCosY
) >> 8;
1536 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< nUnRotW
) &&
1537 ( nUnRotY
>= 0L ) && ( nUnRotY
< nUnRotH
) )
1539 nTmpX
= pMapIX
[ nUnRotX
]; nTmpFX
= pMapFX
[ nUnRotX
];
1540 nTmpY
= pMapIY
[ nUnRotY
], nTmpFY
= pMapFY
[ nUnRotY
];
1542 const long nAlpha0
= pAcc
->GetPixel( nTmpY
, nTmpX
).GetIndex();
1543 const long nAlpha1
= pAcc
->GetPixel( nTmpY
, ++nTmpX
).GetIndex();
1544 const long nAlpha3
= pAcc
->GetPixel( ++nTmpY
, nTmpX
).GetIndex();
1545 const long nAlpha2
= pAcc
->GetPixel( nTmpY
, --nTmpX
).GetIndex();
1546 const long n0
= MAP( nAlpha0
, nAlpha1
, nTmpFX
);
1547 const long n1
= MAP( nAlpha2
, nAlpha3
, nTmpFX
);
1549 aAlphaVal
.SetIndex( MAP( n0
, n1
, nTmpFY
) );
1550 pWAcc
->SetPixel( nY
, nX
, aAlphaVal
);
1553 pWAcc
->SetPixel( nY
, nX
, aTrans
);
1558 aOutAlpha
.ReleaseAccess( pWAcc
);
1562 aAlpha
.ReleaseAccess( pAcc
);
1566 rOutBmpEx
= BitmapEx( aOutBmp
, aOutAlpha
);
1570 Bitmap
aOutMsk( Size( nDstW
, nDstH
), 1 );
1571 pWAcc
= aOutMsk
.AcquireWriteAccess();
1575 Bitmap
aMsk( rBmpEx
.GetMask() );
1576 const BitmapColor
aB( pWAcc
->GetBestMatchingColor( Color( COL_BLACK
) ) );
1577 const BitmapColor
aW( pWAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
1578 BitmapReadAccess
* pMAcc
= NULL
;
1580 if( !aMsk
|| ( ( pMAcc
= aMsk
.AcquireReadAccess() ) != NULL
) )
1582 long* pMapLX
= new long[ nUnRotW
];
1583 long* pMapLY
= new long[ nUnRotH
];
1587 aTestB
= pMAcc
->GetBestMatchingColor( Color( COL_BLACK
) );
1589 // create new horizontal mapping table
1590 for( nX
= 0UL; nX
< nUnRotW
; nX
++ )
1591 pMapLX
[ nX
] = FRound( (double) pMapIX
[ nX
] + pMapFX
[ nX
] / 1048576. );
1593 // create new vertical mapping table
1594 for( nY
= 0UL; nY
< nUnRotH
; nY
++ )
1595 pMapLY
[ nY
] = FRound( (double) pMapIY
[ nY
] + pMapFY
[ nY
] / 1048576. );
1598 for( nY
= 0; nY
< nDstH
; nY
++ )
1600 nSinY
= pSinY
[ nY
];
1601 nCosY
= pCosY
[ nY
];
1603 for( nX
= 0; nX
< nDstW
; nX
++ )
1605 nUnRotX
= ( pCosX
[ nX
] - nSinY
) >> 8;
1606 nUnRotY
= ( pSinX
[ nX
] + nCosY
) >> 8;
1608 if( ( nUnRotX
>= 0L ) && ( nUnRotX
< nUnRotW
) &&
1609 ( nUnRotY
>= 0L ) && ( nUnRotY
< nUnRotH
) )
1613 if( pMAcc
->GetPixel( pMapLY
[ nUnRotY
], pMapLX
[ nUnRotX
] ) == aTestB
)
1614 pWAcc
->SetPixel( nY
, nX
, aB
);
1616 pWAcc
->SetPixel( nY
, nX
, aW
);
1619 pWAcc
->SetPixel( nY
, nX
, aB
);
1622 pWAcc
->SetPixel( nY
, nX
, aW
);
1630 aMsk
.ReleaseAccess( pMAcc
);
1635 aOutMsk
.ReleaseAccess( pWAcc
);
1639 rOutBmpEx
= BitmapEx( aOutBmp
, aOutMsk
);
1643 rOutBmpEx
= aOutBmp
;
1646 rOutBmpEx
= aOutBmp
;
1656 // -----------------------------------------------------------------------------
1658 void GraphicManager::ImplAdjust( BitmapEx
& rBmpEx
, const GraphicAttr
& rAttr
, ULONG nAdjustmentFlags
)
1660 GraphicAttr
aAttr( rAttr
);
1662 if( ( nAdjustmentFlags
& ADJUSTMENT_DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
1664 switch( aAttr
.GetDrawMode() )
1666 case( GRAPHICDRAWMODE_MONO
):
1667 rBmpEx
.Convert( BMP_CONVERSION_1BIT_THRESHOLD
);
1670 case( GRAPHICDRAWMODE_GREYS
):
1671 rBmpEx
.Convert( BMP_CONVERSION_8BIT_GREYS
);
1674 case( GRAPHICDRAWMODE_WATERMARK
):
1676 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
1677 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
1686 if( ( nAdjustmentFlags
& ADJUSTMENT_COLORS
) && aAttr
.IsAdjusted() )
1688 rBmpEx
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
1689 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
1690 aAttr
.GetGamma(), aAttr
.IsInvert() );
1693 if( ( nAdjustmentFlags
& ADJUSTMENT_MIRROR
) && aAttr
.IsMirrored() )
1695 rBmpEx
.Mirror( aAttr
.GetMirrorFlags() );
1698 if( ( nAdjustmentFlags
& ADJUSTMENT_ROTATE
) && aAttr
.IsRotated() )
1700 rBmpEx
.Rotate( aAttr
.GetRotation(), Color( COL_TRANSPARENT
) );
1703 if( ( nAdjustmentFlags
& ADJUSTMENT_TRANSPARENCY
) && aAttr
.IsTransparent() )
1706 BYTE cTrans
= aAttr
.GetTransparency();
1708 if( !rBmpEx
.IsTransparent() )
1709 aAlpha
= AlphaMask( rBmpEx
.GetSizePixel(), &cTrans
);
1710 else if( !rBmpEx
.IsAlpha() )
1712 aAlpha
= rBmpEx
.GetMask();
1713 aAlpha
.Replace( 0, cTrans
);
1717 aAlpha
= rBmpEx
.GetAlpha();
1718 BitmapWriteAccess
* pA
= aAlpha
.AcquireWriteAccess();
1722 ULONG nTrans
= cTrans
, nNewTrans
;
1723 const long nWidth
= pA
->Width(), nHeight
= pA
->Height();
1725 if( pA
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
1727 for( long nY
= 0; nY
< nHeight
; nY
++ )
1729 Scanline pAScan
= pA
->GetScanline( nY
);
1731 for( long nX
= 0; nX
< nWidth
; nX
++ )
1733 nNewTrans
= nTrans
+ *pAScan
;
1734 *pAScan
++ = (BYTE
) ( ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
);
1740 BitmapColor
aAlphaValue( 0 );
1742 for( long nY
= 0; nY
< nHeight
; nY
++ )
1744 for( long nX
= 0; nX
< nWidth
; nX
++ )
1746 nNewTrans
= nTrans
+ pA
->GetPixel( nY
, nX
).GetIndex();
1747 aAlphaValue
.SetIndex( (BYTE
) ( ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
) );
1748 pA
->SetPixel( nY
, nX
, aAlphaValue
);
1753 aAlpha
.ReleaseAccess( pA
);
1757 rBmpEx
= BitmapEx( rBmpEx
.GetBitmap(), aAlpha
);
1761 // -----------------------------------------------------------------------------
1763 void GraphicManager::ImplAdjust( GDIMetaFile
& rMtf
, const GraphicAttr
& rAttr
, ULONG nAdjustmentFlags
)
1765 GraphicAttr
aAttr( rAttr
);
1767 if( ( nAdjustmentFlags
& ADJUSTMENT_DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
1769 switch( aAttr
.GetDrawMode() )
1771 case( GRAPHICDRAWMODE_MONO
):
1772 rMtf
.Convert( MTF_CONVERSION_1BIT_THRESHOLD
);
1775 case( GRAPHICDRAWMODE_GREYS
):
1776 rMtf
.Convert( MTF_CONVERSION_8BIT_GREYS
);
1779 case( GRAPHICDRAWMODE_WATERMARK
):
1781 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
1782 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
1791 if( ( nAdjustmentFlags
& ADJUSTMENT_COLORS
) && aAttr
.IsAdjusted() )
1793 rMtf
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
1794 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
1795 aAttr
.GetGamma(), aAttr
.IsInvert() );
1798 if( ( nAdjustmentFlags
& ADJUSTMENT_MIRROR
) && aAttr
.IsMirrored() )
1800 rMtf
.Mirror( aAttr
.GetMirrorFlags() );
1803 if( ( nAdjustmentFlags
& ADJUSTMENT_ROTATE
) && aAttr
.IsRotated() )
1805 rMtf
.Rotate( aAttr
.GetRotation() );
1808 if( ( nAdjustmentFlags
& ADJUSTMENT_TRANSPARENCY
) && aAttr
.IsTransparent() )
1810 DBG_ERROR( "Missing implementation: Mtf-Transparency" );
1814 // -----------------------------------------------------------------------------
1816 void GraphicManager::ImplAdjust( Animation
& rAnimation
, const GraphicAttr
& rAttr
, ULONG nAdjustmentFlags
)
1818 GraphicAttr
aAttr( rAttr
);
1820 if( ( nAdjustmentFlags
& ADJUSTMENT_DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
1822 switch( aAttr
.GetDrawMode() )
1824 case( GRAPHICDRAWMODE_MONO
):
1825 rAnimation
.Convert( BMP_CONVERSION_1BIT_THRESHOLD
);
1828 case( GRAPHICDRAWMODE_GREYS
):
1829 rAnimation
.Convert( BMP_CONVERSION_8BIT_GREYS
);
1832 case( GRAPHICDRAWMODE_WATERMARK
):
1834 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
1835 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
1844 if( ( nAdjustmentFlags
& ADJUSTMENT_COLORS
) && aAttr
.IsAdjusted() )
1846 rAnimation
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
1847 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
1848 aAttr
.GetGamma(), aAttr
.IsInvert() );
1851 if( ( nAdjustmentFlags
& ADJUSTMENT_MIRROR
) && aAttr
.IsMirrored() )
1853 rAnimation
.Mirror( aAttr
.GetMirrorFlags() );
1856 if( ( nAdjustmentFlags
& ADJUSTMENT_ROTATE
) && aAttr
.IsRotated() )
1858 DBG_ERROR( "Missing implementation: Animation-Rotation" );
1861 if( ( nAdjustmentFlags
& ADJUSTMENT_TRANSPARENCY
) && aAttr
.IsTransparent() )
1863 DBG_ERROR( "Missing implementation: Animation-Transparency" );
1867 // -----------------------------------------------------------------------------
1869 void GraphicManager::ImplDraw( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
1870 const GDIMetaFile
& rMtf
, const GraphicAttr
& rAttr
)
1872 USHORT nRot10
= rAttr
.GetRotation() % 3600;
1873 Point
aOutPt( rPt
);
1878 Polygon
aPoly( Rectangle( aOutPt
, aOutSz
) );
1880 aPoly
.Rotate( aOutPt
, nRot10
);
1881 const Rectangle
aRotBoundRect( aPoly
.GetBoundRect() );
1882 aOutPt
= aRotBoundRect
.TopLeft();
1883 aOutSz
= aRotBoundRect
.GetSize();
1886 pOut
->Push( PUSH_CLIPREGION
);
1887 pOut
->IntersectClipRegion( Rectangle( aOutPt
, aOutSz
) );
1889 ( (GDIMetaFile
&) rMtf
).WindStart();
1890 ( (GDIMetaFile
&) rMtf
).Play( pOut
, aOutPt
, aOutSz
);
1891 ( (GDIMetaFile
&) rMtf
).WindStart();
1896 // -----------------------------------------------------------------------------
1900 ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
1902 Point aTileTopLeft
; // top, left position of the rendered tile
1903 Point aNextTileTopLeft
; // top, left position for next recursion
1905 Size aTileSizePixel
; // size of the generated tile (might
1907 // aNextTileTopLeft-aTileTopLeft, because
1908 // this is nExponent*prevTileSize. The
1909 // generated tile is always nExponent
1910 // times the previous tile, such that it
1911 // can be used in the next stage. The
1912 // required area coverage is often
1913 // less. The extraneous area covered is
1914 // later overwritten by the next stage)
1915 int nTilesEmptyX
; // number of original tiles empty right of
1916 // this tile. This counts from
1917 // aNextTileTopLeft, i.e. the additional
1918 // area covered by aTileSizePixel is not
1919 // considered here. This is for
1920 // unification purposes, as the iterative
1921 // calculation of the next level's empty
1922 // tiles has to be based on this value.
1923 int nTilesEmptyY
; // as above, for Y
1927 bool GraphicObject::ImplRenderTempTile( VirtualDevice
& rVDev
, int nExponent
,
1928 int nNumTilesX
, int nNumTilesY
,
1929 const Size
& rTileSizePixel
,
1930 const GraphicAttr
* pAttr
, ULONG nFlags
)
1932 if( nExponent
<= 1 )
1935 // determine MSB factor
1936 int nMSBFactor( 1 );
1937 while( nNumTilesX
/ nMSBFactor
!= 0 ||
1938 nNumTilesY
/ nMSBFactor
!= 0 )
1940 nMSBFactor
*= nExponent
;
1944 nMSBFactor
/= nExponent
;
1946 ImplTileInfo aTileInfo
;
1948 // #105229# Switch off mapping (converting to logic and back to
1949 // pixel might cause roundoff errors)
1950 BOOL
bOldMap( rVDev
.IsMapModeEnabled() );
1951 rVDev
.EnableMapMode( FALSE
);
1953 bool bRet( ImplRenderTileRecursive( rVDev
, nExponent
, nMSBFactor
, nNumTilesX
, nNumTilesY
,
1954 nNumTilesX
, nNumTilesY
, rTileSizePixel
, pAttr
, nFlags
, aTileInfo
) );
1956 rVDev
.EnableMapMode( bOldMap
);
1961 // -----------------------------------------------------------------------------
1963 // define for debug drawings
1966 // see header comment. this works similar to base conversion of a
1967 // number, i.e. if the exponent is 10, then the number for every tile
1968 // size is given by the decimal place of the corresponding decimal
1970 bool GraphicObject::ImplRenderTileRecursive( VirtualDevice
& rVDev
, int nExponent
, int nMSBFactor
,
1971 int nNumOrigTilesX
, int nNumOrigTilesY
,
1972 int nRemainderTilesX
, int nRemainderTilesY
,
1973 const Size
& rTileSizePixel
, const GraphicAttr
* pAttr
,
1974 ULONG nFlags
, ImplTileInfo
& rTileInfo
)
1976 // gets loaded with our tile bitmap
1977 GraphicObject aTmpGraphic
;
1979 // stores a flag that renders the zero'th tile position
1980 // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the
1981 // recursion stack. All other position already have that tile
1982 // rendered, because the lower levels painted their generated tile
1984 bool bNoFirstTileDraw( false );
1986 // what's left when we're done with our tile size
1987 const int nNewRemainderX( nRemainderTilesX
% nMSBFactor
);
1988 const int nNewRemainderY( nRemainderTilesY
% nMSBFactor
);
1990 // gets filled out from the recursive call with info of what's
1992 ImplTileInfo aTileInfo
;
1994 // current output position while drawing
1998 // check for recursion's end condition: LSB place reached?
1999 if( nMSBFactor
== 1 )
2001 aTmpGraphic
= *this;
2003 // set initial tile size -> orig size
2004 aTileInfo
.aTileSizePixel
= rTileSizePixel
;
2005 aTileInfo
.nTilesEmptyX
= nNumOrigTilesX
;
2006 aTileInfo
.nTilesEmptyY
= nNumOrigTilesY
;
2008 else if( ImplRenderTileRecursive( rVDev
, nExponent
, nMSBFactor
/nExponent
,
2009 nNumOrigTilesX
, nNumOrigTilesY
,
2010 nNewRemainderX
, nNewRemainderY
,
2011 rTileSizePixel
, pAttr
, nFlags
, aTileInfo
) )
2013 // extract generated tile -> see comment on the first loop below
2014 BitmapEx
aTileBitmap( rVDev
.GetBitmap( aTileInfo
.aTileTopLeft
, aTileInfo
.aTileSizePixel
) );
2016 aTmpGraphic
= GraphicObject( aTileBitmap
);
2018 // fill stripes left over from upstream levels:
2026 // where x denotes the place filled by our recursive predecessors
2028 // check whether we have to fill stripes here. Although not
2029 // obvious, there is one case where we can skip this step: if
2030 // the previous recursion level (the one who filled our
2031 // aTileInfo) had zero area to fill, then there are no white
2032 // stripes left, naturally. This happens if the digit
2033 // associated to that level has a zero, and can be checked via
2034 // aTileTopLeft==aNextTileTopLeft.
2035 if( aTileInfo
.aTileTopLeft
!= aTileInfo
.aNextTileTopLeft
)
2037 // now fill one row from aTileInfo.aNextTileTopLeft.X() all
2038 // the way to the right
2039 aCurrPos
.X() = aTileInfo
.aNextTileTopLeft
.X();
2040 aCurrPos
.Y() = aTileInfo
.aTileTopLeft
.Y();
2041 for( nX
=0; nX
< aTileInfo
.nTilesEmptyX
; nX
+= nMSBFactor
)
2043 if( !aTmpGraphic
.Draw( &rVDev
, aCurrPos
, aTileInfo
.aTileSizePixel
, pAttr
, nFlags
) )
2046 aCurrPos
.X() += aTileInfo
.aTileSizePixel
.Width();
2050 // rVDev.SetFillColor( COL_WHITE );
2051 rVDev
.SetFillColor();
2052 rVDev
.SetLineColor( Color( 255 * nExponent
/ nMSBFactor
, 255 - 255 * nExponent
/ nMSBFactor
, 128 - 255 * nExponent
/ nMSBFactor
) );
2053 rVDev
.DrawEllipse( Rectangle(aTileInfo
.aNextTileTopLeft
.X(), aTileInfo
.aTileTopLeft
.Y(),
2054 aTileInfo
.aNextTileTopLeft
.X() - 1 + (aTileInfo
.nTilesEmptyX
/nMSBFactor
)*aTileInfo
.aTileSizePixel
.Width(),
2055 aTileInfo
.aTileTopLeft
.Y() + aTileInfo
.aTileSizePixel
.Height() - 1) );
2058 // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
2059 // the way to the bottom
2060 aCurrPos
.X() = aTileInfo
.aTileTopLeft
.X();
2061 aCurrPos
.Y() = aTileInfo
.aNextTileTopLeft
.Y();
2062 for( nY
=0; nY
< aTileInfo
.nTilesEmptyY
; nY
+= nMSBFactor
)
2064 if( !aTmpGraphic
.Draw( &rVDev
, aCurrPos
, aTileInfo
.aTileSizePixel
, pAttr
, nFlags
) )
2067 aCurrPos
.Y() += aTileInfo
.aTileSizePixel
.Height();
2071 rVDev
.DrawEllipse( Rectangle(aTileInfo
.aTileTopLeft
.X(), aTileInfo
.aNextTileTopLeft
.Y(),
2072 aTileInfo
.aTileTopLeft
.X() + aTileInfo
.aTileSizePixel
.Width() - 1,
2073 aTileInfo
.aNextTileTopLeft
.Y() - 1 + (aTileInfo
.nTilesEmptyY
/nMSBFactor
)*aTileInfo
.aTileSizePixel
.Height()) );
2078 // Thought that aTileInfo.aNextTileTopLeft tile has always
2079 // been drawn already, but that's wrong: typically,
2080 // _parts_ of that tile have been drawn, since the
2081 // previous level generated the tile there. But when
2082 // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the
2083 // difference between these two values is missing in the
2084 // lower right corner of this first tile. So, can do that
2086 bNoFirstTileDraw
= true;
2094 // calc number of original tiles in our drawing area without
2096 nRemainderTilesX
-= nNewRemainderX
;
2097 nRemainderTilesY
-= nNewRemainderY
;
2099 // fill tile info for calling method
2100 rTileInfo
.aTileTopLeft
= aTileInfo
.aNextTileTopLeft
;
2101 rTileInfo
.aNextTileTopLeft
= Point( rTileInfo
.aTileTopLeft
.X() + rTileSizePixel
.Width()*nRemainderTilesX
,
2102 rTileInfo
.aTileTopLeft
.Y() + rTileSizePixel
.Height()*nRemainderTilesY
);
2103 rTileInfo
.aTileSizePixel
= Size( rTileSizePixel
.Width()*nMSBFactor
*nExponent
,
2104 rTileSizePixel
.Height()*nMSBFactor
*nExponent
);
2105 rTileInfo
.nTilesEmptyX
= aTileInfo
.nTilesEmptyX
- nRemainderTilesX
;
2106 rTileInfo
.nTilesEmptyY
= aTileInfo
.nTilesEmptyY
- nRemainderTilesY
;
2108 // init output position
2109 aCurrPos
= aTileInfo
.aNextTileTopLeft
;
2111 // fill our drawing area. Fill possibly more, to create the next
2112 // bigger tile size -> see bitmap extraction above. This does no
2113 // harm, since everything right or below our actual area is
2114 // overdrawn by our caller. Just in case we're in the last level,
2115 // we don't draw beyond the right or bottom border.
2116 for( nY
=0; nY
< aTileInfo
.nTilesEmptyY
&& nY
< nExponent
*nMSBFactor
; nY
+= nMSBFactor
)
2118 aCurrPos
.X() = aTileInfo
.aNextTileTopLeft
.X();
2120 for( nX
=0; nX
< aTileInfo
.nTilesEmptyX
&& nX
< nExponent
*nMSBFactor
; nX
+= nMSBFactor
)
2122 if( bNoFirstTileDraw
)
2123 bNoFirstTileDraw
= false; // don't draw first tile position
2124 else if( !aTmpGraphic
.Draw( &rVDev
, aCurrPos
, aTileInfo
.aTileSizePixel
, pAttr
, nFlags
) )
2127 aCurrPos
.X() += aTileInfo
.aTileSizePixel
.Width();
2130 aCurrPos
.Y() += aTileInfo
.aTileSizePixel
.Height();
2134 // rVDev.SetFillColor( COL_WHITE );
2135 rVDev
.SetFillColor();
2136 rVDev
.SetLineColor( Color( 255 * nExponent
/ nMSBFactor
, 255 - 255 * nExponent
/ nMSBFactor
, 128 - 255 * nExponent
/ nMSBFactor
) );
2137 rVDev
.DrawRect( Rectangle((rTileInfo
.aTileTopLeft
.X())*rTileSizePixel
.Width(),
2138 (rTileInfo
.aTileTopLeft
.Y())*rTileSizePixel
.Height(),
2139 (rTileInfo
.aNextTileTopLeft
.X())*rTileSizePixel
.Width()-1,
2140 (rTileInfo
.aNextTileTopLeft
.Y())*rTileSizePixel
.Height()-1) );
2146 // -----------------------------------------------------------------------------
2148 bool GraphicObject::ImplDrawTiled( OutputDevice
* pOut
, const Rectangle
& rArea
, const Size
& rSizePixel
,
2149 const Size
& rOffset
, const GraphicAttr
* pAttr
, ULONG nFlags
, int nTileCacheSize1D
)
2151 // how many tiles to generate per recursion step
2152 enum{ SubdivisionExponent
=2 };
2154 const MapMode
aOutMapMode( pOut
->GetMapMode() );
2155 const MapMode
aMapMode( aOutMapMode
.GetMapUnit(), Point(), aOutMapMode
.GetScaleX(), aOutMapMode
.GetScaleY() );
2158 // #i42643# Casting to Int64, to avoid integer overflow for
2159 // huge-DPI output devices
2160 if( GetGraphic().GetType() == GRAPHIC_BITMAP
&&
2161 static_cast<sal_Int64
>(rSizePixel
.Width()) * rSizePixel
.Height() <
2162 static_cast<sal_Int64
>(nTileCacheSize1D
)*nTileCacheSize1D
)
2164 // First combine very small bitmaps into a larger tile
2165 // ===================================================
2167 VirtualDevice aVDev
;
2168 const int nNumTilesInCacheX( (nTileCacheSize1D
+ rSizePixel
.Width()-1) / rSizePixel
.Width() );
2169 const int nNumTilesInCacheY( (nTileCacheSize1D
+ rSizePixel
.Height()-1) / rSizePixel
.Height() );
2171 aVDev
.SetOutputSizePixel( Size( nNumTilesInCacheX
*rSizePixel
.Width(),
2172 nNumTilesInCacheY
*rSizePixel
.Height() ) );
2173 aVDev
.SetMapMode( aMapMode
);
2175 // draw bitmap content
2176 if( ImplRenderTempTile( aVDev
, SubdivisionExponent
, nNumTilesInCacheX
,
2177 nNumTilesInCacheY
, rSizePixel
, pAttr
, nFlags
) )
2179 BitmapEx
aTileBitmap( aVDev
.GetBitmap( Point(0,0), aVDev
.GetOutputSize() ) );
2181 // draw alpha content, if any
2182 if( IsTransparent() )
2184 GraphicObject aAlphaGraphic
;
2186 if( GetGraphic().IsAlpha() )
2187 aAlphaGraphic
.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
2189 aAlphaGraphic
.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
2191 if( aAlphaGraphic
.ImplRenderTempTile( aVDev
, SubdivisionExponent
, nNumTilesInCacheX
,
2192 nNumTilesInCacheY
, rSizePixel
, pAttr
, nFlags
) )
2194 // Combine bitmap and alpha/mask
2195 if( GetGraphic().IsAlpha() )
2196 aTileBitmap
= BitmapEx( aTileBitmap
.GetBitmap(),
2197 AlphaMask( aVDev
.GetBitmap( Point(0,0), aVDev
.GetOutputSize() ) ) );
2199 aTileBitmap
= BitmapEx( aTileBitmap
.GetBitmap(),
2200 aVDev
.GetBitmap( Point(0,0), aVDev
.GetOutputSize() ).CreateMask( Color(COL_WHITE
) ) );
2204 // paint generated tile
2205 GraphicObject
aTmpGraphic( aTileBitmap
);
2206 bRet
= aTmpGraphic
.ImplDrawTiled( pOut
, rArea
,
2207 aTileBitmap
.GetSizePixel(),
2208 rOffset
, pAttr
, nFlags
, nTileCacheSize1D
);
2213 const Size
aOutOffset( pOut
->LogicToPixel( rOffset
, aOutMapMode
) );
2214 const Rectangle
aOutArea( pOut
->LogicToPixel( rArea
, aOutMapMode
) );
2216 // number of invisible (because out-of-area) tiles
2217 int nInvisibleTilesX
;
2218 int nInvisibleTilesY
;
2220 // round towards -infty for negative offset
2221 if( aOutOffset
.Width() < 0 )
2222 nInvisibleTilesX
= (aOutOffset
.Width() - rSizePixel
.Width() + 1) / rSizePixel
.Width();
2224 nInvisibleTilesX
= aOutOffset
.Width() / rSizePixel
.Width();
2226 // round towards -infty for negative offset
2227 if( aOutOffset
.Height() < 0 )
2228 nInvisibleTilesY
= (aOutOffset
.Height() - rSizePixel
.Height() + 1) / rSizePixel
.Height();
2230 nInvisibleTilesY
= aOutOffset
.Height() / rSizePixel
.Height();
2232 // origin from where to 'virtually' start drawing in pixel
2233 const Point
aOutOrigin( pOut
->LogicToPixel( Point( rArea
.Left() - rOffset
.Width(),
2234 rArea
.Top() - rOffset
.Height() ) ) );
2235 // position in pixel from where to really start output
2236 const Point
aOutStart( aOutOrigin
.X() + nInvisibleTilesX
*rSizePixel
.Width(),
2237 aOutOrigin
.Y() + nInvisibleTilesY
*rSizePixel
.Height() );
2239 pOut
->Push( PUSH_CLIPREGION
);
2240 pOut
->IntersectClipRegion( rArea
);
2245 bRet
= ImplDrawTiled( *pOut
, aOutStart
,
2246 (aOutArea
.GetWidth() + aOutArea
.Left() - aOutStart
.X() + rSizePixel
.Width() - 1) / rSizePixel
.Width(),
2247 (aOutArea
.GetHeight() + aOutArea
.Top() - aOutStart
.Y() + rSizePixel
.Height() - 1) / rSizePixel
.Height(),
2248 rSizePixel
, pAttr
, nFlags
);
2256 // -----------------------------------------------------------------------------
2258 bool GraphicObject::ImplDrawTiled( OutputDevice
& rOut
, const Point
& rPosPixel
,
2259 int nNumTilesX
, int nNumTilesY
,
2260 const Size
& rTileSizePixel
, const GraphicAttr
* pAttr
, ULONG nFlags
)
2262 Point
aCurrPos( rPosPixel
);
2263 Size
aTileSizeLogic( rOut
.PixelToLogic( rTileSizePixel
) );
2266 // #107607# Use logical coordinates for metafile playing, too
2267 bool bDrawInPixel( rOut
.GetConnectMetaFile() == NULL
&& GRAPHIC_BITMAP
== GetType() );
2270 // #105229# Switch off mapping (converting to logic and back to
2271 // pixel might cause roundoff errors)
2272 BOOL
bOldMap( rOut
.IsMapModeEnabled() );
2275 rOut
.EnableMapMode( FALSE
);
2277 for( nY
=0; nY
< nNumTilesY
; ++nY
)
2279 aCurrPos
.X() = rPosPixel
.X();
2281 for( nX
=0; nX
< nNumTilesX
; ++nX
)
2283 // #105229# work with pixel coordinates here, mapping is disabled!
2284 // #104004# don't disable mapping for metafile recordings
2285 // #108412# don't quit the loop if one draw fails
2287 // update return value. This method should return true, if
2288 // at least one of the looped Draws succeeded.
2289 bRet
|= Draw( &rOut
,
2290 bDrawInPixel
? aCurrPos
: rOut
.PixelToLogic( aCurrPos
),
2291 bDrawInPixel
? rTileSizePixel
: aTileSizeLogic
,
2294 aCurrPos
.X() += rTileSizePixel
.Width();
2297 aCurrPos
.Y() += rTileSizePixel
.Height();
2301 rOut
.EnableMapMode( bOldMap
);
2306 // -----------------------------------------------------------------------------
2308 void GraphicObject::ImplTransformBitmap( BitmapEx
& rBmpEx
,
2309 const GraphicAttr
& rAttr
,
2310 const Size
& rCropLeftTop
,
2311 const Size
& rCropRightBottom
,
2312 const Rectangle
& rCropRect
,
2313 const Size
& rDstSize
,
2314 BOOL bEnlarge
) const
2316 // #107947# Extracted from svdograf.cxx
2318 // #104115# Crop the bitmap
2319 if( rAttr
.IsCropped() )
2321 rBmpEx
.Crop( rCropRect
);
2323 // #104115# Negative crop sizes mean: enlarge bitmap and pad
2325 rCropLeftTop
.Width() < 0 ||
2326 rCropLeftTop
.Height() < 0 ||
2327 rCropRightBottom
.Width() < 0 ||
2328 rCropRightBottom
.Height() < 0 ) )
2330 Size
aBmpSize( rBmpEx
.GetSizePixel() );
2331 sal_Int32
nPadLeft( rCropLeftTop
.Width() < 0 ? -rCropLeftTop
.Width() : 0 );
2332 sal_Int32
nPadTop( rCropLeftTop
.Height() < 0 ? -rCropLeftTop
.Height() : 0 );
2333 sal_Int32
nPadTotalWidth( aBmpSize
.Width() + nPadLeft
+ (rCropRightBottom
.Width() < 0 ? -rCropRightBottom
.Width() : 0) );
2334 sal_Int32
nPadTotalHeight( aBmpSize
.Height() + nPadTop
+ (rCropRightBottom
.Height() < 0 ? -rCropRightBottom
.Height() : 0) );
2338 if( rBmpEx
.IsTransparent() )
2340 if( rBmpEx
.IsAlpha() )
2341 aBmpEx2
= BitmapEx( rBmpEx
.GetBitmap(), rBmpEx
.GetAlpha() );
2343 aBmpEx2
= BitmapEx( rBmpEx
.GetBitmap(), rBmpEx
.GetMask() );
2347 // #104115# Generate mask bitmap and init to zero
2348 Bitmap
aMask( aBmpSize
, 1 );
2349 aMask
.Erase( Color(0,0,0) );
2351 // #104115# Always generate transparent bitmap, we need the border transparent
2352 aBmpEx2
= BitmapEx( rBmpEx
.GetBitmap(), aMask
);
2354 // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
2358 aBmpEx2
.SetSizePixel( Size(nPadTotalWidth
, nPadTotalHeight
) );
2359 aBmpEx2
.Erase( Color(0xFF,0,0,0) );
2360 aBmpEx2
.CopyPixel( Rectangle( Point(nPadLeft
, nPadTop
), aBmpSize
), Rectangle( Point(0, 0), aBmpSize
), &rBmpEx
);
2365 const Size
aSizePixel( rBmpEx
.GetSizePixel() );
2367 if( rAttr
.GetRotation() != 0 && !IsAnimated() )
2369 if( aSizePixel
.Width() && aSizePixel
.Height() && rDstSize
.Width() && rDstSize
.Height() )
2371 double fSrcWH
= (double) aSizePixel
.Width() / aSizePixel
.Height();
2372 double fDstWH
= (double) rDstSize
.Width() / rDstSize
.Height();
2373 double fScaleX
= 1.0, fScaleY
= 1.0;
2375 // always choose scaling to shrink bitmap
2376 if( fSrcWH
< fDstWH
)
2377 fScaleY
= aSizePixel
.Width() / ( fDstWH
* aSizePixel
.Height() );
2379 fScaleX
= fDstWH
* aSizePixel
.Height() / aSizePixel
.Width();
2381 rBmpEx
.Scale( fScaleX
, fScaleY
);