diff options
Diffstat (limited to 'vcl/unx/generic/gdi')
-rw-r--r-- | vcl/unx/generic/gdi/cdeint.cxx | 244 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/dtint.cxx | 139 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/dtsetenum.hxx | 146 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/gcach_xpeer.cxx | 683 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/gcach_xpeer.hxx | 92 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/pspgraphics.cxx | 1504 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salbmp.cxx | 1096 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salcvt.cxx | 341 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salcvt.hxx | 93 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salgdi.cxx | 1273 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salgdi2.cxx | 1151 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salgdi3.cxx | 1690 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salprnpsp.cxx | 1462 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salvd.cxx | 274 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/xrender_peer.cxx | 247 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/xrender_peer.hxx | 387 |
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 |