diff options
Diffstat (limited to 'vcl/unx/source/gdi/salgdi.cxx')
-rw-r--r-- | vcl/unx/source/gdi/salgdi.cxx | 167 |
1 files changed, 125 insertions, 42 deletions
diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx index 6d7812828a10..6695d4abeb21 100644 --- a/vcl/unx/source/gdi/salgdi.cxx +++ b/vcl/unx/source/gdi/salgdi.cxx @@ -6,9 +6,6 @@ * * OpenOffice.org - a multi-platform office productivity suite * - * $RCSfile: salgdi.cxx,v $ - * $Revision: 1.53.16.1 $ - * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify @@ -102,7 +99,8 @@ X11SalGraphics::X11SalGraphics() m_pVDev = NULL; m_pDeleteColormap = NULL; hDrawable_ = None; - pRenderFormat_ = NULL; + m_aRenderPicture = 0; + m_pRenderFormat = NULL; pClipRegion_ = NULL; pPaintRegion_ = NULL; @@ -180,42 +178,70 @@ void X11SalGraphics::freeResources() if( m_pDeleteColormap ) delete m_pDeleteColormap, m_pColormap = m_pDeleteColormap = NULL; + if( m_aRenderPicture ) + XRenderPeer::GetInstance().FreePicture( m_aRenderPicture ), m_aRenderPicture = 0; + bPenGC_ = bFontGC_ = bBrushGC_ = bMonoGC_ = bCopyGC_ = bInvertGC_ = bInvert50GC_ = bStippleGC_ = bTrackingGC_ = false; } void X11SalGraphics::SetDrawable( Drawable aDrawable, int nScreen ) { + // shortcut if nothing changed + if( hDrawable_ == aDrawable ) + return; + + // free screen specific resources if needed if( nScreen != m_nScreen ) { freeResources(); m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap( nScreen ); m_nScreen = nScreen; } + hDrawable_ = aDrawable; - nPenPixel_ = GetPixel( nPenColor_ ); - nTextPixel_ = GetPixel( nTextColor_ ); - nBrushPixel_ = GetPixel( nBrushColor_ ); + SetXRenderFormat( NULL ); + if( m_aRenderPicture ) + { + XRenderPeer::GetInstance().FreePicture( m_aRenderPicture ); + m_aRenderPicture = 0; + } + + if( hDrawable_ ) + { + nPenPixel_ = GetPixel( nPenColor_ ); + nTextPixel_ = GetPixel( nTextColor_ ); + nBrushPixel_ = GetPixel( nBrushColor_ ); + } } void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget, int nScreen ) { +#if 0 // TODO: use SetDrawable() instead m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap(nScreen); hDrawable_ = aTarget; m_nScreen = nScreen; - - bWindow_ = TRUE; - m_pFrame = pFrame; - m_pVDev = NULL; + SetXRenderFormat( NULL ); + if( m_aRenderPicture ) + XRenderPeer::GetInstance().FreePicture( m_aRenderPicture ), m_aRenderPicture = 0; nPenPixel_ = GetPixel( nPenColor_ ); nTextPixel_ = GetPixel( nTextColor_ ); nBrushPixel_ = GetPixel( nBrushColor_ ); +#else + m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap(nScreen); + m_nScreen = nScreen; + SetDrawable( aTarget, nScreen ); +#endif + + bWindow_ = TRUE; + m_pFrame = pFrame; + m_pVDev = NULL; } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= void X11SalGraphics::DeInit() { - hDrawable_ = None; + SetDrawable( None, m_nScreen ); } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= @@ -994,6 +1020,40 @@ BOOL X11SalGraphics::drawEPS( long,long,long,long,void*,ULONG ) // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +XID X11SalGraphics::GetXRenderPicture() +{ + if( !m_aRenderPicture ) + { + // check xrender support for matching visual + // find a XRenderPictFormat compatible with the Drawable + XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); + XRenderPictFormat* pVisualFormat = static_cast<XRenderPictFormat*>(GetXRenderFormat()); + if( !pVisualFormat ) + { + Visual* pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual(); + pVisualFormat = rRenderPeer.FindVisualFormat( pVisual ); + if( !pVisualFormat ) + return 0; + // cache the XRenderPictFormat + SetXRenderFormat( static_cast<void*>(pVisualFormat) ); + } + + // get the matching xrender target for drawable + m_aRenderPicture = rRenderPeer.CreatePicture( hDrawable_, pVisualFormat, 0, NULL ); + } + +#if 0 + // setup clipping so the callers don't have to do it themselves + // TODO: avoid clipping if already set correctly + if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) ) + rRenderPeer.SetPictureClipRegion( aDstPic, pClipRegion_ ); +#endif + + return m_aRenderPicture; +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + SystemGraphicsData X11SalGraphics::GetGraphicsData() const { SystemGraphicsData aRes; @@ -1005,7 +1065,7 @@ SystemGraphicsData X11SalGraphics::GetGraphicsData() const aRes.nScreen = m_nScreen; aRes.nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth(); aRes.aColormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap(); - aRes.pRenderFormat = pRenderFormat_; + aRes.pRenderFormat = m_pRenderFormat; return aRes; } @@ -1072,7 +1132,15 @@ struct HalfTrapCompare } }; -typedef std::priority_queue< HalfTrapezoid, std::vector<HalfTrapezoid>, HalfTrapCompare > HTQueue; +typedef std::priority_queue< HalfTrapezoid, std::vector<HalfTrapezoid>, HalfTrapCompare > HTQueueBase; +// we need a priority queue with a reserve() to prevent countless reallocations +class HTQueue +: public HTQueueBase +{ +public: + void reserve( size_t n ) { c.reserve( n ); } + int capacity() { return c.capacity(); } +}; typedef std::vector<XTrapezoid> TrapezoidVector; @@ -1128,38 +1196,49 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); if( !rRenderPeer.AreTrapezoidsSupported() ) return FALSE; - - // check xrender support for matching visual - Visual* pVisual = GetVisual().GetVisual(); - XRenderPictFormat* pVisualFormat = rRenderPeer.FindVisualFormat( pVisual ); - if( !pVisualFormat ) + Picture aDstPic = GetXRenderPicture(); + // check xrender support for this drawable + if( !aDstPic ) return FALSE; // don't bother with polygons outside of visible area const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() ); - basegfx::B2DRange aPolyRange = basegfx::tools::getRange( rPolyPoly ); - aPolyRange.intersect( aViewRange ); - if( aPolyRange.isEmpty() ) + const basegfx::B2DRange aPolyRange = basegfx::tools::getRange( rPolyPoly ); + const bool bNeedViewClip = !aPolyRange.isInside( aViewRange ); + if( !aPolyRange.overlaps( aViewRange ) ) return true; // convert the polypolygon to trapezoids // first convert the B2DPolyPolygon to HalfTrapezoids + // #i100922# try to prevent priority-queue reallocations by reservering enough + int nHTQueueReserve = 0; + for( int nOuterPolyIdx = 0; nOuterPolyIdx < nPolygonCount; ++nOuterPolyIdx ) + { + const ::basegfx::B2DPolygon aOuterPolygon = rPolyPoly.getB2DPolygon( nOuterPolyIdx ); + const int nPointCount = aOuterPolygon.count(); + nHTQueueReserve += aOuterPolygon.areControlPointsUsed() ? 8 * nPointCount : nPointCount; + } + nHTQueueReserve = ((4*nHTQueueReserve) | 0x1FFF) + 1; HTQueue aHTQueue; + aHTQueue.reserve( nHTQueueReserve ); for( int nOuterPolyIdx = 0; nOuterPolyIdx < nPolygonCount; ++nOuterPolyIdx ) { - ::basegfx::B2DPolygon aOuterPolygon = rPolyPoly.getB2DPolygon( nOuterPolyIdx ); + const ::basegfx::B2DPolygon aOuterPolygon = rPolyPoly.getB2DPolygon( nOuterPolyIdx ); - // get rid of bezier segments - if( aOuterPolygon.areControlPointsUsed() ) - aOuterPolygon = ::basegfx::tools::adaptiveSubdivideByDistance( aOuterPolygon, 0.125 ); + // render-trapezoids should be inside the view => clip polygon against view range + basegfx::B2DPolyPolygon aClippedPolygon( aOuterPolygon ); + if( bNeedViewClip ) + { + aClippedPolygon = basegfx::tools::clipPolygonOnRange( aOuterPolygon, aViewRange, true, false ); + DBG_ASSERT( aClippedPolygon.count(), "polygon confirmed to overlap with view should not get here" ); + if( !aClippedPolygon.count() ) + continue; + } - // clip polygon against view - // (the call below for removing self intersections can be made much cheaper by this) - // TODO: move clipping before subdivision when clipPolyonRange learns to handle curves - const basegfx::B2DPolyPolygon aClippedPolygon = basegfx::tools::clipPolygonOnRange( aOuterPolygon, aViewRange, true, false ); - if( !aClippedPolygon.count() ) - return true; + // render-trapezoids have linear edges => get rid of bezier segments + if( aClippedPolygon.areControlPointsUsed() ) + aClippedPolygon = ::basegfx::tools::adaptiveSubdivideByDistance( aClippedPolygon, 0.125 ); // test and remove self intersections // TODO: make code intersection save, then remove this test @@ -1172,6 +1251,8 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly if( !nPointCount ) continue; + aHTQueue.reserve( aHTQueue.size() + 8 * nPointCount ); + // convert polygon point pairs to HalfTrapezoids // connect the polygon point with the first one if needed XPointFixed aOldXPF = { 0, 0 }; @@ -1384,22 +1465,15 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency ); rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 ); - // notify xrender of target drawable - // TODO: cache the matching xrender picture in the X11SalGraphics - Picture aDst = rRenderPeer.CreatePicture( hDrawable_, pVisualFormat, 0, NULL ); - // set clipping + // TODO: move into GetXRenderPicture? if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) ) - rRenderPeer.SetPictureClipRegion( aDst, pClipRegion_ ); + rRenderPeer.SetPictureClipRegion( aDstPic, pClipRegion_ ); // render the trapezoids const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8(); rRenderPeer.CompositeTrapezoids( PictOpOver, - rEntry.m_aPicture, aDst, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() ); - - // release xrender-counterpart of target drawable - // TODO: use scoped xrender picture - rRenderPeer.FreePicture( aDst ); + rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() ); return TRUE; } @@ -1408,6 +1482,15 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin) { + // #i101491# + if(rPolygon.count() > 1000) + { + // the used basegfx::tools::createAreaGeometry is simply too + // expensive with very big polygons; fallback to caller (who + // should use ImplLineConverter normally) + return false; + } + const XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); if( !rRenderPeer.AreTrapezoidsSupported() ) return false; |