summaryrefslogtreecommitdiff
path: root/vcl/unx/generic/gdi
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/generic/gdi')
-rw-r--r--vcl/unx/generic/gdi/cdeint.cxx244
-rw-r--r--vcl/unx/generic/gdi/dtint.cxx139
-rw-r--r--vcl/unx/generic/gdi/dtsetenum.hxx146
-rw-r--r--vcl/unx/generic/gdi/gcach_xpeer.cxx683
-rw-r--r--vcl/unx/generic/gdi/gcach_xpeer.hxx92
-rw-r--r--vcl/unx/generic/gdi/pspgraphics.cxx1504
-rw-r--r--vcl/unx/generic/gdi/salbmp.cxx1096
-rw-r--r--vcl/unx/generic/gdi/salcvt.cxx341
-rw-r--r--vcl/unx/generic/gdi/salcvt.hxx93
-rw-r--r--vcl/unx/generic/gdi/salgdi.cxx1273
-rw-r--r--vcl/unx/generic/gdi/salgdi2.cxx1151
-rw-r--r--vcl/unx/generic/gdi/salgdi3.cxx1690
-rw-r--r--vcl/unx/generic/gdi/salprnpsp.cxx1462
-rw-r--r--vcl/unx/generic/gdi/salvd.cxx274
-rw-r--r--vcl/unx/generic/gdi/xrender_peer.cxx247
-rw-r--r--vcl/unx/generic/gdi/xrender_peer.hxx387
16 files changed, 10822 insertions, 0 deletions
diff --git a/vcl/unx/generic/gdi/cdeint.cxx b/vcl/unx/generic/gdi/cdeint.cxx
new file mode 100644
index 000000000000..af635f38e9bc
--- /dev/null
+++ b/vcl/unx/generic/gdi/cdeint.cxx
@@ -0,0 +1,244 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+
+#include <vcl/settings.hxx>
+
+#include <unx/salunx.h>
+#include <unx/saldisp.hxx>
+#include <unx/cdeint.hxx>
+
+CDEIntegrator::CDEIntegrator()
+{
+ meType = DtCDE;
+}
+
+CDEIntegrator::~CDEIntegrator()
+{
+}
+
+static int getHexDigit( const char c )
+{
+ if( c >= '0' && c <= '9' )
+ return (int)(c-'0');
+ else if( c >= 'a' && c <= 'f' )
+ return (int)(c-'a'+10);
+ else if( c >= 'A' && c <= 'F' )
+ return (int)(c-'A'+10);
+ return -1;
+}
+
+
+void CDEIntegrator::GetSystemLook( AllSettings& rSettings )
+{
+ static Color aColors[ 8 ];
+ static sal_Bool bRead = sal_False;
+ static sal_Bool bValid = sal_False;
+
+ if( ! bRead )
+ {
+ // get used palette from xrdb
+ char **ppStringList = 0;
+ int nStringCount;
+ XTextProperty aTextProperty;
+ aTextProperty.value = 0;
+ int i;
+
+ static Atom nResMgrAtom = XInternAtom( mpDisplay, "RESOURCE_MANAGER", False );
+
+ if( XGetTextProperty( mpDisplay,
+ RootWindow( mpDisplay, 0 ),
+ &aTextProperty,
+ nResMgrAtom )
+ && aTextProperty.value
+ && XTextPropertyToStringList( &aTextProperty, &ppStringList, &nStringCount )
+ )
+ {
+ // format of ColorPalette resource:
+ // *n*ColorPalette: palettefile
+
+ ByteString aLines;
+ for( i=0; i < nStringCount; i++ )
+ aLines += ppStringList[i];
+ for( i = aLines.GetTokenCount( '\n' )-1; i >= 0; i-- )
+ {
+ ByteString aLine = aLines.GetToken( i, '\n' );
+ int nIndex = aLine.Search( "ColorPalette" );
+ if( nIndex != STRING_NOTFOUND )
+ {
+ int nPos = nIndex;
+
+ nIndex+=12;
+ const char* pStr = aLine.GetBuffer() +nIndex;
+ while( *pStr && isspace( *pStr ) && *pStr != ':' )
+ {
+ pStr++;
+ nIndex++;
+ }
+ if( *pStr != ':' )
+ continue;
+ pStr++, nIndex++;
+ for( ; *pStr && isspace( *pStr ); pStr++, nIndex++ )
+ ;
+ if( ! *pStr )
+ continue;
+ int nIndex2 = nIndex;
+ for( ; *pStr && ! isspace( *pStr ); pStr++, nIndex2++ )
+ ;
+ ByteString aPaletteFile( aLine.Copy( nIndex, nIndex2 - nIndex ) );
+ // extract number before ColorPalette;
+ for( ; nPos >= 0 && aLine.GetChar( nPos ) != '*'; nPos-- )
+ ;
+ nPos--;
+ for( ; nPos >= 0 && aLine.GetChar( nPos ) != '*'; nPos-- )
+ ;
+ int nNumber = aLine.Copy( ++nPos ).ToInt32();
+
+ DBG_TRACE2( "found palette %d in resource \"%s\"", nNumber, aLine.GetBuffer() );
+
+ // found no documentation what this number actually means;
+ // might be the screen number. 0 seems to be the right one
+ // in most cases.
+ if( nNumber )
+ continue;
+
+ DBG_TRACE1( "Palette file is \"%s\".\n", aPaletteFile.GetBuffer() );
+
+ String aPath( aHomeDir );
+ aPath.AppendAscii( "/.dt/palettes/" );
+ aPath += String( aPaletteFile, gsl_getSystemTextEncoding() );
+
+ SvFileStream aStream( aPath, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ {
+ aPath = String::CreateFromAscii( "/usr/dt/palettes/" );
+ aPath += String( aPaletteFile, gsl_getSystemTextEncoding() );
+ aStream.Open( aPath, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ continue;
+ }
+
+ ByteString aBuffer;
+ for( nIndex = 0; nIndex < 8; nIndex++ )
+ {
+ aStream.ReadLine( aBuffer );
+ // format is "#RRRRGGGGBBBB"
+
+ DBG_TRACE1( "\t\"%s\".\n", aBuffer.GetBuffer() );
+
+ if( aBuffer.Len() )
+ {
+ const char* pArr = (const char*)aBuffer.GetBuffer()+1;
+ aColors[nIndex] = Color(
+ getHexDigit( pArr[1] )
+ | ( getHexDigit( pArr[0] ) << 4 ),
+ getHexDigit( pArr[5] )
+ | ( getHexDigit( pArr[4] ) << 4 ),
+ getHexDigit( pArr[9] )
+ | ( getHexDigit( pArr[8] ) << 4 )
+ );
+
+ DBG_TRACE1( "\t\t%lx\n", aColors[nIndex].GetColor() );
+ }
+ }
+
+ bValid = sal_True;
+ break;
+ }
+ }
+ }
+
+ if( ppStringList )
+ XFreeStringList( ppStringList );
+ if( aTextProperty.value )
+ XFree( aTextProperty.value );
+ }
+
+
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ // #i48001# set a default blink rate
+ aStyleSettings.SetCursorBlinkTime( 500 );
+ if (bValid)
+ {
+ aStyleSettings.SetActiveColor( aColors[0] );
+ aStyleSettings.SetActiveColor2( aColors[0] );
+ aStyleSettings.SetActiveBorderColor( aColors[0] );
+
+ aStyleSettings.SetDeactiveColor( aColors[0] );
+ aStyleSettings.SetDeactiveColor2( aColors[0] );
+ aStyleSettings.SetDeactiveBorderColor( aColors[0] );
+
+ Color aActive =
+ aColors[ 0 ].GetBlue() < 128 ||
+ aColors[ 0 ].GetGreen() < 128 ||
+ aColors[ 0 ].GetRed() < 128
+ ? Color( COL_WHITE ) : Color( COL_BLACK );
+ Color aDeactive =
+ aColors[ 1 ].GetBlue() < 128 ||
+ aColors[ 1 ].GetGreen() < 128 ||
+ aColors[ 1 ].GetRed() < 128
+ ? Color( COL_WHITE ) : Color( COL_BLACK );
+ aStyleSettings.SetActiveTextColor( aActive );
+ aStyleSettings.SetDeactiveTextColor( aDeactive );
+
+ aStyleSettings.SetDialogTextColor( aDeactive );
+ aStyleSettings.SetMenuTextColor( aDeactive );
+ aStyleSettings.SetMenuBarTextColor( aDeactive );
+ aStyleSettings.SetButtonTextColor( aDeactive );
+ aStyleSettings.SetRadioCheckTextColor( aDeactive );
+ aStyleSettings.SetGroupTextColor( aDeactive );
+ aStyleSettings.SetLabelTextColor( aDeactive );
+ aStyleSettings.SetInfoTextColor( aDeactive );
+
+ aStyleSettings.Set3DColors( aColors[1] );
+ aStyleSettings.SetFaceColor( aColors[1] );
+ aStyleSettings.SetDialogColor( aColors[1] );
+ aStyleSettings.SetMenuColor( aColors[1] );
+ aStyleSettings.SetMenuBarColor( aColors[1] );
+ if ( aStyleSettings.GetFaceColor() == COL_LIGHTGRAY )
+ aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ // calculate Checked color
+ Color aColor2 = aStyleSettings.GetLightColor();
+ sal_uInt8 nRed = (sal_uInt8)(((sal_uInt16)aColors[1].GetRed() + (sal_uInt16)aColor2.GetRed())/2);
+ sal_uInt8 nGreen = (sal_uInt8)(((sal_uInt16)aColors[1].GetGreen() + (sal_uInt16)aColor2.GetGreen())/2);
+ sal_uInt8 nBlue = (sal_uInt8)(((sal_uInt16)aColors[1].GetBlue() + (sal_uInt16)aColor2.GetBlue())/2);
+ aStyleSettings.SetCheckedColor( Color( nRed, nGreen, nBlue ) );
+ }
+ }
+ rSettings.SetStyleSettings( aStyleSettings );
+}
diff --git a/vcl/unx/generic/gdi/dtint.cxx b/vcl/unx/generic/gdi/dtint.cxx
new file mode 100644
index 000000000000..d14389cd0438
--- /dev/null
+++ b/vcl/unx/generic/gdi/dtint.cxx
@@ -0,0 +1,139 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+
+#include "osl/file.h"
+#include "osl/process.h"
+#include "osl/security.h"
+
+#include "vcl/svapp.hxx"
+
+#include "unx/salunx.h"
+#include <X11/Xatom.h>
+#ifdef USE_CDE
+#include "unx/cdeint.hxx"
+#endif
+#include "unx/dtint.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/saldata.hxx"
+#include "unx/wmadaptor.hxx"
+
+#include "dtsetenum.hxx"
+
+#include <set>
+#include <stdio.h>
+
+// NETBSD has no RTLD_GLOBAL
+#ifndef RTLD_GLOBAL
+#define DLOPEN_MODE (RTLD_LAZY)
+#else
+#define DLOPEN_MODE (RTLD_GLOBAL | RTLD_LAZY)
+#endif
+
+
+using namespace rtl;
+using namespace vcl_sal;
+
+String DtIntegrator::aHomeDir;
+
+DtIntegrator::DtIntegrator() :
+ meType( DtGeneric ),
+ mnSystemLookCommandProcess( -1 )
+{
+ mpSalDisplay = GetX11SalData()->GetDisplay();
+ mpDisplay = mpSalDisplay->GetDisplay();
+ OUString aDir;
+ oslSecurity aCur = osl_getCurrentSecurity();
+ if( aCur )
+ {
+ osl_getHomeDir( aCur, &aDir.pData );
+ osl_freeSecurityHandle( aCur );
+ OUString aSysDir;
+ osl_getSystemPathFromFileURL( aDir.pData, &aSysDir.pData );
+ aHomeDir = aSysDir;
+ }
+}
+
+DtIntegrator::~DtIntegrator()
+{
+}
+
+DtIntegrator* DtIntegrator::CreateDtIntegrator()
+{
+ /*
+ * #i22061# override desktop detection
+ * if environment variable OOO_FORCE_DESKTOP is set
+ * to one of "cde" "kde" "gnome" then autodetection
+ * is overridden.
+ */
+ static const char* pOverride = getenv( "OOO_FORCE_DESKTOP" );
+ if( pOverride && *pOverride )
+ {
+ OString aOver( pOverride );
+
+#if USE_CDE
+ if( aOver.equalsIgnoreAsciiCase( "cde" ) )
+ return new CDEIntegrator();
+#endif
+ if( aOver.equalsIgnoreAsciiCase( "none" ) )
+ return new DtIntegrator();
+ }
+
+#ifdef USE_CDE
+ void* pLibrary = NULL;
+
+ // check dt type
+ // CDE
+ SalDisplay* pSalDisplay = GetX11SalData()->GetDisplay();
+ Display* pDisplay = pSalDisplay->GetDisplay();
+ Atom nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True );
+ if( nDtAtom && ( pLibrary = dlopen( "/usr/dt/lib/libDtSvc.so", DLOPEN_MODE ) ) )
+ {
+ dlclose( pLibrary );
+ return new CDEIntegrator();
+ }
+#endif
+
+ // default: generic implementation
+ return new DtIntegrator();
+}
+
+void DtIntegrator::GetSystemLook( AllSettings& rSettings )
+{
+ // #i48001# set a default blink rate
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ aStyleSettings.SetCursorBlinkTime( 500 );
+ rSettings.SetStyleSettings( aStyleSettings );
+}
diff --git a/vcl/unx/generic/gdi/dtsetenum.hxx b/vcl/unx/generic/gdi/dtsetenum.hxx
new file mode 100644
index 000000000000..5406ac870a43
--- /dev/null
+++ b/vcl/unx/generic/gdi/dtsetenum.hxx
@@ -0,0 +1,146 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_DTSETENUM_HXX
+#define _VCL_DTSETENUM_HXX
+
+enum DtSetEnum
+{
+ /* settings for mouse */
+ MouseOptions = 1,
+ DoubleClickTime,
+ DoubleClickWidth,
+ DoubleClickHeight,
+ StartDragWidth,
+ StartDragHeight,
+ DragMoveCode,
+ DragCopyCode,
+ DragLinkCode,
+ ContextMenuCode,
+ ContextMenuClicks,
+ ContextMenuDown,
+ ScrollRepeat,
+ ButtonStartRepeat,
+ ButtonRepeat,
+ ActionDelay,
+ MenuDelay,
+ Follow,
+ MiddleButtonAction,
+ /* settings for keyboard */
+ KeyboardOptions=64,
+ /* style settings */
+ StyleOptions = 128,
+ BorderSize,
+ TitleHeight,
+ FloatTitleHeight,
+ TearOffTitleHeight,
+ MenuBarHeight,
+ ScrollBarSize,
+ SpinSize,
+ SplitSize,
+ IconHorzSpace,
+ IconVertSpace,
+ CursorSize,
+ CursorBlinkTime,
+ ScreenZoom,
+ ScreenFontZoom,
+ LogoDisplayTime,
+ DragFullOptions,
+ AnimationOptions,
+ SelectionOptions,
+ DisplayOptions,
+ AntialiasingMinPixelHeight,
+ /* style colors */
+ AllTextColors, /* convenience, sets all control text colors */
+ AllBackColors, /* convenience, sets all control background colors */
+ ThreeDColor,
+ FaceColor,
+ CheckedColor,
+ LightColor,
+ LightBorderColor,
+ ShadowColor,
+ DarkShadowColor,
+ ButtonTextColor,
+ RadioCheckTextColor,
+ GroupTextColor,
+ LabelTextColor,
+ InfoTextColor,
+ WindowColor,
+ WindowTextColor,
+ DialogColor,
+ DialogTextColor,
+ WorkspaceColor,
+ FieldColor,
+ FieldTextColor,
+ ActiveColor,
+ ActiveColor2,
+ ActiveTextColor,
+ ActiveBorderColor,
+ DeactiveColor,
+ DeactiveColor2,
+ DeactiveTextColor,
+ DeactiveBorderColor,
+ HighlightColor,
+ HighlightTextColor,
+ DisableColor,
+ HelpColor,
+ HelpTextColor,
+ MenuColor,
+ MenuBarColor,
+ MenuTextColor,
+ MenuHighlightColor,
+ MenuHighlightTextColor,
+ LinkColor,
+ VisitedLinkColor,
+ HighlightLinkColor,
+ HighContrastMode,
+ /* style fonts */
+ UIFont, /* convenience, sets all fonts but TitleFont and FloatTitleFont */
+ AppFont,
+ HelpFont,
+ TitleFont,
+ FloatTitleFont,
+ MenuFont,
+ ToolFont,
+ GroupFont,
+ LabelFont,
+ InfoFont,
+ RadioCheckFont,
+ PushButtonFont,
+ FieldFont,
+ IconFont,
+ /* style numeric styles */
+ RadioButtonStyle,
+ CheckBoxStyle,
+ PushButtonStyle,
+ TabControlStyle,
+ /* toolbar style */
+ ToolbarIconSize
+
+};
+
+#endif // _VCL_DTSETENUM_HXX
diff --git a/vcl/unx/generic/gdi/gcach_xpeer.cxx b/vcl/unx/generic/gdi/gcach_xpeer.cxx
new file mode 100644
index 000000000000..3cd828c24065
--- /dev/null
+++ b/vcl/unx/generic/gdi/gcach_xpeer.cxx
@@ -0,0 +1,683 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "rtl/ustring.hxx"
+#include "osl/module.h"
+#include "osl/thread.h"
+
+#include "unx/saldisp.hxx"
+#include "unx/saldata.hxx"
+#include "unx/salgdi.h"
+
+#include "gcach_xpeer.hxx"
+#include "xrender_peer.hxx"
+
+// ===========================================================================
+
+// all glyph specific data needed by the XGlyphPeer is quite trivial
+// with one exception: if multiple screens are involved and non-antialiased
+// glyph rendering is active, then we need screen specific pixmaps
+struct MultiScreenGlyph
+{
+ const RawBitmap* mpRawBitmap;
+ Glyph maXRGlyphId;
+ Pixmap maPixmaps[1]; // [mnMaxScreens]
+};
+
+// ===========================================================================
+
+X11GlyphPeer::X11GlyphPeer()
+: mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() )
+, mnMaxScreens(0)
+, mnDefaultScreen(0)
+, mnExtByteCount(0)
+, mnForcedAA(0)
+, mnUsingXRender(0)
+{
+ maRawBitmap.mnAllocated = 0;
+ maRawBitmap.mpBits = NULL;
+ if( !mpDisplay )
+ return;
+
+ SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay();
+ mpDisplay = rSalDisplay.GetDisplay();
+ mnMaxScreens = rSalDisplay.GetScreenCount();
+ if( mnMaxScreens > MAX_GCACH_SCREENS )
+ mnMaxScreens = MAX_GCACH_SCREENS;
+ // if specific glyph data has to be kept for many screens
+ // then prepare the allocation of MultiScreenGlyph objects
+ if( mnMaxScreens > 1 )
+ mnExtByteCount = sizeof(MultiScreenGlyph) + sizeof(Pixmap) * (mnMaxScreens - 1);
+ mnDefaultScreen = rSalDisplay.GetDefaultScreenNumber();
+
+ InitAntialiasing();
+}
+
+// ---------------------------------------------------------------------------
+
+X11GlyphPeer::~X11GlyphPeer()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* const pX11Disp = pSalDisp->GetDisplay();
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+ for( int i = 0; i < mnMaxScreens; i++ )
+ {
+ SalDisplay::RenderEntryMap& rMap = pSalDisp->GetRenderEntries( i );
+ for( SalDisplay::RenderEntryMap::iterator it = rMap.begin(); it != rMap.end(); ++it )
+ {
+ if( it->second.m_aPixmap )
+ ::XFreePixmap( pX11Disp, it->second.m_aPixmap );
+ if( it->second.m_aPicture )
+ rRenderPeer.FreePicture( it->second.m_aPicture );
+ }
+ rMap.clear();
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::InitAntialiasing()
+{
+ int nEnvAntiAlias = 0;
+ const char* pEnvAntiAlias = getenv( "SAL_ANTIALIAS_DISABLE" );
+ if( pEnvAntiAlias )
+ {
+ nEnvAntiAlias = atoi( pEnvAntiAlias );
+ if( nEnvAntiAlias == 0 )
+ return;
+ }
+
+ mnUsingXRender = 0;
+ mnForcedAA = 0;
+
+ // enable XRENDER accelerated aliasing on screens that support it
+ // unless it explicitly disabled by an environment variable
+ if( (nEnvAntiAlias & 2) == 0 )
+ mnUsingXRender = XRenderPeer::GetInstance().InitRenderText();
+
+ // else enable client side antialiasing for these screens
+ // unless it is explicitly disabled by an environment variable
+ if( (nEnvAntiAlias & 1) != 0 )
+ return;
+
+ // enable client side antialiasing for screen visuals that are suitable
+ // mnForcedAA is a bitmask of screens enabled for client side antialiasing
+ mnForcedAA = (~(~0U << mnMaxScreens)) ^ mnUsingXRender;
+ SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay();
+ for( int nScreen = 0; nScreen < mnMaxScreens; ++nScreen)
+ {
+ Visual* pVisual = rSalDisplay.GetVisual( nScreen ).GetVisual();
+ XVisualInfo aXVisualInfo;
+ aXVisualInfo.visualid = pVisual->visualid;
+ int nVisuals = 0;
+ XVisualInfo* pXVisualInfo = XGetVisualInfo( mpDisplay, VisualIDMask, &aXVisualInfo, &nVisuals );
+ for( int i = nVisuals; --i >= 0; )
+ {
+ if( ((pXVisualInfo[i].c_class==PseudoColor) || (pXVisualInfo[i].depth<24))
+ && ((pXVisualInfo[i].c_class>GrayScale) || (pXVisualInfo[i].depth!=8) ) )
+ mnForcedAA &= ~(1U << nScreen);
+ }
+ if( pXVisualInfo != NULL )
+ XFree( pXVisualInfo );
+ }
+}
+
+// ===========================================================================
+
+enum { INFO_EMPTY=0, INFO_PIXMAP, INFO_XRENDER, INFO_RAWBMP, INFO_MULTISCREEN };
+static const Glyph NO_GLYPHID = 0;
+static RawBitmap* const NO_RAWBMP = NULL;
+static const Pixmap NO_PIXMAP = ~0;
+
+// ---------------------------------------------------------------------------
+
+MultiScreenGlyph* X11GlyphPeer::PrepareForMultiscreen( ExtGlyphData& rEGD ) const
+{
+ // prepare to store screen specific pixmaps
+ MultiScreenGlyph* pMSGlyph = (MultiScreenGlyph*)new char[ mnExtByteCount ];
+
+ // init the glyph formats
+ pMSGlyph->mpRawBitmap = NO_RAWBMP;
+ pMSGlyph->maXRGlyphId = NO_GLYPHID;
+ for( int i = 0; i < mnMaxScreens; ++i )
+ pMSGlyph->maPixmaps[i] = NO_PIXMAP;
+ // reuse already available glyph formats
+ if( rEGD.meInfo == INFO_XRENDER )
+ pMSGlyph->maXRGlyphId = reinterpret_cast<Glyph>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_RAWBMP )
+ pMSGlyph->mpRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_PIXMAP )
+ {
+ Pixmap aPixmap = reinterpret_cast<Pixmap>(rEGD.mpData);
+ if( aPixmap != None )
+ // pixmap for the default screen is available
+ pMSGlyph->maPixmaps[ mnDefaultScreen ] = aPixmap;
+ else // empty pixmap for all screens is available
+ for( int i = 0; i < mnMaxScreens; ++i )
+ pMSGlyph->maPixmaps[ i ] = None;
+ }
+ // enable use of multiscreen glyph
+ rEGD.mpData = (void*)pMSGlyph;
+ rEGD.meInfo = INFO_MULTISCREEN;
+
+ return pMSGlyph;
+ }
+
+// ---------------------------------------------------------------------------
+
+Glyph X11GlyphPeer::GetRenderGlyph( const GlyphData& rGD ) const
+{
+ Glyph aGlyphId = NO_GLYPHID;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( rEGD.meInfo == INFO_XRENDER )
+ aGlyphId = reinterpret_cast<Glyph>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ aGlyphId = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId;
+ return aGlyphId;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetRenderGlyph( GlyphData& rGD, Glyph aGlyphId ) const
+{
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ switch( rEGD.meInfo )
+ {
+ case INFO_EMPTY:
+ rEGD.meInfo = INFO_XRENDER;
+ // fall through
+ case INFO_XRENDER:
+ rEGD.mpData = reinterpret_cast<void*>(aGlyphId);
+ break;
+ case INFO_PIXMAP:
+ case INFO_RAWBMP:
+ PrepareForMultiscreen( rEGD );
+ // fall through
+ case INFO_MULTISCREEN:
+ reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId = aGlyphId;
+ break;
+ default:
+ break; // cannot happen...
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+const RawBitmap* X11GlyphPeer::GetRawBitmap( const GlyphData& rGD ) const
+{
+ const RawBitmap* pRawBitmap = NO_RAWBMP;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( rEGD.meInfo == INFO_RAWBMP )
+ pRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ pRawBitmap = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap;
+ return pRawBitmap;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetRawBitmap( GlyphData& rGD, const RawBitmap* pRawBitmap ) const
+{
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ switch( rEGD.meInfo )
+ {
+ case INFO_EMPTY:
+ rEGD.meInfo = INFO_RAWBMP;
+ // fall through
+ case INFO_RAWBMP:
+ rEGD.mpData = (void*)pRawBitmap;
+ break;
+ case INFO_PIXMAP:
+ case INFO_XRENDER:
+ PrepareForMultiscreen( rEGD );
+ // fall through
+ case INFO_MULTISCREEN:
+ reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap = pRawBitmap;
+ break;
+ default:
+ // cannot happen...
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+Pixmap X11GlyphPeer::GetPixmap( const GlyphData& rGD, int nScreen ) const
+{
+ Pixmap aPixmap = NO_PIXMAP;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( (rEGD.meInfo == INFO_PIXMAP) && (nScreen == mnDefaultScreen) )
+ aPixmap = (Pixmap)rEGD.mpData;
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ aPixmap = (Pixmap)(reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maPixmaps[nScreen]);
+ return aPixmap;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetPixmap( GlyphData& rGD, Pixmap aPixmap, int nScreen ) const
+{
+ if( aPixmap == NO_PIXMAP )
+ aPixmap = None;
+
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( (rEGD.meInfo == INFO_EMPTY) && (nScreen == mnDefaultScreen) )
+ {
+ rEGD.meInfo = INFO_PIXMAP;
+ rEGD.mpData = (void*)aPixmap;
+ }
+ else
+ {
+ MultiScreenGlyph* pMSGlyph;
+ if( rEGD.meInfo == INFO_MULTISCREEN )
+ pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData);
+ else
+ pMSGlyph = PrepareForMultiscreen( rEGD );
+
+ pMSGlyph->maPixmaps[ nScreen ] = aPixmap;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::RemovingFont( ServerFont& rServerFont )
+{
+ void* pFontExt = rServerFont.GetExtPointer();
+ switch( rServerFont.GetExtInfo() )
+ {
+ case INFO_PIXMAP:
+ case INFO_RAWBMP:
+ // nothing to do
+ break;
+ case INFO_MULTISCREEN:
+ // cannot happen...
+ break;
+
+ case INFO_XRENDER:
+ XRenderPeer::GetInstance().FreeGlyphSet( (GlyphSet)pFontExt );
+ break;
+ }
+
+ rServerFont.SetExtended( INFO_EMPTY, NULL );
+}
+
+// ---------------------------------------------------------------------------
+
+// notification to clean up GlyphPeer resources for this glyph
+void X11GlyphPeer::RemovingGlyph( ServerFont& /*rServerFont*/, GlyphData& rGlyphData, int /*nGlyphIndex*/ )
+{
+ // nothing to do if the GlyphPeer hasn't allocated resources for the glyph
+ if( rGlyphData.ExtDataRef().meInfo == INFO_EMPTY )
+ return;
+
+ const GlyphMetric& rGM = rGlyphData.GetMetric();
+ const int nWidth = rGM.GetSize().Width();
+ const int nHeight = rGM.GetSize().Height();
+
+ void* pGlyphExt = rGlyphData.ExtDataRef().mpData;
+ switch( rGlyphData.ExtDataRef().meInfo )
+ {
+ case INFO_PIXMAP:
+ {
+ Pixmap aPixmap = (Pixmap)pGlyphExt;
+ if( aPixmap != None )
+ {
+ XFreePixmap( mpDisplay, aPixmap );
+ mnBytesUsed -= nHeight * ((nWidth + 7) >> 3);
+ }
+ }
+ break;
+
+ case INFO_MULTISCREEN:
+ {
+ MultiScreenGlyph* pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(pGlyphExt);
+ for( int i = 0; i < mnMaxScreens; ++i)
+ {
+ if( pMSGlyph->maPixmaps[i] == NO_PIXMAP )
+ continue;
+ if( pMSGlyph->maPixmaps[i] == None )
+ continue;
+ XFreePixmap( mpDisplay, pMSGlyph->maPixmaps[i] );
+ mnBytesUsed -= nHeight * ((nWidth + 7) >> 3);
+ }
+ delete pMSGlyph->mpRawBitmap;
+ // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer();
+ // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId );
+ delete[] pMSGlyph; // it was allocated with new char[]
+ }
+ break;
+
+ case INFO_RAWBMP:
+ {
+ RawBitmap* pRawBitmap = (RawBitmap*)pGlyphExt;
+ if( pRawBitmap != NULL )
+ {
+ mnBytesUsed -= pRawBitmap->mnScanlineSize * pRawBitmap->mnHeight;
+ mnBytesUsed -= sizeof(RawBitmap);
+ delete pRawBitmap;
+ }
+ }
+ break;
+
+ case INFO_XRENDER:
+ {
+ // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer();
+ // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId );
+ mnBytesUsed -= nHeight * ((nWidth + 3) & ~3);
+ }
+ break;
+ }
+
+ if( mnBytesUsed < 0 ) // TODO: eliminate nBytesUsed calc mismatch
+ mnBytesUsed = 0;
+
+ rGlyphData.ExtDataRef() = ExtGlyphData();
+}
+
+// ---------------------------------------------------------------------------
+
+bool X11GlyphPeer::ForcedAntialiasing( const ServerFont& rServerFont, int nScreen ) const
+{
+ bool bForceOk = rServerFont.GetAntialiasAdvice();
+ // maximum size for antialiasing is 250 pixels
+ bForceOk &= (rServerFont.GetFontSelData().mnHeight < 250);
+ return (bForceOk && ((mnForcedAA >> nScreen) & 1));
+}
+
+// ---------------------------------------------------------------------------
+
+GlyphSet X11GlyphPeer::GetGlyphSet( ServerFont& rServerFont, int nScreen )
+{
+ if( (nScreen >= 0) && ((mnUsingXRender >> nScreen) & 1) == 0 )
+ return 0;
+
+ GlyphSet aGlyphSet;
+
+ switch( rServerFont.GetExtInfo() )
+ {
+ case INFO_XRENDER:
+ aGlyphSet = (GlyphSet)rServerFont.GetExtPointer();
+ break;
+
+ case INFO_EMPTY:
+ {
+ // antialiasing for reasonable font heights only
+ // => prevents crashes caused by X11 requests >= 256k
+ // => prefer readablity of hinted glyphs at small sizes
+ // => prefer "grey clouds" to "black clouds" at very small sizes
+ int nHeight = rServerFont.GetFontSelData().mnHeight;
+ if( nHeight<250 && rServerFont.GetAntialiasAdvice() )
+ {
+ aGlyphSet = XRenderPeer::GetInstance().CreateGlyphSet();
+ rServerFont.SetExtended( INFO_XRENDER, (void*)aGlyphSet );
+ }
+ else
+ aGlyphSet = 0;
+ }
+ break;
+
+ default:
+ aGlyphSet = 0;
+ break;
+ }
+
+ return aGlyphSet;
+}
+
+// ---------------------------------------------------------------------------
+
+Pixmap X11GlyphPeer::GetPixmap( ServerFont& rServerFont, int nGlyphIndex, int nReqScreen )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return None;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+ Pixmap aPixmap = GetPixmap( rGlyphData, nReqScreen );
+ if( aPixmap == NO_PIXMAP )
+ {
+ aPixmap = None;
+ if( rServerFont.GetGlyphBitmap1( nGlyphIndex, maRawBitmap ) )
+ {
+ // #94666# circumvent bug in some X11 systems, e.g. XF410.LynxEM.v163
+ sal_uLong nPixmapWidth = 8 * maRawBitmap.mnScanlineSize - 1;
+ nPixmapWidth = Max( nPixmapWidth, maRawBitmap.mnWidth );
+
+ rGlyphData.SetSize( Size( nPixmapWidth, maRawBitmap.mnHeight ) );
+ rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
+
+ const sal_uLong nBytes = maRawBitmap.mnHeight * maRawBitmap.mnScanlineSize;
+ if( nBytes > 0 )
+ {
+ // conversion table LSB<->MSB (for XCreatePixmapFromData)
+ static const unsigned char lsb2msb[256] =
+ {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+ };
+
+ unsigned char* pTemp = maRawBitmap.mpBits;
+ for( int i = nBytes; --i >= 0; ++pTemp )
+ *pTemp = lsb2msb[ *pTemp ];
+
+ // often a glyph pixmap is only needed on the default screen
+ // => optimize for this common case
+ int nMinScreen = 0;
+ int nEndScreen = mnMaxScreens;
+ if( nReqScreen == mnDefaultScreen ) {
+ nMinScreen = mnDefaultScreen;
+ nEndScreen = mnDefaultScreen + 1;
+ }
+ // prepare glyph pixmaps for the different screens
+ for( int i = nMinScreen; i < nEndScreen; ++i )
+ {
+ // don't bother if the pixmap is already there
+ if( GetPixmap( rGlyphData, i ) != NO_PIXMAP )
+ continue;
+ // create the glyph pixmap
+ Pixmap aScreenPixmap = XCreatePixmapFromBitmapData( mpDisplay,
+ RootWindow( mpDisplay, i ), (char*)maRawBitmap.mpBits,
+ nPixmapWidth, maRawBitmap.mnHeight, 1, 0, 1 );
+ // and cache it as glyph specific data
+ SetPixmap( rGlyphData, aScreenPixmap, i );
+ mnBytesUsed += nBytes;
+ if( i == nReqScreen )
+ aPixmap = aScreenPixmap;
+ }
+ }
+ }
+ else
+ {
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ aPixmap = GetPixmap( rServerFont, 0, nReqScreen );
+
+ if( aPixmap == NO_PIXMAP )
+ aPixmap = None;
+ }
+ }
+
+ return aPixmap;
+}
+
+// ---------------------------------------------------------------------------
+
+const RawBitmap* X11GlyphPeer::GetRawBitmap( ServerFont& rServerFont,
+ int nGlyphIndex )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return NO_RAWBMP;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+
+ const RawBitmap* pRawBitmap = GetRawBitmap( rGlyphData );
+ if( pRawBitmap == NO_RAWBMP )
+ {
+ RawBitmap* pNewBitmap = new RawBitmap;
+ if( rServerFont.GetGlyphBitmap8( nGlyphIndex, *pNewBitmap ) )
+ {
+ pRawBitmap = pNewBitmap;
+ mnBytesUsed += pNewBitmap->mnScanlineSize * pNewBitmap->mnHeight;
+ mnBytesUsed += sizeof(pNewBitmap);
+ }
+ else
+ {
+ delete pNewBitmap;
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ pRawBitmap = GetRawBitmap( rServerFont, 0 );
+ }
+
+ SetRawBitmap( rGlyphData, pRawBitmap );
+ }
+
+ return pRawBitmap;
+}
+
+// ---------------------------------------------------------------------------
+
+Glyph X11GlyphPeer::GetGlyphId( ServerFont& rServerFont, int nGlyphIndex )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return NO_GLYPHID;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+
+ Glyph aGlyphId = GetRenderGlyph( rGlyphData );
+ if( aGlyphId == NO_GLYPHID )
+ {
+ // prepare GlyphInfo and Bitmap
+ if( rServerFont.GetGlyphBitmap8( nGlyphIndex, maRawBitmap ) )
+ {
+ XGlyphInfo aGlyphInfo;
+ aGlyphInfo.width = maRawBitmap.mnWidth;
+ aGlyphInfo.height = maRawBitmap.mnHeight;
+ aGlyphInfo.x = -maRawBitmap.mnXOffset;
+ aGlyphInfo.y = -maRawBitmap.mnYOffset;
+
+ rGlyphData.SetSize( Size( maRawBitmap.mnWidth, maRawBitmap.mnHeight ) );
+ rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
+
+ const GlyphMetric& rGM = rGlyphData.GetMetric();
+ aGlyphInfo.xOff = +rGM.GetDelta().X();
+ aGlyphInfo.yOff = +rGM.GetDelta().Y();
+
+ // upload glyph bitmap to server
+ GlyphSet aGlyphSet = GetGlyphSet( rServerFont, -1 );
+
+ aGlyphId = nGlyphIndex & 0x00FFFFFF;
+ const sal_uLong nBytes = maRawBitmap.mnScanlineSize * maRawBitmap.mnHeight;
+ XRenderPeer::GetInstance().AddGlyph( aGlyphSet, aGlyphId,
+ aGlyphInfo, (char*)maRawBitmap.mpBits, nBytes );
+ mnBytesUsed += nBytes;
+ }
+ else
+ {
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ aGlyphId = GetGlyphId( rServerFont, 0 );
+ }
+
+ SetRenderGlyph( rGlyphData, aGlyphId );
+ }
+
+ return aGlyphId;
+}
+
+// ===========================================================================
+
+X11GlyphCache::X11GlyphCache( X11GlyphPeer& rPeer )
+: GlyphCache( rPeer )
+{
+}
+
+// ---------------------------------------------------------------------------
+
+static X11GlyphPeer* pX11GlyphPeer = NULL;
+static X11GlyphCache* pX11GlyphCache = NULL;
+
+X11GlyphCache& X11GlyphCache::GetInstance()
+{
+ if( !pX11GlyphCache )
+ {
+ pX11GlyphPeer = new X11GlyphPeer();
+ pX11GlyphCache = new X11GlyphCache( *pX11GlyphPeer );
+ }
+ return *pX11GlyphCache;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphCache::KillInstance()
+{
+ delete pX11GlyphCache;
+ delete pX11GlyphPeer;
+ pX11GlyphCache = NULL;
+ pX11GlyphPeer = NULL;
+}
+
+// ===========================================================================
+
+void X11SalGraphics::releaseGlyphPeer()
+{
+ X11GlyphCache::KillInstance();
+}
+
+// ===========================================================================
+
diff --git a/vcl/unx/generic/gdi/gcach_xpeer.hxx b/vcl/unx/generic/gdi/gcach_xpeer.hxx
new file mode 100644
index 000000000000..a65c75174858
--- /dev/null
+++ b/vcl/unx/generic/gdi/gcach_xpeer.hxx
@@ -0,0 +1,92 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GCACH_XPEER_HXX
+#define _SV_GCACH_XPEER_HXX
+
+#include <tools/prex.h>
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+
+#include <glyphcache.hxx>
+
+class SalDisplay;
+struct MultiScreenGlyph;
+
+class X11GlyphPeer
+: public GlyphCachePeer
+{
+public:
+ X11GlyphPeer();
+ virtual ~X11GlyphPeer();
+
+ Pixmap GetPixmap( ServerFont&, int nGlyphIndex, int nScreen );
+ const RawBitmap* GetRawBitmap( ServerFont&, int nGlyphIndex );
+ bool ForcedAntialiasing( const ServerFont&, int nScreen ) const;
+
+ GlyphSet GetGlyphSet( ServerFont&, int nScreen );
+ Glyph GetGlyphId( ServerFont&, int nGlyphIndex );
+
+protected:
+ void InitAntialiasing();
+
+ virtual void RemovingFont( ServerFont& );
+ virtual void RemovingGlyph( ServerFont&, GlyphData&, int nGlyphIndex );
+
+ MultiScreenGlyph* PrepareForMultiscreen( ExtGlyphData& ) const;
+ void SetRenderGlyph( GlyphData&, Glyph ) const;
+ void SetRawBitmap( GlyphData&, const RawBitmap* ) const;
+ void SetPixmap( GlyphData&, Pixmap, int nScreen ) const;
+ Glyph GetRenderGlyph( const GlyphData& ) const;
+ const RawBitmap* GetRawBitmap( const GlyphData& ) const;
+ Pixmap GetPixmap( const GlyphData&, int nScreen ) const;
+
+private:
+ Display* mpDisplay;
+
+ // thirty-two screens should be enough for everyone...
+ static const int MAX_GCACH_SCREENS = 32;
+ int mnMaxScreens;
+ int mnDefaultScreen;
+ int mnExtByteCount;
+ RawBitmap maRawBitmap;
+ sal_uInt32 mnForcedAA;
+ sal_uInt32 mnUsingXRender;
+};
+
+class X11GlyphCache : public GlyphCache
+{
+public:
+ X11GlyphPeer& GetPeer() { return reinterpret_cast<X11GlyphPeer&>( mrPeer ); }
+static X11GlyphCache& GetInstance();
+static void KillInstance();
+
+private:
+ X11GlyphCache( X11GlyphPeer& );
+};
+
+#endif // _SV_GCACH_XPEER_HXX
diff --git a/vcl/unx/generic/gdi/pspgraphics.cxx b/vcl/unx/generic/gdi/pspgraphics.cxx
new file mode 100644
index 000000000000..e68568a81aa9
--- /dev/null
+++ b/vcl/unx/generic/gdi/pspgraphics.cxx
@@ -0,0 +1,1504 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "unx/pspgraphics.h"
+
+#include "vcl/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/bmpacc.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/sysdata.hxx"
+
+#include "printergfx.hxx"
+#include "salbmp.hxx"
+#include "glyphcache.hxx"
+#include "impfont.hxx"
+#include "outfont.hxx"
+#include "fontsubset.hxx"
+#include "salprn.hxx"
+#include "region.h"
+
+#ifdef ENABLE_GRAPHITE
+#include <graphite_layout.hxx>
+#include <graphite_serverfont.hxx>
+#endif
+
+using namespace psp;
+using namespace rtl;
+
+// ----- Implementation of PrinterBmp by means of SalBitmap/BitmapBuffer ---------------
+
+class SalPrinterBmp : public psp::PrinterBmp
+{
+ private:
+ BitmapBuffer* mpBmpBuffer;
+
+ FncGetPixel mpFncGetPixel;
+ Scanline mpScanAccess;
+ sal_PtrDiff mnScanOffset;
+
+ sal_uInt32 ColorOf (BitmapColor& rColor) const;
+ sal_uInt8 GrayOf (BitmapColor& rColor) const;
+
+ SalPrinterBmp ();
+
+ public:
+
+ SalPrinterBmp (BitmapBuffer* pBitmap);
+ virtual ~SalPrinterBmp ();
+ virtual sal_uInt32 GetPaletteColor (sal_uInt32 nIdx) const;
+ virtual sal_uInt32 GetPaletteEntryCount () const;
+ virtual sal_uInt32 GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt8 GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt8 GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt32 GetWidth () const;
+ virtual sal_uInt32 GetHeight() const;
+ virtual sal_uInt32 GetDepth () const;
+};
+
+SalPrinterBmp::SalPrinterBmp (BitmapBuffer* pBuffer) :
+ mpBmpBuffer (pBuffer)
+{
+ DBG_ASSERT (mpBmpBuffer, "SalPrinterBmp::SalPrinterBmp () can't acquire Bitmap");
+
+ // calibrate scanline buffer
+ if( BMP_SCANLINE_ADJUSTMENT( mpBmpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ {
+ mpScanAccess = mpBmpBuffer->mpBits;
+ mnScanOffset = mpBmpBuffer->mnScanlineSize;
+ }
+ else
+ {
+ mpScanAccess = mpBmpBuffer->mpBits
+ + (mpBmpBuffer->mnHeight - 1) * mpBmpBuffer->mnScanlineSize;
+ mnScanOffset = - mpBmpBuffer->mnScanlineSize;
+ }
+
+ // request read access to the pixels
+ switch( BMP_SCANLINE_FORMAT( mpBmpBuffer->mnFormat ) )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_MSB_PAL; break;
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_LSB_PAL; break;
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_4BIT_MSN_PAL; break;
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_4BIT_LSN_PAL; break;
+ case BMP_FORMAT_8BIT_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_8BIT_PAL; break;
+ case BMP_FORMAT_8BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_8BIT_TC_MASK; break;
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_16BIT_TC_MSB_MASK; break;
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_16BIT_TC_LSB_MASK; break;
+ case BMP_FORMAT_24BIT_TC_BGR:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_BGR; break;
+ case BMP_FORMAT_24BIT_TC_RGB:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_RGB; break;
+ case BMP_FORMAT_24BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_MASK; break;
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_ABGR; break;
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_ARGB; break;
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_BGRA; break;
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_RGBA; break;
+ case BMP_FORMAT_32BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_MASK; break;
+
+ default:
+ DBG_ERROR("Error: SalPrinterBmp::SalPrinterBmp() unknown bitmap format");
+ break;
+ }
+}
+
+SalPrinterBmp::~SalPrinterBmp ()
+{
+}
+
+sal_uInt32
+SalPrinterBmp::GetWidth () const
+{
+ return mpBmpBuffer->mnWidth;
+}
+
+sal_uInt32
+SalPrinterBmp::GetHeight () const
+{
+ return mpBmpBuffer->mnHeight;
+}
+
+sal_uInt32
+SalPrinterBmp::GetDepth () const
+{
+ sal_uInt32 nDepth;
+
+ switch (mpBmpBuffer->mnBitCount)
+ {
+ case 1:
+ nDepth = 1;
+ break;
+
+ case 4:
+ case 8:
+ nDepth = 8;
+ break;
+
+ case 16:
+ case 24:
+ case 32:
+ nDepth = 24;
+ break;
+
+ default:
+ nDepth = 1;
+ DBG_ERROR ("Error: unsupported bitmap depth in SalPrinterBmp::GetDepth()");
+ break;
+ }
+
+ return nDepth;
+}
+
+sal_uInt32
+SalPrinterBmp::ColorOf (BitmapColor& rColor) const
+{
+ if (rColor.IsIndex())
+ return ColorOf (mpBmpBuffer->maPalette[rColor.GetIndex()]);
+ else
+ return ((rColor.GetBlue()) & 0x000000ff)
+ | ((rColor.GetGreen() << 8) & 0x0000ff00)
+ | ((rColor.GetRed() << 16) & 0x00ff0000);
+}
+
+sal_uInt8
+SalPrinterBmp::GrayOf (BitmapColor& rColor) const
+{
+ if (rColor.IsIndex())
+ return GrayOf (mpBmpBuffer->maPalette[rColor.GetIndex()]);
+ else
+ return ( rColor.GetBlue() * 28UL
+ + rColor.GetGreen() * 151UL
+ + rColor.GetRed() * 77UL ) >> 8;
+}
+
+sal_uInt32
+SalPrinterBmp::GetPaletteEntryCount () const
+{
+ return mpBmpBuffer->maPalette.GetEntryCount ();
+}
+
+sal_uInt32
+SalPrinterBmp::GetPaletteColor (sal_uInt32 nIdx) const
+{
+ return ColorOf (mpBmpBuffer->maPalette[nIdx]);
+}
+
+sal_uInt32
+SalPrinterBmp::GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ return ColorOf (aColor);
+}
+
+sal_uInt8
+SalPrinterBmp::GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ return GrayOf (aColor);
+}
+
+sal_uInt8
+SalPrinterBmp::GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ if (aColor.IsIndex())
+ return aColor.GetIndex();
+ else
+ return 0;
+}
+
+/*******************************************************
+ * PspGraphics *
+ *******************************************************/
+
+PspGraphics::~PspGraphics()
+{
+ ReleaseFonts();
+}
+
+void PspGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY )
+{
+ if (m_pJobData != NULL)
+ {
+ int x = m_pJobData->m_aContext.getRenderResolution();
+
+ rDPIX = x;
+ rDPIY = x;
+ }
+}
+
+sal_uInt16 PspGraphics::GetBitCount()
+{
+ return m_pPrinterGfx->GetBitCount();
+}
+
+long PspGraphics::GetGraphicsWidth() const
+{
+ return 0;
+}
+
+void PspGraphics::ResetClipRegion()
+{
+ m_pPrinterGfx->ResetClipRegion();
+}
+
+bool PspGraphics::setClipRegion( const Region& i_rClip )
+{
+ // TODO: support polygonal clipregions here
+ m_pPrinterGfx->BeginSetClipRegion( i_rClip.GetRectCount() );
+
+ ImplRegionInfo aInfo;
+ long nX, nY, nW, nH;
+ bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
+ while( bRegionRect )
+ {
+ if ( nW && nH )
+ {
+ m_pPrinterGfx->UnionClipRegion( nX, nY, nW, nH );
+ }
+ bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
+ }
+ m_pPrinterGfx->EndSetClipRegion();
+ return true;
+}
+
+void PspGraphics::SetLineColor()
+{
+ m_pPrinterGfx->SetLineColor ();
+}
+
+void PspGraphics::SetLineColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetLineColor (aColor);
+}
+
+void PspGraphics::SetFillColor()
+{
+ m_pPrinterGfx->SetFillColor ();
+}
+
+void PspGraphics::SetFillColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetFillColor (aColor);
+}
+
+void PspGraphics::SetROPLineColor( SalROPColor )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::SetROPLineColor() not implemented" );
+}
+
+void PspGraphics::SetROPFillColor( SalROPColor )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::SetROPFillColor() not implemented" );
+}
+
+void PspGraphics::SetXORMode( bool bSet, bool )
+{
+ (void)bSet;
+ DBG_ASSERT( !bSet, "Error: PrinterGfx::SetXORMode() not implemented" );
+}
+
+void PspGraphics::drawPixel( long nX, long nY )
+{
+ m_pPrinterGfx->DrawPixel (Point(nX, nY));
+}
+
+void PspGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->DrawPixel (Point(nX, nY), aColor);
+}
+
+void PspGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ m_pPrinterGfx->DrawLine (Point(nX1, nY1), Point(nX2, nY2));
+}
+
+void PspGraphics::drawRect( long nX, long nY, long nDX, long nDY )
+{
+ m_pPrinterGfx->DrawRect (Rectangle(Point(nX, nY), Size(nDX, nDY)));
+}
+
+void PspGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry )
+{
+ m_pPrinterGfx->DrawPolyLine (nPoints, (Point*)pPtAry);
+}
+
+void PspGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry )
+{
+ // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx
+ m_pPrinterGfx->DrawPolygon (nPoints, (Point*)pPtAry);
+}
+
+void PspGraphics::drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32 *pPoints,
+ PCONSTSALPOINT *pPtAry )
+{
+ m_pPrinterGfx->DrawPolyPolygon (nPoly, pPoints, (const Point**)pPtAry);
+}
+
+bool PspGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
+{
+ // TODO: implement and advertise OutDevSupport_B2DDraw support
+ return false;
+}
+
+bool PspGraphics::drawPolyLine( const basegfx::B2DPolygon&, double /*fTranspareny*/, const basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/)
+{
+ // TODO: a PS printer can draw B2DPolyLines almost directly
+ return false;
+}
+
+sal_Bool PspGraphics::drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry )
+{
+ m_pPrinterGfx->DrawPolyLineBezier (nPoints, (Point*)pPtAry, pFlgAry);
+ return sal_True;
+}
+
+sal_Bool PspGraphics::drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry )
+{
+ m_pPrinterGfx->DrawPolygonBezier (nPoints, (Point*)pPtAry, pFlgAry);
+ return sal_True;
+}
+
+sal_Bool PspGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const sal_uInt8* const* pFlgAry )
+{
+ // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx
+ m_pPrinterGfx->DrawPolyPolygonBezier (nPoly, pPoints, (Point**)pPtAry, (sal_uInt8**)pFlgAry);
+ return sal_True;
+}
+
+void PspGraphics::invert( sal_uLong,
+ const SalPoint*,
+ SalInvert )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::Invert() not implemented" );
+}
+sal_Bool PspGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
+{
+ return m_pPrinterGfx->DrawEPS( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ), pPtr, nSize );
+}
+
+void PspGraphics::copyBits( const SalTwoRect*,
+ SalGraphics* )
+{
+ DBG_ERROR( "Error: PrinterGfx::CopyBits() not implemented" );
+}
+
+void PspGraphics::copyArea ( long,long,long,long,long,long,sal_uInt16 )
+{
+ DBG_ERROR( "Error: PrinterGfx::CopyArea() not implemented" );
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ Rectangle aSrc (Point(pPosAry->mnSrcX, pPosAry->mnSrcY),
+ Size(pPosAry->mnSrcWidth, pPosAry->mnSrcHeight));
+ Rectangle aDst (Point(pPosAry->mnDestX, pPosAry->mnDestY),
+ Size(pPosAry->mnDestWidth, pPosAry->mnDestHeight));
+
+ BitmapBuffer* pBuffer= const_cast<SalBitmap&>(rSalBitmap).AcquireBuffer(sal_True);
+
+ SalPrinterBmp aBmp (pBuffer);
+ m_pPrinterGfx->DrawBitmap (aDst, aSrc, aBmp);
+
+ const_cast<SalBitmap&>(rSalBitmap).ReleaseBuffer (pBuffer, sal_True);
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ const SalBitmap& )
+{
+ DBG_ERROR("Error: no PrinterGfx::DrawBitmap() for transparent bitmap");
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ SalColor )
+{
+ DBG_ERROR("Error: no PrinterGfx::DrawBitmap() for transparent color");
+}
+
+void PspGraphics::drawMask( const SalTwoRect*,
+ const SalBitmap &,
+ SalColor )
+{
+ DBG_ERROR("Error: PrinterGfx::DrawMask() not implemented");
+}
+
+SalBitmap* PspGraphics::getBitmap( long, long, long, long )
+{
+ DBG_WARNING ("Warning: PrinterGfx::GetBitmap() not implemented");
+ return NULL;
+}
+
+SalColor PspGraphics::getPixel( long, long )
+{
+ DBG_ERROR ("Warning: PrinterGfx::GetPixel() not implemented");
+ return 0;
+}
+
+void PspGraphics::invert(long,long,long,long,SalInvert)
+{
+ DBG_ERROR ("Warning: PrinterGfx::Invert() not implemented");
+}
+
+//==========================================================================
+
+class ImplPspFontData : public ImplFontData
+{
+private:
+ enum { PSPFD_MAGIC = 0xb5bf01f0 };
+ sal_IntPtr mnFontId;
+
+public:
+ ImplPspFontData( const psp::FastPrintFontInfo& );
+ virtual sal_IntPtr GetFontId() const { return mnFontId; }
+ virtual ImplFontData* Clone() const { return new ImplPspFontData( *this ); }
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ static bool CheckFontData( const ImplFontData& r ) { return r.CheckMagic( PSPFD_MAGIC ); }
+};
+
+//--------------------------------------------------------------------------
+
+ImplPspFontData::ImplPspFontData( const psp::FastPrintFontInfo& rInfo )
+: ImplFontData( PspGraphics::Info2DevFontAttributes(rInfo), PSPFD_MAGIC ),
+ mnFontId( rInfo.m_nID )
+{}
+
+//--------------------------------------------------------------------------
+
+ImplFontEntry* ImplPspFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
+ return pEntry;
+}
+
+//==========================================================================
+
+class PspFontLayout : public GenericSalLayout
+{
+public:
+ PspFontLayout( ::psp::PrinterGfx& );
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void InitFont() const;
+ virtual void DrawText( SalGraphics& ) const;
+private:
+ ::psp::PrinterGfx& mrPrinterGfx;
+ sal_IntPtr mnFontID;
+ int mnFontHeight;
+ int mnFontWidth;
+ bool mbVertical;
+ bool mbArtItalic;
+ bool mbArtBold;
+};
+
+//--------------------------------------------------------------------------
+
+PspFontLayout::PspFontLayout( ::psp::PrinterGfx& rGfx )
+: mrPrinterGfx( rGfx )
+{
+ mnFontID = mrPrinterGfx.GetFontID();
+ mnFontHeight = mrPrinterGfx.GetFontHeight();
+ mnFontWidth = mrPrinterGfx.GetFontWidth();
+ mbVertical = mrPrinterGfx.GetFontVertical();
+ mbArtItalic = mrPrinterGfx.GetArtificialItalic();
+ mbArtBold = mrPrinterGfx.GetArtificialBold();
+}
+
+//--------------------------------------------------------------------------
+
+bool PspFontLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ mbVertical = ((rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0);
+
+ long nUnitsPerPixel = 1;
+ int nOldGlyphId = -1;
+ long nGlyphWidth = 0;
+ int nCharPos = -1;
+ Point aNewPos( 0, 0 );
+ GlyphItem aPrevItem;
+ rtl_TextEncoding aFontEnc = mrPrinterGfx.GetFontMgr().getFontEncoding( mnFontID );
+ for(;;)
+ {
+ bool bRightToLeft;
+ if( !rArgs.GetNextPos( &nCharPos, &bRightToLeft ) )
+ break;
+
+ sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
+ if( bRightToLeft )
+ cChar = GetMirroredChar( cChar );
+ // symbol font aliasing: 0x0020-0x00ff -> 0xf020 -> 0xf0ff
+ if( aFontEnc == RTL_TEXTENCODING_SYMBOL )
+ if( cChar < 256 )
+ cChar += 0xf000;
+ int nGlyphIndex = cChar; // printer glyphs = unicode
+
+ // update fallback_runs if needed
+ psp::CharacterMetric aMetric;
+ mrPrinterGfx.GetFontMgr().getMetrics( mnFontID, cChar, cChar, &aMetric, mbVertical );
+ if( aMetric.width == -1 && aMetric.height == -1 )
+ rArgs.NeedFallback( nCharPos, bRightToLeft );
+
+ // apply pair kerning to prev glyph if requested
+ if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags )
+ {
+ if( nOldGlyphId > 0 )
+ {
+ const std::list< KernPair >& rKernPairs = mrPrinterGfx.getKernPairs(mbVertical);
+ for( std::list< KernPair >::const_iterator it = rKernPairs.begin();
+ it != rKernPairs.end(); ++it )
+ {
+ if( it->first == nOldGlyphId && it->second == nGlyphIndex )
+ {
+ int nTextScale = mrPrinterGfx.GetFontWidth();
+ if( ! nTextScale )
+ nTextScale = mrPrinterGfx.GetFontHeight();
+ int nKern = (mbVertical ? it->kern_y : it->kern_x) * nTextScale;
+ nGlyphWidth += nKern;
+ aPrevItem.mnNewWidth = nGlyphWidth;
+ break;
+ }
+ }
+ }
+ }
+
+ // finish previous glyph
+ if( nOldGlyphId >= 0 )
+ AppendGlyph( aPrevItem );
+ nOldGlyphId = nGlyphIndex;
+ aNewPos.X() += nGlyphWidth;
+
+ // prepare GlyphItem for appending it in next round
+ nUnitsPerPixel = mrPrinterGfx.GetCharWidth( cChar, cChar, &nGlyphWidth );
+ int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0;
+ nGlyphIndex |= GF_ISCHAR;
+ aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
+ }
+
+ // append last glyph item if any
+ if( nOldGlyphId >= 0 )
+ AppendGlyph( aPrevItem );
+
+ SetOrientation( mrPrinterGfx.GetFontAngle() );
+ SetUnitsPerPixel( nUnitsPerPixel );
+ return (nOldGlyphId >= 0);
+}
+
+class PspServerFontLayout : public ServerFontLayout
+{
+public:
+ PspServerFontLayout( psp::PrinterGfx&, ServerFont& rFont, const ImplLayoutArgs& rArgs );
+
+ virtual void InitFont() const;
+ const sal_Unicode* getTextPtr() const { return maText.getStr() - mnMinCharPos; }
+ int getMinCharPos() const { return mnMinCharPos; }
+ int getMaxCharPos() const { return mnMinCharPos+maText.getLength()-1; }
+private:
+ ::psp::PrinterGfx& mrPrinterGfx;
+ sal_IntPtr mnFontID;
+ int mnFontHeight;
+ int mnFontWidth;
+ bool mbVertical;
+ bool mbArtItalic;
+ bool mbArtBold;
+ rtl::OUString maText;
+ int mnMinCharPos;
+};
+
+PspServerFontLayout::PspServerFontLayout( ::psp::PrinterGfx& rGfx, ServerFont& rFont, const ImplLayoutArgs& rArgs )
+ : ServerFontLayout( rFont ),
+ mrPrinterGfx( rGfx )
+{
+ mnFontID = mrPrinterGfx.GetFontID();
+ mnFontHeight = mrPrinterGfx.GetFontHeight();
+ mnFontWidth = mrPrinterGfx.GetFontWidth();
+ mbVertical = mrPrinterGfx.GetFontVertical();
+ mbArtItalic = mrPrinterGfx.GetArtificialItalic();
+ mbArtBold = mrPrinterGfx.GetArtificialBold();
+ maText = OUString( rArgs.mpStr + rArgs.mnMinCharPos, rArgs.mnEndCharPos - rArgs.mnMinCharPos+1 );
+ mnMinCharPos = rArgs.mnMinCharPos;
+}
+
+void PspServerFontLayout::InitFont() const
+{
+ mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth,
+ mnOrientation, mbVertical, mbArtItalic, mbArtBold );
+}
+
+//--------------------------------------------------------------------------
+
+static void DrawPrinterLayout( const SalLayout& rLayout, ::psp::PrinterGfx& rGfx, bool bIsPspServerFontLayout )
+{
+ const int nMaxGlyphs = 200;
+ sal_uInt32 aGlyphAry[ nMaxGlyphs ]; // TODO: use sal_GlyphId
+ sal_Int32 aWidthAry[ nMaxGlyphs ];
+ sal_Int32 aIdxAry [ nMaxGlyphs ];
+ sal_Unicode aUnicodes[ nMaxGlyphs ];
+ int aCharPosAry [ nMaxGlyphs ];
+
+ Point aPos;
+ long nUnitsPerPixel = rLayout.GetUnitsPerPixel();
+ const sal_Unicode* pText = NULL;
+ int nMinCharPos = 0;
+ int nMaxCharPos = 0;
+ if (bIsPspServerFontLayout)
+ {
+ const PspServerFontLayout * pPspLayout = dynamic_cast<const PspServerFontLayout*>(&rLayout);
+#ifdef ENABLE_GRAPHITE
+ const GraphiteServerFontLayout * pGrLayout = dynamic_cast<const GraphiteServerFontLayout*>(&rLayout);
+#endif
+ if (pPspLayout)
+ {
+ pText = pPspLayout->getTextPtr();
+ nMinCharPos = pPspLayout->getMinCharPos();
+ nMaxCharPos = pPspLayout->getMaxCharPos();
+ }
+#ifdef ENABLE_GRAPHITE
+ else if (pGrLayout)
+ {
+ #if 0 // HACK: disabled for now due to #i114460#, see #desc12 there
+ // TODO: get rid of glyph->string mapping altogether for printing
+ // TODO: fix GraphiteServerFontLayout's returned aCharPosAry
+ // TODO: fix PrinterGfx's caching?
+ pText = pGrLayout->getTextPtr();
+ nMinCharPos = pGrLayout->getMinCharPos();
+ nMaxCharPos = pGrLayout->getMaxCharPos();
+ #endif
+ }
+#endif
+ }
+ for( int nStart = 0;; )
+ {
+ int nGlyphCount = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart, aWidthAry, pText ? aCharPosAry : NULL );
+ if( !nGlyphCount )
+ break;
+
+ sal_Int32 nXOffset = 0;
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ nXOffset += aWidthAry[ i ];
+ aIdxAry[ i ] = nXOffset / nUnitsPerPixel;
+ sal_Int32 nGlyphIdx = aGlyphAry[i] & (GF_IDXMASK | GF_ROTMASK);
+ if( pText )
+ aUnicodes[i] = (aCharPosAry[i] >= nMinCharPos && aCharPosAry[i] <= nMaxCharPos) ? pText[ aCharPosAry[i] ] : 0;
+ else
+ aUnicodes[i] = (aGlyphAry[i] & GF_ISCHAR) ? nGlyphIdx : 0;
+ aGlyphAry[i] = nGlyphIdx;
+ }
+
+ rGfx.DrawGlyphs( aPos, (sal_uInt32 *)aGlyphAry, aUnicodes, nGlyphCount, aIdxAry );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void PspFontLayout::InitFont() const
+{
+ mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth,
+ mnOrientation, mbVertical, mbArtItalic, mbArtBold );
+}
+
+//--------------------------------------------------------------------------
+
+void PspFontLayout::DrawText( SalGraphics& ) const
+{
+ DrawPrinterLayout( *this, mrPrinterGfx, false );
+}
+
+void PspGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
+{
+ // print complex text
+ DrawPrinterLayout( rLayout, *m_pPrinterGfx, true );
+}
+
+const ImplFontCharMap* PspGraphics::GetImplFontCharMap() const
+{
+ if( !m_pServerFont[0] )
+ return NULL;
+
+ const ImplFontCharMap* pIFCMap = m_pServerFont[0]->GetImplFontCharMap();
+ return pIFCMap;
+}
+
+sal_uInt16 PspGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+ // release all fonts that are to be overridden
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( m_pServerFont[i] != NULL )
+ {
+ // old server side font is no longer referenced
+ GlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] );
+ m_pServerFont[i] = NULL;
+ }
+ }
+
+ // return early if there is no new font
+ if( !pEntry )
+ return 0;
+
+ sal_IntPtr nID = pEntry->mpFontData ? pEntry->mpFontData->GetFontId() : 0;
+
+ // determine which font attributes need to be emulated
+ bool bArtItalic = false;
+ bool bArtBold = false;
+ if( pEntry->meItalic == ITALIC_OBLIQUE || pEntry->meItalic == ITALIC_NORMAL )
+ {
+ psp::italic::type eItalic = m_pPrinterGfx->GetFontMgr().getFontItalic( nID );
+ if( eItalic != psp::italic::Italic && eItalic != psp::italic::Oblique )
+ bArtItalic = true;
+ }
+ int nWeight = (int)pEntry->meWeight;
+ int nRealWeight = (int)m_pPrinterGfx->GetFontMgr().getFontWeight( nID );
+ if( nRealWeight <= (int)psp::weight::Medium && nWeight > (int)WEIGHT_MEDIUM )
+ {
+ bArtBold = true;
+ }
+
+ // also set the serverside font for layouting
+ m_bFontVertical = pEntry->mbVertical;
+ if( pEntry->mpFontData )
+ {
+ // requesting a font provided by builtin rasterizer
+ ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
+ if( pServerFont != NULL )
+ {
+ if( pServerFont->TestFont() )
+ m_pServerFont[ nFallbackLevel ] = pServerFont;
+ else
+ GlyphCache::GetInstance().UncacheFont( *pServerFont );
+ }
+ }
+
+ // set the printer font
+ return m_pPrinterGfx->SetFont( nID,
+ pEntry->mnHeight,
+ pEntry->mnWidth,
+ pEntry->mnOrientation,
+ pEntry->mbVertical,
+ bArtItalic,
+ bArtBold
+ );
+}
+
+void PspGraphics::SetTextColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetTextColor (aColor);
+}
+
+bool PspGraphics::AddTempDevFont( ImplDevFontList*, const String&,const String& )
+{
+ return false;
+}
+
+void RegisterFontSubstitutors( ImplDevFontList* );
+
+void PspGraphics::GetDevFontList( ImplDevFontList *pList )
+{
+ ::std::list< psp::fontID > aList;
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getFontList( aList, m_pJobData->m_pParser, m_pInfoPrinter->m_bCompatMetrics );
+
+ ::std::list< psp::fontID >::iterator it;
+ psp::FastPrintFontInfo aInfo;
+ for (it = aList.begin(); it != aList.end(); ++it)
+ if (rMgr.getFontFastInfo (*it, aInfo))
+ AnnounceFonts( pList, aInfo );
+
+ // register platform specific font substitutions if available
+ if( rMgr.hasFontconfig() )
+ RegisterFontSubstitutors( pList );
+}
+
+void PspGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
+{
+ const psp::PrinterInfo& rInfo = psp::PrinterInfoManager::get().getPrinterInfo( m_pJobData->m_aPrinterName );
+ if( rInfo.m_bPerformFontSubstitution )
+ {
+ for( std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator it = rInfo.m_aFontSubstitutes.begin(); it != rInfo.m_aFontSubstitutes.end(); ++it )
+ pOutDev->ImplAddDevFontSubstitute( it->first, it->second, FONT_SUBSTITUTE_ALWAYS );
+ }
+}
+
+void PspGraphics::GetFontMetric( ImplFontMetricData *pMetric, int )
+{
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ psp::PrintFontInfo aInfo;
+
+ if (rMgr.getFontInfo (m_pPrinterGfx->GetFontID(), aInfo))
+ {
+ ImplDevFontAttributes aDFA = Info2DevFontAttributes( aInfo );
+ static_cast<ImplFontAttributes&>(*pMetric) = aDFA;
+ pMetric->mbDevice = aDFA.mbDevice;
+ pMetric->mbScalableFont = true;
+
+ pMetric->mnOrientation = m_pPrinterGfx->GetFontAngle();
+ pMetric->mnSlant = 0;
+
+ sal_Int32 nTextHeight = m_pPrinterGfx->GetFontHeight();
+ sal_Int32 nTextWidth = m_pPrinterGfx->GetFontWidth();
+ if( ! nTextWidth )
+ nTextWidth = nTextHeight;
+
+ pMetric->mnWidth = nTextWidth;
+ pMetric->mnAscent = ( aInfo.m_nAscend * nTextHeight + 500 ) / 1000;
+ pMetric->mnDescent = ( aInfo.m_nDescend * nTextHeight + 500 ) / 1000;
+ pMetric->mnIntLeading = ( aInfo.m_nLeading * nTextHeight + 500 ) / 1000;
+ pMetric->mnExtLeading = 0;
+ }
+}
+
+sal_uLong PspGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData *pKernPairs )
+{
+ const ::std::list< ::psp::KernPair >& rPairs( m_pPrinterGfx->getKernPairs() );
+ sal_uLong nHavePairs = rPairs.size();
+ if( pKernPairs && nPairs )
+ {
+ ::std::list< ::psp::KernPair >::const_iterator it;
+ unsigned int i;
+ int nTextScale = m_pPrinterGfx->GetFontWidth();
+ if( ! nTextScale )
+ nTextScale = m_pPrinterGfx->GetFontHeight();
+ for( i = 0, it = rPairs.begin(); i < nPairs && i < nHavePairs; i++, ++it )
+ {
+ pKernPairs[i].mnChar1 = it->first;
+ pKernPairs[i].mnChar2 = it->second;
+ pKernPairs[i].mnKern = it->kern_x * nTextScale / 1000;
+ }
+
+ }
+ return nHavePairs;
+}
+
+sal_Bool PspGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return sal_False;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return sal_False;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
+ rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+ return sal_True;
+}
+
+sal_Bool PspGraphics::GetGlyphOutline( long nGlyphIndex,
+ ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return sal_False;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return sal_False;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ if( pSF->GetGlyphOutline( nGlyphIndex, rB2DPolyPoly ) )
+ return sal_True;
+
+ return sal_False;
+}
+
+SalLayout* PspGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ // workaround for printers not handling glyph indexing for non-TT fonts
+ int nFontId = m_pPrinterGfx->GetFontID();
+ if( psp::fonttype::TrueType != psp::PrintFontManager::get().getFontType( nFontId ) )
+ rArgs.mnFlags |= SAL_LAYOUT_DISABLE_GLYPH_PROCESSING;
+ else if( nFallbackLevel > 0 )
+ rArgs.mnFlags &= ~SAL_LAYOUT_DISABLE_GLYPH_PROCESSING;
+
+ GenericSalLayout* pLayout = NULL;
+
+ if( m_pServerFont[ nFallbackLevel ]
+ && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+ {
+#ifdef ENABLE_GRAPHITE
+ // Is this a Graphite font?
+ if (GraphiteFontAdaptor::IsGraphiteEnabledFont(*m_pServerFont[nFallbackLevel]))
+ {
+ sal_Int32 xdpi, ydpi;
+ GetResolution(xdpi, ydpi);
+ GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *m_pServerFont[nFallbackLevel], xdpi, ydpi);
+ if (!pGrfont) return NULL;
+ pLayout = new GraphiteServerFontLayout(pGrfont);
+ }
+ else
+#endif
+ pLayout = new PspServerFontLayout( *m_pPrinterGfx, *m_pServerFont[nFallbackLevel], rArgs );
+ }
+ else
+ pLayout = new PspFontLayout( *m_pPrinterGfx );
+
+ return pLayout;
+}
+
+//--------------------------------------------------------------------------
+
+sal_Bool PspGraphics::CreateFontSubset(
+ const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphCount,
+ FontSubsetInfo& rInfo
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ bool bSuccess = rMgr.createFontSubset( rInfo,
+ aFont,
+ rToFile,
+ pGlyphIDs,
+ pEncoding,
+ pWidths,
+ nGlyphCount );
+ return bSuccess;
+}
+
+//--------------------------------------------------------------------------
+
+const void* PspGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
+}
+
+//--------------------------------------------------------------------------
+
+void PspGraphics::FreeEmbedFontData( const void* pData, long nLen )
+{
+ PspGraphics::DoFreeEmbedFontData( pData, nLen );
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* PspGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
+}
+
+//--------------------------------------------------------------------------
+
+void PspGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+
+// static helpers of PspGraphics
+
+const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+
+ psp::PrintFontInfo aFontInfo;
+ if( ! rMgr.getFontInfo( aFont, aFontInfo ) )
+ return NULL;
+
+ // fill in font info
+ rInfo.m_nAscent = aFontInfo.m_nAscend;
+ rInfo.m_nDescent = aFontInfo.m_nDescend;
+ rInfo.m_aPSName = rMgr.getPSName( aFont );
+
+ int xMin, yMin, xMax, yMax;
+ rMgr.getFontBoundingBox( aFont, xMin, yMin, xMax, yMax );
+
+ psp::CharacterMetric aMetrics[256];
+ sal_Ucs aUnicodes[256];
+ if( aFontInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL && aFontInfo.m_eType == psp::fonttype::Type1 )
+ {
+ for( int i = 0; i < 256; i++ )
+ aUnicodes[i] = pUnicodes[i] < 0x0100 ? pUnicodes[i] + 0xf000 : pUnicodes[i];
+ pUnicodes = aUnicodes;
+ }
+ if( ! rMgr.getMetrics( aFont, pUnicodes, 256, aMetrics ) )
+ return NULL;
+
+ OString aSysPath = rMgr.getFontFileSysPath( aFont );
+ struct stat aStat;
+ if( stat( aSysPath.getStr(), &aStat ) )
+ return NULL;
+ int fd = open( aSysPath.getStr(), O_RDONLY );
+ if( fd < 0 )
+ return NULL;
+ void* pFile = mmap( NULL, aStat.st_size, PROT_READ, MAP_SHARED, fd, 0 );
+ close( fd );
+ if( pFile == MAP_FAILED )
+ return NULL;
+
+ *pDataLen = aStat.st_size;
+
+ rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
+ 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;
+}
+
+void PspGraphics::DoFreeEmbedFontData( const void* pData, long nLen )
+{
+ if( pData )
+ munmap( (char*)pData, nLen );
+}
+
+const Ucs2SIntMap* PspGraphics::DoGetFontEncodingVector( fontID aFont, const Ucs2OStrMap** pNonEncoded )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+
+ psp::PrintFontInfo aFontInfo;
+ if( ! rMgr.getFontInfo( aFont, aFontInfo ) )
+ {
+ if( pNonEncoded )
+ *pNonEncoded = NULL;
+ return NULL;
+ }
+
+ return rMgr.getEncodingMap( aFont, pNonEncoded );
+}
+
+void PspGraphics::DoGetGlyphWidths( psp::fontID aFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+// ----------------------------------------------------------------------------
+
+FontWidth PspGraphics::ToFontWidth (psp::width::type eWidth)
+{
+ switch (eWidth)
+ {
+ case psp::width::UltraCondensed: return WIDTH_ULTRA_CONDENSED;
+ case psp::width::ExtraCondensed: return WIDTH_EXTRA_CONDENSED;
+ case psp::width::Condensed: return WIDTH_CONDENSED;
+ case psp::width::SemiCondensed: return WIDTH_SEMI_CONDENSED;
+ case psp::width::Normal: return WIDTH_NORMAL;
+ case psp::width::SemiExpanded: return WIDTH_SEMI_EXPANDED;
+ case psp::width::Expanded: return WIDTH_EXPANDED;
+ case psp::width::ExtraExpanded: return WIDTH_EXTRA_EXPANDED;
+ case psp::width::UltraExpanded: return WIDTH_ULTRA_EXPANDED;
+ case psp::width::Unknown: return WIDTH_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown width mapping" );
+ break;
+ }
+ return WIDTH_DONTKNOW;
+}
+
+FontWeight PspGraphics::ToFontWeight (psp::weight::type eWeight)
+{
+ switch (eWeight)
+ {
+ case psp::weight::Thin: return WEIGHT_THIN;
+ case psp::weight::UltraLight: return WEIGHT_ULTRALIGHT;
+ case psp::weight::Light: return WEIGHT_LIGHT;
+ case psp::weight::SemiLight: return WEIGHT_SEMILIGHT;
+ case psp::weight::Normal: return WEIGHT_NORMAL;
+ case psp::weight::Medium: return WEIGHT_MEDIUM;
+ case psp::weight::SemiBold: return WEIGHT_SEMIBOLD;
+ case psp::weight::Bold: return WEIGHT_BOLD;
+ case psp::weight::UltraBold: return WEIGHT_ULTRABOLD;
+ case psp::weight::Black: return WEIGHT_BLACK;
+ case psp::weight::Unknown: return WEIGHT_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown weight mapping" );
+ break;
+ }
+ return WEIGHT_DONTKNOW;
+}
+
+FontPitch PspGraphics::ToFontPitch (psp::pitch::type ePitch)
+{
+ switch (ePitch)
+ {
+ case psp::pitch::Fixed: return PITCH_FIXED;
+ case psp::pitch::Variable: return PITCH_VARIABLE;
+ case psp::pitch::Unknown: return PITCH_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown pitch mapping" );
+ break;
+ }
+ return PITCH_DONTKNOW;
+}
+
+FontItalic PspGraphics::ToFontItalic (psp::italic::type eItalic)
+{
+ switch (eItalic)
+ {
+ case psp::italic::Upright: return ITALIC_NONE;
+ case psp::italic::Oblique: return ITALIC_OBLIQUE;
+ case psp::italic::Italic: return ITALIC_NORMAL;
+ case psp::italic::Unknown: return ITALIC_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown italic mapping" );
+ break;
+ }
+ return ITALIC_DONTKNOW;
+}
+
+FontFamily PspGraphics::ToFontFamily (psp::family::type eFamily)
+{
+ switch (eFamily)
+ {
+ case psp::family::Decorative: return FAMILY_DECORATIVE;
+ case psp::family::Modern: return FAMILY_MODERN;
+ case psp::family::Roman: return FAMILY_ROMAN;
+ case psp::family::Script: return FAMILY_SCRIPT;
+ case psp::family::Swiss: return FAMILY_SWISS;
+ case psp::family::System: return FAMILY_SYSTEM;
+ case psp::family::Unknown: return FAMILY_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown family mapping" );
+ break;
+ }
+ return FAMILY_DONTKNOW;
+}
+
+ImplDevFontAttributes PspGraphics::Info2DevFontAttributes( const psp::FastPrintFontInfo& rInfo )
+{
+ ImplDevFontAttributes aDFA;
+ aDFA.maName = rInfo.m_aFamilyName;
+ aDFA.maStyleName = rInfo.m_aStyleName;
+ aDFA.meFamily = ToFontFamily (rInfo.m_eFamilyStyle);
+ aDFA.meWeight = ToFontWeight (rInfo.m_eWeight);
+ aDFA.meItalic = ToFontItalic (rInfo.m_eItalic);
+ aDFA.meWidthType = ToFontWidth (rInfo.m_eWidth);
+ aDFA.mePitch = ToFontPitch (rInfo.m_ePitch);
+ aDFA.mbSymbolFlag = (rInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL);
+ aDFA.mbSubsettable = rInfo.m_bSubsettable;
+ aDFA.mbEmbeddable = rInfo.m_bEmbeddable;
+
+ switch( rInfo.m_eType )
+ {
+ case psp::fonttype::Builtin:
+ aDFA.mnQuality = 1024;
+ aDFA.mbDevice = true;
+ break;
+ case psp::fonttype::TrueType:
+ aDFA.mnQuality = 512;
+ aDFA.mbDevice = false;
+ break;
+ case psp::fonttype::Type1:
+ aDFA.mnQuality = 0;
+ aDFA.mbDevice = false;
+ break;
+ default:
+ aDFA.mnQuality = 0;
+ aDFA.mbDevice = false;
+ break;
+ }
+
+ aDFA.mbOrientation = true;
+
+ // add font family name aliases
+ ::std::list< OUString >::const_iterator it = rInfo.m_aAliases.begin();
+ bool bHasMapNames = false;
+ for(; it != rInfo.m_aAliases.end(); ++it )
+ {
+ if( bHasMapNames )
+ aDFA.maMapNames.Append( ';' );
+ aDFA.maMapNames.Append( (*it).getStr() );
+ bHasMapNames = true;
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ if( bHasMapNames )
+ {
+ ByteString aOrigName( aDFA.maName, osl_getThreadTextEncoding() );
+ ByteString aAliasNames( aDFA.maMapNames, osl_getThreadTextEncoding() );
+ fprintf( stderr, "using alias names \"%s\" for font family \"%s\"\n",
+ aAliasNames.GetBuffer(), aOrigName.GetBuffer() );
+ }
+#endif
+
+ return aDFA;
+}
+
+// -----------------------------------------------------------------------
+
+void PspGraphics::AnnounceFonts( ImplDevFontList* pFontList, const psp::FastPrintFontInfo& aInfo )
+{
+ int nQuality = 0;
+
+ if( aInfo.m_eType == psp::fonttype::TrueType )
+ {
+ // asian type 1 fonts are not known
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ ByteString aFileName( rMgr.getFontFileSysPath( aInfo.m_nID ) );
+ int nPos = aFileName.SearchBackward( '_' );
+ if( nPos == STRING_NOTFOUND || aFileName.GetChar( nPos+1 ) == '.' )
+ nQuality += 5;
+ else
+ {
+ static const char* pLangBoost = NULL;
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+ const LanguageType aLang = Application::GetSettings().GetUILanguage();
+ switch( aLang )
+ {
+ case LANGUAGE_JAPANESE:
+ pLangBoost = "jan";
+ break;
+ case LANGUAGE_CHINESE:
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ case LANGUAGE_CHINESE_SINGAPORE:
+ pLangBoost = "zhs";
+ break;
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ case LANGUAGE_CHINESE_HONGKONG:
+ case LANGUAGE_CHINESE_MACAU:
+ pLangBoost = "zht";
+ break;
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ pLangBoost = "kor";
+ break;
+ }
+ }
+
+ if( pLangBoost )
+ if( aFileName.Copy( nPos+1, 3 ).EqualsIgnoreCaseAscii( pLangBoost ) )
+ nQuality += 10;
+ }
+ }
+
+ ImplPspFontData* pFD = new ImplPspFontData( aInfo );
+ pFD->mnQuality += nQuality;
+ pFontList->Add( pFD );
+}
+
+bool PspGraphics::filterText( const String& rOrig, String& rNewText, xub_StrLen nIndex, xub_StrLen& rLen, xub_StrLen& rCutStart, xub_StrLen& rCutStop )
+{
+ if( ! m_pPhoneNr )
+ return false;
+
+ rCutStop = rCutStart = STRING_NOTFOUND;
+
+#define FAX_PHONE_TOKEN "@@#"
+#define FAX_PHONE_TOKEN_LENGTH 3
+#define FAX_END_TOKEN "@@"
+#define FAX_END_TOKEN_LENGTH 2
+
+ bool bRet = false;
+ bool bStarted = false;
+ bool bStopped = false;
+ sal_uInt16 nPos;
+ sal_uInt16 nStart = 0;
+ sal_uInt16 nStop = rLen;
+ String aPhone = rOrig.Copy( nIndex, rLen );
+
+ if( ! m_bPhoneCollectionActive )
+ {
+ if( ( nPos = aPhone.SearchAscii( FAX_PHONE_TOKEN ) ) != STRING_NOTFOUND )
+ {
+ nStart = nPos;
+ m_bPhoneCollectionActive = true;
+ m_aPhoneCollection.Erase();
+ bRet = true;
+ bStarted = true;
+ }
+ }
+ if( m_bPhoneCollectionActive )
+ {
+ bRet = true;
+ nPos = bStarted ? nStart + FAX_PHONE_TOKEN_LENGTH : 0;
+ if( ( nPos = aPhone.SearchAscii( FAX_END_TOKEN, nPos ) ) != STRING_NOTFOUND )
+ {
+ m_bPhoneCollectionActive = false;
+ nStop = nPos + FAX_END_TOKEN_LENGTH;
+ bStopped = true;
+ }
+ int nTokenStart = nStart + (bStarted ? FAX_PHONE_TOKEN_LENGTH : 0);
+ int nTokenStop = nStop - (bStopped ? FAX_END_TOKEN_LENGTH : 0);
+ m_aPhoneCollection += aPhone.Copy( nTokenStart, nTokenStop - nTokenStart );
+ if( ! m_bPhoneCollectionActive )
+ {
+ m_pPhoneNr->AppendAscii( "<Fax#>" );
+ m_pPhoneNr->Append( m_aPhoneCollection );
+ m_pPhoneNr->AppendAscii( "</Fax#>" );
+ m_aPhoneCollection.Erase();
+ }
+ }
+ if( m_aPhoneCollection.Len() > 1024 )
+ {
+ m_bPhoneCollectionActive = false;
+ m_aPhoneCollection.Erase();
+ bRet = false;
+ }
+
+ if( bRet && m_bSwallowFaxNo )
+ {
+ rLen -= nStop - nStart;
+ rCutStart = nStart+nIndex;
+ rCutStop = nStop+nIndex;
+ if( rCutStart )
+ rNewText = rOrig.Copy( 0, rCutStart );
+ rNewText += rOrig.Copy( rCutStop );
+ }
+
+ return bRet && m_bSwallowFaxNo;
+}
+
+bool PspGraphics::drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap&,
+ const SalBitmap& )
+{
+ return false;
+}
+
+bool PspGraphics::drawAlphaRect( long, long, long, long, sal_uInt8 )
+{
+ return false;
+}
+
+SystemGraphicsData PspGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.hDrawable = 0;
+ aRes.pRenderFormat = 0;
+ return aRes;
+}
+
+SystemFontData PspGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.nFontId = 0;
+ aSysFontData.nFontFlags = 0;
+ aSysFontData.bFakeBold = false;
+ aSysFontData.bFakeItalic = false;
+ aSysFontData.bAntialias = true;
+ return aSysFontData;
+}
+
+bool PspGraphics::supportsOperation( OutDevSupportType ) const
+{
+ return false;
+}
diff --git a/vcl/unx/generic/gdi/salbmp.cxx b/vcl/unx/generic/gdi/salbmp.cxx
new file mode 100644
index 000000000000..732ae465df52
--- /dev/null
+++ b/vcl/unx/generic/gdi/salbmp.cxx
@@ -0,0 +1,1096 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#ifdef FREEBSD
+#include <sys/types.h>
+#endif
+
+#include <osl/endian.h>
+#include <rtl/memory.h>
+
+#include <vcl/bitmap.hxx>
+#include <vcl/salbtype.hxx>
+
+#include <tools/prex.h>
+#include "unx/Xproto.h"
+#include <tools/postx.h>
+#include <unx/salunx.h>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+#include <unx/salgdi.h>
+#include <unx/salbmp.h>
+#include <unx/salinst.h>
+
+// -----------
+// - Defines -
+// -----------
+
+#define SAL_DRAWPIXMAP_MAX_EXT 4096
+
+// -------------
+// - SalBitmap -
+// -------------
+
+SalBitmap* X11SalInstance::CreateSalBitmap()
+{
+ return new X11SalBitmap();
+}
+
+ImplSalBitmapCache* X11SalBitmap::mpCache = NULL;
+sal_uLong X11SalBitmap::mnCacheInstCount = 0;
+
+// -----------------------------------------------------------------------------
+
+X11SalBitmap::X11SalBitmap() :
+ mpDIB( NULL ),
+ mpDDB( NULL )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+X11SalBitmap::~X11SalBitmap()
+{
+ Destroy();
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplCreateCache()
+{
+ if( !mnCacheInstCount++ )
+ mpCache = new ImplSalBitmapCache;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplDestroyCache()
+{
+ DBG_ASSERT( mnCacheInstCount, "X11SalBitmap::ImplDestroyCache(): underflow" );
+
+ if( mnCacheInstCount && !--mnCacheInstCount )
+ delete mpCache, mpCache = NULL;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplRemovedFromCache()
+{
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
+{
+ DBG_ASSERT( nBitCount == 1 || nBitCount == 4 || nBitCount == 8 || nBitCount == 16 || nBitCount == 24, "Unsupported BitCount!" );
+
+ BitmapBuffer* pDIB = NULL;
+
+ if( rSize.Width() && rSize.Height() )
+ {
+ try
+ {
+ pDIB = new BitmapBuffer;
+ }
+ catch( std::bad_alloc& )
+ {
+ pDIB = NULL;
+ }
+
+ if( pDIB )
+ {
+ const sal_uInt16 nColors = ( nBitCount <= 8 ) ? ( 1 << nBitCount ) : 0;
+
+ pDIB->mnFormat = BMP_FORMAT_BOTTOM_UP;
+
+ switch( nBitCount )
+ {
+ case( 1 ): pDIB->mnFormat |= BMP_FORMAT_1BIT_MSB_PAL; break;
+ case( 4 ): pDIB->mnFormat |= BMP_FORMAT_4BIT_MSN_PAL; break;
+ case( 8 ): pDIB->mnFormat |= BMP_FORMAT_8BIT_PAL; break;
+#ifdef OSL_BIGENDIAN
+ case(16 ):
+ pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
+ break;
+#else
+ case(16 ):
+ pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
+ break;
+#endif
+ default:
+ nBitCount = 24;
+ //fall through
+ case 24:
+ pDIB->mnFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ break;
+ }
+
+ pDIB->mnWidth = rSize.Width();
+ pDIB->mnHeight = rSize.Height();
+ pDIB->mnScanlineSize = AlignedWidth4Bytes( pDIB->mnWidth * nBitCount );
+ pDIB->mnBitCount = nBitCount;
+
+ if( nColors )
+ {
+ pDIB->maPalette = rPal;
+ pDIB->maPalette.SetEntryCount( nColors );
+ }
+
+ try
+ {
+ pDIB->mpBits = new sal_uInt8[ pDIB->mnScanlineSize * pDIB->mnHeight ];
+ }
+ catch(std::bad_alloc&)
+ {
+ delete pDIB;
+ pDIB = NULL;
+ }
+ }
+ }
+ else
+ pDIB = NULL;
+
+ return pDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::ImplCreateDIB( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ long nX, long nY,
+ long nWidth, long nHeight )
+{
+ BitmapBuffer* pDIB = NULL;
+
+ if( aDrawable && nWidth && nHeight && nDrawableDepth )
+ {
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ SalXLib* pXLib = pSalDisp->GetXLib();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ // do not die on XError here
+ // alternatively one could check the coordinates for being offscreen
+ // but this call can actually work on servers with backing store
+ // defaults even if the rectangle is offscreen
+ // so better catch the XError
+ pXLib->PushXErrorLevel( true );
+ XImage* pImage = XGetImage( pXDisp, aDrawable, nX, nY, nWidth, nHeight, AllPlanes, ZPixmap );
+ bool bWasError = pXLib->HasXErrorOccured() && pXLib->GetLastXErrorRequestCode() == X_GetImage;
+ pXLib->PopXErrorLevel();
+
+ if( ! bWasError && pImage && pImage->data )
+ {
+ const SalTwoRect aTwoRect = { 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight };
+ BitmapBuffer aSrcBuf;
+ sal_uLong nDstFormat = BMP_FORMAT_BOTTOM_UP;
+ const BitmapPalette* pDstPal = NULL;
+
+ aSrcBuf.mnFormat = BMP_FORMAT_TOP_DOWN;
+ aSrcBuf.mnWidth = nWidth;
+ aSrcBuf.mnHeight = nHeight;
+ aSrcBuf.mnBitCount = pImage->bits_per_pixel;
+ aSrcBuf.mnScanlineSize = pImage->bytes_per_line;
+ aSrcBuf.mpBits = (sal_uInt8*) pImage->data;
+
+ pImage->red_mask = pSalDisp->GetVisual( nScreen ).red_mask;
+ pImage->green_mask = pSalDisp->GetVisual( nScreen ).green_mask;
+ pImage->blue_mask = pSalDisp->GetVisual( nScreen ).blue_mask;
+
+ switch( aSrcBuf.mnBitCount )
+ {
+ case( 1 ):
+ {
+ aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL );
+ nDstFormat |= BMP_FORMAT_1BIT_MSB_PAL;
+ }
+ break;
+
+ case( 4 ):
+ {
+ aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL );
+ nDstFormat |= BMP_FORMAT_4BIT_MSN_PAL;
+ }
+ break;
+
+ case( 8 ):
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_8BIT_PAL;
+ nDstFormat |= BMP_FORMAT_8BIT_PAL;
+ }
+ break;
+
+ case( 16 ):
+ {
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ aSrcBuf.maColorMask = ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask );
+
+ if( LSBFirst == pImage->byte_order )
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ }
+ else
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ // aSrcBuf.maColorMask = ColorMask( pImage->red_mask ), SWAPSHORT( pImage->green_mask ), SWAPSHORT( pImage->blue_mask ) );
+ }
+ }
+ break;
+
+ case( 24 ):
+ {
+ if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) )
+ aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_RGB;
+ else
+ aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_BGR;
+
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+
+ case( 32 ):
+ {
+ if( LSBFirst == pImage->byte_order )
+ aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA );
+ else
+ aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB );
+
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+ }
+
+ BitmapPalette& rPal = aSrcBuf.maPalette;
+
+ if( aSrcBuf.mnBitCount == 1 )
+ {
+ rPal.SetEntryCount( 2 );
+ pDstPal = &rPal;
+
+ rPal[ 0 ] = Color( COL_BLACK );
+ rPal[ 1 ] = Color( COL_WHITE );
+ }
+ else if( aSrcBuf.mnBitCount <= 8 )
+ {
+ const SalColormap& rColMap = pSalDisp->GetColormap( nScreen );
+ const sal_uInt16 nCols = Min( (sal_uLong)rColMap.GetUsed(), (sal_uLong)(1 << nDrawableDepth) );
+
+ rPal.SetEntryCount( nCols );
+ pDstPal = &rPal;
+
+ for( sal_uInt16 i = 0; i < nCols; i++ )
+ {
+ const SalColor nColor( rColMap.GetColor( i ) );
+ BitmapColor& rBmpCol = rPal[ i ];
+
+ rBmpCol.SetRed( SALCOLOR_RED( nColor ) );
+ rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) );
+ rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) );
+ }
+ }
+
+ nDstFormat = aSrcBuf.mnFormat;
+ pDIB = StretchAndConvert( aSrcBuf, aTwoRect, nDstFormat,
+ const_cast<BitmapPalette*>(pDstPal), &aSrcBuf.maColorMask );
+ XDestroyImage( pImage );
+ }
+ }
+
+ return pDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+XImage* X11SalBitmap::ImplCreateXImage( SalDisplay *pSalDisp, int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const
+{
+ XImage* pImage = NULL;
+
+ if( !mpDIB && mpDDB )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDIB =
+ ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0,
+ mpDDB->ImplGetWidth(),
+ mpDDB->ImplGetHeight() );
+ }
+
+ if( mpDIB && mpDIB->mnWidth && mpDIB->mnHeight )
+ {
+ Display* pXDisp = pSalDisp->GetDisplay();
+ long nWidth = rTwoRect.mnDestWidth;
+ long nHeight = rTwoRect.mnDestHeight;
+
+ if( 1 == GetBitCount() )
+ nDepth = 1;
+
+ pImage = XCreateImage( pXDisp, pSalDisp->GetVisual( nScreen ).GetVisual(),
+ nDepth, ( 1 == nDepth ) ? XYBitmap :ZPixmap, 0, NULL,
+ nWidth, nHeight, 32, 0 );
+
+ if( pImage )
+ {
+ BitmapBuffer* pDstBuf;
+ sal_uLong nDstFormat = BMP_FORMAT_TOP_DOWN;
+ BitmapPalette* pPal = NULL;
+ ColorMask* pMask = NULL;
+
+ switch( pImage->bits_per_pixel )
+ {
+ case( 1 ):
+ nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL );
+ break;
+
+ case( 4 ):
+ nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL );
+ break;
+
+ case( 8 ):
+ nDstFormat |= BMP_FORMAT_8BIT_PAL;
+ break;
+
+ case( 16 ):
+ {
+ #ifdef OSL_BIGENDIAN
+
+ if( MSBFirst == pImage->byte_order )
+ nDstFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ else
+ nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+
+ #else /* OSL_LITENDIAN */
+
+ nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ if( MSBFirst == pImage->byte_order )
+ pImage->byte_order = LSBFirst;
+
+ #endif
+
+ pMask = new ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask );
+ }
+ break;
+
+ case( 24 ):
+ {
+ if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) )
+ nDstFormat |= BMP_FORMAT_24BIT_TC_RGB;
+ else
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+
+ case( 32 ):
+ {
+ if( LSBFirst == pImage->byte_order )
+ nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA );
+ else
+ nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB );
+ }
+ break;
+ }
+
+ if( pImage->depth == 1 )
+ {
+ pPal = new BitmapPalette( 2 );
+ (*pPal)[ 0 ] = Color( COL_BLACK );
+ (*pPal)[ 1 ] = Color( COL_WHITE );
+ }
+ else if( pImage->depth <= 8 )
+ {
+ const SalColormap& rColMap = pSalDisp->GetColormap( nScreen );
+ const sal_uInt16 nCols = Min( (sal_uLong)rColMap.GetUsed(), (sal_uLong)(1 << pImage->depth) );
+
+ pPal = new BitmapPalette( nCols );
+
+ for( sal_uInt16 i = 0; i < nCols; i++ )
+ {
+ const SalColor nColor( rColMap.GetColor( i ) );
+ BitmapColor& rBmpCol = (*pPal)[ i ];
+
+ rBmpCol.SetRed( SALCOLOR_RED( nColor ) );
+ rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) );
+ rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) );
+ }
+ }
+
+ pDstBuf = StretchAndConvert( *mpDIB, rTwoRect, nDstFormat, pPal, pMask );
+ delete pPal;
+ delete pMask;
+
+ if( pDstBuf && pDstBuf->mpBits )
+ {
+ // set data in buffer as data member in pImage
+ pImage->data = (char*) pDstBuf->mpBits;
+
+ // destroy buffer; don't destroy allocated data in buffer
+ delete pDstBuf;
+ }
+ else
+ {
+ XDestroyImage( pImage );
+ pImage = NULL;
+ }
+ }
+ }
+
+ return pImage;
+}
+
+// -----------------------------------------------------------------------------
+bool X11SalBitmap::ImplCreateFromDrawable( Drawable aDrawable,
+ int nScreen, long nDrawableDepth,
+ long nX, long nY, long nWidth, long nHeight )
+{
+ Destroy();
+
+ if( aDrawable && nWidth && nHeight && nDrawableDepth )
+ mpDDB = new ImplSalDDB( aDrawable, nScreen, nDrawableDepth, nX, nY, nWidth, nHeight );
+
+ return( mpDDB != NULL );
+}
+// -----------------------------------------------------------------------------
+
+bool
+X11SalBitmap::SnapShot (Display* pDisplay, XLIB_Window hWindow)
+{
+ if (hWindow != None)
+ {
+ XWindowAttributes aAttribute;
+ XGetWindowAttributes (pDisplay, hWindow, &aAttribute);
+ if (aAttribute.map_state == IsViewable)
+ {
+ // get coordinates relative to root window
+ XLIB_Window hPetitFleur;
+ int nRootX, nRootY;
+
+ if (XTranslateCoordinates (pDisplay, hWindow, aAttribute.root,
+ 0, 0, &nRootX, &nRootY, &hPetitFleur))
+ {
+ XWindowAttributes aRootAttribute;
+ XGetWindowAttributes (pDisplay, aAttribute.root, &aRootAttribute);
+
+ int width = aAttribute.width;
+ int height = aAttribute.height;
+ int x = nRootX;
+ int y = nRootY;
+
+ // horizontal range check
+ if (x < 0)
+ {
+ width = width + x;
+ x = 0;
+ }
+ else
+ if (x > aRootAttribute.width)
+ {
+ width = 0;
+ x = aRootAttribute.width;
+ }
+ else
+ if (x + width > aRootAttribute.width)
+ {
+ width = aRootAttribute.width - x;
+ }
+
+ // vertical range check
+ if (y < 0)
+ {
+ height = height + y;
+ y = 0;
+ }
+ else
+ if (y > aRootAttribute.height)
+ {
+ height = 0;
+ y = aRootAttribute.height;
+ }
+ else
+ if (y + height > aRootAttribute.height)
+ {
+ height = aRootAttribute.height - y;
+ }
+
+ if ((width > 0) && (height > 0))
+ {
+ XImage* pImage = XGetImage( pDisplay, aAttribute.root,
+ x, y, width, height, AllPlanes, ZPixmap );
+ bool bSnapShot = ImplCreateFromXImage( pDisplay,
+ aAttribute.root,
+ XScreenNumberOfScreen( aAttribute.screen ),
+ pImage );
+ XDestroyImage (pImage);
+
+ return bSnapShot;
+ }
+ }
+ }
+ }
+
+ return False;
+}
+
+bool
+X11SalBitmap::ImplCreateFromXImage (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage)
+{
+ Destroy();
+
+ if (pImage != NULL && pImage->width != 0 && pImage->height != 0 && pImage->depth != 0)
+ {
+ mpDDB = new ImplSalDDB (pDisplay, hWindow, nScreen, pImage);
+ return True;
+ }
+ return False;
+}
+
+ImplSalDDB* X11SalBitmap::ImplGetDDB( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ const SalTwoRect& rTwoRect ) const
+{
+ if( !mpDDB || !mpDDB->ImplMatches( nScreen, nDrawableDepth, rTwoRect ) )
+ {
+ if( mpDDB )
+ {
+ // do we already have a DIB? if not, create aDIB from current DDB first
+ if( !mpDIB )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0,
+ mpDDB->ImplGetWidth(),
+ mpDDB->ImplGetHeight() );
+ }
+
+ delete mpDDB, const_cast<X11SalBitmap*>(this)->mpDDB = NULL;
+ }
+
+ if( mpCache )
+ mpCache->ImplRemove( const_cast<X11SalBitmap*>(this) );
+
+ SalTwoRect aTwoRect( rTwoRect );
+ if( aTwoRect.mnSrcX < 0 )
+ {
+ aTwoRect.mnSrcWidth += aTwoRect.mnSrcX;
+ aTwoRect.mnSrcX = 0;
+ }
+ if( aTwoRect.mnSrcY < 0 )
+ {
+ aTwoRect.mnSrcHeight += aTwoRect.mnSrcY;
+ aTwoRect.mnSrcY = 0;
+ }
+
+ // create new DDB from DIB
+ const Size aSize( GetSize() );
+ if( aTwoRect.mnSrcWidth == aTwoRect.mnDestWidth &&
+ aTwoRect.mnSrcHeight == aTwoRect.mnDestHeight )
+ {
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
+ }
+ else if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() ||
+ aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() )
+ {
+ // #i47823# this should not happen at all, but does nonetheless
+ // because BitmapEx allows for mask bitmaps of different size
+ // than image bitmap (broken)
+ if( aTwoRect.mnSrcX >= aSize.Width() ||
+ aTwoRect.mnSrcY >= aSize.Height() )
+ return NULL; // this would be a really mad case
+
+ if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() )
+ {
+ aTwoRect.mnSrcWidth = aSize.Width()-aTwoRect.mnSrcX;
+ if( aTwoRect.mnSrcWidth < 1 )
+ {
+ aTwoRect.mnSrcX = 0;
+ aTwoRect.mnSrcWidth = aSize.Width();
+ }
+ }
+ if( aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() )
+ {
+ aTwoRect.mnSrcHeight = aSize.Height() - aTwoRect.mnSrcY;
+ if( aTwoRect.mnSrcHeight < 1 )
+ {
+ aTwoRect.mnSrcY = 0;
+ aTwoRect.mnSrcHeight = aSize.Height();
+ }
+ }
+ }
+
+ XImage* pImage = ImplCreateXImage( GetX11SalData()->GetDisplay(), nScreen,
+ nDrawableDepth, aTwoRect );
+
+ if( pImage )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDDB = new ImplSalDDB( pImage, aDrawable, nScreen, aTwoRect );
+ delete[] pImage->data, pImage->data = NULL;
+ XDestroyImage( pImage );
+
+ if( mpCache )
+ mpCache->ImplAdd( const_cast<X11SalBitmap*>(this), mpDDB->ImplGetMemSize() );
+ }
+ }
+
+ return mpDDB;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplDraw( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ const SalTwoRect& rTwoRect,
+ const GC& rGC ) const
+{
+ ImplGetDDB( aDrawable, nScreen, nDrawableDepth, rTwoRect );
+ if( mpDDB )
+ mpDDB->ImplDraw( aDrawable, nDrawableDepth, rTwoRect, rGC );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
+{
+ Destroy();
+ mpDIB = ImplCreateDIB( rSize, nBitCount, rPal );
+
+ return( mpDIB != NULL );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap& rSSalBmp )
+{
+ Destroy();
+
+ const X11SalBitmap& rSalBmp = static_cast<const X11SalBitmap&>( rSSalBmp );
+
+ if( rSalBmp.mpDIB )
+ {
+ // TODO: reference counting...
+ mpDIB = new BitmapBuffer( *rSalBmp.mpDIB );
+ // TODO: get rid of this when BitmapBuffer gets copy constructor
+ try
+ {
+ mpDIB->mpBits = new sal_uInt8[ mpDIB->mnScanlineSize * mpDIB->mnHeight ];
+ }
+ catch( std::bad_alloc& )
+ {
+ delete mpDIB;
+ mpDIB = NULL;
+ }
+
+ if( mpDIB )
+ memcpy( mpDIB->mpBits, rSalBmp.mpDIB->mpBits, mpDIB->mnScanlineSize * mpDIB->mnHeight );
+ }
+ else if( rSalBmp.mpDDB )
+ ImplCreateFromDrawable( rSalBmp.mpDDB->ImplGetPixmap(),
+ rSalBmp.mpDDB->ImplGetScreen(),
+ rSalBmp.mpDDB->ImplGetDepth(),
+ 0, 0, rSalBmp.mpDDB->ImplGetWidth(), rSalBmp.mpDDB->ImplGetHeight() );
+
+ return( ( !rSalBmp.mpDIB && !rSalBmp.mpDDB ) ||
+ ( rSalBmp.mpDIB && ( mpDIB != NULL ) ) ||
+ ( rSalBmp.mpDDB && ( mpDDB != NULL ) ) );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap&, SalGraphics* )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap&, sal_uInt16 )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::Destroy()
+{
+ if( mpDIB )
+ {
+ delete[] mpDIB->mpBits;
+ delete mpDIB, mpDIB = NULL;
+ }
+
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+
+ if( mpCache )
+ mpCache->ImplRemove( this );
+}
+
+// -----------------------------------------------------------------------------
+
+Size X11SalBitmap::GetSize() const
+{
+ Size aSize;
+
+ if( mpDIB )
+ aSize.Width() = mpDIB->mnWidth, aSize.Height() = mpDIB->mnHeight;
+ else if( mpDDB )
+ aSize.Width() = mpDDB->ImplGetWidth(), aSize.Height() = mpDDB->ImplGetHeight();
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------------
+
+sal_uInt16 X11SalBitmap::GetBitCount() const
+{
+ sal_uInt16 nBitCount;
+
+ if( mpDIB )
+ nBitCount = mpDIB->mnBitCount;
+ else if( mpDDB )
+ nBitCount = mpDDB->ImplGetDepth();
+ else
+ nBitCount = 0;
+
+ return nBitCount;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::AcquireBuffer( bool )
+{
+ if( !mpDIB && mpDDB )
+ {
+ mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0, mpDDB->ImplGetWidth(), mpDDB->ImplGetHeight() );
+ }
+
+ return mpDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ReleaseBuffer( BitmapBuffer*, bool bReadOnly )
+{
+ if( !bReadOnly )
+ {
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+
+ if( mpCache )
+ mpCache->ImplRemove( this );
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::GetSystemData( BitmapSystemData& rData )
+{
+ if( mpDDB )
+ {
+ // Rename/retype pDummy to your likings (though X11 Pixmap is
+ // prolly not a good idea, since it's accessed from
+ // non-platform aware code in vcl/bitmap.hxx)
+ rData.aPixmap = (void*)mpDDB->ImplGetPixmap();
+ rData.mnWidth = mpDDB->ImplGetWidth ();
+ rData.mnHeight = mpDDB->ImplGetHeight ();
+ return true;
+ }
+
+ return false;
+}
+
+// --------------
+// - ImplSalDDB -
+// --------------
+
+ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, int nScreen, const SalTwoRect& rTwoRect ) :
+ maPixmap ( 0 ),
+ maTwoRect ( rTwoRect ),
+ mnDepth ( pImage->depth ),
+ mnScreen ( nScreen )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, ImplGetWidth(), ImplGetHeight(), ImplGetDepth() )) )
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if( 1 == mnDepth )
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1, aValues.background = 0;
+ }
+
+ aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues );
+ XPutImage( pXDisp, maPixmap, aGC, pImage, 0, 0, 0, 0, maTwoRect.mnDestWidth, maTwoRect.mnDestHeight );
+ XFreeGC( pXDisp, aGC );
+ }
+}
+
+// -----------------------------------------------------------------------------------------
+// create from XImage
+
+ImplSalDDB::ImplSalDDB (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage) :
+ mnScreen( nScreen )
+{
+ maPixmap = XCreatePixmap (pDisplay, hWindow, pImage->width, pImage->height, pImage->depth);
+ if (maPixmap != 0)
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if (pImage->depth == 1)
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1;
+ aValues.background = 0;
+ }
+
+ aGC = XCreateGC (pDisplay, maPixmap, nValues, &aValues);
+ XPutImage (pDisplay, maPixmap, aGC, pImage, 0, 0, 0, 0, pImage->width, pImage->height);
+ XFreeGC (pDisplay, aGC);
+
+ maTwoRect.mnSrcX = 0;
+ maTwoRect.mnSrcY = 0;
+ maTwoRect.mnDestX = 0;
+ maTwoRect.mnDestY = 0;
+ maTwoRect.mnSrcWidth = pImage->width;
+ maTwoRect.mnDestWidth = pImage->width;
+ maTwoRect.mnSrcHeight = pImage->height;
+ maTwoRect.mnDestHeight = pImage->height;
+
+ mnDepth = pImage->depth;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalDDB::ImplSalDDB( Drawable aDrawable, int nScreen, long nDrawableDepth, long nX, long nY, long nWidth, long nHeight ) :
+ mnDepth( nDrawableDepth ),
+ mnScreen( nScreen )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, nWidth, nHeight, nDrawableDepth )) )
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if( 1 == mnDepth )
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1, aValues.background = 0;
+ }
+
+ aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues );
+ ImplDraw( aDrawable, nDrawableDepth, maPixmap, mnDepth,
+ nX, nY, nWidth, nHeight, 0, 0, aGC );
+ XFreeGC( pXDisp, aGC );
+
+ maTwoRect.mnSrcX = maTwoRect.mnSrcY = maTwoRect.mnDestX = maTwoRect.mnDestY = 0;
+ maTwoRect.mnSrcWidth = maTwoRect.mnDestWidth = nWidth;
+ maTwoRect.mnSrcHeight = maTwoRect.mnDestHeight = nHeight;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalDDB::~ImplSalDDB()
+{
+ if( maPixmap && ImplGetSVData() )
+ XFreePixmap( GetX11SalData()->GetDisplay()->GetDisplay(), maPixmap );
+}
+
+// -----------------------------------------------------------------------------
+
+bool ImplSalDDB::ImplMatches( int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const
+{
+ bool bRet = sal_False;
+
+ if( ( maPixmap != 0 ) && ( ( mnDepth == nDepth ) || ( 1 == mnDepth ) ) && nScreen == mnScreen)
+ {
+ if( rTwoRect.mnSrcX == maTwoRect.mnSrcX && rTwoRect.mnSrcY == maTwoRect.mnSrcY &&
+ rTwoRect.mnSrcWidth == maTwoRect.mnSrcWidth && rTwoRect.mnSrcHeight == maTwoRect.mnSrcHeight &&
+ rTwoRect.mnDestWidth == maTwoRect.mnDestWidth && rTwoRect.mnDestHeight == maTwoRect.mnDestHeight )
+ {
+ // absolutely indentically
+ bRet = sal_True;
+ }
+ else if( rTwoRect.mnSrcWidth == rTwoRect.mnDestWidth && rTwoRect.mnSrcHeight == rTwoRect.mnDestHeight &&
+ maTwoRect.mnSrcWidth == maTwoRect.mnDestWidth && maTwoRect.mnSrcHeight == maTwoRect.mnDestHeight &&
+ rTwoRect.mnSrcX >= maTwoRect.mnSrcX && rTwoRect.mnSrcY >= maTwoRect.mnSrcY &&
+ ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) <= ( maTwoRect.mnSrcX + maTwoRect.mnSrcWidth ) &&
+ ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) <= ( maTwoRect.mnSrcY + maTwoRect.mnSrcHeight ) )
+ {
+ bRet = sal_True;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalDDB::ImplDraw( Drawable aDrawable, long nDrawableDepth, const SalTwoRect& rTwoRect, const GC& rGC ) const
+{
+ ImplDraw( maPixmap, mnDepth, aDrawable, nDrawableDepth,
+ rTwoRect.mnSrcX - maTwoRect.mnSrcX, rTwoRect.mnSrcY - maTwoRect.mnSrcY,
+ rTwoRect.mnDestWidth, rTwoRect.mnDestHeight,
+ rTwoRect.mnDestX, rTwoRect.mnDestY, rGC );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalDDB::ImplDraw( Drawable aSrcDrawable, long nSrcDrawableDepth,
+ Drawable aDstDrawable, long,
+ long nSrcX, long nSrcY,
+ long nDestWidth, long nDestHeight,
+ long nDestX, long nDestY, const GC& rGC )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( 1 == nSrcDrawableDepth )
+ {
+ XCopyPlane( pXDisp, aSrcDrawable, aDstDrawable, rGC,
+ nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY, 1 );
+ }
+ else
+ {
+ XCopyArea( pXDisp, aSrcDrawable, aDstDrawable, rGC,
+ nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY );
+ }
+}
+
+// ----------------------
+// - ImplSalBitmapCache -
+// ----------------------
+
+struct ImplBmpObj
+{
+ X11SalBitmap* mpBmp;
+ sal_uLong mnMemSize;
+ sal_uLong mnFlags;
+
+ ImplBmpObj( X11SalBitmap* pBmp, sal_uLong nMemSize, sal_uLong nFlags ) :
+ mpBmp( pBmp ), mnMemSize( nMemSize ), mnFlags( nFlags ) {}
+};
+
+// -----------------------------------------------------------------------------
+
+ImplSalBitmapCache::ImplSalBitmapCache() :
+ mnTotalSize( 0UL )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalBitmapCache::~ImplSalBitmapCache()
+{
+ ImplClear();
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplAdd( X11SalBitmap* pBmp, sal_uLong nMemSize, sal_uLong nFlags )
+{
+ ImplBmpObj* pObj;
+ bool bFound = sal_False;
+
+ for( pObj = (ImplBmpObj*) maBmpList.Last(); pObj && !bFound; pObj = (ImplBmpObj*) maBmpList.Prev() )
+ if( pObj->mpBmp == pBmp )
+ bFound = sal_True;
+
+ mnTotalSize += nMemSize;
+
+ if( bFound )
+ {
+ mnTotalSize -= pObj->mnMemSize;
+ pObj->mnMemSize = nMemSize, pObj->mnFlags = nFlags;
+ }
+ else
+ maBmpList.Insert( new ImplBmpObj( pBmp, nMemSize, nFlags ), LIST_APPEND );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplRemove( X11SalBitmap* pBmp )
+{
+ for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.Last(); pObj; pObj = (ImplBmpObj*) maBmpList.Prev() )
+ {
+ if( pObj->mpBmp == pBmp )
+ {
+ maBmpList.Remove( pObj );
+ pObj->mpBmp->ImplRemovedFromCache();
+ mnTotalSize -= pObj->mnMemSize;
+ delete pObj;
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplClear()
+{
+ for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.First(); pObj; pObj = (ImplBmpObj*) maBmpList.Next() )
+ {
+ pObj->mpBmp->ImplRemovedFromCache();
+ delete pObj;
+ }
+
+ maBmpList.Clear();
+ mnTotalSize = 0;
+}
diff --git a/vcl/unx/generic/gdi/salcvt.cxx b/vcl/unx/generic/gdi/salcvt.cxx
new file mode 100644
index 000000000000..c699cdb12335
--- /dev/null
+++ b/vcl/unx/generic/gdi/salcvt.cxx
@@ -0,0 +1,341 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include "salcvt.hxx"
+
+
+SalConverterCache::SalConverterCache()
+{
+}
+
+SalConverterCache*
+SalConverterCache::GetInstance ()
+{
+ static SalConverterCache* pCvt = NULL;
+ if (pCvt == NULL)
+ pCvt = new SalConverterCache;
+
+ return pCvt;
+}
+
+SalConverterCache::~SalConverterCache()
+{
+}
+
+// ---> FIXME
+#include <stdio.h>
+// <---
+
+rtl_UnicodeToTextConverter
+SalConverterCache::GetU2TConverter( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( rConverter.mpU2T == NULL )
+ {
+ rConverter.mpU2T =
+ rtl_createUnicodeToTextConverter( nEncoding );
+// ---> FIXME
+if ( rConverter.mpU2T == NULL )
+ fprintf( stderr, "failed to create Unicode -> %i converter\n", nEncoding);
+// <---
+ }
+ return rConverter.mpU2T;
+ }
+ return NULL;
+}
+
+rtl_TextToUnicodeConverter
+SalConverterCache::GetT2UConverter( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( rConverter.mpT2U == NULL )
+ {
+ rConverter.mpT2U =
+ rtl_createTextToUnicodeConverter( nEncoding );
+// ---> FIXME
+if ( rConverter.mpT2U == NULL )
+ fprintf( stderr, "failed to create %i -> Unicode converter\n", nEncoding );
+// <---
+ }
+ return rConverter.mpT2U;
+ }
+ return NULL;
+}
+
+Bool
+SalConverterCache::IsSingleByteEncoding( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( ! rConverter.mbValid )
+ {
+ rConverter.mbValid = True;
+
+ rtl_TextEncodingInfo aTextEncInfo;
+ aTextEncInfo.StructSize = sizeof( aTextEncInfo );
+ rtl_getTextEncodingInfo( nEncoding, &aTextEncInfo );
+
+ if ( aTextEncInfo.MinimumCharSize == aTextEncInfo.MaximumCharSize
+ && aTextEncInfo.MinimumCharSize == 1)
+ rConverter.mbSingleByteEncoding = True;
+ else
+ rConverter.mbSingleByteEncoding = False;
+ }
+
+ return rConverter.mbSingleByteEncoding;
+ }
+ return False;
+}
+
+// check whether the character set nEncoding contains the unicode
+// code point nChar. This list has been compiled from the according
+// ttmap files in /usr/openwin/lib/X11/fonts/TrueType/ttmap/
+Bool
+SalConverterCache::EncodingHasChar( rtl_TextEncoding nEncoding,
+ sal_Unicode nChar )
+{
+ Bool bMatch = False;
+
+ switch ( nEncoding )
+ {
+ case RTL_TEXTENCODING_DONTKNOW:
+ bMatch = False;
+ break;
+
+ case RTL_TEXTENCODING_MS_1252:
+ case RTL_TEXTENCODING_ISO_8859_1:
+ case RTL_TEXTENCODING_ISO_8859_15:
+ // handle iso8859-15 and iso8859-1 the same (and both with euro)
+ // handle them also like ms1252
+ // this is due to the fact that so many X fonts say they are iso8859-1
+ // but have the other glyphs anyway because they are really ms1252
+ bMatch = ( /*nChar >= 0x0000 &&*/ nChar <= 0x00ff )
+ || ( nChar == 0x20ac )
+ || ( nChar == 0x201a )
+ || ( nChar == 0x0192 )
+ || ( nChar == 0x201e )
+ || ( nChar == 0x2026 )
+ || ( nChar == 0x2020 )
+ || ( nChar == 0x2021 )
+ || ( nChar == 0x02c6 )
+ || ( nChar == 0x2030 )
+ || ( nChar == 0x0160 )
+ || ( nChar == 0x2039 )
+ || ( nChar == 0x0152 )
+ || ( nChar == 0x017d )
+ || ( nChar == 0x2018 )
+ || ( nChar == 0x2019 )
+ || ( nChar == 0x201c )
+ || ( nChar == 0x201d )
+ || ( nChar == 0x2022 )
+ || ( nChar == 0x2013 )
+ || ( nChar == 0x2014 )
+ || ( nChar == 0x02dc )
+ || ( nChar == 0x2122 )
+ || ( nChar == 0x0161 )
+ || ( nChar == 0x203a )
+ || ( nChar == 0x0153 )
+ || ( nChar == 0x017e )
+ || ( nChar == 0x0178 )
+ ;
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_2:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x02c7 && nChar <= 0x02dd );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_4:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x02c7 && nChar <= 0x02db );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_5:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00ad )
+ || ( nChar >= 0x0401 && nChar <= 0x045f )
+ || ( nChar == 0x2116 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_6:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x0600 && nChar <= 0x06ff )
+ || ( nChar >= 0xfb50 && nChar <= 0xfffe );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_7:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00bd )
+ || ( nChar == 0x02bd )
+ || ( nChar >= 0x0384 && nChar <= 0x03ce )
+ || ( nChar >= 0x2014 && nChar <= 0x2019 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_8:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00f7 )
+ || ( nChar >= 0x05d0 && nChar <= 0x05ea )
+ || ( nChar == 0x2017 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_9:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x015f );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_13:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x2019 && nChar <= 0x201e );
+ break;
+
+ /* real case for RTL_TEXTENCODING_ISO_8859_15
+ case RTL_TEXTENCODING_ISO_8859_15:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00ff )
+ || ( nChar >= 0x0152 && nChar <= 0x017e )
+ || ( nChar == 0x20ac );
+ break;
+ */
+
+ case RTL_TEXTENCODING_JIS_X_0201:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0xff61 && nChar <= 0xff9f );
+ break;
+
+ case RTL_TEXTENCODING_MS_1251:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00bb )
+ || ( nChar >= 0x0401 && nChar <= 0x045f )
+ || ( nChar >= 0x0490 && nChar <= 0x0491 )
+ || ( nChar >= 0x2013 && nChar <= 0x203a )
+ || ( nChar >= 0x2116 && nChar <= 0x2122 );
+ break;
+
+ case RTL_TEXTENCODING_KOI8_R:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00b7 )
+ || ( nChar == 0x00f7 )
+ || ( nChar >= 0x0401 && nChar <= 0x0451 )
+ || ( nChar >= 0x2219 && nChar <= 0x221a )
+ || ( nChar >= 0x2248 && nChar <= 0x2265 )
+ || ( nChar >= 0x2320 && nChar <= 0x2321 )
+ || ( nChar >= 0x2500 && nChar <= 0x25a0 );
+ break;
+
+ case RTL_TEXTENCODING_UNICODE:
+ bMatch = True;
+ break;
+
+ case RTL_TEXTENCODING_EUC_KR:
+ case RTL_TEXTENCODING_BIG5:
+ case RTL_TEXTENCODING_GBK:
+ case RTL_TEXTENCODING_GB_2312:
+ case RTL_TEXTENCODING_MS_1361:
+ case RTL_TEXTENCODING_JIS_X_0208:
+
+ // XXX Big5 and Korean EUC contain Ascii chars, but Solaris
+ // *-big5-1 and *-ksc5601.1992-3 fonts dont, in general CJK fonts
+ // are monospaced, so dont trust them for latin chars
+ if (nChar <= 0xFF)
+ {
+ bMatch = False;
+ break;
+ }
+
+ default:
+ // XXX really convert the unicode char into the encoding
+ // and check for conversion errors, this is expensive !
+ rtl_UnicodeToTextConverter aConverter;
+ rtl_UnicodeToTextContext aContext;
+
+ aConverter = GetU2TConverter(nEncoding);
+ aContext = rtl_createUnicodeToTextContext( aConverter );
+
+ // ---> FIXME
+ if ( aConverter == NULL )
+ return False;
+ // <---
+
+ sal_Char pConversionBuffer[ 32 ];
+ sal_uInt32 nConversionInfo;
+ sal_Size nConvertedChars;
+ sal_Size nSize;
+
+ nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ &nChar, 1, pConversionBuffer, sizeof(pConversionBuffer),
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR,
+ &nConversionInfo, &nConvertedChars );
+
+ rtl_destroyUnicodeToTextContext( aConverter, aContext );
+
+ bMatch = (nConvertedChars == 1)
+ && (nSize == 1 || nSize == 2) // XXX Fix me this is a hack
+ && ((nConversionInfo & RTL_UNICODETOTEXT_INFO_ERROR) == 0);
+ break;
+ }
+
+ return bMatch;
+}
+
+// wrapper for rtl_convertUnicodeToText that handles the usual cases for
+// textconversion in drawtext and gettextwidth routines
+sal_Size
+SalConverterCache::ConvertStringUTF16( const sal_Unicode *pText, int nTextLen,
+ sal_Char *pBuffer, sal_Size nBufferSize, rtl_TextEncoding nEncoding )
+{
+ rtl_UnicodeToTextConverter aConverter = GetU2TConverter(nEncoding);
+
+ const sal_uInt32 nCvtFlags =
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
+ | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK ;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+
+ rtl_UnicodeToTextContext aContext =
+ rtl_createUnicodeToTextContext( aConverter );
+
+ sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ pText, nTextLen, pBuffer, nBufferSize,
+ nCvtFlags, &nCvtInfo, &nCvtChars );
+
+ rtl_destroyUnicodeToTextContext( aConverter, aContext );
+
+ return nSize;
+}
+
diff --git a/vcl/unx/generic/gdi/salcvt.hxx b/vcl/unx/generic/gdi/salcvt.hxx
new file mode 100644
index 000000000000..6d0e3bf9650c
--- /dev/null
+++ b/vcl/unx/generic/gdi/salcvt.hxx
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef SAL_CONVERTER_CACHE_HXX_
+#define SAL_CONVERTER_CACHE_HXX_
+
+#include <rtl/tencinfo.h>
+#include <rtl/textcvt.h>
+
+#include <unx/salunx.h>
+
+#include <map>
+
+extern "C" const char*
+pGetEncodingName( rtl_TextEncoding nEncoding );
+
+//
+// Cache TextToUnicode and UnicodeToText converter and conversion info which is
+// used in DrawXYZ routines and in the Event loop
+//
+
+class SalConverterCache {
+
+ public:
+ SalConverterCache();
+ ~SalConverterCache();
+ Bool EncodingHasChar(
+ rtl_TextEncoding nEncoding, sal_Unicode nChar );
+ rtl_UnicodeToTextConverter
+ GetU2TConverter( rtl_TextEncoding nEncoding );
+ rtl_TextToUnicodeConverter
+ GetT2UConverter( rtl_TextEncoding nEncoding );
+ Bool IsSingleByteEncoding( rtl_TextEncoding nEncoding );
+ sal_Size ConvertStringUTF16( const sal_Unicode *pText, int nTextLen,
+ sal_Char *pBuffer, sal_Size nBufferSize,
+ rtl_TextEncoding nEncoding);
+
+ static SalConverterCache*
+ GetInstance ();
+
+ private:
+
+ struct ConverterT {
+ rtl_UnicodeToTextConverter mpU2T;
+ rtl_TextToUnicodeConverter mpT2U;
+ Bool mbSingleByteEncoding;
+ Bool mbValid;
+ ConverterT() :
+ mpU2T( NULL ),
+ mpT2U( NULL ),
+ mbSingleByteEncoding( False ),
+ mbValid( False )
+ {
+ }
+ ~ConverterT()
+ {
+ if( mpU2T )
+ rtl_destroyUnicodeToTextConverter( mpU2T );
+ if( mpT2U )
+ rtl_destroyTextToUnicodeConverter( mpT2U );
+ }
+ };
+
+ std::map< rtl_TextEncoding, ConverterT > m_aConverters;
+};
+
+
+
+#endif /* SAL_CONVERTER_CACHE_HXX_ */
+
diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx
new file mode 100644
index 000000000000..39205ab2e321
--- /dev/null
+++ b/vcl/unx/generic/gdi/salgdi.cxx
@@ -0,0 +1,1273 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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 "region.h"
+
+#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();
+
+ 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_uLong nPoints, const SalPoint *pPtAry )
+{
+ drawPolyLine( nPoints, pPtAry, false );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry, bool bClose )
+{
+ if( nPenColor_ != 0xFFFFFFFF )
+ {
+ SalPolyLine Points( nPoints, pPtAry );
+
+ DrawLines( nPoints, Points, SelectPen(), bClose );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolygon( sal_uLong 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_ != 0xFFFFFFFF )
+ 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_uLong, const SalPoint*, const BYTE* )
+{
+ return sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+sal_Bool X11SalGraphics::drawPolygonBezier( sal_uLong, 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_uLong 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)
+{
+ 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();
+ aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(+fHalfWidth,+fHalfWidth) );
+
+ // 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) );
+
+ 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;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
diff --git a/vcl/unx/generic/gdi/salgdi2.cxx b/vcl/unx/generic/gdi/salgdi2.cxx
new file mode 100644
index 000000000000..314797946ecf
--- /dev/null
+++ b/vcl/unx/generic/gdi/salgdi2.cxx
@@ -0,0 +1,1151 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <poll.h>
+
+#include "vcl/salbtype.hxx"
+
+#include "unx/salunx.h"
+#include "unx/saldata.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/salbmp.h"
+#include "unx/salgdi.h"
+#include "unx/salframe.h"
+#include "unx/salvd.h"
+#include "xrender_peer.hxx"
+
+#include "printergfx.hxx"
+
+#include "vcl/bmpacc.hxx"
+
+#undef SALGDI2_TESTTRANS
+
+// -=-= debugging =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#if 0
+
+static void sal_PrintImage( char *s, XImage*p )
+{
+ fprintf( stderr, "%s %d %d %d\n", s, p->depth, p->width, p->height );
+ int nW = Min( 64, p->width*p->bits_per_pixel >> 3 );
+ for( int i = 0; i < Min( 16, p->height ); i++ )
+ {
+ for( int j = 0; j < nW; j++ )
+ fprintf( stderr, "%02X", (UINT8)p->data[i*p->bytes_per_line+j] );
+ fprintf( stderr, "\n" );
+ }
+}
+
+#endif // DBG_UTIL
+
+// -----------------------------------------------------------------------------
+
+#if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+#define DBG_TESTTRANS( _def_drawable ) \
+{ \
+ XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \
+ 0, 0, \
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight, \
+ 0, 0 ); \
+}
+#else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+#define DBG_TESTTRANS( _def_drawable )
+#endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+
+// -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::CopyScreenArea( Display* pDisplay,
+ Drawable aSrc, int nScreenSrc, int nSrcDepth,
+ Drawable aDest, int nScreenDest, int nDestDepth,
+ GC aDestGC,
+ int src_x, int src_y,
+ unsigned int w, unsigned int h,
+ int dest_x, int dest_y )
+{
+ if( nSrcDepth == nDestDepth )
+ {
+ if( nScreenSrc == nScreenDest )
+ XCopyArea( pDisplay, aSrc, aDest, aDestGC,
+ src_x, src_y, w, h, dest_x, dest_y );
+ else
+ {
+ SalXLib* pLib = GetX11SalData()->GetDisplay()->GetXLib();
+ pLib->PushXErrorLevel( true );
+ XImage* pImage = XGetImage( pDisplay, aSrc, src_x, src_y, w, h,
+ AllPlanes, ZPixmap );
+ if( pImage )
+ {
+ if( pImage->data )
+ {
+ XPutImage( pDisplay, aDest, aDestGC, pImage,
+ 0, 0, dest_x, dest_y, w, h );
+ }
+ XDestroyImage( pImage );
+ }
+ pLib->PopXErrorLevel();
+ }
+ }
+ else
+ {
+ X11SalBitmap aBM;
+ aBM.ImplCreateFromDrawable( aSrc, nScreenSrc, nSrcDepth, src_x, src_y, w, h );
+ SalTwoRect aTwoRect;
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = w;
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = h;
+ aTwoRect.mnDestX = dest_x;
+ aTwoRect.mnDestY = dest_y;
+ aBM.ImplDraw( aDest, nScreenDest, nDestDepth, aTwoRect,aDestGC );
+ }
+}
+
+GC X11SalGraphics::CreateGC( Drawable hDrawable, unsigned long nMask )
+{
+ XGCValues values;
+
+ values.graphics_exposures = False;
+ values.foreground = m_pColormap->GetBlackPixel()
+ ^ m_pColormap->GetWhitePixel();
+ values.function = GXxor;
+ values.line_width = 1;
+ values.fill_style = FillStippled;
+ values.stipple = GetDisplay()->GetInvert50( m_nScreen );
+ values.subwindow_mode = ClipByChildren;
+
+ return XCreateGC( GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetMonoGC( Pixmap hPixmap )
+{
+ if( !pMonoGC_ )
+ pMonoGC_ = CreateGC( hPixmap );
+
+ if( !bMonoGC_ )
+ {
+ SetClipRegion( pMonoGC_ );
+ bMonoGC_ = sal_True;
+ }
+
+ return pMonoGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetCopyGC()
+{
+ if( bXORMode_ ) return GetInvertGC();
+
+ if( !pCopyGC_ )
+ pCopyGC_ = CreateGC( GetDrawable() );
+
+ if( !bCopyGC_ )
+ {
+ SetClipRegion( pCopyGC_ );
+ bCopyGC_ = sal_True;
+ }
+ return pCopyGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::GetInvertGC()
+{
+ if( !pInvertGC_ )
+ pInvertGC_ = CreateGC( GetDrawable(),
+ GCGraphicsExposures
+ | GCForeground
+ | GCFunction
+ | GCLineWidth );
+
+ if( !bInvertGC_ )
+ {
+ SetClipRegion( pInvertGC_ );
+ bInvertGC_ = sal_True;
+ }
+ return pInvertGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::GetInvert50GC()
+{
+ if( !pInvert50GC_ )
+ {
+ XGCValues values;
+
+ values.graphics_exposures = False;
+ values.foreground = m_pColormap->GetWhitePixel();
+ values.background = m_pColormap->GetBlackPixel();
+ values.function = GXinvert;
+ values.line_width = 1;
+ values.line_style = LineSolid;
+ unsigned long nValueMask =
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground
+ | GCFunction
+ | GCLineWidth
+ | GCLineStyle
+ | GCFillStyle
+ | GCStipple;
+
+ char* pEnv = getenv( "SAL_DO_NOT_USE_INVERT50" );
+ if( pEnv && ! strcasecmp( pEnv, "true" ) )
+ {
+ values.fill_style = FillSolid;
+ nValueMask &= ~ GCStipple;
+ }
+ else
+ {
+ values.fill_style = FillStippled;
+ values.stipple = GetDisplay()->GetInvert50( m_nScreen );
+ }
+
+ pInvert50GC_ = XCreateGC( GetXDisplay(), GetDrawable(),
+ nValueMask,
+ &values );
+ }
+
+ if( !bInvert50GC_ )
+ {
+ SetClipRegion( pInvert50GC_ );
+ bInvert50GC_ = sal_True;
+ }
+ return pInvert50GC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetStippleGC()
+{
+ if( !pStippleGC_ )
+ pStippleGC_ = CreateGC( GetDrawable(),
+ GCGraphicsExposures
+ | GCFillStyle
+ | GCLineWidth );
+
+ if( !bStippleGC_ )
+ {
+ XSetFunction( GetXDisplay(), pStippleGC_, bXORMode_ ? GXxor : GXcopy );
+ SetClipRegion( pStippleGC_ );
+ bStippleGC_ = sal_True;
+ }
+
+ return pStippleGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+int X11SalGraphics::Clip( XLIB_Region pRegion,
+ int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY ) const
+{
+ XRectangle aRect;
+ XClipBox( pRegion, &aRect );
+
+ if( int(nX + nDX) <= int(aRect.x) || nX >= int(aRect.x + aRect.width) )
+ return RectangleOut;
+ if( int(nY + nDY) <= int(aRect.y) || nY >= int(aRect.y + aRect.height) )
+ return RectangleOut;
+
+ if( nX < aRect.x )
+ {
+ nSrcX += aRect.x - nX;
+ nDX -= aRect.x - nX;
+ nX = aRect.x;
+ }
+ else if( int(nX + nDX) > int(aRect.x + aRect.width) )
+ nDX = aRect.x + aRect.width - nX;
+
+ if( nY < aRect.y )
+ {
+ nSrcY += aRect.y - nY;
+ nDY -= aRect.y - nY;
+ nY = aRect.y;
+ }
+ else if( int(nY + nDY) > int(aRect.y + aRect.height) )
+ nDY = aRect.y + aRect.height - nY;
+
+ return RectangleIn;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+int X11SalGraphics::Clip( int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY ) const
+
+{
+ if( pPaintRegion_
+ && RectangleOut == Clip( pPaintRegion_, nX, nY, nDX, nDY, nSrcX, nSrcY ) )
+ return RectangleOut;
+
+ if( mpClipRegion
+ && RectangleOut == Clip( mpClipRegion, nX, nY, nDX, nDY, nSrcX, nSrcY ) )
+ return RectangleOut;
+
+ int nPaint;
+ if( pPaintRegion_ )
+ {
+ nPaint = XRectInRegion( pPaintRegion_, nX, nY, nDX, nDY );
+ if( RectangleOut == nPaint )
+ return RectangleOut;
+ }
+ else
+ nPaint = RectangleIn;
+
+ int nClip;
+ if( mpClipRegion )
+ {
+ nClip = XRectInRegion( mpClipRegion, nX, nY, nDX, nDY );
+ if( RectangleOut == nClip )
+ return RectangleOut;
+ }
+ else
+ nClip = RectangleIn;
+
+ return RectangleIn == nClip && RectangleIn == nPaint
+ ? RectangleIn
+ : RectanglePart;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::SetMask( int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY,
+ Pixmap hClipMask )
+{
+ int n = Clip( nX, nY, nDX, nDY, nSrcX, nSrcY );
+ if( RectangleOut == n )
+ return NULL;
+
+ Display *pDisplay = GetXDisplay();
+
+ if( !pMaskGC_ )
+ pMaskGC_ = CreateGC( GetDrawable() );
+
+ if( RectangleIn == n )
+ {
+ XSetClipMask( pDisplay, pMaskGC_, hClipMask );
+ XSetClipOrigin( pDisplay, pMaskGC_, nX - nSrcX, nY - nSrcY );
+ return pMaskGC_;
+ }
+
+ // - - - - create alternate clip pixmap for region clipping - - - -
+ Pixmap hPixmap = XCreatePixmap( pDisplay, hClipMask, nDX, nDY, 1 );
+
+ if( !hPixmap )
+ {
+#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
+ fprintf( stderr, "X11SalGraphics::SetMask !hPixmap\n" );
+#endif
+ return NULL;
+ }
+
+ // - - - - reset pixmap; all 0 - - - - - - - - - - - - - - - - - - -
+ XFillRectangle( pDisplay,
+ hPixmap,
+ GetDisplay()->GetMonoGC( m_nScreen ),
+ 0, 0,
+ nDX, nDY );
+
+ // - - - - copy pixmap only within region - - - - - - - - - - - - -
+ GC pMonoGC = GetMonoGC( hPixmap );
+ XSetClipOrigin( pDisplay, pMonoGC, -nX, -nY );
+ XCopyArea( pDisplay,
+ hClipMask, // Source
+ hPixmap, // Destination
+ pMonoGC,
+ nSrcX, nSrcY, // Source
+ nDX, nDY, // Width & Height
+ 0, 0 ); // Destination
+
+ XSetClipMask( pDisplay, pMaskGC_, hPixmap );
+ XSetClipOrigin( pDisplay, pMaskGC_, nX, nY );
+
+ XFreePixmap( pDisplay, hPixmap );
+ return pMaskGC_;
+}
+
+// -=-= SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+extern "C"
+{
+ static Bool GraphicsExposePredicate( Display*, XEvent* pEvent, XPointer pFrameWindow )
+ {
+ Bool bRet = False;
+ if( (pEvent->type == GraphicsExpose || pEvent->type == NoExpose) &&
+ pEvent->xnoexpose.drawable == (Drawable)pFrameWindow )
+ {
+ bRet = True;
+ }
+ return bRet;
+ }
+}
+
+
+void X11SalGraphics::YieldGraphicsExpose()
+{
+ // get frame if necessary
+ SalFrame* pFrame = m_pFrame;
+ Display* pDisplay = GetXDisplay();
+ XLIB_Window aWindow = GetDrawable();
+ if( ! pFrame )
+ {
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end() && ! pFrame; ++it )
+ {
+ const SystemEnvData* pEnvData = (*it)->GetSystemData();
+ if( Drawable(pEnvData->aWindow) == aWindow )
+ pFrame = *it;
+ }
+ if( ! pFrame )
+ return;
+ }
+
+ XEvent aEvent;
+ while( XCheckTypedWindowEvent( pDisplay, aWindow, Expose, &aEvent ) )
+ {
+ SalPaintEvent aPEvt( aEvent.xexpose.x, aEvent.xexpose.y, aEvent.xexpose.width+1, aEvent.xexpose.height+1 );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+
+ do
+ {
+ if( ! GetDisplay()->XIfEventWithTimeout( &aEvent, (XPointer)aWindow, GraphicsExposePredicate ) )
+ // this should not happen at all; still sometimes it happens
+ break;
+
+ if( aEvent.type == NoExpose )
+ break;
+
+ if( pFrame )
+ {
+ SalPaintEvent aPEvt( aEvent.xgraphicsexpose.x, aEvent.xgraphicsexpose.y, aEvent.xgraphicsexpose.width+1, aEvent.xgraphicsexpose.height+1 );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ } while( aEvent.xgraphicsexpose.count != 0 );
+}
+
+void X11SalGraphics::copyBits( const SalTwoRect *pPosAry,
+ SalGraphics *pSSrcGraphics )
+{
+ X11SalGraphics* pSrcGraphics = pSSrcGraphics
+ ? static_cast<X11SalGraphics*>(pSSrcGraphics)
+ : this;
+
+ if( pPosAry->mnSrcWidth <= 0
+ || pPosAry->mnSrcHeight <= 0
+ || pPosAry->mnDestWidth <= 0
+ || pPosAry->mnDestHeight <= 0 )
+ {
+ return;
+ }
+
+ int n;
+ if( pSrcGraphics == this )
+ {
+ n = 2;
+ }
+ else if( pSrcGraphics->bWindow_ )
+ {
+ // window or compatible virtual device
+ if( pSrcGraphics->GetDisplay() == GetDisplay() &&
+ pSrcGraphics->m_nScreen == m_nScreen &&
+ pSrcGraphics->GetVisual().GetDepth() == GetVisual().GetDepth()
+ )
+ n = 2; // same Display
+ else
+ n = 1; // printer or other display
+ }
+ else if( pSrcGraphics->bVirDev_ )
+ {
+ // printer compatible virtual device
+ if( bPrinter_ )
+ n = 2; // printer or compatible virtual device == same display
+ else
+ n = 1; // window or compatible virtual device
+ }
+ else
+ n = 0;
+
+ if( n == 2
+ && pPosAry->mnSrcWidth == pPosAry->mnDestWidth
+ && pPosAry->mnSrcHeight == pPosAry->mnDestHeight
+ )
+ {
+ // #i60699# Need to generate graphics exposures (to repaint
+ // obscured areas beneath overlapping windows), src and dest
+ // are the same window.
+ const bool bNeedGraphicsExposures( pSrcGraphics == this &&
+ !bVirDev_ &&
+ pSrcGraphics->bWindow_ );
+
+ GC pCopyGC;
+
+ if( bXORMode_
+ && !pSrcGraphics->bVirDev_
+ && (GetDisplay()->GetProperties() & PROPERTY_BUG_XCopyArea_GXxor) )
+ {
+ Pixmap hPixmap = XCreatePixmap( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pSrcGraphics->GetBitCount() );
+
+ pCopyGC = GetDisplay()->GetCopyGC( m_nScreen );
+
+ if( bNeedGraphicsExposures )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ True );
+
+ XCopyArea( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ hPixmap, // destination
+ pCopyGC, // no clipping
+ pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ 0, 0 ); // destination
+ XCopyArea( GetXDisplay(),
+ hPixmap, // source
+ GetDrawable(), // destination
+ GetInvertGC(), // destination clipping
+ 0, 0, // source
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+ XFreePixmap( GetXDisplay(), hPixmap );
+ }
+ else
+ {
+ pCopyGC = GetCopyGC();
+
+ if( bNeedGraphicsExposures )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ True );
+
+ XCopyArea( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ GetDrawable(), // destination
+ pCopyGC, // destination clipping
+ pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+ }
+
+ if( bNeedGraphicsExposures )
+ {
+ YieldGraphicsExpose();
+
+ if( pCopyGC )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ False );
+ }
+ }
+ else if( n )
+ {
+ // #i60699# No chance to handle graphics exposures - we copy
+ // to a temp bitmap first, into which no repaints are
+ // technically possible.
+ SalBitmap *pDDB = pSrcGraphics->getBitmap( pPosAry->mnSrcX,
+ pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth,
+ pPosAry->mnSrcHeight );
+
+ if( !pDDB )
+ {
+ stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" );
+ return;
+ }
+
+ SalTwoRect aPosAry( *pPosAry );
+
+ aPosAry.mnSrcX = 0, aPosAry.mnSrcY = 0;
+ drawBitmap( &aPosAry, *pDDB );
+
+ delete pDDB;
+ }
+ else {
+ stderr0( "X11SalGraphics::CopyBits from Printer not yet implemented\n" );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void X11SalGraphics::copyArea ( long nDestX, long nDestY,
+ long nSrcX, long nSrcY,
+ long nSrcWidth, long nSrcHeight,
+ sal_uInt16 )
+{
+ SalTwoRect aPosAry;
+
+ aPosAry.mnDestX = nDestX;
+ aPosAry.mnDestY = nDestY;
+ aPosAry.mnDestWidth = nSrcWidth;
+ aPosAry.mnDestHeight = nSrcHeight;
+
+ aPosAry.mnSrcX = nSrcX;
+ aPosAry.mnSrcY = nSrcY;
+ aPosAry.mnSrcWidth = nSrcWidth;
+ aPosAry.mnSrcHeight = nSrcHeight;
+
+ copyBits ( &aPosAry, 0 );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ const Drawable aDrawable( GetDrawable() );
+ const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen );
+ const long nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
+ GC aGC( GetCopyGC() );
+ XGCValues aOldVal, aNewVal;
+ int nValues = GCForeground | GCBackground;
+
+ if( rSalBitmap.GetBitCount() == 1 )
+ {
+ // set foreground/background values for 1Bit bitmaps
+ XGetGCValues( pXDisp, aGC, nValues, &aOldVal );
+ aNewVal.foreground = rColMap.GetWhitePixel(), aNewVal.background = rColMap.GetBlackPixel();
+ XChangeGC( pXDisp, aGC, nValues, &aNewVal );
+ }
+
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, m_nScreen, nDepth, *pPosAry, aGC );
+
+ if( rSalBitmap.GetBitCount() == 1 )
+ XChangeGC( pXDisp, aGC, nValues, &aOldVal );
+ XFlush( pXDisp );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSrcBitmap,
+ const SalBitmap& rMaskBitmap )
+{
+ DBG_ASSERT( !bPrinter_, "Drawing of transparent bitmaps on printer devices is strictly forbidden" );
+
+ // decide if alpha masking or transparency masking is needed
+ BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( sal_True );
+ if( pAlphaBuffer != NULL )
+ {
+ int nMaskFormat = pAlphaBuffer->mnFormat;
+ const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, sal_True );
+ if( nMaskFormat == BMP_FORMAT_8BIT_PAL )
+ drawAlphaBitmap( *pPosAry, rSrcBitmap, rMaskBitmap );
+ }
+
+ drawMaskedBitmap( pPosAry, rSrcBitmap, rMaskBitmap );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::drawMaskedBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransBitmap )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ Drawable aDrawable( GetDrawable() );
+
+ // figure work mode depth. If this is a VDev Drawable, use its
+ // bitdepth to create pixmaps for, otherwise, XCopyArea will
+ // refuse to work.
+ const sal_uInt16 nDepth( m_pVDev ?
+ m_pVDev->GetDepth() :
+ pSalDisp->GetVisual( m_nScreen ).GetDepth() );
+ Pixmap aFG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, nDepth ) );
+ Pixmap aBG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, nDepth ) );
+
+ if( aFG && aBG )
+ {
+ GC aTmpGC;
+ XGCValues aValues;
+ const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen );
+ const int nBlack = rColMap.GetBlackPixel(), nWhite = rColMap.GetWhitePixel();
+ const int nValues = GCFunction | GCForeground | GCBackground;
+ SalTwoRect aTmpRect( *pPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0;
+
+ // draw paint bitmap in pixmap #1
+ aValues.function = GXcopy, aValues.foreground = nWhite, aValues.background = nBlack;
+ aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, m_nScreen, nDepth, aTmpRect, aTmpGC );
+ DBG_TESTTRANS( aFG );
+
+ // draw background in pixmap #2
+ XCopyArea( pXDisp, aDrawable, aBG, aTmpGC,
+ pPosAry->mnDestX, pPosAry->mnDestY,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ 0, 0 );
+
+ DBG_TESTTRANS( aBG );
+
+ // mask out paint bitmap in pixmap #1 (transparent areas 0)
+ aValues.function = GXand, aValues.foreground = 0x00000000, aValues.background = 0xffffffff;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, m_nScreen, 1, aTmpRect, aTmpGC );
+
+ DBG_TESTTRANS( aFG );
+
+ // #105055# For XOR mode, keep background behind bitmap intact
+ if( !bXORMode_ )
+ {
+ // mask out background in pixmap #2 (nontransparent areas 0)
+ aValues.function = GXand, aValues.foreground = 0xffffffff, aValues.background = 0x00000000;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, m_nScreen, 1, aTmpRect, aTmpGC );
+
+ DBG_TESTTRANS( aBG );
+ }
+
+ // merge pixmap #1 and pixmap #2 in pixmap #2
+ aValues.function = GXxor, aValues.foreground = 0xffffffff, aValues.background = 0x00000000;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ XCopyArea( pXDisp, aFG, aBG, aTmpGC,
+ 0, 0,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ 0, 0 );
+ DBG_TESTTRANS( aBG );
+
+ // #105055# Disable XOR temporarily
+ sal_Bool bOldXORMode( bXORMode_ );
+ bXORMode_ = sal_False;
+
+ // copy pixmap #2 (result) to background
+ XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(),
+ 0, 0,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+
+ DBG_TESTTRANS( aBG );
+
+ bXORMode_ = bOldXORMode;
+
+ XFreeGC( pXDisp, aTmpGC );
+ XFlush( pXDisp );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap );
+
+ if( aFG )
+ XFreePixmap( pXDisp, aFG );
+
+ if( aBG )
+ XFreePixmap( pXDisp, aBG );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool X11SalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
+ const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp )
+{
+ // non 8-bit alpha not implemented yet
+ if( rAlphaBmp.GetBitCount() != 8 )
+ return false;
+
+ // horizontal mirroring not implemented yet
+ if( rTR.mnDestWidth < 0 )
+ return false;
+
+ // stretched conversion is not implemented yet
+ if( rTR.mnDestWidth != rTR.mnSrcWidth )
+ return false;
+ if( rTR.mnDestHeight!= rTR.mnSrcHeight )
+ return false;
+
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() < 0x02 )
+ return false;
+
+ // create destination picture
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return false;
+
+ const SalDisplay* pSalDisp = GetDisplay();
+ const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen );
+ Display* pXDisplay = pSalDisp->GetDisplay();
+
+ // create source Picture
+ int nDepth = m_pVDev ? m_pVDev->GetDepth() : rSalVis.GetDepth();
+ const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap );
+ ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( hDrawable_, m_nScreen, nDepth, rTR );
+ if( !pSrcDDB )
+ return false;
+
+ //#i75249# workaround for ImplGetDDB() giving us back a different depth than
+ // we requested. E.g. mask pixmaps are always compatible with the drawable
+ // TODO: find an appropriate picture format for these cases
+ // then remove the workaround below and the one for #i75531#
+ if( nDepth != pSrcDDB->ImplGetDepth() )
+ return false;
+
+ Pixmap aSrcPM = pSrcDDB->ImplGetPixmap();
+ if( !aSrcPM )
+ return false;
+
+ // create source picture
+ // TODO: use scoped picture
+ Visual* pSrcXVisual = rSalVis.GetVisual();
+ XRenderPictFormat* pSrcVisFmt = rPeer.FindVisualFormat( pSrcXVisual );
+ if( !pSrcVisFmt )
+ return false;
+ Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, NULL );
+ if( !aSrcPic )
+ return false;
+
+ // create alpha Picture
+
+ // TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap
+ // problem is that they don't provide an 8bit Pixmap on a non-8bit display
+ BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( sal_True );
+
+ // an XImage needs its data top_down
+ // TODO: avoid wrongly oriented images in upper layers!
+ const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize;
+ const char* pSrcBits = (char*)pAlphaBuffer->mpBits;
+ char* pAlphaBits = new char[ nImageSize ];
+ if( BMP_SCANLINE_ADJUSTMENT( pAlphaBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ memcpy( pAlphaBits, pSrcBits, nImageSize );
+ else
+ {
+ char* pDstBits = pAlphaBits + nImageSize;
+ const int nLineSize = pAlphaBuffer->mnScanlineSize;
+ for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize )
+ memcpy( pDstBits, pSrcBits, nLineSize );
+ }
+
+ // the alpha values need to be inverted for XRender
+ // TODO: make upper layers use standard alpha
+ long* pLDst = (long*)pAlphaBits;
+ for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst )
+ *pLDst = ~*pLDst;
+
+ char* pCDst = (char*)pLDst;
+ for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst )
+ *pCDst = ~*pCDst;
+
+ const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8();
+ XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0,
+ pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight,
+ pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize );
+
+ Pixmap aAlphaPM = XCreatePixmap( pXDisplay, hDrawable_,
+ rTR.mnDestWidth, rTR.mnDestHeight, 8 );
+
+ XGCValues aAlphaGCV;
+ aAlphaGCV.function = GXcopy;
+ GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV );
+ XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg,
+ rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight );
+ XFreeGC( pXDisplay, aAlphaGC );
+ XFree( pAlphaImg );
+ if( pAlphaBits != (char*)pAlphaBuffer->mpBits )
+ delete[] pAlphaBits;
+
+ const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, sal_True );
+
+ XRenderPictureAttributes aAttr;
+ aAttr.repeat = true;
+ Picture aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr );
+ if( !aAlphaPic )
+ return false;
+
+ // set clipping
+ if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
+ rPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
+
+ // paint source * mask over destination picture
+ rPeer.CompositePicture( PictOpOver, aSrcPic, aAlphaPic, aDstPic,
+ rTR.mnSrcX, rTR.mnSrcY, 0, 0,
+ rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight );
+
+ // TODO: used ScopedPic
+ rPeer.FreePicture( aAlphaPic );
+ XFreePixmap(pXDisplay, aAlphaPM);
+ rPeer.FreePicture( aSrcPic );
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool X11SalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency )
+{
+ if( ! m_pFrame && ! m_pVDev )
+ return false;
+
+ if( bPenGC_ || !bBrushGC_ || bXORMode_ )
+ return false; // can only perform solid fills without XOR.
+
+ if( m_pVDev && m_pVDev->GetDepth() < 8 )
+ return false;
+
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() < 0x02 ) // TODO: replace with better test
+ return false;
+
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return false;
+
+ const double fTransparency = (100 - nTransparency) * (1.0/100);
+ const XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency);
+
+ rPeer.FillRectangle( PictOpOver,
+ aDstPic,
+ &aRenderColor,
+ nX, nY,
+ nWidth, nHeight );
+
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ SalColor )
+{
+ DBG_ERROR( "::DrawBitmap with transparent color not supported" );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap &rSalBitmap,
+ SalColor nMaskColor )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ Drawable aDrawable( GetDrawable() );
+ Pixmap aStipple( XCreatePixmap( pXDisp, aDrawable,
+ pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, 1 ) );
+
+ if( aStipple )
+ {
+ SalTwoRect aTwoRect( *pPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ GC aTmpGC;
+ XGCValues aValues;
+
+ // create a stipple bitmap first (set bits are changed to unset bits and vice versa)
+ aValues.function = GXcopyInverted;
+ aValues.foreground = 1, aValues.background = 0;
+ aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues );
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, m_nScreen, 1, aTwoRect, aTmpGC );
+
+ XFreeGC( pXDisp, aTmpGC );
+
+ // Set stipple and draw rectangle
+ GC aStippleGC( GetStippleGC() );
+ int nX = pPosAry->mnDestX, nY = pPosAry->mnDestY;
+
+ XSetStipple( pXDisp, aStippleGC, aStipple );
+ XSetTSOrigin( pXDisp, aStippleGC, nX, nY );
+ XSetForeground( pXDisp, aStippleGC, GetPixel( nMaskColor ) );
+ XFillRectangle( pXDisp, aDrawable, aStippleGC,
+ nX, nY,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight );
+ XFreePixmap( pXDisp, aStipple );
+ XFlush( pXDisp );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalBitmap *X11SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
+{
+ if( bPrinter_ && !bVirDev_ )
+ return NULL;
+
+ bool bFakeWindowBG = false;
+
+ // normalize
+ if( nDX < 0 )
+ {
+ nX += nDX;
+ nDX = -nDX;
+ }
+ if ( nDY < 0 )
+ {
+ nY += nDY;
+ nDY = -nDY;
+ }
+
+ if( bWindow_ && !bVirDev_ )
+ {
+ XWindowAttributes aAttrib;
+
+ XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib );
+ if( aAttrib.map_state != IsViewable )
+ bFakeWindowBG = true;
+ else
+ {
+ long nOrgDX = nDX, nOrgDY = nDY;
+
+ // clip to window size
+ if ( nX < 0 )
+ {
+ nDX += nX;
+ nX = 0;
+ }
+ if ( nY < 0 )
+ {
+ nDY += nY;
+ nY = 0;
+ }
+ if( nX + nDX > aAttrib.width )
+ nDX = aAttrib.width - nX;
+ if( nY + nDY > aAttrib.height )
+ nDY = aAttrib.height - nY;
+
+ // inside ?
+ if( nDX <= 0 || nDY <= 0 )
+ {
+ bFakeWindowBG = true;
+ nDX = nOrgDX;
+ nDY = nOrgDY;
+ }
+ }
+ }
+
+ X11SalBitmap* pSalBitmap = new X11SalBitmap;
+ sal_uInt16 nBitCount = GetBitCount();
+
+ if( &GetDisplay()->GetColormap( m_nScreen ) != &GetColormap() )
+ nBitCount = 1;
+
+ if( ! bFakeWindowBG )
+ pSalBitmap->ImplCreateFromDrawable( GetDrawable(), m_nScreen, nBitCount, nX, nY, nDX, nDY );
+ else
+ pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) );
+
+ return pSalBitmap;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColor X11SalGraphics::getPixel( long nX, long nY )
+{
+ if( bWindow_ && !bVirDev_ )
+ {
+ XWindowAttributes aAttrib;
+
+ XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib );
+ if( aAttrib.map_state != IsViewable )
+ {
+ stderr0( "X11SalGraphics::GetPixel drawable not viewable\n" );
+ return 0;
+ }
+ }
+
+ XImage *pXImage = XGetImage( GetXDisplay(),
+ GetDrawable(),
+ nX, nY,
+ 1, 1,
+ AllPlanes,
+ ZPixmap );
+ if( !pXImage )
+ {
+ stderr0( "X11SalGraphics::GetPixel !XGetImage()\n" );
+ return 0;
+ }
+
+ XColor aXColor;
+
+ aXColor.pixel = XGetPixel( pXImage, 0, 0 );
+ XDestroyImage( pXImage );
+
+ return GetColormap().GetColor( aXColor.pixel );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::invert( long nX,
+ long nY,
+ long nDX,
+ long nDY,
+ SalInvert nFlags )
+{
+ GC pGC;
+ if( SAL_INVERT_50 & nFlags )
+ {
+ pGC = GetInvert50GC();
+ XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ else
+ {
+ if ( SAL_INVERT_TRACKFRAME & nFlags )
+ {
+ pGC = GetTrackingGC();
+ XDrawRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ else
+ {
+ pGC = GetInvertGC();
+ XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ }
+}
+
+bool X11SalGraphics::supportsOperation( OutDevSupportType eType ) const
+{
+ bool bRet = false;
+ switch( eType )
+ {
+ case OutDevSupport_TransparentRect:
+ case OutDevSupport_B2DDraw:
+ {
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() >= 0x02 )
+ {
+ const SalDisplay* pSalDisp = GetDisplay();
+ const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen );
+
+ Visual* pDstXVisual = rSalVis.GetVisual();
+ XRenderPictFormat* pDstVisFmt = rPeer.FindVisualFormat( pDstXVisual );
+ if( pDstVisFmt )
+ bRet = true;
+ }
+ }
+ break;
+ default: break;
+ }
+ return bRet;
+}
+
diff --git a/vcl/unx/generic/gdi/salgdi3.cxx b/vcl/unx/generic/gdi/salgdi3.cxx
new file mode 100644
index 000000000000..fc278dd250eb
--- /dev/null
+++ b/vcl/unx/generic/gdi/salgdi3.cxx
@@ -0,0 +1,1690 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "sal/alloca.h"
+#include "sal/types.h"
+
+#include "rtl/tencinfo.h"
+
+#include "osl/file.hxx"
+
+#include "tools/string.hxx"
+#include "tools/debug.hxx"
+#include "tools/stream.hxx"
+
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+
+#include "i18npool/mslangid.hxx"
+
+#include <vcl/sysdata.hxx>
+#include "printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/svapp.hxx"
+
+#include "unx/salunx.h"
+#include "unx/saldata.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/salgdi.h"
+#include "unx/pspgraphics.h"
+#include "unx/salvd.h"
+
+#include "salcvt.hxx"
+#include "gcach_xpeer.hxx"
+#include "xrender_peer.hxx"
+#include "impfont.hxx"
+#include "salframe.hxx"
+#include "outdev.h"
+
+
+#include <hash_set>
+
+#ifdef ENABLE_GRAPHITE
+#include <graphite_layout.hxx>
+#include <graphite_serverfont.hxx>
+#endif
+
+struct cairo_surface_t;
+struct cairo_t;
+struct cairo_font_face_t;
+typedef void* FT_Face;
+struct cairo_matrix_t {
+ double xx; double yx;
+ double xy; double yy;
+ double x0; double y0;
+};
+struct cairo_glyph_t
+{
+ unsigned long index;
+ double x;
+ double y;
+};
+struct BOX
+{
+ short x1, x2, y1, y2;
+};
+struct _XRegion
+{
+ long size;
+ long numRects;
+ BOX *rects;
+ BOX extents;
+};
+using namespace rtl;
+
+// ===========================================================================
+
+// PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
+class PspKernInfo : public ExtraKernInfo
+{
+public:
+ PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {}
+protected:
+ virtual void Initialize() const;
+};
+
+//--------------------------------------------------------------------------
+
+void PspKernInfo::Initialize() const
+{
+ mbInitialized = true;
+
+ // get the kerning pairs from psprint
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ typedef std::list< psp::KernPair > PspKernPairs;
+ const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId );
+ if( rKernPairs.empty() )
+ return;
+
+ // feed psprint's kerning list into a lookup-friendly container
+ maUnicodeKernPairs.resize( rKernPairs.size() );
+ PspKernPairs::const_iterator it = rKernPairs.begin();
+ for(; it != rKernPairs.end(); ++it )
+ {
+ ImplKernPairData aKernPair = { it->first, it->second, it->kern_x };
+ maUnicodeKernPairs.insert( aKernPair );
+ }
+}
+
+// ----------------------------------------------------------------------------
+//
+// X11SalGraphics
+//
+// ----------------------------------------------------------------------------
+
+GC
+X11SalGraphics::GetFontGC()
+{
+ Display *pDisplay = GetXDisplay();
+
+ if( !pFontGC_ )
+ {
+ XGCValues values;
+ values.subwindow_mode = ClipByChildren;
+ values.fill_rule = EvenOddRule; // Pict import/ Gradient
+ values.graphics_exposures = False;
+ values.foreground = nTextPixel_;
+ pFontGC_ = XCreateGC( pDisplay, hDrawable_,
+ GCSubwindowMode | GCFillRule
+ | GCGraphicsExposures | GCForeground,
+ &values );
+ }
+ if( !bFontGC_ )
+ {
+ XSetForeground( pDisplay, pFontGC_, nTextPixel_ );
+ SetClipRegion( pFontGC_ );
+ bFontGC_ = sal_True;
+ }
+
+ return pFontGC_;
+}
+
+//--------------------------------------------------------------------------
+
+bool X11SalGraphics::setFont( const ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+#ifdef HDU_DEBUG
+ ByteString aReqName( "NULL" );
+ if( pEntry )
+ aReqName = ByteString( pEntry->maName, RTL_TEXTENCODING_UTF8 );
+ ByteString aUseName( "NULL" );
+ if( pEntry && pEntry->mpFontData )
+ aUseName = ByteString( pEntry->mpFontData->GetFamilyName(), RTL_TEXTENCODING_UTF8 );
+ fprintf( stderr, "SetFont(lvl=%d,\"%s\", %d*%d, naa=%d,b=%d,i=%d) => \"%s\"\n",
+ nFallbackLevel, aReqName.GetBuffer(),
+ !pEntry?-1:pEntry->mnWidth, !pEntry?-1:pEntry->mnHeight,
+ !pEntry?-1:pEntry->mbNonAntialiased,
+ !pEntry?-1:pEntry->meWeight, !pEntry?-1:pEntry->meItalic,
+ aUseName.GetBuffer() );
+#endif
+
+ // release all no longer needed font resources
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mpServerFont[i] != NULL )
+ {
+ // old server side font is no longer referenced
+ GlyphCache::GetInstance().UncacheFont( *mpServerFont[i] );
+ mpServerFont[i] = NULL;
+ }
+ }
+
+ // return early if there is no new font
+ if( !pEntry )
+ return false;
+
+ bFontVertical_ = pEntry->mbVertical;
+
+ // return early if this is not a valid font for this graphics
+ if( !pEntry->mpFontData )
+ return false;
+
+ // handle the request for a non-native X11-font => use the GlyphCache
+ ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
+ if( pServerFont != NULL )
+ {
+ // ignore fonts with e.g. corrupted font files
+ if( !pServerFont->TestFont() )
+ {
+ GlyphCache::GetInstance().UncacheFont( *pServerFont );
+ return false;
+ }
+
+ // register to use the font
+ mpServerFont[ nFallbackLevel ] = pServerFont;
+
+ // apply font specific-hint settings if needed
+ // TODO: also disable it for reference devices
+ if( !bPrinter_ )
+ {
+ ImplServerFontEntry* pSFE = static_cast<ImplServerFontEntry*>( pEntry->mpFontEntry );
+ pSFE->HandleFontOptions();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void ImplServerFontEntry::HandleFontOptions( void )
+{
+ bool GetFCFontOptions( const ImplFontAttributes&, int nSize, ImplFontOptions& );
+
+ if( !mpServerFont )
+ return;
+ if( !mbGotFontOptions )
+ {
+ // get and cache the font options
+ mbGotFontOptions = true;
+ mbValidFontOptions = GetFCFontOptions( *maFontSelData.mpFontData,
+ maFontSelData.mnHeight, maFontOptions );
+ }
+ // apply the font options
+ if( mbValidFontOptions )
+ mpServerFont->SetFontOptions( maFontOptions );
+}
+
+//--------------------------------------------------------------------------
+
+namespace {
+
+class CairoWrapper
+{
+private:
+ oslModule mpCairoLib;
+
+ cairo_surface_t* (*mp_xlib_surface_create_with_xrender_format)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int );
+ void (*mp_surface_destroy)(cairo_surface_t *);
+ cairo_t* (*mp_create)(cairo_surface_t *);
+ void (*mp_destroy)(cairo_t*);
+ void (*mp_clip)(cairo_t*);
+ void (*mp_rectangle)(cairo_t*, double, double, double, double);
+ cairo_font_face_t * (*mp_ft_font_face_create_for_ft_face)(FT_Face, int);
+ void (*mp_set_font_face)(cairo_t *, cairo_font_face_t *);
+ void (*mp_font_face_destroy)(cairo_font_face_t *);
+ void (*mp_matrix_init_identity)(cairo_matrix_t *);
+ void (*mp_matrix_scale)(cairo_matrix_t *, double, double);
+ void (*mp_matrix_rotate)(cairo_matrix_t *, double);
+ void (*mp_set_font_matrix)(cairo_t *, const cairo_matrix_t *);
+ void (*mp_show_glyphs)(cairo_t *, const cairo_glyph_t *, int );
+ void (*mp_set_source_rgb)(cairo_t *, double , double , double );
+ void (*mp_set_font_options)(cairo_t *, const void *);
+ void (*mp_ft_font_options_substitute)(const void*, void*);
+
+ bool canEmbolden() const { return false; }
+
+ CairoWrapper();
+public:
+ static CairoWrapper& get();
+ bool isValid() const { return (mpCairoLib != NULL); }
+ bool isCairoRenderable(const ServerFont& rFont);
+
+ cairo_surface_t* xlib_surface_create_with_xrender_format(Display *pDisplay, Drawable drawable, Screen *pScreen, XRenderPictFormat *pFormat, int width, int height)
+ { return (*mp_xlib_surface_create_with_xrender_format)(pDisplay, drawable, pScreen, pFormat, width, height); }
+ void surface_destroy(cairo_surface_t *surface) { (*mp_surface_destroy)(surface); }
+ cairo_t* create(cairo_surface_t *surface) { return (*mp_create)(surface); }
+ void destroy(cairo_t *cr) { (*mp_destroy)(cr); }
+ void clip(cairo_t *cr) { (*mp_clip)(cr); }
+ void rectangle(cairo_t *cr, double x, double y, double width, double height)
+ { (*mp_rectangle)(cr, x, y, width, height); }
+ cairo_font_face_t* ft_font_face_create_for_ft_face(FT_Face face, int load_flags)
+ { return (*mp_ft_font_face_create_for_ft_face)(face, load_flags); }
+ void set_font_face(cairo_t *cr, cairo_font_face_t *font_face)
+ { (*mp_set_font_face)(cr, font_face); }
+ void font_face_destroy(cairo_font_face_t *font_face)
+ { (*mp_font_face_destroy)(font_face); }
+ void matrix_init_identity(cairo_matrix_t *matrix)
+ { (*mp_matrix_init_identity)(matrix); }
+ void matrix_scale(cairo_matrix_t *matrix, double sx, double sy)
+ { (*mp_matrix_scale)(matrix, sx, sy); }
+ void matrix_rotate(cairo_matrix_t *matrix, double radians)
+ { (*mp_matrix_rotate)(matrix, radians); }
+ void set_font_matrix(cairo_t *cr, const cairo_matrix_t *matrix)
+ { (*mp_set_font_matrix)(cr, matrix); }
+ void show_glyphs(cairo_t *cr, const cairo_glyph_t *glyphs, int no_glyphs)
+ { (*mp_show_glyphs)(cr, glyphs, no_glyphs); }
+ void set_source_rgb(cairo_t *cr, double red, double green, double blue)
+ { (*mp_set_source_rgb)(cr, red, green, blue); }
+ void set_font_options(cairo_t *cr, const void *options)
+ { (*mp_set_font_options)(cr, options); }
+ void ft_font_options_substitute(const void *options, void *pattern)
+ { (*mp_ft_font_options_substitute)(options, pattern); }
+};
+
+static CairoWrapper* pCairoInstance = NULL;
+
+CairoWrapper& CairoWrapper::get()
+{
+ if( ! pCairoInstance )
+ pCairoInstance = new CairoWrapper();
+ return *pCairoInstance;
+}
+
+CairoWrapper::CairoWrapper()
+: mpCairoLib( NULL )
+{
+ static const char* pDisableCairoText = getenv( "SAL_DISABLE_CAIROTEXT" );
+ if( pDisableCairoText && (pDisableCairoText[0] != '0') )
+ return;
+
+ int nDummy;
+ if( !XQueryExtension( GetX11SalData()->GetDisplay()->GetDisplay(), "RENDER", &nDummy, &nDummy, &nDummy ) )
+ return;
+
+#ifdef MACOSX
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libcairo.2.dylib" ));
+#else
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libcairo.so.2" ));
+#endif
+ mpCairoLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if( !mpCairoLib )
+ return;
+
+#ifdef DEBUG
+ // check cairo version
+ int (*p_version)();
+ p_version = (int(*)()) osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_version" );
+ const int nVersion = p_version ? (*p_version)() : 0;
+ fprintf( stderr, "CAIRO version=%d\n", nVersion );
+#endif
+
+ mp_xlib_surface_create_with_xrender_format = (cairo_surface_t* (*)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_xlib_surface_create_with_xrender_format" );
+ mp_surface_destroy = (void(*)(cairo_surface_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_surface_destroy" );
+ mp_create = (cairo_t*(*)(cairo_surface_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_create" );
+ mp_destroy = (void(*)(cairo_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_destroy" );
+ mp_clip = (void(*)(cairo_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_clip" );
+ mp_rectangle = (void(*)(cairo_t*, double, double, double, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_rectangle" );
+ mp_ft_font_face_create_for_ft_face = (cairo_font_face_t * (*)(FT_Face, int))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_face_create_for_ft_face" );
+ mp_set_font_face = (void (*)(cairo_t *, cairo_font_face_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_face" );
+ mp_font_face_destroy = (void (*)(cairo_font_face_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_font_face_destroy" );
+ mp_matrix_init_identity = (void (*)(cairo_matrix_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_init_identity" );
+ mp_matrix_scale = (void (*)(cairo_matrix_t *, double, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_scale" );
+ mp_matrix_rotate = (void (*)(cairo_matrix_t *, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_rotate" );
+ mp_set_font_matrix = (void (*)(cairo_t *, const cairo_matrix_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_matrix" );
+ mp_show_glyphs = (void (*)(cairo_t *, const cairo_glyph_t *, int ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_show_glyphs" );
+ mp_set_source_rgb = (void (*)(cairo_t *, double , double , double ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_source_rgb" );
+ mp_set_font_options = (void (*)(cairo_t *, const void *options ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_options" );
+ mp_ft_font_options_substitute = (void (*)(const void *, void *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_options_substitute" );
+
+ if( !(
+ mp_xlib_surface_create_with_xrender_format &&
+ mp_surface_destroy &&
+ mp_create &&
+ mp_destroy &&
+ mp_clip &&
+ mp_rectangle &&
+ mp_ft_font_face_create_for_ft_face &&
+ mp_set_font_face &&
+ mp_font_face_destroy &&
+ mp_matrix_init_identity &&
+ mp_matrix_scale &&
+ mp_matrix_rotate &&
+ mp_set_font_matrix &&
+ mp_show_glyphs &&
+ mp_set_source_rgb &&
+ mp_set_font_options &&
+ mp_ft_font_options_substitute
+ ) )
+ {
+ osl_unloadModule( mpCairoLib );
+ mpCairoLib = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not all needed symbols were found\n" );
+#endif
+ }
+}
+
+bool CairoWrapper::isCairoRenderable(const ServerFont& rFont)
+{
+ return rFont.GetFtFace() && isValid() && rFont.GetAntialiasAdvice() &&
+ (rFont.NeedsArtificialBold() ? canEmbolden() : true);
+}
+
+} //namespace
+
+CairoFontsCache::LRUFonts CairoFontsCache::maLRUFonts;
+int CairoFontsCache::mnRefCount = 0;
+
+CairoFontsCache::CairoFontsCache()
+{
+ ++mnRefCount;
+}
+
+CairoFontsCache::~CairoFontsCache()
+{
+ --mnRefCount;
+ if (!mnRefCount && !maLRUFonts.empty())
+ {
+ CairoWrapper &rCairo = CairoWrapper::get();
+ LRUFonts::iterator aEnd = maLRUFonts.end();
+ for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
+ rCairo.font_face_destroy((cairo_font_face_t*)aI->first);
+ }
+}
+
+void CairoFontsCache::CacheFont(void *pFont, void* pId)
+{
+ maLRUFonts.push_front( std::pair<void*, void *>(pFont, pId) );
+ if (maLRUFonts.size() > 8)
+ {
+ CairoWrapper &rCairo = CairoWrapper::get();
+ rCairo.font_face_destroy((cairo_font_face_t*)maLRUFonts.back().first);
+ maLRUFonts.pop_back();
+ }
+}
+
+void* CairoFontsCache::FindCachedFont(void *pId)
+{
+ LRUFonts::iterator aEnd = maLRUFonts.end();
+ for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
+ if (aI->second == pId)
+ return aI->first;
+ return NULL;
+}
+
+void X11SalGraphics::DrawCairoAAFontString( const ServerFontLayout& rLayout )
+{
+ std::vector<cairo_glyph_t> cairo_glyphs;
+ cairo_glyphs.reserve( 256 );
+
+ Point aPos;
+ sal_GlyphId aGlyphId;
+ for( int nStart = 0; rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
+ {
+ cairo_glyph_t aGlyph;
+ aGlyph.index = aGlyphId & GF_IDXMASK;
+ aGlyph.x = aPos.X();
+ aGlyph.y = aPos.Y();
+ cairo_glyphs.push_back(aGlyph);
+ }
+
+ if (cairo_glyphs.empty())
+ return;
+
+ // find a XRenderPictFormat compatible with the Drawable
+ XRenderPictFormat* pVisualFormat = static_cast<XRenderPictFormat*>(GetXRenderFormat());
+ if( !pVisualFormat )
+ {
+ Visual* pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
+ pVisualFormat = XRenderPeer::GetInstance().FindVisualFormat( pVisual );
+ // cache the XRenderPictFormat
+ SetXRenderFormat( static_cast<void*>(pVisualFormat) );
+ }
+
+ DBG_ASSERT( pVisualFormat!=NULL, "no matching XRenderPictFormat for text" );
+ if( !pVisualFormat )
+ return;
+
+ CairoWrapper &rCairo = CairoWrapper::get();
+
+ Display* pDisplay = GetXDisplay();
+
+ cairo_surface_t *surface = rCairo.xlib_surface_create_with_xrender_format (pDisplay,
+ hDrawable_, ScreenOfDisplay(pDisplay, m_nScreen), pVisualFormat, SAL_MAX_INT16, SAL_MAX_INT16);
+
+ /*
+ * It might be ideal to cache surface and cairo context between calls and
+ * only destroy it when the drawable changes, but to do that we need to at
+ * least change the SalFrame etc impls to dtor the SalGraphics *before* the
+ * destruction of the windows they reference
+ */
+ cairo_t *cr = rCairo.create(surface);
+ rCairo.surface_destroy(surface);
+
+ if (const void *pOptions = Application::GetSettings().GetStyleSettings().GetCairoFontOptions())
+ rCairo.set_font_options( cr, pOptions);
+
+ if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
+ {
+ for (long i = 0; i < mpClipRegion->numRects; ++i)
+ {
+ rCairo.rectangle(cr,
+ mpClipRegion->rects[i].x1,
+ mpClipRegion->rects[i].y1,
+ mpClipRegion->rects[i].x2 - mpClipRegion->rects[i].x1,
+ mpClipRegion->rects[i].y2 - mpClipRegion->rects[i].y1);
+ }
+ rCairo.clip(cr);
+ }
+
+ rCairo.set_source_rgb(cr,
+ SALCOLOR_RED(nTextColor_)/255.0,
+ SALCOLOR_GREEN(nTextColor_)/255.0,
+ SALCOLOR_BLUE(nTextColor_)/255.0);
+
+ ServerFont& rFont = rLayout.GetServerFont();
+
+ cairo_font_face_t* font_face = NULL;
+
+ void *pId = rFont.GetFtFace();
+ font_face = (cairo_font_face_t*)m_aCairoFontsCache.FindCachedFont(pId);
+ if (!font_face)
+ {
+ font_face = rCairo.ft_font_face_create_for_ft_face(pId, rFont.GetLoadFlags());
+ m_aCairoFontsCache.CacheFont(font_face, pId);
+ }
+
+ rCairo.set_font_face(cr, font_face);
+
+ cairo_matrix_t m;
+ const ImplFontSelectData& rFSD = rFont.GetFontSelData();
+ int nWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
+
+ rCairo.matrix_init_identity(&m);
+
+ if (rLayout.GetOrientation())
+ rCairo.matrix_rotate(&m, (3600 - rLayout.GetOrientation()) * M_PI / 1800.0);
+
+ rCairo.matrix_scale(&m, nWidth, rFSD.mnHeight);
+ if (rFont.NeedsArtificialItalic())
+ m.xy = -m.xx * 0x6000L / 0x10000L;
+
+ rCairo.set_font_matrix(cr, &m);
+ rCairo.show_glyphs(cr, &cairo_glyphs[0], cairo_glyphs.size());
+ rCairo.destroy(cr);
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerAAFontString( const ServerFontLayout& rLayout )
+{
+ // get xrender target for this drawable
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return;
+
+ // get a XRenderPicture for the font foreground
+ // TODO: move into own method
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+ XRenderPictFormat* pVisualFormat = (XRenderPictFormat*)GetXRenderFormat();
+ DBG_ASSERT( pVisualFormat, "we already have a render picture, but XRenderPictFormat==NULL???");
+ const int nVisualDepth = pVisualFormat->depth;
+ SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ nVisualDepth ];
+ if( !rEntry.m_aPicture )
+ {
+ // create and cache XRenderPicture for the font foreground
+ Display* pDisplay = GetXDisplay();
+#ifdef DEBUG
+ int iDummy;
+ unsigned uDummy;
+ XLIB_Window wDummy;
+ unsigned int nDrawDepth;
+ ::XGetGeometry( pDisplay, hDrawable_, &wDummy, &iDummy, &iDummy,
+ &uDummy, &uDummy, &uDummy, &nDrawDepth );
+ DBG_ASSERT( static_cast<unsigned>(nVisualDepth) == nDrawDepth, "depth messed up for XRender" );
+#endif
+
+ rEntry.m_aPixmap = ::XCreatePixmap( pDisplay, hDrawable_, 1, 1, nVisualDepth );
+
+ XRenderPictureAttributes aAttr;
+ aAttr.repeat = true;
+ rEntry.m_aPicture = rRenderPeer.CreatePicture ( rEntry.m_aPixmap, pVisualFormat, CPRepeat, &aAttr );
+ }
+
+ // set font foreground color and opacity
+ XRenderColor aRenderColor = GetXRenderColor( nTextColor_ );
+ 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 );
+
+ ServerFont& rFont = rLayout.GetServerFont();
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ GlyphSet aGlyphSet = rGlyphPeer.GetGlyphSet( rFont, m_nScreen );
+
+ Point aPos;
+ static const int MAXGLYPHS = 160;
+ sal_GlyphId aGlyphAry[ MAXGLYPHS ];
+ int nMaxGlyphs = rLayout.GetOrientation() ? 1 : MAXGLYPHS;
+ for( int nStart = 0;;)
+ {
+ int nGlyphs = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart );
+ if( !nGlyphs )
+ break;
+
+ // #i51924# avoid 32->16bit coordinate truncation problem in X11
+ // TODO: reevaluate once displays with >30000 pixels are available
+ if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
+ continue;
+
+ unsigned int aRenderAry[ MAXGLYPHS ];
+ for( int i = 0; i < nGlyphs; ++i )
+ aRenderAry[ i ] = rGlyphPeer.GetGlyphId( rFont, aGlyphAry[i] );
+ rRenderPeer.CompositeString32( rEntry.m_aPicture, aDstPic,
+ aGlyphSet, aPos.X(), aPos.Y(), aRenderAry, nGlyphs );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+bool X11SalGraphics::DrawServerAAForcedString( const ServerFontLayout& rLayout )
+{
+ ServerFont& rFont = rLayout.GetServerFont();
+
+ // prepare glyphs and get extent of operation
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ int nXmin = 0;
+ int nXmax = 0;
+ int nYmin = 0;
+ int nYmax = 0;
+ int nStart = 0;
+ Point aPos;
+ sal_GlyphId nGlyph;
+ for( bool bFirst=true; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
+ if( !pRawBitmap )
+ continue;
+
+ const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
+ const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
+ const int nX2 = nX1 + pRawBitmap->mnWidth;
+ const int nY2 = nY1 + pRawBitmap->mnHeight;
+
+ if( bFirst )
+ {
+ bFirst = false;
+ nXmin = nX1;
+ nXmax = nX2;
+ nYmin = nY1;
+ nYmax = nY2;
+ }
+ else
+ {
+ if( nXmin > nX1 ) nXmin = nX1;
+ if( nXmax < nX2 ) nXmax = nX2;
+ if( nYmin > nY1 ) nYmin = nY1;
+ if( nYmax < nY2 ) nYmax = nY2;
+ }
+ }
+
+ // get XImage
+ GetDisplay()->GetXLib()->PushXErrorLevel( true );
+ Display* pDisplay = GetXDisplay();
+
+ XRectangle aXRect;
+ long nWidth = 1, nHeight = 1;
+ if( m_pFrame )
+ nWidth = m_pFrame->maGeometry.nWidth, nHeight = m_pFrame->maGeometry.nHeight;
+ else if( m_pVDev )
+ nWidth = m_pVDev->GetWidth(), nHeight = m_pVDev->GetHeight();
+
+ if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
+ {
+ // get bounding box
+ XClipBox( mpClipRegion, &aXRect );
+ // clip with window
+ if( aXRect.x < 0 ) aXRect.x = 0;
+
+ if( aXRect.y < 0 ) aXRect.y = 0;
+ if( aXRect.width+aXRect.x > nWidth ) aXRect.width = nWidth-aXRect.x;
+ if( aXRect.height+aXRect.y > nHeight ) aXRect.height = nHeight-aXRect.y;
+ }
+ else
+ {
+ aXRect.x = 0;
+ aXRect.y = 0;
+ aXRect.width = nWidth;
+ aXRect.height = nHeight;
+ }
+ if( m_pFrame )
+ {
+ // clip with screen
+ int nScreenX = m_pFrame->maGeometry.nX+aXRect.x;
+ int nScreenY = m_pFrame->maGeometry.nY+aXRect.y;
+ const Size& rScreenSize = GetDisplay()->getDataForScreen( m_nScreen ).m_aSize;
+ int nScreenW = rScreenSize.Width();
+ int nScreenH = rScreenSize.Height();
+ if( nScreenX < 0 )
+ aXRect.x -= nScreenX, aXRect.width += nScreenX;
+ if( nScreenX+aXRect.width > nScreenW )
+ aXRect.width = nScreenW-nScreenX;
+ if( nScreenY < 0 )
+ aXRect.y -= nScreenY, aXRect.height += nScreenY;
+ if( nScreenY+aXRect.height > nScreenH )
+ aXRect.height = nScreenH-nScreenY;
+ }
+
+
+ if( nXmin < aXRect.x ) nXmin = aXRect.x;
+ if( nYmin < aXRect.y ) nYmin = aXRect.y;
+ if( nXmax >= aXRect.x+aXRect.width ) nXmax = aXRect.x + aXRect.width - 1;
+ if( nYmax >= aXRect.y+aXRect.height ) nYmax = aXRect.y + aXRect.height - 1;
+
+ if( nXmin > nXmax )
+ return false;
+ if( nYmin > nYmax )
+ return false;
+
+ XImage* pImg = XGetImage( pDisplay, hDrawable_,
+ nXmin, nYmin,
+ (nXmax-nXmin+1), (nYmax-nYmin+1),
+ ~0, ZPixmap );
+ if( pImg == NULL )
+ {
+ if( m_pFrame )
+ {
+ // the reason we did not get an image could be that the frame
+ // geometry changed in the meantime; lets get the current geometry
+ // and clip against the current window size as well as the screen
+ // with the current frame position
+ const Size& rScreenSize = GetDisplay()->getDataForScreen(m_nScreen).m_aSize;
+ int nScreenW = rScreenSize.Width();
+ int nScreenH = rScreenSize.Height();
+ XLIB_Window aRoot = None;
+ int x = 0, y = 0;
+ unsigned int w = 0, h = 0, bw = 0, d;
+ XGetGeometry( pDisplay, hDrawable_, &aRoot, &x, &y, &w, &h, &bw, &d );
+ XTranslateCoordinates( pDisplay, hDrawable_, aRoot, 0, 0, &x, &y, &aRoot );
+ if( nXmin + x < 0 ) // clip on left screen edge
+ nXmin += x-nXmin;
+ if( nYmin + y < 0 ) // clip on top screen edge
+ nYmin += y-nYmin;
+ if( nXmax >= int(w) ) // clip on right window egde
+ nXmax = w-1;
+ if( nYmax >= int(h) ) // clip on bottom window edge
+ nYmax = h-1;
+ if( nXmax + x >= nScreenW ) // clip on right screen edge
+ nXmax -= (nXmax + x - nScreenW)+1;
+ if( nYmax + y >= nScreenH ) // clip on bottom screen edge
+ nYmax -= (nYmax + y - nScreenH)+1;
+ if( nXmax >= nXmin && nYmax >= nYmin )
+ {
+ // try again to get the image
+ pImg = XGetImage( pDisplay, hDrawable_,
+ nXmin, nYmin,
+ (nXmax-nXmin+1), (nYmax-nYmin+1),
+ ~0, ZPixmap );
+ }
+ }
+ if( pImg == NULL )
+ {
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+ return false;
+ }
+ }
+
+ // prepare context
+ GC nGC = GetFontGC();
+ XGCValues aGCVal;
+ XGetGCValues( pDisplay, nGC, GCForeground, &aGCVal );
+
+ unsigned long nOrigColor = XGetPixel( pImg, 0, 0 );
+ XPutPixel( pImg, 0, 0, aGCVal.foreground );
+ unsigned char aColor[4];
+ aColor[0] = pImg->data[0];
+ aColor[1] = pImg->data[1];
+ aColor[2] = pImg->data[2];
+ aColor[3] = pImg->data[3];
+ XPutPixel( pImg, 0, 0, nOrigColor );
+
+ // work on XImage
+ const int bpp = pImg->bits_per_pixel >> 3;
+ for( nStart = 0; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
+ if( !pRawBitmap )
+ continue;
+
+ const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
+ const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
+
+ if( (nX1 <= nXmax) && (int(nX1 + pRawBitmap->mnWidth) > nXmin)
+ && (nY1 <= nYmax) && (int(nY1 + pRawBitmap->mnHeight) > nYmin) )
+ {
+ const unsigned char* p10 = pRawBitmap->mpBits;
+ unsigned char* p20 = (unsigned char*)pImg->data; // dest left limit
+ p20 += (nY1 - nYmin) * pImg->bytes_per_line;
+ unsigned char* p21 = p20 + (nX1 - nXmin + pImg->xoffset) * bpp;
+ int y = pRawBitmap->mnHeight;
+ if( y > nYmax - nY1 )
+ y = nYmax - nY1 + 1;
+ while( --y >= 0 )
+ {
+ if( p20 >= (unsigned char*)pImg->data )
+ {
+ unsigned char* const p22 = p20 + pImg->width * bpp; // dest right limit
+ unsigned char* pDst = p21;
+ const unsigned char* pSrc = p10;
+ for( int x = pRawBitmap->mnWidth; (--x >= 0) && (p22 > pDst); ++pSrc )
+ {
+ if( (*pSrc == 0) || (p20 > pDst) ) // keep background
+ pDst += bpp;
+ else if( *pSrc == 0xFF ) // paint foreground
+ {
+ const unsigned char* pColor = aColor;
+ for( int z = bpp; --z >= 0; ++pColor, ++pDst )
+ *pDst = *pColor;
+ }
+ else // blend fg into bg
+ {
+ const unsigned char* pColor = aColor;
+ for( int z = bpp; --z >= 0; ++pColor, ++pDst )
+ // theoretically it should be *257) >> 16
+ // but the error is <0.4% worst case and we are in
+ // the innermost loop of very perf-sensitive code
+
+ *pDst += (*pSrc * ((int)*pColor - *pDst)) >> 8;
+ }
+ }
+ }
+ p10 += pRawBitmap->mnScanlineSize;
+ p20 += pImg->bytes_per_line;
+ p21 += pImg->bytes_per_line;
+ }
+ }
+ }
+
+ // put XImage
+ XPutImage( pDisplay, hDrawable_, nGC, pImg,
+ 0, 0, nXmin, nYmin, (nXmax - nXmin + 1), (nYmax - nYmin + 1) );
+ XDestroyImage( pImg );
+
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+ return true;
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerSimpleFontString( const ServerFontLayout& rSalLayout )
+{
+ ServerFont& rFont = rSalLayout.GetServerFont();
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+
+ Display* pDisplay = GetXDisplay();
+ GC nGC = GetFontGC();
+
+ XGCValues aGCVal;
+ aGCVal.fill_style = FillStippled;
+ aGCVal.line_width = 0;
+ GC tmpGC = XCreateGC( pDisplay, hDrawable_, GCFillStyle|GCLineWidth, &aGCVal );
+ XCopyGC( pDisplay, nGC, (1<<GCLastBit)-(1+GCFillStyle+GCLineWidth), tmpGC );
+
+ Point aPos;
+ sal_GlyphId nGlyph;
+ for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ // #i51924# avoid 32->16bit coordinate truncation problem in X11
+ // TODO: reevaluate once displays with >30000 pixels are available
+ if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
+ continue;
+
+ Pixmap aStipple = rGlyphPeer.GetPixmap( rFont, nGlyph, m_nScreen );
+ const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyph );
+
+ if( aStipple != None )
+ {
+ const int nDestX = aPos.X() + rGM.GetOffset().X();
+ const int nDestY = aPos.Y() + rGM.GetOffset().Y();
+
+ aGCVal.stipple = aStipple;
+ aGCVal.ts_x_origin = nDestX;
+ aGCVal.ts_y_origin = nDestY;
+ XChangeGC( pDisplay, tmpGC, GCStipple|GCTileStipXOrigin|GCTileStipYOrigin, &aGCVal );
+
+ const int nWidth = rGM.GetSize().Width();
+ const int nHeight = rGM.GetSize().Height();
+ XFillRectangle( pDisplay, hDrawable_, tmpGC, nDestX, nDestY, nWidth, nHeight );
+ }
+ }
+
+ XFreeGC( pDisplay, tmpGC );
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
+{
+ // draw complex text
+ ServerFont& rFont = rLayout.GetServerFont();
+ const bool bVertical = rFont.GetFontSelData().mbVertical;
+
+ if( !bVertical && CairoWrapper::get().isCairoRenderable(rFont) )
+ DrawCairoAAFontString( rLayout );
+ else
+ {
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ if( rGlyphPeer.GetGlyphSet( rFont, m_nScreen ) )
+ DrawServerAAFontString( rLayout );
+ else if( !rGlyphPeer.ForcedAntialiasing( rFont, m_nScreen ) )
+ DrawServerSimpleFontString( rLayout );
+ else
+ DrawServerAAForcedString( rLayout );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+const ImplFontCharMap* X11SalGraphics::GetImplFontCharMap() const
+{
+ if( !mpServerFont[0] )
+ return NULL;
+
+ const ImplFontCharMap* pIFCMap = mpServerFont[0]->GetImplFontCharMap();
+ return pIFCMap;
+}
+
+// ----------------------------------------------------------------------------
+//
+// SalGraphics
+//
+// ----------------------------------------------------------------------------
+
+sal_uInt16 X11SalGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+ sal_uInt16 nRetVal = 0;
+ if( !setFont( pEntry, nFallbackLevel ) )
+ nRetVal |= SAL_SETFONT_BADFONT;
+ if( bPrinter_ || (mpServerFont[ nFallbackLevel ] != NULL) )
+ nRetVal |= SAL_SETFONT_USEDRAWTEXTARRAY;
+ return nRetVal;
+}
+
+// ----------------------------------------------------------------------------
+
+void
+X11SalGraphics::SetTextColor( SalColor nSalColor )
+{
+ if( nTextColor_ != nSalColor )
+ {
+ nTextColor_ = nSalColor;
+ nTextPixel_ = GetPixel( nSalColor );
+ bFontGC_ = sal_False;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+bool X11SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFileURL, const String& rFontName )
+{
+ // inform PSP font manager
+ rtl::OUString aUSystemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFileURL, aUSystemPath ) );
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ OString aOFileName( OUStringToOString( aUSystemPath, aEncoding ) );
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ int nFontId = rMgr.addFontFile( aOFileName, 0 );
+ if( !nFontId )
+ return false;
+
+ // prepare font data
+ psp::FastPrintFontInfo aInfo;
+ rMgr.getFontFastInfo( nFontId, aInfo );
+ aInfo.m_aFamilyName = rFontName;
+
+ // inform glyph cache of new font
+ ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
+ aDFA.mnQuality += 5800;
+
+ int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
+ if( nFaceNum < 0 )
+ nFaceNum = 0;
+
+ GlyphCache& rGC = X11GlyphCache::GetInstance();
+ const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
+ rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA );
+
+ // announce new font to device's font list
+ rGC.AnnounceFonts( pFontList );
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+void RegisterFontSubstitutors( ImplDevFontList* );
+
+void X11SalGraphics::GetDevFontList( ImplDevFontList *pList )
+{
+ // prepare the GlyphCache using psprint's font infos
+ X11GlyphCache& rGC = X11GlyphCache::GetInstance();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ ::std::list< psp::fontID > aList;
+ ::std::list< psp::fontID >::iterator it;
+ psp::FastPrintFontInfo aInfo;
+ rMgr.getFontList( aList );
+ for( it = aList.begin(); it != aList.end(); ++it )
+ {
+ if( !rMgr.getFontFastInfo( *it, aInfo ) )
+ continue;
+
+ // the GlyphCache must not bother with builtin fonts because
+ // it cannot access or use them anyway
+ if( aInfo.m_eType == psp::fonttype::Builtin )
+ continue;
+
+ // normalize face number to the GlyphCache
+ int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
+ if( nFaceNum < 0 )
+ nFaceNum = 0;
+
+ // for fonts where extra kerning info can be provided on demand
+ // an ExtraKernInfo object is supplied
+ const ExtraKernInfo* pExtraKernInfo = NULL;
+ if( aInfo.m_eType == psp::fonttype::Type1 )
+ pExtraKernInfo = new PspKernInfo( *it );
+
+ // inform GlyphCache about this font provided by the PsPrint subsystem
+ ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
+ aDFA.mnQuality += 4096;
+ const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
+ rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo );
+ }
+
+ // announce glyphcache fonts
+ rGC.AnnounceFonts( pList );
+
+ // register platform specific font substitutions if available
+ if( rMgr.hasFontconfig() )
+ RegisterFontSubstitutors( pList );
+
+ ImplGetSVData()->maGDIData.mbNativeFontConfig = rMgr.hasFontconfig();
+}
+
+// ----------------------------------------------------------------------------
+
+void X11SalGraphics::GetDevFontSubstList( OutputDevice* )
+{
+ // no device specific font substitutions on X11 needed
+}
+
+// ----------------------------------------------------------------------------
+
+void cairosubcallback( void* pPattern )
+{
+ CairoWrapper& rCairo = CairoWrapper::get();
+ if( !rCairo.isValid() )
+ return;
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const void* pFontOptions = rStyleSettings.GetCairoFontOptions();
+ if( !pFontOptions )
+ return;
+ rCairo.ft_font_options_substitute( pFontOptions, pPattern );
+}
+
+bool GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize,
+ ImplFontOptions& rFontOptions)
+{
+ // TODO: get rid of these insane enum-conversions
+ // e.g. by using the classic vclenum values inside VCL
+
+ psp::FastPrintFontInfo aInfo;
+ // set family name
+ aInfo.m_aFamilyName = rFontAttributes.GetFamilyName();
+ // set italic
+ switch( rFontAttributes.GetSlant() )
+ {
+ case ITALIC_NONE:
+ aInfo.m_eItalic = psp::italic::Upright;
+ break;
+ case ITALIC_NORMAL:
+ aInfo.m_eItalic = psp::italic::Italic;
+ break;
+ case ITALIC_OBLIQUE:
+ aInfo.m_eItalic = psp::italic::Oblique;
+ break;
+ default:
+ aInfo.m_eItalic = psp::italic::Unknown;
+ break;
+ }
+ // set weight
+ switch( rFontAttributes.GetWeight() )
+ {
+ case WEIGHT_THIN:
+ aInfo.m_eWeight = psp::weight::Thin;
+ break;
+ case WEIGHT_ULTRALIGHT:
+ aInfo.m_eWeight = psp::weight::UltraLight;
+ break;
+ case WEIGHT_LIGHT:
+ aInfo.m_eWeight = psp::weight::Light;
+ break;
+ case WEIGHT_SEMILIGHT:
+ aInfo.m_eWeight = psp::weight::SemiLight;
+ break;
+ case WEIGHT_NORMAL:
+ aInfo.m_eWeight = psp::weight::Normal;
+ break;
+ case WEIGHT_MEDIUM:
+ aInfo.m_eWeight = psp::weight::Medium;
+ break;
+ case WEIGHT_SEMIBOLD:
+ aInfo.m_eWeight = psp::weight::SemiBold;
+ break;
+ case WEIGHT_BOLD:
+ aInfo.m_eWeight = psp::weight::Bold;
+ break;
+ case WEIGHT_ULTRABOLD:
+ aInfo.m_eWeight = psp::weight::UltraBold;
+ break;
+ case WEIGHT_BLACK:
+ aInfo.m_eWeight = psp::weight::Black;
+ break;
+ default:
+ aInfo.m_eWeight = psp::weight::Unknown;
+ break;
+ }
+ // set width
+ switch( rFontAttributes.GetWidthType() )
+ {
+ case WIDTH_ULTRA_CONDENSED:
+ aInfo.m_eWidth = psp::width::UltraCondensed;
+ break;
+ case WIDTH_EXTRA_CONDENSED:
+ aInfo.m_eWidth = psp::width::ExtraCondensed;
+ break;
+ case WIDTH_CONDENSED:
+ aInfo.m_eWidth = psp::width::Condensed;
+ break;
+ case WIDTH_SEMI_CONDENSED:
+ aInfo.m_eWidth = psp::width::SemiCondensed;
+ break;
+ case WIDTH_NORMAL:
+ aInfo.m_eWidth = psp::width::Normal;
+ break;
+ case WIDTH_SEMI_EXPANDED:
+ aInfo.m_eWidth = psp::width::SemiExpanded;
+ break;
+ case WIDTH_EXPANDED:
+ aInfo.m_eWidth = psp::width::Expanded;
+ break;
+ case WIDTH_EXTRA_EXPANDED:
+ aInfo.m_eWidth = psp::width::ExtraExpanded;
+ break;
+ case WIDTH_ULTRA_EXPANDED:
+ aInfo.m_eWidth = psp::width::UltraExpanded;
+ break;
+ default:
+ aInfo.m_eWidth = psp::width::Unknown;
+ break;
+ }
+
+ const psp::PrintFontManager& rPFM = psp::PrintFontManager::get();
+ bool bOK = rPFM.getFontOptions( aInfo, nSize, cairosubcallback, rFontOptions);
+ return bOK;
+}
+
+// ----------------------------------------------------------------------------
+
+void
+X11SalGraphics::GetFontMetric( ImplFontMetricData *pMetric, int nFallbackLevel )
+{
+ if( nFallbackLevel >= MAX_FALLBACK )
+ return;
+
+ if( mpServerFont[nFallbackLevel] != NULL )
+ {
+ long rDummyFactor;
+ mpServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor );
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+sal_uLong
+X11SalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData *pKernPairs )
+{
+ if( ! bPrinter_ )
+ {
+ if( mpServerFont[0] != NULL )
+ {
+ ImplKernPairData* pTmpKernPairs;
+ sal_uLong nGotPairs = mpServerFont[0]->GetKernPairs( &pTmpKernPairs );
+ for( unsigned int i = 0; i < nPairs && i < nGotPairs; ++i )
+ pKernPairs[ i ] = pTmpKernPairs[ i ];
+ delete[] pTmpKernPairs;
+ return nGotPairs;
+ }
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+
+sal_Bool X11SalGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return sal_False;
+
+ ServerFont* pSF = mpServerFont[ nLevel ];
+ if( !pSF )
+ return sal_False;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
+ rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+ return sal_True;
+}
+
+// ---------------------------------------------------------------------------
+
+sal_Bool X11SalGraphics::GetGlyphOutline( long nGlyphIndex,
+ ::basegfx::B2DPolyPolygon& rPolyPoly )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return sal_False;
+
+ ServerFont* pSF = mpServerFont[ nLevel ];
+ if( !pSF )
+ return sal_False;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ if( pSF->GetGlyphOutline( nGlyphIndex, rPolyPoly ) )
+ return sal_True;
+
+ return sal_False;
+}
+
+//--------------------------------------------------------------------------
+
+SalLayout* X11SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ SalLayout* pLayout = NULL;
+
+ if( mpServerFont[ nFallbackLevel ]
+ && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+ {
+#ifdef ENABLE_GRAPHITE
+ // Is this a Graphite font?
+ if (!bDisableGraphite_ &&
+ GraphiteFontAdaptor::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel]))
+ {
+ sal_Int32 xdpi, ydpi;
+
+ xdpi = GetDisplay()->GetResolution().A();
+ ydpi = GetDisplay()->GetResolution().B();
+
+ GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *mpServerFont[nFallbackLevel], xdpi, ydpi);
+ if (!pGrfont) return NULL;
+ pLayout = new GraphiteServerFontLayout(pGrfont);
+ }
+ else
+#endif
+ pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] );
+ }
+
+ return pLayout;
+}
+
+//--------------------------------------------------------------------------
+
+SystemFontData X11SalGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.nFontId = 0;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ if (mpServerFont[nFallbacklevel] != NULL)
+ {
+ ServerFont* rFont = mpServerFont[nFallbacklevel];
+ aSysFontData.nFontId = rFont->GetFtFace();
+ aSysFontData.nFontFlags = rFont->GetLoadFlags();
+ aSysFontData.bFakeBold = rFont->NeedsArtificialBold();
+ aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic();
+ aSysFontData.bAntialias = rFont->GetAntialiasAdvice();
+ aSysFontData.bVerticalCharacterType = rFont->GetFontSelData().mbVertical;
+ }
+
+ return aSysFontData;
+}
+
+//--------------------------------------------------------------------------
+
+sal_Bool X11SalGraphics::CreateFontSubset(
+ const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphCount,
+ FontSubsetInfo& rInfo
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ bool bSuccess = rMgr.createFontSubset( rInfo,
+ aFont,
+ rToFile,
+ pGlyphIDs,
+ pEncoding,
+ pWidths,
+ nGlyphCount );
+ return bSuccess;
+}
+
+//--------------------------------------------------------------------------
+
+const void* X11SalGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::FreeEmbedFontData( const void* pData, long nLen )
+{
+ PspGraphics::DoFreeEmbedFontData( pData, nLen );
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+// ===========================================================================
+// platform specific font substitution hooks
+
+class FcPreMatchSubstititution
+: public ImplPreMatchFontSubstitution
+{
+public:
+ bool FindFontSubstitute( ImplFontSelectData& ) const;
+};
+
+class FcGlyphFallbackSubstititution
+: public ImplGlyphFallbackFontSubstitution
+{
+ // TODO: add a cache
+public:
+ bool FindFontSubstitute( ImplFontSelectData&, OUString& rMissingCodes ) const;
+};
+
+void RegisterFontSubstitutors( ImplDevFontList* pList )
+{
+ // init font substitution defaults
+ int nDisableBits = 0;
+#ifdef SOLARIS
+ nDisableBits = 1; // disable "font fallback" here on default
+#endif
+ // apply the environment variable if any
+ const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
+ if( pEnvStr )
+ {
+ if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
+ nDisableBits = (*pEnvStr - '0');
+ else
+ nDisableBits = ~0U; // no specific bits set: disable all
+ }
+
+ // register font fallback substitutions (unless disabled by bit0)
+ if( (nDisableBits & 1) == 0 )
+ {
+ static FcPreMatchSubstititution aSubstPreMatch;
+ pList->SetPreMatchHook( &aSubstPreMatch );
+ }
+
+ // register glyph fallback substitutions (unless disabled by bit1)
+ if( (nDisableBits & 2) == 0 )
+ {
+ static FcGlyphFallbackSubstititution aSubstFallback;
+ pList->SetFallbackHook( &aSubstFallback );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static ImplFontSelectData GetFcSubstitute(const ImplFontSelectData &rFontSelData, OUString& rMissingCodes )
+{
+ ImplFontSelectData aRet(rFontSelData);
+
+ const rtl::OString aLangAttrib = MsLangId::convertLanguageToIsoByteString( rFontSelData.meLanguage );
+
+ psp::italic::type eItalic = psp::italic::Unknown;
+ if( rFontSelData.GetSlant() != ITALIC_DONTKNOW )
+ {
+ switch( rFontSelData.GetSlant() )
+ {
+ case ITALIC_NONE: eItalic = psp::italic::Upright; break;
+ case ITALIC_NORMAL: eItalic = psp::italic::Italic; break;
+ case ITALIC_OBLIQUE: eItalic = psp::italic::Oblique; break;
+ default:
+ break;
+ }
+ }
+
+ psp::weight::type eWeight = psp::weight::Unknown;
+ if( rFontSelData.GetWeight() != WEIGHT_DONTKNOW )
+ {
+ switch( rFontSelData.GetWeight() )
+ {
+ case WEIGHT_THIN: eWeight = psp::weight::Thin; break;
+ case WEIGHT_ULTRALIGHT: eWeight = psp::weight::UltraLight; break;
+ case WEIGHT_LIGHT: eWeight = psp::weight::Light; break;
+ case WEIGHT_SEMILIGHT: eWeight = psp::weight::SemiLight; break;
+ case WEIGHT_NORMAL: eWeight = psp::weight::Normal; break;
+ case WEIGHT_MEDIUM: eWeight = psp::weight::Medium; break;
+ case WEIGHT_SEMIBOLD: eWeight = psp::weight::SemiBold; break;
+ case WEIGHT_BOLD: eWeight = psp::weight::Bold; break;
+ case WEIGHT_ULTRABOLD: eWeight = psp::weight::UltraBold; break;
+ case WEIGHT_BLACK: eWeight = psp::weight::Black; break;
+ default:
+ break;
+ }
+ }
+
+ psp::width::type eWidth = psp::width::Unknown;
+ if( rFontSelData.GetWidthType() != WIDTH_DONTKNOW )
+ {
+ switch( rFontSelData.GetWidthType() )
+ {
+ case WIDTH_ULTRA_CONDENSED: eWidth = psp::width::UltraCondensed; break;
+ case WIDTH_EXTRA_CONDENSED: eWidth = psp::width::ExtraCondensed; break;
+ case WIDTH_CONDENSED: eWidth = psp::width::Condensed; break;
+ case WIDTH_SEMI_CONDENSED: eWidth = psp::width::SemiCondensed; break;
+ case WIDTH_NORMAL: eWidth = psp::width::Normal; break;
+ case WIDTH_SEMI_EXPANDED: eWidth = psp::width::SemiExpanded; break;
+ case WIDTH_EXPANDED: eWidth = psp::width::Expanded; break;
+ case WIDTH_EXTRA_EXPANDED: eWidth = psp::width::ExtraExpanded; break;
+ case WIDTH_ULTRA_EXPANDED: eWidth = psp::width::UltraExpanded; break;
+ default:
+ break;
+ }
+ }
+
+ psp::pitch::type ePitch = psp::pitch::Unknown;
+ if( rFontSelData.GetPitch() != PITCH_DONTKNOW )
+ {
+ switch( rFontSelData.GetPitch() )
+ {
+ case PITCH_FIXED: ePitch=psp::pitch::Fixed; break;
+ case PITCH_VARIABLE: ePitch=psp::pitch::Variable; break;
+ default:
+ break;
+ }
+ }
+
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch);
+
+ switch (eItalic)
+ {
+ case psp::italic::Upright: aRet.meItalic = ITALIC_NONE; break;
+ case psp::italic::Italic: aRet.meItalic = ITALIC_NORMAL; break;
+ case psp::italic::Oblique: aRet.meItalic = ITALIC_OBLIQUE; break;
+ default:
+ break;
+ }
+
+ switch (eWeight)
+ {
+ case psp::weight::Thin: aRet.meWeight = WEIGHT_THIN; break;
+ case psp::weight::UltraLight: aRet.meWeight = WEIGHT_ULTRALIGHT; break;
+ case psp::weight::Light: aRet.meWeight = WEIGHT_LIGHT; break;
+ case psp::weight::SemiLight: aRet.meWeight = WEIGHT_SEMILIGHT; break;
+ case psp::weight::Normal: aRet.meWeight = WEIGHT_NORMAL; break;
+ case psp::weight::Medium: aRet.meWeight = WEIGHT_MEDIUM; break;
+ case psp::weight::SemiBold: aRet.meWeight = WEIGHT_SEMIBOLD; break;
+ case psp::weight::Bold: aRet.meWeight = WEIGHT_BOLD; break;
+ case psp::weight::UltraBold: aRet.meWeight = WEIGHT_ULTRABOLD; break;
+ case psp::weight::Black: aRet.meWeight = WEIGHT_BLACK; break;
+ default:
+ break;
+ }
+
+ switch (eWidth)
+ {
+ case psp::width::UltraCondensed: aRet.meWidthType = WIDTH_ULTRA_CONDENSED; break;
+ case psp::width::ExtraCondensed: aRet.meWidthType = WIDTH_EXTRA_CONDENSED; break;
+ case psp::width::Condensed: aRet.meWidthType = WIDTH_CONDENSED; break;
+ case psp::width::SemiCondensed: aRet.meWidthType = WIDTH_SEMI_CONDENSED; break;
+ case psp::width::Normal: aRet.meWidthType = WIDTH_NORMAL; break;
+ case psp::width::SemiExpanded: aRet.meWidthType = WIDTH_SEMI_EXPANDED; break;
+ case psp::width::Expanded: aRet.meWidthType = WIDTH_EXPANDED; break;
+ case psp::width::ExtraExpanded: aRet.meWidthType = WIDTH_EXTRA_EXPANDED; break;
+ case psp::width::UltraExpanded: aRet.meWidthType = WIDTH_ULTRA_EXPANDED; break;
+ default:
+ break;
+ }
+
+ switch (ePitch)
+ {
+ case psp::pitch::Fixed: aRet.mePitch = PITCH_FIXED; break;
+ case psp::pitch::Variable: aRet.mePitch = PITCH_VARIABLE; break;
+ default:
+ break;
+ }
+
+ return aRet;
+}
+
+namespace
+{
+ bool uselessmatch(const ImplFontSelectData &rOrig, const ImplFontSelectData &rNew)
+ {
+ return
+ (
+ rOrig.maTargetName == rNew.maSearchName &&
+ rOrig.meWeight == rNew.meWeight &&
+ rOrig.meItalic == rNew.meItalic &&
+ rOrig.mePitch == rNew.mePitch &&
+ rOrig.meWidthType == rNew.meWidthType
+ );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+bool FcPreMatchSubstititution::FindFontSubstitute( ImplFontSelectData &rFontSelData ) const
+{
+ // We dont' actually want to talk to Fontconfig at all for symbol fonts
+ if( rFontSelData.IsSymbolFont() )
+ return false;
+ // StarSymbol is a unicode font, but it still deserves the symbol flag
+ if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
+ || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
+ return false;
+
+ rtl::OUString aDummy;
+ const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, aDummy );
+ // TODO: cache the font substitution suggestion
+ // FC doing it would be preferable because it knows the invariables
+ // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
+ // whereas we would have to check for every size or attribute
+ if( !aOut.maSearchName.Len() )
+ return false;
+
+ const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
+
+#ifdef DEBUG
+ const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
+ printf( "FcPreMatchSubstititution \"%s\" bipw=%d%d%d%d -> ",
+ aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
+ rFontSelData.mePitch, rFontSelData.meWidthType );
+ if( !bHaveSubstitute )
+ printf( "no substitute available\n" );
+ else
+ printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
+ aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
+#endif
+
+ if( bHaveSubstitute )
+ rFontSelData = aOut;
+
+ return bHaveSubstitute;
+}
+
+// -----------------------------------------------------------------------
+
+bool FcGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData,
+ rtl::OUString& rMissingCodes ) const
+{
+ // We dont' actually want to talk to Fontconfig at all for symbol fonts
+ if( rFontSelData.IsSymbolFont() )
+ return false;
+ // StarSymbol is a unicode font, but it still deserves the symbol flag
+ if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
+ || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
+ return false;
+
+ const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, rMissingCodes );
+ // TODO: cache the unicode + srcfont specific result
+ // FC doing it would be preferable because it knows the invariables
+ // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
+ // whereas we would have to check for every size or attribute
+ if( !aOut.maSearchName.Len() )
+ return false;
+
+ const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
+
+#ifdef DEBUG
+ const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
+ printf( "FcGFSubstititution \"%s\" bipw=%d%d%d%d ->",
+ aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
+ rFontSelData.mePitch, rFontSelData.meWidthType );
+ if( !bHaveSubstitute )
+ printf( "no substitute available\n" );
+ else
+ printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
+ aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
+#endif
+
+ if( bHaveSubstitute )
+ rFontSelData = aOut;
+
+ return bHaveSubstitute;
+}
+
+// ===========================================================================
+
diff --git a/vcl/unx/generic/gdi/salprnpsp.cxx b/vcl/unx/generic/gdi/salprnpsp.cxx
new file mode 100644
index 000000000000..0a278cab971f
--- /dev/null
+++ b/vcl/unx/generic/gdi/salprnpsp.cxx
@@ -0,0 +1,1462 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+/**
+ this file implements the sal printer interface ( SalPrinter, SalInfoPrinter
+ and some printer relevant methods of SalInstance and SalGraphicsData )
+
+ as aunderlying library the printer features of psprint are used.
+
+ The query methods of a SalInfoPrinter are implemented by querying psprint
+
+ The job methods of a SalPrinter are implemented by calling psprint
+ printer job functions.
+ */
+
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include "rtl/ustring.hxx"
+
+#include "osl/module.h"
+
+#include "vcl/svapp.hxx"
+#include "vcl/print.hxx"
+#include "vcl/pdfwriter.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include <unx/salunx.h>
+#include "unx/saldisp.hxx"
+#include "unx/salinst.h"
+#include "unx/salprn.h"
+#include "unx/salframe.h"
+#include "unx/pspgraphics.h"
+#include "unx/saldata.hxx"
+
+#include "jobset.h"
+#include "print.h"
+#include "salptype.hxx"
+
+using namespace psp;
+using namespace rtl;
+using namespace com::sun::star;
+
+/*
+ * static helpers
+ */
+
+static oslModule driverLib = NULL;
+extern "C"
+{
+typedef int(*setupFunction)(PrinterInfo&);
+static setupFunction pSetupFunction = NULL;
+typedef int(*faxFunction)(String&);
+static faxFunction pFaxNrFunction = NULL;
+}
+
+static String getPdfDir( const PrinterInfo& rInfo )
+{
+ String aDir;
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( ! aToken.compareToAscii( "pdf=", 4 ) )
+ {
+ sal_Int32 nPos = 0;
+ aDir = aToken.getToken( 1, '=', nPos );
+ if( ! aDir.Len() )
+ aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
+ break;
+ }
+ }
+ return aDir;
+}
+
+static void getPaLib()
+{
+ if( ! driverLib )
+ {
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME ) );
+ driverLib = osl_loadModuleRelative( (oslGenericFunction)getPaLib, aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if ( !driverLib )
+ {
+ return;
+ }
+
+ pSetupFunction = (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" );
+ if ( !pSetupFunction )
+ fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" );
+
+ pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" );
+ if ( !pFaxNrFunction )
+ fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" );
+ }
+}
+
+inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
+
+inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
+
+static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
+{
+ pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
+
+ // copy page size
+ String aPaper;
+ int width, height;
+
+ rData.m_aContext.getPageSize( aPaper, width, height );
+ pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
+
+ pJobSetup->mnPaperWidth = 0;
+ pJobSetup->mnPaperHeight = 0;
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ {
+ // transform to 100dth mm
+ width = PtTo10Mu( width );
+ height = PtTo10Mu( height );
+
+ if( rData.m_eOrientation == psp::orientation::Portrait )
+ {
+ pJobSetup->mnPaperWidth = width;
+ pJobSetup->mnPaperHeight= height;
+ }
+ else
+ {
+ pJobSetup->mnPaperWidth = height;
+ pJobSetup->mnPaperHeight= width;
+ }
+ }
+
+ // copy input slot
+ const PPDKey* pKey = NULL;
+ const PPDValue* pValue = NULL;
+
+ pJobSetup->mnPaperBin = 0;
+ if( rData.m_pParser )
+ pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( pKey )
+ pValue = rData.m_aContext.getValue( pKey );
+ if( pKey && pValue )
+ {
+ for( pJobSetup->mnPaperBin = 0;
+ pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
+ pJobSetup->mnPaperBin < pKey->countValues();
+ pJobSetup->mnPaperBin++ )
+ ;
+ if( pJobSetup->mnPaperBin >= pKey->countValues() )
+ pJobSetup->mnPaperBin = 0;
+ }
+
+ // copy duplex
+ pKey = NULL;
+ pValue = NULL;
+
+ pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
+ if( rData.m_pParser )
+ pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( pKey )
+ pValue = rData.m_aContext.getValue( pKey );
+ if( pKey && pValue )
+ {
+ if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
+ pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
+ )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_OFF;
+ }
+ else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
+ }
+ else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
+ }
+ }
+
+ // copy the whole context
+ if( pJobSetup->mpDriverData )
+ rtl_freeMemory( pJobSetup->mpDriverData );
+
+ int nBytes;
+ void* pBuffer = NULL;
+ if( rData.getStreamBuffer( pBuffer, nBytes ) )
+ {
+ pJobSetup->mnDriverDataLen = nBytes;
+ pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
+ }
+ else
+ {
+ pJobSetup->mnDriverDataLen = 0;
+ pJobSetup->mpDriverData = NULL;
+ }
+}
+
+static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true )
+{
+ bool bSuccess = false;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aCmdLine( rCommandLine, aEncoding );
+ ByteString aFilename( rFilename, aEncoding );
+
+ bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true;
+
+ // setup command line for exec
+ if( ! bPipe )
+ while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND )
+ ;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s commandline: \"%s\"\n",
+ bPipe ? "piping to" : "executing",
+ aCmdLine.GetBuffer() );
+ struct stat aStat;
+ if( stat( aFilename.GetBuffer(), &aStat ) )
+ fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() );
+ fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode );
+#endif
+ const char* argv[4];
+ if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) )
+ argv[ 0 ] = "/bin/sh";
+ argv[ 1 ] = "-c";
+ argv[ 2 ] = aCmdLine.GetBuffer();
+ argv[ 3 ] = 0;
+
+ bool bHavePipes = false;
+ int pid, fd[2];
+
+ if( bPipe )
+ bHavePipes = pipe( fd ) ? false : true;
+ if( ( pid = fork() ) > 0 )
+ {
+ if( bPipe && bHavePipes )
+ {
+ close( fd[0] );
+ char aBuffer[ 2048 ];
+ FILE* fp = fopen( aFilename.GetBuffer(), "r" );
+ while( fp && ! feof( fp ) )
+ {
+ int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp );
+ if( nBytes )
+ write( fd[ 1 ], aBuffer, nBytes );
+ }
+ fclose( fp );
+ close( fd[ 1 ] );
+ }
+ int status = 0;
+ waitpid( pid, &status, 0 );
+ if( ! status )
+ bSuccess = true;
+ }
+ else if( ! pid )
+ {
+ if( bPipe && bHavePipes )
+ {
+ close( fd[1] );
+ if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
+ dup2( fd[0], STDIN_FILENO );
+ }
+ execv( argv[0], const_cast<char**>(argv) );
+ fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() );
+ _exit( 1 );
+ }
+ else
+ fprintf( stderr, "failed to fork\n" );
+
+ // clean up the mess
+ if( bRemoveFile )
+ unlink( aFilename.GetBuffer() );
+
+ return bSuccess;
+}
+
+static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand )
+{
+ std::list< OUString > aFaxNumbers;
+
+ if( ! rFaxNumber.Len() )
+ {
+ getPaLib();
+ if( pFaxNrFunction )
+ {
+ String aNewNr;
+ if( pFaxNrFunction( aNewNr ) )
+ aFaxNumbers.push_back( OUString( aNewNr ) );
+ }
+ }
+ else
+ {
+ sal_Int32 nIndex = 0;
+ OUString aFaxes( rFaxNumber );
+ OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") );
+ OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") );
+ while( nIndex != -1 )
+ {
+ nIndex = aFaxes.indexOf( aBeginToken, nIndex );
+ if( nIndex != -1 )
+ {
+ sal_Int32 nBegin = nIndex + aBeginToken.getLength();
+ nIndex = aFaxes.indexOf( aEndToken, nIndex );
+ if( nIndex != -1 )
+ {
+ aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
+ nIndex += aEndToken.getLength();
+ }
+ }
+ }
+ }
+
+ bool bSuccess = true;
+ if( aFaxNumbers.begin() != aFaxNumbers.end() )
+ {
+ while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
+ {
+ String aCmdLine( rCommand );
+ String aFaxNumber( aFaxNumbers.front() );
+ aFaxNumbers.pop_front();
+ while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND )
+ ;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
+ }
+ }
+ else
+ bSuccess = false;
+
+ // clean up temp file
+ unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() );
+
+ return bSuccess;
+}
+
+static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine )
+{
+ String aCommandLine( rCommandLine );
+ while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND )
+ ;
+ return passFileToCommandLine( rFromFile, aCommandLine );
+}
+
+/*
+ * SalInstance
+ */
+
+// -----------------------------------------------------------------------
+
+SalInfoPrinter* X11SalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pJobSetup )
+{
+ mbPrinterInit = true;
+ // create and initialize SalInfoPrinter
+ PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter;
+
+ if( pJobSetup )
+ {
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
+ pPrinter->m_aJobData = aInfo;
+ pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
+
+ if( pJobSetup->mpDriverData )
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
+
+ pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
+ pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
+ pJobSetup->maDriver = aInfo.m_aDriverName;
+ copyJobDataToJobSetup( pJobSetup, aInfo );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+ }
+
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+SalPrinter* X11SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ mbPrinterInit = true;
+ // create and initialize SalPrinter
+ PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
+ pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ mbPrinterInit = true;
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
+ if( ! pNoSyncDetection || ! *pNoSyncDetection )
+ {
+ // #i62663# synchronize possible asynchronouse printer detection now
+ rManager.checkPrintersChanged( true );
+ }
+ ::std::list< OUString > aPrinters;
+ rManager.listPrinters( aPrinters );
+
+ for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
+ {
+ const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
+ // Neuen Eintrag anlegen
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = *it;
+ pInfo->maDriver = rInfo.m_aDriverName;
+ pInfo->maLocation = rInfo.m_aLocation;
+ pInfo->maComment = rInfo.m_aComment;
+ pInfo->mpSysData = NULL;
+
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
+ {
+ pInfo->maLocation = getPdfDir( rInfo );
+ break;
+ }
+ }
+
+ pList->Add( pInfo );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
+{
+ mbPrinterInit = true;
+}
+
+// -----------------------------------------------------------------------
+
+String X11SalInstance::GetDefaultPrinter()
+{
+ mbPrinterInit = true;
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ return rManager.getDefaultPrinter();
+}
+
+// =======================================================================
+
+PspSalInfoPrinter::PspSalInfoPrinter()
+{
+ m_pGraphics = NULL;
+ m_bPapersInit = false;
+}
+
+// -----------------------------------------------------------------------
+
+PspSalInfoPrinter::~PspSalInfoPrinter()
+{
+ if( m_pGraphics )
+ {
+ delete m_pGraphics;
+ m_pGraphics = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
+{
+ m_aPaperFormats.clear();
+ m_bPapersInit = true;
+
+ if( m_aJobData.m_pParser )
+ {
+ const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( pKey )
+ {
+ int nValues = pKey->countValues();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDValue* pValue = pKey->getValue( i );
+ int nWidth = 0, nHeight = 0;
+ m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
+ PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
+ m_aPaperFormats.push_back( aInfo );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
+{
+ return 900;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* PspSalInfoPrinter::GetGraphics()
+{
+ // return a valid pointer only once
+ // the reasoning behind this is that we could have different
+ // SalGraphics that can run in multiple threads
+ // (future plans)
+ SalGraphics* pRet = NULL;
+ if( ! m_pGraphics )
+ {
+ m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
+ m_pGraphics->SetLayout( 0 );
+ pRet = m_pGraphics;
+ }
+ return pRet;
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ if( pGraphics == m_pGraphics )
+ {
+ delete pGraphics;
+ m_pGraphics = NULL;
+ }
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
+{
+ if( ! pFrame || ! pJobSetup )
+ return sal_False;
+
+ getPaLib();
+
+ if( ! pSetupFunction )
+ return sal_False;
+
+ PrinterInfoManager& rManager = PrinterInfoManager::get();
+
+ PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
+ if ( pJobSetup->mpDriverData )
+ {
+ SetData( ~0, pJobSetup );
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
+ }
+
+ if( pSetupFunction( aInfo ) )
+ {
+ rtl_freeMemory( pJobSetup->mpDriverData );
+ pJobSetup->mpDriverData = NULL;
+
+ int nBytes;
+ void* pBuffer = NULL;
+ aInfo.getStreamBuffer( pBuffer, nBytes );
+ pJobSetup->mnDriverDataLen = nBytes;
+ pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
+
+ // copy everything to job setup
+ copyJobDataToJobSetup( pJobSetup, aInfo );
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ return sal_True;
+ }
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+// This function gets the driver data and puts it into pJobSetup
+// If pJobSetup->mpDriverData is NOT NULL, then the independend
+// data should be merged into the driver data
+// If pJobSetup->mpDriverData IS NULL, then the driver defaults
+// should be merged into the independent data
+sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
+{
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+
+ if( pJobSetup->mpDriverData )
+ return SetData( ~0, pJobSetup );
+
+ copyJobDataToJobSetup( pJobSetup, m_aJobData );
+
+ return sal_True;
+}
+
+// -----------------------------------------------------------------------
+
+// This function merges the independ driver data
+// and sets the new independ data in pJobSetup
+// Only the data must be changed, where the bit
+// in nGetDataFlags is set
+sal_Bool PspSalInfoPrinter::SetData(
+ sal_uLong nSetDataFlags,
+ ImplJobSetup* pJobSetup )
+{
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ if( aData.m_pParser )
+ {
+ const PPDKey* pKey;
+ const PPDValue* pValue;
+
+ // merge papersize if necessary
+ if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ int nWidth, nHeight;
+ if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT )
+ {
+ nWidth = pJobSetup->mnPaperWidth;
+ nHeight = pJobSetup->mnPaperHeight;
+ }
+ else
+ {
+ nWidth = pJobSetup->mnPaperHeight;
+ nHeight = pJobSetup->mnPaperWidth;
+ }
+ String aPaper;
+
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( pJobSetup->mnPaperWidth ),
+ TenMuToPt( pJobSetup->mnPaperHeight ) );
+ else
+ aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
+
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
+
+ // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5)
+ // try to find the correct paper anyway using the size
+ if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER )
+ {
+ PaperInfo aInfo( pJobSetup->mePaperFormat );
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( aInfo.getWidth() ),
+ TenMuToPt( aInfo.getHeight() ) );
+ pValue = pKey->getValueCaseInsensitive( aPaper );
+ }
+
+ if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
+ return sal_False;
+ }
+
+ // merge paperbin if necessary
+ if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
+ {
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( pKey )
+ {
+ int nPaperBin = pJobSetup->mnPaperBin;
+ if( nPaperBin >= pKey->countValues() )
+ pValue = pKey->getDefaultValue();
+ else
+ pValue = pKey->getValue( pJobSetup->mnPaperBin );
+
+ // may fail due to constraints;
+ // real paper bin is copied back to jobsetup in that case
+ aData.m_aContext.setValue( pKey, pValue );
+ }
+ // if printer has no InputSlot key simply ignore this setting
+ // (e.g. SGENPRT has no InputSlot)
+ }
+
+ // merge orientation if necessary
+ if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
+ aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
+
+ // merge duplex if necessary
+ if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
+ {
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( pKey )
+ {
+ pValue = NULL;
+ switch( pJobSetup->meDuplexMode )
+ {
+ case DUPLEX_OFF:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ if( pValue == NULL )
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) );
+ break;
+ case DUPLEX_SHORTEDGE:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) );
+ break;
+ case DUPLEX_LONGEDGE:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) );
+ break;
+ case DUPLEX_UNKNOWN:
+ default:
+ pValue = 0;
+ break;
+ }
+ if( ! pValue )
+ pValue = pKey->getDefaultValue();
+ aData.m_aContext.setValue( pKey, pValue );
+ }
+ }
+
+ m_aJobData = aData;
+ copyJobDataToJobSetup( pJobSetup, aData );
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::GetPageInfo(
+ const ImplJobSetup* pJobSetup,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight )
+{
+ if( ! pJobSetup )
+ return;
+
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ // get the selected page size
+ if( aData.m_pParser )
+ {
+
+ String aPaper;
+ int width, height;
+ int left = 0, top = 0, right = 0, bottom = 0;
+ int nDPI = aData.m_aContext.getRenderResolution();
+
+
+ if( aData.m_eOrientation == psp::orientation::Portrait )
+ {
+ aData.m_aContext.getPageSize( aPaper, width, height );
+ aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
+ }
+ else
+ {
+ aData.m_aContext.getPageSize( aPaper, height, width );
+ aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
+ }
+
+ rPageWidth = width * nDPI / 72;
+ rPageHeight = height * nDPI / 72;
+ rPageOffX = left * nDPI / 72;
+ rPageOffY = top * nDPI / 72;
+ rOutWidth = ( width - left - right ) * nDPI / 72;
+ rOutHeight = ( height - top - bottom ) * nDPI / 72;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
+{
+ if( ! pJobSetup )
+ return 0;
+
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
+ return pKey ? pKey->countValues() : 0;
+}
+
+// -----------------------------------------------------------------------
+
+String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin )
+{
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ String aRet;
+ if( aData.m_pParser )
+ {
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
+ if( ! pKey || nPaperBin >= (sal_uLong)pKey->countValues() )
+ aRet = aData.m_pParser->getDefaultInputSlot();
+ else
+ {
+ const PPDValue* pValue = pKey->getValue( nPaperBin );
+ if( pValue )
+ aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType )
+{
+ switch( nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return 1;
+ case PRINTER_CAPABILITIES_COPIES:
+ return 0xffff;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ {
+ // see if the PPD contains a value to set Collate to True
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL;
+ const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL;
+
+ // PPDs don't mention the number of possible collated copies.
+ // so let's guess as many as we want ?
+ return pVal ? 0xffff : 0;
+ }
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ return 1;
+ case PRINTER_CAPABILITIES_SETDUPLEX:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPER:
+ return 0;
+ case PRINTER_CAPABILITIES_FAX:
+ return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0;
+ case PRINTER_CAPABILITIES_PDF:
+ if( PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) )
+ return 1;
+ else
+ {
+ // see if the PPD contains a value to set Collate to True
+ JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
+ if( pJobSetup->mpDriverData )
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+ return aData.m_nPDFDevice > 0 ? 1 : 0;
+ }
+ case PRINTER_CAPABILITIES_EXTERNALDIALOG:
+ return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0;
+ case PRINTER_CAPABILITIES_USEPULLMODEL:
+ {
+ // see if the PPD contains a value to set Collate to True
+ JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
+ if( pJobSetup->mpDriverData )
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+ return aData.m_nPDFDevice > 0 ? 1 : 0;
+ }
+ default: break;
+ };
+ return 0;
+}
+
+// =======================================================================
+
+/*
+ * SalPrinter
+ */
+
+ PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
+ : m_bFax( false ),
+ m_bPdf( false ),
+ m_bSwallowFaxNo( false ),
+ m_bIsPDFWriterJob( false ),
+ m_pGraphics( NULL ),
+ m_nCopies( 1 ),
+ m_bCollate( false ),
+ m_pInfoPrinter( pInfoPrinter )
+{
+}
+
+// -----------------------------------------------------------------------
+
+PspSalPrinter::~PspSalPrinter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+static String getTmpName()
+{
+ rtl::OUString aTmp, aSys;
+ osl_createTempFile( NULL, NULL, &aTmp.pData );
+ osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
+
+ return aSys;
+}
+
+sal_Bool PspSalPrinter::StartJob(
+ const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ sal_uLong nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pJobSetup )
+{
+ vcl_sal::PrinterUpdate::jobStarted();
+
+ m_bFax = false;
+ m_bPdf = false;
+ m_aFileName = pFileName ? *pFileName : String();
+ m_aTmpFile = String();
+ m_nCopies = nCopies;
+ m_bCollate = bCollate;
+
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ if( m_nCopies > 1 )
+ {
+ // in case user did not do anything (m_nCopies=1)
+ // take the default from jobsetup
+ m_aJobData.m_nCopies = m_nCopies;
+ m_aJobData.setCollate( bCollate );
+ }
+
+ // check wether this printer is configured as fax
+ int nMode = 0;
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( ! aToken.compareToAscii( "fax", 3 ) )
+ {
+ m_bFax = true;
+ m_aTmpFile = getTmpName();
+ nMode = S_IRUSR | S_IWUSR;
+
+ ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
+ it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) );
+ if( it != pJobSetup->maValueMap.end() )
+ m_aFaxNr = it->second;
+
+ sal_Int32 nPos = 0;
+ m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false;
+
+ break;
+ }
+ if( ! aToken.compareToAscii( "pdf=", 4 ) )
+ {
+ m_bPdf = true;
+ m_aTmpFile = getTmpName();
+ nMode = S_IRUSR | S_IWUSR;
+
+ if( ! m_aFileName.Len() )
+ {
+ m_aFileName = getPdfDir( rInfo );
+ m_aFileName.Append( '/' );
+ m_aFileName.Append( rJobName );
+ m_aFileName.AppendAscii( ".pdf" );
+ }
+ break;
+ }
+ }
+ m_aPrinterGfx.Init( m_aJobData );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+
+ return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? sal_True : sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PspSalPrinter::EndJob()
+{
+ sal_Bool bSuccess = sal_False;
+ if( m_bIsPDFWriterJob )
+ bSuccess = sal_True;
+ else
+ {
+ bSuccess = m_aPrintJob.EndJob();
+
+ if( bSuccess )
+ {
+ // check for fax
+ if( m_bFax )
+ {
+
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ // sendAFax removes the file after use
+ bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
+ }
+ else if( m_bPdf )
+ {
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
+ }
+ }
+ }
+ vcl_sal::PrinterUpdate::jobEnded();
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PspSalPrinter::AbortJob()
+{
+ sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False;
+ vcl_sal::PrinterUpdate::jobEnded();
+ return bAbort;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool )
+{
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter );
+ m_pGraphics->SetLayout( 0 );
+ if( m_nCopies > 1 )
+ {
+ // in case user did not do anything (m_nCopies=1)
+ // take the default from jobsetup
+ m_aJobData.m_nCopies = m_nCopies;
+ m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
+ }
+
+ m_aPrintJob.StartPage( m_aJobData );
+ m_aPrinterGfx.Init( m_aPrintJob );
+
+ return m_pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PspSalPrinter::EndPage()
+{
+ sal_Bool bResult = m_aPrintJob.EndPage();
+ m_aPrinterGfx.Clear();
+ return bResult ? sal_True : sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong PspSalPrinter::GetErrorCode()
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+struct PDFNewJobParameters
+{
+ Size maPageSize;
+ sal_uInt16 mnPaperBin;
+
+ PDFNewJobParameters( const Size& i_rSize = Size(),
+ sal_uInt16 i_nPaperBin = 0xffff )
+ : maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {}
+
+ bool operator!=(const PDFNewJobParameters& rComp ) const
+ {
+ Size aCompLSSize( rComp.maPageSize.Height(), rComp.maPageSize.Width() );
+ return
+ (maPageSize != rComp.maPageSize && maPageSize != aCompLSSize)
+ || mnPaperBin != rComp.mnPaperBin
+ ;
+ }
+
+ bool operator==(const PDFNewJobParameters& rComp) const
+ {
+ return ! this->operator!=(rComp);
+ }
+};
+
+struct PDFPrintFile
+{
+ rtl::OUString maTmpURL;
+ PDFNewJobParameters maParameters;
+
+ PDFPrintFile( const rtl::OUString& i_rURL, const PDFNewJobParameters& i_rNewParameters )
+ : maTmpURL( i_rURL )
+ , maParameters( i_rNewParameters ) {}
+};
+
+sal_Bool PspSalPrinter::StartJob( const String* i_pFileName, const String& i_rJobName, const String& i_rAppName,
+ ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController )
+{
+ OSL_TRACE( "StartJob with controller: pFilename = %s", i_pFileName ? rtl::OUStringToOString( *i_pFileName, RTL_TEXTENCODING_UTF8 ).getStr() : "<nil>" );
+ // mark for endjob
+ m_bIsPDFWriterJob = true;
+ // reset IsLastPage
+ i_rController.setLastPage( sal_False );
+
+ // update job data
+ if( i_pSetupData )
+ JobData::constructFromStreamBuffer( i_pSetupData->mpDriverData, i_pSetupData->mnDriverDataLen, m_aJobData );
+
+ OSL_ASSERT( m_aJobData.m_nPDFDevice > 0 );
+ m_aJobData.m_nPDFDevice = 1;
+
+ // possibly create one job for collated output
+ sal_Bool bSinglePrintJobs = sal_False;
+ beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
+ if( pSingleValue )
+ {
+ pSingleValue->Value >>= bSinglePrintJobs;
+ }
+
+ int nCopies = i_rController.getPrinter()->GetCopyCount();
+ bool bCollate = i_rController.getPrinter()->IsCollateCopy();
+
+ // notify start of real print job
+ i_rController.jobStarted();
+
+ // setup PDFWriter context
+ vcl::PDFWriter::PDFWriterContext aContext;
+ aContext.Version = vcl::PDFWriter::PDF_1_4;
+ aContext.Tagged = false;
+ aContext.EmbedStandardFonts = true;
+ aContext.DocumentLocale = Application::GetSettings().GetLocale();
+ aContext.ColorMode = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales()
+ ? vcl::PDFWriter::DrawGreyscale : vcl::PDFWriter::DrawColor;
+
+ // prepare doc info
+ aContext.DocumentInfo.Title = i_rJobName;
+ aContext.DocumentInfo.Creator = i_rAppName;
+ aContext.DocumentInfo.Producer = i_rAppName;
+
+ // define how we handle metafiles in PDFWriter
+ vcl::PDFWriter::PlayMetafileContext aMtfContext;
+ aMtfContext.m_bOnlyLosslessCompression = true;
+
+ boost::shared_ptr<vcl::PDFWriter> pWriter;
+ std::vector< PDFPrintFile > aPDFFiles;
+ boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
+ int nAllPages = i_rController.getFilteredPageCount();
+ i_rController.createProgressDialog();
+ bool bAborted = false;
+ PDFNewJobParameters aLastParm;
+
+ aContext.DPIx = pPrinter->ImplGetDPIX();
+ aContext.DPIy = pPrinter->ImplGetDPIY();
+ for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ )
+ {
+ if( nPage == nAllPages-1 )
+ i_rController.setLastPage( sal_True );
+
+ // get the page's metafile
+ GDIMetaFile aPageFile;
+ vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile );
+ if( i_rController.isProgressCanceled() )
+ {
+ bAborted = true;
+ if( nPage != nAllPages-1 )
+ {
+ i_rController.createProgressDialog();
+ i_rController.setLastPage( sal_True );
+ i_rController.getFilteredPageFile( nPage, aPageFile );
+ }
+ }
+ else
+ {
+ pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
+ pPrinter->SetPaperSizeUser( aPageSize.aSize, true );
+ PDFNewJobParameters aNewParm( pPrinter->GetPaperSize(), pPrinter->GetPaperBin() );
+
+ // create PDF writer on demand
+ // either on first page
+ // or on paper format change - cups does not support multiple paper formats per job (yet?)
+ // so we need to start a new job to get a new paper format from the printer
+ // orientation switches (that is switch of height and width) is handled transparently by CUPS
+ if( ! pWriter ||
+ (aNewParm != aLastParm && ! i_pFileName ) )
+ {
+ if( pWriter )
+ {
+ pWriter->Emit();
+ }
+ // produce PDF file
+ OUString aPDFUrl;
+ if( i_pFileName )
+ aPDFUrl = *i_pFileName;
+ else
+ osl_createTempFile( NULL, NULL, &aPDFUrl.pData );
+ // normalize to file URL
+ if( aPDFUrl.compareToAscii( "file:", 5 ) != 0 )
+ {
+ // this is not a file URL, but it should
+ // form it into a osl friendly file URL
+ rtl::OUString aTmp;
+ osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData );
+ aPDFUrl = aTmp;
+ }
+ // save current file and paper format
+ aLastParm = aNewParm;
+ aPDFFiles.push_back( PDFPrintFile( aPDFUrl, aNewParm ) );
+ // update context
+ aContext.URL = aPDFUrl;
+
+ // create and initialize PDFWriter
+ #if defined __SUNPRO_CC
+ #pragma disable_warn
+ #endif
+ pWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) );
+ #if defined __SUNPRO_CC
+ #pragma enable_warn
+ #endif
+ }
+
+ pWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ),
+ TenMuToPt( aNewParm.maPageSize.Height() ),
+ vcl::PDFWriter::Portrait );
+
+ pWriter->PlayMetafile( aPageFile, aMtfContext, NULL );
+ }
+ }
+
+ // emit the last file
+ if( pWriter )
+ pWriter->Emit();
+
+ // handle collate, copy count and multiple jobs correctly
+ int nOuterJobs = 1;
+ if( bSinglePrintJobs )
+ {
+ nOuterJobs = nCopies;
+ m_aJobData.m_nCopies = 1;
+ }
+ else
+ {
+ if( bCollate )
+ {
+ if( aPDFFiles.size() == 1 && pPrinter->HasSupport( SUPPORT_COLLATECOPY ) )
+ {
+ m_aJobData.setCollate( true );
+ m_aJobData.m_nCopies = nCopies;
+ }
+ else
+ {
+ nOuterJobs = nCopies;
+ m_aJobData.m_nCopies = 1;
+ }
+ }
+ else
+ {
+ m_aJobData.setCollate( false );
+ m_aJobData.m_nCopies = nCopies;
+ }
+ }
+
+ // spool files
+ if( ! i_pFileName && ! bAborted )
+ {
+ bool bFirstJob = true;
+ for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ )
+ {
+ for( size_t i = 0; i < aPDFFiles.size(); i++ )
+ {
+ oslFileHandle pFile = NULL;
+ osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read );
+ if( pFile )
+ {
+ osl_setFilePos( pFile, osl_Pos_Absolut, 0 );
+ std::vector< char > buffer( 0x10000, 0 );
+ // update job data with current page size
+ Size aPageSize( aPDFFiles[i].maParameters.maPageSize );
+ m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) );
+ // update job data with current paperbin
+ m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin );
+
+ // spool current file
+ FILE* fp = PrinterInfoManager::get().startSpool( pPrinter->GetName(), i_rController.isDirectPrint() );
+ if( fp )
+ {
+ sal_uInt64 nBytesRead = 0;
+ do
+ {
+ osl_readFile( pFile, &buffer[0], buffer.size(), &nBytesRead );
+ if( nBytesRead > 0 )
+ fwrite( &buffer[0], 1, nBytesRead, fp );
+ } while( nBytesRead == buffer.size() );
+ rtl::OUStringBuffer aBuf( i_rJobName.Len() + 8 );
+ aBuf.append( i_rJobName );
+ if( i > 0 || nCurJob > 0 )
+ {
+ aBuf.append( sal_Unicode(' ') );
+ aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) );
+ }
+ PrinterInfoManager::get().endSpool( pPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob );
+ bFirstJob = false;
+ }
+ }
+ osl_closeFile( pFile );
+ }
+ }
+ }
+
+ // job has been spooled
+ i_rController.setJobState( bAborted ? view::PrintableState_JOB_ABORTED : view::PrintableState_JOB_SPOOLED );
+
+ // clean up the temporary PDF files
+ if( ! i_pFileName || bAborted )
+ {
+ for( size_t i = 0; i < aPDFFiles.size(); i++ )
+ {
+ osl_removeFile( aPDFFiles[i].maTmpURL.pData );
+ OSL_TRACE( "removed print PDF file %s\n", rtl::OUStringToOString( aPDFFiles[i].maTmpURL, RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ return sal_True;
+}
+
+
+
+/*
+ * vcl::PrinterUpdate
+ */
+
+Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL;
+int vcl_sal::PrinterUpdate::nActiveJobs = 0;
+
+void vcl_sal::PrinterUpdate::doUpdate()
+{
+ ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
+ if( rManager.checkPrintersChanged( false ) )
+ {
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ const std::list< SalFrame* >& rList = pDisp->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rList.begin();
+ it != rList.end(); ++it )
+ pDisp->SendInternalEvent( *it, NULL, SALEVENT_PRINTERCHANGED );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG )
+{
+ if( nActiveJobs < 1 )
+ {
+ doUpdate();
+ delete pPrinterUpdateTimer;
+ pPrinterUpdateTimer = NULL;
+ }
+ else
+ pPrinterUpdateTimer->Start();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void vcl_sal::PrinterUpdate::update()
+{
+ if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
+ return;
+
+ if( ! static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
+ {
+ // #i45389# start background printer detection
+ psp::PrinterInfoManager::get();
+ return;
+ }
+
+ if( nActiveJobs < 1 )
+ doUpdate();
+ else if( ! pPrinterUpdateTimer )
+ {
+ pPrinterUpdateTimer = new Timer();
+ pPrinterUpdateTimer->SetTimeout( 500 );
+ pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) );
+ pPrinterUpdateTimer->Start();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void vcl_sal::PrinterUpdate::jobEnded()
+{
+ nActiveJobs--;
+ if( nActiveJobs < 1 )
+ {
+ if( pPrinterUpdateTimer )
+ {
+ pPrinterUpdateTimer->Stop();
+ delete pPrinterUpdateTimer;
+ pPrinterUpdateTimer = NULL;
+ doUpdate();
+ }
+ }
+}
diff --git a/vcl/unx/generic/gdi/salvd.cxx b/vcl/unx/generic/gdi/salvd.cxx
new file mode 100644
index 000000000000..9f18ba6388ea
--- /dev/null
+++ b/vcl/unx/generic/gdi/salvd.cxx
@@ -0,0 +1,274 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/sysdata.hxx>
+
+#include <tools/prex.h>
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+
+#include <unx/salunx.h>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+#include <unx/salgdi.h>
+#include <unx/salvd.h>
+
+#include <salinst.hxx>
+
+// -=-= SalInstance =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalVirtualDevice* X11SalInstance::CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ sal_uInt16 nBitCount, const SystemGraphicsData *pData )
+{
+ X11SalVirtualDevice *pVDev = new X11SalVirtualDevice();
+ if( !nBitCount && pGraphics )
+ nBitCount = pGraphics->GetBitCount();
+
+ if( pData && pData->hDrawable != None )
+ {
+ XLIB_Window aRoot;
+ int x, y;
+ unsigned int w = 0, h = 0, bw, d;
+ Display* pDisp = GetX11SalData()->GetDisplay()->GetDisplay();
+ XGetGeometry( pDisp, pData->hDrawable,
+ &aRoot, &x, &y, &w, &h, &bw, &d );
+ int nScreen = 0;
+ while( nScreen < ScreenCount( pDisp ) )
+ {
+ if( RootWindow( pDisp, nScreen ) == aRoot )
+ break;
+ nScreen++;
+ }
+ nDX = (long)w;
+ nDY = (long)h;
+ if( !pVDev->Init( GetX11SalData()->GetDisplay(), nDX, nDY, nBitCount, nScreen, pData->hDrawable, pData->pRenderFormat ) )
+ {
+ delete pVDev;
+ return NULL;
+ }
+ }
+ else if( !pVDev->Init( GetX11SalData()->GetDisplay(), nDX, nDY, nBitCount,
+ pGraphics ? static_cast<X11SalGraphics*>(pGraphics)->GetScreenNumber() :
+ GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() ) )
+ {
+ delete pVDev;
+ return NULL;
+ }
+
+ pVDev->InitGraphics( pVDev );
+ return pVDev;
+}
+
+void X11SalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+// -=-= SalGraphicsData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::Init( X11SalVirtualDevice *pDevice, SalColormap* pColormap, bool bDeleteColormap )
+{
+ SalColormap *pOrigDeleteColormap = m_pDeleteColormap;
+
+ SalDisplay *pDisplay = pDevice->GetDisplay();
+ m_nScreen = pDevice->GetScreenNumber();
+
+ int nVisualDepth = pDisplay->GetColormap( m_nScreen ).GetVisual().GetDepth();
+ int nDeviceDepth = pDevice->GetDepth();
+
+ if( pColormap )
+ {
+ m_pColormap = pColormap;
+ if( bDeleteColormap )
+ m_pDeleteColormap = pColormap;
+ }
+ else
+ if( nDeviceDepth == nVisualDepth )
+ m_pColormap = &pDisplay->GetColormap( m_nScreen );
+ else
+ if( nDeviceDepth == 1 )
+ m_pColormap = m_pDeleteColormap = new SalColormap();
+
+ if (m_pDeleteColormap != pOrigDeleteColormap)
+ delete pOrigDeleteColormap;
+
+ const Drawable aVdevDrawable = pDevice->GetDrawable();
+ SetDrawable( aVdevDrawable, m_nScreen );
+
+ m_pVDev = pDevice;
+ m_pFrame = NULL;
+
+ bWindow_ = pDisplay->IsDisplay();
+ bVirDev_ = sal_True;
+}
+
+// -=-= SalVirDevData / SalVirtualDevice -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+sal_Bool X11SalVirtualDevice::Init( SalDisplay *pDisplay,
+ long nDX, long nDY,
+ sal_uInt16 nBitCount,
+ int nScreen,
+ Pixmap hDrawable,
+ void* pRenderFormatVoid )
+{
+ SalColormap* pColormap = NULL;
+ bool bDeleteColormap = false;
+
+ pDisplay_ = pDisplay;
+ pGraphics_ = new X11SalGraphics();
+ m_nScreen = nScreen;
+ if( pRenderFormatVoid ) {
+ XRenderPictFormat *pRenderFormat = ( XRenderPictFormat* )pRenderFormatVoid;
+ pGraphics_->SetXRenderFormat( pRenderFormat );
+ if( pRenderFormat->colormap )
+ pColormap = new SalColormap( pDisplay, pRenderFormat->colormap, m_nScreen );
+ else
+ pColormap = new SalColormap( nBitCount );
+ bDeleteColormap = true;
+ }
+ else if( nBitCount != pDisplay->GetVisual( m_nScreen ).GetDepth() )
+ {
+ pColormap = new SalColormap( nBitCount );
+ bDeleteColormap = true;
+ }
+ pGraphics_->SetLayout( 0 ); // by default no! mirroring for VirtualDevices, can be enabled with EnableRTL()
+ nDX_ = nDX;
+ nDY_ = nDY;
+ nDepth_ = nBitCount;
+
+ if( hDrawable == None )
+ hDrawable_ = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ nDX_, nDY_,
+ GetDepth() );
+ else
+ {
+ hDrawable_ = hDrawable;
+ bExternPixmap_ = sal_True;
+ }
+
+ pGraphics_->Init( this, pColormap, bDeleteColormap );
+
+ return hDrawable_ != None ? sal_True : sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalVirtualDevice::X11SalVirtualDevice()
+{
+ pDisplay_ = (SalDisplay*)ILLEGAL_POINTER;
+ pGraphics_ = NULL;
+ hDrawable_ = None;
+ nDX_ = 0;
+ nDY_ = 0;
+ nDepth_ = 0;
+ bGraphics_ = sal_False;
+ bExternPixmap_ = sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalVirtualDevice::~X11SalVirtualDevice()
+{
+ if( pGraphics_ )
+ delete pGraphics_;
+ pGraphics_ = NULL;
+
+ if( GetDrawable() && !bExternPixmap_ )
+ XFreePixmap( GetXDisplay(), GetDrawable() );
+}
+
+SalGraphics* X11SalVirtualDevice::GetGraphics()
+{
+ if( bGraphics_ )
+ return NULL;
+
+ if( pGraphics_ )
+ bGraphics_ = sal_True;
+
+ return pGraphics_;
+}
+
+void X11SalVirtualDevice::ReleaseGraphics( SalGraphics* )
+{ bGraphics_ = sal_False; }
+
+sal_Bool X11SalVirtualDevice::SetSize( long nDX, long nDY )
+{
+ if( bExternPixmap_ )
+ return sal_False;
+
+ // #144688#
+ // the X protocol request CreatePixmap puts an upper bound
+ // of 16 bit to the size. Beyond that there may be implementation
+ // limits of the Xserver; which we should catch by a failed XCreatePixmap
+ // call. However extra large values should be caught here since we'd run into
+ // 16 bit truncation here without noticing.
+ if( nDX < 0 || nDX > 65535 ||
+ nDY < 0 || nDY > 65535 )
+ return sal_False;
+
+ if( !nDX ) nDX = 1;
+ if( !nDY ) nDY = 1;
+
+ Pixmap h = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ nDX, nDY, nDepth_ );
+
+ if( !h )
+ {
+ if( !GetDrawable() )
+ {
+ hDrawable_ = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ 1, 1, nDepth_ );
+ nDX_ = 1;
+ nDY_ = 1;
+ }
+ return sal_False;
+ }
+
+ if( GetDrawable() )
+ XFreePixmap( GetXDisplay(), GetDrawable() );
+ hDrawable_ = h;
+
+ nDX_ = nDX;
+ nDY_ = nDY;
+
+ if( pGraphics_ )
+ InitGraphics( this );
+
+ return sal_True;
+}
+
+void X11SalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ rWidth = GetWidth();
+ rHeight = GetHeight();
+}
+
diff --git a/vcl/unx/generic/gdi/xrender_peer.cxx b/vcl/unx/generic/gdi/xrender_peer.cxx
new file mode 100644
index 000000000000..32e656bcbf5f
--- /dev/null
+++ b/vcl/unx/generic/gdi/xrender_peer.cxx
@@ -0,0 +1,247 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+
+#include <rtl/ustring.hxx>
+#include <osl/module.h>
+
+#include <unx/salunx.h>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+
+#include <xrender_peer.hxx>
+
+using namespace rtl;
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer::XRenderPeer()
+: mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() ),
+ mpStandardFormatA8( NULL ),
+ mnRenderVersion( 0 ),
+ mpRenderLib( NULL )
+#ifndef XRENDER_LINK
+, mpXRenderCompositeTrapezoids( NULL )
+, mpXRenderAddTraps( NULL )
+#endif // XRENDER_LINK
+{
+ InitRenderLib();
+}
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer::~XRenderPeer()
+{
+ osl_unloadModule( mpRenderLib );
+}
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer& XRenderPeer::GetInstance()
+{
+ static XRenderPeer aPeer;
+ return aPeer;
+}
+
+// ---------------------------------------------------------------------------
+
+void XRenderPeer::InitRenderLib()
+{
+ int nDummy;
+ if( !XQueryExtension( mpDisplay, "RENDER", &nDummy, &nDummy, &nDummy ) )
+ return;
+
+#ifndef XRENDER_LINK
+ // we don't know if we are running on a system with xrender library
+ // we don't want to install system libraries ourselves
+ // => load them dynamically when they are there
+ const OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrender.so.1" ));
+ mpRenderLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if( !mpRenderLib ) {
+#ifdef DEBUG
+ fprintf( stderr, "Display can do XRender, but no %s installed.\n"
+ "Please install for improved display performance\n", OUStringToOString( aLibName.getStr(),
+ osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return;
+ }
+
+ oslGenericFunction pFunc;
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderQueryExtension" );
+ if( !pFunc ) return;
+ mpXRenderQueryExtension = (Bool(*)(Display*,int*,int*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderQueryVersion" );
+ if( !pFunc ) return;
+ mpXRenderQueryVersion = (void(*)(Display*,int*,int*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindVisualFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindVisualFormat = (XRenderPictFormat*(*)(Display*,Visual*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindStandardFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindStandardFormat = (XRenderPictFormat*(*)(Display*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindFormat = (XRenderPictFormat*(*)(Display*,unsigned long,
+ const XRenderPictFormat*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCreateGlyphSet" );
+ if( !pFunc ) return;
+ mpXRenderCreateGlyphSet = (GlyphSet(*)(Display*,const XRenderPictFormat*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreeGlyphSet" );
+ if( !pFunc ) return;
+ mpXRenderFreeGlyphSet = (void(*)(Display*,GlyphSet))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderAddGlyphs" );
+ if( !pFunc ) return;
+ mpXRenderAddGlyphs = (void(*)(Display*,GlyphSet,Glyph*,const XGlyphInfo*,
+ int,const char*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreeGlyphs" );
+ if( !pFunc ) return;
+ mpXRenderFreeGlyphs = (void(*)(Display*,GlyphSet,Glyph*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCompositeString32" );
+ if( !pFunc ) return;
+ mpXRenderCompositeString32 = (void(*)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,GlyphSet,int,int,int,int,const unsigned*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCreatePicture" );
+ if( !pFunc ) return;
+ 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;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreePicture" );
+ if( !pFunc ) return;
+ mpXRenderFreePicture = (void(*)(Display*,Picture))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderComposite" );
+ if( !pFunc ) return;
+ mpXRenderComposite = (void(*)(Display*,int,Picture,Picture,Picture,
+ int,int,int,int,int,int,unsigned,unsigned))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFillRectangle" );
+ if( !pFunc ) return;
+ mpXRenderFillRectangle = (void(*)(Display*,int,Picture,const XRenderColor*,
+ int,int,unsigned int,unsigned int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCompositeTrapezoids" );
+#if 0 // not having trapezoid support is supported
+ if( !pFunc ) return;
+#endif
+ mpXRenderCompositeTrapezoids = (void(*)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,int,int,const XTrapezoid*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderAddTraps" );
+#if 0 // not having trapezoid support is supported
+ if( !pFunc ) return;
+#endif
+ mpXRenderAddTraps = (void(*)(Display*,Picture,int,int,const _XTrap*,int))pFunc;
+
+#endif // XRENDER_LINK
+
+ // needed to initialize libXrender internals, we already know its there
+#ifdef XRENDER_LINK
+ XRenderQueryExtension( mpDisplay, &nDummy, &nDummy );
+#else
+ (*mpXRenderQueryExtension)( mpDisplay, &nDummy, &nDummy );
+#endif
+
+ int nMajor, nMinor;
+#ifdef XRENDER_LINK
+ XRenderQueryVersion( mpDisplay, &nMajor, &nMinor );
+#else
+ (*mpXRenderQueryVersion)( mpDisplay, &nMajor, &nMinor );
+#endif
+ mnRenderVersion = 16*nMajor + nMinor;
+
+ // the 8bit alpha mask format must be there
+ XRenderPictFormat aPictFormat={0,0,8,{0,0,0,0,0,0,0,0xFF},0};
+ mpStandardFormatA8 = FindPictureFormat( PictFormatAlphaMask|PictFormatDepth, aPictFormat );
+}
+
+// ---------------------------------------------------------------------------
+
+// return mask of screens capable of XRENDER text
+sal_uInt32 XRenderPeer::InitRenderText()
+{
+ if( mnRenderVersion < 0x01 )
+ return 0;
+
+ // #93033# disable XRENDER for old RENDER versions if XINERAMA is present
+ int nDummy;
+ if( XQueryExtension( mpDisplay, "XINERAMA", &nDummy, &nDummy, &nDummy ) )
+ if( mnRenderVersion < 0x02 )
+ return 0;
+
+ if( !mpStandardFormatA8 )
+ return 0;
+
+ // and the visual must be supported too on at least one screen
+ sal_uInt32 nRetMask = 0;
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ const int nScreenCount = pSalDisp->GetScreenCount();
+ XRenderPictFormat* pVisualFormat = NULL;
+ int nMaxDepth = 0;
+ for( int nScreen = 0; nScreen < nScreenCount; ++nScreen )
+ {
+ Visual* pXVisual = pSalDisp->GetVisual( nScreen ).GetVisual();
+ pVisualFormat = FindVisualFormat( pXVisual );
+ if( pVisualFormat != NULL )
+ {
+ int nVDepth = pSalDisp->GetVisual( nScreen ).GetDepth();
+ if( nVDepth > nMaxDepth )
+ nMaxDepth = nVDepth;
+ nRetMask |= 1U << nScreen;
+ }
+ }
+
+ // #97763# disable XRENDER on <15bit displays for XFree<=4.2.0
+ if( mnRenderVersion <= 0x02 )
+ if( nMaxDepth < 15 )
+ nRetMask = 0;
+
+ return nRetMask;
+}
+
+// ---------------------------------------------------------------------------
diff --git a/vcl/unx/generic/gdi/xrender_peer.hxx b/vcl/unx/generic/gdi/xrender_peer.hxx
new file mode 100644
index 000000000000..89dccfcef40b
--- /dev/null
+++ b/vcl/unx/generic/gdi/xrender_peer.hxx
@@ -0,0 +1,387 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_XRENDER_PEER_HXX
+#define _SV_XRENDER_PEER_HXX
+
+#include <tools/prex.h>
+struct _XTrap; // on some older systems this is not declared within Xrender.h
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+
+#include <vcl/salgtype.hxx>
+#include <osl/module.h>
+
+class XRenderPeer
+{
+public:
+ static XRenderPeer& GetInstance();
+ int GetVersion() const;
+
+ sal_uInt32 InitRenderText();
+
+protected:
+ XRenderPeer();
+ ~XRenderPeer();
+ void InitRenderLib();
+
+ Display* mpDisplay;
+ XRenderPictFormat* mpStandardFormatA8;
+ int mnRenderVersion;
+ oslModule mpRenderLib;
+
+public:
+ XRenderPictFormat* GetStandardFormatA8() const;
+ XRenderPictFormat* FindStandardFormat(int nFormat) const;
+
+ // the methods below are thin wrappers for the XRENDER API
+ XRenderPictFormat* FindVisualFormat( Visual* ) const;
+ XRenderPictFormat* FindPictureFormat( unsigned long nMask,
+ 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,
+ int nXDst, int nYDst, unsigned nWidth, unsigned nHeight ) const;
+ void FreePicture( Picture ) const;
+
+ GlyphSet CreateGlyphSet() const;
+ void FreeGlyphSet( GlyphSet ) const;
+ void AddGlyph( GlyphSet, Glyph nGlyphId, const XGlyphInfo&,
+ const char* pBuffer, int nBufSize ) const;
+ void FreeGlyph( GlyphSet, Glyph nGlyphId ) const;
+ void CompositeString32( Picture aSrc, Picture aDst, GlyphSet,
+ int nDstX, int nDstY, const unsigned* pText, int nTextLen ) const;
+ void FillRectangle( int nOp, Picture aDst, const XRenderColor*,
+ int nX, int nY, unsigned nW, unsigned nH ) const;
+ void CompositeTrapezoids( int nOp, Picture aSrc, Picture aDst,
+ const XRenderPictFormat*, int nXSrc, int nYSrc,
+ const XTrapezoid*, int nCount ) const;
+ bool AddTraps( Picture aDst, int nXOfs, int nYOfs,
+ const _XTrap*, int nCount ) const;
+
+ bool AreTrapezoidsSupported() const
+#ifdef XRENDER_LINK
+ { return true; }
+#else
+ { return mpXRenderCompositeTrapezoids!=NULL; }
+
+private:
+ XRenderPictFormat* (*mpXRenderFindFormat)(Display*,unsigned long,
+ const XRenderPictFormat*,int);
+ XRenderPictFormat* (*mpXRenderFindVisualFormat)(Display*,Visual*);
+ XRenderPictFormat* (*mpXRenderFindStandardFormat)(Display*,int);
+ Bool (*mpXRenderQueryExtension)(Display*,int*,int*);
+ void (*mpXRenderQueryVersion)(Display*,int*,int*);
+
+ 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,
+ int,int,int,int,int,int,unsigned,unsigned);
+
+ GlyphSet (*mpXRenderCreateGlyphSet)(Display*, const XRenderPictFormat*);
+ void (*mpXRenderFreeGlyphSet)(Display*,GlyphSet);
+ void (*mpXRenderAddGlyphs)(Display*,GlyphSet,Glyph*,
+ const XGlyphInfo*,int,const char*,int);
+ void (*mpXRenderFreeGlyphs)(Display*,GlyphSet,Glyph*,int);
+ void (*mpXRenderCompositeString32)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,GlyphSet,int,int,int,int,const unsigned*,int);
+ void (*mpXRenderFillRectangle)(Display*,int,Picture,
+ const XRenderColor*,int,int,unsigned int,unsigned int);
+ void (*mpXRenderCompositeTrapezoids)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,int,int,const XTrapezoid*,int);
+ void (*mpXRenderAddTraps)(Display*,Picture,int,int,const _XTrap*,int);
+#endif // XRENDER_LINK
+};
+
+//=====================================================================
+
+class ScopedPic
+{
+public:
+ ScopedPic( XRenderPeer& rPeer, Picture& rPic );
+ ~ScopedPic();
+ Picture& Get();
+
+private:
+ XRenderPeer& mrRenderPeer;
+ Picture maPicture;
+
+private: // prevent copy and assignmet
+ ScopedPic( const ScopedPic& );
+ void operator=( const ScopedPic& );
+};
+
+//=====================================================================
+
+inline int XRenderPeer::GetVersion() const
+{
+ return mnRenderVersion;
+}
+
+inline XRenderPictFormat* XRenderPeer::GetStandardFormatA8() const
+{
+ return mpStandardFormatA8;
+}
+
+inline XRenderPictFormat* XRenderPeer::FindStandardFormat(int nFormat) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindStandardFormat(mpDisplay, nFormat);
+#else
+ return (*mpXRenderFindStandardFormat)(mpDisplay, nFormat);
+#endif
+}
+
+inline XRenderPictFormat* XRenderPeer::FindVisualFormat( Visual* pVisual ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindVisualFormat ( mpDisplay, pVisual );
+#else
+ return (*mpXRenderFindVisualFormat)( mpDisplay, pVisual );
+#endif
+}
+
+inline XRenderPictFormat* XRenderPeer::FindPictureFormat( unsigned long nFormatMask,
+ const XRenderPictFormat& rFormatAttr ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindFormat( mpDisplay, nFormatMask, &rFormatAttr, 0 );
+#else
+ return (*mpXRenderFindFormat)( mpDisplay, nFormatMask, &rFormatAttr, 0 );
+#endif
+}
+
+inline Picture XRenderPeer::CreatePicture( Drawable aDrawable,
+ const XRenderPictFormat* pVisFormat, unsigned long nValueMask,
+ const XRenderPictureAttributes* pRenderAttr ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderCreatePicture( mpDisplay, aDrawable, pVisFormat,
+ nValueMask, pRenderAttr );
+#else
+ return (*mpXRenderCreatePicture)( mpDisplay, aDrawable, pVisFormat,
+ nValueMask, pRenderAttr );
+#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
+{
+#ifdef XRENDER_LINK
+ XRenderSetPictureClipRegion( mpDisplay, aPicture, aXlibRegion );
+#else
+ (*mpXRenderSetPictureClipRegion)( mpDisplay, aPicture, aXlibRegion );
+#endif
+}
+
+inline void XRenderPeer::CompositePicture( int nXRenderOp,
+ Picture aSrcPic, Picture aMaskPic, Picture aDstPic,
+ int nSrcX, int nSrcY, int nMaskX, int nMaskY, int nDstX, int nDstY,
+ unsigned nWidth, unsigned nHeight ) const
+{
+#ifdef XRENDER_LINK
+ XRenderComposite( mpDisplay, nXRenderOp, aSrcPic, aMaskPic, aDstPic,
+ nSrcX, nSrcY, nMaskX, nMaskY, nDstX, nDstY, nWidth, nHeight );
+#else
+ (*mpXRenderComposite)( mpDisplay, nXRenderOp, aSrcPic, aMaskPic, aDstPic,
+ nSrcX, nSrcY, nMaskX, nMaskY, nDstX, nDstY, nWidth, nHeight );
+#endif
+}
+
+inline void XRenderPeer::FreePicture( Picture aPicture ) const
+{
+#ifdef XRENDER_LINK
+ XRenderFreePicture( mpDisplay, aPicture );
+#else
+ (*mpXRenderFreePicture)( mpDisplay, aPicture );
+#endif
+}
+
+inline GlyphSet XRenderPeer::CreateGlyphSet() const
+{
+#ifdef XRENDER_LINK
+ return XRenderCreateGlyphSet( mpDisplay, mpStandardFormatA8 );
+#else
+ return (*mpXRenderCreateGlyphSet)( mpDisplay, mpStandardFormatA8 );
+#endif
+}
+
+inline void XRenderPeer::FreeGlyphSet( GlyphSet aGS ) const
+{
+#ifdef XRENDER_LINK
+ XRenderFreeGlyphSet( mpDisplay, aGS );
+#else
+ (*mpXRenderFreeGlyphSet)( mpDisplay, aGS );
+#endif
+}
+
+inline void XRenderPeer::AddGlyph( GlyphSet aGS, Glyph nGlyphId,
+ const XGlyphInfo& rGI, const char* pBuffer, int nBufSize ) const
+{
+#ifdef XRENDER_LINK
+ XRenderAddGlyphs( mpDisplay, aGS, &nGlyphId, &rGI, 1,
+ const_cast<char*>(pBuffer), nBufSize );
+#else
+ (*mpXRenderAddGlyphs)( mpDisplay, aGS, &nGlyphId, &rGI, 1,
+ const_cast<char*>(pBuffer), nBufSize );
+#endif
+}
+
+inline void XRenderPeer::FreeGlyph( GlyphSet aGS, Glyph nGlyphId ) const
+{
+ (void)aGS; (void)nGlyphId;
+
+ // XRenderFreeGlyphs not implemented yet for version<=0.2
+ // #108209# disabled because of crash potential,
+ // the glyph leak is not too bad because they will
+ // be cleaned up when the glyphset is released
+#if 0 // TODO: reenable when it works without problems
+ if( mnRenderVersion >= 0x05 )
+ {
+#ifdef XRENDER_LINK
+ XRenderFreeGlyphs( mpDisplay, aGS, &nGlyphId, 1 );
+#else
+ (*mpXRenderFreeGlyphs)( mpDisplay, aGS, &nGlyphId, 1 );
+#endif
+ }
+#endif
+}
+
+inline void XRenderPeer::CompositeString32( Picture aSrc, Picture aDst,
+ GlyphSet aGlyphSet, int nDstX, int nDstY,
+ const unsigned* pText, int nTextLen ) const
+{
+#ifdef XRENDER_LINK
+ XRenderCompositeString32( mpDisplay, PictOpOver, aSrc, aDst, NULL,
+ aGlyphSet, 0, 0, nDstX, nDstY, pText, nTextLen );
+#else
+ (*mpXRenderCompositeString32)( mpDisplay, PictOpOver, aSrc, aDst, NULL,
+ aGlyphSet, 0, 0, nDstX, nDstY, pText, nTextLen );
+#endif
+}
+
+inline void XRenderPeer::FillRectangle( int a, Picture b, const XRenderColor* c,
+ int d, int e, unsigned int f, unsigned int g) const
+{
+#ifdef XRENDER_LINK
+ XRenderFillRectangle( mpDisplay, a, b, c, d, e, f, g );
+#else
+ (*mpXRenderFillRectangle)( mpDisplay, a, b, c, d, e, f, g );
+#endif
+}
+
+
+inline void XRenderPeer::CompositeTrapezoids( int nOp,
+ Picture aSrc, Picture aDst, const XRenderPictFormat* pXRPF,
+ int nXSrc, int nYSrc, const XTrapezoid* pXT, int nCount ) const
+{
+#ifdef XRENDER_LINK
+ XRenderCompositeTrapezoids( mpDisplay, nOp, aSrc, aDst, pXRPF,
+ nXSrc, nYSrc, pXT, nCount );
+#else
+ (*mpXRenderCompositeTrapezoids)( mpDisplay, nOp, aSrc, aDst, pXRPF,
+ nXSrc, nYSrc, pXT, nCount );
+#endif
+}
+
+inline bool XRenderPeer::AddTraps( Picture aDst, int nXOfs, int nYOfs,
+ const _XTrap* pTraps, int nCount ) const
+{
+#ifdef XRENDER_LINK
+ XRenderAddTraps( mpDisplay, aDst, nXOfs, nYOfs, pTraps, nCount );
+#else
+ if( !mpXRenderAddTraps )
+ return false;
+ (*mpXRenderAddTraps)( mpDisplay, aDst, nXOfs, nYOfs, pTraps, nCount );
+#endif
+ return true;
+}
+
+//=====================================================================
+
+inline ScopedPic::ScopedPic( XRenderPeer& rPeer, Picture& rPic )
+: mrRenderPeer( rPeer)
+, maPicture( rPic )
+{}
+
+inline ScopedPic::~ScopedPic()
+{
+ if( maPicture )
+ mrRenderPeer.FreePicture( maPicture );
+}
+
+inline Picture& ScopedPic::Get()
+{
+ return maPicture;
+}
+
+//=====================================================================
+
+inline XRenderColor GetXRenderColor( const SalColor& rSalColor, double fTransparency = 0.0 )
+{
+ XRenderColor aRetVal;
+ // convert the SalColor
+ aRetVal.red = SALCOLOR_RED( rSalColor ); aRetVal.red |= (aRetVal.red << 8);
+ aRetVal.green = SALCOLOR_GREEN( rSalColor ); aRetVal.green |= (aRetVal.green << 8);
+ aRetVal.blue = SALCOLOR_BLUE( rSalColor ); aRetVal.blue |= (aRetVal.blue << 8);
+
+ // handle transparency
+ aRetVal.alpha = 0xFFFF; // default to opaque
+ if( fTransparency != 0 )
+ {
+ const double fAlpha = 1.0 - fTransparency;
+ aRetVal.alpha = static_cast<sal_uInt16>(fAlpha * 0xFFFF + 0.5);
+ // xrender wants pre-multiplied colors
+ aRetVal.red = static_cast<sal_uInt16>(fAlpha * aRetVal.red + 0.5);
+ aRetVal.green = static_cast<sal_uInt16>(fAlpha * aRetVal.green + 0.5);
+ aRetVal.blue = static_cast<sal_uInt16>(fAlpha * aRetVal.blue + 0.5);
+ }
+
+ return aRetVal;
+}
+
+//=====================================================================
+
+#endif // _SV_XRENDER_PEER_HXX