summaryrefslogtreecommitdiff
path: root/vcl/unx/source/gdi/salgdi.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/source/gdi/salgdi.cxx')
-rw-r--r--vcl/unx/source/gdi/salgdi.cxx167
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;