blob: f77c530b08930ed7139bb603ae1e1ccc163cf831 [file] [log] [blame]
/**************************************************************
*
* 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 "tools/debug.hxx"
#include "basegfx/polygon/b2dpolygon.hxx"
#include "basegfx/polygon/b2dpolypolygon.hxx"
#include "basegfx/polygon/b2dpolypolygontools.hxx"
#include "basegfx/polygon/b2dpolygontools.hxx"
#include "basegfx/polygon/b2dpolygonclipper.hxx"
#include "basegfx/polygon/b2dlinegeometry.hxx"
#include "basegfx/matrix/b2dhommatrix.hxx"
#include "basegfx/matrix/b2dhommatrixtools.hxx"
#include "basegfx/polygon/b2dpolypolygoncutter.hxx"
#include "basegfx/polygon/b2dtrapezoid.hxx"
#include "vcl/jobdata.hxx"
#include "unx/Xproto.h"
#include "unx/salunx.h"
#include "unx/saldata.hxx"
#include "unx/saldisp.hxx"
#include "unx/salgdi.h"
#include "unx/salframe.h"
#include "unx/salvd.h"
#include "printergfx.hxx"
#include "xrender_peer.hxx"
#include <vector>
#include <queue>
#include <set>
// -=-= SalPolyLine =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#define STATIC_POINTS 64
class SalPolyLine
{
XPoint Points_[STATIC_POINTS];
XPoint *pFirst_;
public:
inline SalPolyLine( sal_uLong nPoints );
inline SalPolyLine( sal_uLong nPoints, const SalPoint *p );
inline ~SalPolyLine();
inline XPoint &operator [] ( sal_uLong n ) const
{ return pFirst_[n]; }
};
inline SalPolyLine::SalPolyLine( sal_uLong nPoints )
: pFirst_( nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_ )
{}
inline SalPolyLine::SalPolyLine( sal_uLong nPoints, const SalPoint *p )
: pFirst_( nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_ )
{
for( sal_uLong i = 0; i < nPoints; i++ )
{
pFirst_[i].x = (short)p[i].mnX;
pFirst_[i].y = (short)p[i].mnY;
}
pFirst_[nPoints] = pFirst_[0]; // close polyline
}
inline SalPolyLine::~SalPolyLine()
{ if( pFirst_ != Points_ ) delete [] pFirst_; }
#undef STATIC_POINTS
// -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
X11SalGraphics::X11SalGraphics()
{
m_pFrame = NULL;
m_pVDev = NULL;
m_pDeleteColormap = NULL;
hDrawable_ = None;
m_aRenderPicture = 0;
m_pRenderFormat = NULL;
mpClipRegion = NULL;
pPaintRegion_ = NULL;
pPenGC_ = NULL;
nPenPixel_ = 0;
nPenColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
pFontGC_ = NULL;
for( int i = 0; i < MAX_FALLBACK; ++i )
mpServerFont[i] = NULL;
nTextPixel_ = 0;
nTextColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
#ifdef ENABLE_GRAPHITE
// check if graphite fonts have been disabled
static const char* pDisableGraphiteStr = getenv( "SAL_DISABLE_GRAPHITE" );
bDisableGraphite_ = pDisableGraphiteStr ? (pDisableGraphiteStr[0]!='0') : sal_False;
#endif
pBrushGC_ = NULL;
nBrushPixel_ = 0;
nBrushColor_ = MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ); // White
hBrush_ = None;
pMonoGC_ = NULL;
pCopyGC_ = NULL;
pMaskGC_ = NULL;
pInvertGC_ = NULL;
pInvert50GC_ = NULL;
pStippleGC_ = NULL;
pTrackingGC_ = NULL;
bWindow_ = sal_False;
bPrinter_ = sal_False;
bVirDev_ = sal_False;
bPenGC_ = sal_False;
bFontGC_ = sal_False;
bBrushGC_ = sal_False;
bMonoGC_ = sal_False;
bCopyGC_ = sal_False;
bInvertGC_ = sal_False;
bInvert50GC_ = sal_False;
bStippleGC_ = sal_False;
bTrackingGC_ = sal_False;
bXORMode_ = sal_False;
bDitherBrush_ = sal_False;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
X11SalGraphics::~X11SalGraphics()
{
ReleaseFonts();
freeResources();
}
// -=-= SalGraphics / X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::freeResources()
{
Display *pDisplay = GetXDisplay();
DBG_ASSERT( !pPaintRegion_, "pPaintRegion_" );
if( mpClipRegion ) XDestroyRegion( mpClipRegion ), mpClipRegion = None;
if( hBrush_ ) XFreePixmap( pDisplay, hBrush_ ), hBrush_ = None;
if( pPenGC_ ) XFreeGC( pDisplay, pPenGC_ ), pPenGC_ = None;
if( pFontGC_ ) XFreeGC( pDisplay, pFontGC_ ), pFontGC_ = None;
if( pBrushGC_ ) XFreeGC( pDisplay, pBrushGC_ ), pBrushGC_ = None;
if( pMonoGC_ ) XFreeGC( pDisplay, pMonoGC_ ), pMonoGC_ = None;
if( pCopyGC_ ) XFreeGC( pDisplay, pCopyGC_ ), pCopyGC_ = None;
if( pMaskGC_ ) XFreeGC( pDisplay, pMaskGC_ ), pMaskGC_ = None;
if( pInvertGC_ ) XFreeGC( pDisplay, pInvertGC_ ), pInvertGC_ = None;
if( pInvert50GC_ ) XFreeGC( pDisplay, pInvert50GC_ ), pInvert50GC_ = None;
if( pStippleGC_ ) XFreeGC( pDisplay, pStippleGC_ ), pStippleGC_ = None;
if( pTrackingGC_ ) XFreeGC( pDisplay, pTrackingGC_ ), pTrackingGC_ = None;
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;
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;
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_ = sal_True;
m_pFrame = pFrame;
m_pVDev = NULL;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::DeInit()
{
SetDrawable( None, m_nScreen );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::SetClipRegion( GC pGC, XLIB_Region pXReg ) const
{
Display *pDisplay = GetXDisplay();
int n = 0;
XLIB_Region Regions[3];
if( mpClipRegion /* && !XEmptyRegion( mpClipRegion ) */ )
Regions[n++] = mpClipRegion;
// if( pPaintRegion_ /* && !XEmptyRegion( pPaintRegion_ ) */ )
// Regions[n++] = pPaintRegion_;
if( pXReg && !XEmptyRegion( pXReg ) )
Regions[n++] = pXReg;
if( 0 == n )
XSetClipMask( pDisplay, pGC, None );
else if( 1 == n )
XSetRegion( pDisplay, pGC, Regions[0] );
else
{
XLIB_Region pTmpRegion = XCreateRegion();
XIntersectRegion( Regions[0], Regions[1], pTmpRegion );
// if( 3 == n )
// XIntersectRegion( Regions[2], pTmpRegion, pTmpRegion );
XSetRegion( pDisplay, pGC, pTmpRegion );
XDestroyRegion( pTmpRegion );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
GC X11SalGraphics::SelectPen()
{
Display *pDisplay = GetXDisplay();
if( !pPenGC_ )
{
XGCValues values;
values.subwindow_mode = ClipByChildren;
values.fill_rule = EvenOddRule; // Pict import/ Gradient
values.graphics_exposures = False;
pPenGC_ = XCreateGC( pDisplay, hDrawable_,
GCSubwindowMode | GCFillRule | GCGraphicsExposures,
&values );
}
if( !bPenGC_ )
{
if( nPenColor_ != SALCOLOR_NONE )
XSetForeground( pDisplay, pPenGC_, nPenPixel_ );
XSetFunction ( pDisplay, pPenGC_, bXORMode_ ? GXxor : GXcopy );
SetClipRegion( pPenGC_ );
bPenGC_ = sal_True;
}
return pPenGC_;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
GC X11SalGraphics::SelectBrush()
{
Display *pDisplay = GetXDisplay();
DBG_ASSERT( nBrushColor_ != SALCOLOR_NONE, "Brush Transparent" );
if( !pBrushGC_ )
{
XGCValues values;
// values.subwindow_mode = IncludeInferiors;
values.subwindow_mode = ClipByChildren;
values.fill_rule = EvenOddRule; // Pict import/ Gradient
values.graphics_exposures = False;
pBrushGC_ = XCreateGC( pDisplay, hDrawable_,
GCSubwindowMode | GCFillRule | GCGraphicsExposures,
&values );
}
if( !bBrushGC_ )
{
if( !bDitherBrush_ )
{
XSetFillStyle ( pDisplay, pBrushGC_, FillSolid );
XSetForeground( pDisplay, pBrushGC_, nBrushPixel_ );
if( bPrinter_ )
XSetTile( pDisplay, pBrushGC_, None );
}
else
{
// Bug in Sun Solaris 2.5.1, XFillPolygon doesn't allways reflect
// changes of the tile. PROPERTY_BUG_Tile doesn't fix this !
if (GetDisplay()->GetProperties() & PROPERTY_BUG_FillPolygon_Tile)
XSetFillStyle ( pDisplay, pBrushGC_, FillSolid );
XSetFillStyle ( pDisplay, pBrushGC_, FillTiled );
XSetTile ( pDisplay, pBrushGC_, hBrush_ );
}
XSetFunction ( pDisplay, pBrushGC_, bXORMode_ ? GXxor : GXcopy );
SetClipRegion( pBrushGC_ );
bBrushGC_ = sal_True;
}
return pBrushGC_;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
GC X11SalGraphics::GetTrackingGC()
{
const char dash_list[2] = {2, 2};
if( !pTrackingGC_ )
{
XGCValues values;
values.graphics_exposures = False;
values.foreground = m_pColormap->GetBlackPixel()
^ m_pColormap->GetWhitePixel();
values.function = GXxor;
values.line_width = 1;
values.line_style = LineOnOffDash;
pTrackingGC_ = XCreateGC( GetXDisplay(), GetDrawable(),
GCGraphicsExposures | GCForeground | GCFunction
| GCLineWidth | GCLineStyle,
&values );
XSetDashes( GetXDisplay(), pTrackingGC_, 0, dash_list, 2 );
}
if( !bTrackingGC_ )
{
SetClipRegion( pTrackingGC_ );
bTrackingGC_ = sal_True;
}
return pTrackingGC_;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::DrawLines( sal_uLong nPoints,
const SalPolyLine &rPoints,
GC pGC,
bool bClose
)
{
// errechne wie viele Linien XWindow auf einmal zeichnen kann
sal_uLong nMaxLines = (GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq))
/ sizeof(xPoint);
if( nMaxLines > nPoints ) nMaxLines = nPoints;
// gebe alle Linien aus, die XWindows zeichnen kann.
sal_uLong n;
for( n = 0; nPoints - n > nMaxLines; n += nMaxLines - 1 )
XDrawLines( GetXDisplay(),
GetDrawable(),
pGC,
&rPoints[n],
nMaxLines,
CoordModeOrigin );
if( n < nPoints )
XDrawLines( GetXDisplay(),
GetDrawable(),
pGC,
&rPoints[n],
nPoints - n,
CoordModeOrigin );
if( bClose )
{
if( rPoints[nPoints-1].x != rPoints[0].x || rPoints[nPoints-1].y != rPoints[0].y )
drawLine( rPoints[nPoints-1].x, rPoints[nPoints-1].y, rPoints[0].x, rPoints[0].y );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Dithern: Calculate a dither-pixmap and make a brush of it
#define P_DELTA 51
#define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA))
BOOL X11SalGraphics::GetDitherPixmap( SalColor nSalColor )
{
static const short nOrdDither8Bit[ 8 ][ 8 ] =
{
{ 0, 38, 9, 48, 2, 40, 12, 50},
{25, 12, 35, 22, 28, 15, 37, 24},
{ 6, 44, 3, 41, 8, 47, 5, 44},
{32, 19, 28, 16, 34, 21, 31, 18},
{ 1, 40, 11, 49, 0, 39, 10, 48},
{27, 14, 36, 24, 26, 13, 36, 23},
{ 8, 46, 4, 43, 7, 45, 4, 42},
{33, 20, 30, 17, 32, 20, 29, 16}
};
// test for correct depth (8bit)
if( GetColormap().GetVisual().GetDepth() != 8 )
return sal_False;
char pBits[64];
char *pBitsPtr = pBits;
// Set the pallette-entries for the dithering tile
sal_uInt8 nSalColorRed = SALCOLOR_RED ( nSalColor );
sal_uInt8 nSalColorGreen = SALCOLOR_GREEN ( nSalColor );
sal_uInt8 nSalColorBlue = SALCOLOR_BLUE ( nSalColor );
for( int nY = 0; nY < 8; nY++ )
{
for( int nX = 0; nX < 8; nX++ )
{
short nMagic = nOrdDither8Bit[nY][nX];
sal_uInt8 nR = P_DELTA * DMAP( nSalColorRed, nMagic );
sal_uInt8 nG = P_DELTA * DMAP( nSalColorGreen, nMagic );
sal_uInt8 nB = P_DELTA * DMAP( nSalColorBlue, nMagic );
*pBitsPtr++ = GetColormap().GetPixel( MAKE_SALCOLOR( nR, nG, nB ) );
}
}
// create the tile as ximage and an according pixmap -> caching
XImage *pImage = XCreateImage( GetXDisplay(),
GetColormap().GetXVisual(),
8,
ZPixmap,
0, // offset
pBits, // data
8, 8, // width & height
8, // bitmap_pad
0 ); // (default) bytes_per_line
if ( GetDisplay()->GetProperties() & PROPERTY_BUG_Tile )
{
if (hBrush_)
XFreePixmap (GetXDisplay(), hBrush_);
hBrush_ = XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
}
else
if( !hBrush_ )
hBrush_ = XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
// put the ximage to the pixmap
XPutImage( GetXDisplay(),
hBrush_,
GetDisplay()->GetCopyGC( m_nScreen ),
pImage,
0, 0, // Source
0, 0, // Destination
8, 8 ); // width & height
// destroy image-frame but not palette-data
pImage->data = NULL;
XDestroyImage( pImage );
return sal_True;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) // const
{
const SalDisplay *pDisplay = GetDisplay();
rDPIX = pDisplay->GetResolution().A();
rDPIY = pDisplay->GetResolution().B();
if( !pDisplay->GetExactResolution() && rDPIY < 96 )
{
rDPIX = Divide( rDPIX * 96, rDPIY );
rDPIY = 96;
}
else if ( rDPIY > 200 )
{
rDPIX = Divide( rDPIX * 200, rDPIY );
rDPIY = 200;
}
// #i12705# equalize x- and y-resolution if they are close enough
if( rDPIX != rDPIY )
{
// different x- and y- resolutions are usually artifacts of
// a wrongly calculated screen size.
//if( (13*rDPIX >= 10*rDPIY) && (13*rDPIY >= 10*rDPIX) ) //+-30%
{
#ifdef DEBUG
printf("Forcing Resolution from %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 " to %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 "\n",
rDPIX,rDPIY,rDPIY,rDPIY);
#endif
rDPIX = rDPIY; // y-resolution is more trustworthy
}
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sal_uInt16 X11SalGraphics::GetBitCount() // const
{
return GetVisual().GetDepth();
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalGraphics::GetGraphicsWidth() const
{
if( m_pFrame )
return m_pFrame->maGeometry.nWidth;
else if( m_pVDev )
return m_pVDev->GetWidth();
else
return 0;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long X11SalGraphics::GetGraphicsHeight() const
{
if( m_pFrame )
return m_pFrame->maGeometry.nHeight;
else if( m_pVDev )
return m_pVDev->GetHeight();
else
return 0;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::ResetClipRegion()
{
if( mpClipRegion )
{
bPenGC_ = sal_False;
bFontGC_ = sal_False;
bBrushGC_ = sal_False;
bMonoGC_ = sal_False;
bCopyGC_ = sal_False;
bInvertGC_ = sal_False;
bInvert50GC_ = sal_False;
bStippleGC_ = sal_False;
bTrackingGC_ = sal_False;
XDestroyRegion( mpClipRegion );
mpClipRegion = NULL;
}
}
bool X11SalGraphics::setClipRegion( const Region& i_rClip )
{
if( mpClipRegion )
XDestroyRegion( mpClipRegion );
mpClipRegion = XCreateRegion();
RectangleVector aRectangles;
i_rClip.GetRegionRectangles(aRectangles);
for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
{
const long nW(aRectIter->GetWidth());
if(nW)
{
const long nH(aRectIter->GetHeight());
if(nH)
{
XRectangle aRect;
aRect.x = (short)aRectIter->Left();
aRect.y = (short)aRectIter->Top();
aRect.width = (unsigned short)nW;
aRect.height = (unsigned short)nH;
XUnionRectWithRegion(&aRect, mpClipRegion, mpClipRegion);
}
}
}
//ImplRegionInfo aInfo;
//long nX, nY, nW, nH;
//bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
//while( bRegionRect )
//{
// if ( nW && nH )
// {
// XRectangle aRect;
// aRect.x = (short)nX;
// aRect.y = (short)nY;
// aRect.width = (unsigned short)nW;
// aRect.height = (unsigned short)nH;
//
// XUnionRectWithRegion( &aRect, mpClipRegion, mpClipRegion );
// }
// bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
//}
// done, invalidate GCs
bPenGC_ = sal_False;
bFontGC_ = sal_False;
bBrushGC_ = sal_False;
bMonoGC_ = sal_False;
bCopyGC_ = sal_False;
bInvertGC_ = sal_False;
bInvert50GC_ = sal_False;
bStippleGC_ = sal_False;
bTrackingGC_ = sal_False;
if( XEmptyRegion( mpClipRegion ) )
{
XDestroyRegion( mpClipRegion );
mpClipRegion= NULL;
}
return true;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::SetLineColor()
{
if( nPenColor_ != SALCOLOR_NONE )
{
nPenColor_ = SALCOLOR_NONE;
bPenGC_ = sal_False;
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::SetLineColor( SalColor nSalColor )
{
if( nPenColor_ != nSalColor )
{
nPenColor_ = nSalColor;
nPenPixel_ = GetPixel( nSalColor );
bPenGC_ = sal_False;
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::SetFillColor()
{
if( nBrushColor_ != SALCOLOR_NONE )
{
bDitherBrush_ = sal_False;
nBrushColor_ = SALCOLOR_NONE;
bBrushGC_ = sal_False;
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::SetFillColor( SalColor nSalColor )
{
if( nBrushColor_ != nSalColor )
{
bDitherBrush_ = sal_False;
nBrushColor_ = nSalColor;
nBrushPixel_ = GetPixel( nSalColor );
if( TrueColor != GetColormap().GetVisual().GetClass()
&& GetColormap().GetColor( nBrushPixel_ ) != nBrushColor_
&& nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x00 ) // black
&& nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x80 ) // blue
&& nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x00 ) // green
&& nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x80 ) // cyan
&& nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x00 ) // red
&& nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x80 ) // magenta
&& nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x00 ) // brown
&& nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x80 ) // gray
&& nSalColor != MAKE_SALCOLOR( 0xC0, 0xC0, 0xC0 ) // light gray
&& nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0xFF ) // light blue
&& nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0x00 ) // light green
&& nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0xFF ) // light cyan
&& nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0x00 ) // light red
&& nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0xFF ) // light magenta
&& nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0x00 ) // light brown
&& nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) )
bDitherBrush_ = GetDitherPixmap(nSalColor);
bBrushGC_ = sal_False;
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor )
{
switch( nROPColor )
{
case SAL_ROP_0 : // 0
nPenPixel_ = (Pixel)0;
break;
case SAL_ROP_1 : // 1
nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
break;
case SAL_ROP_INVERT : // 2
nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
break;
}
nPenColor_ = GetColormap().GetColor( nPenPixel_ );
bPenGC_ = sal_False;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor )
{
switch( nROPColor )
{
case SAL_ROP_0 : // 0
nBrushPixel_ = (Pixel)0;
break;
case SAL_ROP_1 : // 1
nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
break;
case SAL_ROP_INVERT : // 2
nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
break;
}
bDitherBrush_ = sal_False;
nBrushColor_ = GetColormap().GetColor( nBrushPixel_ );
bBrushGC_ = sal_False;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::SetXORMode( bool bSet, bool )
{
if( !bXORMode_ == bSet )
{
bXORMode_ = bSet;
bPenGC_ = sal_False;
bFontGC_ = sal_False;
bBrushGC_ = sal_False;
bMonoGC_ = sal_False;
bCopyGC_ = sal_False;
bInvertGC_ = sal_False;
bInvert50GC_ = sal_False;
bStippleGC_ = sal_False;
bTrackingGC_ = sal_False;
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawPixel( long nX, long nY )
{
if( nPenColor_ != SALCOLOR_NONE )
XDrawPoint( GetXDisplay(), GetDrawable(), SelectPen(), nX, nY );
}
void X11SalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
{
if( nSalColor != SALCOLOR_NONE )
{
Display *pDisplay = GetXDisplay();
if( (nPenColor_ == SALCOLOR_NONE) && !bPenGC_ )
{
SetLineColor( nSalColor );
XDrawPoint( pDisplay, GetDrawable(), SelectPen(), nX, nY );
nPenColor_ = SALCOLOR_NONE;
bPenGC_ = False;
}
else
{
GC pGC = SelectPen();
if( nSalColor != nPenColor_ )
XSetForeground( pDisplay, pGC, GetPixel( nSalColor ) );
XDrawPoint( pDisplay, GetDrawable(), pGC, nX, nY );
if( nSalColor != nPenColor_ )
XSetForeground( pDisplay, pGC, nPenPixel_ );
}
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
{
if( nPenColor_ != SALCOLOR_NONE )
{
if ( GetDisplay()->GetProperties() & PROPERTY_BUG_DrawLine )
{
GC aGC = SelectPen();
XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX1, (int)nY1);
XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX2, (int)nY2);
XDrawLine (GetXDisplay(), GetDrawable(), aGC, nX1, nY1, nX2, nY2 );
}
else
XDrawLine( GetXDisplay(), GetDrawable(),SelectPen(),
nX1, nY1, nX2, nY2 );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawRect( long nX, long nY, long nDX, long nDY )
{
if( nBrushColor_ != SALCOLOR_NONE )
{
XFillRectangle( GetXDisplay(),
GetDrawable(),
SelectBrush(),
nX, nY, nDX, nDY );
}
// Beschreibung DrawRect verkehrt, deshalb -1
if( nPenColor_ != SALCOLOR_NONE )
XDrawRectangle( GetXDisplay(),
GetDrawable(),
SelectPen(),
nX, nY, nDX-1, nDY-1 );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry )
{
drawPolyLine( nPoints, pPtAry, false );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry, bool bClose )
{
if( nPenColor_ != SALCOLOR_NONE)
{
SalPolyLine Points( nPoints, pPtAry );
DrawLines( nPoints, Points, SelectPen(), bClose );
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
{
if( nPoints == 0 )
return;
if( nPoints < 3 )
{
if( !bXORMode_ )
{
if( 1 == nPoints )
drawPixel( pPtAry[0].mnX, pPtAry[0].mnY );
else
drawLine( pPtAry[0].mnX, pPtAry[0].mnY,
pPtAry[1].mnX, pPtAry[1].mnY );
}
return;
}
SalPolyLine Points( nPoints, pPtAry );
nPoints++;
/* WORKAROUND: some Xservers (Xorg, VIA chipset in this case)
* do not draw the visible part of a polygon
* if it overlaps to the left of screen 0,y.
* This happens to be the case in the gradient drawn in the
* menubar background. workaround for the special case of
* of a rectangle overlapping to the left.
*/
if( nPoints == 5 &&
Points[ 0 ].x == Points[ 1 ].x &&
Points[ 1 ].y == Points[ 2 ].y &&
Points[ 2 ].x == Points[ 3 ].x &&
Points[ 0 ].x == Points[ 4 ].x && Points[ 0 ].y == Points[ 4 ].y
)
{
bool bLeft = false;
bool bRight = false;
for(unsigned int i = 0; i < nPoints; i++ )
{
if( Points[i].x < 0 )
bLeft = true;
else
bRight= true;
}
if( bLeft && ! bRight )
return;
if( bLeft && bRight )
{
for( unsigned int i = 0; i < nPoints; i++ )
if( Points[i].x < 0 )
Points[i].x = 0;
}
}
if( nBrushColor_ != SALCOLOR_NONE )
XFillPolygon( GetXDisplay(),
GetDrawable(),
SelectBrush(),
&Points[0], nPoints,
Complex, CoordModeOrigin );
if( nPenColor_ != SALCOLOR_NONE)
DrawLines( nPoints, Points, SelectPen(), true );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
const sal_uInt32 *pPoints,
PCONSTSALPOINT *pPtAry )
{
if( nBrushColor_ != SALCOLOR_NONE )
{
sal_uInt32 i, n;
XLIB_Region pXRegA = NULL;
for( i = 0; i < nPoly; i++ ) {
n = pPoints[i];
SalPolyLine Points( n, pPtAry[i] );
if( n > 2 )
{
XLIB_Region pXRegB = XPolygonRegion( &Points[0], n+1, WindingRule );
if( !pXRegA )
pXRegA = pXRegB;
else
{
XXorRegion( pXRegA, pXRegB, pXRegA );
XDestroyRegion( pXRegB );
}
}
}
if( pXRegA )
{
XRectangle aXRect;
XClipBox( pXRegA, &aXRect );
GC pGC = SelectBrush();
SetClipRegion( pGC, pXRegA ); // ??? doppelt
XDestroyRegion( pXRegA );
bBrushGC_ = sal_False;
XFillRectangle( GetXDisplay(),
GetDrawable(),
pGC,
aXRect.x, aXRect.y, aXRect.width, aXRect.height );
}
}
if( nPenColor_ != SALCOLOR_NONE )
for( sal_uInt32 i = 0; i < nPoly; i++ )
drawPolyLine( pPoints[i], pPtAry[i], true );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sal_Bool X11SalGraphics::drawPolyLineBezier( sal_uInt32, const SalPoint*, const BYTE* )
{
return sal_False;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sal_Bool X11SalGraphics::drawPolygonBezier( sal_uInt32, const SalPoint*, const BYTE* )
{
return sal_False;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sal_Bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*,
const SalPoint* const*, const BYTE* const* )
{
return sal_False;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::invert( sal_uInt32 nPoints,
const SalPoint* pPtAry,
SalInvert nFlags )
{
SalPolyLine Points ( nPoints, pPtAry );
GC pGC;
if( SAL_INVERT_50 & nFlags )
pGC = GetInvert50GC();
else
if ( SAL_INVERT_TRACKFRAME & nFlags )
pGC = GetTrackingGC();
else
pGC = GetInvertGC();
if( SAL_INVERT_TRACKFRAME & nFlags )
DrawLines ( nPoints, Points, pGC, true );
else
XFillPolygon( GetXDisplay(),
GetDrawable(),
pGC,
&Points[0], nPoints,
Complex, CoordModeOrigin );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
BOOL X11SalGraphics::drawEPS( long,long,long,long,void*,sal_uLong )
{
return sal_False;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
XID X11SalGraphics::GetXRenderPicture()
{
XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
if( !m_aRenderPicture )
{
// check xrender support for matching visual
// find a XRenderPictFormat compatible with the Drawable
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( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
rRenderPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
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;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
SystemGraphicsData X11SalGraphics::GetGraphicsData() const
{
SystemGraphicsData aRes;
aRes.nSize = sizeof(aRes);
aRes.pDisplay = GetXDisplay();
aRes.hDrawable = hDrawable_;
aRes.pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
aRes.nScreen = m_nScreen;
aRes.nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
aRes.aColormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap();
aRes.pRenderFormat = m_pRenderFormat;
return aRes;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// draw a poly-polygon
bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency )
{
// nothing to do for empty polypolygons
const int nOrigPolyCount = rOrigPolyPoly.count();
if( nOrigPolyCount <= 0 )
return sal_True;
// nothing to do if everything is transparent
if( (nBrushColor_ == SALCOLOR_NONE)
&& (nPenColor_ == SALCOLOR_NONE) )
return sal_True;
// cannot handle pencolor!=brushcolor yet
if( (nPenColor_ != SALCOLOR_NONE)
&& (nPenColor_ != nBrushColor_) )
return sal_False;
// TODO: remove the env-variable when no longer needed
static const char* pRenderEnv = getenv( "SAL_DISABLE_RENDER_POLY" );
if( pRenderEnv )
return sal_False;
// snap to raster if requested
basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly;
const bool bSnapToRaster = !getAntiAliasB2DDraw();
if( bSnapToRaster )
aPolyPoly = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly );
// don't bother with polygons outside of visible area
const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() );
aPolyPoly = basegfx::tools::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false );
if( !aPolyPoly.count() )
return true;
// tesselate the polypolygon into trapezoids
basegfx::B2DTrapezoidVector aB2DTrapVector;
basegfx::tools::trapezoidSubdivide( aB2DTrapVector, aPolyPoly );
const int nTrapCount = aB2DTrapVector.size();
if( !nTrapCount )
return true;
const bool bDrawn = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency );
return bDrawn;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool X11SalGraphics::drawFilledTrapezoids( const ::basegfx::B2DTrapezoid* pB2DTraps, int nTrapCount, double fTransparency )
{
if( nTrapCount <= 0 )
return true;
Picture aDstPic = GetXRenderPicture();
// check xrender support for this drawable
if( !aDstPic )
return false;
// convert the B2DTrapezoids into XRender-Trapezoids
typedef std::vector<XTrapezoid> TrapezoidVector;
TrapezoidVector aTrapVector( nTrapCount );
const basegfx::B2DTrapezoid* pB2DTrap = pB2DTraps;
for( int i = 0; i < nTrapCount; ++pB2DTrap, ++i )
{
XTrapezoid& rTrap = aTrapVector[ i ] ;
// set y-coordinates
const double fY1 = pB2DTrap->getTopY();
rTrap.left.p1.y = rTrap.right.p1.y = rTrap.top = XDoubleToFixed( fY1 );
const double fY2 = pB2DTrap->getBottomY();
rTrap.left.p2.y = rTrap.right.p2.y = rTrap.bottom = XDoubleToFixed( fY2 );
// set x-coordinates
const double fXL1 = pB2DTrap->getTopXLeft();
rTrap.left.p1.x = XDoubleToFixed( fXL1 );
const double fXR1 = pB2DTrap->getTopXRight();
rTrap.right.p1.x = XDoubleToFixed( fXR1 );
const double fXL2 = pB2DTrap->getBottomXLeft();
rTrap.left.p2.x = XDoubleToFixed( fXL2 );
const double fXR2 = pB2DTrap->getBottomXRight();
rTrap.right.p2.x = XDoubleToFixed( fXR2 );
}
// get xrender Picture for polygon foreground
// TODO: cache it like the target picture which uses GetXRenderPicture()
XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ 32 ];
if( !rEntry.m_aPicture )
{
Display* pXDisplay = GetXDisplay();
rEntry.m_aPixmap = ::XCreatePixmap( pXDisplay, hDrawable_, 1, 1, 32 );
XRenderPictureAttributes aAttr;
aAttr.repeat = true;
XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 );
rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr );
}
// set polygon foreground color and opacity
XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency );
rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
// set clipping
// TODO: move into GetXRenderPicture?
if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
rRenderPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
// render the trapezoids
const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8();
rRenderPeer.CompositeTrapezoids( PictOpOver,
rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() );
return true;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool X11SalGraphics::drawPolyLine(
const ::basegfx::B2DPolygon& rPolygon,
double fTransparency,
const ::basegfx::B2DVector& rLineWidth,
basegfx::B2DLineJoin eLineJoin,
com::sun::star::drawing::LineCap eLineCap)
{
const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
// #i101491#
if( !bIsHairline && (rPolygon.count() > 1000) )
{
// the used basegfx::tools::createAreaGeometry is simply too
// expensive with very big polygons; fallback to caller (who
// should use ImplLineConverter normally)
// AW: ImplLineConverter had to be removed since it does not even
// know LineJoins, so the fallback will now prepare the line geometry
// the same way.
return false;
}
// temporarily adjust brush color to pen color
// since the line is drawn as an area-polygon
const SalColor aKeepBrushColor = nBrushColor_;
nBrushColor_ = nPenColor_;
// #i11575#desc5#b adjust B2D tesselation result to raster positions
basegfx::B2DPolygon aPolygon = rPolygon;
const double fHalfWidth = 0.5 * rLineWidth.getX();
// #122456# This is probably thought to happen to align hairlines to pixel positions, so
// it should be a 0.5 translation, not more. It will definitely go wrong with fat lines
aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(0.5, 0.5) );
// shortcut for hairline drawing to improve performance
bool bDrawnOk = true;
if( bIsHairline )
{
// hairlines can benefit from a simplified tesselation
// e.g. for hairlines the linejoin style can be ignored
basegfx::B2DTrapezoidVector aB2DTrapVector;
basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() );
// draw tesselation result
const int nTrapCount = aB2DTrapVector.size();
if( nTrapCount > 0 )
bDrawnOk = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency );
// restore the original brush GC
nBrushColor_ = aKeepBrushColor;
return bDrawnOk;
}
// get the area polygon for the line polygon
if( (rLineWidth.getX() != rLineWidth.getY())
&& !basegfx::fTools::equalZero( rLineWidth.getY() ) )
{
// prepare for createAreaGeometry() with anisotropic linewidth
aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY()));
}
// create the area-polygon for the line
const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap) );
if( (rLineWidth.getX() != rLineWidth.getY())
&& !basegfx::fTools::equalZero( rLineWidth.getX() ) )
{
// postprocess createAreaGeometry() for anisotropic linewidth
aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX()));
}
// draw each area polypolygon component individually
// to emulate the polypolygon winding rule "non-zero"
const int nPolyCount = aAreaPolyPoly.count();
for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
{
const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) );
bDrawnOk = drawPolyPolygon( aOnePoly, fTransparency );
if( !bDrawnOk )
break;
}
// restore the original brush GC
nBrushColor_ = aKeepBrushColor;
return bDrawnOk;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=