/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include // declare system types in sysdata.hxx #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; DBG_NAME( OutputDevice ) DBG_NAME( Polygon ) DBG_NAME( PolyPolygon ) DBG_NAMEEX( Region ) // ----------------------------------------------------------------------- #ifdef DBG_UTIL const char* ImplDbgCheckOutputDevice( const void* pObj ) { DBG_TESTSOLARMUTEX(); const OutputDevice* pOutDev = (OutputDevice*)pObj; if ( (pOutDev->GetOutDevType() != OUTDEV_DONTKNOW) && (pOutDev->GetOutDevType() != OUTDEV_WINDOW) && (pOutDev->GetOutDevType() != OUTDEV_PRINTER) && (pOutDev->GetOutDevType() != OUTDEV_VIRDEV) ) return "OutputDevice data overwrite"; return NULL; } #endif // ======================================================================= #define OUTDEV_POLYPOLY_STACKBUF 32 // ======================================================================= struct ImplObjStack { ImplObjStack* mpPrev; MapMode* mpMapMode; Region* mpClipRegion; Color* mpLineColor; Color* mpFillColor; Font* mpFont; Color* mpTextColor; Color* mpTextFillColor; Color* mpTextLineColor; Color* mpOverlineColor; Point* mpRefPoint; TextAlign meTextAlign; RasterOp meRasterOp; sal_uLong mnTextLayoutMode; LanguageType meTextLanguage; sal_uInt16 mnFlags; }; // ----------------------------------------------------------------------- static void ImplDeleteObjStack( ImplObjStack* pObjStack ) { if ( pObjStack->mnFlags & PUSH_LINECOLOR ) { if ( pObjStack->mpLineColor ) delete pObjStack->mpLineColor; } if ( pObjStack->mnFlags & PUSH_FILLCOLOR ) { if ( pObjStack->mpFillColor ) delete pObjStack->mpFillColor; } if ( pObjStack->mnFlags & PUSH_FONT ) delete pObjStack->mpFont; if ( pObjStack->mnFlags & PUSH_TEXTCOLOR ) delete pObjStack->mpTextColor; if ( pObjStack->mnFlags & PUSH_TEXTFILLCOLOR ) { if ( pObjStack->mpTextFillColor ) delete pObjStack->mpTextFillColor; } if ( pObjStack->mnFlags & PUSH_TEXTLINECOLOR ) { if ( pObjStack->mpTextLineColor ) delete pObjStack->mpTextLineColor; } if ( pObjStack->mnFlags & PUSH_OVERLINECOLOR ) { if ( pObjStack->mpOverlineColor ) delete pObjStack->mpOverlineColor; } if ( pObjStack->mnFlags & PUSH_MAPMODE ) { if ( pObjStack->mpMapMode ) delete pObjStack->mpMapMode; } if ( pObjStack->mnFlags & PUSH_CLIPREGION ) { if ( pObjStack->mpClipRegion ) delete pObjStack->mpClipRegion; } if ( pObjStack->mnFlags & PUSH_REFPOINT ) { if ( pObjStack->mpRefPoint ) delete pObjStack->mpRefPoint; } delete pObjStack; } // ----------------------------------------------------------------------- bool OutputDevice::ImplIsAntiparallel() const { bool bRet = false; if( ImplGetGraphics() ) { if( ( (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) && ! IsRTLEnabled() ) || ( ! (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) && IsRTLEnabled() ) ) { bRet = true; } } return bRet; } // ----------------------------------------------------------------------- bool OutputDevice::ImplSelectClipRegion( const Region& rRegion, SalGraphics* pGraphics ) { DBG_TESTSOLARMUTEX(); if( !pGraphics ) { if( !mpGraphics ) if( !ImplGetGraphics() ) return false; pGraphics = mpGraphics; } bool bClipRegion = pGraphics->SetClipRegion( rRegion, this ); OSL_ENSURE( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't cerate region" ); return bClipRegion; } // ======================================================================= Polygon ImplSubdivideBezier( const Polygon& rPoly ) { Polygon aPoly; // #100127# Use adaptive subdivide instead of fixed 25 segments rPoly.AdaptiveSubdivide( aPoly ); return aPoly; } // ======================================================================= PolyPolygon ImplSubdivideBezier( const PolyPolygon& rPolyPoly ) { sal_uInt16 i, nPolys = rPolyPoly.Count(); PolyPolygon aPolyPoly( nPolys ); for( i=0; i OUTDEV_POLYPOLY_STACKBUF ) { pPointAry = new sal_uInt32[nPoly]; pPointAryAry = new PCONSTSALPOINT[nPoly]; pFlagAryAry = new const sal_uInt8*[nPoly]; } else { pPointAry = aStackAry1; pPointAryAry = aStackAry2; pFlagAryAry = (const sal_uInt8**)aStackAry3; } do { const Polygon& rPoly = rPolyPoly.GetObject( i ); sal_uInt16 nSize = rPoly.GetSize(); if ( nSize ) { pPointAry[j] = nSize; pPointAryAry[j] = (PCONSTSALPOINT)rPoly.GetConstPointAry(); pFlagAryAry[j] = rPoly.GetConstFlagAry(); last = i; if( pFlagAryAry[j] ) bHaveBezier = sal_True; ++j; } ++i; } while ( i < nPoly ); if ( j == 1 ) { // #100127# Forward beziers to sal, if any if( bHaveBezier ) { if( !mpGraphics->DrawPolygonBezier( *pPointAry, *pPointAryAry, *pFlagAryAry, this ) ) { Polygon aPoly = ImplSubdivideBezier( rPolyPoly.GetObject( last ) ); mpGraphics->DrawPolygon( aPoly.GetSize(), (const SalPoint*)aPoly.GetConstPointAry(), this ); } } else { mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this ); } } else { // #100127# Forward beziers to sal, if any if( bHaveBezier ) { if( !mpGraphics->DrawPolyPolygonBezier( j, pPointAry, pPointAryAry, pFlagAryAry, this ) ) { PolyPolygon aPolyPoly = ImplSubdivideBezier( rPolyPoly ); ImplDrawPolyPolygon( aPolyPoly.Count(), aPolyPoly ); } } else { mpGraphics->DrawPolyPolygon( j, pPointAry, pPointAryAry, this ); } } if ( pPointAry != aStackAry1 ) { delete[] pPointAry; delete[] pPointAryAry; delete[] pFlagAryAry; } } // ======================================================================= OutputDevice::OutputDevice() : maRegion( REGION_NULL ), maFillColor( COL_WHITE ), maTextLineColor( COL_TRANSPARENT ), maSettings( Application::GetSettings() ) { DBG_CTOR( OutputDevice, ImplDbgCheckOutputDevice ); mpGraphics = NULL; mpUnoGraphicsList = NULL; mpPrevGraphics = NULL; mpNextGraphics = NULL; mpMetaFile = NULL; mpFontEntry = NULL; mpFontCache = NULL; mpFontList = NULL; mpGetDevFontList = NULL; mpGetDevSizeList = NULL; mpObjStack = NULL; mpOutDevData = NULL; mpPDFWriter = NULL; mpAlphaVDev = NULL; mpExtOutDevData = NULL; mnOutOffX = 0; mnOutOffY = 0; mnOutWidth = 0; mnOutHeight = 0; mnDPIX = 0; mnDPIY = 0; mnTextOffX = 0; mnTextOffY = 0; mnOutOffOrigX = 0; mnOutOffLogicX = 0; mnOutOffOrigY = 0; mnOutOffLogicY = 0; mnEmphasisAscent = 0; mnEmphasisDescent = 0; mnDrawMode = 0; mnTextLayoutMode = TEXT_LAYOUT_DEFAULT; if( Application::GetSettings().GetLayoutRTL() ) //#i84553# tip BiDi preference to RTL mnTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT; meOutDevType = OUTDEV_DONTKNOW; meOutDevViewType = OUTDEV_VIEWTYPE_DONTKNOW; mbMap = sal_False; mbMapIsDefault = sal_True; mbClipRegion = sal_False; mbBackground = sal_False; mbOutput = sal_True; mbDevOutput = sal_False; mbOutputClipped = sal_False; maTextColor = Color( COL_BLACK ); maOverlineColor = Color( COL_TRANSPARENT ); meTextAlign = maFont.GetAlign(); meRasterOp = ROP_OVERPAINT; mnAntialiasing = 0; meTextLanguage = 0; // TODO: get default from configuration? mbLineColor = sal_True; mbFillColor = sal_True; mbInitLineColor = sal_True; mbInitFillColor = sal_True; mbInitFont = sal_True; mbInitTextColor = sal_True; mbInitClipRegion = sal_True; mbClipRegionSet = sal_False; mbKerning = sal_False; mbNewFont = sal_True; mbTextLines = sal_False; mbTextSpecial = sal_False; mbRefPoint = sal_False; mbEnableRTL = sal_False; // mirroring must be explicitly allowed (typically for windows only) // struct ImplMapRes maMapRes.mnMapOfsX = 0; maMapRes.mnMapOfsY = 0; maMapRes.mnMapScNumX = 1; maMapRes.mnMapScNumY = 1; maMapRes.mnMapScDenomX = 1; maMapRes.mnMapScDenomY = 1; // struct ImplThresholdRes maThresRes.mnThresLogToPixX = 0; maThresRes.mnThresLogToPixY = 0; maThresRes.mnThresPixToLogX = 0; maThresRes.mnThresPixToLogY = 0; } // ----------------------------------------------------------------------- OutputDevice::~OutputDevice() { DBG_DTOR( OutputDevice, ImplDbgCheckOutputDevice ); if ( GetUnoGraphicsList() ) { UnoWrapperBase* pWrapper = Application::GetUnoWrapper( sal_False ); if ( pWrapper ) pWrapper->ReleaseAllGraphics( this ); delete mpUnoGraphicsList; mpUnoGraphicsList = NULL; } if ( mpOutDevData ) ImplDeInitOutDevData(); ImplObjStack* pData = mpObjStack; if ( pData ) { DBG_ERRORFILE( "OutputDevice::~OutputDevice(): OutputDevice::Push() calls != OutputDevice::Pop() calls" ); while ( pData ) { ImplObjStack* pTemp = pData; pData = pData->mpPrev; ImplDeleteObjStack( pTemp ); } } // release the active font instance if( mpFontEntry ) mpFontCache->Release( mpFontEntry ); // remove cached results of GetDevFontList/GetDevSizeList // TODO: use smart pointers for them if( mpGetDevFontList ) delete mpGetDevFontList; if( mpGetDevSizeList ) delete mpGetDevSizeList; // release ImplFontCache specific to this OutputDevice // TODO: refcount ImplFontCache if( mpFontCache && (mpFontCache != ImplGetSVData()->maGDIData.mpScreenFontCache) && (ImplGetSVData()->maGDIData.mpScreenFontCache != NULL) ) { delete mpFontCache; mpFontCache = NULL; } // release ImplFontList specific to this OutputDevice // TODO: refcount ImplFontList if( mpFontList && (mpFontList != ImplGetSVData()->maGDIData.mpScreenFontList) && (ImplGetSVData()->maGDIData.mpScreenFontList != NULL) ) { mpFontList->Clear(); delete mpFontList; mpFontList = NULL; } delete mpAlphaVDev; } bool OutputDevice::supportsOperation( OutDevSupportType eType ) const { if( !mpGraphics ) if( !ImplGetGraphics() ) return false; const bool bHasSupport = mpGraphics->supportsOperation( eType ); return bHasSupport; } // ----------------------------------------------------------------------- void OutputDevice::EnableRTL( sal_Bool bEnable ) { mbEnableRTL = (bEnable != 0); if( meOutDevType == OUTDEV_VIRDEV ) { // virdevs default to not mirroring, they will only be set to mirroring // under rare circumstances in the UI, eg the valueset control // because each virdev has its own SalGraphics we can safely switch the SalGraphics here // ...hopefully if( ImplGetGraphics() ) mpGraphics->SetLayout( mbEnableRTL ? SAL_LAYOUT_BIDI_RTL : 0 ); } // convenience: for controls also switch layout mode if( dynamic_cast(this) != 0 ) SetLayoutMode( bEnable ? TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT : TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_TEXTORIGIN_LEFT); Window* pWin = dynamic_cast(this); if( pWin ) pWin->StateChanged( STATE_CHANGE_MIRRORING ); if( mpAlphaVDev ) mpAlphaVDev->EnableRTL( bEnable ); } sal_Bool OutputDevice::ImplHasMirroredGraphics() { // HOTFIX for #i55719# if( meOutDevType == OUTDEV_PRINTER ) return sal_False; return ( ImplGetGraphics() && (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) ); } // note: the coordiantes to be remirrored are in frame coordiantes ! void OutputDevice::ImplReMirror( Point &rPoint ) const { rPoint.X() = mnOutOffX + mnOutWidth - 1 - rPoint.X() + mnOutOffX; } void OutputDevice::ImplReMirror( Rectangle &rRect ) const { long nWidth = rRect.nRight - rRect.nLeft; //long lc_x = rRect.nLeft - mnOutOffX; // normalize //lc_x = mnOutWidth - nWidth - 1 - lc_x; // mirror //rRect.nLeft = lc_x + mnOutOffX; // re-normalize rRect.nLeft = mnOutOffX + mnOutWidth - nWidth - 1 - rRect.nLeft + mnOutOffX; rRect.nRight = rRect.nLeft + nWidth; } void OutputDevice::ImplReMirror( Region &rRegion ) const { long nX; long nY; long nWidth; long nHeight; ImplRegionInfo aInfo; sal_Bool bRegionRect; Region aMirroredRegion; bRegionRect = rRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); while ( bRegionRect ) { Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) ); ImplReMirror( aRect ); aMirroredRegion.Union( aRect ); bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); } rRegion = aMirroredRegion; } // ----------------------------------------------------------------------- int OutputDevice::ImplGetGraphics() const { DBG_TESTSOLARMUTEX(); if ( mpGraphics ) return sal_True; mbInitLineColor = sal_True; mbInitFillColor = sal_True; mbInitFont = sal_True; mbInitTextColor = sal_True; mbInitClipRegion = sal_True; ImplSVData* pSVData = ImplGetSVData(); if ( meOutDevType == OUTDEV_WINDOW ) { Window* pWindow = (Window*)this; mpGraphics = pWindow->mpWindowImpl->mpFrame->GetGraphics(); // try harder if no wingraphics was available directly if ( !mpGraphics ) { // find another output device in the same frame OutputDevice* pReleaseOutDev = pSVData->maGDIData.mpLastWinGraphics; while ( pReleaseOutDev ) { if ( ((Window*)pReleaseOutDev)->mpWindowImpl->mpFrame == pWindow->mpWindowImpl->mpFrame ) break; pReleaseOutDev = pReleaseOutDev->mpPrevGraphics; } if ( pReleaseOutDev ) { // steal the wingraphics from the other outdev mpGraphics = pReleaseOutDev->mpGraphics; pReleaseOutDev->ImplReleaseGraphics( sal_False ); } else { // if needed retry after releasing least recently used wingraphics while ( !mpGraphics ) { if ( !pSVData->maGDIData.mpLastWinGraphics ) break; pSVData->maGDIData.mpLastWinGraphics->ImplReleaseGraphics(); mpGraphics = pWindow->mpWindowImpl->mpFrame->GetGraphics(); } } } // update global LRU list of wingraphics if ( mpGraphics ) { mpNextGraphics = pSVData->maGDIData.mpFirstWinGraphics; pSVData->maGDIData.mpFirstWinGraphics = const_cast(this); if ( mpNextGraphics ) mpNextGraphics->mpPrevGraphics = const_cast(this); if ( !pSVData->maGDIData.mpLastWinGraphics ) pSVData->maGDIData.mpLastWinGraphics = const_cast(this); } } else if ( meOutDevType == OUTDEV_VIRDEV ) { const VirtualDevice* pVirDev = (const VirtualDevice*)this; if ( pVirDev->mpVirDev ) { mpGraphics = pVirDev->mpVirDev->GetGraphics(); // if needed retry after releasing least recently used virtual device graphics while ( !mpGraphics ) { if ( !pSVData->maGDIData.mpLastVirGraphics ) break; pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics(); mpGraphics = pVirDev->mpVirDev->GetGraphics(); } // update global LRU list of virtual device graphics if ( mpGraphics ) { mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics; pSVData->maGDIData.mpFirstVirGraphics = const_cast(this); if ( mpNextGraphics ) mpNextGraphics->mpPrevGraphics = const_cast(this); if ( !pSVData->maGDIData.mpLastVirGraphics ) pSVData->maGDIData.mpLastVirGraphics = const_cast(this); } } } else if ( meOutDevType == OUTDEV_PRINTER ) { const Printer* pPrinter = (const Printer*)this; if ( pPrinter->mpJobGraphics ) mpGraphics = pPrinter->mpJobGraphics; else if ( pPrinter->mpDisplayDev ) { const VirtualDevice* pVirDev = pPrinter->mpDisplayDev; mpGraphics = pVirDev->mpVirDev->GetGraphics(); // if needed retry after releasing least recently used virtual device graphics while ( !mpGraphics ) { if ( !pSVData->maGDIData.mpLastVirGraphics ) break; pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics(); mpGraphics = pVirDev->mpVirDev->GetGraphics(); } // update global LRU list of virtual device graphics if ( mpGraphics ) { mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics; pSVData->maGDIData.mpFirstVirGraphics = const_cast(this); if ( mpNextGraphics ) mpNextGraphics->mpPrevGraphics = const_cast(this); if ( !pSVData->maGDIData.mpLastVirGraphics ) pSVData->maGDIData.mpLastVirGraphics = const_cast(this); } } else { mpGraphics = pPrinter->mpInfoPrinter->GetGraphics(); // if needed retry after releasing least recently used printer graphics while ( !mpGraphics ) { if ( !pSVData->maGDIData.mpLastPrnGraphics ) break; pSVData->maGDIData.mpLastPrnGraphics->ImplReleaseGraphics(); mpGraphics = pPrinter->mpInfoPrinter->GetGraphics(); } // update global LRU list of printer graphics if ( mpGraphics ) { mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics; pSVData->maGDIData.mpFirstPrnGraphics = const_cast(this); if ( mpNextGraphics ) mpNextGraphics->mpPrevGraphics = const_cast(this); if ( !pSVData->maGDIData.mpLastPrnGraphics ) pSVData->maGDIData.mpLastPrnGraphics = const_cast(this); } } } if ( mpGraphics ) { mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp), ROP_INVERT == meRasterOp ); mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW); return sal_True; } return sal_False; } // ----------------------------------------------------------------------- void OutputDevice::ImplReleaseGraphics( sal_Bool bRelease ) { DBG_TESTSOLARMUTEX(); if ( !mpGraphics ) return; // release the fonts of the physically released graphics device if( bRelease ) { #ifndef UNX // HACK to fix an urgent P1 printing issue fast // WinSalPrinter does not respect GetGraphics/ReleaseGraphics conventions // so Printer::mpGraphics often points to a dead WinSalGraphics // TODO: fix WinSalPrinter's GetGraphics/ReleaseGraphics handling if( meOutDevType != OUTDEV_PRINTER ) #endif mpGraphics->ReleaseFonts(); mbNewFont = true; mbInitFont = true; if ( mpFontEntry ) { mpFontCache->Release( mpFontEntry ); mpFontEntry = NULL; } if ( mpGetDevFontList ) { delete mpGetDevFontList; mpGetDevFontList = NULL; } if ( mpGetDevSizeList ) { delete mpGetDevSizeList; mpGetDevSizeList = NULL; } } ImplSVData* pSVData = ImplGetSVData(); if ( meOutDevType == OUTDEV_WINDOW ) { Window* pWindow = (Window*)this; if ( bRelease ) pWindow->mpWindowImpl->mpFrame->ReleaseGraphics( mpGraphics ); // remove from global LRU list of window graphics if ( mpPrevGraphics ) mpPrevGraphics->mpNextGraphics = mpNextGraphics; else pSVData->maGDIData.mpFirstWinGraphics = mpNextGraphics; if ( mpNextGraphics ) mpNextGraphics->mpPrevGraphics = mpPrevGraphics; else pSVData->maGDIData.mpLastWinGraphics = mpPrevGraphics; } else if ( meOutDevType == OUTDEV_VIRDEV ) { VirtualDevice* pVirDev = (VirtualDevice*)this; if ( bRelease ) pVirDev->mpVirDev->ReleaseGraphics( mpGraphics ); // remove from global LRU list of virtual device graphics if ( mpPrevGraphics ) mpPrevGraphics->mpNextGraphics = mpNextGraphics; else pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics; if ( mpNextGraphics ) mpNextGraphics->mpPrevGraphics = mpPrevGraphics; else pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics; } else if ( meOutDevType == OUTDEV_PRINTER ) { Printer* pPrinter = (Printer*)this; if ( !pPrinter->mpJobGraphics ) { if ( pPrinter->mpDisplayDev ) { VirtualDevice* pVirDev = pPrinter->mpDisplayDev; if ( bRelease ) pVirDev->mpVirDev->ReleaseGraphics( mpGraphics ); // remove from global LRU list of virtual device graphics if ( mpPrevGraphics ) mpPrevGraphics->mpNextGraphics = mpNextGraphics; else pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics; if ( mpNextGraphics ) mpNextGraphics->mpPrevGraphics = mpPrevGraphics; else pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics; } else { if ( bRelease ) pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics ); // remove from global LRU list of printer graphics if ( mpPrevGraphics ) mpPrevGraphics->mpNextGraphics = mpNextGraphics; else pSVData->maGDIData.mpFirstPrnGraphics = mpNextGraphics; if ( mpNextGraphics ) mpNextGraphics->mpPrevGraphics = mpPrevGraphics; else pSVData->maGDIData.mpLastPrnGraphics = mpPrevGraphics; } } } mpGraphics = NULL; mpPrevGraphics = NULL; mpNextGraphics = NULL; } // ----------------------------------------------------------------------- void OutputDevice::ImplInitOutDevData() { if ( !mpOutDevData ) { mpOutDevData = new ImplOutDevData; mpOutDevData->mpRotateDev = NULL; mpOutDevData->mpRecordLayout = NULL; // #i75163# mpOutDevData->mpViewTransform = NULL; mpOutDevData->mpInverseViewTransform = NULL; } } // ----------------------------------------------------------------------- // #i75163# void OutputDevice::ImplInvalidateViewTransform() { if(mpOutDevData) { if(mpOutDevData->mpViewTransform) { delete mpOutDevData->mpViewTransform; mpOutDevData->mpViewTransform = NULL; } if(mpOutDevData->mpInverseViewTransform) { delete mpOutDevData->mpInverseViewTransform; mpOutDevData->mpInverseViewTransform = NULL; } } } // ----------------------------------------------------------------------- sal_Bool OutputDevice::ImplIsRecordLayout() const { return mpOutDevData && mpOutDevData->mpRecordLayout; } // ----------------------------------------------------------------------- void OutputDevice::ImplDeInitOutDevData() { if ( mpOutDevData ) { if ( mpOutDevData->mpRotateDev ) delete mpOutDevData->mpRotateDev; // #i75163# ImplInvalidateViewTransform(); delete mpOutDevData; } } // ----------------------------------------------------------------------- void OutputDevice::ImplInitLineColor() { DBG_TESTSOLARMUTEX(); if( mbLineColor ) { if( ROP_0 == meRasterOp ) mpGraphics->SetROPLineColor( SAL_ROP_0 ); else if( ROP_1 == meRasterOp ) mpGraphics->SetROPLineColor( SAL_ROP_1 ); else if( ROP_INVERT == meRasterOp ) mpGraphics->SetROPLineColor( SAL_ROP_INVERT ); else mpGraphics->SetLineColor( ImplColorToSal( maLineColor ) ); } else mpGraphics->SetLineColor(); mbInitLineColor = sal_False; } // ----------------------------------------------------------------------- void OutputDevice::ImplInitFillColor() { DBG_TESTSOLARMUTEX(); if( mbFillColor ) { if( ROP_0 == meRasterOp ) mpGraphics->SetROPFillColor( SAL_ROP_0 ); else if( ROP_1 == meRasterOp ) mpGraphics->SetROPFillColor( SAL_ROP_1 ); else if( ROP_INVERT == meRasterOp ) mpGraphics->SetROPFillColor( SAL_ROP_INVERT ); else mpGraphics->SetFillColor( ImplColorToSal( maFillColor ) ); } else mpGraphics->SetFillColor(); mbInitFillColor = sal_False; } // ----------------------------------------------------------------------- void OutputDevice::ImplInitClipRegion() { DBG_TESTSOLARMUTEX(); if ( GetOutDevType() == OUTDEV_WINDOW ) { Window* pWindow = (Window*)this; Region aRegion; // Hintergrund-Sicherung zuruecksetzen if ( pWindow->mpWindowImpl->mpFrameData->mpFirstBackWin ) pWindow->ImplInvalidateAllOverlapBackgrounds(); if ( pWindow->mpWindowImpl->mbInPaint ) aRegion = *(pWindow->mpWindowImpl->mpPaintRegion); else { aRegion = *(pWindow->ImplGetWinChildClipRegion()); // --- RTL -- only this region is in frame coordinates, so re-mirror it // the mpWindowImpl->mpPaintRegion above is already correct (see ImplCallPaint()) ! if( ImplIsAntiparallel() ) ImplReMirror ( aRegion ); } if ( mbClipRegion ) aRegion.Intersect( ImplPixelToDevicePixel( maRegion ) ); if ( aRegion.IsEmpty() ) mbOutputClipped = sal_True; else { mbOutputClipped = sal_False; ImplSelectClipRegion( aRegion ); } mbClipRegionSet = sal_True; } else { if ( mbClipRegion ) { if ( maRegion.IsEmpty() ) mbOutputClipped = sal_True; else { mbOutputClipped = sal_False; // #102532# Respect output offset also for clip region Region aRegion( ImplPixelToDevicePixel( maRegion ) ); const bool bClipDeviceBounds( ! GetPDFWriter() && GetOutDevType() != OUTDEV_PRINTER ); if( bClipDeviceBounds ) { // #b6520266# Perform actual rect clip against outdev // dimensions, to generate empty clips whenever one of the // values is completely off the device. Rectangle aDeviceBounds( mnOutOffX, mnOutOffY, mnOutOffX+GetOutputWidthPixel()-1, mnOutOffY+GetOutputHeightPixel()-1 ); aRegion.Intersect( aDeviceBounds ); } if ( aRegion.IsEmpty() ) { mbOutputClipped = sal_True; } else { mbOutputClipped = sal_False; ImplSelectClipRegion( aRegion ); } } mbClipRegionSet = sal_True; } else { if ( mbClipRegionSet ) { mpGraphics->ResetClipRegion(); mbClipRegionSet = sal_False; } mbOutputClipped = sal_False; } } mbInitClipRegion = sal_False; } // ----------------------------------------------------------------------- void OutputDevice::ImplSetClipRegion( const Region* pRegion ) { DBG_TESTSOLARMUTEX(); if ( !pRegion ) { if ( mbClipRegion ) { maRegion = Region( REGION_NULL ); mbClipRegion = sal_False; mbInitClipRegion = sal_True; } } else { maRegion = *pRegion; mbClipRegion = sal_True; mbInitClipRegion = sal_True; } } // ----------------------------------------------------------------------- void OutputDevice::SetClipRegion() { DBG_TRACE( "OutputDevice::SetClipRegion()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaClipRegionAction( Region(), sal_False ) ); ImplSetClipRegion( NULL ); if( mpAlphaVDev ) mpAlphaVDev->SetClipRegion(); } // ----------------------------------------------------------------------- void OutputDevice::SetClipRegion( const Region& rRegion ) { DBG_TRACE( "OutputDevice::SetClipRegion( rRegion )" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaClipRegionAction( rRegion, sal_True ) ); if ( rRegion.GetType() == REGION_NULL ) ImplSetClipRegion( NULL ); else { Region aRegion = LogicToPixel( rRegion ); ImplSetClipRegion( &aRegion ); } if( mpAlphaVDev ) mpAlphaVDev->SetClipRegion( rRegion ); } // ----------------------------------------------------------------------- Region OutputDevice::GetClipRegion() const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); return PixelToLogic( maRegion ); } // ----------------------------------------------------------------------- Region OutputDevice::GetActiveClipRegion() const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( GetOutDevType() == OUTDEV_WINDOW ) { Region aRegion( REGION_NULL ); Window* pWindow = (Window*)this; if ( pWindow->mpWindowImpl->mbInPaint ) { aRegion = *(pWindow->mpWindowImpl->mpPaintRegion); aRegion.Move( -mnOutOffX, -mnOutOffY ); } if ( mbClipRegion ) aRegion.Intersect( maRegion ); return PixelToLogic( aRegion ); } else return GetClipRegion(); } // ----------------------------------------------------------------------- void OutputDevice::MoveClipRegion( long nHorzMove, long nVertMove ) { DBG_TRACE( "OutputDevice::MoveClipRegion()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mbClipRegion ) { if( mpMetaFile ) mpMetaFile->AddAction( new MetaMoveClipRegionAction( nHorzMove, nVertMove ) ); maRegion.Move( ImplLogicWidthToDevicePixel( nHorzMove ), ImplLogicHeightToDevicePixel( nVertMove ) ); mbInitClipRegion = sal_True; } if( mpAlphaVDev ) mpAlphaVDev->MoveClipRegion( nHorzMove, nVertMove ); } // ----------------------------------------------------------------------- void OutputDevice::IntersectClipRegion( const Rectangle& rRect ) { DBG_TRACE( "OutputDevice::IntersectClipRegion( rRect )" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaISectRectClipRegionAction( rRect ) ); Rectangle aRect = LogicToPixel( rRect ); maRegion.Intersect( aRect ); mbClipRegion = sal_True; mbInitClipRegion = sal_True; if( mpAlphaVDev ) mpAlphaVDev->IntersectClipRegion( rRect ); } // ----------------------------------------------------------------------- void OutputDevice::IntersectClipRegion( const Region& rRegion ) { DBG_TRACE( "OutputDevice::IntersectClipRegion( rRegion )" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); RegionType eType = rRegion.GetType(); if ( eType != REGION_NULL ) { if ( mpMetaFile ) mpMetaFile->AddAction( new MetaISectRegionClipRegionAction( rRegion ) ); Region aRegion = LogicToPixel( rRegion ); maRegion.Intersect( aRegion ); mbClipRegion = sal_True; mbInitClipRegion = sal_True; } if( mpAlphaVDev ) mpAlphaVDev->IntersectClipRegion( rRegion ); } // ----------------------------------------------------------------------- void OutputDevice::SetDrawMode( sal_uLong nDrawMode ) { DBG_TRACE1( "OutputDevice::SetDrawMode( %lx )", nDrawMode ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); mnDrawMode = nDrawMode; if( mpAlphaVDev ) mpAlphaVDev->SetDrawMode( nDrawMode ); } // ----------------------------------------------------------------------- void OutputDevice::SetRasterOp( RasterOp eRasterOp ) { DBG_TRACE1( "OutputDevice::SetRasterOp( %d )", (int)eRasterOp ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaRasterOpAction( eRasterOp ) ); if ( meRasterOp != eRasterOp ) { meRasterOp = eRasterOp; mbInitLineColor = mbInitFillColor = sal_True; if( mpGraphics || ImplGetGraphics() ) mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp), ROP_INVERT == meRasterOp ); } if( mpAlphaVDev ) mpAlphaVDev->SetRasterOp( eRasterOp ); } // ----------------------------------------------------------------------- void OutputDevice::SetLineColor() { DBG_TRACE( "OutputDevice::SetLineColor()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaLineColorAction( Color(), sal_False ) ); if ( mbLineColor ) { mbInitLineColor = sal_True; mbLineColor = sal_False; maLineColor = Color( COL_TRANSPARENT ); } if( mpAlphaVDev ) mpAlphaVDev->SetLineColor(); } // ----------------------------------------------------------------------- void OutputDevice::SetLineColor( const Color& rColor ) { DBG_TRACE1( "OutputDevice::SetLineColor( %lx )", rColor.GetColor() ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); Color aColor( rColor ); if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE | DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE | DRAWMODE_SETTINGSLINE ) ) { if( !ImplIsColorTransparent( aColor ) ) { if( mnDrawMode & DRAWMODE_BLACKLINE ) { aColor = Color( COL_BLACK ); } else if( mnDrawMode & DRAWMODE_WHITELINE ) { aColor = Color( COL_WHITE ); } else if( mnDrawMode & DRAWMODE_GRAYLINE ) { const sal_uInt8 cLum = aColor.GetLuminance(); aColor = Color( cLum, cLum, cLum ); } else if( mnDrawMode & DRAWMODE_SETTINGSLINE ) { aColor = GetSettings().GetStyleSettings().GetFontColor(); } if( mnDrawMode & DRAWMODE_GHOSTEDLINE ) { aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, ( aColor.GetGreen() >> 1 ) | 0x80, ( aColor.GetBlue() >> 1 ) | 0x80); } } } if( mpMetaFile ) mpMetaFile->AddAction( new MetaLineColorAction( aColor, sal_True ) ); if( ImplIsColorTransparent( aColor ) ) { if ( mbLineColor ) { mbInitLineColor = sal_True; mbLineColor = sal_False; maLineColor = Color( COL_TRANSPARENT ); } } else { if( maLineColor != aColor ) { mbInitLineColor = sal_True; mbLineColor = sal_True; maLineColor = aColor; } } if( mpAlphaVDev ) mpAlphaVDev->SetLineColor( COL_BLACK ); } // ----------------------------------------------------------------------- void OutputDevice::SetFillColor() { DBG_TRACE( "OutputDevice::SetFillColor()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaFillColorAction( Color(), sal_False ) ); if ( mbFillColor ) { mbInitFillColor = sal_True; mbFillColor = sal_False; maFillColor = Color( COL_TRANSPARENT ); } if( mpAlphaVDev ) mpAlphaVDev->SetFillColor(); } // ----------------------------------------------------------------------- void OutputDevice::SetFillColor( const Color& rColor ) { DBG_TRACE1( "OutputDevice::SetFillColor( %lx )", rColor.GetColor() ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); Color aColor( rColor ); if( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL | DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) ) { if( !ImplIsColorTransparent( aColor ) ) { if( mnDrawMode & DRAWMODE_BLACKFILL ) { aColor = Color( COL_BLACK ); } else if( mnDrawMode & DRAWMODE_WHITEFILL ) { aColor = Color( COL_WHITE ); } else if( mnDrawMode & DRAWMODE_GRAYFILL ) { const sal_uInt8 cLum = aColor.GetLuminance(); aColor = Color( cLum, cLum, cLum ); } else if( mnDrawMode & DRAWMODE_NOFILL ) { aColor = Color( COL_TRANSPARENT ); } else if( mnDrawMode & DRAWMODE_SETTINGSFILL ) { aColor = GetSettings().GetStyleSettings().GetWindowColor(); } if( mnDrawMode & DRAWMODE_GHOSTEDFILL ) { aColor = Color( (aColor.GetRed() >> 1) | 0x80, (aColor.GetGreen() >> 1) | 0x80, (aColor.GetBlue() >> 1) | 0x80); } } } if ( mpMetaFile ) mpMetaFile->AddAction( new MetaFillColorAction( aColor, sal_True ) ); if ( ImplIsColorTransparent( aColor ) ) { if ( mbFillColor ) { mbInitFillColor = sal_True; mbFillColor = sal_False; maFillColor = Color( COL_TRANSPARENT ); } } else { if ( maFillColor != aColor ) { mbInitFillColor = sal_True; mbFillColor = sal_True; maFillColor = aColor; } } if( mpAlphaVDev ) mpAlphaVDev->SetFillColor( COL_BLACK ); } // ----------------------------------------------------------------------- void OutputDevice::SetBackground() { DBG_TRACE( "OutputDevice::SetBackground()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); maBackground = Wallpaper(); mbBackground = sal_False; if( mpAlphaVDev ) mpAlphaVDev->SetBackground(); } // ----------------------------------------------------------------------- void OutputDevice::SetBackground( const Wallpaper& rBackground ) { DBG_TRACE( "OutputDevice::SetBackground( rBackground )" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); maBackground = rBackground; if( rBackground.GetStyle() == WALLPAPER_NULL ) mbBackground = sal_False; else mbBackground = sal_True; if( mpAlphaVDev ) mpAlphaVDev->SetBackground( rBackground ); } // ----------------------------------------------------------------------- void OutputDevice::SetRefPoint() { DBG_TRACE( "OutputDevice::SetRefPoint()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaRefPointAction( Point(), sal_False ) ); mbRefPoint = sal_False; maRefPoint.X() = maRefPoint.Y() = 0L; if( mpAlphaVDev ) mpAlphaVDev->SetRefPoint(); } // ----------------------------------------------------------------------- void OutputDevice::SetRefPoint( const Point& rRefPoint ) { DBG_TRACE( "OutputDevice::SetRefPoint( rRefPoint )" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaRefPointAction( rRefPoint, sal_True ) ); mbRefPoint = sal_True; maRefPoint = rRefPoint; if( mpAlphaVDev ) mpAlphaVDev->SetRefPoint( rRefPoint ); } // ----------------------------------------------------------------------- void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt ) { DBG_TRACE( "OutputDevice::DrawLine()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt ) ); if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() ) return; if ( !mpGraphics ) { if ( !ImplGetGraphics() ) return; } if ( mbInitClipRegion ) ImplInitClipRegion(); if ( mbOutputClipped ) return; if ( mbInitLineColor ) ImplInitLineColor(); // #i101598# support AA and snap for lines, too if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) && ROP_OVERPAINT == GetRasterOp() && IsLineColor()) { // at least transform with double precision to device coordinates; this will // avoid pixel snap of single, appended lines const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation()); const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); basegfx::B2DPolygon aB2DPolyLine; aB2DPolyLine.append(basegfx::B2DPoint(rStartPt.X(), rStartPt.Y())); aB2DPolyLine.append(basegfx::B2DPoint(rEndPt.X(), rEndPt.Y())); aB2DPolyLine.transform( aTransform ); if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE) { aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine); } if( mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this)) { return; } } const Point aStartPt(ImplLogicToDevicePixel(rStartPt)); const Point aEndPt(ImplLogicToDevicePixel(rEndPt)); mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), this ); if( mpAlphaVDev ) mpAlphaVDev->DrawLine( rStartPt, rEndPt ); } // ----------------------------------------------------------------------- void OutputDevice::impPaintLineGeometryWithEvtlExpand( const LineInfo& rInfo, basegfx::B2DPolyPolygon aLinePolyPolygon) { const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) && ROP_OVERPAINT == GetRasterOp() && IsLineColor()); basegfx::B2DPolyPolygon aFillPolyPolygon; const bool bDashUsed(LINE_DASH == rInfo.GetStyle()); const bool bLineWidthUsed(rInfo.GetWidth() > 1); if(bDashUsed && aLinePolyPolygon.count()) { ::std::vector< double > fDotDashArray; const double fDashLen(rInfo.GetDashLen()); const double fDotLen(rInfo.GetDotLen()); const double fDistance(rInfo.GetDistance()); for(sal_uInt16 a(0); a < rInfo.GetDashCount(); a++) { fDotDashArray.push_back(fDashLen); fDotDashArray.push_back(fDistance); } for(sal_uInt16 b(0); b < rInfo.GetDotCount(); b++) { fDotDashArray.push_back(fDotLen); fDotDashArray.push_back(fDistance); } const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0)); if(fAccumulated > 0.0) { basegfx::B2DPolyPolygon aResult; for(sal_uInt32 c(0); c < aLinePolyPolygon.count(); c++) { basegfx::B2DPolyPolygon aLineTraget; basegfx::tools::applyLineDashing( aLinePolyPolygon.getB2DPolygon(c), fDotDashArray, &aLineTraget); aResult.append(aLineTraget); } aLinePolyPolygon = aResult; } } if(bLineWidthUsed && aLinePolyPolygon.count()) { const double fHalfLineWidth((rInfo.GetWidth() * 0.5) + 0.5); if(aLinePolyPolygon.areControlPointsUsed()) { // #i110768# When area geometry has to be created, do not // use the fallback bezier decomposition inside createAreaGeometry, // but one that is at least as good as ImplSubdivideBezier was. // There, Polygon::AdaptiveSubdivide was used with default parameter // 1.0 as quality index. aLinePolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(aLinePolyPolygon, 1.0); } for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) { aFillPolyPolygon.append(basegfx::tools::createAreaGeometry( aLinePolyPolygon.getB2DPolygon(a), fHalfLineWidth, rInfo.GetLineJoin(), rInfo.GetLineCap())); } aLinePolyPolygon.clear(); } GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = NULL; if(aLinePolyPolygon.count()) { for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) { const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); bool bDone(false); if(bTryAA) { bDone = mpGraphics->DrawPolyLine( aCandidate, 0.0, basegfx::B2DVector(1.0,1.0), basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this); } if(!bDone) { const Polygon aPolygon(aCandidate); mpGraphics->DrawPolyLine(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this); } } } if(aFillPolyPolygon.count()) { const Color aOldLineColor( maLineColor ); const Color aOldFillColor( maFillColor ); SetLineColor(); ImplInitLineColor(); SetFillColor( aOldLineColor ); ImplInitFillColor(); bool bDone(false); if(bTryAA) { bDone = mpGraphics->DrawPolyPolygon(aFillPolyPolygon, 0.0, this); } if(!bDone) { for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) { Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); // need to subdivide, mpGraphics->DrawPolygon ignores curves aPolygon.AdaptiveSubdivide(aPolygon); mpGraphics->DrawPolygon(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this); } } SetFillColor( aOldFillColor ); SetLineColor( aOldLineColor ); } mpMetaFile = pOldMetaFile; } // ----------------------------------------------------------------------- void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt, const LineInfo& rLineInfo ) { DBG_TRACE( "OutputDevice::DrawLine()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( rLineInfo.IsDefault() ) { DrawLine( rStartPt, rEndPt ); return; } if ( mpMetaFile ) mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt, rLineInfo ) ); if ( !IsDeviceOutputNecessary() || !mbLineColor || ( LINE_NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() ) return; if( !mpGraphics && !ImplGetGraphics() ) return; if ( mbInitClipRegion ) ImplInitClipRegion(); if ( mbOutputClipped ) return; const Point aStartPt( ImplLogicToDevicePixel( rStartPt ) ); const Point aEndPt( ImplLogicToDevicePixel( rEndPt ) ); const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); const bool bDashUsed(LINE_DASH == aInfo.GetStyle()); const bool bLineWidthUsed(aInfo.GetWidth() > 1); if ( mbInitLineColor ) ImplInitLineColor(); if(bDashUsed || bLineWidthUsed) { basegfx::B2DPolygon aLinePolygon; aLinePolygon.append(basegfx::B2DPoint(aStartPt.X(), aStartPt.Y())); aLinePolygon.append(basegfx::B2DPoint(aEndPt.X(), aEndPt.Y())); impPaintLineGeometryWithEvtlExpand(aInfo, basegfx::B2DPolyPolygon(aLinePolygon)); } else { mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), this ); } if( mpAlphaVDev ) mpAlphaVDev->DrawLine( rStartPt, rEndPt, rLineInfo ); } // ----------------------------------------------------------------------- void OutputDevice::DrawRect( const Rectangle& rRect ) { DBG_TRACE( "OutputDevice::DrawRect()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaRectAction( rRect ) ); if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() ) return; Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); if ( aRect.IsEmpty() ) return; aRect.Justify(); if ( !mpGraphics ) { if ( !ImplGetGraphics() ) return; } if ( mbInitClipRegion ) ImplInitClipRegion(); if ( mbOutputClipped ) return; if ( mbInitLineColor ) ImplInitLineColor(); if ( mbInitFillColor ) ImplInitFillColor(); mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), this ); if( mpAlphaVDev ) mpAlphaVDev->DrawRect( rRect ); } // ----------------------------------------------------------------------- void OutputDevice::DrawPolyLine( const Polygon& rPoly ) { DBG_TRACE( "OutputDevice::DrawPolyLine()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); DBG_CHKOBJ( &rPoly, Polygon, NULL ); if( mpMetaFile ) mpMetaFile->AddAction( new MetaPolyLineAction( rPoly ) ); sal_uInt16 nPoints = rPoly.GetSize(); if ( !IsDeviceOutputNecessary() || !mbLineColor || (nPoints < 2) || ImplIsRecordLayout() ) return; // we need a graphics if ( !mpGraphics ) if ( !ImplGetGraphics() ) return; if ( mbInitClipRegion ) ImplInitClipRegion(); if ( mbOutputClipped ) return; if ( mbInitLineColor ) ImplInitLineColor(); const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) && ROP_OVERPAINT == GetRasterOp() && IsLineColor()); // use b2dpolygon drawing if possible if(bTryAA && ImpTryDrawPolyLineDirect(rPoly.getB2DPolygon())) { basegfx::B2DPolygon aB2DPolyLine(rPoly.getB2DPolygon()); const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); // transform the polygon aB2DPolyLine.transform( aTransform ); if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE) { aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine); } if(mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this)) { return; } } Polygon aPoly = ImplLogicToDevicePixel( rPoly ); const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry(); // #100127# Forward beziers to sal, if any if( aPoly.HasFlags() ) { const sal_uInt8* pFlgAry = aPoly.GetConstFlagAry(); if( !mpGraphics->DrawPolyLineBezier( nPoints, pPtAry, pFlgAry, this ) ) { aPoly = ImplSubdivideBezier(aPoly); pPtAry = (const SalPoint*)aPoly.GetConstPointAry(); mpGraphics->DrawPolyLine( aPoly.GetSize(), pPtAry, this ); } } else { mpGraphics->DrawPolyLine( nPoints, pPtAry, this ); } if( mpAlphaVDev ) mpAlphaVDev->DrawPolyLine( rPoly ); } // ----------------------------------------------------------------------- void OutputDevice::DrawPolyLine( const Polygon& rPoly, const LineInfo& rLineInfo ) { DBG_TRACE( "OutputDevice::DrawPolyLine()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); DBG_CHKOBJ( &rPoly, Polygon, NULL ); if ( rLineInfo.IsDefault() ) { DrawPolyLine( rPoly ); return; } // #i101491# // Try direct Fallback to B2D-Version of DrawPolyLine if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && LINE_SOLID == rLineInfo.GetStyle()) { DrawPolyLine( rPoly.getB2DPolygon(), (double)rLineInfo.GetWidth(), rLineInfo.GetLineJoin(), rLineInfo.GetLineCap()); return; } if ( mpMetaFile ) mpMetaFile->AddAction( new MetaPolyLineAction( rPoly, rLineInfo ) ); ImpDrawPolyLineWithLineInfo(rPoly, rLineInfo); } void OutputDevice::ImpDrawPolyLineWithLineInfo(const Polygon& rPoly, const LineInfo& rLineInfo) { sal_uInt16 nPoints(rPoly.GetSize()); if ( !IsDeviceOutputNecessary() || !mbLineColor || ( nPoints < 2 ) || ( LINE_NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() ) return; Polygon aPoly = ImplLogicToDevicePixel( rPoly ); // #100127# LineInfo is not curve-safe, subdivide always // // What shall this mean? It's wrong to subdivide here when the // polygon is a fat line. In that case, the painted geometry // WILL be much different. // I also have no idea how this could be related to the given ID // which reads 'consolidate boost versions' in the task description. // Removing. // //if( aPoly.HasFlags() ) //{ // aPoly = ImplSubdivideBezier( aPoly ); // nPoints = aPoly.GetSize(); //} // we need a graphics if ( !mpGraphics && !ImplGetGraphics() ) return; if ( mbInitClipRegion ) ImplInitClipRegion(); if ( mbOutputClipped ) return; if ( mbInitLineColor ) ImplInitLineColor(); const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); const bool bDashUsed(LINE_DASH == aInfo.GetStyle()); const bool bLineWidthUsed(aInfo.GetWidth() > 1); if(bDashUsed || bLineWidthUsed) { impPaintLineGeometryWithEvtlExpand(aInfo, basegfx::B2DPolyPolygon(aPoly.getB2DPolygon())); } else { // #100127# the subdivision HAS to be done here since only a pointer // to an array of points is given to the DrawPolyLine method, there is // NO way to find out there that it's a curve. if( aPoly.HasFlags() ) { aPoly = ImplSubdivideBezier( aPoly ); nPoints = aPoly.GetSize(); } mpGraphics->DrawPolyLine(nPoints, (const SalPoint*)aPoly.GetConstPointAry(), this); } if( mpAlphaVDev ) mpAlphaVDev->DrawPolyLine( rPoly, rLineInfo ); } // ----------------------------------------------------------------------- void OutputDevice::DrawPolygon( const Polygon& rPoly ) { DBG_TRACE( "OutputDevice::DrawPolygon()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); DBG_CHKOBJ( &rPoly, Polygon, NULL ); if( mpMetaFile ) mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) ); sal_uInt16 nPoints = rPoly.GetSize(); if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || (nPoints < 2) || ImplIsRecordLayout() ) return; // we need a graphics if ( !mpGraphics ) if ( !ImplGetGraphics() ) return; if ( mbInitClipRegion ) ImplInitClipRegion(); if ( mbOutputClipped ) return; if ( mbInitLineColor ) ImplInitLineColor(); if ( mbInitFillColor ) ImplInitFillColor(); // use b2dpolygon drawing if possible if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) && ROP_OVERPAINT == GetRasterOp() && (IsLineColor() || IsFillColor())) { const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); basegfx::B2DPolygon aB2DPolygon(rPoly.getB2DPolygon()); bool bSuccess(true); // transform the polygon and ensure closed aB2DPolygon.transform(aTransform); aB2DPolygon.setClosed(true); if(IsFillColor()) { bSuccess = mpGraphics->DrawPolyPolygon(basegfx::B2DPolyPolygon(aB2DPolygon), 0.0, this); } if(bSuccess && IsLineColor()) { const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE) { aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon); } bSuccess = mpGraphics->DrawPolyLine( aB2DPolygon, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this); } if(bSuccess) { return; } } Polygon aPoly = ImplLogicToDevicePixel( rPoly ); const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry(); // #100127# Forward beziers to sal, if any if( aPoly.HasFlags() ) { const sal_uInt8* pFlgAry = aPoly.GetConstFlagAry(); if( !mpGraphics->DrawPolygonBezier( nPoints, pPtAry, pFlgAry, this ) ) { aPoly = ImplSubdivideBezier(aPoly); pPtAry = (const SalPoint*)aPoly.GetConstPointAry(); mpGraphics->DrawPolygon( aPoly.GetSize(), pPtAry, this ); } } else { mpGraphics->DrawPolygon( nPoints, pPtAry, this ); } if( mpAlphaVDev ) mpAlphaVDev->DrawPolygon( rPoly ); } // ----------------------------------------------------------------------- void OutputDevice::DrawPolyPolygon( const PolyPolygon& rPolyPoly ) { DBG_TRACE( "OutputDevice::DrawPolyPolygon()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL ); if( mpMetaFile ) mpMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) ); sal_uInt16 nPoly = rPolyPoly.Count(); if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || !nPoly || ImplIsRecordLayout() ) return; // we need a graphics if ( !mpGraphics ) if ( !ImplGetGraphics() ) return; if ( mbInitClipRegion ) ImplInitClipRegion(); if ( mbOutputClipped ) return; if ( mbInitLineColor ) ImplInitLineColor(); if ( mbInitFillColor ) ImplInitFillColor(); // use b2dpolygon drawing if possible if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) && ROP_OVERPAINT == GetRasterOp() && (IsLineColor() || IsFillColor())) { const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon()); bool bSuccess(true); // transform the polygon and ensure closed aB2DPolyPolygon.transform(aTransform); aB2DPolyPolygon.setClosed(true); if(IsFillColor()) { bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this); } if(bSuccess && IsLineColor()) { const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE) { aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon); } for(sal_uInt32 a(0); bSuccess && a < aB2DPolyPolygon.count(); a++) { bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this); } } if(bSuccess) { return; } } if ( nPoly == 1 ) { // #100127# Map to DrawPolygon Polygon aPoly = rPolyPoly.GetObject( 0 ); if( aPoly.GetSize() >= 2 ) { GDIMetaFile* pOldMF = mpMetaFile; mpMetaFile = NULL; DrawPolygon( aPoly ); mpMetaFile = pOldMF; } } else { // #100127# moved real PolyPolygon draw to separate method, // have to call recursively, avoiding duplicate // ImplLogicToDevicePixel calls ImplDrawPolyPolygon( nPoly, ImplLogicToDevicePixel( rPolyPoly ) ); } if( mpAlphaVDev ) mpAlphaVDev->DrawPolyPolygon( rPolyPoly ); } // ----------------------------------------------------------------------- void OutputDevice::DrawPolygon( const ::basegfx::B2DPolygon& rB2DPolygon) { // AW: Do NOT paint empty polygons if(rB2DPolygon.count()) { ::basegfx::B2DPolyPolygon aPP( rB2DPolygon ); DrawPolyPolygon( aPP ); } } // ----------------------------------------------------------------------- // Caution: This method is nearly the same as // OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency), // so when changes are made here do not forget to make change sthere, too void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly ) { DBG_TRACE( "OutputDevice::DrawPolyPolygon(B2D&)" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); #if 0 // MetaB2DPolyPolygonAction is not implemented yet: // according to AW adding it is very dangerous since there is a lot // of code that uses the metafile actions directly and unless every // place that does this knows about the new action we need to fallback if( mpMetaFile ) mpMetaFile->AddAction( new MetaB2DPolyPolygonAction( rB2DPolyPoly ) ); #else if( mpMetaFile ) mpMetaFile->AddAction( new MetaPolyPolygonAction( PolyPolygon( rB2DPolyPoly ) ) ); #endif // call helper ImpDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly); } void OutputDevice::ImpDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon& rB2DPolyPoly) { // AW: Do NOT paint empty PolyPolygons if(!rB2DPolyPoly.count()) return; // we need a graphics if( !mpGraphics ) if( !ImplGetGraphics() ) return; if( mbInitClipRegion ) ImplInitClipRegion(); if( mbOutputClipped ) return; if( mbInitLineColor ) ImplInitLineColor(); if( mbInitFillColor ) ImplInitFillColor(); if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) && ROP_OVERPAINT == GetRasterOp() && (IsLineColor() || IsFillColor())) { const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation()); basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly); bool bSuccess(true); // transform the polygon and ensure closed aB2DPolyPolygon.transform(aTransform); aB2DPolyPolygon.setClosed(true); if(IsFillColor()) { bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this); } if(bSuccess && IsLineColor()) { const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE) { aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon); } for(sal_uInt32 a(0);bSuccess && a < aB2DPolyPolygon.count(); a++) { bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this); } } if(bSuccess) { return; } } // fallback to old polygon drawing if needed const PolyPolygon aToolsPolyPolygon( rB2DPolyPoly ); const PolyPolygon aPixelPolyPolygon = ImplLogicToDevicePixel( aToolsPolyPolygon ); ImplDrawPolyPolygon( aPixelPolyPolygon.Count(), aPixelPolyPolygon ); } // ----------------------------------------------------------------------- bool OutputDevice::ImpTryDrawPolyLineDirect( const basegfx::B2DPolygon& rB2DPolygon, double fLineWidth, basegfx::B2DLineJoin eLineJoin, com::sun::star::drawing::LineCap eLineCap) { const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); basegfx::B2DVector aB2DLineWidth(1.0, 1.0); // transform the line width if used if( fLineWidth != 0.0 ) { aB2DLineWidth = aTransform * ::basegfx::B2DVector( fLineWidth, fLineWidth ); } // transform the polygon basegfx::B2DPolygon aB2DPolygon(rB2DPolygon); aB2DPolygon.transform(aTransform); if((mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE) && aB2DPolygon.count() < 1000) { // #i98289#, #i101491# // better to remove doubles on device coordinates. Also assume from a given amount // of points that the single edges are not long enough to smooth aB2DPolygon.removeDoublePoints(); aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon); } // draw the polyline return mpGraphics->DrawPolyLine( aB2DPolygon, 0.0, aB2DLineWidth, eLineJoin, eLineCap, this); } void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon, double fLineWidth, basegfx::B2DLineJoin eLineJoin, com::sun::star::drawing::LineCap eLineCap) { DBG_TRACE( "OutputDevice::DrawPolyLine(B2D&)" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); (void)eLineJoin; // ATM used in UNX, but not in WNT, access it for warning-free (void)eLineCap; #if 0 // MetaB2DPolyLineAction is not implemented yet: // according to AW adding it is very dangerous since there is a lot // of code that uses the metafile actions directly and unless every // place that does this knows about the new action we need to fallback if( mpMetaFile ) mpMetaFile->AddAction( new MetaB2DPolyLineAction( rB2DPolygon ) ); #else if( mpMetaFile ) { LineInfo aLineInfo; if( fLineWidth != 0.0 ) aLineInfo.SetWidth( static_cast(fLineWidth+0.5) ); const Polygon aToolsPolygon( rB2DPolygon ); mpMetaFile->AddAction( new MetaPolyLineAction( aToolsPolygon, aLineInfo ) ); } #endif // AW: Do NOT paint empty PolyPolygons if(!rB2DPolygon.count()) return; // we need a graphics if( !mpGraphics ) if( !ImplGetGraphics() ) return; if( mbInitClipRegion ) ImplInitClipRegion(); if( mbOutputClipped ) return; if( mbInitLineColor ) ImplInitLineColor(); const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) && ROP_OVERPAINT == GetRasterOp() && IsLineColor()); // use b2dpolygon drawing if possible if(bTryAA && ImpTryDrawPolyLineDirect(rB2DPolygon, fLineWidth, eLineJoin, eLineCap)) { return; } // #i101491# // no output yet; fallback to geometry decomposition and use filled polygon paint // when line is fat and not too complex. ImpDrawPolyPolygonWithB2DPolyPolygon // will do internal needed AA checks etc. if(fLineWidth >= 2.5 && rB2DPolygon.count() && rB2DPolygon.count() <= 1000) { const double fHalfLineWidth((fLineWidth * 0.5) + 0.5); const basegfx::B2DPolyPolygon aAreaPolyPolygon( basegfx::tools::createAreaGeometry( rB2DPolygon, fHalfLineWidth, eLineJoin, eLineCap)); const Color aOldLineColor(maLineColor); const Color aOldFillColor(maFillColor); SetLineColor(); ImplInitLineColor(); SetFillColor(aOldLineColor); ImplInitFillColor(); // draw usig a loop; else the topology will paint a PolyPolygon for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++) { ImpDrawPolyPolygonWithB2DPolyPolygon( basegfx::B2DPolyPolygon(aAreaPolyPolygon.getB2DPolygon(a))); } SetLineColor(aOldLineColor); ImplInitLineColor(); SetFillColor(aOldFillColor); ImplInitFillColor(); if(bTryAA) { // when AA it is necessary to also paint the filled polygon's outline // to avoid optical gaps for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++) { ImpTryDrawPolyLineDirect(aAreaPolyPolygon.getB2DPolygon(a)); } } } else { // fallback to old polygon drawing if needed const Polygon aToolsPolygon( rB2DPolygon ); LineInfo aLineInfo; if( fLineWidth != 0.0 ) aLineInfo.SetWidth( static_cast(fLineWidth+0.5) ); ImpDrawPolyLineWithLineInfo( aToolsPolygon, aLineInfo ); } } // ----------------------------------------------------------------------- sal_uInt32 OutputDevice::GetGCStackDepth() const { const ImplObjStack* pData = mpObjStack; sal_uInt32 nDepth = 0; while( pData ) { nDepth++; pData = pData->mpPrev; } return nDepth; } // ----------------------------------------------------------------------- void OutputDevice::Push( sal_uInt16 nFlags ) { DBG_TRACE( "OutputDevice::Push()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaPushAction( nFlags ) ); ImplObjStack* pData = new ImplObjStack; pData->mpPrev = mpObjStack; mpObjStack = pData; pData->mnFlags = nFlags; if ( nFlags & PUSH_LINECOLOR ) { if ( mbLineColor ) pData->mpLineColor = new Color( maLineColor ); else pData->mpLineColor = NULL; } if ( nFlags & PUSH_FILLCOLOR ) { if ( mbFillColor ) pData->mpFillColor = new Color( maFillColor ); else pData->mpFillColor = NULL; } if ( nFlags & PUSH_FONT ) pData->mpFont = new Font( maFont ); if ( nFlags & PUSH_TEXTCOLOR ) pData->mpTextColor = new Color( GetTextColor() ); if ( nFlags & PUSH_TEXTFILLCOLOR ) { if ( IsTextFillColor() ) pData->mpTextFillColor = new Color( GetTextFillColor() ); else pData->mpTextFillColor = NULL; } if ( nFlags & PUSH_TEXTLINECOLOR ) { if ( IsTextLineColor() ) pData->mpTextLineColor = new Color( GetTextLineColor() ); else pData->mpTextLineColor = NULL; } if ( nFlags & PUSH_OVERLINECOLOR ) { if ( IsOverlineColor() ) pData->mpOverlineColor = new Color( GetOverlineColor() ); else pData->mpOverlineColor = NULL; } if ( nFlags & PUSH_TEXTALIGN ) pData->meTextAlign = GetTextAlign(); if( nFlags & PUSH_TEXTLAYOUTMODE ) pData->mnTextLayoutMode = GetLayoutMode(); if( nFlags & PUSH_TEXTLANGUAGE ) pData->meTextLanguage = GetDigitLanguage(); if ( nFlags & PUSH_RASTEROP ) pData->meRasterOp = GetRasterOp(); if ( nFlags & PUSH_MAPMODE ) { if ( mbMap ) pData->mpMapMode = new MapMode( maMapMode ); else pData->mpMapMode = NULL; } if ( nFlags & PUSH_CLIPREGION ) { if ( mbClipRegion ) pData->mpClipRegion = new Region( maRegion ); else pData->mpClipRegion = NULL; } if ( nFlags & PUSH_REFPOINT ) { if ( mbRefPoint ) pData->mpRefPoint = new Point( maRefPoint ); else pData->mpRefPoint = NULL; } if( mpAlphaVDev ) mpAlphaVDev->Push(); } // ----------------------------------------------------------------------- void OutputDevice::Pop() { DBG_TRACE( "OutputDevice::Pop()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if( mpMetaFile ) mpMetaFile->AddAction( new MetaPopAction() ); GDIMetaFile* pOldMetaFile = mpMetaFile; ImplObjStack* pData = mpObjStack; mpMetaFile = NULL; if ( !pData ) { DBG_ERRORFILE( "OutputDevice::Pop() without OutputDevice::Push()" ); return; } if( mpAlphaVDev ) mpAlphaVDev->Pop(); mpObjStack = pData->mpPrev; if ( pData->mnFlags & PUSH_LINECOLOR ) { if ( pData->mpLineColor ) SetLineColor( *pData->mpLineColor ); else SetLineColor(); } if ( pData->mnFlags & PUSH_FILLCOLOR ) { if ( pData->mpFillColor ) SetFillColor( *pData->mpFillColor ); else SetFillColor(); } if ( pData->mnFlags & PUSH_FONT ) SetFont( *pData->mpFont ); if ( pData->mnFlags & PUSH_TEXTCOLOR ) SetTextColor( *pData->mpTextColor ); if ( pData->mnFlags & PUSH_TEXTFILLCOLOR ) { if ( pData->mpTextFillColor ) SetTextFillColor( *pData->mpTextFillColor ); else SetTextFillColor(); } if ( pData->mnFlags & PUSH_TEXTLINECOLOR ) { if ( pData->mpTextLineColor ) SetTextLineColor( *pData->mpTextLineColor ); else SetTextLineColor(); } if ( pData->mnFlags & PUSH_OVERLINECOLOR ) { if ( pData->mpOverlineColor ) SetOverlineColor( *pData->mpOverlineColor ); else SetOverlineColor(); } if ( pData->mnFlags & PUSH_TEXTALIGN ) SetTextAlign( pData->meTextAlign ); if( pData->mnFlags & PUSH_TEXTLAYOUTMODE ) SetLayoutMode( pData->mnTextLayoutMode ); if( pData->mnFlags & PUSH_TEXTLANGUAGE ) SetDigitLanguage( pData->meTextLanguage ); if ( pData->mnFlags & PUSH_RASTEROP ) SetRasterOp( pData->meRasterOp ); if ( pData->mnFlags & PUSH_MAPMODE ) { if ( pData->mpMapMode ) SetMapMode( *pData->mpMapMode ); else SetMapMode(); } if ( pData->mnFlags & PUSH_CLIPREGION ) ImplSetClipRegion( pData->mpClipRegion ); if ( pData->mnFlags & PUSH_REFPOINT ) { if ( pData->mpRefPoint ) SetRefPoint( *pData->mpRefPoint ); else SetRefPoint(); } ImplDeleteObjStack( pData ); mpMetaFile = pOldMetaFile; } // ----------------------------------------------------------------------- void OutputDevice::SetConnectMetaFile( GDIMetaFile* pMtf ) { mpMetaFile = pMtf; } // ----------------------------------------------------------------------- void OutputDevice::EnableOutput( sal_Bool bEnable ) { mbOutput = (bEnable != 0); if( mpAlphaVDev ) mpAlphaVDev->EnableOutput( bEnable ); } // ----------------------------------------------------------------------- void OutputDevice::SetSettings( const AllSettings& rSettings ) { maSettings = rSettings; if( mpAlphaVDev ) mpAlphaVDev->SetSettings( rSettings ); } // ----------------------------------------------------------------------- sal_uInt16 OutputDevice::GetBitCount() const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( meOutDevType == OUTDEV_VIRDEV ) return ((VirtualDevice*)this)->mnBitCount; // we need a graphics if ( !mpGraphics ) { if ( !((OutputDevice*)this)->ImplGetGraphics() ) return 0; } return (sal_uInt16)mpGraphics->GetBitCount(); } // ----------------------------------------------------------------------- sal_uInt16 OutputDevice::GetAlphaBitCount() const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); if ( meOutDevType == OUTDEV_VIRDEV && mpAlphaVDev != NULL ) { return mpAlphaVDev->GetBitCount(); } return 0; } // ----------------------------------------------------------------------- sal_uLong OutputDevice::GetColorCount() const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); const sal_uInt16 nBitCount = GetBitCount(); return( ( nBitCount > 31 ) ? ULONG_MAX : ( ( (sal_uLong) 1 ) << nBitCount) ); } // ----------------------------------------------------------------------- sal_Bool OutputDevice::HasAlpha() { return mpAlphaVDev != NULL; } // ----------------------------------------------------------------------- ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics > OutputDevice::CreateUnoGraphics() { UnoWrapperBase* pWrapper = Application::GetUnoWrapper(); return pWrapper ? pWrapper->CreateGraphics( this ) : ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >(); } // ----------------------------------------------------------------------- SystemGraphicsData OutputDevice::GetSystemGfxData() const { if ( !mpGraphics ) { if ( !ImplGetGraphics() ) return SystemGraphicsData(); } return mpGraphics->GetGraphicsData(); } // ----------------------------------------------------------------------- ::com::sun::star::uno::Any OutputDevice::GetSystemGfxDataAny() const { ::com::sun::star::uno::Any aRet; const SystemGraphicsData aSysData = GetSystemGfxData(); ::com::sun::star::uno::Sequence< sal_Int8 > aSeq( (sal_Int8*)&aSysData, aSysData.nSize ); return uno::makeAny(aSeq); } // ----------------------------------------------------------------------- ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas > OutputDevice::GetCanvas() const { uno::Sequence< uno::Any > aArg(6); aArg[ 0 ] = uno::makeAny( reinterpret_cast(this) ); aArg[ 2 ] = uno::makeAny( ::com::sun::star::awt::Rectangle( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight ) ); aArg[ 3 ] = uno::makeAny( sal_False ); aArg[ 5 ] = GetSystemGfxDataAny(); uno::Reference xFactory = vcl::unohelper::GetMultiServiceFactory(); uno::Reference xCanvas; // Create canvas instance with window handle // ========================================= if ( xFactory.is() ) { static uno::Reference xCanvasFactory( xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star." "rendering.CanvasFactory") ) ), uno::UNO_QUERY ); if(xCanvasFactory.is()) { xCanvas.set( xCanvasFactory->createInstanceWithArguments( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.rendering.Canvas" )), aArg ), uno::UNO_QUERY ); } } return xCanvas; } // -----------------------------------------------------------------------