summaryrefslogtreecommitdiff
path: root/vcl/unx
diff options
context:
space:
mode:
authorPhilipp Lohmann [pl] <Philipp.Lohmann@Sun.COM>2009-12-11 13:49:58 +0100
committerPhilipp Lohmann [pl] <Philipp.Lohmann@Sun.COM>2009-12-11 13:49:58 +0100
commitaf24b66c7b07b21e0ef5268116d75e6c22b95c90 (patch)
tree4826d7b88f8368a29e17df24cd1cfabea56dc43b /vcl/unx
parent0d1debd8e0179006d80f7f9ca443d21730f14dae (diff)
parentf8ada8f2a93659e27928f3b5244c813de2c3847b (diff)
merge with DEV300m67
Diffstat (limited to 'vcl/unx')
-rw-r--r--vcl/unx/gtk/window/gtkframe.cxx16
-rw-r--r--vcl/unx/headless/svppspgraphics.cxx22
-rw-r--r--vcl/unx/inc/plugins/gtk/gtkframe.hxx7
-rw-r--r--vcl/unx/source/gdi/pspgraphics.cxx22
-rw-r--r--vcl/unx/source/gdi/salgdi.cxx422
-rw-r--r--vcl/unx/source/gdi/xrender_peer.cxx4
-rw-r--r--vcl/unx/source/gdi/xrender_peer.hxx14
-rw-r--r--vcl/unx/source/printergfx/common_gfx.cxx66
8 files changed, 454 insertions, 119 deletions
diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx
index 9d401d84770d..72719e899bdb 100644
--- a/vcl/unx/gtk/window/gtkframe.cxx
+++ b/vcl/unx/gtk/window/gtkframe.cxx
@@ -772,7 +772,10 @@ void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle )
m_aForeignTopLevelWindow = None;
m_nStyle = nStyle;
- GtkWindowType eWinType = ((nStyle & SAL_FRAME_STYLE_FLOAT) && ! (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION))
+ GtkWindowType eWinType = ( (nStyle & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|
+ SAL_FRAME_STYLE_FLOAT_FOCUSABLE))
+ )
? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
if( nStyle & SAL_FRAME_STYLE_SYSTEMCHILD )
@@ -801,7 +804,7 @@ void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle )
bool bDecoHandling =
! isChild() &&
( ! (nStyle & SAL_FRAME_STYLE_FLOAT) ||
- (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) );
+ (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) );
/* #i100116# metacity has a peculiar behavior regarding WM_HINT accept focus and _NET_WM_USER_TIME
at some point that may be fixed in metacity and we will have to revisit this
@@ -832,6 +835,11 @@ void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle )
lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, true );
bNoDecor = true;
}
+ else if( (nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ }
+
if( (nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN ) )
{
eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
@@ -869,7 +877,7 @@ void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle )
if( bDecoHandling )
{
gtk_window_set_resizable( GTK_WINDOW(m_pWindow), (nStyle & SAL_FRAME_STYLE_SIZEABLE) ? TRUE : FALSE );
- if( ( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) || bMetaCityToolWindowHack )
+ if( ( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) ) || bMetaCityToolWindowHack )
lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, false );
}
@@ -2075,7 +2083,7 @@ void GtkSalFrame::ToTop( USHORT nFlags )
* to our window - which it of course won't since our input hint
* is set to false.
*/
- if( (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ if( (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE)) )
XSetInputFocus( getDisplay()->GetDisplay(), GDK_WINDOW_XWINDOW( m_pWindow->window ), RevertToParent, CurrentTime );
}
else
diff --git a/vcl/unx/headless/svppspgraphics.cxx b/vcl/unx/headless/svppspgraphics.cxx
index 3e9d67bcbbe9..1311aaed4ee4 100644
--- a/vcl/unx/headless/svppspgraphics.cxx
+++ b/vcl/unx/headless/svppspgraphics.cxx
@@ -986,13 +986,6 @@ const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnico
return NULL;
// fill in font info
- switch( aFontInfo.m_eType )
- {
- case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
- case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
- default:
- return NULL;
- }
rInfo.m_nAscent = aFontInfo.m_nAscend;
rInfo.m_nDescent = aFontInfo.m_nDescend;
rInfo.m_aPSName = rMgr.getPSName( aFont );
@@ -1029,9 +1022,22 @@ const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnico
rInfo.m_nCapHeight = yMax; // Well ...
for( int i = 0; i < 256; i++ )
-
pWidths[i] = (aMetrics[i].width > 0 ? aMetrics[i].width : 0);
+ switch( aFontInfo.m_eType )
+ {
+ case psp::fonttype::TrueType:
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ break;
+ case psp::fonttype::Type1: {
+ const bool bPFA = ((*(unsigned char*)pFile) < 0x80);
+ rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
return pFile;
}
diff --git a/vcl/unx/inc/plugins/gtk/gtkframe.hxx b/vcl/unx/inc/plugins/gtk/gtkframe.hxx
index a8fc6f65d4ee..c2a147517ac8 100644
--- a/vcl/unx/inc/plugins/gtk/gtkframe.hxx
+++ b/vcl/unx/inc/plugins/gtk/gtkframe.hxx
@@ -242,9 +242,10 @@ class GtkSalFrame : public SalFrame
bool isFloatGrabWindow() const
{
return
- (m_nStyle & SAL_FRAME_STYLE_FLOAT) && // only a float can be floatgrab
- !(m_nStyle & SAL_FRAME_STYLE_TOOLTIP) && // tool tips are not
- !(m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION); // toolbars are also not
+ (m_nStyle & SAL_FRAME_STYLE_FLOAT) && // only a float can be floatgrab
+ !(m_nStyle & SAL_FRAME_STYLE_TOOLTIP) && // tool tips are not
+ !(m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) && // toolbars are also not
+ !(m_nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE); // focusable floats are not
}
bool isChild( bool bPlug = true, bool bSysChild = true )
diff --git a/vcl/unx/source/gdi/pspgraphics.cxx b/vcl/unx/source/gdi/pspgraphics.cxx
index 009b14c56062..227d6cd7e9b2 100644
--- a/vcl/unx/source/gdi/pspgraphics.cxx
+++ b/vcl/unx/source/gdi/pspgraphics.cxx
@@ -1094,13 +1094,6 @@ const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnico
return NULL;
// fill in font info
- switch( aFontInfo.m_eType )
- {
- case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
- case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
- default:
- return NULL;
- }
rInfo.m_nAscent = aFontInfo.m_nAscend;
rInfo.m_nDescent = aFontInfo.m_nDescend;
rInfo.m_aPSName = rMgr.getPSName( aFont );
@@ -1137,9 +1130,22 @@ const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnico
rInfo.m_nCapHeight = yMax; // Well ...
for( int i = 0; i < 256; i++ )
-
pWidths[i] = (aMetrics[i].width > 0 ? aMetrics[i].width : 0);
+ switch( aFontInfo.m_eType )
+ {
+ case psp::fonttype::TrueType:
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ break;
+ case psp::fonttype::Type1: {
+ const bool bPFA = ((*(unsigned char*)pFile) < 0x80);
+ rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
return pFile;
}
diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx
index 34f2dfd4b935..c09803dcb269 100644
--- a/vcl/unx/source/gdi/salgdi.cxx
+++ b/vcl/unx/source/gdi/salgdi.cxx
@@ -1028,11 +1028,12 @@ BOOL X11SalGraphics::drawEPS( long,long,long,long,void*,ULONG )
XID X11SalGraphics::GetXRenderPicture()
{
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+
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 )
{
@@ -1053,7 +1054,15 @@ XID X11SalGraphics::GetXRenderPicture()
// TODO: avoid clipping if already set correctly
if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) )
rRenderPeer.SetPictureClipRegion( aDstPic, pClipRegion_ );
+ else
#endif
+ {
+ // reset clip region
+ // TODO: avoid clip reset if already done
+ XRenderPictureAttributes aAttr;
+ aAttr.clip_mask = None;
+ rRenderPeer.ChangePicture( m_aRenderPicture, CPClipMask, &aAttr );
+ }
return m_aRenderPicture;
}
@@ -1096,6 +1105,7 @@ bool IsLeftOf( const XLineFixed& rA, const XLineFixed& rB )
const XFixed aXDiff = rU.p2.x - rU.p1.x;
const XFixed aYDiff = rU.p2.y - rU.p1.y;
+ // compare upper point of lower segment with line through upper segment
if( (rU.p1.y != rL.p1.y) || (rU.p1.x != rL.p1.x) )
{
const sal_Int64 n1 = (sal_Int64)aXDiff * (rL.p1.y - rU.p1.y);
@@ -1104,6 +1114,7 @@ bool IsLeftOf( const XLineFixed& rA, const XLineFixed& rB )
return ((n1 < n2) == bAbove);
}
+ // compare lower point of lower segment with line through upper segment
if( (rU.p2.y != rL.p2.y) || (rU.p2.x != rL.p2.x) )
{
const sal_Int64 n3 = (sal_Int64)aXDiff * (rL.p2.y - rU.p1.y);
@@ -1122,10 +1133,14 @@ struct HalfTrapezoid
// maLine.p1.y <= mnY < maLine.p2.y
XLineFixed maLine;
XFixed mnY;
+
+ XFixed getXMin() const { return std::min( maLine.p1.x, maLine.p2.x); }
+ XFixed getXMax() const { return std::max( maLine.p1.x, maLine.p2.x); }
};
-struct HalfTrapCompare
+class HalfTrapCompare
{
+public:
bool operator()( const HalfTrapezoid& rA, const HalfTrapezoid& rB ) const
{
bool bIsTopLeft = false;
@@ -1138,14 +1153,15 @@ struct HalfTrapCompare
}
};
-typedef std::priority_queue< HalfTrapezoid, std::vector<HalfTrapezoid>, HalfTrapCompare > HTQueueBase;
+typedef std::vector< HalfTrapezoid > HTVector;
+typedef std::priority_queue< HalfTrapezoid, HTVector, 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(); }
+ void swapvec( HTVector& v ) { c.swap( v ); }
};
typedef std::vector<XTrapezoid> TrapezoidVector;
@@ -1173,6 +1189,10 @@ public:
};
typedef std::multiset< int, TrapezoidYCompare > VerticalTrapSet;
+
+#ifndef DISABLE_SOLVECROSSOVER_WORKAROUND
+void splitIntersectingSegments( HTVector&);
+#endif // DISABLE_SOLVECROSSOVER_WORKAROUND
} // end of anonymous namespace
// draw a poly-polygon
@@ -1210,7 +1230,7 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly
// don't bother with polygons outside of visible area
const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() );
const basegfx::B2DRange aPolyRange = basegfx::tools::getRange( rOrigPolyPoly );
- const bool bNeedViewClip = !aPolyRange.isInside( aViewRange );
+ const bool bNeedViewClip = aPolyRange.isInside( aViewRange );
if( !aPolyRange.overlaps( aViewRange ) )
return true;
@@ -1237,6 +1257,15 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly
if( !nClippedPolyCount )
continue;
+#ifndef DISABLE_SOLVECROSSOVER_WORKAROUND
+ for( int nClippedPolyIdx = 0; nClippedPolyIdx < nClippedPolyCount; ++nClippedPolyIdx )
+ {
+ const ::basegfx::B2DPolygon aSolvedPolygon = aClippedPolygon.getB2DPolygon( nClippedPolyIdx );
+ const int nPointCount = aSolvedPolygon.count();
+ aGoodPolyPoly.append( aSolvedPolygon );
+ nHTQueueReserve += aSolvedPolygon.areControlPointsUsed() ? 8 * nPointCount : nPointCount;
+ }
+#else // DISABLE_SOLVECROSSOVER_WORKAROUND
// #i103259# polypoly.solveCrossover() fails to remove self-intersections
// but polygon.solveCrossover() works. Use it to build the intersection-free polypolygon
// TODO: if the self-intersection prevention is too expensive make the trap-algorithm tolerate intersections
@@ -1255,11 +1284,12 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly
nHTQueueReserve += aSolvedPolygon.areControlPointsUsed() ? 8 * nPointCount : nPointCount;
}
}
+#endif // DISABLE_SOLVECROSSOVER_WORKAROUND
}
// #i100922# try to prevent priority-queue reallocations by reservering enough
nHTQueueReserve = ((4*nHTQueueReserve) | 0x1FFF) + 1;
- HTQueue aHTQueue;
- aHTQueue.reserve( nHTQueueReserve );
+ HTVector aHTVector;
+ aHTVector.reserve( nHTQueueReserve );
// first convert the B2DPolyPolygon to HalfTrapezoids
const int nGoodPolyCount = aGoodPolyPoly.count();
@@ -1299,9 +1329,6 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly
// check if enough data is available for a new HalfTrapezoid
if( nPointIdx == 0 )
continue;
- // ignore vertical segments
- if( aNewXPF.y == aOldXPF.y )
- continue;
// construct HalfTrapezoid as topdown segment
HalfTrapezoid aHT;
@@ -1326,14 +1353,33 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly
#endif
// queue up the HalfTrapezoid
- aHTQueue.push( aHT );
+ aHTVector.push_back( aHT );
}
}
}
- if( aHTQueue.empty() )
+ if( aHTVector.empty() )
return TRUE;
+#ifndef DISABLE_SOLVECROSSOVER_WORKAROUND
+ // find intersecting halftraps and split them up
+ // TODO: remove when solveCrossOvers gets fast enough so its use can be enabled above
+ // FAQ: why should segment intersection be handled before adaptiveSubdivide()?
+ // Answer: because it is conceptually much faster
+ // Example: consider two intersecting circles with a diameter of 1000 pixels
+ // before subdivision: eight bezier segments
+ // after subdivision: more than a thousand line segments
+ // since even the best generic intersection finders have a complexity of O((n+k)*log(n+k))
+ // it shows that testing while the segment count is still low is a much better approach.
+ splitIntersectingSegments( aHTVector);
+#endif // DISABLE_SOLVECROSSOVER_WORKAROUND
+
+ // build queue from vector of intersection-free segments
+ // TODO: is replacing the priority-queue by a sorted vector worth it?
+ std::make_heap( aHTVector.begin(), aHTVector.end(), HalfTrapCompare());
+ HTQueue aHTQueue;
+ aHTQueue.swapvec( aHTVector);
+
// then convert the HalfTrapezoids into full Trapezoids
TrapezoidVector aTrapVector;
aTrapVector.reserve( aHTQueue.size() * 2 ); // just a guess
@@ -1349,24 +1395,28 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly
XTrapezoid aTrapezoid;
// convert a HalfTrapezoid pair
+ // get the left side of the trapezoid
const HalfTrapezoid& rLeft = aHTQueue.top();
aTrapezoid.top = rLeft.mnY;
- aTrapezoid.bottom = rLeft.maLine.p2.y;
aTrapezoid.left = rLeft.maLine;
+ aHTQueue.pop();
-#if 0
- // ignore empty trapezoids
- if( aTrapezoid.bottom <= aTrapezoid.top )
+ // ignore left segment that would result in an empty trapezoid
+ if( aTrapezoid.left.p2.y <= aTrapezoid.top )
continue;
-#endif
- aHTQueue.pop();
- if( aHTQueue.empty() ) // TODO: assert
- break;
- const HalfTrapezoid& rRight = aHTQueue.top();
- aTrapezoid.right = rRight.maLine;
- aHTQueue.pop();
+ // get the right side of the trapezoid
+ aTrapezoid.right.p2.y = aTrapezoid.bottom;
+ while( !aHTQueue.empty() ) {
+ const HalfTrapezoid& rRight = aHTQueue.top();
+ aTrapezoid.right = rRight.maLine;
+ aHTQueue.pop();
+ // ignore right segment that would result in an empty trapezoid
+ if( aTrapezoid.right.p2.y > aTrapezoid.top )
+ break;
+ }
+ // the topmost endpoint determines the trapezoid bottom
aTrapezoid.bottom = aTrapezoid.left.p2.y;
if( aTrapezoid.bottom > aTrapezoid.right.p2.y )
aTrapezoid.bottom = aTrapezoid.right.p2.y;
@@ -1374,44 +1424,49 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly
// keep the full Trapezoid candidate
aTrapVector.push_back( aTrapezoid );
- // unless it splits an older trapezoid
+ // unless it splits another trapezoid that is still active
bool bSplit = false;
- for(;;)
+ ActiveTrapSet::iterator aActiveTrapsIt = aActiveTraps.begin();
+ for(; aActiveTrapsIt != aActiveTraps.end(); ++aActiveTrapsIt )
{
- // check if the new trapezoid overlaps with an old trapezoid
- ActiveTrapSet::iterator aActiveTrapsIt
- = aActiveTraps.upper_bound( aTrapVector.size()-1 );
- if( aActiveTrapsIt == aActiveTraps.begin() )
- break;
- --aActiveTrapsIt;
-
XTrapezoid& rLeftTrap = aTrapVector[ *aActiveTrapsIt ];
+ // skip until first overlap candidate
+ // TODO: use stl::*er_bound() instead
+ if( IsLeftOf( aTrapezoid.left, rLeftTrap.left) )
+ continue;
+
// in the ActiveTrapSet there are still trapezoids where
// a vertical overlap with new trapezoids is no longer possible
// they could have been removed in the verticaltraps loop below
- // but this would have been expensive and is not needed as we can
- // simply ignore them now and remove them from the ActiveTrapSet
- // so they won't bother us in the future
+ // but this would be expensive and is not needed as we can
+ // simply ignore them until we stumble upon them here.
if( rLeftTrap.bottom <= aTrapezoid.top )
{
- aActiveTraps.erase( aActiveTrapsIt );
+ ActiveTrapSet::iterator it = aActiveTrapsIt;
+ if( aActiveTrapsIt != aActiveTraps.begin() )
+ --aActiveTrapsIt;
+ aActiveTraps.erase( it );
continue;
}
// check if there is horizontal overlap
// aTrapezoid.left==rLeftTrap.right is allowed though
if( !IsLeftOf( aTrapezoid.left, rLeftTrap.right ) )
- break;
+ continue;
- // split the old trapezoid and keep its upper part
+ // prepare to split the old trapezoid and keep its upper part
// find the old trapezoids entry in the VerticalTrapSet and remove it
typedef std::pair<VerticalTrapSet::iterator, VerticalTrapSet::iterator> VTSPair;
VTSPair aVTSPair = aVerticalTraps.equal_range( *aActiveTrapsIt );
VerticalTrapSet::iterator aVTSit = aVTSPair.first;
- for(; (aVTSit != aVTSPair.second) && (*aVTSit != *aActiveTrapsIt); ++aVTSit ) ;
- if( aVTSit != aVTSPair.second )
+ for(; aVTSit != aVTSPair.second; ++aVTSit )
+ {
+ if( *aVTSit != *aActiveTrapsIt )
+ continue;
aVerticalTraps.erase( aVTSit );
+ break;
+ }
// then update the old trapezoid's bottom
rLeftTrap.bottom = aTrapezoid.top;
// enter the updated old trapzoid in VerticalTrapSet
@@ -1444,24 +1499,26 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPoly
// mark trapezoids that can no longer be split as inactive
// and recycle their sides which were not fully resolved
static const XFixed nMaxTop = +0x7FFFFFFF;
- XFixed nNewTop = aHTQueue.empty() ? nMaxTop : aHTQueue.top().mnY;
+ const XFixed nNewTop = aHTQueue.empty() ? nMaxTop : aHTQueue.top().mnY;
while( !aVerticalTraps.empty() )
{
+ // check the next trapezoid to be retired
const XTrapezoid& rOldTrap = aTrapVector[ *aVerticalTraps.begin() ];
if( nNewTop < rOldTrap.bottom )
break;
- // the reference Trapezoid can no longer be split
+ // this trapezoid can no longer be split
aVerticalTraps.erase( aVerticalTraps.begin() );
// recycle its sides that were not fully resolved
HalfTrapezoid aHT;
aHT.mnY = rOldTrap.bottom;
- if( rOldTrap.left.p2.y > rOldTrap.bottom )
+
+ if( rOldTrap.left.p2.y > aHT.mnY )
{
aHT.maLine = rOldTrap.left;
aHTQueue.push( aHT );
}
- if( rOldTrap.right.p2.y > rOldTrap.bottom )
+ if( rOldTrap.right.p2.y > aHT.mnY )
{
aHT.maLine = rOldTrap.right;
aHTQueue.push( aHT );
@@ -1527,13 +1584,20 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const :
aPolygon.transform( aAnisoMatrix );
}
- // AW: reSegment no longer needed; new createAreaGeometry will remove exteme positions
- // and create bezier polygons
- //if( aPolygon.areControlPointsUsed() )
- // aPolygon = basegfx::tools::reSegmentPolygonEdges( aPolygon, 8, true, false );
- //const basegfx::B2DPolyPolygon aAreaPolyPoly = basegfx::tools::createAreaGeometryForSimplePolygon(
- // aPolygon, 0.5*rLineWidth.getX(), eLineJoin );
- const basegfx::B2DPolyPolygon aAreaPolyPoly(basegfx::tools::createAreaGeometry(aPolygon, 0.5*rLineWidth.getX(), eLineJoin));
+ // special handling for hairlines to improve the drawing performance
+ // TODO: revisit after basegfx performance related changes
+ const bool bIsHairline = (rLineWidth.getX() < 1.2) && (rLineWidth.getY() < 1.2);
+ if( bIsHairline )
+ {
+ // for hairlines the linejoin style becomes irrelevant
+ eLineJoin = basegfx::B2DLINEJOIN_NONE;
+ // createAreaGeometry is still too expensive when beziers are involved
+ if( aPolygon.areControlPointsUsed() )
+ aPolygon = ::basegfx::tools::adaptiveSubdivideByDistance( aPolygon, 0.125 );
+ }
+
+ // create the area-polygon for the line
+ const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, 0.5*rLineWidth.getX(), eLineJoin) );
if( (rLineWidth.getX() != rLineWidth.getY())
&& !basegfx::fTools::equalZero( rLineWidth.getX() ) )
@@ -1568,3 +1632,259 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const :
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef DISABLE_SOLVECROSSOVER_WORKAROUND
+// TODO: move the intersection solver into basegfx
+// and then support bezier-intersection finding too
+
+namespace { // anonymous namespace to prevent export
+
+typedef HalfTrapezoid LineSeg;
+typedef HTVector LSVector;
+
+inline bool operator==( const LineSeg& r1, const LineSeg& r2)
+{
+ if( r1.maLine.p2.y != r2.maLine.p2.y) return false;
+ if( r1.maLine.p2.x != r2.maLine.p2.x) return false;
+ if( r1.maLine.p1.y != r2.maLine.p1.y) return false;
+ if( r1.maLine.p1.x != r2.maLine.p1.x) return false;
+ return true;
+}
+
+struct LSYMinCmp
+{
+ bool operator()( const LineSeg& r1, const LineSeg& r2) const
+ { return r2.maLine.p1.y < r1.maLine.p1.y; }
+};
+
+struct LSYMaxCmp
+{
+ bool operator()( const LineSeg& r1, const LineSeg& r2) const
+ { return r2.maLine.p2.y < r1.maLine.p2.y; }
+};
+
+struct LSXMinCmp
+{
+ bool operator()( const LineSeg& r1, const LineSeg& r2) const
+ { return( r1.getXMin() < r2.getXMin()); }
+};
+
+struct CutPoint
+{
+ XFixed mnSegmentId;
+ float mfCutParam;
+ XPointFixed maPoint;
+};
+
+struct CutPointCmp
+{
+ bool operator()( const CutPoint& r1, const CutPoint& r2) const
+ {
+ if( r1.mnSegmentId != r2.mnSegmentId)
+ return (r1.mnSegmentId < r2.mnSegmentId);
+ return (r1.mfCutParam < r2.mfCutParam);
+ }
+};
+
+bool findIntersection( const LineSeg& rLS1, const LineSeg& rLS2, CutPoint aCutPoints[2])
+{
+ // segments intersect at r1.p1 + s*(r1.p2-r1.p1) == r2.p1 + t*(r2.p2-r2.p1)
+ // when both segment-parameters are ((0 <s<1) && (0<t<1))
+ // (r1.p1 - r2.p1) == s * (r1.p1 - r1.p2) + t * (r2.p2 - r2.p1)
+ // =>
+ // (r1.p1x - r2.p1x) == s * (r1.p1x - r1.p2x) + t * (r2.p2x - r2.p1x)
+ // (r1.p1y - r2.p1y) == s * (r1.p1y - r1.p2y) + t * (r2.p2y - r2.p1y)
+ // check if lines are identical or parallel => not intersecting
+ const XLineFixed& r1 = rLS1.maLine;
+ const XLineFixed& r2 = rLS2.maLine;
+ const double fDet = (double)(r1.p1.x - r1.p2.x) * (r2.p2.y - r2.p1.y)
+ - (double)(r2.p2.x - r2.p1.x) * (r1.p1.y - r1.p2.y);
+ static const double fEps = 1e-8;
+ if( fabs(fDet) < fEps)
+ return false;
+ // check if intersecting with first segment
+ const double fS1 = (double)(r2.p2.y - r2.p1.y) * (r1.p1.x - r2.p1.x);
+ const double fS2 = (double)(r2.p2.x - r2.p1.x) * (r2.p1.y - r1.p1.y);
+ const double fS = (fS1 + fS2) / fDet;
+ if( (fS <= +fEps) || (fS >= 1-fEps))
+ return false;
+ // check if intersecting with second segment
+ const double fT1 = (double)(r1.p2.y - r1.p1.y) * (r1.p1.x - r2.p1.x);
+ const double fT2 = (double)(r1.p2.x - r1.p1.x) * (r2.p1.y - r1.p1.y);
+ const double fT = (fT1 + fT2) / fDet;
+ if( (fT <= +fEps) || (fT >= 1-fEps))
+ return false;
+ // force the intersection point to be exactly identical on both segments
+ aCutPoints[0].maPoint.x = (XFixed)(r1.p1.x + fS * (r1.p2.x - r1.p1.x));
+ aCutPoints[0].maPoint.y = (XFixed)(r1.p1.y + fS * (r1.p2.y - r1.p1.y));
+ aCutPoints[1].maPoint.x = aCutPoints[0].maPoint.x;
+ aCutPoints[1].maPoint.y = aCutPoints[0].maPoint.y;
+ aCutPoints[0].mnSegmentId = rLS1.mnY;
+ aCutPoints[0].mfCutParam = (float)fS;
+ aCutPoints[1].mnSegmentId = rLS2.mnY;
+ aCutPoints[1].mfCutParam = (float)fT;
+ return true;
+}
+
+typedef std::priority_queue< LineSeg, LSVector, LSYMinCmp> LSYMinQueueBase;
+typedef std::priority_queue< LineSeg, LSVector, LSYMaxCmp> LSYMaxQueueBase;
+typedef std::multiset< LineSeg, LSXMinCmp> LSXMinSet;
+typedef std::set< CutPoint, CutPointCmp> CutPointSet;
+
+class LSYMinQueue : public LSYMinQueueBase
+{
+public:
+ void reserve( size_t n) { c.reserve(n);}
+ void swapvec( LSVector& v) { c.swap(v);}
+};
+
+class LSYMaxQueue : public LSYMaxQueueBase
+{
+public:
+ void reserve( size_t n) { c.reserve(n);}
+};
+
+void addAndCutSegment( LSVector& rLSVector, const LineSeg& rLS, CutPointSet& rCutPointSet)
+{
+ // short circuit when no segment was cut
+ if( rCutPointSet.empty()) {
+ rLSVector.push_back( rLS);
+ return;
+ }
+
+ // find the first cut point for this segment
+ LineSeg aCS = rLS;
+ CutPoint aMinCutPoint;
+ aMinCutPoint.mnSegmentId = rLS.mnY;
+ aMinCutPoint.mfCutParam = 0.0;
+ CutPointSet::iterator itFirst = rCutPointSet.lower_bound( aMinCutPoint);
+ CutPointSet::iterator it = itFirst;
+ // iterate through all cut points of this segment
+ for(; it != rCutPointSet.end(); ++it) {
+ const CutPoint rCutPoint = (*it);
+ if( rCutPoint.mnSegmentId != rLS.mnY)
+ break;
+ // cut segment at the cutpoint
+ aCS.maLine.p2 = rCutPoint.maPoint;
+ rLSVector.push_back( aCS);
+ // prepare for next segment cut
+ aCS.maLine.p1 = aCS.maLine.p2;
+ }
+ // remove cutparams that will no longer be needed
+ // TODO: is it worth it or should we just keep the cutparams?
+ rCutPointSet.erase( itFirst, it);
+
+ // add segment part remaining after last cut
+ aCS.maLine.p2 = rLS.maLine.p2;
+ rLSVector.push_back( aCS);
+}
+
+void splitIntersectingSegments( LSVector& rLSVector)
+{
+ // get a unique id for each lineseg, temporarily abuse the mnY member
+ LSVector::iterator aLSit = rLSVector.begin();
+ for( int i = 0; aLSit != rLSVector.end(); ++aLSit) {
+ LineSeg& rLS = *aLSit;
+ rLS.mnY = i++;
+ }
+ // get an y-sorted queue from the input vector
+ LSYMinQueue aYMinQueue;
+ std::make_heap( rLSVector.begin(), rLSVector.end(), LSYMinCmp());
+ aYMinQueue.swapvec( rLSVector);
+
+ // prepare the result vector
+ // try to avoid reallocations by guessing a reasonable result size
+ rLSVector.reserve( aYMinQueue.size() * 1.5);
+
+ // find all intersections
+ CutPointSet aCutPointSet;
+ LSXMinSet aXMinSet;
+ LSYMaxQueue aYMaxQueue;
+ aYMaxQueue.reserve( aYMinQueue.size());
+ // sweep-down and check all segment-pairs that overlap
+ while( !aYMinQueue.empty()) {
+ // get next input-segment
+ const LineSeg& rLS = aYMinQueue.top();
+ // retire obsoleted segments
+ const XFixed fYCur = rLS.maLine.p1.y;
+ while( !aYMaxQueue.empty()) {
+ // check next segment to be retired
+ const LineSeg& rOS = aYMaxQueue.top();
+ if( fYCur < rOS.maLine.p2.y)
+ break;
+ // emit resolved segment into result
+ addAndCutSegment( rLSVector, rOS, aCutPointSet);
+ // find segment to be retired in xmin-compare-set
+ LSXMinSet::iterator itR = aXMinSet.lower_bound( rOS);
+ while( !(*itR == rOS)) ++itR;
+ // retire segment from xmin-compare-set
+ aXMinSet.erase( itR);
+ // this segment is pining for the fjords
+ aYMaxQueue.pop();
+ }
+
+ // iterate over all segments that might overlap
+ // skip over the leftmost segments that cannot overlap
+ const XFixed fXMax = rLS.getXMax();
+ LSXMinSet::const_iterator itC = aXMinSet.begin();
+ for(; itC != aXMinSet.end(); ++itC)
+ if( (*itC).getXMin() <= fXMax)
+ break;
+ // TODO: if the linear search becomes too expensive
+ // then use an XMaxQueue based approach to replace it
+ const XFixed fXMin = rLS.getXMin();
+ for(; itC != aXMinSet.end(); ++itC) {
+ const LineSeg& rOS = *itC;
+ if( fXMin >= rOS.getXMax())
+ continue;
+ if( fXMax < rOS.getXMin())
+ break;
+ CutPoint aCutPoints[2];
+ if( !findIntersection( rLS, rOS, aCutPoints))
+ continue;
+ // remember cut parameters
+ // TODO: std::set seems to use individual allocations
+ // which results in perf-problems for many entries
+ // => pre-allocate nodes by using a non-default allocator
+ aCutPointSet.insert( aCutPoints[0]);
+ aCutPointSet.insert( aCutPoints[1]);
+ }
+ // add segment to xmin-compare-set
+ // TODO: do we have a good insertion hint?
+ aXMinSet.insert( /*itC,*/ rLS);
+ // register segment for retirement
+ aYMaxQueue.push( rLS);
+ aYMinQueue.pop();
+ }
+
+ // retire the remaining segments
+ aXMinSet.clear();
+ while( !aYMaxQueue.empty()) {
+ // emit segments and cut them up if needed
+ const LineSeg& rLS = aYMaxQueue.top();
+ addAndCutSegment( rLSVector, rLS, aCutPointSet);
+ aYMaxQueue.pop();
+ }
+
+ // get the segments ready to be consumed by the drawPolygon() caller
+ aLSit = rLSVector.begin();
+ LSVector::iterator aLSit2 = aLSit;
+ for(; aLSit != rLSVector.end(); ++aLSit) {
+ LineSeg& rLS = *aLSit;
+ // restore the segment top member
+ rLS.mnY = rLS.maLine.p1.y;
+ // remove horizontal segments for now
+ // TODO: until the trapezoid converter is adjusted to handle them
+ if( rLS.maLine.p1.y == rLS.maLine.p2.y )
+ continue;
+ *(aLSit2++) = rLS;
+ }
+ if(aLSit2 != aLSit)
+ rLSVector.resize( aLSit2 - rLSVector.begin() );
+}
+
+} // end anonymous namespace
+
+#endif // DISABLE_SOLVECROSSOVER_WORKAROUND
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
diff --git a/vcl/unx/source/gdi/xrender_peer.cxx b/vcl/unx/source/gdi/xrender_peer.cxx
index d8f2045c6fde..fc8de818fafd 100644
--- a/vcl/unx/source/gdi/xrender_peer.cxx
+++ b/vcl/unx/source/gdi/xrender_peer.cxx
@@ -142,6 +142,10 @@ void XRenderPeer::InitRenderLib()
mpXRenderCreatePicture = (Picture(*)(Display*,Drawable,const XRenderPictFormat*,
unsigned long,const XRenderPictureAttributes*))pFunc;
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderChangePicture" );
+ if( !pFunc ) return;
+ mpXRenderChangePicture = (void(*)(Display*,Picture,unsigned long,const XRenderPictureAttributes*))pFunc;
+
pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderSetPictureClipRegion" );
if( !pFunc ) return;
mpXRenderSetPictureClipRegion = (void(*)(Display*,Picture,XLIB_Region))pFunc;
diff --git a/vcl/unx/source/gdi/xrender_peer.hxx b/vcl/unx/source/gdi/xrender_peer.hxx
index f1e2fd77a273..27c8fb3dcaeb 100644
--- a/vcl/unx/source/gdi/xrender_peer.hxx
+++ b/vcl/unx/source/gdi/xrender_peer.hxx
@@ -66,6 +66,8 @@ public:
const XRenderPictFormat& ) const;
Picture CreatePicture( Drawable, const XRenderPictFormat*,
unsigned long nDrawable, const XRenderPictureAttributes* ) const;
+ void ChangePicture( Picture, unsigned long nValueMask,
+ const XRenderPictureAttributes* ) const;
void SetPictureClipRegion( Picture, XLIB_Region ) const;
void CompositePicture( int nOp, Picture aSrc, Picture aMask, Picture aDst,
int nXSrc, int nYSrc, int nXMask, int nYMask,
@@ -103,6 +105,8 @@ private:
Picture (*mpXRenderCreatePicture)(Display*,Drawable, const XRenderPictFormat*,
unsigned long,const XRenderPictureAttributes*);
+ void (*mpXRenderChangePicture)(Display*,Picture,
+ unsigned long,const XRenderPictureAttributes*);
void (*mpXRenderSetPictureClipRegion)(Display*,Picture,XLIB_Region);
void (*mpXRenderFreePicture)(Display*,Picture);
void (*mpXRenderComposite)(Display*,int,Picture,Picture,Picture,
@@ -194,6 +198,16 @@ inline Picture XRenderPeer::CreatePicture( Drawable aDrawable,
#endif
}
+inline void XRenderPeer::ChangePicture( Picture aPicture,
+ unsigned long nValueMask, const XRenderPictureAttributes* pRenderAttr ) const
+{
+#ifdef XRENDER_LINK
+ XRenderChangePicture( mpDisplay, aPicture, nValueMask, pRenderAttr );
+#else
+ (*mpXRenderChangePicture)( mpDisplay, aPicture, nValueMask, pRenderAttr );
+#endif
+}
+
inline void XRenderPeer::SetPictureClipRegion( Picture aPicture,
XLIB_Region aXlibRegion ) const
{
diff --git a/vcl/unx/source/printergfx/common_gfx.cxx b/vcl/unx/source/printergfx/common_gfx.cxx
index 632f0d70aa2f..9b305ff323ba 100644
--- a/vcl/unx/source/printergfx/common_gfx.cxx
+++ b/vcl/unx/source/printergfx/common_gfx.cxx
@@ -7,7 +7,6 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: common_gfx.cxx,v $
- * $Revision: 1.20.18.1 $
*
* This file is part of OpenOffice.org.
*
@@ -535,68 +534,47 @@ PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints, const Point* pPath, const BY
const sal_uInt32 nBezString = 1024;
sal_Char pString[nBezString];
- if ( maLineColor.Is() && nPoints && pPath )
+ if ( nPoints > 1 && maLineColor.Is() && pPath )
{
PSSetColor (maLineColor);
PSSetColor ();
PSSetLineWidth ();
- if (pFlgAry[0] != POLY_NORMAL) //There must be a starting point to moveto
- {
- return;
- }
- else
- {
- snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
- WritePS(mpPageBody, pString);
- }
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
+ WritePS(mpPageBody, pString);
// Handle the drawing of mixed lines mixed with curves
// - a normal point followed by a normal point is a line
// - a normal point followed by 2 control points and a normal point is a curve
for (unsigned int i=1; i<nPoints;)
{
- if (pFlgAry[i+1] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
+ if (pFlgAry[i] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
{
- if (i+1 >= nPoints) return; //Make sure we don't pass the end of the array
snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
i++;
}
else //Otherwise we're drawing a spline
{
- if (i+3 >= nPoints) return; //Make sure we don't pass the end of the array
- snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
- pPath[i+1].X(), pPath[i+1].Y(),
- pPath[i+2].X(), pPath[i+2].Y(),
- pPath[i+3].X(), pPath[i+3].Y());
+ if (i+2 >= nPoints)
+ return; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
+ (pFlgAry[i+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i].X(), pPath[i].Y(),
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y());
+ }
+ else
+ {
+ DBG_ERROR( "PrinterGfx::DrawPolyLineBezier: Strange output" );
+ }
i+=3;
}
WritePS(mpPageBody, pString);
}
- }
-
- // if eofill and stroke, save the current path
- if( maFillColor.Is() && maLineColor.Is())
- PSGSave();
-
- // first draw area
- if( maFillColor.Is() )
- {
- PSSetColor (maFillColor);
- PSSetColor ();
- WritePS (mpPageBody, "eofill\n");
- }
-
- // restore the current path
- if( maFillColor.Is() && maLineColor.Is())
- PSGRestore();
- // now draw outlines
- if( maLineColor.Is() )
- {
- PSSetColor (maLineColor);
- PSSetColor ();
- PSSetLineWidth ();
+ // now draw outlines
WritePS (mpPageBody, "stroke\n");
}
}
@@ -635,7 +613,7 @@ PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints, const Point* pPath, const BYT
}
else
{
- fprintf(stderr, "Strange output\n");
+ DBG_ERROR( "PrinterGfx::DrawPolygonBezier: Strange output" );
}
i+=3;
}
@@ -699,9 +677,7 @@ PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly, const sal_uInt32 * pPoints,
}
else
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf(stderr, "Strange output\n");
-#endif
+ DBG_ERROR( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
}
j+=3;
}