merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / gdi / outdev.cxx
blob64087c91b7bdfc3a962cbb11aafec1ebe109b33e
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>
35 #ifndef _SV_SVSYS_HXX
36 #include <svsys.h>
37 #endif
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>
47 #ifndef _POLY_HXX
48 #include <tools/poly.hxx>
49 #endif
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 )
83 DBG_NAME( Polygon )
84 DBG_NAME( PolyPolygon )
85 DBG_NAMEEX( Region )
87 // -----------------------------------------------------------------------
89 #ifdef DBG_UTIL
90 const char* ImplDbgCheckOutputDevice( const void* pObj )
92 DBG_TESTSOLARMUTEX();
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";
102 return NULL;
104 #endif
106 // =======================================================================
108 #define OUTDEV_POLYPOLY_STACKBUF 32
110 // =======================================================================
112 struct ImplObjStack
114 ImplObjStack* mpPrev;
115 MapMode* mpMapMode;
116 Region* mpClipRegion;
117 Color* mpLineColor;
118 Color* mpFillColor;
119 Font* mpFont;
120 Color* mpTextColor;
121 Color* mpTextFillColor;
122 Color* mpTextLineColor;
123 Color* mpOverlineColor;
124 Point* mpRefPoint;
125 TextAlign meTextAlign;
126 RasterOp meRasterOp;
127 ULONG mnTextLayoutMode;
128 LanguageType meTextLanguage;
129 USHORT mnFlags;
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;
181 delete pObjStack;
184 // -----------------------------------------------------------------------
186 bool OutputDevice::ImplIsAntiparallel() const
188 bool bRet = false;
189 if( ImplGetGraphics() )
191 if( ( (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) && ! IsRTLEnabled() ) ||
192 ( ! (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) && IsRTLEnabled() ) )
194 bRet = true;
197 return bRet;
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;
211 if( !pGraphics )
213 if( !mpGraphics )
214 if( !ImplGetGraphics() )
215 return false;
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();
226 return true;
229 long nX;
230 long nY;
231 long nWidth;
232 long nHeight;
233 ULONG nRectCount;
234 ImplRegionInfo aInfo;
235 BOOL bRegionRect;
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
260 // format of X11).
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(),
267 aTmpRect.Top(),
268 aTmpRect.GetWidth(),
269 aTmpRect.GetHeight(),
270 pOutDev ) )
272 bClipRegion = FALSE;
275 else
277 // #i79850# Fake off-screen clip
278 if ( !pGraphics->UnionClipRegion( nDeviceWidth+1,
279 nDeviceHeight+1,
280 1, 1,
281 pOutDev ) )
283 bClipRegion = FALSE;
286 DBG_ASSERT( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't create region" );
287 bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
290 else
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 ) )
298 bClipRegion = FALSE;
299 DBG_ASSERT( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't cerate region" );
300 bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
303 pGraphics->EndSetClipRegion();
304 return bClipRegion;
308 // =======================================================================
310 Polygon ImplSubdivideBezier( const Polygon& rPoly )
312 Polygon aPoly;
314 // #100127# Use adaptive subdivide instead of fixed 25 segments
315 rPoly.AdaptiveSubdivide( aPoly );
317 return 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) ) );
329 return aPolyPoly;
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
338 if(!nPoly)
339 return;
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];
355 else
357 pPointAry = aStackAry1;
358 pPointAryAry = aStackAry2;
359 pFlagAryAry = (const BYTE**)aStackAry3;
363 const Polygon& rPoly = rPolyPoly.GetObject( i );
364 USHORT nSize = rPoly.GetSize();
365 if ( nSize )
367 pPointAry[j] = nSize;
368 pPointAryAry[j] = (PCONSTSALPOINT)rPoly.GetConstPointAry();
369 pFlagAryAry[j] = rPoly.GetConstFlagAry();
370 last = i;
372 if( pFlagAryAry[j] )
373 bHaveBezier = sal_True;
375 ++j;
378 ++i;
380 while ( i < nPoly );
382 if ( j == 1 )
384 // #100127# Forward beziers to sal, if any
385 if( bHaveBezier )
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 );
393 else
395 mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this );
398 else
400 // #100127# Forward beziers to sal, if any
401 if( bHaveBezier )
403 if( !mpGraphics->DrawPolyPolygonBezier( j, pPointAry, pPointAryAry, pFlagAryAry, this ) )
405 PolyPolygon aPolyPoly = ImplSubdivideBezier( rPolyPoly );
406 ImplDrawPolyPolygon( aPolyPoly.Count(), aPolyPoly );
409 else
411 mpGraphics->DrawPolyPolygon( j, pPointAry, pPointAryAry, this );
415 if ( pPointAry != aStackAry1 )
417 delete[] pPointAry;
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 );
433 mpGraphics = NULL;
434 mpUnoGraphicsList = NULL;
435 mpPrevGraphics = NULL;
436 mpNextGraphics = NULL;
437 mpMetaFile = NULL;
438 mpFontEntry = NULL;
439 mpFontCache = NULL;
440 mpFontList = NULL;
441 mpGetDevFontList = NULL;
442 mpGetDevSizeList = NULL;
443 mpObjStack = NULL;
444 mpOutDevData = NULL;
445 mpPDFWriter = NULL;
446 mpAlphaVDev = NULL;
447 mpExtOutDevData = NULL;
448 mnOutOffX = 0;
449 mnOutOffY = 0;
450 mnOutWidth = 0;
451 mnOutHeight = 0;
452 mnDPIX = 0;
453 mnDPIY = 0;
454 mnTextOffX = 0;
455 mnTextOffY = 0;
456 mnOutOffOrigX = 0;
457 mnOutOffLogicX = 0;
458 mnOutOffOrigY = 0;
459 mnOutOffLogicY = 0;
460 mnEmphasisAscent = 0;
461 mnEmphasisDescent = 0;
462 mnDrawMode = 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;
468 mbMap = FALSE;
469 mbMapIsDefault = TRUE;
470 mbClipRegion = FALSE;
471 mbBackground = FALSE;
472 mbOutput = TRUE;
473 mbDevOutput = FALSE;
474 mbOutputClipped = FALSE;
475 maTextColor = Color( COL_BLACK );
476 maOverlineColor = Color( COL_TRANSPARENT );
477 meTextAlign = maFont.GetAlign();
478 meRasterOp = ROP_OVERPAINT;
479 mnAntialiasing = 0;
480 meTextLanguage = 0; // TODO: get default from configuration?
481 mbLineColor = TRUE;
482 mbFillColor = TRUE;
483 mbInitLineColor = TRUE;
484 mbInitFillColor = TRUE;
485 mbInitFont = TRUE;
486 mbInitTextColor = TRUE;
487 mbInitClipRegion = TRUE;
488 mbClipRegionSet = FALSE;
489 mbKerning = FALSE;
490 mbNewFont = TRUE;
491 mbTextLines = FALSE;
492 mbTextSpecial = FALSE;
493 mbRefPoint = FALSE;
494 mbEnableRTL = FALSE; // mirroring must be explicitly allowed (typically for windows only)
496 // struct ImplMapRes
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 );
519 if ( pWrapper )
520 pWrapper->ReleaseAllGraphics( this );
521 delete mpUnoGraphicsList;
522 mpUnoGraphicsList = NULL;
525 if ( mpOutDevData )
526 ImplDeInitOutDevData();
528 ImplObjStack* pData = mpObjStack;
529 if ( pData )
531 DBG_ERRORFILE( "OutputDevice::~OutputDevice(): OutputDevice::Push() calls != OutputDevice::Pop() calls" );
532 while ( pData )
534 ImplObjStack* pTemp = pData;
535 pData = pData->mpPrev;
536 ImplDeleteObjStack( pTemp );
540 // release the active font instance
541 if( mpFontEntry )
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
552 if( mpFontCache
553 && (mpFontCache != ImplGetSVData()->maGDIData.mpScreenFontCache)
554 && (ImplGetSVData()->maGDIData.mpScreenFontCache != NULL) )
556 delete mpFontCache;
557 mpFontCache = NULL;
560 // release ImplFontList specific to this OutputDevice
561 // TODO: refcount ImplFontList
562 if( mpFontList
563 && (mpFontList != ImplGetSVData()->maGDIData.mpScreenFontList)
564 && (ImplGetSVData()->maGDIData.mpScreenFontList != NULL) )
566 mpFontList->Clear();
567 delete mpFontList;
568 mpFontList = NULL;
571 delete mpAlphaVDev;
574 bool OutputDevice::supportsOperation( OutDevSupportType eType ) const
576 if( !mpGraphics )
577 if( !ImplGetGraphics() )
578 return false;
579 const bool bHasSupport = mpGraphics->supportsOperation( eType );
580 return bHasSupport;
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
593 // ...hopefully
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);
603 if( pWin )
604 pWin->StateChanged( STATE_CHANGE_MIRRORING );
606 if( mpAlphaVDev )
607 mpAlphaVDev->EnableRTL( bEnable );
610 BOOL OutputDevice::ImplHasMirroredGraphics()
612 // HOTFIX for #i55719#
613 if( meOutDevType == OUTDEV_PRINTER )
614 return FALSE;
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
638 long nX;
639 long nY;
640 long nWidth;
641 long nHeight;
642 ImplRegionInfo aInfo;
643 BOOL bRegionRect;
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();
664 if ( mpGraphics )
665 return TRUE;
667 mbInitLineColor = TRUE;
668 mbInitFillColor = TRUE;
669 mbInitFont = 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
680 if ( !mpGraphics )
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 )
687 break;
688 pReleaseOutDev = pReleaseOutDev->mpPrevGraphics;
691 if ( pReleaseOutDev )
693 // steal the wingraphics from the other outdev
694 mpGraphics = pReleaseOutDev->mpGraphics;
695 pReleaseOutDev->ImplReleaseGraphics( FALSE );
697 else
699 // if needed retry after releasing least recently used wingraphics
700 while ( !mpGraphics )
702 if ( !pSVData->maGDIData.mpLastWinGraphics )
703 break;
704 pSVData->maGDIData.mpLastWinGraphics->ImplReleaseGraphics();
705 mpGraphics = pWindow->mpWindowImpl->mpFrame->GetGraphics();
710 // update global LRU list of wingraphics
711 if ( mpGraphics )
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 )
732 break;
733 pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics();
734 mpGraphics = pVirDev->mpVirDev->GetGraphics();
736 // update global LRU list of virtual device graphics
737 if ( mpGraphics )
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 )
762 break;
763 pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics();
764 mpGraphics = pVirDev->mpVirDev->GetGraphics();
766 // update global LRU list of virtual device graphics
767 if ( mpGraphics )
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);
777 else
779 mpGraphics = pPrinter->mpInfoPrinter->GetGraphics();
780 // if needed retry after releasing least recently used printer graphics
781 while ( !mpGraphics )
783 if ( !pSVData->maGDIData.mpLastPrnGraphics )
784 break;
785 pSVData->maGDIData.mpLastPrnGraphics->ImplReleaseGraphics();
786 mpGraphics = pPrinter->mpInfoPrinter->GetGraphics();
788 // update global LRU list of printer graphics
789 if ( mpGraphics )
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);
801 if ( mpGraphics )
803 mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp), ROP_INVERT == meRasterOp );
804 mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
805 return TRUE;
808 return FALSE;
811 // -----------------------------------------------------------------------
813 void OutputDevice::ImplReleaseGraphics( BOOL bRelease )
815 DBG_TESTSOLARMUTEX();
817 if ( !mpGraphics )
818 return;
820 // release the fonts of the physically released graphics device
821 if( bRelease )
823 #ifndef UNX
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 )
829 #endif
830 mpGraphics->ReleaseFonts();
832 mbNewFont = true;
833 mbInitFont = true;
835 if ( mpFontEntry )
837 mpFontCache->Release( mpFontEntry );
838 mpFontEntry = NULL;
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;
859 if ( bRelease )
860 pWindow->mpWindowImpl->mpFrame->ReleaseGraphics( mpGraphics );
861 // remove from global LRU list of window graphics
862 if ( mpPrevGraphics )
863 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
864 else
865 pSVData->maGDIData.mpFirstWinGraphics = mpNextGraphics;
866 if ( mpNextGraphics )
867 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
868 else
869 pSVData->maGDIData.mpLastWinGraphics = mpPrevGraphics;
871 else if ( meOutDevType == OUTDEV_VIRDEV )
873 VirtualDevice* pVirDev = (VirtualDevice*)this;
875 if ( bRelease )
876 pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
877 // remove from global LRU list of virtual device graphics
878 if ( mpPrevGraphics )
879 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
880 else
881 pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
882 if ( mpNextGraphics )
883 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
884 else
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;
896 if ( bRelease )
897 pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
898 // remove from global LRU list of virtual device graphics
899 if ( mpPrevGraphics )
900 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
901 else
902 pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
903 if ( mpNextGraphics )
904 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
905 else
906 pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
908 else
910 if ( bRelease )
911 pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics );
912 // remove from global LRU list of printer graphics
913 if ( mpPrevGraphics )
914 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
915 else
916 pSVData->maGDIData.mpFirstPrnGraphics = mpNextGraphics;
917 if ( mpNextGraphics )
918 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
919 else
920 pSVData->maGDIData.mpLastPrnGraphics = mpPrevGraphics;
925 mpGraphics = NULL;
926 mpPrevGraphics = NULL;
927 mpNextGraphics = NULL;
930 // -----------------------------------------------------------------------
932 void OutputDevice::ImplInitOutDevData()
934 if ( !mpOutDevData )
936 mpOutDevData = new ImplOutDevData;
937 mpOutDevData->mpRotateDev = NULL;
938 mpOutDevData->mpRecordLayout = NULL;
940 // #i75163#
941 mpOutDevData->mpViewTransform = NULL;
942 mpOutDevData->mpInverseViewTransform = NULL;
946 // -----------------------------------------------------------------------
948 // #i75163#
949 void OutputDevice::ImplInvalidateViewTransform()
951 if(mpOutDevData)
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()
978 if ( mpOutDevData )
980 if ( mpOutDevData->mpRotateDev )
981 delete mpOutDevData->mpRotateDev;
983 // #i75163#
984 ImplInvalidateViewTransform();
986 delete mpOutDevData;
990 // -----------------------------------------------------------------------
992 void OutputDevice::ImplInitLineColor()
994 DBG_TESTSOLARMUTEX();
996 if( mbLineColor )
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 );
1004 else
1005 mpGraphics->SetLineColor( ImplColorToSal( maLineColor ) );
1007 else
1008 mpGraphics->SetLineColor();
1010 mbInitLineColor = FALSE;
1013 // -----------------------------------------------------------------------
1015 void OutputDevice::ImplInitFillColor()
1017 DBG_TESTSOLARMUTEX();
1019 if( mbFillColor )
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 );
1027 else
1028 mpGraphics->SetFillColor( ImplColorToSal( maFillColor ) );
1030 else
1031 mpGraphics->SetFillColor();
1033 mbInitFillColor = FALSE;
1036 // -----------------------------------------------------------------------
1038 void OutputDevice::ImplInitClipRegion()
1040 DBG_TESTSOLARMUTEX();
1042 if ( GetOutDevType() == OUTDEV_WINDOW )
1044 Window* pWindow = (Window*)this;
1045 Region aRegion;
1047 // Hintergrund-Sicherung zuruecksetzen
1048 if ( pWindow->mpWindowImpl->mpFrameData->mpFirstBackWin )
1049 pWindow->ImplInvalidateAllOverlapBackgrounds();
1050 if ( pWindow->mpWindowImpl->mbInPaint )
1051 aRegion = *(pWindow->mpWindowImpl->mpPaintRegion);
1052 else
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 );
1060 if ( mbClipRegion )
1061 aRegion.Intersect( ImplPixelToDevicePixel( maRegion ) );
1062 if ( aRegion.IsEmpty() )
1063 mbOutputClipped = TRUE;
1064 else
1066 mbOutputClipped = FALSE;
1067 ImplSelectClipRegion( aRegion );
1069 mbClipRegionSet = TRUE;
1071 else
1073 if ( mbClipRegion )
1075 if ( maRegion.IsEmpty() )
1076 mbOutputClipped = TRUE;
1077 else
1079 mbOutputClipped = FALSE;
1080 ImplSelectClipRegion(
1081 // #102532# Respect output offset also for clip region
1082 ImplPixelToDevicePixel( maRegion ) );
1085 mbClipRegionSet = TRUE;
1087 else
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();
1108 if ( !pRegion )
1110 if ( mbClipRegion )
1112 maRegion = Region( REGION_NULL );
1113 mbClipRegion = FALSE;
1114 mbInitClipRegion = TRUE;
1117 else
1119 maRegion = *pRegion;
1120 mbClipRegion = TRUE;
1121 mbInitClipRegion = TRUE;
1125 // -----------------------------------------------------------------------
1127 namespace
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)
1141 if(b == 0)
1142 return 0x80000000;
1143 if(a >= 0)
1144 return a / b;
1145 int q = -(-a / b); // quotient
1146 int r = -a % b; // remainder
1147 if(r)
1148 q--;
1149 return q;
1152 inline int floorMod( int a, int b )
1154 if(b == 0)
1155 return 0x80000000;
1156 if(a >= 0)
1157 return a % b;
1158 int r = -a % b; // remainder
1159 if(r)
1160 r = b - r;
1161 return r;
1164 inline int ceilDiv( int a, int b )
1166 if(b == 0)
1167 return 0x80000000;
1168 a += - 1 + b;
1169 if(a >= 0)
1170 return a / b;
1171 int q = -(-a / b); // quotient
1172 int r = -a % b; // remainder
1173 if(r)
1174 q--;
1175 return q;
1178 inline int ceilMod( int a, int b )
1180 if(b == 0)
1181 return 0x80000000;
1182 a += - 1 + b;
1183 if(a >= 0)
1184 return (a % b) + 1 - b;
1185 int r = -a % b;
1186 if(r)
1187 r = b - r;
1188 return r + 1 - b;
1191 inline int ceilFix4(int x) { return (x + 0xF) & 0xFFFFFFF0; }
1193 struct vertex
1195 float x,y;
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; }
1202 class SpanIterator
1204 public:
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; }
1214 private:
1216 sal_Int32 *mpTable;
1217 sal_Int32 *mpSpanArray;
1218 sal_Int32 maNumSpans;
1219 sal_Int32 maRemainingScanlines;
1220 size_t maPitch;
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;
1234 mpTable += maPitch;
1235 sal_Int32 *pNumSpans = mpTable;
1236 mpSpanArray = reinterpret_cast<sal_Int32 *>(pNumSpans+2);
1237 maNumSpans = *pNumSpans;
1238 return (*this);
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;
1255 return (*this);
1258 inline std::pair<sal_Int32,sal_Int32> SpanIterator::GetNextSpan( void )
1260 sal_Int32 x(0);
1261 sal_Int32 w(0);
1262 if(maNumSpans)
1264 x = *mpSpanArray++;
1265 w = *mpSpanArray++;
1266 --maNumSpans;
1268 return std::pair<sal_Int32,sal_Int32>(x,w);
1271 inline sal_Int32 SpanIterator::GetNumEqualScanlines( void )
1273 return mpTable[1];
1276 inline sal_Int32 SpanIterator::GetNumRemainingScanlines( void )
1278 return maRemainingScanlines;
1281 class ScanlineContainer
1284 public:
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 );
1299 private:
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;
1306 struct span
1308 sal_Int32 x;
1309 sal_Int32 w;
1312 sal_uInt32 maNumScanlines;
1313 sal_uInt32 maNumSpansPerScanline;
1314 sal_Int32 *mpTable;
1315 size_t maPitch;
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.
1324 ++dwNumScanlines;
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)
1344 pNumSpans[0] = 0;
1345 pNumSpans[1] = 0;
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
1372 // in the table.
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;
1383 return;
1386 // consolidate with left neighbour
1387 if((pSpanArray[dwIndex].x+pSpanArray[dwIndex].w) == lx)
1389 pSpanArray[dwIndex].w += rx-lx;
1390 return;
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)
1396 break;
1398 // forward to next element in the list.
1399 ++dwIndex;
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;
1415 --dwNumSpan;
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.
1423 ++maNumberOfSpans;
1427 void ScanlineContainer::Consolidate( void )
1429 sal_Int32 *pScanline = mpTable;
1431 sal_Int32 dwRemaining = maNumScanlines;
1432 while(dwRemaining)
1434 sal_Int32 dwNumSpans = pScanline[0];
1435 sal_Int32 *pSpanArray = pScanline+2;
1437 sal_Int32 dwRest = dwRemaining-1;
1438 sal_Int32 *pNext = pScanline;
1439 while(dwRest)
1441 pNext += maPitch;
1442 sal_Int32 dwNumNextSpans = pNext[0];
1443 sal_Int32 *pSpanArrayNext = pNext+2;
1444 if(dwNumSpans != dwNumNextSpans)
1445 break;
1447 sal_Int32 dwCompare = dwNumSpans<<1;
1448 while(dwCompare)
1450 if(pSpanArray[dwCompare-1] != pSpanArrayNext[dwCompare-1])
1451 break;
1452 --dwCompare;
1454 if(dwCompare)
1455 break;
1457 --dwRest;
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()))
1481 return;
1482 if(!(mpGraphics))
1483 if(!(ImplGetGraphics()))
1484 return;
1486 if( mpGraphics->supportsOperation( OutDevSupport_B2DClip ) )
1488 #if 0
1489 ::basegfx::B2DPolyPolygon aB2DPolyPolygon = rPolyPolygon.getB2DPolyPolygon();
1490 #else
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 );
1507 #endif
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;
1540 return;
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);
1565 if(p.Y() < miny)
1566 miny = p.Y();
1567 if(p.Y() > maxy)
1568 maxy = p.Y();
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
1579 // visible areas.
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;
1594 return;
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
1622 vertex v0(p0);
1623 vertex v1(p1);
1624 vertex v2(p2);
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.
1672 int lx,rx;
1674 // this pair will serve as the error accumulator while
1675 // we step along the edges.
1676 int ld,rd,lD,rD;
1678 // these are the edge and error stepping values that
1679 // will be used while stepping.
1680 int lQ,rQ,lR,rR;
1682 if(i4x1 < x)
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);
1688 lQ = mq12;
1689 rQ = mq13;
1690 lR = mr12;
1691 rR = mr13;
1692 lD = i4dy12 << 4;
1693 rD = i4dy13 << 4;
1695 else
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);
1701 lQ = mq13;
1702 rQ = mq12;
1703 lR = mr13;
1704 rR = mr12;
1705 lD = i4dy13 << 4;
1706 rD = i4dy12 << 4;
1709 for(signed int y=y0; y<y1; y++)
1711 container.InsertSpan(y-miny,lx,rx);
1713 lx += lQ; ld += lR;
1714 if(ld > 0) { ld -= lD; lx += 1; }
1715 rx += rQ; rd += rR;
1716 if(rd > 0) { rd -= rD; rx += 1; }
1719 if(i4x1 < x)
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);
1725 lQ = mq23;
1726 lR = mr23;
1727 lD = i4dy23 << 4;
1729 else
1731 rx = ceilDiv(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
1732 rd = ceilMod(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
1733 rQ = mq23;
1734 rR = mr23;
1735 rD = i4dy23 << 4;
1738 for(signed int y=y1; y<y2; y++)
1740 container.InsertSpan(y-miny,lx,rx);
1742 lx += lQ; ld += lR;
1743 if(ld > 0) { ld -= lD; lx += 1; }
1744 rx += rQ; rd += rR;
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() );
1764 while(miny < maxy)
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,
1777 offset_y+miny,
1778 span.second,
1779 dwNumEqual,
1780 this );
1782 it.Skip(dwNumEqual);
1783 miny += 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 );
1814 if ( mpMetaFile )
1815 mpMetaFile->AddAction( new MetaClipRegionAction( Region(), FALSE ) );
1817 ImplSetClipRegion( NULL );
1819 if( mpAlphaVDev )
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 );
1831 if ( mpMetaFile )
1832 mpMetaFile->AddAction( new MetaClipRegionAction( rRegion, TRUE ) );
1834 if ( rRegion.GetType() == REGION_NULL )
1835 ImplSetClipRegion( NULL );
1836 else
1838 Region aRegion = LogicToPixel( rRegion );
1839 ImplSetClipRegion( &aRegion );
1842 if( mpAlphaVDev )
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()))
1857 SetClipRegion();
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
1873 if ( mpMetaFile )
1874 mpMetaFile->AddAction( new MetaClipRegionAction( maRegion, TRUE ) );
1876 ImplSetTriangleClipRegion( rPolyPolygon );
1878 if( mpAlphaVDev )
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 );
1906 if ( mbClipRegion )
1907 aRegion.Intersect( maRegion );
1908 return PixelToLogic( aRegion );
1910 else
1911 return GetClipRegion();
1914 // -----------------------------------------------------------------------
1916 void OutputDevice::MoveClipRegion( long nHorzMove, long nVertMove )
1918 DBG_TRACE( "OutputDevice::MoveClipRegion()" );
1919 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1921 if ( mbClipRegion )
1923 if( mpMetaFile )
1924 mpMetaFile->AddAction( new MetaMoveClipRegionAction( nHorzMove, nVertMove ) );
1926 maRegion.Move( ImplLogicWidthToDevicePixel( nHorzMove ),
1927 ImplLogicHeightToDevicePixel( nVertMove ) );
1928 mbInitClipRegion = TRUE;
1931 if( mpAlphaVDev )
1932 mpAlphaVDev->MoveClipRegion( nHorzMove, nVertMove );
1935 // -----------------------------------------------------------------------
1937 void OutputDevice::IntersectClipRegion( const Rectangle& rRect )
1939 DBG_TRACE( "OutputDevice::IntersectClipRegion( rRect )" );
1940 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1942 if ( mpMetaFile )
1943 mpMetaFile->AddAction( new MetaISectRectClipRegionAction( rRect ) );
1945 Rectangle aRect = LogicToPixel( rRect );
1946 maRegion.Intersect( aRect );
1947 mbClipRegion = TRUE;
1948 mbInitClipRegion = TRUE;
1950 if( mpAlphaVDev )
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 )
1966 if ( mpMetaFile )
1967 mpMetaFile->AddAction( new MetaISectRegionClipRegionAction( rRegion ) );
1969 Region aRegion = LogicToPixel( rRegion );
1970 maRegion.Intersect( aRegion );
1971 mbClipRegion = TRUE;
1972 mbInitClipRegion = TRUE;
1975 if( mpAlphaVDev )
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;
1988 if( mpAlphaVDev )
1989 mpAlphaVDev->SetDrawMode( nDrawMode );
1992 // -----------------------------------------------------------------------
1994 void OutputDevice::SetRasterOp( RasterOp eRasterOp )
1996 DBG_TRACE1( "OutputDevice::SetRasterOp( %d )", (int)eRasterOp );
1997 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1999 if ( mpMetaFile )
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 );
2011 if( mpAlphaVDev )
2012 mpAlphaVDev->SetRasterOp( eRasterOp );
2015 // -----------------------------------------------------------------------
2017 void OutputDevice::SetLineColor()
2019 DBG_TRACE( "OutputDevice::SetLineColor()" );
2020 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
2022 if ( mpMetaFile )
2023 mpMetaFile->AddAction( new MetaLineColorAction( Color(), FALSE ) );
2025 if ( mbLineColor )
2027 mbInitLineColor = TRUE;
2028 mbLineColor = FALSE;
2029 maLineColor = Color( COL_TRANSPARENT );
2032 if( mpAlphaVDev )
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);
2078 if( mpMetaFile )
2079 mpMetaFile->AddAction( new MetaLineColorAction( aColor, TRUE ) );
2081 if( ImplIsColorTransparent( aColor ) )
2083 if ( mbLineColor )
2085 mbInitLineColor = TRUE;
2086 mbLineColor = FALSE;
2087 maLineColor = Color( COL_TRANSPARENT );
2090 else
2092 if( maLineColor != aColor )
2094 mbInitLineColor = TRUE;
2095 mbLineColor = TRUE;
2096 maLineColor = aColor;
2100 if( mpAlphaVDev )
2101 mpAlphaVDev->SetLineColor( COL_BLACK );
2104 // -----------------------------------------------------------------------
2106 void OutputDevice::SetFillColor()
2108 DBG_TRACE( "OutputDevice::SetFillColor()" );
2109 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
2111 if ( mpMetaFile )
2112 mpMetaFile->AddAction( new MetaFillColorAction( Color(), FALSE ) );
2114 if ( mbFillColor )
2116 mbInitFillColor = TRUE;
2117 mbFillColor = FALSE;
2118 maFillColor = Color( COL_TRANSPARENT );
2121 if( mpAlphaVDev )
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);
2171 if ( mpMetaFile )
2172 mpMetaFile->AddAction( new MetaFillColorAction( aColor, TRUE ) );
2174 if ( ImplIsColorTransparent( aColor ) )
2176 if ( mbFillColor )
2178 mbInitFillColor = TRUE;
2179 mbFillColor = FALSE;
2180 maFillColor = Color( COL_TRANSPARENT );
2183 else
2185 if ( maFillColor != aColor )
2187 mbInitFillColor = TRUE;
2188 mbFillColor = TRUE;
2189 maFillColor = aColor;
2193 if( mpAlphaVDev )
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;
2207 if( mpAlphaVDev )
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;
2222 else
2223 mbBackground = TRUE;
2225 if( mpAlphaVDev )
2226 mpAlphaVDev->SetBackground( rBackground );
2229 // -----------------------------------------------------------------------
2231 void OutputDevice::SetRefPoint()
2233 DBG_TRACE( "OutputDevice::SetRefPoint()" );
2234 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
2236 if ( mpMetaFile )
2237 mpMetaFile->AddAction( new MetaRefPointAction( Point(), FALSE ) );
2239 mbRefPoint = FALSE;
2240 maRefPoint.X() = maRefPoint.Y() = 0L;
2242 if( mpAlphaVDev )
2243 mpAlphaVDev->SetRefPoint();
2246 // -----------------------------------------------------------------------
2248 void OutputDevice::SetRefPoint( const Point& rRefPoint )
2250 DBG_TRACE( "OutputDevice::SetRefPoint( rRefPoint )" );
2251 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
2253 if ( mpMetaFile )
2254 mpMetaFile->AddAction( new MetaRefPointAction( rRefPoint, TRUE ) );
2256 mbRefPoint = TRUE;
2257 maRefPoint = rRefPoint;
2259 if( mpAlphaVDev )
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 );
2270 if ( mpMetaFile )
2271 mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt ) );
2273 if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
2274 return;
2276 if ( !mpGraphics )
2278 if ( !ImplGetGraphics() )
2279 return;
2282 if ( mbInitClipRegion )
2283 ImplInitClipRegion();
2284 if ( mbOutputClipped )
2285 return;
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()
2294 && IsLineColor())
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))
2313 return;
2317 const Point aStartPt(ImplLogicToDevicePixel(rStartPt));
2318 const Point aEndPt(ImplLogicToDevicePixel(rEndPt));
2320 mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), this );
2322 if( mpAlphaVDev )
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 );
2337 return;
2340 if ( mpMetaFile )
2341 mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt, rLineInfo ) );
2343 if ( !IsDeviceOutputNecessary() || !mbLineColor || ( LINE_NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() )
2344 return;
2346 if( !mpGraphics && !ImplGetGraphics() )
2347 return;
2349 if ( mbInitClipRegion )
2350 ImplInitClipRegion();
2352 if ( mbOutputClipped )
2353 return;
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 );
2363 mpMetaFile = NULL;
2365 if ( aInfo.GetWidth() > 1 )
2367 const Color aOldLineColor( maLineColor );
2368 const Color aOldFillColor( maFillColor );
2370 SetLineColor();
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 );
2381 else
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;
2391 else
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 );
2402 if( mpAlphaVDev )
2403 mpAlphaVDev->DrawLine( rStartPt, rEndPt, rLineInfo );
2406 // -----------------------------------------------------------------------
2408 void OutputDevice::DrawRect( const Rectangle& rRect )
2410 DBG_TRACE( "OutputDevice::DrawRect()" );
2411 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
2413 if ( mpMetaFile )
2414 mpMetaFile->AddAction( new MetaRectAction( rRect ) );
2416 if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
2417 return;
2419 Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
2421 if ( aRect.IsEmpty() )
2422 return;
2423 aRect.Justify();
2425 if ( !mpGraphics )
2427 if ( !ImplGetGraphics() )
2428 return;
2431 if ( mbInitClipRegion )
2432 ImplInitClipRegion();
2433 if ( mbOutputClipped )
2434 return;
2436 if ( mbInitLineColor )
2437 ImplInitLineColor();
2438 if ( mbInitFillColor )
2439 ImplInitFillColor();
2441 mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), this );
2443 if( mpAlphaVDev )
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 );
2455 if( mpMetaFile )
2456 mpMetaFile->AddAction( new MetaPolyLineAction( rPoly ) );
2458 USHORT nPoints = rPoly.GetSize();
2460 if ( !IsDeviceOutputNecessary() || !mbLineColor || (nPoints < 2) || ImplIsRecordLayout() )
2461 return;
2463 // we need a graphics
2464 if ( !mpGraphics )
2465 if ( !ImplGetGraphics() )
2466 return;
2468 if ( mbInitClipRegion )
2469 ImplInitClipRegion();
2470 if ( mbOutputClipped )
2471 return;
2473 if ( mbInitLineColor )
2474 ImplInitLineColor();
2476 const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
2477 && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
2478 && ROP_OVERPAINT == GetRasterOp()
2479 && IsLineColor());
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))
2498 return;
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 );
2516 else
2518 mpGraphics->DrawPolyLine( nPoints, pPtAry, this );
2521 if( mpAlphaVDev )
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 );
2536 return;
2539 // #i101491#
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);
2545 return;
2548 if ( mpMetaFile )
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() )
2559 return;
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() )
2572 return;
2574 if ( mbInitClipRegion )
2575 ImplInitClipRegion();
2577 if ( mbOutputClipped )
2578 return;
2580 const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) );
2581 const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
2582 && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
2583 && ROP_OVERPAINT == GetRasterOp()
2584 && IsLineColor());
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 );
2593 mpMetaFile = NULL;
2594 SetLineColor();
2595 ImplInitLineColor();
2596 SetFillColor( aOldLineColor );
2597 ImplInitFillColor();
2598 bool bDone(false);
2600 if(bTryAA)
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);
2611 if(bSuccess)
2613 bDone = true;
2617 if(!bDone)
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;
2629 else
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 );
2639 else
2640 mpGraphics->DrawPolyLine( nPoints, (const SalPoint*) aPoly.GetConstPointAry(), this );
2643 if( mpAlphaVDev )
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 );
2655 if( mpMetaFile )
2656 mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
2658 USHORT nPoints = rPoly.GetSize();
2660 if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || (nPoints < 2) || ImplIsRecordLayout() )
2661 return;
2663 // we need a graphics
2664 if ( !mpGraphics )
2665 if ( !ImplGetGraphics() )
2666 return;
2668 if ( mbInitClipRegion )
2669 ImplInitClipRegion();
2670 if ( mbOutputClipped )
2671 return;
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);
2692 if(IsFillColor())
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);
2709 if(bSuccess)
2711 return;
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 );
2729 else
2731 mpGraphics->DrawPolygon( nPoints, pPtAry, this );
2733 if( mpAlphaVDev )
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 );
2745 if( mpMetaFile )
2746 mpMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );
2748 USHORT nPoly = rPolyPoly.Count();
2750 if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || !nPoly || ImplIsRecordLayout() )
2751 return;
2753 // we need a graphics
2754 if ( !mpGraphics )
2755 if ( !ImplGetGraphics() )
2756 return;
2758 if ( mbInitClipRegion )
2759 ImplInitClipRegion();
2760 if ( mbOutputClipped )
2761 return;
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);
2782 if(IsFillColor())
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);
2802 if(bSuccess)
2804 return;
2808 if ( nPoly == 1 )
2810 // #100127# Map to DrawPolygon
2811 Polygon aPoly = rPolyPoly.GetObject( 0 );
2812 if( aPoly.GetSize() >= 2 )
2814 GDIMetaFile* pOldMF = mpMetaFile;
2815 mpMetaFile = NULL;
2817 DrawPolygon( aPoly );
2819 mpMetaFile = pOldMF;
2822 else
2824 // #100127# moved real PolyPolygon draw to separate method,
2825 // have to call recursively, avoiding duplicate
2826 // ImplLogicToDevicePixel calls
2827 ImplDrawPolyPolygon( nPoly, ImplLogicToDevicePixel( rPolyPoly ) );
2829 if( mpAlphaVDev )
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 );
2855 #if 0
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
2860 if( mpMetaFile )
2861 mpMetaFile->AddAction( new MetaB2DPolyPolygonAction( rB2DPolyPoly ) );
2862 #else
2863 if( mpMetaFile )
2864 mpMetaFile->AddAction( new MetaPolyPolygonAction( PolyPolygon( rB2DPolyPoly ) ) );
2865 #endif
2867 // call helper
2868 ImpDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly);
2871 void OutputDevice::ImpDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon& rB2DPolyPoly)
2873 // AW: Do NOT paint empty PolyPolygons
2874 if(!rB2DPolyPoly.count())
2875 return;
2877 // we need a graphics
2878 if( !mpGraphics )
2879 if( !ImplGetGraphics() )
2880 return;
2882 if( mbInitClipRegion )
2883 ImplInitClipRegion();
2884 if( mbOutputClipped )
2885 return;
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);
2905 if(IsFillColor())
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);
2925 if(bSuccess)
2927 return;
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,
2941 double fLineWidth,
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,
2973 double fLineWidth,
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
2984 if( mpMetaFile )
2985 mpMetaFile->AddAction( new MetaB2DPolyLineAction( rB2DPolygon ) );
2986 #else
2987 if( mpMetaFile )
2989 LineInfo aLineInfo;
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 ) );
2995 #endif
2997 // AW: Do NOT paint empty PolyPolygons
2998 if(!rB2DPolygon.count())
2999 return;
3001 // we need a graphics
3002 if( !mpGraphics )
3003 if( !ImplGetGraphics() )
3004 return;
3006 if( mbInitClipRegion )
3007 ImplInitClipRegion();
3008 if( mbOutputClipped )
3009 return;
3011 if( mbInitLineColor )
3012 ImplInitLineColor();
3014 const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
3015 && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
3016 && ROP_OVERPAINT == GetRasterOp()
3017 && IsLineColor());
3019 // use b2dpolygon drawing if possible
3020 if(bTryAA && ImpTryDrawPolyLineDirect(rB2DPolygon, fLineWidth, eLineJoin))
3022 return;
3025 // #i101491#
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);
3040 SetLineColor();
3041 ImplInitLineColor();
3042 SetFillColor(aOldLineColor);
3043 ImplInitFillColor();
3045 ImpDrawPolyPolygonWithB2DPolyPolygon(aAreaPolyPolygon);
3047 SetLineColor(aOldLineColor);
3048 ImplInitLineColor();
3049 SetFillColor(aOldFillColor);
3050 ImplInitFillColor();
3052 if(bTryAA)
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 );
3066 LineInfo aLineInfo;
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 );
3079 if ( mpMetaFile )
3080 mpMetaFile->AddAction( new MetaPushAction( nFlags ) );
3082 ImplObjStack* pData = new ImplObjStack;
3083 pData->mpPrev = mpObjStack;
3084 mpObjStack = pData;
3086 pData->mnFlags = nFlags;
3088 if ( nFlags & PUSH_LINECOLOR )
3090 if ( mbLineColor )
3091 pData->mpLineColor = new Color( maLineColor );
3092 else
3093 pData->mpLineColor = NULL;
3095 if ( nFlags & PUSH_FILLCOLOR )
3097 if ( mbFillColor )
3098 pData->mpFillColor = new Color( maFillColor );
3099 else
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() );
3110 else
3111 pData->mpTextFillColor = NULL;
3113 if ( nFlags & PUSH_TEXTLINECOLOR )
3115 if ( IsTextLineColor() )
3116 pData->mpTextLineColor = new Color( GetTextLineColor() );
3117 else
3118 pData->mpTextLineColor = NULL;
3120 if ( nFlags & PUSH_OVERLINECOLOR )
3122 if ( IsOverlineColor() )
3123 pData->mpOverlineColor = new Color( GetOverlineColor() );
3124 else
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 )
3137 if ( mbMap )
3138 pData->mpMapMode = new MapMode( maMapMode );
3139 else
3140 pData->mpMapMode = NULL;
3142 if ( nFlags & PUSH_CLIPREGION )
3144 if ( mbClipRegion )
3145 pData->mpClipRegion = new Region( maRegion );
3146 else
3147 pData->mpClipRegion = NULL;
3149 if ( nFlags & PUSH_REFPOINT )
3151 if ( mbRefPoint )
3152 pData->mpRefPoint = new Point( maRefPoint );
3153 else
3154 pData->mpRefPoint = NULL;
3157 if( mpAlphaVDev )
3158 mpAlphaVDev->Push();
3161 // -----------------------------------------------------------------------
3163 void OutputDevice::Pop()
3165 DBG_TRACE( "OutputDevice::Pop()" );
3166 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
3168 if( mpMetaFile )
3169 mpMetaFile->AddAction( new MetaPopAction() );
3171 GDIMetaFile* pOldMetaFile = mpMetaFile;
3172 ImplObjStack* pData = mpObjStack;
3173 mpMetaFile = NULL;
3175 if ( !pData )
3177 DBG_ERRORFILE( "OutputDevice::Pop() without OutputDevice::Push()" );
3178 return;
3181 if( mpAlphaVDev )
3182 mpAlphaVDev->Pop();
3184 mpObjStack = pData->mpPrev;
3186 if ( pData->mnFlags & PUSH_LINECOLOR )
3188 if ( pData->mpLineColor )
3189 SetLineColor( *pData->mpLineColor );
3190 else
3191 SetLineColor();
3193 if ( pData->mnFlags & PUSH_FILLCOLOR )
3195 if ( pData->mpFillColor )
3196 SetFillColor( *pData->mpFillColor );
3197 else
3198 SetFillColor();
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 );
3208 else
3209 SetTextFillColor();
3211 if ( pData->mnFlags & PUSH_TEXTLINECOLOR )
3213 if ( pData->mpTextLineColor )
3214 SetTextLineColor( *pData->mpTextLineColor );
3215 else
3216 SetTextLineColor();
3218 if ( pData->mnFlags & PUSH_OVERLINECOLOR )
3220 if ( pData->mpOverlineColor )
3221 SetOverlineColor( *pData->mpOverlineColor );
3222 else
3223 SetOverlineColor();
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 );
3237 else
3238 SetMapMode();
3240 if ( pData->mnFlags & PUSH_CLIPREGION )
3241 ImplSetClipRegion( pData->mpClipRegion );
3242 if ( pData->mnFlags & PUSH_REFPOINT )
3244 if ( pData->mpRefPoint )
3245 SetRefPoint( *pData->mpRefPoint );
3246 else
3247 SetRefPoint();
3250 ImplDeleteObjStack( pData );
3252 mpMetaFile = pOldMetaFile;
3255 // -----------------------------------------------------------------------
3257 void OutputDevice::SetConnectMetaFile( GDIMetaFile* pMtf )
3259 mpMetaFile = pMtf;
3262 // -----------------------------------------------------------------------
3264 void OutputDevice::EnableOutput( BOOL bEnable )
3266 mbOutput = (bEnable != 0);
3268 if( mpAlphaVDev )
3269 mpAlphaVDev->EnableOutput( bEnable );
3272 // -----------------------------------------------------------------------
3274 void OutputDevice::SetSettings( const AllSettings& rSettings )
3276 maSettings = rSettings;
3278 if( mpAlphaVDev )
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
3292 if ( !mpGraphics )
3294 if ( !((OutputDevice*)this)->ImplGetGraphics() )
3295 return 0;
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();
3313 return 0;
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
3345 if ( !mpGraphics )
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,
3361 aSysData.nSize );
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(
3388 "com.sun.star."
3389 "rendering.CanvasFactory") ) ),
3390 uno::UNO_QUERY );
3391 if(xCanvasFactory.is())
3393 xCanvas.set(
3394 xCanvasFactory->createInstanceWithArguments(
3395 OUString( RTL_CONSTASCII_USTRINGPARAM(
3396 "com.sun.star.rendering.Canvas" )),
3397 aArg ),
3398 uno::UNO_QUERY );
3402 return xCanvas;
3405 // -----------------------------------------------------------------------