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: outdev.cxx,v $
10 * $Revision: 1.59.74.2 $
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_vcl.hxx"
34 #include <tools/ref.hxx>
38 #include <vcl/salgdi.hxx>
39 #include <vcl/sallayout.hxx>
40 #include <vcl/salframe.hxx>
41 #include <vcl/salvd.hxx>
42 #include <vcl/salprn.hxx>
43 #include <tools/debug.hxx>
44 #include <vcl/svdata.hxx>
45 #include <vcl/svapp.hxx>
46 #include <vcl/ctrl.hxx>
48 #include <tools/poly.hxx>
50 #include <vcl/region.hxx>
51 #include <vcl/region.h>
52 #include <vcl/virdev.hxx>
53 #include <vcl/window.h>
54 #include <vcl/window.hxx>
55 #include <vcl/metaact.hxx>
56 #include <vcl/gdimtf.hxx>
57 #include <vcl/outdata.hxx>
58 #include <vcl/print.hxx>
59 #include <implncvt.hxx>
60 #include <vcl/outdev.h>
61 #include <vcl/outdev.hxx>
62 #include <vcl/unowrap.hxx>
63 #include <vcl/sysdata.hxx>
65 #include <basegfx/point/b2dpoint.hxx>
66 #include <basegfx/vector/b2dvector.hxx>
67 #include <basegfx/polygon/b2dpolygon.hxx>
68 #include <basegfx/polygon/b2dpolypolygon.hxx>
69 #include <basegfx/matrix/b2dhommatrix.hxx>
70 #include <basegfx/polygon/b2dpolygontools.hxx>
71 #include <basegfx/polygon/b2dpolypolygontools.hxx>
72 #include <basegfx/polygon/b2dlinegeometry.hxx>
74 #include <com/sun/star/awt/XGraphics.hpp>
75 #include <com/sun/star/uno/Sequence.hxx>
76 #include <com/sun/star/rendering/XCanvas.hpp>
77 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
78 #include <vcl/unohelp.hxx>
80 using namespace ::com::sun::star
;
82 DBG_NAME( OutputDevice
)
84 DBG_NAME( PolyPolygon
)
87 // -----------------------------------------------------------------------
90 const char* ImplDbgCheckOutputDevice( const void* pObj
)
94 const OutputDevice
* pOutDev
= (OutputDevice
*)pObj
;
96 if ( (pOutDev
->GetOutDevType() != OUTDEV_DONTKNOW
) &&
97 (pOutDev
->GetOutDevType() != OUTDEV_WINDOW
) &&
98 (pOutDev
->GetOutDevType() != OUTDEV_PRINTER
) &&
99 (pOutDev
->GetOutDevType() != OUTDEV_VIRDEV
) )
100 return "OutputDevice data overwrite";
106 // =======================================================================
108 #define OUTDEV_POLYPOLY_STACKBUF 32
110 // =======================================================================
114 ImplObjStack
* mpPrev
;
116 Region
* mpClipRegion
;
121 Color
* mpTextFillColor
;
122 Color
* mpTextLineColor
;
123 Color
* mpOverlineColor
;
125 TextAlign meTextAlign
;
127 ULONG mnTextLayoutMode
;
128 LanguageType meTextLanguage
;
132 // -----------------------------------------------------------------------
134 static void ImplDeleteObjStack( ImplObjStack
* pObjStack
)
136 if ( pObjStack
->mnFlags
& PUSH_LINECOLOR
)
138 if ( pObjStack
->mpLineColor
)
139 delete pObjStack
->mpLineColor
;
141 if ( pObjStack
->mnFlags
& PUSH_FILLCOLOR
)
143 if ( pObjStack
->mpFillColor
)
144 delete pObjStack
->mpFillColor
;
146 if ( pObjStack
->mnFlags
& PUSH_FONT
)
147 delete pObjStack
->mpFont
;
148 if ( pObjStack
->mnFlags
& PUSH_TEXTCOLOR
)
149 delete pObjStack
->mpTextColor
;
150 if ( pObjStack
->mnFlags
& PUSH_TEXTFILLCOLOR
)
152 if ( pObjStack
->mpTextFillColor
)
153 delete pObjStack
->mpTextFillColor
;
155 if ( pObjStack
->mnFlags
& PUSH_TEXTLINECOLOR
)
157 if ( pObjStack
->mpTextLineColor
)
158 delete pObjStack
->mpTextLineColor
;
160 if ( pObjStack
->mnFlags
& PUSH_OVERLINECOLOR
)
162 if ( pObjStack
->mpOverlineColor
)
163 delete pObjStack
->mpOverlineColor
;
165 if ( pObjStack
->mnFlags
& PUSH_MAPMODE
)
167 if ( pObjStack
->mpMapMode
)
168 delete pObjStack
->mpMapMode
;
170 if ( pObjStack
->mnFlags
& PUSH_CLIPREGION
)
172 if ( pObjStack
->mpClipRegion
)
173 delete pObjStack
->mpClipRegion
;
175 if ( pObjStack
->mnFlags
& PUSH_REFPOINT
)
177 if ( pObjStack
->mpRefPoint
)
178 delete pObjStack
->mpRefPoint
;
184 // -----------------------------------------------------------------------
186 bool OutputDevice::ImplIsAntiparallel() const
189 if( ImplGetGraphics() )
191 if( ( (mpGraphics
->GetLayout() & SAL_LAYOUT_BIDI_RTL
) && ! IsRTLEnabled() ) ||
192 ( ! (mpGraphics
->GetLayout() & SAL_LAYOUT_BIDI_RTL
) && IsRTLEnabled() ) )
200 // -----------------------------------------------------------------------
203 bool OutputDevice::ImplSelectClipRegion( const Region
& rRegion
, SalGraphics
* pGraphics
)
205 DBG_TESTSOLARMUTEX();
207 // TODO(Q3): Change from static to plain method - everybody's
208 // calling it with pOutDev=this!
209 // => done, but only with minimal changes for now => TODO
210 OutputDevice
* const pOutDev
= this;
214 if( !ImplGetGraphics() )
216 pGraphics
= mpGraphics
;
219 if( rRegion
.HasPolyPolygon()
220 && pGraphics
->supportsOperation( OutDevSupport_B2DClip
) )
222 const ::basegfx::B2DPolyPolygon
& rB2DPolyPolygon
= rRegion
.GetB2DPolyPolygon();
223 pGraphics
->BeginSetClipRegion( 0 );
224 pGraphics
->UnionClipRegion( rB2DPolyPolygon
, pOutDev
);
225 pGraphics
->EndSetClipRegion();
234 ImplRegionInfo aInfo
;
236 BOOL bClipRegion
= TRUE
;
237 const BOOL
bClipDeviceBounds( !pOutDev
->GetPDFWriter()
238 && pOutDev
->GetOutDevType() != OUTDEV_PRINTER
);
240 nRectCount
= rRegion
.GetRectCount();
241 pGraphics
->BeginSetClipRegion( nRectCount
);
242 bRegionRect
= rRegion
.ImplGetFirstRect( aInfo
, nX
, nY
, nWidth
, nHeight
);
243 if( bClipDeviceBounds
)
245 // #b6520266# Perform actual rect clip against outdev
246 // dimensions, to generate empty clips whenever one of the
247 // values is completely off the device.
248 const long nOffX( pOutDev
->mnOutOffX
);
249 const long nOffY( pOutDev
->mnOutOffY
);
250 const long nDeviceWidth( pOutDev
->GetOutputWidthPixel() );
251 const long nDeviceHeight( pOutDev
->GetOutputHeightPixel() );
252 Rectangle
aDeviceBounds( nOffX
, nOffY
,
253 nOffX
+nDeviceWidth
-1,
254 nOffY
+nDeviceHeight
-1 );
255 while ( bRegionRect
)
257 // #i59315# Limit coordinates passed to sal layer to actual
258 // outdev dimensions - everything else bears the risk of
259 // overflowing internal coordinates (e.g. the 16 bit wire
261 Rectangle
aTmpRect(nX
,nY
,nX
+nWidth
-1,nY
+nHeight
-1);
262 aTmpRect
.Intersection(aDeviceBounds
);
264 if( !aTmpRect
.IsEmpty() )
266 if ( !pGraphics
->UnionClipRegion( aTmpRect
.Left(),
269 aTmpRect
.GetHeight(),
277 // #i79850# Fake off-screen clip
278 if ( !pGraphics
->UnionClipRegion( nDeviceWidth
+1,
286 DBG_ASSERT( bClipRegion
, "OutputDevice::ImplSelectClipRegion() - can't create region" );
287 bRegionRect
= rRegion
.ImplGetNextRect( aInfo
, nX
, nY
, nWidth
, nHeight
);
292 // #i65720# Actually, _don't_ clip anything on printer or PDF
293 // export, since output might be visible outside the specified
294 // device boundaries.
295 while ( bRegionRect
)
297 if ( !pGraphics
->UnionClipRegion( nX
, nY
, nWidth
, nHeight
, pOutDev
) )
299 DBG_ASSERT( bClipRegion
, "OutputDevice::ImplSelectClipRegion() - can't cerate region" );
300 bRegionRect
= rRegion
.ImplGetNextRect( aInfo
, nX
, nY
, nWidth
, nHeight
);
303 pGraphics
->EndSetClipRegion();
308 // =======================================================================
310 Polygon
ImplSubdivideBezier( const Polygon
& rPoly
)
314 // #100127# Use adaptive subdivide instead of fixed 25 segments
315 rPoly
.AdaptiveSubdivide( aPoly
);
320 // =======================================================================
322 PolyPolygon
ImplSubdivideBezier( const PolyPolygon
& rPolyPoly
)
324 USHORT i
, nPolys
= rPolyPoly
.Count();
325 PolyPolygon
aPolyPoly( nPolys
);
326 for( i
=0; i
<nPolys
; ++i
)
327 aPolyPoly
.Insert( ImplSubdivideBezier( rPolyPoly
.GetObject(i
) ) );
332 // =======================================================================
334 // #100127# Extracted from OutputDevice::DrawPolyPolygon()
335 void OutputDevice::ImplDrawPolyPolygon( USHORT nPoly
, const PolyPolygon
& rPolyPoly
)
337 // AW: This crashes on empty PolyPolygons, avoid that
341 sal_uInt32 aStackAry1
[OUTDEV_POLYPOLY_STACKBUF
];
342 PCONSTSALPOINT aStackAry2
[OUTDEV_POLYPOLY_STACKBUF
];
343 BYTE
* aStackAry3
[OUTDEV_POLYPOLY_STACKBUF
];
344 sal_uInt32
* pPointAry
;
345 PCONSTSALPOINT
* pPointAryAry
;
346 const BYTE
** pFlagAryAry
;
347 USHORT i
= 0, j
= 0, last
= 0;
348 BOOL bHaveBezier
= sal_False
;
349 if ( nPoly
> OUTDEV_POLYPOLY_STACKBUF
)
351 pPointAry
= new sal_uInt32
[nPoly
];
352 pPointAryAry
= new PCONSTSALPOINT
[nPoly
];
353 pFlagAryAry
= new const BYTE
*[nPoly
];
357 pPointAry
= aStackAry1
;
358 pPointAryAry
= aStackAry2
;
359 pFlagAryAry
= (const BYTE
**)aStackAry3
;
363 const Polygon
& rPoly
= rPolyPoly
.GetObject( i
);
364 USHORT nSize
= rPoly
.GetSize();
367 pPointAry
[j
] = nSize
;
368 pPointAryAry
[j
] = (PCONSTSALPOINT
)rPoly
.GetConstPointAry();
369 pFlagAryAry
[j
] = rPoly
.GetConstFlagAry();
373 bHaveBezier
= sal_True
;
384 // #100127# Forward beziers to sal, if any
387 if( !mpGraphics
->DrawPolygonBezier( *pPointAry
, *pPointAryAry
, *pFlagAryAry
, this ) )
389 Polygon aPoly
= ImplSubdivideBezier( rPolyPoly
.GetObject( last
) );
390 mpGraphics
->DrawPolygon( aPoly
.GetSize(), (const SalPoint
*)aPoly
.GetConstPointAry(), this );
395 mpGraphics
->DrawPolygon( *pPointAry
, *pPointAryAry
, this );
400 // #100127# Forward beziers to sal, if any
403 if( !mpGraphics
->DrawPolyPolygonBezier( j
, pPointAry
, pPointAryAry
, pFlagAryAry
, this ) )
405 PolyPolygon aPolyPoly
= ImplSubdivideBezier( rPolyPoly
);
406 ImplDrawPolyPolygon( aPolyPoly
.Count(), aPolyPoly
);
411 mpGraphics
->DrawPolyPolygon( j
, pPointAry
, pPointAryAry
, this );
415 if ( pPointAry
!= aStackAry1
)
418 delete[] pPointAryAry
;
419 delete[] pFlagAryAry
;
423 // =======================================================================
425 OutputDevice::OutputDevice() :
426 maRegion( REGION_NULL
),
427 maFillColor( COL_WHITE
),
428 maTextLineColor( COL_TRANSPARENT
),
429 maSettings( Application::GetSettings() )
431 DBG_CTOR( OutputDevice
, ImplDbgCheckOutputDevice
);
434 mpUnoGraphicsList
= NULL
;
435 mpPrevGraphics
= NULL
;
436 mpNextGraphics
= NULL
;
441 mpGetDevFontList
= NULL
;
442 mpGetDevSizeList
= NULL
;
447 mpExtOutDevData
= NULL
;
460 mnEmphasisAscent
= 0;
461 mnEmphasisDescent
= 0;
463 mnTextLayoutMode
= TEXT_LAYOUT_DEFAULT
;
464 if( Application::GetSettings().GetLayoutRTL() ) //#i84553# tip BiDi preference to RTL
465 mnTextLayoutMode
= TEXT_LAYOUT_BIDI_RTL
| TEXT_LAYOUT_TEXTORIGIN_LEFT
;
466 meOutDevType
= OUTDEV_DONTKNOW
;
467 meOutDevViewType
= OUTDEV_VIEWTYPE_DONTKNOW
;
469 mbMapIsDefault
= TRUE
;
470 mbClipRegion
= FALSE
;
471 mbBackground
= FALSE
;
474 mbOutputClipped
= FALSE
;
475 maTextColor
= Color( COL_BLACK
);
476 maOverlineColor
= Color( COL_TRANSPARENT
);
477 meTextAlign
= maFont
.GetAlign();
478 meRasterOp
= ROP_OVERPAINT
;
480 meTextLanguage
= 0; // TODO: get default from configuration?
483 mbInitLineColor
= TRUE
;
484 mbInitFillColor
= TRUE
;
486 mbInitTextColor
= TRUE
;
487 mbInitClipRegion
= TRUE
;
488 mbClipRegionSet
= FALSE
;
492 mbTextSpecial
= FALSE
;
494 mbEnableRTL
= FALSE
; // mirroring must be explicitly allowed (typically for windows only)
497 maMapRes
.mnMapOfsX
= 0;
498 maMapRes
.mnMapOfsY
= 0;
499 maMapRes
.mnMapScNumX
= 1;
500 maMapRes
.mnMapScNumY
= 1;
501 maMapRes
.mnMapScDenomX
= 1;
502 maMapRes
.mnMapScDenomY
= 1;
503 // struct ImplThresholdRes
504 maThresRes
.mnThresLogToPixX
= 0;
505 maThresRes
.mnThresLogToPixY
= 0;
506 maThresRes
.mnThresPixToLogX
= 0;
507 maThresRes
.mnThresPixToLogY
= 0;
510 // -----------------------------------------------------------------------
512 OutputDevice::~OutputDevice()
514 DBG_DTOR( OutputDevice
, ImplDbgCheckOutputDevice
);
516 if ( GetUnoGraphicsList() )
518 UnoWrapperBase
* pWrapper
= Application::GetUnoWrapper( FALSE
);
520 pWrapper
->ReleaseAllGraphics( this );
521 delete mpUnoGraphicsList
;
522 mpUnoGraphicsList
= NULL
;
526 ImplDeInitOutDevData();
528 ImplObjStack
* pData
= mpObjStack
;
531 DBG_ERRORFILE( "OutputDevice::~OutputDevice(): OutputDevice::Push() calls != OutputDevice::Pop() calls" );
534 ImplObjStack
* pTemp
= pData
;
535 pData
= pData
->mpPrev
;
536 ImplDeleteObjStack( pTemp
);
540 // release the active font instance
542 mpFontCache
->Release( mpFontEntry
);
543 // remove cached results of GetDevFontList/GetDevSizeList
544 // TODO: use smart pointers for them
545 if( mpGetDevFontList
)
546 delete mpGetDevFontList
;
547 if( mpGetDevSizeList
)
548 delete mpGetDevSizeList
;
550 // release ImplFontCache specific to this OutputDevice
551 // TODO: refcount ImplFontCache
553 && (mpFontCache
!= ImplGetSVData()->maGDIData
.mpScreenFontCache
)
554 && (ImplGetSVData()->maGDIData
.mpScreenFontCache
!= NULL
) )
560 // release ImplFontList specific to this OutputDevice
561 // TODO: refcount ImplFontList
563 && (mpFontList
!= ImplGetSVData()->maGDIData
.mpScreenFontList
)
564 && (ImplGetSVData()->maGDIData
.mpScreenFontList
!= NULL
) )
574 bool OutputDevice::supportsOperation( OutDevSupportType eType
) const
577 if( !ImplGetGraphics() )
579 const bool bHasSupport
= mpGraphics
->supportsOperation( eType
);
583 // -----------------------------------------------------------------------
585 void OutputDevice::EnableRTL( BOOL bEnable
)
587 mbEnableRTL
= (bEnable
!= 0);
588 if( meOutDevType
== OUTDEV_VIRDEV
)
590 // virdevs default to not mirroring, they will only be set to mirroring
591 // under rare circumstances in the UI, eg the valueset control
592 // because each virdev has its own SalGraphics we can safely switch the SalGraphics here
594 if( ImplGetGraphics() )
595 mpGraphics
->SetLayout( mbEnableRTL
? SAL_LAYOUT_BIDI_RTL
: 0 );
598 // convenience: for controls also switch layout mode
599 if( dynamic_cast<Control
*>(this) != 0 )
600 SetLayoutMode( bEnable
? TEXT_LAYOUT_BIDI_RTL
| TEXT_LAYOUT_TEXTORIGIN_LEFT
: TEXT_LAYOUT_BIDI_LTR
| TEXT_LAYOUT_TEXTORIGIN_LEFT
);
602 Window
* pWin
= dynamic_cast<Window
*>(this);
604 pWin
->StateChanged( STATE_CHANGE_MIRRORING
);
607 mpAlphaVDev
->EnableRTL( bEnable
);
610 BOOL
OutputDevice::ImplHasMirroredGraphics()
612 // HOTFIX for #i55719#
613 if( meOutDevType
== OUTDEV_PRINTER
)
616 return ( ImplGetGraphics() && (mpGraphics
->GetLayout() & SAL_LAYOUT_BIDI_RTL
) );
619 // note: the coordiantes to be remirrored are in frame coordiantes !
621 void OutputDevice::ImplReMirror( Point
&rPoint
) const
623 rPoint
.X() = mnOutOffX
+ mnOutWidth
- 1 - rPoint
.X() + mnOutOffX
;
625 void OutputDevice::ImplReMirror( Rectangle
&rRect
) const
627 long nWidth
= rRect
.nRight
- rRect
.nLeft
;
629 //long lc_x = rRect.nLeft - mnOutOffX; // normalize
630 //lc_x = mnOutWidth - nWidth - 1 - lc_x; // mirror
631 //rRect.nLeft = lc_x + mnOutOffX; // re-normalize
633 rRect
.nLeft
= mnOutOffX
+ mnOutWidth
- nWidth
- 1 - rRect
.nLeft
+ mnOutOffX
;
634 rRect
.nRight
= rRect
.nLeft
+ nWidth
;
636 void OutputDevice::ImplReMirror( Region
&rRegion
) const
642 ImplRegionInfo aInfo
;
644 Region aMirroredRegion
;
646 bRegionRect
= rRegion
.ImplGetFirstRect( aInfo
, nX
, nY
, nWidth
, nHeight
);
647 while ( bRegionRect
)
649 Rectangle
aRect( Point(nX
, nY
), Size(nWidth
, nHeight
) );
650 ImplReMirror( aRect
);
651 aMirroredRegion
.Union( aRect
);
652 bRegionRect
= rRegion
.ImplGetNextRect( aInfo
, nX
, nY
, nWidth
, nHeight
);
654 rRegion
= aMirroredRegion
;
658 // -----------------------------------------------------------------------
660 int OutputDevice::ImplGetGraphics() const
662 DBG_TESTSOLARMUTEX();
667 mbInitLineColor
= TRUE
;
668 mbInitFillColor
= TRUE
;
670 mbInitTextColor
= TRUE
;
671 mbInitClipRegion
= TRUE
;
673 ImplSVData
* pSVData
= ImplGetSVData();
674 if ( meOutDevType
== OUTDEV_WINDOW
)
676 Window
* pWindow
= (Window
*)this;
678 mpGraphics
= pWindow
->mpWindowImpl
->mpFrame
->GetGraphics();
679 // try harder if no wingraphics was available directly
682 // find another output device in the same frame
683 OutputDevice
* pReleaseOutDev
= pSVData
->maGDIData
.mpLastWinGraphics
;
684 while ( pReleaseOutDev
)
686 if ( ((Window
*)pReleaseOutDev
)->mpWindowImpl
->mpFrame
== pWindow
->mpWindowImpl
->mpFrame
)
688 pReleaseOutDev
= pReleaseOutDev
->mpPrevGraphics
;
691 if ( pReleaseOutDev
)
693 // steal the wingraphics from the other outdev
694 mpGraphics
= pReleaseOutDev
->mpGraphics
;
695 pReleaseOutDev
->ImplReleaseGraphics( FALSE
);
699 // if needed retry after releasing least recently used wingraphics
700 while ( !mpGraphics
)
702 if ( !pSVData
->maGDIData
.mpLastWinGraphics
)
704 pSVData
->maGDIData
.mpLastWinGraphics
->ImplReleaseGraphics();
705 mpGraphics
= pWindow
->mpWindowImpl
->mpFrame
->GetGraphics();
710 // update global LRU list of wingraphics
713 mpNextGraphics
= pSVData
->maGDIData
.mpFirstWinGraphics
;
714 pSVData
->maGDIData
.mpFirstWinGraphics
= const_cast<OutputDevice
*>(this);
715 if ( mpNextGraphics
)
716 mpNextGraphics
->mpPrevGraphics
= const_cast<OutputDevice
*>(this);
717 if ( !pSVData
->maGDIData
.mpLastWinGraphics
)
718 pSVData
->maGDIData
.mpLastWinGraphics
= const_cast<OutputDevice
*>(this);
721 else if ( meOutDevType
== OUTDEV_VIRDEV
)
723 const VirtualDevice
* pVirDev
= (const VirtualDevice
*)this;
725 if ( pVirDev
->mpVirDev
)
727 mpGraphics
= pVirDev
->mpVirDev
->GetGraphics();
728 // if needed retry after releasing least recently used virtual device graphics
729 while ( !mpGraphics
)
731 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
733 pSVData
->maGDIData
.mpLastVirGraphics
->ImplReleaseGraphics();
734 mpGraphics
= pVirDev
->mpVirDev
->GetGraphics();
736 // update global LRU list of virtual device graphics
739 mpNextGraphics
= pSVData
->maGDIData
.mpFirstVirGraphics
;
740 pSVData
->maGDIData
.mpFirstVirGraphics
= const_cast<OutputDevice
*>(this);
741 if ( mpNextGraphics
)
742 mpNextGraphics
->mpPrevGraphics
= const_cast<OutputDevice
*>(this);
743 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
744 pSVData
->maGDIData
.mpLastVirGraphics
= const_cast<OutputDevice
*>(this);
748 else if ( meOutDevType
== OUTDEV_PRINTER
)
750 const Printer
* pPrinter
= (const Printer
*)this;
752 if ( pPrinter
->mpJobGraphics
)
753 mpGraphics
= pPrinter
->mpJobGraphics
;
754 else if ( pPrinter
->mpDisplayDev
)
756 const VirtualDevice
* pVirDev
= pPrinter
->mpDisplayDev
;
757 mpGraphics
= pVirDev
->mpVirDev
->GetGraphics();
758 // if needed retry after releasing least recently used virtual device graphics
759 while ( !mpGraphics
)
761 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
763 pSVData
->maGDIData
.mpLastVirGraphics
->ImplReleaseGraphics();
764 mpGraphics
= pVirDev
->mpVirDev
->GetGraphics();
766 // update global LRU list of virtual device graphics
769 mpNextGraphics
= pSVData
->maGDIData
.mpFirstVirGraphics
;
770 pSVData
->maGDIData
.mpFirstVirGraphics
= const_cast<OutputDevice
*>(this);
771 if ( mpNextGraphics
)
772 mpNextGraphics
->mpPrevGraphics
= const_cast<OutputDevice
*>(this);
773 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
774 pSVData
->maGDIData
.mpLastVirGraphics
= const_cast<OutputDevice
*>(this);
779 mpGraphics
= pPrinter
->mpInfoPrinter
->GetGraphics();
780 // if needed retry after releasing least recently used printer graphics
781 while ( !mpGraphics
)
783 if ( !pSVData
->maGDIData
.mpLastPrnGraphics
)
785 pSVData
->maGDIData
.mpLastPrnGraphics
->ImplReleaseGraphics();
786 mpGraphics
= pPrinter
->mpInfoPrinter
->GetGraphics();
788 // update global LRU list of printer graphics
791 mpNextGraphics
= pSVData
->maGDIData
.mpFirstPrnGraphics
;
792 pSVData
->maGDIData
.mpFirstPrnGraphics
= const_cast<OutputDevice
*>(this);
793 if ( mpNextGraphics
)
794 mpNextGraphics
->mpPrevGraphics
= const_cast<OutputDevice
*>(this);
795 if ( !pSVData
->maGDIData
.mpLastPrnGraphics
)
796 pSVData
->maGDIData
.mpLastPrnGraphics
= const_cast<OutputDevice
*>(this);
803 mpGraphics
->SetXORMode( (ROP_INVERT
== meRasterOp
) || (ROP_XOR
== meRasterOp
), ROP_INVERT
== meRasterOp
);
804 mpGraphics
->setAntiAliasB2DDraw(mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
);
811 // -----------------------------------------------------------------------
813 void OutputDevice::ImplReleaseGraphics( BOOL bRelease
)
815 DBG_TESTSOLARMUTEX();
820 // release the fonts of the physically released graphics device
824 // HACK to fix an urgent P1 printing issue fast
825 // WinSalPrinter does not respect GetGraphics/ReleaseGraphics conventions
826 // so Printer::mpGraphics often points to a dead WinSalGraphics
827 // TODO: fix WinSalPrinter's GetGraphics/ReleaseGraphics handling
828 if( meOutDevType
!= OUTDEV_PRINTER
)
830 mpGraphics
->ReleaseFonts();
837 mpFontCache
->Release( mpFontEntry
);
841 if ( mpGetDevFontList
)
843 delete mpGetDevFontList
;
844 mpGetDevFontList
= NULL
;
847 if ( mpGetDevSizeList
)
849 delete mpGetDevSizeList
;
850 mpGetDevSizeList
= NULL
;
854 ImplSVData
* pSVData
= ImplGetSVData();
855 if ( meOutDevType
== OUTDEV_WINDOW
)
857 Window
* pWindow
= (Window
*)this;
860 pWindow
->mpWindowImpl
->mpFrame
->ReleaseGraphics( mpGraphics
);
861 // remove from global LRU list of window graphics
862 if ( mpPrevGraphics
)
863 mpPrevGraphics
->mpNextGraphics
= mpNextGraphics
;
865 pSVData
->maGDIData
.mpFirstWinGraphics
= mpNextGraphics
;
866 if ( mpNextGraphics
)
867 mpNextGraphics
->mpPrevGraphics
= mpPrevGraphics
;
869 pSVData
->maGDIData
.mpLastWinGraphics
= mpPrevGraphics
;
871 else if ( meOutDevType
== OUTDEV_VIRDEV
)
873 VirtualDevice
* pVirDev
= (VirtualDevice
*)this;
876 pVirDev
->mpVirDev
->ReleaseGraphics( mpGraphics
);
877 // remove from global LRU list of virtual device graphics
878 if ( mpPrevGraphics
)
879 mpPrevGraphics
->mpNextGraphics
= mpNextGraphics
;
881 pSVData
->maGDIData
.mpFirstVirGraphics
= mpNextGraphics
;
882 if ( mpNextGraphics
)
883 mpNextGraphics
->mpPrevGraphics
= mpPrevGraphics
;
885 pSVData
->maGDIData
.mpLastVirGraphics
= mpPrevGraphics
;
887 else if ( meOutDevType
== OUTDEV_PRINTER
)
889 Printer
* pPrinter
= (Printer
*)this;
891 if ( !pPrinter
->mpJobGraphics
)
893 if ( pPrinter
->mpDisplayDev
)
895 VirtualDevice
* pVirDev
= pPrinter
->mpDisplayDev
;
897 pVirDev
->mpVirDev
->ReleaseGraphics( mpGraphics
);
898 // remove from global LRU list of virtual device graphics
899 if ( mpPrevGraphics
)
900 mpPrevGraphics
->mpNextGraphics
= mpNextGraphics
;
902 pSVData
->maGDIData
.mpFirstVirGraphics
= mpNextGraphics
;
903 if ( mpNextGraphics
)
904 mpNextGraphics
->mpPrevGraphics
= mpPrevGraphics
;
906 pSVData
->maGDIData
.mpLastVirGraphics
= mpPrevGraphics
;
911 pPrinter
->mpInfoPrinter
->ReleaseGraphics( mpGraphics
);
912 // remove from global LRU list of printer graphics
913 if ( mpPrevGraphics
)
914 mpPrevGraphics
->mpNextGraphics
= mpNextGraphics
;
916 pSVData
->maGDIData
.mpFirstPrnGraphics
= mpNextGraphics
;
917 if ( mpNextGraphics
)
918 mpNextGraphics
->mpPrevGraphics
= mpPrevGraphics
;
920 pSVData
->maGDIData
.mpLastPrnGraphics
= mpPrevGraphics
;
926 mpPrevGraphics
= NULL
;
927 mpNextGraphics
= NULL
;
930 // -----------------------------------------------------------------------
932 void OutputDevice::ImplInitOutDevData()
936 mpOutDevData
= new ImplOutDevData
;
937 mpOutDevData
->mpRotateDev
= NULL
;
938 mpOutDevData
->mpRecordLayout
= NULL
;
941 mpOutDevData
->mpViewTransform
= NULL
;
942 mpOutDevData
->mpInverseViewTransform
= NULL
;
946 // -----------------------------------------------------------------------
949 void OutputDevice::ImplInvalidateViewTransform()
953 if(mpOutDevData
->mpViewTransform
)
955 delete mpOutDevData
->mpViewTransform
;
956 mpOutDevData
->mpViewTransform
= NULL
;
959 if(mpOutDevData
->mpInverseViewTransform
)
961 delete mpOutDevData
->mpInverseViewTransform
;
962 mpOutDevData
->mpInverseViewTransform
= NULL
;
967 // -----------------------------------------------------------------------
969 BOOL
OutputDevice::ImplIsRecordLayout() const
971 return mpOutDevData
&& mpOutDevData
->mpRecordLayout
;
974 // -----------------------------------------------------------------------
976 void OutputDevice::ImplDeInitOutDevData()
980 if ( mpOutDevData
->mpRotateDev
)
981 delete mpOutDevData
->mpRotateDev
;
984 ImplInvalidateViewTransform();
990 // -----------------------------------------------------------------------
992 void OutputDevice::ImplInitLineColor()
994 DBG_TESTSOLARMUTEX();
998 if( ROP_0
== meRasterOp
)
999 mpGraphics
->SetROPLineColor( SAL_ROP_0
);
1000 else if( ROP_1
== meRasterOp
)
1001 mpGraphics
->SetROPLineColor( SAL_ROP_1
);
1002 else if( ROP_INVERT
== meRasterOp
)
1003 mpGraphics
->SetROPLineColor( SAL_ROP_INVERT
);
1005 mpGraphics
->SetLineColor( ImplColorToSal( maLineColor
) );
1008 mpGraphics
->SetLineColor();
1010 mbInitLineColor
= FALSE
;
1013 // -----------------------------------------------------------------------
1015 void OutputDevice::ImplInitFillColor()
1017 DBG_TESTSOLARMUTEX();
1021 if( ROP_0
== meRasterOp
)
1022 mpGraphics
->SetROPFillColor( SAL_ROP_0
);
1023 else if( ROP_1
== meRasterOp
)
1024 mpGraphics
->SetROPFillColor( SAL_ROP_1
);
1025 else if( ROP_INVERT
== meRasterOp
)
1026 mpGraphics
->SetROPFillColor( SAL_ROP_INVERT
);
1028 mpGraphics
->SetFillColor( ImplColorToSal( maFillColor
) );
1031 mpGraphics
->SetFillColor();
1033 mbInitFillColor
= FALSE
;
1036 // -----------------------------------------------------------------------
1038 void OutputDevice::ImplInitClipRegion()
1040 DBG_TESTSOLARMUTEX();
1042 if ( GetOutDevType() == OUTDEV_WINDOW
)
1044 Window
* pWindow
= (Window
*)this;
1047 // Hintergrund-Sicherung zuruecksetzen
1048 if ( pWindow
->mpWindowImpl
->mpFrameData
->mpFirstBackWin
)
1049 pWindow
->ImplInvalidateAllOverlapBackgrounds();
1050 if ( pWindow
->mpWindowImpl
->mbInPaint
)
1051 aRegion
= *(pWindow
->mpWindowImpl
->mpPaintRegion
);
1054 aRegion
= *(pWindow
->ImplGetWinChildClipRegion());
1055 // --- RTL -- only this region is in frame coordinates, so re-mirror it
1056 // the mpWindowImpl->mpPaintRegion above is already correct (see ImplCallPaint()) !
1057 if( ImplIsAntiparallel() )
1058 ImplReMirror ( aRegion
);
1061 aRegion
.Intersect( ImplPixelToDevicePixel( maRegion
) );
1062 if ( aRegion
.IsEmpty() )
1063 mbOutputClipped
= TRUE
;
1066 mbOutputClipped
= FALSE
;
1067 ImplSelectClipRegion( aRegion
);
1069 mbClipRegionSet
= TRUE
;
1075 if ( maRegion
.IsEmpty() )
1076 mbOutputClipped
= TRUE
;
1079 mbOutputClipped
= FALSE
;
1080 ImplSelectClipRegion(
1081 // #102532# Respect output offset also for clip region
1082 ImplPixelToDevicePixel( maRegion
) );
1085 mbClipRegionSet
= TRUE
;
1089 if ( mbClipRegionSet
)
1091 mpGraphics
->ResetClipRegion();
1092 mbClipRegionSet
= FALSE
;
1095 mbOutputClipped
= FALSE
;
1099 mbInitClipRegion
= FALSE
;
1102 // -----------------------------------------------------------------------
1104 void OutputDevice::ImplSetClipRegion( const Region
* pRegion
)
1106 DBG_TESTSOLARMUTEX();
1112 maRegion
= Region( REGION_NULL
);
1113 mbClipRegion
= FALSE
;
1114 mbInitClipRegion
= TRUE
;
1119 maRegion
= *pRegion
;
1120 mbClipRegion
= TRUE
;
1121 mbInitClipRegion
= TRUE
;
1125 // -----------------------------------------------------------------------
1129 inline int iround( float x
)
1131 sal_Int32 a
= *reinterpret_cast<const sal_Int32
*>(&x
);
1132 sal_Int32 exponent
= (127 + 31) - ((a
>> 23) & 0xFF);
1133 sal_Int32 r
= ((sal_Int32(a
) << 8) | (1U << 31)) >> exponent
;
1134 r
&= ((exponent
- 32) >> 31);
1135 sal_Int32 sign
= a
>> 31;
1136 return r
= (r
^ sign
) - sign
;
1139 inline int floorDiv(int a
, int b
)
1145 int q
= -(-a
/ b
); // quotient
1146 int r
= -a
% b
; // remainder
1152 inline int floorMod( int a
, int b
)
1158 int r
= -a
% b
; // remainder
1164 inline int ceilDiv( int a
, int b
)
1171 int q
= -(-a
/ b
); // quotient
1172 int r
= -a
% b
; // remainder
1178 inline int ceilMod( int a
, int b
)
1184 return (a
% b
) + 1 - b
;
1191 inline int ceilFix4(int x
) { return (x
+ 0xF) & 0xFFFFFFF0; }
1196 inline vertex( const Point
&p
)
1197 : x((float)p
.getX()),y((float)p
.getY()) {}
1200 template<class T
> inline void swap(T
&a
, T
&b
) { T t
=a
; a
=b
; b
=t
; }
1206 SpanIterator( sal_Int32
*pTable
, size_t dwPitch
, sal_Int32 dwNumScanlines
);
1207 std::pair
<sal_Int32
,sal_Int32
> GetNextSpan( void );
1208 sal_Int32
GetNumRemainingScanlines( void );
1209 sal_Int32
GetNumEqualScanlines( void );
1210 SpanIterator
&operator++ ();
1211 SpanIterator
&Skip( sal_Int32 dwNumScanlines
);
1212 sal_Int32
GetRemainingSpans( void ) const { return maNumSpans
; }
1217 sal_Int32
*mpSpanArray
;
1218 sal_Int32 maNumSpans
;
1219 sal_Int32 maRemainingScanlines
;
1223 inline SpanIterator::SpanIterator( sal_Int32
*pTable
, size_t dwPitch
, sal_Int32 dwNumScanlines
)
1224 : mpTable(pTable
),maRemainingScanlines(dwNumScanlines
),maPitch(dwPitch
)
1226 sal_Int32
*pNumSpans
= mpTable
;
1227 mpSpanArray
= reinterpret_cast<sal_Int32
*>(pNumSpans
+2);
1228 maNumSpans
= *pNumSpans
;
1231 inline SpanIterator
&SpanIterator::operator++ ()
1233 --maRemainingScanlines
;
1235 sal_Int32
*pNumSpans
= mpTable
;
1236 mpSpanArray
= reinterpret_cast<sal_Int32
*>(pNumSpans
+2);
1237 maNumSpans
= *pNumSpans
;
1241 inline SpanIterator
&SpanIterator::Skip( sal_Int32 dwNumScanlines
)
1243 // don't skip more scanlines than there are...
1244 if(dwNumScanlines
> maRemainingScanlines
)
1245 dwNumScanlines
= maRemainingScanlines
;
1247 // skip in one fellow swoop...
1248 maRemainingScanlines
-= dwNumScanlines
;
1249 mpTable
+= maPitch
* dwNumScanlines
;
1251 // initialize necessary query fields...
1252 sal_Int32
*pNumSpans
= mpTable
;
1253 mpSpanArray
= reinterpret_cast<sal_Int32
*>(pNumSpans
+2);
1254 maNumSpans
= *pNumSpans
;
1258 inline std::pair
<sal_Int32
,sal_Int32
> SpanIterator::GetNextSpan( void )
1268 return std::pair
<sal_Int32
,sal_Int32
>(x
,w
);
1271 inline sal_Int32
SpanIterator::GetNumEqualScanlines( void )
1276 inline sal_Int32
SpanIterator::GetNumRemainingScanlines( void )
1278 return maRemainingScanlines
;
1281 class ScanlineContainer
1286 ScanlineContainer( sal_uInt32 dwNumScanlines
,
1287 sal_uInt32 dwNumSpansPerScanline
);
1289 ~ScanlineContainer( void );
1291 void InsertSpan( sal_Int32 y
, sal_Int32 lx
, sal_Int32 rx
);
1293 SpanIterator
Iterate( void ) const { return SpanIterator(mpTable
,maPitch
,maNumScanlines
); }
1295 inline sal_uInt32
GetNumSpans( void ) const { return maNumberOfSpans
; }
1297 void Consolidate( void );
1301 // the span table will assist in determinate exactly how many clipping
1302 // regions [that is *spans*] we will end up with.
1303 // the counter for this purpose is right ahead.
1304 sal_uInt32 maNumberOfSpans
;
1312 sal_uInt32 maNumScanlines
;
1313 sal_uInt32 maNumSpansPerScanline
;
1318 ScanlineContainer::ScanlineContainer( sal_uInt32 dwNumScanlines
,
1319 sal_uInt32 dwNumSpansPerScanline
) : maNumScanlines(dwNumScanlines
),
1320 maNumSpansPerScanline(dwNumSpansPerScanline
)
1322 // #128002# add one scanline buffer at the end, as
1323 // SpanIterator::Skip reads two bytes past the end.
1326 // since each triangle could possibly add another span
1327 // we can calculate the upper limit by [num scanlines * num triangles].
1328 const sal_uInt32 dwNumPossibleRegions
= dwNumScanlines
*dwNumSpansPerScanline
;
1330 // calculate the number of bytes the span table will consume
1331 const size_t dwTableSize
= dwNumPossibleRegions
*sizeof(span
)+dwNumScanlines
*(sizeof(sal_Int32
)<<1);
1333 // allocate the span table [on the stack]
1334 mpTable
= static_cast<sal_Int32
*>(rtl_allocateMemory(dwTableSize
));
1336 // calculate the table pitch, that is how many int's do i need to get from a scanline to the next.
1337 maPitch
= (dwNumSpansPerScanline
*sizeof(span
)/sizeof(sal_Int32
))+2;
1339 // we need to initialize the table here.
1340 // the first *int* on each scanline tells us how many spans are on it.
1341 sal_Int32
*pNumSpans
= mpTable
;
1342 for(unsigned int i
=0; i
<dwNumScanlines
; ++i
)
1346 pNumSpans
+= maPitch
;
1349 maNumberOfSpans
= 0;
1352 ScanlineContainer::~ScanlineContainer( void )
1354 rtl_freeMemory(mpTable
);
1357 void ScanlineContainer::InsertSpan( sal_Int32 y
, sal_Int32 lx
, sal_Int32 rx
)
1359 // there's new incoming span which we need to store in the table.
1360 // first see if its width contributes a valid span.
1361 if(sal_Int32 dwSpanWidth
= rx
-lx
)
1363 // first select the appropriate scanline the new span.
1364 sal_Int32
*pNumSpans
= mpTable
+(y
*maPitch
);
1365 span
*pSpanArray
= reinterpret_cast<span
*>(pNumSpans
+2);
1367 // retrieve the number of already contained spans.
1368 sal_Int32 dwNumSpan
= *pNumSpans
;
1370 // since we need to sort the spans from top to bottom
1371 // and left to right, we need to find the correct location
1373 sal_Int32 dwIndex
= 0;
1374 while(dwIndex
<dwNumSpan
)
1376 // since we would like to avoid unnecessary spans
1377 // we try to consolidate them if possible.
1378 // consolidate with right neighbour
1379 if(pSpanArray
[dwIndex
].x
== rx
)
1381 pSpanArray
[dwIndex
].x
= lx
;
1382 pSpanArray
[dwIndex
].w
+= dwSpanWidth
;
1386 // consolidate with left neighbour
1387 if((pSpanArray
[dwIndex
].x
+pSpanArray
[dwIndex
].w
) == lx
)
1389 pSpanArray
[dwIndex
].w
+= rx
-lx
;
1393 // no consolidation possible, either this is a completely
1394 // seperate span or it is the first in the list.
1395 if(pSpanArray
[dwIndex
].x
> lx
)
1398 // forward to next element in the list.
1402 // if we reach here, the new span needs to be stored
1403 // in the table, increase the number of spans in the
1404 // current scanline.
1405 *pNumSpans
= dwNumSpan
+1;
1407 // keep the list of spans in sorted order. 'dwIndex'
1408 // is where we want to store the new span. 'dwNumSpan'
1409 // is the number of spans already there. now we need
1410 // to move the offending spans out of the way.
1411 while(dwIndex
!= dwNumSpan
)
1413 pSpanArray
[dwNumSpan
].x
= pSpanArray
[dwNumSpan
-1].x
;
1414 pSpanArray
[dwNumSpan
].w
= pSpanArray
[dwNumSpan
-1].w
;
1418 // insert the new span
1419 pSpanArray
[dwIndex
].x
= lx
;
1420 pSpanArray
[dwIndex
].w
= rx
-lx
;
1422 // remember the total number of spans in the table.
1427 void ScanlineContainer::Consolidate( void )
1429 sal_Int32
*pScanline
= mpTable
;
1431 sal_Int32 dwRemaining
= maNumScanlines
;
1434 sal_Int32 dwNumSpans
= pScanline
[0];
1435 sal_Int32
*pSpanArray
= pScanline
+2;
1437 sal_Int32 dwRest
= dwRemaining
-1;
1438 sal_Int32
*pNext
= pScanline
;
1442 sal_Int32 dwNumNextSpans
= pNext
[0];
1443 sal_Int32
*pSpanArrayNext
= pNext
+2;
1444 if(dwNumSpans
!= dwNumNextSpans
)
1447 sal_Int32 dwCompare
= dwNumSpans
<<1;
1450 if(pSpanArray
[dwCompare
-1] != pSpanArrayNext
[dwCompare
-1])
1460 const sal_Int32
dwNumEqualScanlines(dwRemaining
-dwRest
);
1461 pScanline
[1] = dwNumEqualScanlines
;
1462 pScanline
+= maPitch
*dwNumEqualScanlines
;
1463 dwRemaining
-= dwNumEqualScanlines
;
1465 // since we track the total number of spans to generate,
1466 // we need to account for consolidated scanlines here.
1467 if(dwNumEqualScanlines
> 1)
1468 maNumberOfSpans
-= dwNumSpans
* (dwNumEqualScanlines
-1);
1473 // TODO: we should consider passing a basegfx b2dpolypolygon here to
1474 // ensure that the signature isn't misleading.
1475 // if we could pass a b2dpolypolygon here, we could easily triangulate it.
1476 void OutputDevice::ImplSetTriangleClipRegion( const PolyPolygon
&rPolyPolygon
)
1478 DBG_TESTSOLARMUTEX();
1480 if(!(IsDeviceOutputNecessary()))
1483 if(!(ImplGetGraphics()))
1486 if( mpGraphics
->supportsOperation( OutDevSupport_B2DClip
) )
1489 ::basegfx::B2DPolyPolygon aB2DPolyPolygon
= rPolyPolygon
.getB2DPolyPolygon();
1491 // getB2DPolyPolygon() "optimizes away" some points
1492 // which prevents reliable undoing of the "triangle thingy" parameter
1493 // so the toolspoly -> b2dpoly conversion has to be done manually
1494 ::basegfx::B2DPolyPolygon aB2DPolyPolygon
;
1495 for( USHORT nPolyIdx
= 0; nPolyIdx
< rPolyPolygon
.Count(); ++nPolyIdx
)
1497 const Polygon
& rPolygon
= rPolyPolygon
[ nPolyIdx
];
1498 ::basegfx::B2DPolygon aB2DPoly
;
1499 for( USHORT nPointIdx
= 0; nPointIdx
< rPolygon
.GetSize(); ++nPointIdx
)
1501 const Point
& rPoint
= rPolygon
[ nPointIdx
];
1502 const ::basegfx::B2DPoint
aB2DPoint( rPoint
.X(), rPoint
.Y() );
1503 aB2DPoly
.append( aB2DPoint
);
1505 aB2DPolyPolygon
.append( aB2DPoly
);
1509 const ::basegfx::B2DHomMatrix aTransform
= ImplGetDeviceTransformation();
1510 aB2DPolyPolygon
.transform( aTransform
);
1512 // the rPolyPolygon argument is a "triangle thingy"
1513 // so convert it to a normal polypolyon first
1514 ::basegfx::B2DPolyPolygon aPolyTriangle
;
1515 const int nPolyCount
= aB2DPolyPolygon
.count();
1516 for( int nPolyIdx
= 0; nPolyIdx
< nPolyCount
; ++nPolyIdx
)
1518 const ::basegfx::B2DPolygon rPolygon
= aB2DPolyPolygon
.getB2DPolygon( nPolyIdx
);
1519 const int nPointCount
= rPolygon
.count();
1520 for( int nPointIdx
= 0; nPointIdx
+2 < nPointCount
; nPointIdx
+=3 )
1522 ::basegfx::B2DPolygon aTriangle
;
1523 aTriangle
.append( rPolygon
.getB2DPoint( nPointIdx
+0 ) );
1524 aTriangle
.append( rPolygon
.getB2DPoint( nPointIdx
+1 ) );
1525 aTriangle
.append( rPolygon
.getB2DPoint( nPointIdx
+2 ) );
1526 aPolyTriangle
.append( aTriangle
);
1530 // now set the clip region with the real polypolygon
1531 mpGraphics
->BeginSetClipRegion( 0 );
1532 mpGraphics
->UnionClipRegion( aPolyTriangle
, this );
1533 mpGraphics
->EndSetClipRegion();
1535 // and mark the clip status as ready
1536 mbOutputClipped
= FALSE
;
1537 mbClipRegion
= TRUE
;
1538 mbClipRegionSet
= TRUE
;
1539 mbInitClipRegion
= FALSE
;
1543 sal_Int32 offset_x
= 0;
1544 sal_Int32 offset_y
= 0;
1545 if ( GetOutDevType() == OUTDEV_WINDOW
)
1547 offset_x
= mnOutOffX
+mnOutOffOrigX
;
1548 offset_y
= mnOutOffY
+mnOutOffOrigY
;
1551 // first of all we need to know the upper limit
1552 // of the amount of possible clipping regions.
1553 sal_Int32 maxy
= SAL_MIN_INT32
;
1554 sal_Int32 miny
= SAL_MAX_INT32
;
1555 sal_uInt32 dwNumTriangles
= 0;
1556 for(USHORT i
=0; i
<rPolyPolygon
.Count(); ++i
)
1558 const Polygon
&rPoly
= rPolyPolygon
.GetObject(i
);
1559 const sal_Int32 dwNumVertices
= rPoly
.GetSize();
1560 if(!(dwNumVertices
% 3))
1562 for(USHORT j
=0; j
<rPoly
.GetSize(); ++j
)
1564 const Point
&p
= rPoly
.GetPoint(j
);
1570 dwNumTriangles
+= dwNumVertices
/ 3;
1574 const sal_uInt32 dwNumScanlines
= (maxy
-miny
);
1575 if(!(dwNumScanlines
))
1577 // indicates that no output needs to be produced
1578 // since the clipping region did not provide any
1580 mbOutputClipped
= TRUE
;
1582 // indicates that a clip region has been
1583 // presented to the output device.
1584 mbClipRegion
= TRUE
;
1586 // indicates that the set clipping region
1587 // has been processed.
1588 mbClipRegionSet
= TRUE
;
1590 // under 'normal' circumstances a new clipping region
1591 // needs to be processed by ImplInitClipRegion(),
1592 // which we need to circumvent.
1593 mbInitClipRegion
= FALSE
;
1597 // this container provides all services we need to
1598 // efficiently store/retrieve spans from the table.
1599 const sal_uInt32 dwNumSpansPerScanline
= dwNumTriangles
;
1600 ScanlineContainer
container(dwNumScanlines
,dwNumSpansPerScanline
);
1602 // convert the incoming polypolygon to spans, we assume that
1603 // the polypolygon has already been triangulated since we don't
1604 // want to use the basegfx-types here. this could be leveraged
1605 // after the tools-types had been removed.
1606 for(USHORT i
=0; i
<rPolyPolygon
.Count(); ++i
)
1608 const Polygon
&rPoly
= rPolyPolygon
.GetObject(i
);
1609 const USHORT dwNumVertices
= rPoly
.GetSize();
1610 if(!(dwNumVertices
% 3))
1612 for(USHORT j
=0; j
<dwNumVertices
; j
+=3)
1614 const Point
&p0
= rPoly
.GetPoint(j
+0);
1615 const Point
&p1
= rPoly
.GetPoint(j
+1);
1616 const Point
&p2
= rPoly
.GetPoint(j
+2);
1618 // what now follows is an extremely fast triangle
1619 // rasterizer from which all tricky and interesting
1620 // parts were forcibly amputated.
1621 // note: top.left fill-convention
1626 //sprintf(string,"[%f,%f] [%f,%f] [%f,%f]\n",v0.x,v0.y,v1.x,v1.y,v2.x,v2.y);
1627 //OSL_TRACE(string);
1629 if(v0
.y
> v2
.y
) ::swap(v0
, v2
);
1630 if(v1
.y
> v2
.y
) ::swap(v1
, v2
);
1631 if(v0
.y
> v1
.y
) ::swap(v0
, v1
);
1633 const float float2fixed(16.0f
);
1635 // vertex coordinates of the triangle [28.4 fixed-point]
1636 const int i4x0
= iround(float2fixed
* (v0
.x
- 0.5f
));
1637 const int i4y0
= iround(float2fixed
* (v0
.y
- 0.5f
));
1638 const int i4x1
= iround(float2fixed
* (v1
.x
- 0.5f
));
1639 const int i4y1
= iround(float2fixed
* (v1
.y
- 0.5f
));
1640 const int i4x2
= iround(float2fixed
* (v2
.x
- 0.5f
));
1641 const int i4y2
= iround(float2fixed
* (v2
.y
- 0.5f
));
1643 // vertex coordinate deltas [28.4 fixed-point]
1644 const int i4dx12
= i4x1
-i4x0
;
1645 const int i4dy12
= i4y1
-i4y0
;
1646 const int i4dx13
= i4x2
-i4x0
;
1647 const int i4dy13
= i4y2
-i4y0
;
1648 const int i4dx23
= i4x2
-i4x1
;
1649 const int i4dy23
= i4y2
-i4y1
;
1651 // slope of edges [quotient,remainder]
1652 const int mq12
= floorDiv(i4dx12
<< 4, i4dy12
<< 4);
1653 const int mq13
= floorDiv(i4dx13
<< 4, i4dy13
<< 4);
1654 const int mq23
= floorDiv(i4dx23
<< 4, i4dy23
<< 4);
1655 const int mr12
= floorMod(i4dx12
<< 4, i4dy12
<< 4);
1656 const int mr13
= floorMod(i4dx13
<< 4, i4dy13
<< 4);
1657 const int mr23
= floorMod(i4dx23
<< 4, i4dy23
<< 4);
1659 // convert the vertical coordinates back to integers.
1660 // according to the top-left fillrule we need to step
1661 // the coordinates to the ceiling.
1662 const int y0
= (i4y0
+15)>>4;
1663 const int y1
= (i4y1
+15)>>4;
1664 const int y2
= (i4y2
+15)>>4;
1666 // calculate the value of the horizontal coordinate
1667 // from the edge that 'spans' the triangle.
1668 const int x
= ceilDiv(i4dx13
*i4dy12
+ i4x0
*i4dy13
, i4dy13
);
1670 // this will hold the horizontal coordinates
1671 // of the seperate spans during the rasterization process.
1674 // this pair will serve as the error accumulator while
1675 // we step along the edges.
1678 // these are the edge and error stepping values that
1679 // will be used while stepping.
1684 lx
= ceilDiv(i4dx12
* (ceilFix4(i4y0
) - i4y0
) + i4x0
* i4dy12
, i4dy12
<< 4);
1685 ld
= ceilMod(i4dx12
* (ceilFix4(i4y0
) - i4y0
) + i4x0
* i4dy12
, i4dy12
<< 4);
1686 rx
= ceilDiv(i4dx13
* (ceilFix4(i4y0
) - i4y0
) + i4x0
* i4dy13
, i4dy13
<< 4);
1687 rd
= ceilMod(i4dx13
* (ceilFix4(i4y0
) - i4y0
) + i4x0
* i4dy13
, i4dy13
<< 4);
1697 lx
= ceilDiv(i4dx13
* (ceilFix4(i4y0
) - i4y0
) + i4x0
* i4dy13
, i4dy13
<< 4);
1698 ld
= ceilMod(i4dx13
* (ceilFix4(i4y0
) - i4y0
) + i4x0
* i4dy13
, i4dy13
<< 4);
1699 rx
= ceilDiv(i4dx12
* (ceilFix4(i4y0
) - i4y0
) + i4x0
* i4dy12
, i4dy12
<< 4);
1700 rd
= ceilMod(i4dx12
* (ceilFix4(i4y0
) - i4y0
) + i4x0
* i4dy12
, i4dy12
<< 4);
1709 for(signed int y
=y0
; y
<y1
; y
++)
1711 container
.InsertSpan(y
-miny
,lx
,rx
);
1714 if(ld
> 0) { ld
-= lD
; lx
+= 1; }
1716 if(rd
> 0) { rd
-= rD
; rx
+= 1; }
1721 lx
= ceilDiv(i4dx23
* (ceilFix4(i4y1
) - i4y1
) + i4x1
* i4dy23
, i4dy23
<< 4);
1722 ld
= ceilMod(i4dx23
* (ceilFix4(i4y1
) - i4y1
) + i4x1
* i4dy23
, i4dy23
<< 4);
1723 rx
= ceilDiv(i4dx13
* (ceilFix4(i4y1
) - i4y0
) + i4x0
* i4dy13
, i4dy13
<< 4);
1724 rd
= ceilMod(i4dx13
* (ceilFix4(i4y1
) - i4y0
) + i4x0
* i4dy13
, i4dy13
<< 4);
1731 rx
= ceilDiv(i4dx23
* (ceilFix4(i4y1
) - i4y1
) + i4x1
* i4dy23
, i4dy23
<< 4);
1732 rd
= ceilMod(i4dx23
* (ceilFix4(i4y1
) - i4y1
) + i4x1
* i4dy23
, i4dy23
<< 4);
1738 for(signed int y
=y1
; y
<y2
; y
++)
1740 container
.InsertSpan(y
-miny
,lx
,rx
);
1743 if(ld
> 0) { ld
-= lD
; lx
+= 1; }
1745 if(rd
> 0) { rd
-= rD
; rx
+= 1; }
1751 // now try to consolidate as many scanlines as possible.
1752 // please note that this will probably change the number
1753 // of spans [at least this is why we do all this hassle].
1754 // so, if you use 'consolidate' you should *use* this
1755 // information during iteration, because the 'graphics'
1756 // object we tell all those regions about is a bit,
1757 // hm, how to say, *picky* if you supply not correctly
1758 // the amount of regions.
1759 container
.Consolidate();
1761 // now forward the spantable to the graphics handler.
1762 SpanIterator
it(container
.Iterate());
1763 mpGraphics
->BeginSetClipRegion( container
.GetNumSpans() );
1766 const sal_Int32
dwNumEqual(it
.GetNumEqualScanlines());
1767 while(it
.GetRemainingSpans())
1769 // retrieve the next span [x-coordinate, width] from the current scanline.
1770 std::pair
<sal_Int32
,sal_Int32
> span(it
.GetNextSpan());
1772 // now forward this to the graphics object.
1773 // the only part that is worth noting is that we use
1774 // the number of equal spanlines [the current is always the
1775 // first one of the equal bunch] as the height of the region.
1776 mpGraphics
->UnionClipRegion( offset_x
+span
.first
,
1782 it
.Skip(dwNumEqual
);
1785 mpGraphics
->EndSetClipRegion();
1787 // indicates that no output needs to be produced
1788 // since the clipping region did not provide any
1789 // visible areas. the clip covers the whole area
1790 // if there's not a single region.
1791 mbOutputClipped
= (container
.GetNumSpans() == 0);
1793 // indicates that a clip region has been
1794 // presented to the output device.
1795 mbClipRegion
= TRUE
;
1797 // indicates that the set clipping region
1798 // has been processed.
1799 mbClipRegionSet
= TRUE
;
1801 // under 'normal' circumstances a new clipping region
1802 // needs to be processed by ImplInitClipRegion(),
1803 // which we need to circumvent.
1804 mbInitClipRegion
= FALSE
;
1807 // -----------------------------------------------------------------------
1809 void OutputDevice::SetClipRegion()
1811 DBG_TRACE( "OutputDevice::SetClipRegion()" );
1812 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1815 mpMetaFile
->AddAction( new MetaClipRegionAction( Region(), FALSE
) );
1817 ImplSetClipRegion( NULL
);
1820 mpAlphaVDev
->SetClipRegion();
1823 // -----------------------------------------------------------------------
1825 void OutputDevice::SetClipRegion( const Region
& rRegion
)
1827 DBG_TRACE( "OutputDevice::SetClipRegion( rRegion )" );
1828 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1829 DBG_CHKOBJ( &rRegion
, Region
, ImplDbgTestRegion
);
1832 mpMetaFile
->AddAction( new MetaClipRegionAction( rRegion
, TRUE
) );
1834 if ( rRegion
.GetType() == REGION_NULL
)
1835 ImplSetClipRegion( NULL
);
1838 Region aRegion
= LogicToPixel( rRegion
);
1839 ImplSetClipRegion( &aRegion
);
1843 mpAlphaVDev
->SetClipRegion( rRegion
);
1846 // -----------------------------------------------------------------------
1848 void OutputDevice::SetTriangleClipRegion( const PolyPolygon
&rPolyPolygon
)
1850 DBG_TRACE( "OutputDevice::SetTriangleClipRegion( rPolyPolygon )" );
1851 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1853 // in case the passed polypolygon is empty, use the
1854 // existing SetClipRegion() method which gracefully
1855 // unsets any previously set clipping region.
1856 if(!(rPolyPolygon
.Count()))
1859 sal_Int32 offset_x
= 0;
1860 sal_Int32 offset_y
= 0;
1861 if ( GetOutDevType() == OUTDEV_WINDOW
)
1863 offset_x
= mnOutOffX
+mnOutOffOrigX
;
1864 offset_y
= mnOutOffY
+mnOutOffOrigY
;
1867 // play nice with the rest of the system and provide an old-style region.
1868 // the rest of this method does not rely on this.
1869 maRegion
= Region::GetRegionFromPolyPolygon( LogicToPixel(rPolyPolygon
) );
1870 maRegion
.Move(offset_x
,offset_x
);
1872 // feed region to metafile
1874 mpMetaFile
->AddAction( new MetaClipRegionAction( maRegion
, TRUE
) );
1876 ImplSetTriangleClipRegion( rPolyPolygon
);
1879 mpAlphaVDev
->SetTriangleClipRegion( rPolyPolygon
);
1882 // -----------------------------------------------------------------------
1884 Region
OutputDevice::GetClipRegion() const
1886 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1888 return PixelToLogic( maRegion
);
1891 // -----------------------------------------------------------------------
1893 Region
OutputDevice::GetActiveClipRegion() const
1895 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1897 if ( GetOutDevType() == OUTDEV_WINDOW
)
1899 Region
aRegion( REGION_NULL
);
1900 Window
* pWindow
= (Window
*)this;
1901 if ( pWindow
->mpWindowImpl
->mbInPaint
)
1903 aRegion
= *(pWindow
->mpWindowImpl
->mpPaintRegion
);
1904 aRegion
.Move( -mnOutOffX
, -mnOutOffY
);
1907 aRegion
.Intersect( maRegion
);
1908 return PixelToLogic( aRegion
);
1911 return GetClipRegion();
1914 // -----------------------------------------------------------------------
1916 void OutputDevice::MoveClipRegion( long nHorzMove
, long nVertMove
)
1918 DBG_TRACE( "OutputDevice::MoveClipRegion()" );
1919 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1924 mpMetaFile
->AddAction( new MetaMoveClipRegionAction( nHorzMove
, nVertMove
) );
1926 maRegion
.Move( ImplLogicWidthToDevicePixel( nHorzMove
),
1927 ImplLogicHeightToDevicePixel( nVertMove
) );
1928 mbInitClipRegion
= TRUE
;
1932 mpAlphaVDev
->MoveClipRegion( nHorzMove
, nVertMove
);
1935 // -----------------------------------------------------------------------
1937 void OutputDevice::IntersectClipRegion( const Rectangle
& rRect
)
1939 DBG_TRACE( "OutputDevice::IntersectClipRegion( rRect )" );
1940 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1943 mpMetaFile
->AddAction( new MetaISectRectClipRegionAction( rRect
) );
1945 Rectangle aRect
= LogicToPixel( rRect
);
1946 maRegion
.Intersect( aRect
);
1947 mbClipRegion
= TRUE
;
1948 mbInitClipRegion
= TRUE
;
1951 mpAlphaVDev
->IntersectClipRegion( rRect
);
1954 // -----------------------------------------------------------------------
1956 void OutputDevice::IntersectClipRegion( const Region
& rRegion
)
1958 DBG_TRACE( "OutputDevice::IntersectClipRegion( rRegion )" );
1959 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1960 DBG_CHKOBJ( &rRegion
, Region
, ImplDbgTestRegion
);
1962 RegionType eType
= rRegion
.GetType();
1964 if ( eType
!= REGION_NULL
)
1967 mpMetaFile
->AddAction( new MetaISectRegionClipRegionAction( rRegion
) );
1969 Region aRegion
= LogicToPixel( rRegion
);
1970 maRegion
.Intersect( aRegion
);
1971 mbClipRegion
= TRUE
;
1972 mbInitClipRegion
= TRUE
;
1976 mpAlphaVDev
->IntersectClipRegion( rRegion
);
1979 // -----------------------------------------------------------------------
1981 void OutputDevice::SetDrawMode( ULONG nDrawMode
)
1983 DBG_TRACE1( "OutputDevice::SetDrawMode( %lx )", nDrawMode
);
1984 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1986 mnDrawMode
= nDrawMode
;
1989 mpAlphaVDev
->SetDrawMode( nDrawMode
);
1992 // -----------------------------------------------------------------------
1994 void OutputDevice::SetRasterOp( RasterOp eRasterOp
)
1996 DBG_TRACE1( "OutputDevice::SetRasterOp( %d )", (int)eRasterOp
);
1997 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2000 mpMetaFile
->AddAction( new MetaRasterOpAction( eRasterOp
) );
2002 if ( meRasterOp
!= eRasterOp
)
2004 meRasterOp
= eRasterOp
;
2005 mbInitLineColor
= mbInitFillColor
= TRUE
;
2007 if( mpGraphics
|| ImplGetGraphics() )
2008 mpGraphics
->SetXORMode( (ROP_INVERT
== meRasterOp
) || (ROP_XOR
== meRasterOp
), ROP_INVERT
== meRasterOp
);
2012 mpAlphaVDev
->SetRasterOp( eRasterOp
);
2015 // -----------------------------------------------------------------------
2017 void OutputDevice::SetLineColor()
2019 DBG_TRACE( "OutputDevice::SetLineColor()" );
2020 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2023 mpMetaFile
->AddAction( new MetaLineColorAction( Color(), FALSE
) );
2027 mbInitLineColor
= TRUE
;
2028 mbLineColor
= FALSE
;
2029 maLineColor
= Color( COL_TRANSPARENT
);
2033 mpAlphaVDev
->SetLineColor();
2036 // -----------------------------------------------------------------------
2038 void OutputDevice::SetLineColor( const Color
& rColor
)
2040 DBG_TRACE1( "OutputDevice::SetLineColor( %lx )", rColor
.GetColor() );
2041 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2043 Color
aColor( rColor
);
2045 if( mnDrawMode
& ( DRAWMODE_BLACKLINE
| DRAWMODE_WHITELINE
|
2046 DRAWMODE_GRAYLINE
| DRAWMODE_GHOSTEDLINE
|
2047 DRAWMODE_SETTINGSLINE
) )
2049 if( !ImplIsColorTransparent( aColor
) )
2051 if( mnDrawMode
& DRAWMODE_BLACKLINE
)
2053 aColor
= Color( COL_BLACK
);
2055 else if( mnDrawMode
& DRAWMODE_WHITELINE
)
2057 aColor
= Color( COL_WHITE
);
2059 else if( mnDrawMode
& DRAWMODE_GRAYLINE
)
2061 const UINT8 cLum
= aColor
.GetLuminance();
2062 aColor
= Color( cLum
, cLum
, cLum
);
2064 else if( mnDrawMode
& DRAWMODE_SETTINGSLINE
)
2066 aColor
= GetSettings().GetStyleSettings().GetFontColor();
2069 if( mnDrawMode
& DRAWMODE_GHOSTEDLINE
)
2071 aColor
= Color( ( aColor
.GetRed() >> 1 ) | 0x80,
2072 ( aColor
.GetGreen() >> 1 ) | 0x80,
2073 ( aColor
.GetBlue() >> 1 ) | 0x80);
2079 mpMetaFile
->AddAction( new MetaLineColorAction( aColor
, TRUE
) );
2081 if( ImplIsColorTransparent( aColor
) )
2085 mbInitLineColor
= TRUE
;
2086 mbLineColor
= FALSE
;
2087 maLineColor
= Color( COL_TRANSPARENT
);
2092 if( maLineColor
!= aColor
)
2094 mbInitLineColor
= TRUE
;
2096 maLineColor
= aColor
;
2101 mpAlphaVDev
->SetLineColor( COL_BLACK
);
2104 // -----------------------------------------------------------------------
2106 void OutputDevice::SetFillColor()
2108 DBG_TRACE( "OutputDevice::SetFillColor()" );
2109 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2112 mpMetaFile
->AddAction( new MetaFillColorAction( Color(), FALSE
) );
2116 mbInitFillColor
= TRUE
;
2117 mbFillColor
= FALSE
;
2118 maFillColor
= Color( COL_TRANSPARENT
);
2122 mpAlphaVDev
->SetFillColor();
2125 // -----------------------------------------------------------------------
2127 void OutputDevice::SetFillColor( const Color
& rColor
)
2129 DBG_TRACE1( "OutputDevice::SetFillColor( %lx )", rColor
.GetColor() );
2130 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2132 Color
aColor( rColor
);
2134 if( mnDrawMode
& ( DRAWMODE_BLACKFILL
| DRAWMODE_WHITEFILL
|
2135 DRAWMODE_GRAYFILL
| DRAWMODE_NOFILL
|
2136 DRAWMODE_GHOSTEDFILL
| DRAWMODE_SETTINGSFILL
) )
2138 if( !ImplIsColorTransparent( aColor
) )
2140 if( mnDrawMode
& DRAWMODE_BLACKFILL
)
2142 aColor
= Color( COL_BLACK
);
2144 else if( mnDrawMode
& DRAWMODE_WHITEFILL
)
2146 aColor
= Color( COL_WHITE
);
2148 else if( mnDrawMode
& DRAWMODE_GRAYFILL
)
2150 const UINT8 cLum
= aColor
.GetLuminance();
2151 aColor
= Color( cLum
, cLum
, cLum
);
2153 else if( mnDrawMode
& DRAWMODE_NOFILL
)
2155 aColor
= Color( COL_TRANSPARENT
);
2157 else if( mnDrawMode
& DRAWMODE_SETTINGSFILL
)
2159 aColor
= GetSettings().GetStyleSettings().GetWindowColor();
2162 if( mnDrawMode
& DRAWMODE_GHOSTEDFILL
)
2164 aColor
= Color( (aColor
.GetRed() >> 1) | 0x80,
2165 (aColor
.GetGreen() >> 1) | 0x80,
2166 (aColor
.GetBlue() >> 1) | 0x80);
2172 mpMetaFile
->AddAction( new MetaFillColorAction( aColor
, TRUE
) );
2174 if ( ImplIsColorTransparent( aColor
) )
2178 mbInitFillColor
= TRUE
;
2179 mbFillColor
= FALSE
;
2180 maFillColor
= Color( COL_TRANSPARENT
);
2185 if ( maFillColor
!= aColor
)
2187 mbInitFillColor
= TRUE
;
2189 maFillColor
= aColor
;
2194 mpAlphaVDev
->SetFillColor( COL_BLACK
);
2197 // -----------------------------------------------------------------------
2199 void OutputDevice::SetBackground()
2201 DBG_TRACE( "OutputDevice::SetBackground()" );
2202 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2204 maBackground
= Wallpaper();
2205 mbBackground
= FALSE
;
2208 mpAlphaVDev
->SetBackground();
2211 // -----------------------------------------------------------------------
2213 void OutputDevice::SetBackground( const Wallpaper
& rBackground
)
2215 DBG_TRACE( "OutputDevice::SetBackground( rBackground )" );
2216 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2218 maBackground
= rBackground
;
2220 if( rBackground
.GetStyle() == WALLPAPER_NULL
)
2221 mbBackground
= FALSE
;
2223 mbBackground
= TRUE
;
2226 mpAlphaVDev
->SetBackground( rBackground
);
2229 // -----------------------------------------------------------------------
2231 void OutputDevice::SetRefPoint()
2233 DBG_TRACE( "OutputDevice::SetRefPoint()" );
2234 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2237 mpMetaFile
->AddAction( new MetaRefPointAction( Point(), FALSE
) );
2240 maRefPoint
.X() = maRefPoint
.Y() = 0L;
2243 mpAlphaVDev
->SetRefPoint();
2246 // -----------------------------------------------------------------------
2248 void OutputDevice::SetRefPoint( const Point
& rRefPoint
)
2250 DBG_TRACE( "OutputDevice::SetRefPoint( rRefPoint )" );
2251 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2254 mpMetaFile
->AddAction( new MetaRefPointAction( rRefPoint
, TRUE
) );
2257 maRefPoint
= rRefPoint
;
2260 mpAlphaVDev
->SetRefPoint( rRefPoint
);
2263 // -----------------------------------------------------------------------
2265 void OutputDevice::DrawLine( const Point
& rStartPt
, const Point
& rEndPt
)
2267 DBG_TRACE( "OutputDevice::DrawLine()" );
2268 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2271 mpMetaFile
->AddAction( new MetaLineAction( rStartPt
, rEndPt
) );
2273 if ( !IsDeviceOutputNecessary() || !mbLineColor
|| ImplIsRecordLayout() )
2278 if ( !ImplGetGraphics() )
2282 if ( mbInitClipRegion
)
2283 ImplInitClipRegion();
2284 if ( mbOutputClipped
)
2287 if ( mbInitLineColor
)
2288 ImplInitLineColor();
2290 // #i101598# support AA and snap for lines, too
2291 if((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
2292 && mpGraphics
->supportsOperation(OutDevSupport_B2DDraw
)
2293 && ROP_OVERPAINT
== GetRasterOp()
2296 // at least transform with double precision to device coordinates; this will
2297 // avoid pixel snap of single, appended lines
2298 const basegfx::B2DHomMatrix
aTransform(ImplGetDeviceTransformation());
2299 const basegfx::B2DVector
aB2DLineWidth( 1.0, 1.0 );
2300 basegfx::B2DPolygon aB2DPolyLine
;
2302 aB2DPolyLine
.append(basegfx::B2DPoint(rStartPt
.X(), rStartPt
.Y()));
2303 aB2DPolyLine
.append(basegfx::B2DPoint(rEndPt
.X(), rEndPt
.Y()));
2304 aB2DPolyLine
.transform( aTransform
);
2306 if(mnAntialiasing
& ANTIALIASING_PIXELSNAPHAIRLINE
)
2308 aB2DPolyLine
= basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine
);
2311 if(mpGraphics
->DrawPolyLine(aB2DPolyLine
, aB2DLineWidth
, basegfx::B2DLINEJOIN_NONE
, this))
2317 const Point
aStartPt(ImplLogicToDevicePixel(rStartPt
));
2318 const Point
aEndPt(ImplLogicToDevicePixel(rEndPt
));
2320 mpGraphics
->DrawLine( aStartPt
.X(), aStartPt
.Y(), aEndPt
.X(), aEndPt
.Y(), this );
2323 mpAlphaVDev
->DrawLine( rStartPt
, rEndPt
);
2326 // -----------------------------------------------------------------------
2328 void OutputDevice::DrawLine( const Point
& rStartPt
, const Point
& rEndPt
,
2329 const LineInfo
& rLineInfo
)
2331 DBG_TRACE( "OutputDevice::DrawLine()" );
2332 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2334 if ( rLineInfo
.IsDefault() )
2336 DrawLine( rStartPt
, rEndPt
);
2341 mpMetaFile
->AddAction( new MetaLineAction( rStartPt
, rEndPt
, rLineInfo
) );
2343 if ( !IsDeviceOutputNecessary() || !mbLineColor
|| ( LINE_NONE
== rLineInfo
.GetStyle() ) || ImplIsRecordLayout() )
2346 if( !mpGraphics
&& !ImplGetGraphics() )
2349 if ( mbInitClipRegion
)
2350 ImplInitClipRegion();
2352 if ( mbOutputClipped
)
2355 const LineInfo
aInfo( ImplLogicToDevicePixel( rLineInfo
) );
2357 if( ( aInfo
.GetWidth() > 1L ) || ( LINE_DASH
== aInfo
.GetStyle() ) )
2359 Polygon
aPoly( 2 ); aPoly
[ 0 ] = rStartPt
; aPoly
[ 1 ] = rEndPt
;
2360 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
2361 ImplLineConverter
aLineCvt( ImplLogicToDevicePixel( aPoly
), aInfo
, ( mbRefPoint
) ? &maRefPoint
: NULL
);
2365 if ( aInfo
.GetWidth() > 1 )
2367 const Color
aOldLineColor( maLineColor
);
2368 const Color
aOldFillColor( maFillColor
);
2371 ImplInitLineColor();
2372 SetFillColor( aOldLineColor
);
2373 ImplInitFillColor();
2375 for( const Polygon
* pPoly
= aLineCvt
.ImplGetFirst(); pPoly
; pPoly
= aLineCvt
.ImplGetNext() )
2376 mpGraphics
->DrawPolygon( pPoly
->GetSize(), (const SalPoint
*) pPoly
->GetConstPointAry(), this );
2378 SetFillColor( aOldFillColor
);
2379 SetLineColor( aOldLineColor
);
2383 if ( mbInitLineColor
)
2384 ImplInitLineColor();
2386 for ( const Polygon
* pPoly
= aLineCvt
.ImplGetFirst(); pPoly
; pPoly
= aLineCvt
.ImplGetNext() )
2387 mpGraphics
->DrawLine( (*pPoly
)[ 0 ].X(), (*pPoly
)[ 0 ].Y(), (*pPoly
)[ 1 ].X(), (*pPoly
)[ 1 ].Y(), this );
2389 mpMetaFile
= pOldMetaFile
;
2393 const Point
aStartPt( ImplLogicToDevicePixel( rStartPt
) );
2394 const Point
aEndPt( ImplLogicToDevicePixel( rEndPt
) );
2396 if ( mbInitLineColor
)
2397 ImplInitLineColor();
2399 mpGraphics
->DrawLine( aStartPt
.X(), aStartPt
.Y(), aEndPt
.X(), aEndPt
.Y(), this );
2403 mpAlphaVDev
->DrawLine( rStartPt
, rEndPt
, rLineInfo
);
2406 // -----------------------------------------------------------------------
2408 void OutputDevice::DrawRect( const Rectangle
& rRect
)
2410 DBG_TRACE( "OutputDevice::DrawRect()" );
2411 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2414 mpMetaFile
->AddAction( new MetaRectAction( rRect
) );
2416 if ( !IsDeviceOutputNecessary() || (!mbLineColor
&& !mbFillColor
) || ImplIsRecordLayout() )
2419 Rectangle
aRect( ImplLogicToDevicePixel( rRect
) );
2421 if ( aRect
.IsEmpty() )
2427 if ( !ImplGetGraphics() )
2431 if ( mbInitClipRegion
)
2432 ImplInitClipRegion();
2433 if ( mbOutputClipped
)
2436 if ( mbInitLineColor
)
2437 ImplInitLineColor();
2438 if ( mbInitFillColor
)
2439 ImplInitFillColor();
2441 mpGraphics
->DrawRect( aRect
.Left(), aRect
.Top(), aRect
.GetWidth(), aRect
.GetHeight(), this );
2444 mpAlphaVDev
->DrawRect( rRect
);
2447 // -----------------------------------------------------------------------
2449 void OutputDevice::DrawPolyLine( const Polygon
& rPoly
)
2451 DBG_TRACE( "OutputDevice::DrawPolyLine()" );
2452 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2453 DBG_CHKOBJ( &rPoly
, Polygon
, NULL
);
2456 mpMetaFile
->AddAction( new MetaPolyLineAction( rPoly
) );
2458 USHORT nPoints
= rPoly
.GetSize();
2460 if ( !IsDeviceOutputNecessary() || !mbLineColor
|| (nPoints
< 2) || ImplIsRecordLayout() )
2463 // we need a graphics
2465 if ( !ImplGetGraphics() )
2468 if ( mbInitClipRegion
)
2469 ImplInitClipRegion();
2470 if ( mbOutputClipped
)
2473 if ( mbInitLineColor
)
2474 ImplInitLineColor();
2476 const bool bTryAA((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
2477 && mpGraphics
->supportsOperation(OutDevSupport_B2DDraw
)
2478 && ROP_OVERPAINT
== GetRasterOp()
2481 // use b2dpolygon drawing if possible
2482 if(bTryAA
&& ImpTryDrawPolyLineDirect(rPoly
.getB2DPolygon(), 0.0, basegfx::B2DLINEJOIN_NONE
))
2484 basegfx::B2DPolygon
aB2DPolyLine(rPoly
.getB2DPolygon());
2485 const ::basegfx::B2DHomMatrix aTransform
= ImplGetDeviceTransformation();
2486 const ::basegfx::B2DVector
aB2DLineWidth( 1.0, 1.0 );
2488 // transform the polygon
2489 aB2DPolyLine
.transform( aTransform
);
2491 if(mnAntialiasing
& ANTIALIASING_PIXELSNAPHAIRLINE
)
2493 aB2DPolyLine
= basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine
);
2496 if(mpGraphics
->DrawPolyLine(aB2DPolyLine
, aB2DLineWidth
, basegfx::B2DLINEJOIN_NONE
, this))
2502 Polygon aPoly
= ImplLogicToDevicePixel( rPoly
);
2503 const SalPoint
* pPtAry
= (const SalPoint
*)aPoly
.GetConstPointAry();
2505 // #100127# Forward beziers to sal, if any
2506 if( aPoly
.HasFlags() )
2508 const BYTE
* pFlgAry
= aPoly
.GetConstFlagAry();
2509 if( !mpGraphics
->DrawPolyLineBezier( nPoints
, pPtAry
, pFlgAry
, this ) )
2511 aPoly
= ImplSubdivideBezier(aPoly
);
2512 pPtAry
= (const SalPoint
*)aPoly
.GetConstPointAry();
2513 mpGraphics
->DrawPolyLine( aPoly
.GetSize(), pPtAry
, this );
2518 mpGraphics
->DrawPolyLine( nPoints
, pPtAry
, this );
2522 mpAlphaVDev
->DrawPolyLine( rPoly
);
2525 // -----------------------------------------------------------------------
2527 void OutputDevice::DrawPolyLine( const Polygon
& rPoly
, const LineInfo
& rLineInfo
)
2529 DBG_TRACE( "OutputDevice::DrawPolyLine()" );
2530 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2531 DBG_CHKOBJ( &rPoly
, Polygon
, NULL
);
2533 if ( rLineInfo
.IsDefault() )
2535 DrawPolyLine( rPoly
);
2540 // Try direct Fallback to B2D-Version of DrawPolyLine
2541 if((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
2542 && LINE_SOLID
== rLineInfo
.GetStyle())
2544 DrawPolyLine(rPoly
.getB2DPolygon(), (double)rLineInfo
.GetWidth(), basegfx::B2DLINEJOIN_ROUND
);
2549 mpMetaFile
->AddAction( new MetaPolyLineAction( rPoly
, rLineInfo
) );
2551 ImpDrawPolyLineWithLineInfo(rPoly
, rLineInfo
);
2554 void OutputDevice::ImpDrawPolyLineWithLineInfo(const Polygon
& rPoly
, const LineInfo
& rLineInfo
)
2556 USHORT nPoints
= rPoly
.GetSize();
2558 if ( !IsDeviceOutputNecessary() || !mbLineColor
|| ( nPoints
< 2 ) || ( LINE_NONE
== rLineInfo
.GetStyle() ) || ImplIsRecordLayout() )
2561 Polygon aPoly
= ImplLogicToDevicePixel( rPoly
);
2563 // #100127# LineInfo is not curve-safe, subdivide always
2564 if( aPoly
.HasFlags() )
2566 aPoly
= ImplSubdivideBezier( aPoly
);
2567 nPoints
= aPoly
.GetSize();
2570 // we need a graphics
2571 if ( !mpGraphics
&& !ImplGetGraphics() )
2574 if ( mbInitClipRegion
)
2575 ImplInitClipRegion();
2577 if ( mbOutputClipped
)
2580 const LineInfo
aInfo( ImplLogicToDevicePixel( rLineInfo
) );
2581 const bool bTryAA((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
2582 && mpGraphics
->supportsOperation(OutDevSupport_B2DDraw
)
2583 && ROP_OVERPAINT
== GetRasterOp()
2586 if( aInfo
.GetWidth() > 1L )
2588 const Color
aOldLineColor( maLineColor
);
2589 const Color
aOldFillColor( maFillColor
);
2590 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
2591 ImplLineConverter
aLineCvt( aPoly
, aInfo
, ( mbRefPoint
) ? &maRefPoint
: NULL
);
2595 ImplInitLineColor();
2596 SetFillColor( aOldLineColor
);
2597 ImplInitFillColor();
2602 // #i101491# try AAed version
2603 // Use old on-the-fly geometry preparation, combine with AA
2604 bool bSuccess(true);
2606 for(const Polygon
* pPoly
= aLineCvt
.ImplGetFirst(); bSuccess
&& pPoly
; pPoly
= aLineCvt
.ImplGetNext())
2608 bSuccess
= mpGraphics
->DrawPolyPolygon(basegfx::B2DPolyPolygon(pPoly
->getB2DPolygon()), 0.0, this);
2619 for( const Polygon
* pPoly
= aLineCvt
.ImplGetFirst(); pPoly
; pPoly
= aLineCvt
.ImplGetNext() )
2621 mpGraphics
->DrawPolygon( pPoly
->GetSize(), (const SalPoint
*) pPoly
->GetConstPointAry(), this );
2625 SetLineColor( aOldLineColor
);
2626 SetFillColor( aOldFillColor
);
2627 mpMetaFile
= pOldMetaFile
;
2631 if ( mbInitLineColor
)
2632 ImplInitLineColor();
2633 if ( LINE_DASH
== aInfo
.GetStyle() )
2635 ImplLineConverter
aLineCvt( aPoly
, aInfo
, ( mbRefPoint
) ? &maRefPoint
: NULL
);
2636 for( const Polygon
* pPoly
= aLineCvt
.ImplGetFirst(); pPoly
; pPoly
= aLineCvt
.ImplGetNext() )
2637 mpGraphics
->DrawPolyLine( pPoly
->GetSize(), (const SalPoint
*)pPoly
->GetConstPointAry(), this );
2640 mpGraphics
->DrawPolyLine( nPoints
, (const SalPoint
*) aPoly
.GetConstPointAry(), this );
2644 mpAlphaVDev
->DrawPolyLine( rPoly
, rLineInfo
);
2647 // -----------------------------------------------------------------------
2649 void OutputDevice::DrawPolygon( const Polygon
& rPoly
)
2651 DBG_TRACE( "OutputDevice::DrawPolygon()" );
2652 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2653 DBG_CHKOBJ( &rPoly
, Polygon
, NULL
);
2656 mpMetaFile
->AddAction( new MetaPolygonAction( rPoly
) );
2658 USHORT nPoints
= rPoly
.GetSize();
2660 if ( !IsDeviceOutputNecessary() || (!mbLineColor
&& !mbFillColor
) || (nPoints
< 2) || ImplIsRecordLayout() )
2663 // we need a graphics
2665 if ( !ImplGetGraphics() )
2668 if ( mbInitClipRegion
)
2669 ImplInitClipRegion();
2670 if ( mbOutputClipped
)
2673 if ( mbInitLineColor
)
2674 ImplInitLineColor();
2675 if ( mbInitFillColor
)
2676 ImplInitFillColor();
2678 // use b2dpolygon drawing if possible
2679 if((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
2680 && mpGraphics
->supportsOperation(OutDevSupport_B2DDraw
)
2681 && ROP_OVERPAINT
== GetRasterOp()
2682 && (IsLineColor() || IsFillColor()))
2684 const ::basegfx::B2DHomMatrix aTransform
= ImplGetDeviceTransformation();
2685 basegfx::B2DPolygon
aB2DPolygon(rPoly
.getB2DPolygon());
2686 bool bSuccess(true);
2688 // transform the polygon and ensure closed
2689 aB2DPolygon
.transform(aTransform
);
2690 aB2DPolygon
.setClosed(true);
2694 bSuccess
= mpGraphics
->DrawPolyPolygon(basegfx::B2DPolyPolygon(aB2DPolygon
), 0.0, this);
2697 if(bSuccess
&& IsLineColor())
2699 const ::basegfx::B2DVector
aB2DLineWidth( 1.0, 1.0 );
2701 if(mnAntialiasing
& ANTIALIASING_PIXELSNAPHAIRLINE
)
2703 aB2DPolygon
= basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon
);
2706 bSuccess
= mpGraphics
->DrawPolyLine(aB2DPolygon
, aB2DLineWidth
, basegfx::B2DLINEJOIN_NONE
, this);
2715 Polygon aPoly
= ImplLogicToDevicePixel( rPoly
);
2716 const SalPoint
* pPtAry
= (const SalPoint
*)aPoly
.GetConstPointAry();
2718 // #100127# Forward beziers to sal, if any
2719 if( aPoly
.HasFlags() )
2721 const BYTE
* pFlgAry
= aPoly
.GetConstFlagAry();
2722 if( !mpGraphics
->DrawPolygonBezier( nPoints
, pPtAry
, pFlgAry
, this ) )
2724 aPoly
= ImplSubdivideBezier(aPoly
);
2725 pPtAry
= (const SalPoint
*)aPoly
.GetConstPointAry();
2726 mpGraphics
->DrawPolygon( aPoly
.GetSize(), pPtAry
, this );
2731 mpGraphics
->DrawPolygon( nPoints
, pPtAry
, this );
2734 mpAlphaVDev
->DrawPolygon( rPoly
);
2737 // -----------------------------------------------------------------------
2739 void OutputDevice::DrawPolyPolygon( const PolyPolygon
& rPolyPoly
)
2741 DBG_TRACE( "OutputDevice::DrawPolyPolygon()" );
2742 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2743 DBG_CHKOBJ( &rPolyPoly
, PolyPolygon
, NULL
);
2746 mpMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPoly
) );
2748 USHORT nPoly
= rPolyPoly
.Count();
2750 if ( !IsDeviceOutputNecessary() || (!mbLineColor
&& !mbFillColor
) || !nPoly
|| ImplIsRecordLayout() )
2753 // we need a graphics
2755 if ( !ImplGetGraphics() )
2758 if ( mbInitClipRegion
)
2759 ImplInitClipRegion();
2760 if ( mbOutputClipped
)
2763 if ( mbInitLineColor
)
2764 ImplInitLineColor();
2765 if ( mbInitFillColor
)
2766 ImplInitFillColor();
2768 // use b2dpolygon drawing if possible
2769 if((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
2770 && mpGraphics
->supportsOperation(OutDevSupport_B2DDraw
)
2771 && ROP_OVERPAINT
== GetRasterOp()
2772 && (IsLineColor() || IsFillColor()))
2774 const ::basegfx::B2DHomMatrix aTransform
= ImplGetDeviceTransformation();
2775 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rPolyPoly
.getB2DPolyPolygon());
2776 bool bSuccess(true);
2778 // transform the polygon and ensure closed
2779 aB2DPolyPolygon
.transform(aTransform
);
2780 aB2DPolyPolygon
.setClosed(true);
2784 bSuccess
= mpGraphics
->DrawPolyPolygon(aB2DPolyPolygon
, 0.0, this);
2787 if(bSuccess
&& IsLineColor())
2789 const ::basegfx::B2DVector
aB2DLineWidth( 1.0, 1.0 );
2791 if(mnAntialiasing
& ANTIALIASING_PIXELSNAPHAIRLINE
)
2793 aB2DPolyPolygon
= basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon
);
2796 for(sal_uInt32
a(0); bSuccess
&& a
< aB2DPolyPolygon
.count(); a
++)
2798 bSuccess
= mpGraphics
->DrawPolyLine(aB2DPolyPolygon
.getB2DPolygon(a
), aB2DLineWidth
, basegfx::B2DLINEJOIN_NONE
, this);
2810 // #100127# Map to DrawPolygon
2811 Polygon aPoly
= rPolyPoly
.GetObject( 0 );
2812 if( aPoly
.GetSize() >= 2 )
2814 GDIMetaFile
* pOldMF
= mpMetaFile
;
2817 DrawPolygon( aPoly
);
2819 mpMetaFile
= pOldMF
;
2824 // #100127# moved real PolyPolygon draw to separate method,
2825 // have to call recursively, avoiding duplicate
2826 // ImplLogicToDevicePixel calls
2827 ImplDrawPolyPolygon( nPoly
, ImplLogicToDevicePixel( rPolyPoly
) );
2830 mpAlphaVDev
->DrawPolyPolygon( rPolyPoly
);
2833 // -----------------------------------------------------------------------
2835 void OutputDevice::DrawPolygon( const ::basegfx::B2DPolygon
& rB2DPolygon
)
2837 // AW: Do NOT paint empty polygons
2838 if(rB2DPolygon
.count())
2840 ::basegfx::B2DPolyPolygon
aPP( rB2DPolygon
);
2841 DrawPolyPolygon( aPP
);
2845 // -----------------------------------------------------------------------
2846 // Caution: This method is nearly the same as
2847 // OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency),
2848 // so when changes are made here do not forget to make change sthere, too
2850 void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon
& rB2DPolyPoly
)
2852 DBG_TRACE( "OutputDevice::DrawPolyPolygon(B2D&)" );
2853 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2856 // MetaB2DPolyPolygonAction is not implemented yet:
2857 // according to AW adding it is very dangerous since there is a lot
2858 // of code that uses the metafile actions directly and unless every
2859 // place that does this knows about the new action we need to fallback
2861 mpMetaFile
->AddAction( new MetaB2DPolyPolygonAction( rB2DPolyPoly
) );
2864 mpMetaFile
->AddAction( new MetaPolyPolygonAction( PolyPolygon( rB2DPolyPoly
) ) );
2868 ImpDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly
);
2871 void OutputDevice::ImpDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon
& rB2DPolyPoly
)
2873 // AW: Do NOT paint empty PolyPolygons
2874 if(!rB2DPolyPoly
.count())
2877 // we need a graphics
2879 if( !ImplGetGraphics() )
2882 if( mbInitClipRegion
)
2883 ImplInitClipRegion();
2884 if( mbOutputClipped
)
2887 if( mbInitLineColor
)
2888 ImplInitLineColor();
2889 if( mbInitFillColor
)
2890 ImplInitFillColor();
2892 if((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
2893 && mpGraphics
->supportsOperation(OutDevSupport_B2DDraw
)
2894 && ROP_OVERPAINT
== GetRasterOp()
2895 && (IsLineColor() || IsFillColor()))
2897 const basegfx::B2DHomMatrix
aTransform(ImplGetDeviceTransformation());
2898 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rB2DPolyPoly
);
2899 bool bSuccess(true);
2901 // transform the polygon and ensure closed
2902 aB2DPolyPolygon
.transform(aTransform
);
2903 aB2DPolyPolygon
.setClosed(true);
2907 bSuccess
= mpGraphics
->DrawPolyPolygon(aB2DPolyPolygon
, 0.0, this);
2910 if(bSuccess
&& IsLineColor())
2912 const ::basegfx::B2DVector
aB2DLineWidth( 1.0, 1.0 );
2914 if(mnAntialiasing
& ANTIALIASING_PIXELSNAPHAIRLINE
)
2916 aB2DPolyPolygon
= basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon
);
2919 for(sal_uInt32
a(0);bSuccess
&& a
< aB2DPolyPolygon
.count(); a
++)
2921 bSuccess
= mpGraphics
->DrawPolyLine(aB2DPolyPolygon
.getB2DPolygon(a
), aB2DLineWidth
, basegfx::B2DLINEJOIN_NONE
, this);
2931 // fallback to old polygon drawing if needed
2932 const PolyPolygon
aToolsPolyPolygon( rB2DPolyPoly
);
2933 const PolyPolygon aPixelPolyPolygon
= ImplLogicToDevicePixel( aToolsPolyPolygon
);
2934 ImplDrawPolyPolygon( aPixelPolyPolygon
.Count(), aPixelPolyPolygon
);
2937 // -----------------------------------------------------------------------
2939 bool OutputDevice::ImpTryDrawPolyLineDirect(
2940 const basegfx::B2DPolygon
& rB2DPolygon
,
2942 basegfx::B2DLineJoin eLineJoin
)
2944 const basegfx::B2DHomMatrix aTransform
= ImplGetDeviceTransformation();
2945 basegfx::B2DVector
aB2DLineWidth(1.0, 1.0);
2947 // transform the line width if used
2948 if( fLineWidth
!= 0.0 )
2950 aB2DLineWidth
= aTransform
* ::basegfx::B2DVector( fLineWidth
, fLineWidth
);
2953 // transform the polygon
2954 basegfx::B2DPolygon
aB2DPolygon(rB2DPolygon
);
2955 aB2DPolygon
.transform(aTransform
);
2957 if((mnAntialiasing
& ANTIALIASING_PIXELSNAPHAIRLINE
)
2958 && aB2DPolygon
.count() < 1000)
2960 // #i98289#, #i101491#
2961 // better to remove doubles on device coordinates. Also assume from a given amount
2962 // of points that the single edges are not long enough to smooth
2963 aB2DPolygon
.removeDoublePoints();
2964 aB2DPolygon
= basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon
);
2967 // draw the polyline
2968 return mpGraphics
->DrawPolyLine(aB2DPolygon
, aB2DLineWidth
, eLineJoin
, this);
2971 void OutputDevice::DrawPolyLine(
2972 const basegfx::B2DPolygon
& rB2DPolygon
,
2974 basegfx::B2DLineJoin eLineJoin
)
2976 DBG_TRACE( "OutputDevice::DrawPolyLine(B2D&)" );
2977 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
2978 (void)eLineJoin
; // ATM used in UNX, but not in WNT, access it for warning-free
2980 #if 0 // MetaB2DPolyLineAction is not implemented yet:
2981 // according to AW adding it is very dangerous since there is a lot
2982 // of code that uses the metafile actions directly and unless every
2983 // place that does this knows about the new action we need to fallback
2985 mpMetaFile
->AddAction( new MetaB2DPolyLineAction( rB2DPolygon
) );
2990 if( fLineWidth
!= 0.0 )
2991 aLineInfo
.SetWidth( static_cast<long>(fLineWidth
+0.5) );
2992 const Polygon
aToolsPolygon( rB2DPolygon
);
2993 mpMetaFile
->AddAction( new MetaPolyLineAction( aToolsPolygon
, aLineInfo
) );
2997 // AW: Do NOT paint empty PolyPolygons
2998 if(!rB2DPolygon
.count())
3001 // we need a graphics
3003 if( !ImplGetGraphics() )
3006 if( mbInitClipRegion
)
3007 ImplInitClipRegion();
3008 if( mbOutputClipped
)
3011 if( mbInitLineColor
)
3012 ImplInitLineColor();
3014 const bool bTryAA((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
3015 && mpGraphics
->supportsOperation(OutDevSupport_B2DDraw
)
3016 && ROP_OVERPAINT
== GetRasterOp()
3019 // use b2dpolygon drawing if possible
3020 if(bTryAA
&& ImpTryDrawPolyLineDirect(rB2DPolygon
, fLineWidth
, eLineJoin
))
3026 // no output yet; fallback to geometry decomposition and use filled polygon paint
3027 // when line is fat and not too complex. ImpDrawPolyPolygonWithB2DPolyPolygon
3028 // will do internal needed AA checks etc.
3029 if(fLineWidth
>= 2.5
3030 && rB2DPolygon
.count()
3031 && rB2DPolygon
.count() <= 1000)
3033 const double fHalfLineWidth((fLineWidth
* 0.5) + 0.5);
3034 const basegfx::B2DPolyPolygon
aAreaPolyPolygon(basegfx::tools::createAreaGeometry(
3035 rB2DPolygon
, fHalfLineWidth
, eLineJoin
));
3037 const Color
aOldLineColor(maLineColor
);
3038 const Color
aOldFillColor(maFillColor
);
3041 ImplInitLineColor();
3042 SetFillColor(aOldLineColor
);
3043 ImplInitFillColor();
3045 ImpDrawPolyPolygonWithB2DPolyPolygon(aAreaPolyPolygon
);
3047 SetLineColor(aOldLineColor
);
3048 ImplInitLineColor();
3049 SetFillColor(aOldFillColor
);
3050 ImplInitFillColor();
3054 // when AA it is necessary to also paint the filled polygon's outline
3055 // to avoid optical gaps
3056 for(sal_uInt32
a(0); a
< aAreaPolyPolygon
.count(); a
++)
3058 ImpTryDrawPolyLineDirect(aAreaPolyPolygon
.getB2DPolygon(a
), 0.0, basegfx::B2DLINEJOIN_NONE
);
3063 // fallback to old polygon drawing if needed. This will really
3064 // use ImplLineConverter, but still try to AA lines
3065 const Polygon
aToolsPolygon( rB2DPolygon
);
3067 if( fLineWidth
!= 0.0 )
3068 aLineInfo
.SetWidth( static_cast<long>(fLineWidth
+0.5) );
3069 ImpDrawPolyLineWithLineInfo( aToolsPolygon
, aLineInfo
);
3072 // -----------------------------------------------------------------------
3074 void OutputDevice::Push( USHORT nFlags
)
3076 DBG_TRACE( "OutputDevice::Push()" );
3077 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
3080 mpMetaFile
->AddAction( new MetaPushAction( nFlags
) );
3082 ImplObjStack
* pData
= new ImplObjStack
;
3083 pData
->mpPrev
= mpObjStack
;
3086 pData
->mnFlags
= nFlags
;
3088 if ( nFlags
& PUSH_LINECOLOR
)
3091 pData
->mpLineColor
= new Color( maLineColor
);
3093 pData
->mpLineColor
= NULL
;
3095 if ( nFlags
& PUSH_FILLCOLOR
)
3098 pData
->mpFillColor
= new Color( maFillColor
);
3100 pData
->mpFillColor
= NULL
;
3102 if ( nFlags
& PUSH_FONT
)
3103 pData
->mpFont
= new Font( maFont
);
3104 if ( nFlags
& PUSH_TEXTCOLOR
)
3105 pData
->mpTextColor
= new Color( GetTextColor() );
3106 if ( nFlags
& PUSH_TEXTFILLCOLOR
)
3108 if ( IsTextFillColor() )
3109 pData
->mpTextFillColor
= new Color( GetTextFillColor() );
3111 pData
->mpTextFillColor
= NULL
;
3113 if ( nFlags
& PUSH_TEXTLINECOLOR
)
3115 if ( IsTextLineColor() )
3116 pData
->mpTextLineColor
= new Color( GetTextLineColor() );
3118 pData
->mpTextLineColor
= NULL
;
3120 if ( nFlags
& PUSH_OVERLINECOLOR
)
3122 if ( IsOverlineColor() )
3123 pData
->mpOverlineColor
= new Color( GetOverlineColor() );
3125 pData
->mpOverlineColor
= NULL
;
3127 if ( nFlags
& PUSH_TEXTALIGN
)
3128 pData
->meTextAlign
= GetTextAlign();
3129 if( nFlags
& PUSH_TEXTLAYOUTMODE
)
3130 pData
->mnTextLayoutMode
= GetLayoutMode();
3131 if( nFlags
& PUSH_TEXTLANGUAGE
)
3132 pData
->meTextLanguage
= GetDigitLanguage();
3133 if ( nFlags
& PUSH_RASTEROP
)
3134 pData
->meRasterOp
= GetRasterOp();
3135 if ( nFlags
& PUSH_MAPMODE
)
3138 pData
->mpMapMode
= new MapMode( maMapMode
);
3140 pData
->mpMapMode
= NULL
;
3142 if ( nFlags
& PUSH_CLIPREGION
)
3145 pData
->mpClipRegion
= new Region( maRegion
);
3147 pData
->mpClipRegion
= NULL
;
3149 if ( nFlags
& PUSH_REFPOINT
)
3152 pData
->mpRefPoint
= new Point( maRefPoint
);
3154 pData
->mpRefPoint
= NULL
;
3158 mpAlphaVDev
->Push();
3161 // -----------------------------------------------------------------------
3163 void OutputDevice::Pop()
3165 DBG_TRACE( "OutputDevice::Pop()" );
3166 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
3169 mpMetaFile
->AddAction( new MetaPopAction() );
3171 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
3172 ImplObjStack
* pData
= mpObjStack
;
3177 DBG_ERRORFILE( "OutputDevice::Pop() without OutputDevice::Push()" );
3184 mpObjStack
= pData
->mpPrev
;
3186 if ( pData
->mnFlags
& PUSH_LINECOLOR
)
3188 if ( pData
->mpLineColor
)
3189 SetLineColor( *pData
->mpLineColor
);
3193 if ( pData
->mnFlags
& PUSH_FILLCOLOR
)
3195 if ( pData
->mpFillColor
)
3196 SetFillColor( *pData
->mpFillColor
);
3200 if ( pData
->mnFlags
& PUSH_FONT
)
3201 SetFont( *pData
->mpFont
);
3202 if ( pData
->mnFlags
& PUSH_TEXTCOLOR
)
3203 SetTextColor( *pData
->mpTextColor
);
3204 if ( pData
->mnFlags
& PUSH_TEXTFILLCOLOR
)
3206 if ( pData
->mpTextFillColor
)
3207 SetTextFillColor( *pData
->mpTextFillColor
);
3211 if ( pData
->mnFlags
& PUSH_TEXTLINECOLOR
)
3213 if ( pData
->mpTextLineColor
)
3214 SetTextLineColor( *pData
->mpTextLineColor
);
3218 if ( pData
->mnFlags
& PUSH_OVERLINECOLOR
)
3220 if ( pData
->mpOverlineColor
)
3221 SetOverlineColor( *pData
->mpOverlineColor
);
3225 if ( pData
->mnFlags
& PUSH_TEXTALIGN
)
3226 SetTextAlign( pData
->meTextAlign
);
3227 if( pData
->mnFlags
& PUSH_TEXTLAYOUTMODE
)
3228 SetLayoutMode( pData
->mnTextLayoutMode
);
3229 if( pData
->mnFlags
& PUSH_TEXTLANGUAGE
)
3230 SetDigitLanguage( pData
->meTextLanguage
);
3231 if ( pData
->mnFlags
& PUSH_RASTEROP
)
3232 SetRasterOp( pData
->meRasterOp
);
3233 if ( pData
->mnFlags
& PUSH_MAPMODE
)
3235 if ( pData
->mpMapMode
)
3236 SetMapMode( *pData
->mpMapMode
);
3240 if ( pData
->mnFlags
& PUSH_CLIPREGION
)
3241 ImplSetClipRegion( pData
->mpClipRegion
);
3242 if ( pData
->mnFlags
& PUSH_REFPOINT
)
3244 if ( pData
->mpRefPoint
)
3245 SetRefPoint( *pData
->mpRefPoint
);
3250 ImplDeleteObjStack( pData
);
3252 mpMetaFile
= pOldMetaFile
;
3255 // -----------------------------------------------------------------------
3257 void OutputDevice::SetConnectMetaFile( GDIMetaFile
* pMtf
)
3262 // -----------------------------------------------------------------------
3264 void OutputDevice::EnableOutput( BOOL bEnable
)
3266 mbOutput
= (bEnable
!= 0);
3269 mpAlphaVDev
->EnableOutput( bEnable
);
3272 // -----------------------------------------------------------------------
3274 void OutputDevice::SetSettings( const AllSettings
& rSettings
)
3276 maSettings
= rSettings
;
3279 mpAlphaVDev
->SetSettings( rSettings
);
3282 // -----------------------------------------------------------------------
3284 USHORT
OutputDevice::GetBitCount() const
3286 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
3288 if ( meOutDevType
== OUTDEV_VIRDEV
)
3289 return ((VirtualDevice
*)this)->mnBitCount
;
3291 // we need a graphics
3294 if ( !((OutputDevice
*)this)->ImplGetGraphics() )
3298 return (USHORT
)mpGraphics
->GetBitCount();
3301 // -----------------------------------------------------------------------
3303 USHORT
OutputDevice::GetAlphaBitCount() const
3305 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
3307 if ( meOutDevType
== OUTDEV_VIRDEV
&&
3308 mpAlphaVDev
!= NULL
)
3310 return mpAlphaVDev
->GetBitCount();
3316 // -----------------------------------------------------------------------
3318 ULONG
OutputDevice::GetColorCount() const
3320 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
3322 const USHORT nBitCount
= GetBitCount();
3323 return( ( nBitCount
> 31 ) ? ULONG_MAX
: ( ( (ULONG
) 1 ) << nBitCount
) );
3326 // -----------------------------------------------------------------------
3328 BOOL
OutputDevice::HasAlpha()
3330 return mpAlphaVDev
!= NULL
;
3333 // -----------------------------------------------------------------------
3335 ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XGraphics
> OutputDevice::CreateUnoGraphics()
3337 UnoWrapperBase
* pWrapper
= Application::GetUnoWrapper();
3338 return pWrapper
? pWrapper
->CreateGraphics( this ) : ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XGraphics
>();
3341 // -----------------------------------------------------------------------
3343 SystemGraphicsData
OutputDevice::GetSystemGfxData() const
3347 if ( !ImplGetGraphics() )
3348 return SystemGraphicsData();
3351 return mpGraphics
->GetGraphicsData();
3354 // -----------------------------------------------------------------------
3356 ::com::sun::star::uno::Any
OutputDevice::GetSystemGfxDataAny() const
3358 ::com::sun::star::uno::Any aRet
;
3359 const SystemGraphicsData aSysData
= GetSystemGfxData();
3360 ::com::sun::star::uno::Sequence
< sal_Int8
> aSeq( (sal_Int8
*)&aSysData
,
3363 return uno::makeAny(aSeq
);
3366 // -----------------------------------------------------------------------
3368 ::com::sun::star::uno::Reference
< ::com::sun::star::rendering::XCanvas
> OutputDevice::GetCanvas() const
3370 uno::Sequence
< uno::Any
> aArg(6);
3372 aArg
[ 0 ] = uno::makeAny( reinterpret_cast<sal_Int64
>(this) );
3373 aArg
[ 2 ] = uno::makeAny( ::com::sun::star::awt::Rectangle( mnOutOffX
, mnOutOffY
, mnOutWidth
, mnOutHeight
) );
3374 aArg
[ 3 ] = uno::makeAny( sal_False
);
3375 aArg
[ 5 ] = GetSystemGfxDataAny();
3377 uno::Reference
<lang::XMultiServiceFactory
> xFactory
= vcl::unohelper::GetMultiServiceFactory();
3379 uno::Reference
<rendering::XCanvas
> xCanvas
;
3381 // Create canvas instance with window handle
3382 // =========================================
3383 if ( xFactory
.is() )
3385 static uno::Reference
<lang::XMultiServiceFactory
> xCanvasFactory(
3386 xFactory
->createInstance(
3387 OUString( RTL_CONSTASCII_USTRINGPARAM(
3389 "rendering.CanvasFactory") ) ),
3391 if(xCanvasFactory
.is())
3394 xCanvasFactory
->createInstanceWithArguments(
3395 OUString( RTL_CONSTASCII_USTRINGPARAM(
3396 "com.sun.star.rendering.Canvas" )),
3405 // -----------------------------------------------------------------------