summaryrefslogtreecommitdiff
path: root/vcl/unx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx')
-rw-r--r--vcl/unx/gtk/window/gtkframe.cxx26
-rw-r--r--vcl/unx/headless/svpprn.cxx69
-rw-r--r--vcl/unx/headless/svpprn.hxx8
-rw-r--r--vcl/unx/headless/svppspgraphics.cxx30
-rw-r--r--vcl/unx/headless/svppspgraphics.hxx8
-rw-r--r--vcl/unx/inc/dtint.hxx3
-rw-r--r--vcl/unx/inc/macosxint.hxx48
-rw-r--r--vcl/unx/inc/prex.h2
-rw-r--r--vcl/unx/inc/pspgraphics.h14
-rw-r--r--vcl/unx/inc/saldata.hxx2
-rw-r--r--vcl/unx/inc/saldisp.hxx3
-rw-r--r--vcl/unx/inc/salinst.h3
-rw-r--r--vcl/unx/inc/salprn.h8
-rw-r--r--vcl/unx/inc/salunx.h2
-rw-r--r--vcl/unx/inc/xsalprn.h192
-rw-r--r--vcl/unx/source/app/i18n_ic.cxx4
-rw-r--r--vcl/unx/source/app/i18n_im.cxx9
-rw-r--r--vcl/unx/source/app/i18n_wrp.cxx13
-rw-r--r--vcl/unx/source/app/keysymnames.cxx11
-rw-r--r--vcl/unx/source/app/makefile.mk1
-rw-r--r--vcl/unx/source/app/saldisp.cxx28
-rw-r--r--vcl/unx/source/app/salinst.cxx153
-rw-r--r--vcl/unx/source/app/wmadaptor.cxx6
-rw-r--r--vcl/unx/source/fontmanager/adobeenc.tab1090
-rwxr-xr-xvcl/unx/source/fontmanager/afm_hash.cpp245
-rwxr-xr-xvcl/unx/source/fontmanager/afm_keyword_list58
-rw-r--r--vcl/unx/source/fontmanager/fontcache.cxx821
-rw-r--r--vcl/unx/source/fontmanager/fontconfig.cxx1078
-rw-r--r--vcl/unx/source/fontmanager/fontmanager.cxx4008
-rw-r--r--vcl/unx/source/fontmanager/helper.cxx407
-rw-r--r--vcl/unx/source/fontmanager/makefile.mk76
-rw-r--r--vcl/unx/source/fontmanager/parseAFM.cxx1569
-rw-r--r--vcl/unx/source/fontmanager/parseAFM.hxx344
-rw-r--r--vcl/unx/source/gdi/dtint.cxx6
-rw-r--r--vcl/unx/source/gdi/gcach_xpeer.cxx3
-rw-r--r--vcl/unx/source/gdi/macosxint.cxx250
-rw-r--r--vcl/unx/source/gdi/macosxrc.txt33
-rw-r--r--vcl/unx/source/gdi/makefile.mk8
-rw-r--r--vcl/unx/source/gdi/pspgraphics.cxx24
-rw-r--r--vcl/unx/source/gdi/salgdi.cxx41
-rw-r--r--vcl/unx/source/gdi/salgdi2.cxx28
-rw-r--r--vcl/unx/source/gdi/salgdi3.cxx68
-rw-r--r--vcl/unx/source/gdi/salprnpsp.cxx87
-rw-r--r--vcl/unx/source/gdi/xprintext.cxx656
-rw-r--r--vcl/unx/source/gdi/xrender_peer.cxx4
-rw-r--r--vcl/unx/source/printer/cupsmgr.cxx1140
-rw-r--r--vcl/unx/source/printer/jobdata.cxx207
-rw-r--r--vcl/unx/source/printer/makefile.mk74
-rw-r--r--vcl/unx/source/printer/ppdparser.cxx1876
-rw-r--r--vcl/unx/source/printer/printerinfomanager.cxx1472
-rw-r--r--vcl/unx/source/printergfx/bitmap_gfx.cxx735
-rw-r--r--vcl/unx/source/printergfx/common_gfx.cxx1310
-rw-r--r--vcl/unx/source/printergfx/glyphset.cxx908
-rw-r--r--vcl/unx/source/printergfx/glyphset.hxx138
-rw-r--r--vcl/unx/source/printergfx/makefile.mk69
-rw-r--r--vcl/unx/source/printergfx/printerjob.cxx1197
-rw-r--r--vcl/unx/source/printergfx/psheader.ps372
-rw-r--r--vcl/unx/source/printergfx/psputil.cxx271
-rw-r--r--vcl/unx/source/printergfx/psputil.hxx81
-rw-r--r--vcl/unx/source/printergfx/text_gfx.cxx865
-rw-r--r--vcl/unx/source/window/salframe.cxx120
61 files changed, 20741 insertions, 1641 deletions
diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx
index 630b034733a4..8e280675866a 100644
--- a/vcl/unx/gtk/window/gtkframe.cxx
+++ b/vcl/unx/gtk/window/gtkframe.cxx
@@ -84,20 +84,10 @@ static USHORT GetKeyModCode( guint state )
USHORT nCode = 0;
if( (state & GDK_SHIFT_MASK) )
nCode |= KEY_SHIFT;
- if( (state & GDK_CONTROL_MASK)
-#ifdef MACOSX
- || (state & GDK_MOD2_MASK) // map Meta (aka Command key) to Ctrl
-#endif
- )
+ if( (state & GDK_CONTROL_MASK) )
nCode |= KEY_MOD1;
if( (state & GDK_MOD1_MASK) )
- {
nCode |= KEY_MOD2;
-#ifdef MACOSX
- if( ! (nCode & KEY_MOD1) )
- nCode |= KEY_MOD3;
-#endif
- }
return nCode;
}
@@ -2951,35 +2941,21 @@ gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame
// The modifier mode therefore has to be adapted manually.
switch( pEvent->keyval )
{
-#ifdef MACOSX
- case GDK_Meta_L: // map Meta (aka Command key) to Ctrl
-#endif
case GDK_Control_L:
nExtModMask = MODKEY_LMOD1;
nModMask = KEY_MOD1;
break;
-#ifdef MACOSX
- case GDK_Meta_R: // map Meta (aka Command key) to Ctrl
-#endif
case GDK_Control_R:
nExtModMask = MODKEY_RMOD1;
nModMask = KEY_MOD1;
break;
case GDK_Alt_L:
nExtModMask = MODKEY_LMOD2;
-#ifdef MACOSX
- nModMask = KEY_MOD3;
-#else
nModMask = KEY_MOD2;
-#endif
break;
case GDK_Alt_R:
nExtModMask = MODKEY_RMOD2;
-#ifdef MACOSX
- nModMask = KEY_MOD2 | (pEvent->type == GDK_KEY_RELEASE ? KEY_MOD3 : 0);
-#else
nModMask = KEY_MOD2;
-#endif
break;
case GDK_Shift_L:
nExtModMask = MODKEY_LSHIFT;
diff --git a/vcl/unx/headless/svpprn.cxx b/vcl/unx/headless/svpprn.cxx
index 0ac79afeec88..e9d726464921 100644
--- a/vcl/unx/headless/svpprn.cxx
+++ b/vcl/unx/headless/svpprn.cxx
@@ -28,17 +28,17 @@
*
************************************************************************/
-#include <vcl/svapp.hxx>
-#include <vcl/jobset.h>
+#include "vcl/svapp.hxx"
+#include "vcl/jobset.h"
+#include "vcl/print.h"
+#include "vcl/salptype.hxx"
+#include "vcl/timer.hxx"
+#include "vcl/printerinfomanager.hxx"
+
#include "svpprn.hxx"
-#include <vcl/print.h>
-#include <vcl/salptype.hxx>
-#include <vcl/timer.hxx>
#include "svppspgraphics.hxx"
#include "svpinst.hxx"
-#include <psprint/printerinfomanager.hxx>
-
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
@@ -623,58 +623,13 @@ BOOL PspSalInfoPrinter::SetData(
}
String aPaper;
-#ifdef MACOSX
- // For Mac OS X, many printers are directly attached
- // USB/Serial printers with a stripped-down PPD that gives us
- // problems. We need to do PS->PDF conversion for these printers
- // but they are not able to handle multiple page sizes in the same
- // document at all, since we must pass -o media=... to them to get
- // a good printout.
- // So, we must find a match between the paper size from OOo and what
- // the PPD of the printer has, and pass that paper size to -o media=...
- // If a match cannot be found (ie the paper size from Format->Page is
- // nowhere near anything in the PPD), we default to what has been
- // chosen in File->Print->Properties.
- //
- // For printers capable of directly accepting PostScript data, none
- // of this occurs and we default to the normal OOo behavior.
- const PPDKey *pCupsFilterKey;
- const PPDValue *pCupsFilterValue;
- BOOL bIsCUPSPrinter = TRUE;
-
- // Printers that need PS->PDF conversion have a "cupsFilter" key and
- // a value of "application/pdf" in that key
- pCupsFilterKey = aData.m_pParser->getKey( String(RTL_CONSTASCII_USTRINGPARAM("cupsFilter")) );
- pCupsFilterValue = pCupsFilterKey != NULL ? aData.m_aContext.getValue( pCupsFilterKey ) : NULL;
- if ( pCupsFilterValue )
- {
- // PPD had a cupsFilter key, check for PS->PDF conversion requirement
- ByteString aCupsFilterString( pCupsFilterValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 );
- if ( aCupsFilterString.Search("application/pdf") == 0 )
- bIsCUPSPrinter = FALSE;
- }
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( pJobSetup->mnPaperWidth ),
+ TenMuToPt( pJobSetup->mnPaperHeight ) );
else
- bIsCUPSPrinter = FALSE;
+ aPaper = String( ByteString( aPaperTab[ pJobSetup->mePaperFormat ].name ), RTL_TEXTENCODING_ISO_8859_1 );
- if ( TRUE == bIsCUPSPrinter )
- {
- // If its a directly attached printer, with a
- // stripped down PPD (most OS X printers are) always
- // match the paper size.
- aPaper = aData.m_pParser->matchPaper(
- TenMuToPt( pJobSetup->mnPaperWidth ),
- TenMuToPt( pJobSetup->mnPaperHeight ) );
- }
- else
-#endif
- {
- if( pJobSetup->mePaperFormat == PAPER_USER )
- aPaper = aData.m_pParser->matchPaper(
- TenMuToPt( pJobSetup->mnPaperWidth ),
- TenMuToPt( pJobSetup->mnPaperHeight ) );
- else
- aPaper = String( ByteString( aPaperTab[ pJobSetup->mePaperFormat ].name ), RTL_TEXTENCODING_ISO_8859_1 );
- }
pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
pValue = pKey ? pKey->getValue( aPaper ) : NULL;
if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
diff --git a/vcl/unx/headless/svpprn.hxx b/vcl/unx/headless/svpprn.hxx
index eef8865fb56b..c2d85c054fce 100644
--- a/vcl/unx/headless/svpprn.hxx
+++ b/vcl/unx/headless/svpprn.hxx
@@ -31,10 +31,10 @@
#ifndef _SVP_SVPPRN_HXX
#define _SVP_SVPPRN_HXX
-#include <psprint/jobdata.hxx>
-#include <psprint/printergfx.hxx>
-#include <psprint/printerjob.hxx>
-#include <vcl/salprn.hxx>
+#include "vcl/jobdata.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/printerjob.hxx"
+#include "vcl/salprn.hxx"
class PspGraphics;
diff --git a/vcl/unx/headless/svppspgraphics.cxx b/vcl/unx/headless/svppspgraphics.cxx
index 12302c1bbae2..2ff48966c765 100644
--- a/vcl/unx/headless/svppspgraphics.cxx
+++ b/vcl/unx/headless/svppspgraphics.cxx
@@ -29,22 +29,24 @@
************************************************************************/
#include "svppspgraphics.hxx"
-#include <psprint/jobdata.hxx>
-#include <psprint/printergfx.hxx>
-#include <psprint/printerinfomanager.hxx>
-#include <vcl/bmpacc.hxx>
-#include <vcl/salbmp.hxx>
-#include <vcl/glyphcache.hxx>
-#include <vcl/impfont.hxx>
-#include <vcl/outfont.hxx>
-#include <vcl/svapp.hxx>
-#include <vcl/salprn.hxx>
-#include <vcl/sysdata.hxx>
-#include <basegfx/vector/b2ivector.hxx>
-#include <basegfx/point/b2ipoint.hxx>
-#include <basebmp/color.hxx>
#include "svpbmp.hxx"
+#include "vcl/jobdata.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/bmpacc.hxx"
+#include "vcl/salbmp.hxx"
+#include "vcl/glyphcache.hxx"
+#include "vcl/impfont.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/salprn.hxx"
+#include "vcl/sysdata.hxx"
+
+#include "basegfx/vector/b2ivector.hxx"
+#include "basegfx/point/b2ipoint.hxx"
+#include "basebmp/color.hxx"
+
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
diff --git a/vcl/unx/headless/svppspgraphics.hxx b/vcl/unx/headless/svppspgraphics.hxx
index 9cbbac446477..ba7d690a9f90 100644
--- a/vcl/unx/headless/svppspgraphics.hxx
+++ b/vcl/unx/headless/svppspgraphics.hxx
@@ -32,11 +32,9 @@
#define _SVP_PSPGRAPHICS_HXX
-#ifndef _PSPRINT_FONTMANAGER_HXX
-#include <psprint/fontmanager.hxx>
-#endif
-#include <vcl/sallayout.hxx>
-#include <vcl/salgdi.hxx>
+#include "vcl/fontmanager.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/salgdi.hxx"
namespace psp { struct JobData; class PrinterGfx; }
diff --git a/vcl/unx/inc/dtint.hxx b/vcl/unx/inc/dtint.hxx
index b7cc8941219f..e65e41a73af5 100644
--- a/vcl/unx/inc/dtint.hxx
+++ b/vcl/unx/inc/dtint.hxx
@@ -49,8 +49,7 @@ struct XEvent;
enum DtType {
DtGeneric,
- DtCDE,
- DtMACOSX
+ DtCDE
};
class DtIntegrator
diff --git a/vcl/unx/inc/macosxint.hxx b/vcl/unx/inc/macosxint.hxx
deleted file mode 100644
index 86b5f34840df..000000000000
--- a/vcl/unx/inc/macosxint.hxx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*************************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * Copyright 2008 by Sun Microsystems, Inc.
- *
- * OpenOffice.org - a multi-platform office productivity suite
- *
- * $RCSfile: macosxint.hxx,v $
- * $Revision: 1.3 $
- *
- * 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_MACOSXINT_HXX
-#define _SV_MACOSXINT_HXX
-
-#include <dtint.hxx>
-#include <tools/list.hxx>
-
-class MACOSXIntegrator : public DtIntegrator
-{
- friend DtIntegrator* DtIntegrator::CreateDtIntegrator();
-private:
- MACOSXIntegrator();
-
-public:
- virtual ~MACOSXIntegrator();
-
- virtual void GetSystemLook( AllSettings& rSettings );
-};
-
-#endif
diff --git a/vcl/unx/inc/prex.h b/vcl/unx/inc/prex.h
index 705e33ca5188..131e628efe2e 100644
--- a/vcl/unx/inc/prex.h
+++ b/vcl/unx/inc/prex.h
@@ -50,7 +50,7 @@
extern "C" {
#endif
-#if defined(LINUX) || defined(FREEBSD) || defined(MACOSX) // should really check for xfree86 or for X11R6.1 and higher
+#if defined(LINUX) || defined(FREEBSD) // should really check for xfree86 or for X11R6.1 and higher
#define __XKeyboardExtension__ 1
#else
#define __XKeyboardExtension__ 0
diff --git a/vcl/unx/inc/pspgraphics.h b/vcl/unx/inc/pspgraphics.h
index c8c0abf29fd6..5c31d889453c 100644
--- a/vcl/unx/inc/pspgraphics.h
+++ b/vcl/unx/inc/pspgraphics.h
@@ -32,16 +32,12 @@
#define _VCL_PSPGRAPHICS_H
-#include <vcl/salgdi.hxx>
-#ifndef _PSPRINT_FONTMANAGER_HXX
-#include <psprint/fontmanager.hxx>
-#endif
-#include <vcl/sallayout.hxx>
-#include <vcl/dllapi.h>
-
-#ifndef _USE_PRINT_EXTENSION_
+#include "vcl/fontmanager.hxx"
+#include "vcl/salgdi.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/dllapi.h"
+
namespace psp { struct JobData; class PrinterGfx; }
-#endif
class ServerFont;
class ImplDevFontAttributes;
diff --git a/vcl/unx/inc/saldata.hxx b/vcl/unx/inc/saldata.hxx
index e62b00952663..a4326990c464 100644
--- a/vcl/unx/inc/saldata.hxx
+++ b/vcl/unx/inc/saldata.hxx
@@ -51,7 +51,7 @@ class SalPrinter;
DECLARE_LIST( SalDisplays, SalDisplay* )
-#if defined SCO || defined LINUX || defined NETBSD || defined AIX || defined HPUX || defined FREEBSD || defined MACOSX
+#if defined SCO || defined LINUX || defined NETBSD || defined AIX || defined HPUX || defined FREEBSD
#include <pthread.h>
#else
typedef unsigned int pthread_t;
diff --git a/vcl/unx/inc/saldisp.hxx b/vcl/unx/inc/saldisp.hxx
index dbb8b7bd7ec4..9f9383106615 100644
--- a/vcl/unx/inc/saldisp.hxx
+++ b/vcl/unx/inc/saldisp.hxx
@@ -384,9 +384,6 @@ protected:
KeySym nShiftKeySym_; // first shift modifier
KeySym nCtrlKeySym_; // first control modifier
KeySym nMod1KeySym_; // first mod1 modifier
-#ifdef MACOSX
- KeySym nMod2KeySym_; //first mod2 modifier
-#endif
ByteString m_aKeyboardName;
vcl_sal::WMAdaptor* m_pWMAdaptor;
diff --git a/vcl/unx/inc/salinst.h b/vcl/unx/inc/salinst.h
index e35774b01f02..c0614a78af9b 100644
--- a/vcl/unx/inc/salinst.h
+++ b/vcl/unx/inc/salinst.h
@@ -113,7 +113,8 @@ public:
virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData );
virtual void DestroyMenuItem( SalMenuItem* pItem );
- virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes );
+ virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes );
+ void FillFontPathList( std::list< rtl::OString >& o_rFontPaths );
bool isPrinterInit() const
diff --git a/vcl/unx/inc/salprn.h b/vcl/unx/inc/salprn.h
index 51e22dbbe589..452fa5a89387 100644
--- a/vcl/unx/inc/salprn.h
+++ b/vcl/unx/inc/salprn.h
@@ -31,10 +31,10 @@
#ifndef _SV_SALPRN_H
#define _SV_SALPRN_H
-#include <psprint/jobdata.hxx>
-#include <psprint/printergfx.hxx>
-#include <psprint/printerjob.hxx>
-#include <vcl/salprn.hxx>
+#include "vcl/jobdata.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/printerjob.hxx"
+#include "vcl/salprn.hxx"
class PspGraphics;
diff --git a/vcl/unx/inc/salunx.h b/vcl/unx/inc/salunx.h
index ed9368895f0c..cdf45fd30867 100644
--- a/vcl/unx/inc/salunx.h
+++ b/vcl/unx/inc/salunx.h
@@ -32,7 +32,7 @@
#define _SALUNX_H
// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-#if defined SCO || defined LINUX || defined HPUX || defined FREEBSD || defined NETBSD || defined MACOSX
+#if defined SCO || defined LINUX || defined HPUX || defined FREEBSD || defined NETBSD
#include <sys/time.h>
#elif defined AIX
#include <time.h>
diff --git a/vcl/unx/inc/xsalprn.h b/vcl/unx/inc/xsalprn.h
deleted file mode 100644
index ac72454c70ab..000000000000
--- a/vcl/unx/inc/xsalprn.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*************************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * Copyright 2008 by Sun Microsystems, Inc.
- *
- * OpenOffice.org - a multi-platform office productivity suite
- *
- * $RCSfile: xsalprn.h,v $
- * $Revision: 1.4 $
- *
- * 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 __salprint_h
-#define __salprint_h
-
-
-class String;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* printer interface */
-extern int XSalIsDisplay( const Display * );
-extern int XSalIsPrinter( const Display * );
-
-/* error handling */
-typedef int (*XSalPrinterErrorHandler)( XErrorEvent * );
-
-extern XSalPrinterErrorHandler XSalSetPrinterErrorHandler( XSalPrinterErrorHandler );
-
-/* common callbacks */
-typedef void* XSalPointer;
-typedef int (*XSalPrinterCallback)( XSalPointer cb_data, XSalPointer client_data );
-
-#ifndef _SV_SV_H
-#define _SV_SV_H
-#define USHORT unsigned short
-#include <vcl/prntypes.hxx>
-#undef USHORT
-#undef _SV_SV_H
-#else
-#include <vcl/prntypes.hxx>
-#endif
-
-typedef enum Orientation Orientation;
-
-/* initialize before first use */
-extern void XSalPrinterInit( const String& installPath );
-
-typedef unsigned short XSalEnum;
-typedef unsigned char XSalBool;
-
-#define COLOR_SPACE_COLOR 1
-#define COLOR_SPACE_GRAY 0
-
-typedef struct
-{
- unsigned int nMagic; /* internal data */
- unsigned short nVersion; /* internal data */
- unsigned short nFlags; /* internal data */
- XSalEnum eDriver; /* PostScript, PCL, ... */
- unsigned short nCopies; /* number of copies */
- unsigned short nPaperBin; /* paper bin to use */
- XSalEnum ePaper; /* A4, A5, ... */
- unsigned int nPaperWidth; /* paper width if PAPER_USER */
- unsigned int nPaperHeight; /* paper height if PAPER_USER */
- XSalEnum eOrientation; /* portrait / landscape */
- unsigned int nScale; /* [%] ( 100 => 1:1 ) */
- unsigned short nResolutionX; /* [dots per inch] */
- unsigned short nResolutionY; /* [dots per inch] */
- char sCompatCommand[256];/* current shell command */
- char sPort[256]; /* default shell command */
- char cDriverName[32]; /* Druckertreibername */
- unsigned int nTrailingBytes; /* trailing bytes appended to this structure */
-} XSalPrinterSetup;
-
-#define XSAL_PRINTER_SETUP_MAGIC 0x0000ede1
-#define WRONG_ENDIANESS_MAGIC 0xe1ed0000
-
-/* definition for XSalPrinterSetup.nFlags */
-#define XSALPRINTERSETUP_FLAG_LEVEL_DEFAULT 0x0000
-#define XSALPRINTERSETUP_FLAG_LEVEL 0x000f
-#define XSALPRINTERSETUP_FLAG_LEVEL_SHIFT 0
-#define XSALPRINTERSETUP_FLAG_COLOR 0x0010 /* colored bitmaps */
-#define XSALPRINTERSETUP_FLAG_COLOR_DEFAULT 0x0020
-#define XSALPRINTERSETUP_FLAG_COMPRESS 0x0040 /* compress bitmaps */
-#define XSALPRINTERSETUP_FLAG_COMPRESS_DEFAULT 0x0080 /* compress bitmaps */
-#define XSALPRINTERSETUP_FLAG_DEPTH_DEFAULT 0x0700
-#define XSALPRINTERSETUP_FLAG_DEPTH 0x0700 /* depth n = depth 2^n, 6 = 24Bit, 7 = default */
-#define XSALPRINTERSETUP_FLAG_DEPTH_SHIFT 8
-
-#define XSALPRINTERSETUP_FLAG_DEFAULT\
- (XSALPRINTERSETUP_FLAG_LEVEL_DEFAULT | \
- XSALPRINTERSETUP_FLAG_COMPRESS_DEFAULT | \
- XSALPRINTERSETUP_FLAG_COLOR_DEFAULT | \
- XSALPRINTERSETUP_FLAG_DEPTH_DEFAULT )
-
-
-/* XSalPrinterSetup access */
-extern unsigned short XSalGetPrinterDriverId( const char* driverName );
-extern const char* XSalGetPrinterDriverName( unsigned short driverId );
-
-extern unsigned short XSalGetLanguageLevel( const XSalPrinterSetup* pSetup );
-extern void XSalGetLanguageLevels(
- const XSalPrinterSetup* pSetup,
- unsigned short* minLevel,
- unsigned short* maxLevel );
-extern void XSalSetLanguageLevel( XSalPrinterSetup* pSetup, unsigned short);
-
-extern unsigned short XSalGetDepth( const XSalPrinterSetup* pSetup );
-extern void XSalSetDepth( XSalPrinterSetup* pSetup, unsigned short depth );
-
-extern XSalEnum XSalGetColorSpace( const XSalPrinterSetup* pSetup );
-extern void XSalSetColorSpace( XSalPrinterSetup* pSetup, XSalEnum space );
-
-extern XSalBool XSalGetBmpCompression( const XSalPrinterSetup* pSetup );
-extern void XSalSetBmpCompression( XSalPrinterSetup* pSetup, XSalBool compress );
-
-extern XSalEnum XSalGetOrientation( const char* string );
-extern const char* XSalGetOrientationName( XSalEnum eOrientation );
-
-extern XSalEnum XSalGetPaper( const char* sPaperName );
-extern const char* XSalGetPaperName( XSalEnum ePaper );
-
-/* use XSalInitPrinterSetup to initialize internal data */
-extern void XSalInitPrinterSetup( XSalPrinterSetup* );
-extern void XSalCorrectEndianess( XSalPrinterSetup* );
-extern void XSalSetupPrinterSetup( XSalPrinterSetup*, Display* display, XLIB_Window parent);
-
-
-/* the following two functions set defaults of the profile */
-extern void XSalReadPrinterSetup( XSalPrinterSetup*, const String& rPrinter );
-extern void XSalReadPrinterSetupDefaults( XSalPrinterSetup* );
-
-
-typedef Display XSalPrinter; /* an XSalPrinter is a Display. Draw into RootWindow */
-
-
-/* open, change setup and close printer */
-extern XSalPrinter* XSalOpenPrinter( const XSalPrinterSetup * pSetup, const String& rPrinterName, const String& rPrintFile );
-/* XSalSetupPrinter() can setup: Orientation, Copies, Page, PaperBin */
-extern void XSalSetupPrinter( XSalPrinter *, const XSalPrinterSetup * pSetup );
-extern void XSalClosePrinter( XSalPrinter * );
-
-typedef struct
-{
- int nWidth; /* [dots] drawable area */
- int nHeight; /* [dots] drawable area */
- int nMarginLeft; /* [dots] left margin */
- int nMarginTop; /* [dots] top margin */
- int nMarginRight; /* [dots] right margin */
- int nMarginBottom; /* [dots] bottom margin */
- int nResolutionX; /* [dpi] resolution x */
- int nResolutionY; /* [dpi] resolution y */
-} XSalPageInfo;
-
-extern void XSalGetPageInfo(
- const XSalPrinter* printer,
- const XSalPrinterSetup* pSetup,
- XSalPageInfo* pPageInfo );
-
-
-/* printer job control */
-extern int XSalStartDoc( XSalPrinter * printer, const String& jobName );
-extern int XSalStartPage( XSalPrinter * printer );
-extern int XSalEndPage( XSalPrinter * printer );
-extern int XSalEndDoc( XSalPrinter * printer );
-extern int XSalAbortDoc( XSalPrinter * printer );
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif
diff --git a/vcl/unx/source/app/i18n_ic.cxx b/vcl/unx/source/app/i18n_ic.cxx
index 9fba669f338d..817fc2781e8c 100644
--- a/vcl/unx/source/app/i18n_ic.cxx
+++ b/vcl/unx/source/app/i18n_ic.cxx
@@ -340,7 +340,7 @@ SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) :
if ( mnPreeditStyle != XIMPreeditNone )
{
-#if defined LINUX || defined FREEBSD || defined NETBSD || defined IRIX || defined MACOSX
+#if defined LINUX || defined FREEBSD || defined NETBSD || defined IRIX
if ( mpPreeditAttributes != NULL )
#endif
mpAttributes = XVaAddToNestedList( mpAttributes,
@@ -348,7 +348,7 @@ SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) :
}
if ( mnStatusStyle != XIMStatusNone )
{
-#if defined LINUX || defined FREEBSD || defined NETBSD || defined IRIX || defined MACOSX
+#if defined LINUX || defined FREEBSD || defined NETBSD || defined IRIX
if ( mpStatusAttributes != NULL )
#endif
mpAttributes = XVaAddToNestedList( mpAttributes,
diff --git a/vcl/unx/source/app/i18n_im.cxx b/vcl/unx/source/app/i18n_im.cxx
index d4ff59e87864..a47cefcef7dd 100644
--- a/vcl/unx/source/app/i18n_im.cxx
+++ b/vcl/unx/source/app/i18n_im.cxx
@@ -55,10 +55,6 @@
#include "i18n_im.hxx"
#include <i18n_status.hxx>
-#ifdef MACOSX
-#include <osl/process.h>
-#include <tools/string.hxx>
-#endif
#include <osl/thread.h>
using namespace vcl;
@@ -253,13 +249,8 @@ SalI18N_InputMethod::SetLocale( const char* pLocale )
char *locale = SetSystemLocale( pLocale );
if ( (!IsXWindowCompatibleLocale(locale)) || IsPosixLocale(locale) )
{
- #ifdef MACOSX // MacOS X always uses UTF-8 for the filesystem
- osl_setThreadTextEncoding (RTL_TEXTENCODING_UTF8);
- locale = SetSystemLocale( "en_US.UTF-8" );
- #else
osl_setThreadTextEncoding (RTL_TEXTENCODING_ISO_8859_1);
locale = SetSystemLocale( "en_US" );
- #endif
#ifdef SOLARIS
SetSystemEnvironment( "en_US" );
#endif
diff --git a/vcl/unx/source/app/i18n_wrp.cxx b/vcl/unx/source/app/i18n_wrp.cxx
index f561e18e0ff0..b3a3ebc8e101 100644
--- a/vcl/unx/source/app/i18n_wrp.cxx
+++ b/vcl/unx/source/app/i18n_wrp.cxx
@@ -45,10 +45,7 @@ struct XIMArg
#include <sal/alloca.h>
#include <string.h>
-#if !defined(MACOSX)
-/* MacOS X doesn't yet support XIM... FIXME */
#include <dlfcn.h>
-#endif
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include "XIM.h"
@@ -66,10 +63,8 @@ typedef XIM (*OpenFunction)(Display*, XrmDatabase, char*, char*, XIMArg*);
}
/* global variables */
-#if !defined(MACOSX)
static void *g_dlmodule = 0;
static OpenFunction g_open_im = (OpenFunction)NULL;
-#endif
/* utility function to transform vararg list into an array of XIMArg */
@@ -213,8 +208,6 @@ XvaOpenIM(Display *display, XrmDatabase rdb,
XvaGetArgs( variable, args );
va_end(variable);
- /* MacOS X doesn't yet support XIM... FIXME */
-#if !defined(MACOSX)
if (!g_dlmodule)
{
g_dlmodule = dlopen(XIIIMP_LIB, RTLD_LAZY);
@@ -235,13 +228,10 @@ XvaOpenIM(Display *display, XrmDatabase rdb,
{
goto legacy_XIM;
}
-#endif
}
// in #if to prevent warning "warning: label 'legacy_XIM' defined but not used"
-#if !defined(MACOSX)
legacy_XIM:
-#endif
if (!xim)
xim = XOpenIM(display, rdb, res_name, res_class);
@@ -257,8 +247,6 @@ Status XvaCloseIM(XIM)
{
Status s = False;
- /* MacOS X doesn't yet support XIM... FIXME */
-#if !defined(MACOSX)
if (!g_dlmodule)
{
/* assuming one XvaOpenIM call */
@@ -267,7 +255,6 @@ Status XvaCloseIM(XIM)
g_open_im = (OpenFunction)NULL;
s = True;
}
-#endif
return (s);
}
diff --git a/vcl/unx/source/app/keysymnames.cxx b/vcl/unx/source/app/keysymnames.cxx
index 2a78110c35fa..4a2bf13af3e0 100644
--- a/vcl/unx/source/app/keysymnames.cxx
+++ b/vcl/unx/source/app/keysymnames.cxx
@@ -649,18 +649,7 @@ const char* SalDisplay::GetKeyboardName( BOOL bRefresh )
{
XkbDescPtr pXkbDesc = NULL;
// try X keyboard extension
- #ifdef MACOSX
- // FIXME
- // XDarwin doesn't yet have very good support for the Xkeyboard extension.
- // When we call XkbGetKeyboard(), the XServer throws a message up in the
- // console about xkbcomp and files for geometry include. The side effect of
- // this is _very_ noticable lag when drawing menus. The file menu, for example,
- // takes about 1s to come down on my G4/450 DP and you can see it draw. Therefore
- // we are disabling it for the moment until better XDarwin support exists.
- if ( 0 )
- #else
if( (pXkbDesc = XkbGetKeyboard( GetDisplay(), XkbAllComponentsMask, XkbUseCoreKbd )) )
- #endif
{
const char* pAtom = NULL;
if( pXkbDesc->names->groups[0] )
diff --git a/vcl/unx/source/app/makefile.mk b/vcl/unx/source/app/makefile.mk
index 948c2b2de5be..a7f790fd67ab 100644
--- a/vcl/unx/source/app/makefile.mk
+++ b/vcl/unx/source/app/makefile.mk
@@ -71,6 +71,7 @@ SLOFILES=\
EXCEPTIONSFILES=\
$(SLO)$/wmadaptor.obj \
$(SLO)$/saldata.obj \
+ $(SLO)$/salinst.obj \
$(SLO)$/saldisp.obj \
$(SLO)$/i18n_status.obj \
$(SLO)$/i18n_cb.obj \
diff --git a/vcl/unx/source/app/saldisp.cxx b/vcl/unx/source/app/saldisp.cxx
index e09346d6cfff..95679d77fdfb 100644
--- a/vcl/unx/source/app/saldisp.cxx
+++ b/vcl/unx/source/app/saldisp.cxx
@@ -65,7 +65,7 @@
#ifdef USE_XINERAMA
#ifdef USE_XINERAMA_XORG
-#if defined(X86) || defined(X86_64) || defined(MACOSX)
+#if defined(X86) || defined(X86_64)
#include <X11/extensions/Xinerama.h>
#endif
#elif defined USE_XINERAMA_XSUN
@@ -893,7 +893,7 @@ void SalDisplay::Init()
sscanf( pProperties, "%li", &nProperties_ );
else
{
-#if defined DBG_UTIL || defined SUN || defined LINUX || defined FREEBSD || defined IRIX || defined MACOSX
+#if defined DBG_UTIL || defined SUN || defined LINUX || defined FREEBSD || defined IRIX
nProperties_ |= PROPERTY_FEATURE_Maximize;
#endif
// Server Bugs & Properties
@@ -919,7 +919,7 @@ void SalDisplay::Init()
if( GetServerVendor() == vendor_xfree )
{
nProperties_ |= PROPERTY_BUG_XCopyArea_GXxor;
-#if defined LINUX || defined FREEBSD || defined MACOSX
+#if defined LINUX || defined FREEBSD
// otherwm and olwm are a kind of default, which are not detected
// carefully. if we are running linux (i.e. not netbsd) on an xfree
// display, fvwm is most probable the wm to choose, confusing with mwm
@@ -1085,9 +1085,6 @@ void SalDisplay::ModifierMapping()
nShiftKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ShiftMapIndex );
nCtrlKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ControlMapIndex );
nMod1KeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, Mod1MapIndex );
-#ifdef MACOSX
- nMod2KeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, Mod2MapIndex );
-#endif
// Auf Sun-Servern und SCO-Severn beruecksichtigt XLookupString
// nicht den NumLock Modifier.
if( (GetServerVendor() == vendor_sun)
@@ -1116,25 +1113,12 @@ XubString SalDisplay::GetKeyName( USHORT nKeyCode ) const
String aStrMap;
if( nKeyCode & KEY_MOD1 )
- {
- if( aStrMap.Len() )
- aStrMap += '+';
aStrMap += GetKeyNameFromKeySym( nCtrlKeySym_ );
- }
-#ifdef MACOSX
- if( nKeyCode & KEY_MOD3 )
- {
- aStrMap += GetKeyNameFromKeySym( nMod2KeySym_ );
- }
if( nKeyCode & KEY_MOD2 )
{
- if ( aStrMap.Len() )
- aStrMap += '+' ;
-#else
- if( nKeyCode & KEY_MOD2 )
- {
-#endif
+ if( aStrMap.Len() )
+ aStrMap += '+';
aStrMap += GetKeyNameFromKeySym( nMod1KeySym_ );
}
@@ -2646,7 +2630,7 @@ void SalDisplay::InitXinerama()
}
}
#elif defined(USE_XINERAMA_XORG)
-#if defined( X86 ) || defined( X86_64 ) || defined( MACOSX )
+#if defined( X86 ) || defined( X86_64 )
if( XineramaIsActive( pDisp_ ) )
{
int nFramebuffers = 1;
diff --git a/vcl/unx/source/app/salinst.cxx b/vcl/unx/source/app/salinst.cxx
index 18b24e2cb2f3..c160ea4c2fa5 100644
--- a/vcl/unx/source/app/salinst.cxx
+++ b/vcl/unx/source/app/salinst.cxx
@@ -35,20 +35,21 @@
#include <stdio.h>
#include <stdlib.h>
-#include <salunx.h>
+#include "salunx.h"
-#ifndef _VOS_MUTEX_HXX
-#include <vos/mutex.hxx>
-#endif
-#include <saldata.hxx>
-#include <saldisp.hxx>
-#include <salinst.h>
-#include <salframe.h>
-#include <vcl/salwtype.hxx>
-#include <vcl/salatype.hxx>
-#include <dtint.hxx>
-#include <salprn.h>
-#include <sm.hxx>
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salinst.h"
+#include "salframe.h"
+#include "dtint.hxx"
+#include "salprn.h"
+#include "sm.hxx"
+
+#include "vcl/salwtype.hxx"
+#include "vcl/salatype.hxx"
+#include "vcl/helper.hxx"
+
+#include "vos/mutex.hxx"
// -------------------------------------------------------------------------
//
@@ -276,3 +277,129 @@ void X11SalInstance::DestroyFrame( SalFrame* pFrame )
{
delete pFrame;
}
+
+static void getServerDirectories( std::list< rtl::OString >& o_rFontPaths )
+{
+#ifdef LINUX
+ /*
+ * chkfontpath exists on some (RH derived) Linux distributions
+ */
+ static const char* pCommands[] = {
+ "/usr/sbin/chkfontpath 2>/dev/null", "chkfontpath 2>/dev/null"
+ };
+ ::std::list< ByteString > aLines;
+
+ for( unsigned int i = 0; i < sizeof(pCommands)/sizeof(pCommands[0]); i++ )
+ {
+ FILE* pPipe = popen( pCommands[i], "r" );
+ aLines.clear();
+ if( pPipe )
+ {
+ char line[1024];
+ char* pSearch;
+ while( fgets( line, sizeof(line), pPipe ) )
+ {
+ int nLen = strlen( line );
+ if( line[nLen-1] == '\n' )
+ line[nLen-1] = 0;
+ pSearch = strstr( line, ": " );
+ if( pSearch )
+ aLines.push_back( pSearch+2 );
+ }
+ if( ! pclose( pPipe ) )
+ break;
+ }
+ }
+
+ for( ::std::list< ByteString >::iterator it = aLines.begin(); it != aLines.end(); ++it )
+ {
+ if( ! access( it->GetBuffer(), F_OK ) )
+ {
+ o_rFontPaths.push_back( *it );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding fs dir %s\n", it->GetBuffer() );
+#endif
+ }
+ }
+#else
+ (void)o_rFontPaths;
+#endif
+}
+
+
+
+void X11SalInstance::FillFontPathList( std::list< rtl::OString >& o_rFontPaths )
+{
+ Display *pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+
+ DBG_ASSERT( pDisplay, "No Display !" );
+ if( pDisplay )
+ {
+ // get font paths to look for fonts
+ int nPaths = 0, i;
+ char** pPaths = XGetFontPath( pDisplay, &nPaths );
+
+ bool bServerDirs = false;
+ for( i = 0; i < nPaths; i++ )
+ {
+ OString aPath( pPaths[i] );
+ sal_Int32 nPos = 0;
+ if( ! bServerDirs
+ && ( nPos = aPath.indexOf( ':' ) ) > 0
+ && ( !aPath.copy(nPos).equals( ":unscaled" ) ) )
+ {
+ bServerDirs = true;
+ getServerDirectories( o_rFontPaths );
+ }
+ else
+ {
+ psp::normPath( aPath );
+ o_rFontPaths.push_back( aPath );
+ }
+ }
+
+ if( nPaths )
+ XFreeFontPath( pPaths );
+ }
+
+ // insert some standard directories
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/TrueType" );
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/Type1" );
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/Type1/sun" );
+ o_rFontPaths.push_back( "/usr/X11R6/lib/X11/fonts/truetype" );
+ o_rFontPaths.push_back( "/usr/X11R6/lib/X11/fonts/Type1" );
+
+ #ifdef SOLARIS
+ /* cde specials, from /usr/dt/bin/Xsession: here are the good fonts,
+ the OWfontpath file may contain as well multiple lines as a comma
+ separated list of fonts in each line. to make it even more weird
+ environment variables are allowed as well */
+
+ const char* lang = getenv("LANG");
+ if ( lang != NULL )
+ {
+ String aOpenWinDir( String::CreateFromAscii( "/usr/openwin/lib/locale/" ) );
+ aOpenWinDir.AppendAscii( lang );
+ aOpenWinDir.AppendAscii( "/OWfontpath" );
+
+ SvFileStream aStream( aOpenWinDir, STREAM_READ );
+
+ // TODO: replace environment variables
+ while( aStream.IsOpen() && ! aStream.IsEof() )
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ // need an OString for normpath
+ OString aNLine( aLine );
+ psp::normPath( aNLine );
+ aLine = aNLine;
+ // try to avoid bad fonts in some cases
+ static bool bAvoid = (strncasecmp( lang, "ar", 2 ) == 0) || (strncasecmp( lang, "he", 2 ) == 0) || strncasecmp( lang, "iw", 2 ) == 0 || (strncasecmp( lang, "hi", 2 ) == 0);
+ if( bAvoid && aLine.Search( "iso_8859" ) != STRING_NOTFOUND )
+ continue;
+ o_rFontPaths.push_back( aLine );
+ }
+ }
+ #endif /* SOLARIS */
+}
+
diff --git a/vcl/unx/source/app/wmadaptor.cxx b/vcl/unx/source/app/wmadaptor.cxx
index e099af0de0fb..37015b6e58d6 100644
--- a/vcl/unx/source/app/wmadaptor.cxx
+++ b/vcl/unx/source/app/wmadaptor.cxx
@@ -405,12 +405,6 @@ WMAdaptor::WMAdaptor( SalDisplay* pDisplay ) :
XFree( pProperty );
}
}
-
-#ifdef MACOSX
- /* Apple's X11 needs NW gravity with OOo 1.1 */
- m_nWinGravity = NorthWestGravity;
- m_nInitWinGravity = NorthWestGravity;
-#endif
}
/*
diff --git a/vcl/unx/source/fontmanager/adobeenc.tab b/vcl/unx/source/fontmanager/adobeenc.tab
new file mode 100644
index 000000000000..e4005a87849f
--- /dev/null
+++ b/vcl/unx/source/fontmanager/adobeenc.tab
@@ -0,0 +1,1090 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: adobeenc.tab,v $
+ * $Revision: 1.4 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+struct AdobeEncEntry {
+ sal_Unicode aUnicode;
+ sal_uInt8 aAdobeStandardCode;
+ const char* const pAdobename;
+};
+
+static const AdobeEncEntry aAdobeCodes[]=
+{
+ { 0x0041, 0101, "A" },
+ { 0x00C6, 0341, "AE" },
+ { 0x01FC, 0, "AEacute" },
+ { 0xF7E6, 0, "AEsmall" },
+ { 0x00C1, 0, "Aacute" },
+ { 0xF7E1, 0, "Aacutesmall" },
+ { 0x0102, 0, "Abreve" },
+ { 0x00C2, 0, "Acircumflex" },
+ { 0xF7E2, 0, "Acircumflexsmall" },
+ { 0xF6C9, 0, "Acute" },
+ { 0xF7B4, 0, "Acutesmall" },
+ { 0x00C4, 0, "Adieresis" },
+ { 0xF7E4, 0, "Adieresissmall" },
+ { 0x00C0, 0, "Agrave" },
+ { 0xF7E0, 0, "Agravesmall" },
+ { 0x0391, 0, "Alpha" },
+ { 0x0386, 0, "Alphatonos" },
+ { 0x0100, 0, "Amacron" },
+ { 0x0104, 0, "Aogonek" },
+ { 0x00C5, 0, "Aring" },
+ { 0x01FA, 0, "Aringacute" },
+ { 0xF7E5, 0, "Aringsmall" },
+ { 0xF761, 0, "Asmall" },
+ { 0x00C3, 0, "Atilde" },
+ { 0xF7E3, 0, "Atildesmall" },
+ { 0x0042, 0102, "B" },
+ { 0x0392, 0, "Beta" },
+ { 0xF6F4, 0, "Brevesmall" },
+ { 0xF762, 0, "Bsmall" },
+ { 0x0043, 0103, "C" },
+ { 0x0106, 0, "Cacute" },
+ { 0xF6CA, 0, "Caron" },
+ { 0xF6F5, 0, "Caronsmall" },
+ { 0x010C, 0, "Ccaron" },
+ { 0x00C7, 0, "Ccedilla" },
+ { 0xF7E7, 0, "Ccedillasmall" },
+ { 0x0108, 0, "Ccircumflex" },
+ { 0x010A, 0, "Cdotaccent" },
+ { 0xF7B8, 0, "Cedillasmall" },
+ { 0x03A7, 0, "Chi" },
+ { 0xF6F6, 0, "Circumflexsmall" },
+ { 0xF763, 0, "Csmall" },
+ { 0x0044, 0104, "D" },
+ { 0x010E, 0, "Dcaron" },
+ { 0x0110, 0, "Dcroat" },
+ { 0x2206, 0, "Delta" },
+ { 0x0394, 0, "Delta" },
+ { 0xF6CB, 0, "Dieresis" },
+ { 0xF6CC, 0, "DieresisAcute" },
+ { 0xF6CD, 0, "DieresisGrave" },
+ { 0xF7A8, 0, "Dieresissmall" },
+ { 0xF6F7, 0, "Dotaccentsmall" },
+ { 0xF764, 0, "Dsmall" },
+ { 0x0045, 0105, "E" },
+ { 0x00C9, 0, "Eacute" },
+ { 0xF7E9, 0, "Eacutesmall" },
+ { 0x0114, 0, "Ebreve" },
+ { 0x011A, 0, "Ecaron" },
+ { 0x00CA, 0, "Ecircumflex" },
+ { 0xF7EA, 0, "Ecircumflexsmall" },
+ { 0x00CB, 0, "Edieresis" },
+ { 0xF7EB, 0, "Edieresissmall" },
+ { 0x0116, 0, "Edotaccent" },
+ { 0x00C8, 0, "Egrave" },
+ { 0xF7E8, 0, "Egravesmall" },
+ { 0x0112, 0, "Emacron" },
+ { 0x014A, 0, "Eng" },
+ { 0x0118, 0, "Eogonek" },
+ { 0x0395, 0, "Epsilon" },
+ { 0x0388, 0, "Epsilontonos" },
+ { 0xF765, 0, "Esmall" },
+ { 0x0397, 0, "Eta" },
+ { 0x0389, 0, "Etatonos" },
+ { 0x00D0, 0, "Eth" },
+ { 0xF7F0, 0, "Ethsmall" },
+ { 0x20AC, 0, "Euro" },
+ { 0x0046, 0106, "F" },
+ { 0xF766, 0, "Fsmall" },
+ { 0x0047, 0107, "G" },
+ { 0x0393, 0, "Gamma" },
+ { 0x011E, 0, "Gbreve" },
+ { 0x01E6, 0, "Gcaron" },
+ { 0x011C, 0, "Gcircumflex" },
+ { 0x0122, 0, "Gcommaaccent" },
+ { 0x0120, 0, "Gdotaccent" },
+ { 0xF6CE, 0, "Grave" },
+ { 0xF760, 0, "Gravesmall" },
+ { 0xF767, 0, "Gsmall" },
+ { 0x0048, 0110, "H" },
+ { 0x25CF, 0, "H18533" },
+ { 0x25AA, 0, "H18543" },
+ { 0x25AB, 0, "H18551" },
+ { 0x25A1, 0, "H22073" },
+ { 0x0126, 0, "Hbar" },
+ { 0x0124, 0, "Hcircumflex" },
+ { 0xF768, 0, "Hsmall" },
+ { 0xF6CF, 0, "Hungarumlaut" },
+ { 0xF6F8, 0, "Hungarumlautsmall" },
+ { 0x0049, 0111, "I" },
+ { 0x0132, 0, "IJ" },
+ { 0x00CD, 0, "Iacute" },
+ { 0xF7ED, 0, "Iacutesmall" },
+ { 0x012C, 0, "Ibreve" },
+ { 0x00CE, 0, "Icircumflex" },
+ { 0xF7EE, 0, "Icircumflexsmall" },
+ { 0x00CF, 0, "Idieresis" },
+ { 0xF7EF, 0, "Idieresissmall" },
+ { 0x0130, 0, "Idotaccent" },
+ { 0x2111, 0, "Ifraktur" },
+ { 0x00CC, 0, "Igrave" },
+ { 0xF7EC, 0, "Igravesmall" },
+ { 0x012A, 0, "Imacron" },
+ { 0x012E, 0, "Iogonek" },
+ { 0x0399, 0, "Iota" },
+ { 0x03AA, 0, "Iotadieresis" },
+ { 0x038A, 0, "Iotatonos" },
+ { 0xF769, 0, "Ismall" },
+ { 0x0128, 0, "Itilde" },
+ { 0x004A, 0112, "J" },
+ { 0x0134, 0, "Jcircumflex" },
+ { 0xF76A, 0, "Jsmall" },
+ { 0x004B, 0113, "K" },
+ { 0x039A, 0, "Kappa" },
+ { 0x0136, 0, "Kcommaaccent" },
+ { 0xF76B, 0, "Ksmall" },
+ { 0x004C, 0114, "L" },
+ { 0xF6BF, 0, "LL" },
+ { 0x0139, 0, "Lacute" },
+ { 0x039B, 0, "Lambda" },
+ { 0x013D, 0, "Lcaron" },
+ { 0x013B, 0, "Lcommaaccent" },
+ { 0x013F, 0, "Ldot" },
+ { 0x0141, 0350, "Lslash" },
+ { 0xF6F9, 0, "Lslashsmall" },
+ { 0xF76C, 0, "Lsmall" },
+ { 0x004D, 0115, "M" },
+ { 0xF6D0, 0, "Macron" },
+ { 0xF7AF, 0, "Macronsmall" },
+ { 0xF76D, 0, "Msmall" },
+ { 0x039C, 0, "Mu" },
+ { 0x004E, 0116, "N" },
+ { 0x0143, 0, "Nacute" },
+ { 0x0147, 0, "Ncaron" },
+ { 0x0145, 0, "Ncommaaccent" },
+ { 0xF76E, 0, "Nsmall" },
+ { 0x00D1, 0, "Ntilde" },
+ { 0xF7F1, 0, "Ntildesmall" },
+ { 0x039D, 0, "Nu" },
+ { 0x004F, 0117, "O" },
+ { 0x0152, 0, "OE" },
+ { 0xF6FA, 0, "OEsmall" },
+ { 0x00D3, 0, "Oacute" },
+ { 0xF7F3, 0, "Oacutesmall" },
+ { 0x014E, 0, "Obreve" },
+ { 0x00D4, 0, "Ocircumflex" },
+ { 0xF7F4, 0, "Ocircumflexsmall" },
+ { 0x00D6, 0, "Odieresis" },
+ { 0xF7F6, 0, "Odieresissmall" },
+ { 0xF6FB, 0, "Ogoneksmall" },
+ { 0x00D2, 0, "Ograve" },
+ { 0xF7F2, 0, "Ogravesmall" },
+ { 0x01A0, 0, "Ohorn" },
+ { 0x0150, 0, "Ohungarumlaut" },
+ { 0x014C, 0, "Omacron" },
+ { 0x2126, 0, "Omega" },
+ { 0x03A9, 0, "Omega" },
+ { 0x038F, 0, "Omegatonos" },
+ { 0x039F, 0, "Omicron" },
+ { 0x038C, 0, "Omicrontonos" },
+ { 0x00D8, 0351, "Oslash" },
+ { 0x01FE, 0, "Oslashacute" },
+ { 0xF7F8, 0, "Oslashsmall" },
+ { 0xF76F, 0, "Osmall" },
+ { 0x00D5, 0, "Otilde" },
+ { 0xF7F5, 0, "Otildesmall" },
+ { 0x0050, 0120, "P" },
+ { 0x03A6, 0, "Phi" },
+ { 0x03A0, 0, "Pi" },
+ { 0x03A8, 0, "Psi" },
+ { 0xF770, 0, "Psmall" },
+ { 0x0051, 0121, "Q" },
+ { 0xF771, 0, "Qsmall" },
+ { 0x0052, 0122, "R" },
+ { 0x0154, 0, "Racute" },
+ { 0x0158, 0, "Rcaron" },
+ { 0x0156, 0, "Rcommaaccent" },
+ { 0x211C, 0, "Rfraktur" },
+ { 0x03A1, 0, "Rho" },
+ { 0xF6FC, 0, "Ringsmall" },
+ { 0xF772, 0, "Rsmall" },
+ { 0x0053, 0123, "S" },
+ { 0x250C, 0, "SF010000" },
+ { 0x2514, 0, "SF020000" },
+ { 0x2510, 0, "SF030000" },
+ { 0x2518, 0, "SF040000" },
+ { 0x253C, 0, "SF050000" },
+ { 0x252C, 0, "SF060000" },
+ { 0x2534, 0, "SF070000" },
+ { 0x251C, 0, "SF080000" },
+ { 0x2524, 0, "SF090000" },
+ { 0x2500, 0, "SF100000" },
+ { 0x2502, 0, "SF110000" },
+ { 0x2561, 0, "SF190000" },
+ { 0x2562, 0, "SF200000" },
+ { 0x2556, 0, "SF210000" },
+ { 0x2555, 0, "SF220000" },
+ { 0x2563, 0, "SF230000" },
+ { 0x2551, 0, "SF240000" },
+ { 0x2557, 0, "SF250000" },
+ { 0x255D, 0, "SF260000" },
+ { 0x255C, 0, "SF270000" },
+ { 0x255B, 0, "SF280000" },
+ { 0x255E, 0, "SF360000" },
+ { 0x255F, 0, "SF370000" },
+ { 0x255A, 0, "SF380000" },
+ { 0x2554, 0, "SF390000" },
+ { 0x2569, 0, "SF400000" },
+ { 0x2566, 0, "SF410000" },
+ { 0x2560, 0, "SF420000" },
+ { 0x2550, 0, "SF430000" },
+ { 0x256C, 0, "SF440000" },
+ { 0x2567, 0, "SF450000" },
+ { 0x2568, 0, "SF460000" },
+ { 0x2564, 0, "SF470000" },
+ { 0x2565, 0, "SF480000" },
+ { 0x2559, 0, "SF490000" },
+ { 0x2558, 0, "SF500000" },
+ { 0x2552, 0, "SF510000" },
+ { 0x2553, 0, "SF520000" },
+ { 0x256B, 0, "SF530000" },
+ { 0x256A, 0, "SF540000" },
+ { 0x015A, 0, "Sacute" },
+ { 0x0160, 0, "Scaron" },
+ { 0xF6FD, 0, "Scaronsmall" },
+ { 0x015E, 0, "Scedilla" },
+ { 0xF6C1, 0, "Scedilla" },
+ { 0x015C, 0, "Scircumflex" },
+ { 0x0218, 0, "Scommaaccent" },
+ { 0x03A3, 0, "Sigma" },
+ { 0xF773, 0, "Ssmall" },
+ { 0x0054, 0124, "T" },
+ { 0x03A4, 0, "Tau" },
+ { 0x0166, 0, "Tbar" },
+ { 0x0164, 0, "Tcaron" },
+ { 0x0162, 0, "Tcommaaccent" },
+ { 0x021A, 0, "Tcommaaccent" },
+ { 0x0398, 0, "Theta" },
+ { 0x00DE, 0, "Thorn" },
+ { 0xF7FE, 0, "Thornsmall" },
+ { 0xF6FE, 0, "Tildesmall" },
+ { 0xF774, 0, "Tsmall" },
+ { 0x0055, 0125, "U" },
+ { 0x00DA, 0, "Uacute" },
+ { 0xF7FA, 0, "Uacutesmall" },
+ { 0x016C, 0, "Ubreve" },
+ { 0x00DB, 0, "Ucircumflex" },
+ { 0xF7FB, 0, "Ucircumflexsmall" },
+ { 0x00DC, 0, "Udieresis" },
+ { 0xF7FC, 0, "Udieresissmall" },
+ { 0x00D9, 0, "Ugrave" },
+ { 0xF7F9, 0, "Ugravesmall" },
+ { 0x01AF, 0, "Uhorn" },
+ { 0x0170, 0, "Uhungarumlaut" },
+ { 0x016A, 0, "Umacron" },
+ { 0x0172, 0, "Uogonek" },
+ { 0x03A5, 0, "Upsilon" },
+ { 0x03D2, 0, "Upsilon1" },
+ { 0x03AB, 0, "Upsilondieresis" },
+ { 0x038E, 0, "Upsilontonos" },
+ { 0x016E, 0, "Uring" },
+ { 0xF775, 0, "Usmall" },
+ { 0x0168, 0, "Utilde" },
+ { 0x0056, 0126, "V" },
+ { 0xF776, 0, "Vsmall" },
+ { 0x0057, 0127, "W" },
+ { 0x1E82, 0, "Wacute" },
+ { 0x0174, 0, "Wcircumflex" },
+ { 0x1E84, 0, "Wdieresis" },
+ { 0x1E80, 0, "Wgrave" },
+ { 0xF777, 0, "Wsmall" },
+ { 0x0058, 0130, "X" },
+ { 0x039E, 0, "Xi" },
+ { 0xF778, 0, "Xsmall" },
+ { 0x0059, 0131, "Y" },
+ { 0x00DD, 0, "Yacute" },
+ { 0xF7FD, 0, "Yacutesmall" },
+ { 0x0176, 0, "Ycircumflex" },
+ { 0x0178, 0, "Ydieresis" },
+ { 0xF7FF, 0, "Ydieresissmall" },
+ { 0x1EF2, 0, "Ygrave" },
+ { 0xF779, 0, "Ysmall" },
+ { 0x005A, 0132, "Z" },
+ { 0x0179, 0, "Zacute" },
+ { 0x017D, 0, "Zcaron" },
+ { 0xF6FF, 0, "Zcaronsmall" },
+ { 0x017B, 0, "Zdotaccent" },
+ { 0x0396, 0, "Zeta" },
+ { 0xF77A, 0, "Zsmall" },
+ { 0x0061, 0141, "a" },
+ { 0x00E1, 0, "aacute" },
+ { 0x0103, 0, "abreve" },
+ { 0x00E2, 0, "acircumflex" },
+ { 0x00B4, 0302, "acute" },
+ { 0x0301, 0, "acutecomb" },
+ { 0x00E4, 0, "adieresis" },
+ { 0x00E6, 0361, "ae" },
+ { 0x01FD, 0, "aeacute" },
+ { 0x2015, 0, "afii00208" },
+ { 0x0410, 0, "afii10017" },
+ { 0x0411, 0, "afii10018" },
+ { 0x0412, 0, "afii10019" },
+ { 0x0413, 0, "afii10020" },
+ { 0x0414, 0, "afii10021" },
+ { 0x0415, 0, "afii10022" },
+ { 0x0401, 0, "afii10023" },
+ { 0x0416, 0, "afii10024" },
+ { 0x0417, 0, "afii10025" },
+ { 0x0418, 0, "afii10026" },
+ { 0x0419, 0, "afii10027" },
+ { 0x041A, 0, "afii10028" },
+ { 0x041B, 0, "afii10029" },
+ { 0x041C, 0, "afii10030" },
+ { 0x041D, 0, "afii10031" },
+ { 0x041E, 0, "afii10032" },
+ { 0x041F, 0, "afii10033" },
+ { 0x0420, 0, "afii10034" },
+ { 0x0421, 0, "afii10035" },
+ { 0x0422, 0, "afii10036" },
+ { 0x0423, 0, "afii10037" },
+ { 0x0424, 0, "afii10038" },
+ { 0x0425, 0, "afii10039" },
+ { 0x0426, 0, "afii10040" },
+ { 0x0427, 0, "afii10041" },
+ { 0x0428, 0, "afii10042" },
+ { 0x0429, 0, "afii10043" },
+ { 0x042A, 0, "afii10044" },
+ { 0x042B, 0, "afii10045" },
+ { 0x042C, 0, "afii10046" },
+ { 0x042D, 0, "afii10047" },
+ { 0x042E, 0, "afii10048" },
+ { 0x042F, 0, "afii10049" },
+ { 0x0490, 0, "afii10050" },
+ { 0x0402, 0, "afii10051" },
+ { 0x0403, 0, "afii10052" },
+ { 0x0404, 0, "afii10053" },
+ { 0x0405, 0, "afii10054" },
+ { 0x0406, 0, "afii10055" },
+ { 0x0407, 0, "afii10056" },
+ { 0x0408, 0, "afii10057" },
+ { 0x0409, 0, "afii10058" },
+ { 0x040A, 0, "afii10059" },
+ { 0x040B, 0, "afii10060" },
+ { 0x040C, 0, "afii10061" },
+ { 0x040E, 0, "afii10062" },
+ { 0xF6C4, 0, "afii10063" },
+ { 0xF6C5, 0, "afii10064" },
+ { 0x0430, 0, "afii10065" },
+ { 0x0431, 0, "afii10066" },
+ { 0x0432, 0, "afii10067" },
+ { 0x0433, 0, "afii10068" },
+ { 0x0434, 0, "afii10069" },
+ { 0x0435, 0, "afii10070" },
+ { 0x0451, 0, "afii10071" },
+ { 0x0436, 0, "afii10072" },
+ { 0x0437, 0, "afii10073" },
+ { 0x0438, 0, "afii10074" },
+ { 0x0439, 0, "afii10075" },
+ { 0x043A, 0, "afii10076" },
+ { 0x043B, 0, "afii10077" },
+ { 0x043C, 0, "afii10078" },
+ { 0x043D, 0, "afii10079" },
+ { 0x043E, 0, "afii10080" },
+ { 0x043F, 0, "afii10081" },
+ { 0x0440, 0, "afii10082" },
+ { 0x0441, 0, "afii10083" },
+ { 0x0442, 0, "afii10084" },
+ { 0x0443, 0, "afii10085" },
+ { 0x0444, 0, "afii10086" },
+ { 0x0445, 0, "afii10087" },
+ { 0x0446, 0, "afii10088" },
+ { 0x0447, 0, "afii10089" },
+ { 0x0448, 0, "afii10090" },
+ { 0x0449, 0, "afii10091" },
+ { 0x044A, 0, "afii10092" },
+ { 0x044B, 0, "afii10093" },
+ { 0x044C, 0, "afii10094" },
+ { 0x044D, 0, "afii10095" },
+ { 0x044E, 0, "afii10096" },
+ { 0x044F, 0, "afii10097" },
+ { 0x0491, 0, "afii10098" },
+ { 0x0452, 0, "afii10099" },
+ { 0x0453, 0, "afii10100" },
+ { 0x0454, 0, "afii10101" },
+ { 0x0455, 0, "afii10102" },
+ { 0x0456, 0, "afii10103" },
+ { 0x0457, 0, "afii10104" },
+ { 0x0458, 0, "afii10105" },
+ { 0x0459, 0, "afii10106" },
+ { 0x045A, 0, "afii10107" },
+ { 0x045B, 0, "afii10108" },
+ { 0x045C, 0, "afii10109" },
+ { 0x045E, 0, "afii10110" },
+ { 0x040F, 0, "afii10145" },
+ { 0x0462, 0, "afii10146" },
+ { 0x0472, 0, "afii10147" },
+ { 0x0474, 0, "afii10148" },
+ { 0xF6C6, 0, "afii10192" },
+ { 0x045F, 0, "afii10193" },
+ { 0x0463, 0, "afii10194" },
+ { 0x0473, 0, "afii10195" },
+ { 0x0475, 0, "afii10196" },
+ { 0xF6C7, 0, "afii10831" },
+ { 0xF6C8, 0, "afii10832" },
+ { 0x04D9, 0, "afii10846" },
+ { 0x200E, 0, "afii299" },
+ { 0x200F, 0, "afii300" },
+ { 0x200D, 0, "afii301" },
+ { 0x066A, 0, "afii57381" },
+ { 0x060C, 0, "afii57388" },
+ { 0x0660, 0, "afii57392" },
+ { 0x0661, 0, "afii57393" },
+ { 0x0662, 0, "afii57394" },
+ { 0x0663, 0, "afii57395" },
+ { 0x0664, 0, "afii57396" },
+ { 0x0665, 0, "afii57397" },
+ { 0x0666, 0, "afii57398" },
+ { 0x0667, 0, "afii57399" },
+ { 0x0668, 0, "afii57400" },
+ { 0x0669, 0, "afii57401" },
+ { 0x061B, 0, "afii57403" },
+ { 0x061F, 0, "afii57407" },
+ { 0x0621, 0, "afii57409" },
+ { 0x0622, 0, "afii57410" },
+ { 0x0623, 0, "afii57411" },
+ { 0x0624, 0, "afii57412" },
+ { 0x0625, 0, "afii57413" },
+ { 0x0626, 0, "afii57414" },
+ { 0x0627, 0, "afii57415" },
+ { 0x0628, 0, "afii57416" },
+ { 0x0629, 0, "afii57417" },
+ { 0x062A, 0, "afii57418" },
+ { 0x062B, 0, "afii57419" },
+ { 0x062C, 0, "afii57420" },
+ { 0x062D, 0, "afii57421" },
+ { 0x062E, 0, "afii57422" },
+ { 0x062F, 0, "afii57423" },
+ { 0x0630, 0, "afii57424" },
+ { 0x0631, 0, "afii57425" },
+ { 0x0632, 0, "afii57426" },
+ { 0x0633, 0, "afii57427" },
+ { 0x0634, 0, "afii57428" },
+ { 0x0635, 0, "afii57429" },
+ { 0x0636, 0, "afii57430" },
+ { 0x0637, 0, "afii57431" },
+ { 0x0638, 0, "afii57432" },
+ { 0x0639, 0, "afii57433" },
+ { 0x063A, 0, "afii57434" },
+ { 0x0640, 0, "afii57440" },
+ { 0x0641, 0, "afii57441" },
+ { 0x0642, 0, "afii57442" },
+ { 0x0643, 0, "afii57443" },
+ { 0x0644, 0, "afii57444" },
+ { 0x0645, 0, "afii57445" },
+ { 0x0646, 0, "afii57446" },
+ { 0x0648, 0, "afii57448" },
+ { 0x0649, 0, "afii57449" },
+ { 0x064A, 0, "afii57450" },
+ { 0x064B, 0, "afii57451" },
+ { 0x064C, 0, "afii57452" },
+ { 0x064D, 0, "afii57453" },
+ { 0x064E, 0, "afii57454" },
+ { 0x064F, 0, "afii57455" },
+ { 0x0650, 0, "afii57456" },
+ { 0x0651, 0, "afii57457" },
+ { 0x0652, 0, "afii57458" },
+ { 0x0647, 0, "afii57470" },
+ { 0x06A4, 0, "afii57505" },
+ { 0x067E, 0, "afii57506" },
+ { 0x0686, 0, "afii57507" },
+ { 0x0698, 0, "afii57508" },
+ { 0x06AF, 0, "afii57509" },
+ { 0x0679, 0, "afii57511" },
+ { 0x0688, 0, "afii57512" },
+ { 0x0691, 0, "afii57513" },
+ { 0x06BA, 0, "afii57514" },
+ { 0x06D2, 0, "afii57519" },
+ { 0x06D5, 0, "afii57534" },
+ { 0x20AA, 0, "afii57636" },
+ { 0x05BE, 0, "afii57645" },
+ { 0x05C3, 0, "afii57658" },
+ { 0x05D0, 0, "afii57664" },
+ { 0x05D1, 0, "afii57665" },
+ { 0x05D2, 0, "afii57666" },
+ { 0x05D3, 0, "afii57667" },
+ { 0x05D4, 0, "afii57668" },
+ { 0x05D5, 0, "afii57669" },
+ { 0x05D6, 0, "afii57670" },
+ { 0x05D7, 0, "afii57671" },
+ { 0x05D8, 0, "afii57672" },
+ { 0x05D9, 0, "afii57673" },
+ { 0x05DA, 0, "afii57674" },
+ { 0x05DB, 0, "afii57675" },
+ { 0x05DC, 0, "afii57676" },
+ { 0x05DD, 0, "afii57677" },
+ { 0x05DE, 0, "afii57678" },
+ { 0x05DF, 0, "afii57679" },
+ { 0x05E0, 0, "afii57680" },
+ { 0x05E1, 0, "afii57681" },
+ { 0x05E2, 0, "afii57682" },
+ { 0x05E3, 0, "afii57683" },
+ { 0x05E4, 0, "afii57684" },
+ { 0x05E5, 0, "afii57685" },
+ { 0x05E6, 0, "afii57686" },
+ { 0x05E7, 0, "afii57687" },
+ { 0x05E8, 0, "afii57688" },
+ { 0x05E9, 0, "afii57689" },
+ { 0x05EA, 0, "afii57690" },
+ { 0xFB2A, 0, "afii57694" },
+ { 0xFB2B, 0, "afii57695" },
+ { 0xFB4B, 0, "afii57700" },
+ { 0xFB1F, 0, "afii57705" },
+ { 0x05F0, 0, "afii57716" },
+ { 0x05F1, 0, "afii57717" },
+ { 0x05F2, 0, "afii57718" },
+ { 0xFB35, 0, "afii57723" },
+ { 0x05B4, 0, "afii57793" },
+ { 0x05B5, 0, "afii57794" },
+ { 0x05B6, 0, "afii57795" },
+ { 0x05BB, 0, "afii57796" },
+ { 0x05B8, 0, "afii57797" },
+ { 0x05B7, 0, "afii57798" },
+ { 0x05B0, 0, "afii57799" },
+ { 0x05B2, 0, "afii57800" },
+ { 0x05B1, 0, "afii57801" },
+ { 0x05B3, 0, "afii57802" },
+ { 0x05C2, 0, "afii57803" },
+ { 0x05C1, 0, "afii57804" },
+ { 0x05B9, 0, "afii57806" },
+ { 0x05BC, 0, "afii57807" },
+ { 0x05BD, 0, "afii57839" },
+ { 0x05BF, 0, "afii57841" },
+ { 0x05C0, 0, "afii57842" },
+ { 0x02BC, 0, "afii57929" },
+ { 0x2105, 0, "afii61248" },
+ { 0x2113, 0, "afii61289" },
+ { 0x2116, 0, "afii61352" },
+ { 0x202C, 0, "afii61573" },
+ { 0x202D, 0, "afii61574" },
+ { 0x202E, 0, "afii61575" },
+ { 0x200C, 0, "afii61664" },
+ { 0x066D, 0, "afii63167" },
+ { 0x02BD, 0, "afii64937" },
+ { 0x00E0, 0, "agrave" },
+ { 0x2135, 0, "aleph" },
+ { 0x03B1, 0, "alpha" },
+ { 0x03AC, 0, "alphatonos" },
+ { 0x0101, 0, "amacron" },
+ { 0x0026, 046, "ampersand" },
+ { 0xF726, 0, "ampersandsmall" },
+ { 0x2220, 0, "angle" },
+ { 0x2329, 0, "angleleft" },
+ { 0x232A, 0, "angleright" },
+ { 0x0387, 0, "anoteleia" },
+ { 0x0105, 0, "aogonek" },
+ { 0x2248, 0, "approxequal" },
+ { 0x00E5, 0, "aring" },
+ { 0x01FB, 0, "aringacute" },
+ { 0x2194, 0, "arrowboth" },
+ { 0x21D4, 0, "arrowdblboth" },
+ { 0x21D3, 0, "arrowdbldown" },
+ { 0x21D0, 0, "arrowdblleft" },
+ { 0x21D2, 0, "arrowdblright" },
+ { 0x21D1, 0, "arrowdblup" },
+ { 0x2193, 0, "arrowdown" },
+ { 0xF8E7, 0, "arrowhorizex" },
+ { 0x2190, 0, "arrowleft" },
+ { 0x2192, 0, "arrowright" },
+ { 0x2191, 0, "arrowup" },
+ { 0x2195, 0, "arrowupdn" },
+ { 0x21A8, 0, "arrowupdnbse" },
+ { 0xF8E6, 0, "arrowvertex" },
+ { 0x005E, 0136, "asciicircum" },
+ { 0x007E, 0176, "asciitilde" },
+ { 0x002A, 052, "asterisk" },
+ { 0x2217, 0, "asteriskmath" },
+ { 0xF6E9, 0, "asuperior" },
+ { 0x0040, 0100, "at" },
+ { 0x00E3, 0, "atilde" },
+ { 0x0062, 0142, "b" },
+ { 0x005C, 0134, "backslash" },
+ { 0x007C, 0174, "bar" },
+ { 0x03B2, 0, "beta" },
+ { 0x2588, 0, "block" },
+ { 0xF8F4, 0, "braceex" },
+ { 0x007B, 0173, "braceleft" },
+ { 0xF8F3, 0, "braceleftbt" },
+ { 0xF8F2, 0, "braceleftmid" },
+ { 0xF8F1, 0, "bracelefttp" },
+ { 0x007D, 0175, "braceright" },
+ { 0xF8FE, 0, "bracerightbt" },
+ { 0xF8FD, 0, "bracerightmid" },
+ { 0xF8FC, 0, "bracerighttp" },
+ { 0x005B, 0133, "bracketleft" },
+ { 0xF8F0, 0, "bracketleftbt" },
+ { 0xF8EF, 0, "bracketleftex" },
+ { 0xF8EE, 0, "bracketlefttp" },
+ { 0x005D, 0135, "bracketright" },
+ { 0xF8FB, 0, "bracketrightbt" },
+ { 0xF8FA, 0, "bracketrightex" },
+ { 0xF8F9, 0, "bracketrighttp" },
+ { 0x02D8, 0306, "breve" },
+ { 0x00A6, 0, "brokenbar" },
+ { 0xF6EA, 0, "bsuperior" },
+ { 0x2022, 0267, "bullet" },
+ { 0x0063, 0143, "c" },
+ { 0x0107, 0, "cacute" },
+ { 0x02C7, 0317, "caron" },
+ { 0x21B5, 0, "carriagereturn" },
+ { 0x010D, 0, "ccaron" },
+ { 0x00E7, 0, "ccedilla" },
+ { 0x0109, 0, "ccircumflex" },
+ { 0x010B, 0, "cdotaccent" },
+ { 0x00B8, 0313, "cedilla" },
+ { 0x00A2, 0242, "cent" },
+ { 0xF6DF, 0, "centinferior" },
+ { 0xF7A2, 0, "centoldstyle" },
+ { 0xF6E0, 0, "centsuperior" },
+ { 0x03C7, 0, "chi" },
+ { 0x25CB, 0, "circle" },
+ { 0x2297, 0, "circlemultiply" },
+ { 0x2295, 0, "circleplus" },
+ { 0x02C6, 0303, "circumflex" },
+ { 0x2663, 0, "club" },
+ { 0x003A, 072, "colon" },
+ { 0x20A1, 0, "colonmonetary" },
+ { 0x002C, 054, "comma" },
+ { 0xF6C3, 0, "commaaccent" },
+ { 0xF6E1, 0, "commainferior" },
+ { 0xF6E2, 0, "commasuperior" },
+ { 0x2245, 0, "congruent" },
+ { 0x00A9, 0, "copyright" },
+ { 0xF8E9, 0, "copyrightsans" },
+ { 0xF6D9, 0, "copyrightserif" },
+ { 0x00A4, 0250, "currency" },
+ { 0xF6D1, 0, "cyrBreve" },
+ { 0xF6D2, 0, "cyrFlex" },
+ { 0xF6D4, 0, "cyrbreve" },
+ { 0xF6D5, 0, "cyrflex" },
+ { 0x0064, 0144, "d" },
+ { 0x2020, 0262, "dagger" },
+ { 0x2021, 0263, "daggerdbl" },
+ { 0xF6D3, 0, "dblGrave" },
+ { 0xF6D6, 0, "dblgrave" },
+ { 0x010F, 0, "dcaron" },
+ { 0x0111, 0, "dcroat" },
+ { 0x00B0, 0, "degree" },
+ { 0x03B4, 0, "delta" },
+ { 0x2666, 0, "diamond" },
+ { 0x00A8, 0310, "dieresis" },
+ { 0xF6D7, 0, "dieresisacute" },
+ { 0xF6D8, 0, "dieresisgrave" },
+ { 0x0385, 0, "dieresistonos" },
+ { 0x00F7, 0, "divide" },
+ { 0x2593, 0, "dkshade" },
+ { 0x2584, 0, "dnblock" },
+ { 0x0024, 044, "dollar" },
+ { 0xF6E3, 0, "dollarinferior" },
+ { 0xF724, 0, "dollaroldstyle" },
+ { 0xF6E4, 0, "dollarsuperior" },
+ { 0x20AB, 0, "dong" },
+ { 0x02D9, 0307, "dotaccent" },
+ { 0x0323, 0, "dotbelowcomb" },
+ { 0x0131, 0365, "dotlessi" },
+ { 0xF6BE, 0, "dotlessj" },
+ { 0x22C5, 0, "dotmath" },
+ { 0xF6EB, 0, "dsuperior" },
+ { 0x0065, 0145, "e" },
+ { 0x00E9, 0, "eacute" },
+ { 0x0115, 0, "ebreve" },
+ { 0x011B, 0, "ecaron" },
+ { 0x00EA, 0, "ecircumflex" },
+ { 0x00EB, 0, "edieresis" },
+ { 0x0117, 0, "edotaccent" },
+ { 0x00E8, 0, "egrave" },
+ { 0x0038, 070, "eight" },
+ { 0x2088, 0, "eightinferior" },
+ { 0xF738, 0, "eightoldstyle" },
+ { 0x2078, 0, "eightsuperior" },
+ { 0x2208, 0, "element" },
+ { 0x2026, 0274, "ellipsis" },
+ { 0x0113, 0, "emacron" },
+ { 0x2014, 0320, "emdash" },
+ { 0x2205, 0, "emptyset" },
+ { 0x2013, 0261, "endash" },
+ { 0x014B, 0, "eng" },
+ { 0x0119, 0, "eogonek" },
+ { 0x03B5, 0, "epsilon" },
+ { 0x03AD, 0, "epsilontonos" },
+ { 0x003D, 075, "equal" },
+ { 0x2261, 0, "equivalence" },
+ { 0x212E, 0, "estimated" },
+ { 0xF6EC, 0, "esuperior" },
+ { 0x03B7, 0, "eta" },
+ { 0x03AE, 0, "etatonos" },
+ { 0x00F0, 0, "eth" },
+ { 0x0021, 041, "exclam" },
+ { 0x203C, 0, "exclamdbl" },
+ { 0x00A1, 0241, "exclamdown" },
+ { 0xF7A1, 0, "exclamdownsmall" },
+ { 0xF721, 0, "exclamsmall" },
+ { 0x2203, 0, "existential" },
+ { 0x0066, 0146, "f" },
+ { 0x2640, 0, "female" },
+ { 0xFB00, 0, "ff" },
+ { 0xFB03, 0, "ffi" },
+ { 0xFB04, 0, "ffl" },
+ { 0xFB01, 0256, "fi" },
+ { 0x2012, 0, "figuredash" },
+ { 0x25A0, 0, "filledbox" },
+ { 0x25AC, 0, "filledrect" },
+ { 0x0035, 065, "five" },
+ { 0x215D, 0, "fiveeighths" },
+ { 0x2085, 0, "fiveinferior" },
+ { 0xF735, 0, "fiveoldstyle" },
+ { 0x2075, 0, "fivesuperior" },
+ { 0xFB02, 0257, "fl" },
+ { 0x0192, 0246, "florin" },
+ { 0x0034, 064, "four" },
+ { 0x2084, 0, "fourinferior" },
+ { 0xF734, 0, "fouroldstyle" },
+ { 0x2074, 0, "foursuperior" },
+ { 0x2044, 0244, "fraction" },
+ { 0x2215, 0244, "fraction" },
+ { 0x20A3, 0, "franc" },
+ { 0x0067, 0147, "g" },
+ { 0x03B3, 0, "gamma" },
+ { 0x011F, 0, "gbreve" },
+ { 0x01E7, 0, "gcaron" },
+ { 0x011D, 0, "gcircumflex" },
+ { 0x0123, 0, "gcommaaccent" },
+ { 0x0121, 0, "gdotaccent" },
+ { 0x00DF, 0373, "germandbls" },
+ { 0x2207, 0, "gradient" },
+ { 0x0060, 0301, "grave" },
+ { 0x0300, 0, "gravecomb" },
+ { 0x003E, 076, "greater" },
+ { 0x2265, 0, "greaterequal" },
+ { 0x00AB, 0253, "guillemotleft" },
+ { 0x00BB, 0273, "guillemotright" },
+ { 0x2039, 0254, "guilsinglleft" },
+ { 0x203A, 0255, "guilsinglright" },
+ { 0x0068, 0150, "h" },
+ { 0x0127, 0, "hbar" },
+ { 0x0125, 0, "hcircumflex" },
+ { 0x2665, 0, "heart" },
+ { 0x0309, 0, "hookabovecomb" },
+ { 0x2302, 0, "house" },
+ { 0x02DD, 0315, "hungarumlaut" },
+ { 0x002D, 055, "hyphen" },
+ { 0x00AD, 0, "hyphen" },
+ { 0xF6E5, 0, "hypheninferior" },
+ { 0xF6E6, 0, "hyphensuperior" },
+ { 0x0069, 0151, "i" },
+ { 0x00ED, 0, "iacute" },
+ { 0x012D, 0, "ibreve" },
+ { 0x00EE, 0, "icircumflex" },
+ { 0x00EF, 0, "idieresis" },
+ { 0x00EC, 0, "igrave" },
+ { 0x0133, 0, "ij" },
+ { 0x012B, 0, "imacron" },
+ { 0x221E, 0, "infinity" },
+ { 0x222B, 0, "integral" },
+ { 0x2321, 0, "integralbt" },
+ { 0xF8F5, 0, "integralex" },
+ { 0x2320, 0, "integraltp" },
+ { 0x2229, 0, "intersection" },
+ { 0x25D8, 0, "invbullet" },
+ { 0x25D9, 0, "invcircle" },
+ { 0x263B, 0, "invsmileface" },
+ { 0x012F, 0, "iogonek" },
+ { 0x03B9, 0, "iota" },
+ { 0x03CA, 0, "iotadieresis" },
+ { 0x0390, 0, "iotadieresistonos" },
+ { 0x03AF, 0, "iotatonos" },
+ { 0xF6ED, 0, "isuperior" },
+ { 0x0129, 0, "itilde" },
+ { 0x006A, 0152, "j" },
+ { 0x0135, 0, "jcircumflex" },
+ { 0x006B, 0153, "k" },
+ { 0x03BA, 0, "kappa" },
+ { 0x0137, 0, "kcommaaccent" },
+ { 0x0138, 0, "kgreenlandic" },
+ { 0x006C, 0154, "l" },
+ { 0x013A, 0, "lacute" },
+ { 0x03BB, 0, "lambda" },
+ { 0x013E, 0, "lcaron" },
+ { 0x013C, 0, "lcommaaccent" },
+ { 0x0140, 0, "ldot" },
+ { 0x003C, 074, "less" },
+ { 0x2264, 0, "lessequal" },
+ { 0x258C, 0, "lfblock" },
+ { 0x20A4, 0, "lira" },
+ { 0xF6C0, 0, "ll" },
+ { 0x2227, 0, "logicaland" },
+ { 0x00AC, 0, "logicalnot" },
+ { 0x2228, 0, "logicalor" },
+ { 0x017F, 0, "longs" },
+ { 0x25CA, 0, "lozenge" },
+ { 0x0142, 0370, "lslash" },
+ { 0xF6EE, 0, "lsuperior" },
+ { 0x2591, 0, "ltshade" },
+ { 0x006D, 0155, "m" },
+ { 0x00AF, 0305, "macron" },
+ { 0x02C9, 0305, "macron" },
+ { 0x2642, 0, "male" },
+ { 0x2212, 0, "minus" },
+ { 0x2032, 0, "minute" },
+ { 0xF6EF, 0, "msuperior" },
+ { 0x00B5, 0, "mu" },
+ { 0x03BC, 0, "mu" },
+ { 0x00D7, 0, "multiply" },
+ { 0x266A, 0, "musicalnote" },
+ { 0x266B, 0, "musicalnotedbl" },
+ { 0x006E, 0156, "n" },
+ { 0x0144, 0, "nacute" },
+ { 0x0149, 0, "napostrophe" },
+ { 0x0148, 0, "ncaron" },
+ { 0x0146, 0, "ncommaaccent" },
+ { 0x0039, 071, "nine" },
+ { 0x2089, 0, "nineinferior" },
+ { 0xF739, 0, "nineoldstyle" },
+ { 0x2079, 0, "ninesuperior" },
+ { 0x2209, 0, "notelement" },
+ { 0x2260, 0, "notequal" },
+ { 0x2284, 0, "notsubset" },
+ { 0x207F, 0, "nsuperior" },
+ { 0x00F1, 0, "ntilde" },
+ { 0x03BD, 0, "nu" },
+ { 0x0023, 043, "numbersign" },
+ { 0x006F, 0157, "o" },
+ { 0x00F3, 0, "oacute" },
+ { 0x014F, 0, "obreve" },
+ { 0x00F4, 0, "ocircumflex" },
+ { 0x00F6, 0, "odieresis" },
+ { 0x0153, 0372, "oe" },
+ { 0x02DB, 0316, "ogonek" },
+ { 0x00F2, 0, "ograve" },
+ { 0x01A1, 0, "ohorn" },
+ { 0x0151, 0, "ohungarumlaut" },
+ { 0x014D, 0, "omacron" },
+ { 0x03C9, 0, "omega" },
+ { 0x03D6, 0, "omega1" },
+ { 0x03CE, 0, "omegatonos" },
+ { 0x03BF, 0, "omicron" },
+ { 0x03CC, 0, "omicrontonos" },
+ { 0x0031, 061, "one" },
+ { 0x2024, 0, "onedotenleader" },
+ { 0x215B, 0, "oneeighth" },
+ { 0xF6DC, 0, "onefitted" },
+ { 0x00BD, 0, "onehalf" },
+ { 0x2081, 0, "oneinferior" },
+ { 0xF731, 0, "oneoldstyle" },
+ { 0x00BC, 0, "onequarter" },
+ { 0x00B9, 0, "onesuperior" },
+ { 0x2153, 0, "onethird" },
+ { 0x25E6, 0, "openbullet" },
+ { 0x00AA, 0343, "ordfeminine" },
+ { 0x00BA, 0353, "ordmasculine" },
+ { 0x221F, 0, "orthogonal" },
+ { 0x00F8, 0371, "oslash" },
+ { 0x01FF, 0, "oslashacute" },
+ { 0xF6F0, 0, "osuperior" },
+ { 0x00F5, 0, "otilde" },
+ { 0x0070, 0160, "p" },
+ { 0x00B6, 0266, "paragraph" },
+ { 0x0028, 050, "parenleft" },
+ { 0xF8ED, 0, "parenleftbt" },
+ { 0xF8EC, 0, "parenleftex" },
+ { 0x208D, 0, "parenleftinferior" },
+ { 0x207D, 0, "parenleftsuperior" },
+ { 0xF8EB, 0, "parenlefttp" },
+ { 0x0029, 051, "parenright" },
+ { 0xF8F8, 0, "parenrightbt" },
+ { 0xF8F7, 0, "parenrightex" },
+ { 0x208E, 0, "parenrightinferior" },
+ { 0x207E, 0, "parenrightsuperior" },
+ { 0xF8F6, 0, "parenrighttp" },
+ { 0x2202, 0, "partialdiff" },
+ { 0x0025, 045, "percent" },
+ { 0x002E, 056, "period" },
+ { 0x00B7, 0264, "periodcentered" },
+ { 0x2219, 0, "periodcentered" },
+ { 0xF6E7, 0, "periodinferior" },
+ { 0xF6E8, 0, "periodsuperior" },
+ { 0x22A5, 0, "perpendicular" },
+ { 0x2030, 0275, "perthousand" },
+ { 0x20A7, 0, "peseta" },
+ { 0x03C6, 0, "phi" },
+ { 0x03D5, 0, "phi1" },
+ { 0x03C0, 0, "pi" },
+ { 0x002B, 053, "plus" },
+ { 0x00B1, 0, "plusminus" },
+ { 0x211E, 0, "prescription" },
+ { 0x220F, 0, "product" },
+ { 0x2282, 0, "propersubset" },
+ { 0x2283, 0, "propersuperset" },
+ { 0x221D, 0, "proportional" },
+ { 0x03C8, 0, "psi" },
+ { 0x0071, 0161, "q" },
+ { 0x003F, 077, "question" },
+ { 0x00BF, 0277, "questiondown" },
+ { 0xF7BF, 0, "questiondownsmall" },
+ { 0xF73F, 0, "questionsmall" },
+ { 0x0022, 042, "quotedbl" },
+ { 0x201E, 0271, "quotedblbase" },
+ { 0x201C, 0252, "quotedblleft" },
+ { 0x201D, 0272, "quotedblright" },
+ { 0x2018, 0140, "quoteleft" },
+ { 0x201B, 0, "quotereversed" },
+ { 0x2019, 047, "quoteright" },
+ { 0x201A, 0270, "quotesinglbase" },
+ { 0x0027, 0251, "quotesingle" },
+ { 0x0072, 0162, "r" },
+ { 0x0155, 0, "racute" },
+ { 0x221A, 0, "radical" },
+ { 0xF8E5, 0, "radicalex" },
+ { 0x0159, 0, "rcaron" },
+ { 0x0157, 0, "rcommaaccent" },
+ { 0x2286, 0, "reflexsubset" },
+ { 0x2287, 0, "reflexsuperset" },
+ { 0x00AE, 0, "registered" },
+ { 0xF8E8, 0, "registersans" },
+ { 0xF6DA, 0, "registerserif" },
+ { 0x2310, 0, "revlogicalnot" },
+ { 0x03C1, 0, "rho" },
+ { 0x02DA, 0312, "ring" },
+ { 0xF6F1, 0, "rsuperior" },
+ { 0x2590, 0, "rtblock" },
+ { 0xF6DD, 0, "rupiah" },
+ { 0x0073, 0163, "s" },
+ { 0x015B, 0, "sacute" },
+ { 0x0161, 0, "scaron" },
+ { 0x015F, 0, "scedilla" },
+ { 0xF6C2, 0, "scedilla" },
+ { 0x015D, 0, "scircumflex" },
+ { 0x0219, 0, "scommaaccent" },
+ { 0x2033, 0, "second" },
+ { 0x00A7, 0247, "section" },
+ { 0x003B, 073, "semicolon" },
+ { 0x0037, 067, "seven" },
+ { 0x215E, 0, "seveneighths" },
+ { 0x2087, 0, "seveninferior" },
+ { 0xF737, 0, "sevenoldstyle" },
+ { 0x2077, 0, "sevensuperior" },
+ { 0x2592, 0, "shade" },
+ { 0x03C3, 0, "sigma" },
+ { 0x03C2, 0, "sigma1" },
+ { 0x223C, 0, "similar" },
+ { 0x0036, 066, "six" },
+ { 0x2086, 0, "sixinferior" },
+ { 0xF736, 0, "sixoldstyle" },
+ { 0x2076, 0, "sixsuperior" },
+ { 0x002F, 057, "slash" },
+ { 0x263A, 0, "smileface" },
+ { 0x0020, 040, "space" },
+ { 0x00A0, 040, "space" },
+ { 0x2660, 0, "spade" },
+ { 0xF6F2, 0, "ssuperior" },
+ { 0x00A3, 0243, "sterling" },
+ { 0x220B, 0, "suchthat" },
+ { 0x2211, 0, "summation" },
+ { 0x263C, 0, "sun" },
+ { 0x0074, 0164, "t" },
+ { 0x03C4, 0, "tau" },
+ { 0x0167, 0, "tbar" },
+ { 0x0165, 0, "tcaron" },
+ { 0x0163, 0, "tcommaaccent" },
+ { 0x021B, 0, "tcommaaccent" },
+ { 0x2234, 0, "therefore" },
+ { 0x03B8, 0, "theta" },
+ { 0x03D1, 0, "theta1" },
+ { 0x00FE, 0, "thorn" },
+ { 0x0033, 063, "three" },
+ { 0x215C, 0, "threeeighths" },
+ { 0x2083, 0, "threeinferior" },
+ { 0xF733, 0, "threeoldstyle" },
+ { 0x00BE, 0, "threequarters" },
+ { 0xF6DE, 0, "threequartersemdash" },
+ { 0x00B3, 0, "threesuperior" },
+ { 0x02DC, 0304, "tilde" },
+ { 0x0303, 0, "tildecomb" },
+ { 0x0384, 0, "tonos" },
+ { 0x2122, 0, "trademark" },
+ { 0xF8EA, 0, "trademarksans" },
+ { 0xF6DB, 0, "trademarkserif" },
+ { 0x25BC, 0, "triagdn" },
+ { 0x25C4, 0, "triaglf" },
+ { 0x25BA, 0, "triagrt" },
+ { 0x25B2, 0, "triagup" },
+ { 0xF6F3, 0, "tsuperior" },
+ { 0x0032, 062, "two" },
+ { 0x2025, 0, "twodotenleader" },
+ { 0x2082, 0, "twoinferior" },
+ { 0xF732, 0, "twooldstyle" },
+ { 0x00B2, 0, "twosuperior" },
+ { 0x2154, 0, "twothirds" },
+ { 0x0075, 0165, "u" },
+ { 0x00FA, 0, "uacute" },
+ { 0x016D, 0, "ubreve" },
+ { 0x00FB, 0, "ucircumflex" },
+ { 0x00FC, 0, "udieresis" },
+ { 0x00F9, 0, "ugrave" },
+ { 0x01B0, 0, "uhorn" },
+ { 0x0171, 0, "uhungarumlaut" },
+ { 0x016B, 0, "umacron" },
+ { 0x005F, 0137, "underscore" },
+ { 0x2017, 0, "underscoredbl" },
+ { 0x222A, 0, "union" },
+ { 0x2200, 0, "universal" },
+ { 0x0173, 0, "uogonek" },
+ { 0x2580, 0, "upblock" },
+ { 0x03C5, 0, "upsilon" },
+ { 0x03CB, 0, "upsilondieresis" },
+ { 0x03B0, 0, "upsilondieresistonos" },
+ { 0x03CD, 0, "upsilontonos" },
+ { 0x016F, 0, "uring" },
+ { 0x0169, 0, "utilde" },
+ { 0x0076, 0166, "v" },
+ { 0x0077, 0167, "w" },
+ { 0x1E83, 0, "wacute" },
+ { 0x0175, 0, "wcircumflex" },
+ { 0x1E85, 0, "wdieresis" },
+ { 0x2118, 0, "weierstrass" },
+ { 0x1E81, 0, "wgrave" },
+ { 0x0078, 0170, "x" },
+ { 0x03BE, 0, "xi" },
+ { 0x0079, 0171, "y" },
+ { 0x00FD, 0, "yacute" },
+ { 0x0177, 0, "ycircumflex" },
+ { 0x00FF, 0, "ydieresis" },
+ { 0x00A5, 0245, "yen" },
+ { 0x1EF3, 0, "ygrave" },
+ { 0x007A, 0172, "z" },
+ { 0x017A, 0, "zacute" },
+ { 0x017E, 0, "zcaron" },
+ { 0x017C, 0, "zdotaccent" },
+ { 0x0030, 060, "zero" },
+ { 0x2080, 0, "zeroinferior" },
+ { 0xF730, 0, "zerooldstyle" },
+ { 0x2070, 0, "zerosuperior" },
+ { 0x03B6, 0, "zeta" }
+};
diff --git a/vcl/unx/source/fontmanager/afm_hash.cpp b/vcl/unx/source/fontmanager/afm_hash.cpp
new file mode 100755
index 000000000000..de01d8cd0434
--- /dev/null
+++ b/vcl/unx/source/fontmanager/afm_hash.cpp
@@ -0,0 +1,245 @@
+/* C++ code produced by gperf version 3.0.1 */
+/* Command-line: gperf -C -t -l -L C++ -m 20 -Z AfmKeywordHash afm_keyword_list */
+/* Computed positions: -k'1,4,6,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 1 "afm_keyword_list"
+struct hash_entry { const char* name; enum parseKey eKey; };
+
+#define TOTAL_KEYWORDS 56
+#define MIN_WORD_LENGTH 1
+#define MAX_WORD_LENGTH 18
+#define MIN_HASH_VALUE 1
+#define MAX_HASH_VALUE 57
+/* maximum key range = 57, duplicates = 0 */
+
+class AfmKeywordHash
+{
+private:
+ static inline unsigned int hash (const char *str, unsigned int len);
+public:
+ static const struct hash_entry *in_word_set (const char *str, unsigned int len);
+};
+
+inline unsigned int
+AfmKeywordHash::hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 28, 1, 0, 9, 0,
+ 19, 58, 2, 10, 58, 0, 28, 0, 20, 58,
+ 44, 58, 58, 0, 16, 10, 24, 2, 3, 58,
+ 58, 58, 58, 58, 58, 58, 58, 6, 58, 0,
+ 19, 0, 58, 25, 14, 6, 58, 58, 17, 11,
+ 0, 17, 39, 58, 0, 0, 10, 58, 58, 58,
+ 13, 4, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[5]];
+ /*FALLTHROUGH*/
+ case 5:
+ case 4:
+ hval += asso_values[(unsigned char)str[3]];
+ /*FALLTHROUGH*/
+ case 3:
+ case 2:
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval + asso_values[(unsigned char)str[len - 1]];
+}
+
+const struct hash_entry *
+AfmKeywordHash::in_word_set (register const char *str, register unsigned int len)
+{
+ static const unsigned char lengthtable[] =
+ {
+ 0, 1, 2, 1, 2, 1, 3, 2, 3, 5, 10, 11, 12, 2,
+ 14, 15, 16, 11, 9, 13, 14, 12, 12, 14, 13, 9, 7, 9,
+ 7, 9, 14, 5, 6, 14, 12, 16, 10, 14, 11, 10, 7, 1,
+ 12, 8, 17, 18, 2, 3, 7, 1, 8, 8, 13, 6, 6, 8,
+ 0, 1
+ };
+ static const struct hash_entry wordlist[] =
+ {
+ {"",NOPE},
+#line 6 "afm_keyword_list"
+ {"C",CODE},
+#line 7 "afm_keyword_list"
+ {"CC",COMPCHAR},
+#line 5 "afm_keyword_list"
+ {"B",CHARBBOX},
+#line 8 "afm_keyword_list"
+ {"CH",CODEHEX},
+#line 54 "afm_keyword_list"
+ {"W",XYWIDTH},
+#line 33 "afm_keyword_list"
+ {"KPX",KERNPAIRXAMT},
+#line 56 "afm_keyword_list"
+ {"WX",XWIDTH},
+#line 55 "afm_keyword_list"
+ {"W0X",X0WIDTH},
+#line 47 "afm_keyword_list"
+ {"StdHW",STDHW},
+#line 12 "afm_keyword_list"
+ {"Characters",CHARACTERS},
+#line 36 "afm_keyword_list"
+ {"MetricsSets",METRICSSETS},
+#line 23 "afm_keyword_list"
+ {"EndKernPairs",ENDKERNPAIRS},
+#line 16 "afm_keyword_list"
+ {"Em",EM},
+#line 45 "afm_keyword_list"
+ {"StartKernPairs",STARTKERNPAIRS},
+#line 41 "afm_keyword_list"
+ {"StartComposites",STARTCOMPOSITES},
+#line 40 "afm_keyword_list"
+ {"StartCharMetrics",STARTCHARMETRICS},
+#line 22 "afm_keyword_list"
+ {"EndKernData",ENDKERNDATA},
+#line 14 "afm_keyword_list"
+ {"Descender",DESCENDER},
+#line 44 "afm_keyword_list"
+ {"StartKernData",STARTKERNDATA},
+#line 18 "afm_keyword_list"
+ {"EndCharMetrics",ENDCHARMETRICS},
+#line 20 "afm_keyword_list"
+ {"EndDirection",ENDDIRECTION},
+#line 11 "afm_keyword_list"
+ {"CharacterSet",CHARACTERSET},
+#line 42 "afm_keyword_list"
+ {"StartDirection",STARTDIRECTION},
+#line 19 "afm_keyword_list"
+ {"EndComposites",ENDCOMPOSITES},
+#line 49 "afm_keyword_list"
+ {"TrackKern",TRACKKERN},
+#line 15 "afm_keyword_list"
+ {"Descent",DESCENT},
+#line 9 "afm_keyword_list"
+ {"CapHeight",CAPHEIGHT},
+#line 13 "afm_keyword_list"
+ {"Comment",COMMENT},
+#line 10 "afm_keyword_list"
+ {"CharWidth",CHARWIDTH},
+#line 46 "afm_keyword_list"
+ {"StartTrackKern",STARTTRACKKERN},
+#line 48 "afm_keyword_list"
+ {"StdVW",STDVW},
+#line 38 "afm_keyword_list"
+ {"Notice",NOTICE},
+#line 21 "afm_keyword_list"
+ {"EndFontMetrics",ENDFONTMETRICS},
+#line 24 "afm_keyword_list"
+ {"EndTrackKern",ENDTRACKKERN},
+#line 43 "afm_keyword_list"
+ {"StartFontMetrics",STARTFONTMETRICS},
+#line 29 "afm_keyword_list"
+ {"IsBaseFont",ISBASEFONT},
+#line 17 "afm_keyword_list"
+ {"EncodingScheme",ENCODINGSCHEME},
+#line 31 "afm_keyword_list"
+ {"ItalicAngle",ITALICANGLE},
+#line 25 "afm_keyword_list"
+ {"FamilyName",FAMILYNAME},
+#line 58 "afm_keyword_list"
+ {"XHeight",XHEIGHT},
+#line 37 "afm_keyword_list"
+ {"N",CHARNAME},
+#line 30 "afm_keyword_list"
+ {"IsFixedPitch",ISFIXEDPITCH},
+#line 27 "afm_keyword_list"
+ {"FontName",FONTNAME},
+#line 50 "afm_keyword_list"
+ {"UnderlinePosition",UNDERLINEPOSITION},
+#line 51 "afm_keyword_list"
+ {"UnderlineThickness",UNDERLINETHICKNESS},
+#line 32 "afm_keyword_list"
+ {"KP",KERNPAIR},
+#line 39 "afm_keyword_list"
+ {"PCC",COMPCHARPIECE},
+#line 53 "afm_keyword_list"
+ {"Version",VERSION},
+#line 52 "afm_keyword_list"
+ {"V",VVECTOR},
+#line 28 "afm_keyword_list"
+ {"FullName",FULLNAME},
+#line 26 "afm_keyword_list"
+ {"FontBBox",FONTBBOX},
+#line 35 "afm_keyword_list"
+ {"MappingScheme",MAPPINGSCHEME},
+#line 57 "afm_keyword_list"
+ {"Weight",WEIGHT},
+#line 4 "afm_keyword_list"
+ {"Ascent",ASCENT},
+#line 3 "afm_keyword_list"
+ {"Ascender",ASCENDER},
+ {"",NOPE},
+#line 34 "afm_keyword_list"
+ {"L",LIGATURE}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ if (len == lengthtable[key])
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !memcmp (str + 1, s + 1, len - 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/vcl/unx/source/fontmanager/afm_keyword_list b/vcl/unx/source/fontmanager/afm_keyword_list
new file mode 100755
index 000000000000..263d76bca4d3
--- /dev/null
+++ b/vcl/unx/source/fontmanager/afm_keyword_list
@@ -0,0 +1,58 @@
+struct hash_entry { char* name; enum parseKey eKey; };
+%%
+Ascender,ASCENDER
+Ascent,ASCENT
+B,CHARBBOX
+C,CODE
+CC,COMPCHAR
+CH,CODEHEX
+CapHeight,CAPHEIGHT
+CharWidth,CHARWIDTH
+CharacterSet,CHARACTERSET
+Characters,CHARACTERS
+Comment,COMMENT
+Descender,DESCENDER
+Descent,DESCENT
+Em,EM
+EncodingScheme,ENCODINGSCHEME
+EndCharMetrics,ENDCHARMETRICS
+EndComposites,ENDCOMPOSITES
+EndDirection,ENDDIRECTION
+EndFontMetrics,ENDFONTMETRICS
+EndKernData,ENDKERNDATA
+EndKernPairs,ENDKERNPAIRS
+EndTrackKern,ENDTRACKKERN
+FamilyName,FAMILYNAME
+FontBBox,FONTBBOX
+FontName,FONTNAME
+FullName,FULLNAME
+IsBaseFont,ISBASEFONT
+IsFixedPitch,ISFIXEDPITCH
+ItalicAngle,ITALICANGLE
+KP,KERNPAIR
+KPX,KERNPAIRXAMT
+L,LIGATURE
+MappingScheme,MAPPINGSCHEME
+MetricsSets,METRICSSETS
+N,CHARNAME
+Notice,NOTICE
+PCC,COMPCHARPIECE
+StartCharMetrics,STARTCHARMETRICS
+StartComposites,STARTCOMPOSITES
+StartDirection,STARTDIRECTION
+StartFontMetrics,STARTFONTMETRICS
+StartKernData,STARTKERNDATA
+StartKernPairs,STARTKERNPAIRS
+StartTrackKern,STARTTRACKKERN
+StdHW,STDHW
+StdVW,STDVW
+TrackKern,TRACKKERN
+UnderlinePosition,UNDERLINEPOSITION
+UnderlineThickness,UNDERLINETHICKNESS
+V,VVECTOR
+Version,VERSION
+W,XYWIDTH
+W0X,X0WIDTH
+WX,XWIDTH
+Weight,WEIGHT
+XHeight,XHEIGHT
diff --git a/vcl/unx/source/fontmanager/fontcache.cxx b/vcl/unx/source/fontmanager/fontcache.cxx
new file mode 100644
index 000000000000..4932f7a771e0
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontcache.cxx
@@ -0,0 +1,821 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: fontcache.cxx,v $
+ * $Revision: 1.26 $
+ *
+ * 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 <cstdlib>
+#include <cstring>
+
+#include "vcl/fontcache.hxx"
+
+#include "osl/thread.h"
+
+#include "unotools/atom.hxx"
+
+#include "tools/stream.hxx"
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if OSL_DEBUG_LEVEL >1
+#include <cstdio>
+#endif
+
+#define FONTCACHEFILE "/user/psprint/pspfontcache"
+#define CACHE_MAGIC "PspFontCacheFile format 3"
+
+using namespace std;
+using namespace rtl;
+using namespace psp;
+using namespace utl;
+
+/*
+ * static helpers
+ */
+
+/*
+ * FontCache constructor
+ */
+
+FontCache::FontCache()
+{
+ m_bDoFlush = false;
+ m_aCacheFile = getOfficePath( UserPath );
+ if( m_aCacheFile.Len() )
+ {
+ m_aCacheFile.AppendAscii( FONTCACHEFILE );
+ read();
+ }
+}
+
+/*
+ * FontCache destructor
+ */
+
+FontCache::~FontCache()
+{
+ clearCache();
+}
+
+/*
+ * FontCache::clearCache
+ */
+void FontCache::clearCache()
+{
+ for( FontCacheData::iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++dir_it )
+ {
+ for( FontDirMap::iterator entry_it = dir_it->second.m_aEntries.begin(); entry_it != dir_it->second.m_aEntries.end(); ++entry_it )
+ {
+ for( FontCacheEntry::iterator font_it = entry_it->second.m_aEntry.begin(); font_it != entry_it->second.m_aEntry.end(); ++font_it )
+ delete *font_it;
+ }
+ }
+ m_aCache.clear();
+}
+
+/*
+ * FontCache::Commit
+ */
+
+void FontCache::flush()
+{
+ if( ! m_bDoFlush || ! m_aCacheFile.Len() )
+ return;
+
+ SvFileStream aStream;
+ aStream.Open( m_aCacheFile, STREAM_WRITE | STREAM_TRUNC );
+ if( ! (aStream.IsOpen() && aStream.IsWritable()) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FontCache::flush: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+#endif
+ return;
+ }
+
+ aStream.SetLineDelimiter( LINEEND_LF );
+ aStream.WriteLine( ByteString( CACHE_MAGIC ) );
+
+ PrintFontManager& rManager( PrintFontManager::get() );
+ MultiAtomProvider* pAtoms = rManager.m_pAtoms;
+
+ for( FontCacheData::const_iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++ dir_it )
+ {
+ const FontDirMap& rDir( dir_it->second.m_aEntries );
+
+ ByteString aDirectory( rManager.getDirectory( dir_it->first ) );
+ ByteString aLine( "FontCacheDirectory:" );
+ aLine.Append( ByteString::CreateFromInt64( dir_it->second.m_nTimestamp ) );
+ aLine.Append( ':' );
+ aLine.Append( aDirectory );
+ if( rDir.empty() && dir_it->second.m_bNoFiles )
+ aLine.Insert( "Empty", 0 );
+ aStream.WriteLine( aLine );
+
+ for( FontDirMap::const_iterator entry_it = rDir.begin(); entry_it != rDir.end(); ++entry_it )
+ {
+ // insert cache entries
+ const FontCacheEntry& rEntry( entry_it->second.m_aEntry );
+ if( rEntry.begin() == rEntry.end() )
+ continue;
+
+ aLine = "File:";
+ aLine.Append( ByteString( entry_it->first ) );
+ aStream.WriteLine( aLine );
+
+ int nEntrySize = entry_it->second.m_aEntry.size();
+ // write: type;nfonts
+ aLine = ByteString::CreateFromInt32( rEntry.front()->m_eType );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( nEntrySize ) );
+ aStream.WriteLine( aLine );
+
+ sal_Int32 nSubEntry = 0;
+ for( FontCacheEntry::const_iterator it = rEntry.begin(); it != rEntry.end(); ++it, nSubEntry++ )
+ {
+ /*
+ * for each font entry write:
+ * name[;name[;name]]
+ * fontnr;PSName;italic;weight;width;pitch;encoding;ascend;descend;leading;vsubst;gxw;gxh;gyw;gyh;useroverrride;embed;antialias[;{metricfile,typeflags}][;stylename]
+ */
+ if( nEntrySize > 1 )
+ nSubEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nCollectionEntry;
+ else
+ nSubEntry = -1;
+
+ aLine = OUStringToOString( pAtoms->getString( ATOM_FAMILYNAME, (*it)->m_nFamilyName ), RTL_TEXTENCODING_UTF8 );
+ for( ::std::list< int >::const_iterator name_it = (*it)->m_aAliases.begin(); name_it != (*it)->m_aAliases.end(); ++name_it )
+ {
+ const OUString& rAdd( pAtoms->getString( ATOM_FAMILYNAME, *name_it ) );
+ if( rAdd.getLength() )
+ {
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( rAdd ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ }
+ aStream.WriteLine( aLine );
+
+ const OUString& rPSName( pAtoms->getString( ATOM_PSNAME, (*it)->m_nPSName ) );
+ aLine = ByteString::CreateFromInt32( nSubEntry );
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( rPSName ), RTL_TEXTENCODING_UTF8 ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eItalic ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWeight ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWidth ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_ePitch ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aEncoding ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nAscend ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nDescend ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nLeading ) );
+ aLine.Append( ';' );
+ aLine.Append( (*it)->m_bHaveVerticalSubstitutedGlyphs ? "1" : "0" );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.width ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.height ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.width ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.height ) );
+ aLine.Append( ';' );
+ aLine.Append( (*it)->m_bUserOverride ? "1" : "0" );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eEmbeddedbitmap ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eAntialias ) );
+
+ switch( (*it)->m_eType )
+ {
+ case fonttype::Type1:
+ aLine.Append( ';' );
+ aLine.Append( ByteString( static_cast<const PrintFontManager::Type1FontFile*>(*it)->m_aMetricFile ) );
+ break;
+ case fonttype::TrueType:
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nTypeFlags ) );
+ break;
+ default: break;
+ }
+ if( (*it)->m_aStyleName.getLength() )
+ {
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( (*it)->m_aStyleName ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ aStream.WriteLine( aLine );
+ }
+ aStream.WriteLine( ByteString() );
+ }
+ }
+ m_bDoFlush = false;
+}
+
+/*
+ * FontCache::read
+ */
+
+void FontCache::read()
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ MultiAtomProvider* pAtoms = rManager.m_pAtoms;
+
+ SvFileStream aStream( m_aCacheFile, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FontCache::read: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+#endif
+ return;
+ }
+
+
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ if( !aLine.Equals( CACHE_MAGIC ) )
+ {
+ #if OSL_DEBUG_LEVEL >1
+ fprintf( stderr, "FontCache::read: cache file %s fails magic test\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+ #endif
+ return;
+ }
+
+ int nDir = 0;
+ FontDirMap* pDir = NULL;
+ xub_StrLen nIndex;
+ bool bKeepOnlyUserOverridden = false;
+ do
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.CompareTo( "FontCacheDirectory:", 19 ) == COMPARE_EQUAL ||
+ aLine.CompareTo( "EmptyFontCacheDirectory:", 24 ) == COMPARE_EQUAL )
+ {
+ bool bEmpty = (aLine.CompareTo( "Empty", 5 ) == COMPARE_EQUAL);
+ xub_StrLen nSearchIndex = bEmpty ? 24 : 19;
+
+ OString aDir;
+ sal_Int64 nTimestamp = 0;
+ xub_StrLen nTEnd = aLine.Search( ':', nSearchIndex );
+ if( nTEnd != STRING_NOTFOUND )
+ {
+ nTimestamp = aLine.Copy( nSearchIndex, nTEnd - nSearchIndex ).ToInt64();
+ aDir = aLine.Copy( nTEnd+1 );
+ }
+ else
+ {
+ // invalid format, remove
+ pDir = NULL;
+ nDir = 0;
+ m_bDoFlush = true;
+ continue;
+ }
+
+ // is the directory modified ?
+ struct stat aStat;
+ if( stat( aDir.getStr(), &aStat ) ||
+ ! S_ISDIR(aStat.st_mode) )
+ {
+ // remove outdated cache data
+ pDir = NULL;
+ nDir = 0;
+ m_bDoFlush = true;
+ continue;
+ }
+ else
+ {
+ nDir = rManager.getDirectoryAtom( aDir, true );
+ m_aCache[ nDir ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+ m_aCache[ nDir ].m_bNoFiles = bEmpty;
+ pDir = bEmpty ? NULL : &m_aCache[ nDir ].m_aEntries;
+ bKeepOnlyUserOverridden = ((sal_Int64)aStat.st_mtime != nTimestamp);
+ m_aCache[ nDir ].m_bUserOverrideOnly = bKeepOnlyUserOverridden;
+ }
+ }
+ else if( pDir && aLine.CompareTo( "File:", 5 ) == COMPARE_EQUAL )
+ {
+ OString aFile( aLine.Copy( 5 ) );
+ aStream.ReadLine( aLine );
+
+ const char* pLine = aLine.GetBuffer();
+
+ fonttype::type eType = (fonttype::type)atoi( pLine );
+ if( eType != fonttype::TrueType &&
+ eType != fonttype::Type1 &&
+ eType != fonttype::Builtin
+ )
+ continue;
+ while( *pLine && *pLine != ';' )
+ pLine++;
+ if( *pLine != ';' )
+ continue;
+
+ pLine++;
+ sal_Int32 nFonts = atoi( pLine );
+ for( int n = 0; n < nFonts; n++ )
+ {
+ aStream.ReadLine( aLine );
+ pLine = aLine.GetBuffer();
+ int nLen = aLine.Len();
+
+ PrintFontManager::PrintFont* pFont = NULL;
+ switch( eType )
+ {
+ case fonttype::TrueType:
+ pFont = new PrintFontManager::TrueTypeFontFile();
+ break;
+ case fonttype::Type1:
+ pFont = new PrintFontManager::Type1FontFile();
+ break;
+ case fonttype::Builtin:
+ pFont = new PrintFontManager::BuiltinFont();
+ break;
+ default: break;
+ }
+
+ for( nIndex = 0; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
+ ;
+
+ pFont->m_nFamilyName = pAtoms->getAtom( ATOM_FAMILYNAME,
+ OUString( pLine, nIndex, RTL_TEXTENCODING_UTF8 ),
+ sal_True );
+ while( nIndex < nLen )
+ {
+ xub_StrLen nLastIndex = nIndex+1;
+ for( nIndex = nLastIndex ; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
+ ;
+ if( nIndex - nLastIndex > 1 )
+ {
+ OUString aAlias( pLine+nLastIndex, nIndex-nLastIndex-1, RTL_TEXTENCODING_UTF8 );
+ pFont->m_aAliases.push_back( pAtoms->getAtom( ATOM_FAMILYNAME, aAlias, sal_True ) );
+ }
+ }
+ aStream.ReadLine( aLine );
+ pLine = aLine.GetBuffer();
+ nLen = aLine.Len();
+
+ // get up to 20 token positions
+ const int nMaxTokens = 20;
+ int nTokenPos[nMaxTokens];
+ nTokenPos[0] = 0;
+ int nTokens = 1;
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( pLine[i] == ';' )
+ {
+ nTokenPos[nTokens++] = i+1;
+ if( nTokens == nMaxTokens )
+ break;
+ }
+ }
+ if( nTokens < 18 )
+ {
+ delete pFont;
+ continue;
+ }
+ int nCollEntry = atoi( pLine );
+ pFont->m_nPSName = pAtoms->getAtom( ATOM_PSNAME, OUString( pLine + nTokenPos[1], nTokenPos[2]-nTokenPos[1]-1, RTL_TEXTENCODING_UTF8 ), sal_True );
+ pFont->m_eItalic = (italic::type)atoi( pLine+nTokenPos[2] );
+ pFont->m_eWeight = (weight::type)atoi( pLine+nTokenPos[3] );
+ pFont->m_eWidth = (width::type)atoi( pLine+nTokenPos[4] );
+ pFont->m_ePitch = (pitch::type)atoi( pLine+nTokenPos[5] );
+ pFont->m_aEncoding = (rtl_TextEncoding)atoi( pLine+nTokenPos[6] );
+ pFont->m_nAscend = atoi( pLine + nTokenPos[7] );
+ pFont->m_nDescend = atoi( pLine + nTokenPos[8] );
+ pFont->m_nLeading = atoi( pLine + nTokenPos[9] );
+ pFont->m_bHaveVerticalSubstitutedGlyphs
+ = (atoi( pLine + nTokenPos[10] ) != 0);
+ pFont->m_aGlobalMetricX.width
+ = atoi( pLine + nTokenPos[11] );
+ pFont->m_aGlobalMetricX.height
+ = atoi( pLine + nTokenPos[12] );
+ pFont->m_aGlobalMetricY.width
+ = atoi( pLine + nTokenPos[13] );
+ pFont->m_aGlobalMetricY.height
+ = atoi( pLine + nTokenPos[14] );
+ pFont->m_bUserOverride
+ = (atoi( pLine + nTokenPos[15] ) != 0);
+ pFont->m_eEmbeddedbitmap
+ = (fcstatus::type)atoi(pLine+nTokenPos[16]);
+ pFont->m_eAntialias = (fcstatus::type)atoi(pLine+nTokenPos[17]);
+ int nStyleTokenNr = 18;
+ switch( eType )
+ {
+ case fonttype::TrueType:
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nTypeFlags = atoi( pLine + nTokenPos[18] );
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry = nCollEntry;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile = aFile;
+ nStyleTokenNr++;
+ break;
+ case fonttype::Type1:
+ {
+ int nTokLen = (nTokens > 19 ) ? nTokenPos[19]-nTokenPos[18]-1 : nLen - nTokenPos[18];
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aMetricFile = OString( pLine + nTokenPos[18], nTokLen );
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile = aFile;
+ nStyleTokenNr++;
+ }
+ break;
+ case fonttype::Builtin:
+ static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile = aFile;
+ break;
+ default: break;
+ }
+ if( nTokens > nStyleTokenNr )
+ pFont->m_aStyleName = OUString::intern( pLine + nTokenPos[nStyleTokenNr],
+ nLen - nTokenPos[nStyleTokenNr],
+ RTL_TEXTENCODING_UTF8 );
+
+ bool bObsolete = false;
+ if( bKeepOnlyUserOverridden )
+ {
+ if( pFont->m_bUserOverride )
+ {
+ ByteString aFilePath = rManager.getDirectory( nDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString(aFile) );
+ struct stat aStat;
+ if( stat( aFilePath.GetBuffer(), &aStat ) ||
+ ! S_ISREG( aStat.st_mode ) ||
+ aStat.st_size < 16 )
+ {
+ bObsolete = true;
+ }
+ #if OSL_DEBUG_LEVEL > 2
+ else
+ fprintf( stderr, "keeping file %s in outdated cache entry due to user override\n",
+ aFilePath.GetBuffer() );
+ #endif
+ }
+ else
+ bObsolete = true;
+ }
+ if( bObsolete )
+ {
+ m_bDoFlush = true;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "removing obsolete font %s\n", aFile.getStr() );
+#endif
+ delete pFont;
+ continue;
+ }
+
+ FontCacheEntry& rEntry = (*pDir)[aFile].m_aEntry;
+ rEntry.push_back( pFont );
+ }
+ }
+ } while( ! aStream.IsEof() );
+}
+
+/*
+ * FontCache::updateDirTimestamp
+ */
+void FontCache::updateDirTimestamp( int nDirID )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ const OString& rDir = rManager.getDirectory( nDirID );
+
+ struct stat aStat;
+ if( ! stat( rDir.getStr(), &aStat ) )
+ m_aCache[ nDirID ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+}
+
+
+/*
+ * FontCache::copyPrintFont
+ */
+void FontCache::copyPrintFont( const PrintFontManager::PrintFont* pFrom, PrintFontManager::PrintFont* pTo ) const
+{
+ if( pFrom->m_eType != pTo->m_eType )
+ return;
+ switch( pFrom->m_eType )
+ {
+ case fonttype::TrueType:
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_aFontFile;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nCollectionEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nCollectionEntry;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nTypeFlags = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nTypeFlags;
+ break;
+ case fonttype::Type1:
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aFontFile;
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aMetricFile;
+ break;
+ case fonttype::Builtin:
+ static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_aMetricFile;
+ break;
+ default: break;
+ }
+ pTo->m_nFamilyName = pFrom->m_nFamilyName;
+ pTo->m_aStyleName = pFrom->m_aStyleName;
+ pTo->m_aAliases = pFrom->m_aAliases;
+ pTo->m_nPSName = pFrom->m_nPSName;
+ pTo->m_eItalic = pFrom->m_eItalic;
+ pTo->m_eWeight = pFrom->m_eWeight;
+ pTo->m_eWidth = pFrom->m_eWidth;
+ pTo->m_ePitch = pFrom->m_ePitch;
+ pTo->m_aEncoding = pFrom->m_aEncoding;
+ pTo->m_aGlobalMetricX = pFrom->m_aGlobalMetricX;
+ pTo->m_aGlobalMetricY = pFrom->m_aGlobalMetricY;
+ pTo->m_nAscend = pFrom->m_nAscend;
+ pTo->m_nDescend = pFrom->m_nDescend;
+ pTo->m_nLeading = pFrom->m_nLeading;
+ pTo->m_nXMin = pFrom->m_nXMin;
+ pTo->m_nYMin = pFrom->m_nYMin;
+ pTo->m_nXMax = pFrom->m_nXMax;
+ pTo->m_nYMax = pFrom->m_nYMax;
+ pTo->m_bHaveVerticalSubstitutedGlyphs = pFrom->m_bHaveVerticalSubstitutedGlyphs;
+ pTo->m_bUserOverride = pFrom->m_bUserOverride;
+ pTo->m_eEmbeddedbitmap = pFrom->m_eEmbeddedbitmap;
+ pTo->m_eAntialias = pFrom->m_eAntialias;
+}
+
+/*
+ * FontCache::equalsPrintFont
+ */
+bool FontCache::equalsPrintFont( const PrintFontManager::PrintFont* pLeft, PrintFontManager::PrintFont* pRight ) const
+{
+ if( pLeft->m_eType != pRight->m_eType )
+ return false;
+ switch( pLeft->m_eType )
+ {
+ case fonttype::TrueType:
+ {
+ const PrintFontManager::TrueTypeFontFile* pLT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pLeft);
+ const PrintFontManager::TrueTypeFontFile* pRT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aFontFile != pLT->m_aFontFile ||
+ pRT->m_nCollectionEntry != pLT->m_nCollectionEntry ||
+ pRT->m_nTypeFlags != pLT->m_nTypeFlags )
+ return false;
+ }
+ break;
+ case fonttype::Type1:
+ {
+ const PrintFontManager::Type1FontFile* pLT = static_cast<const PrintFontManager::Type1FontFile*>(pLeft);
+ const PrintFontManager::Type1FontFile* pRT = static_cast<const PrintFontManager::Type1FontFile*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aFontFile != pLT->m_aFontFile ||
+ pRT->m_aMetricFile != pLT->m_aMetricFile )
+ return false;
+ }
+ break;
+ case fonttype::Builtin:
+ {
+ const PrintFontManager::BuiltinFont* pLT = static_cast<const PrintFontManager::BuiltinFont*>(pLeft);
+ const PrintFontManager::BuiltinFont* pRT = static_cast<const PrintFontManager::BuiltinFont*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aMetricFile != pLT->m_aMetricFile )
+ return false;
+ }
+ break;
+ default: break;
+ }
+ if( pRight->m_nFamilyName != pLeft->m_nFamilyName ||
+ pRight->m_aStyleName != pLeft->m_aStyleName ||
+ pRight->m_nPSName != pLeft->m_nPSName ||
+ pRight->m_eItalic != pLeft->m_eItalic ||
+ pRight->m_eWeight != pLeft->m_eWeight ||
+ pRight->m_eWidth != pLeft->m_eWidth ||
+ pRight->m_ePitch != pLeft->m_ePitch ||
+ pRight->m_aEncoding != pLeft->m_aEncoding ||
+ pRight->m_aGlobalMetricX != pLeft->m_aGlobalMetricX ||
+ pRight->m_aGlobalMetricY != pLeft->m_aGlobalMetricY ||
+ pRight->m_nAscend != pLeft->m_nAscend ||
+ pRight->m_nDescend != pLeft->m_nDescend ||
+ pRight->m_nLeading != pLeft->m_nLeading ||
+ pRight->m_nXMin != pLeft->m_nXMin ||
+ pRight->m_nYMin != pLeft->m_nYMin ||
+ pRight->m_nXMax != pLeft->m_nXMax ||
+ pRight->m_nYMax != pLeft->m_nYMax ||
+ pRight->m_bHaveVerticalSubstitutedGlyphs != pLeft->m_bHaveVerticalSubstitutedGlyphs ||
+ pRight->m_bUserOverride != pLeft->m_bUserOverride ||
+ pRight->m_eEmbeddedbitmap != pLeft->m_eEmbeddedbitmap ||
+ pRight->m_eAntialias != pLeft->m_eAntialias
+ )
+ return false;
+ std::list< int >::const_iterator lit, rit;
+ for( lit = pLeft->m_aAliases.begin(), rit = pRight->m_aAliases.begin();
+ lit != pLeft->m_aAliases.end() && rit != pRight->m_aAliases.end() && (*lit) == (*rit);
+ ++lit, ++rit )
+ ;
+ return lit == pLeft->m_aAliases.end() && rit == pRight->m_aAliases.end();
+}
+
+/*
+ * FontCache::clonePrintFont
+ */
+PrintFontManager::PrintFont* FontCache::clonePrintFont( const PrintFontManager::PrintFont* pOldFont ) const
+{
+ PrintFontManager::PrintFont* pFont = NULL;
+ switch( pOldFont->m_eType )
+ {
+ case fonttype::TrueType:
+ pFont = new PrintFontManager::TrueTypeFontFile();
+ break;
+ case fonttype::Type1:
+ pFont = new PrintFontManager::Type1FontFile();
+ break;
+ case fonttype::Builtin:
+ pFont = new PrintFontManager::BuiltinFont();
+ break;
+ default: break;
+ }
+ if( pFont )
+ {
+ copyPrintFont( pOldFont, pFont );
+ }
+ return pFont;
+ }
+
+/*
+ * FontCache::getFontCacheFile
+ */
+bool FontCache::getFontCacheFile( int nDirID, const OString& rFile, list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ bool bSuccess = false;
+
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ if( dir != m_aCache.end() )
+ {
+ FontDirMap::const_iterator entry = dir->second.m_aEntries.find( rFile );
+ if( entry != dir->second.m_aEntries.end() )
+ {
+ for( FontCacheEntry::const_iterator font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
+ {
+ bSuccess = true;
+ PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
+ rNewFonts.push_back( pFont );
+ }
+ }
+ }
+ return bSuccess;
+}
+
+/*
+ * FontCache::updateFontCacheEntry
+ */
+void FontCache::updateFontCacheEntry( const PrintFontManager::PrintFont* pFont, bool bFlush )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ OString aFile;
+ int nDirID = 0;
+ switch( pFont->m_eType )
+ {
+ case fonttype::TrueType:
+ nDirID = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile;
+ break;
+ case fonttype::Type1:
+ nDirID = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile;
+ break;
+ case fonttype::Builtin:
+ nDirID = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile;
+ break;
+ default:
+ return;
+ }
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ FontDirMap::const_iterator entry;
+ FontCacheEntry::const_iterator font;
+ PrintFontManager::PrintFont* pCacheFont = NULL;
+
+ if( dir != m_aCache.end() )
+ {
+ entry = dir->second.m_aEntries.find( aFile );
+ if( entry != dir->second.m_aEntries.end() )
+ {
+ for( font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
+ {
+ if( (*font)->m_eType == pFont->m_eType &&
+ ( (*font)->m_eType != fonttype::TrueType ||
+ static_cast<const PrintFontManager::TrueTypeFontFile*>(*font)->m_nCollectionEntry == static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry
+ ) )
+ break;
+ }
+ if( font != entry->second.m_aEntry.end() )
+ pCacheFont = *font;
+ }
+ }
+ else
+ createCacheDir( nDirID );
+
+ if( pCacheFont )
+ {
+ if( ! equalsPrintFont( pFont, pCacheFont ) )
+ {
+ copyPrintFont( pFont, pCacheFont );
+ m_bDoFlush = true;
+ }
+ }
+ else
+ {
+ pCacheFont = clonePrintFont( pFont );
+ m_aCache[nDirID].m_aEntries[aFile].m_aEntry.push_back( pCacheFont );
+
+ ByteString aPath = rManager.getDirectory( nDirID );
+ aPath.Append( '/' );
+ aPath.Append( ByteString( aFile ) );
+ m_bDoFlush = true;
+ }
+ if( bFlush )
+ flush();
+}
+
+/*
+ * FontCache::listDirectory
+ */
+bool FontCache::listDirectory( const OString& rDir, std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ int nDirID = rManager.getDirectoryAtom( rDir );
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ bool bFound = (dir != m_aCache.end());
+
+ if( bFound && !dir->second.m_bNoFiles )
+ {
+ for( FontDirMap::const_iterator file = dir->second.m_aEntries.begin(); file != dir->second.m_aEntries.end(); ++file )
+ {
+ for( FontCacheEntry::const_iterator font = file->second.m_aEntry.begin(); font != file->second.m_aEntry.end(); ++font )
+ {
+ PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
+ rNewFonts.push_back( pFont );
+ }
+ }
+ }
+ return bFound;
+}
+
+/*
+ * FontCache::listDirectory
+ */
+bool FontCache::scanAdditionalFiles( const OString& rDir )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ int nDirID = rManager.getDirectoryAtom( rDir );
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ bool bFound = (dir != m_aCache.end());
+
+ return (bFound && dir->second.m_bUserOverrideOnly);
+}
+
+/*
+ * FontCache::createCacheDir
+ */
+void FontCache::createCacheDir( int nDirID )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ const OString& rDir = rManager.getDirectory( nDirID );
+ struct stat aStat;
+ if( ! stat( rDir.getStr(), &aStat ) )
+ m_aCache[nDirID].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+}
+
+/*
+ * FontCache::markEmptyDir
+ */
+void FontCache::markEmptyDir( int nDirID, bool bNoFiles )
+{
+ createCacheDir( nDirID );
+ m_aCache[nDirID].m_bNoFiles = bNoFiles;
+ m_bDoFlush = true;
+}
diff --git a/vcl/unx/source/fontmanager/fontconfig.cxx b/vcl/unx/source/fontmanager/fontconfig.cxx
new file mode 100644
index 000000000000..c44e082f91bd
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontconfig.cxx
@@ -0,0 +1,1078 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: fontconfig.cxx,v $
+ * $Revision: 1.30.24.2 $
+ *
+ * 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/fontmanager.hxx"
+#include "vcl/fontcache.hxx"
+
+using namespace psp;
+
+#ifdef ENABLE_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include <fontconfig/fcfreetype.h>
+// be compatible with fontconfig 2.2.0 release
+#ifndef FC_WEIGHT_BOOK
+ #define FC_WEIGHT_BOOK 75
+#endif
+#ifndef FC_EMBEDDED_BITMAP
+ #define FC_EMBEDDED_BITMAP "embeddedbitmap"
+#endif
+#ifndef FC_FAMILYLANG
+ #define FC_FAMILYLANG "familylang"
+#endif
+#else
+typedef void FcConfig;
+typedef void FcObjectSet;
+typedef void FcPattern;
+typedef void FcFontSet;
+typedef void FcCharSet;
+typedef int FcResult;
+typedef int FcBool;
+typedef int FcMatchKind;
+typedef char FcChar8;
+typedef int FcChar32;
+typedef unsigned int FT_UInt;
+typedef void* FT_Face;
+typedef int FcSetName;
+#endif
+
+#include <cstdio>
+#include <cstdarg>
+
+#include "unotools/atom.hxx"
+
+#include "osl/module.h"
+#include "osl/thread.h"
+#include "osl/process.h"
+
+#include "rtl/ustrbuf.hxx"
+#include "rtl/locale.hxx"
+
+#include "sal/alloca.h"
+
+#include <utility>
+#include <algorithm>
+
+using namespace osl;
+using namespace rtl;
+
+class FontCfgWrapper
+{
+ oslModule m_pLib;
+ FcFontSet* m_pOutlineSet;
+
+ FcBool (*m_pFcInit)();
+ int (*m_pFcGetVersion)();
+ FcConfig* (*m_pFcConfigGetCurrent)();
+ FcObjectSet* (*m_pFcObjectSetVaBuild)(const char*,va_list);
+ void (*m_pFcObjectSetDestroy)(FcObjectSet* pSet);
+ FcPattern* (*m_pFcPatternCreate)();
+ void (*m_pFcPatternDestroy)(FcPattern*);
+ FcFontSet* (*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*);
+ FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName);
+ FcFontSet* (*m_pFcFontSetCreate)();
+ FcCharSet* (*m_pFcCharSetCreate)();
+ FcBool (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32);
+ FcBool (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32);
+ void (*m_pFcCharSetDestroy)(FcCharSet*);
+ void (*m_pFcFontSetDestroy)(FcFontSet*);
+ FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*);
+ void (*m_pFcPatternReference)(FcPattern*);
+ FcResult (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**);
+ FcResult (*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**);
+ FcResult (*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*);
+ FcResult (*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*);
+ FcResult (*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*);
+ void (*m_pFcDefaultSubstitute)(FcPattern *);
+ FcPattern* (*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*);
+ FcBool (*m_pFcConfigAppFontAddFile)(FcConfig*, const FcChar8*);
+ FcBool (*m_pFcConfigAppFontAddDir)(FcConfig*, const FcChar8*);
+ FcBool (*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind);
+ FcBool (*m_pFcPatternAddInteger)(FcPattern*,const char*,int);
+ FcBool (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool);
+ FcBool (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*);
+ FcBool (*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*);
+ FT_UInt (*m_pFcFreeTypeCharIndex)(FT_Face,FcChar32);
+
+ oslGenericFunction loadSymbol( const char* );
+ void addFontSet( FcSetName );
+
+ FontCfgWrapper();
+ ~FontCfgWrapper();
+
+public:
+ static FontCfgWrapper& get();
+ static void release();
+
+ bool isValid() const
+ { return m_pLib != NULL;}
+
+ FcFontSet* getFontSet();
+
+ FcBool FcInit()
+ { return m_pFcInit(); }
+
+ int FcGetVersion()
+ { return m_pFcGetVersion(); }
+
+ FcConfig* FcConfigGetCurrent()
+ { return m_pFcConfigGetCurrent(); }
+
+ FcObjectSet* FcObjectSetBuild( const char* first, ... )
+ {
+ va_list ap;
+ va_start( ap, first );
+ FcObjectSet* pSet = m_pFcObjectSetVaBuild( first, ap );
+ va_end( ap );
+ return pSet;
+ }
+
+ void FcObjectSetDestroy( FcObjectSet* pSet )
+ { m_pFcObjectSetDestroy( pSet ); }
+
+ FcPattern* FcPatternCreate()
+ { return m_pFcPatternCreate(); }
+
+ void FcPatternDestroy( FcPattern* pPattern )
+ { m_pFcPatternDestroy( pPattern ); }
+
+ FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet )
+ { return m_pFcFontList( pConfig, pPattern, pSet ); }
+
+ FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet)
+ { return m_pFcConfigGetFonts( pConfig, eSet ); }
+
+ FcFontSet* FcFontSetCreate()
+ { return m_pFcFontSetCreate(); }
+
+ FcCharSet* FcCharSetCreate()
+ { return m_pFcCharSetCreate(); }
+
+ FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4)
+ { return m_pFcCharSetAddChar(fcs, ucs4); }
+
+ FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4)
+ { return m_pFcCharSetHasChar(fcs, ucs4); }
+
+ void FcCharSetDestroy( FcCharSet* pSet )
+ { m_pFcCharSetDestroy( pSet );}
+
+ void FcFontSetDestroy( FcFontSet* pSet )
+ { m_pFcFontSetDestroy( pSet );}
+
+ FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern )
+ { return m_pFcFontSetAdd( pSet, pPattern ); }
+
+ void FcPatternReference( FcPattern* pPattern )
+ { m_pFcPatternReference( pPattern ); }
+
+ FcResult FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s )
+ { return m_pFcPatternGetCharSet( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s )
+ { return m_pFcPatternGetString( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetInteger( const FcPattern* pPattern, const char* object, int n, int* s )
+ { return m_pFcPatternGetInteger( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s )
+ { return m_pFcPatternGetDouble( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s )
+ { return m_pFcPatternGetBool( pPattern, object, n, s ); }
+ FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName )
+ { return m_pFcConfigAppFontAddFile( pConfig, pFileName ); }
+ FcBool FcConfigAppFontAddDir(FcConfig* pConfig, const FcChar8* pDirName )
+ { return m_pFcConfigAppFontAddDir( pConfig, pDirName ); }
+ void FcDefaultSubstitute( FcPattern* pPattern )
+ { m_pFcDefaultSubstitute( pPattern ); }
+ FcPattern* FcFontSetMatch( FcConfig* pConfig, FcFontSet **ppFontSet, int nset, FcPattern* pPattern, FcResult* pResult )
+ { return m_pFcFontSetMatch ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; }
+ FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind )
+ { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); }
+ FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue )
+ { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString )
+ { return m_pFcPatternAddString( pPattern, pObject, pString ); }
+ FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue )
+ { return m_pFcPatternAddBool( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet)
+ { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); }
+
+ FT_UInt FcFreeTypeCharIndex( FT_Face face, FcChar32 ucs4 )
+ { return m_pFcFreeTypeCharIndex ? m_pFcFreeTypeCharIndex( face, ucs4 ) : 0; }
+
+public: // TODO: cleanup
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontconfigNameToLocalized;
+};
+
+oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol )
+{
+ OUString aSym( OUString::createFromAscii( pSymbol ) );
+ oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
+#endif
+ return pSym;
+}
+
+FontCfgWrapper::FontCfgWrapper()
+ : m_pLib( NULL ),
+ m_pOutlineSet( NULL )
+{
+ OUString aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( !m_pLib )
+ {
+ aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so" ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ }
+
+ if( ! m_pLib )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "no libfontconfig\n" );
+#endif
+ return;
+ }
+
+ m_pFcInit = (FcBool(*)())
+ loadSymbol( "FcInit" );
+ m_pFcGetVersion = (int(*)())
+ loadSymbol( "FcGetVersion" );
+ m_pFcConfigGetCurrent = (FcConfig *(*)())
+ loadSymbol( "FcConfigGetCurrent" );
+ m_pFcObjectSetVaBuild = (FcObjectSet*(*)(const char*,va_list))
+ loadSymbol( "FcObjectSetVaBuild" );
+ m_pFcObjectSetDestroy = (void(*)(FcObjectSet*))
+ loadSymbol( "FcObjectSetDestroy" );
+ m_pFcPatternCreate = (FcPattern*(*)())
+ loadSymbol( "FcPatternCreate" );
+ m_pFcPatternDestroy = (void(*)(FcPattern*))
+ loadSymbol( "FcPatternDestroy" );
+ m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*))
+ loadSymbol( "FcFontList" );
+ m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName))
+ loadSymbol( "FcConfigGetFonts" );
+ m_pFcFontSetCreate = (FcFontSet*(*)())
+ loadSymbol( "FcFontSetCreate" );
+ m_pFcCharSetCreate = (FcCharSet*(*)())
+ loadSymbol( "FcCharSetCreate" );
+ m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32))
+ loadSymbol( "FcCharSetAddChar" );
+ m_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32))
+ loadSymbol( "FcCharSetHasChar" );
+ m_pFcCharSetDestroy = (void(*)(FcCharSet*))
+ loadSymbol( "FcCharSetDestroy" );
+ m_pFcFontSetDestroy = (void(*)(FcFontSet*))
+ loadSymbol( "FcFontSetDestroy" );
+ m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*))
+ loadSymbol( "FcFontSetAdd" );
+ m_pFcPatternReference = (void(*)(FcPattern*))
+ loadSymbol( "FcPatternReference" );
+ m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**))
+ loadSymbol( "FcPatternGetCharSet" );
+ m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**))
+ loadSymbol( "FcPatternGetString" );
+ m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*))
+ loadSymbol( "FcPatternGetInteger" );
+ m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*))
+ loadSymbol( "FcPatternGetDouble" );
+ m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*))
+ loadSymbol( "FcPatternGetBool" );
+ m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*))
+ loadSymbol( "FcConfigAppFontAddFile" );
+ m_pFcConfigAppFontAddDir = (FcBool(*)(FcConfig*, const FcChar8*))
+ loadSymbol( "FcConfigAppFontAddDir" );
+ m_pFcDefaultSubstitute = (void(*)(FcPattern *))
+ loadSymbol( "FcDefaultSubstitute" );
+ m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**,int,FcPattern*,FcResult*))
+ loadSymbol( "FcFontSetMatch" );
+ m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind))
+ loadSymbol( "FcConfigSubstitute" );
+ m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int))
+ loadSymbol( "FcPatternAddInteger" );
+ m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool))
+ loadSymbol( "FcPatternAddBool" );
+ m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *))
+ loadSymbol( "FcPatternAddCharSet" );
+ m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*))
+ loadSymbol( "FcPatternAddString" );
+ m_pFcFreeTypeCharIndex = (FT_UInt(*)(FT_Face,FcChar32))
+ loadSymbol( "FcFreeTypeCharIndex" );
+
+ if( ! (
+ m_pFcInit &&
+ m_pFcGetVersion &&
+ m_pFcConfigGetCurrent &&
+ m_pFcObjectSetVaBuild &&
+ m_pFcObjectSetDestroy &&
+ m_pFcPatternCreate &&
+ m_pFcPatternDestroy &&
+ m_pFcFontList &&
+ m_pFcConfigGetFonts &&
+ m_pFcFontSetCreate &&
+ m_pFcCharSetCreate &&
+ m_pFcCharSetAddChar &&
+ m_pFcCharSetHasChar &&
+ m_pFcCharSetDestroy &&
+ m_pFcFontSetDestroy &&
+ m_pFcFontSetAdd &&
+ m_pFcPatternReference &&
+ m_pFcPatternGetCharSet &&
+ m_pFcPatternGetString &&
+ m_pFcPatternGetInteger &&
+ m_pFcPatternGetDouble &&
+ m_pFcPatternGetBool &&
+ m_pFcConfigAppFontAddFile &&
+ m_pFcConfigAppFontAddDir &&
+ m_pFcDefaultSubstitute &&
+ m_pFcConfigSubstitute &&
+ m_pFcPatternAddInteger &&
+ m_pFcPatternAddCharSet &&
+ m_pFcPatternAddBool &&
+ m_pFcPatternAddString
+ ) )
+ {
+ osl_unloadModule( (oslModule)m_pLib );
+ m_pLib = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not all needed symbols were found in libfontconfig\n" );
+#endif
+ return;
+ }
+
+
+ FcInit();
+ if( ! FcConfigGetCurrent() )
+ {
+ osl_unloadModule( (oslModule)m_pLib );
+ m_pLib = NULL;
+ }
+}
+
+void FontCfgWrapper::addFontSet( FcSetName eSetName )
+{
+ #ifdef ENABLE_FONTCONFIG
+ /*
+ add only acceptable outlined fonts to our config,
+ for future fontconfig use
+ */
+ FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
+ if( !pOrig )
+ return;
+
+ for( int i = 0; i < pOrig->nfont; ++i )
+ {
+ FcBool outline = false;
+ FcPattern *pOutlinePattern = pOrig->fonts[i];
+ FcResult eOutRes =
+ FcPatternGetBool( pOutlinePattern, FC_OUTLINE, 0, &outline );
+ if( (eOutRes != FcResultMatch) || (outline != FcTrue) )
+ continue;
+ FcPatternReference(pOutlinePattern);
+ FcFontSetAdd(m_pOutlineSet, pOutlinePattern);
+ }
+ // TODO: FcFontSetDestroy( pOrig );
+ #else
+ (void)eSetName; // prevent compiler warning about unused parameter
+ #endif
+}
+
+FcFontSet* FontCfgWrapper::getFontSet()
+{
+ #ifdef ENABLE_FONTCONFIG
+ if( !m_pOutlineSet )
+ {
+ m_pOutlineSet = FcFontSetCreate();
+ addFontSet( FcSetSystem );
+ const int nVersion = FcGetVersion();
+ if( nVersion > 20400 )
+ addFontSet( FcSetApplication );
+ }
+ #endif
+
+ return m_pOutlineSet;
+}
+
+FontCfgWrapper::~FontCfgWrapper()
+{
+ if( m_pOutlineSet )
+ FcFontSetDestroy( m_pOutlineSet );
+ if( m_pLib )
+ osl_unloadModule( (oslModule)m_pLib );
+}
+
+static FontCfgWrapper* pOneInstance = NULL;
+
+FontCfgWrapper& FontCfgWrapper::get()
+{
+ if( ! pOneInstance )
+ pOneInstance = new FontCfgWrapper();
+ return *pOneInstance;
+}
+
+void FontCfgWrapper::release()
+{
+ if( pOneInstance )
+ {
+ delete pOneInstance;
+ pOneInstance = NULL;
+ }
+}
+
+#ifdef ENABLE_FONTCONFIG
+namespace
+{
+ typedef std::pair<FcChar8*, FcChar8*> lang_and_family;
+
+ class localizedsorter
+ {
+ rtl::OLocale maLoc;
+ public:
+ localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
+ FcChar8* bestname(const std::vector<lang_and_family> &families);
+ };
+
+ FcChar8* localizedsorter::bestname(const std::vector<lang_and_family> &families)
+ {
+ FcChar8* candidate = families.begin()->second;
+ rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
+ rtl::OString sFullMatch = sLangMatch;
+ sFullMatch += OString('-');
+ sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
+
+ std::vector<lang_and_family>::const_iterator aEnd = families.end();
+ bool alreadyclosematch = false;
+ for (std::vector<lang_and_family>::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter)
+ {
+ const char *pLang = (const char*)aIter->first;
+ //perfect
+ if( rtl_str_compare(pLang,sFullMatch.getStr() ) == 0)
+ {
+ candidate = aIter->second;
+ break;
+ }
+ else if( (rtl_str_compare(pLang,sLangMatch.getStr()) == 0) && (!alreadyclosematch))
+ {
+ candidate = aIter->second;
+ alreadyclosematch = true;
+ }
+ }
+
+ return candidate;
+ }
+
+
+ FcResult lcl_FamilyFromPattern(FontCfgWrapper& rWrapper, FcPattern* pPattern, FcChar8 **family,
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > &aFontconfigNameToLocalized)
+ {
+ FcChar8 *origfamily;
+ FcResult eFamilyRes = rWrapper.FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily );
+ *family = origfamily;
+
+ if( eFamilyRes == FcResultMatch)
+ {
+ FcChar8* familylang = NULL;
+ if (rWrapper.FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch)
+ {
+ std::vector< lang_and_family > lang_and_families;
+ lang_and_families.push_back(lang_and_family(familylang, *family));
+ int k = 1;
+ while (1)
+ {
+ if (rWrapper.FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch)
+ break;
+ if (rWrapper.FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch)
+ break;
+ lang_and_families.push_back(lang_and_family(familylang, *family));
+ ++k;
+ }
+
+ //possible to-do, sort by UILocale instead of process locale
+ rtl_Locale* pLoc;
+ osl_getProcessLocale(&pLoc);
+ localizedsorter aSorter(pLoc);
+ *family = aSorter.bestname(lang_and_families);
+
+ std::vector<lang_and_family>::const_iterator aEnd = lang_and_families.end();
+ for (std::vector<lang_and_family>::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter)
+ {
+ const char *candidate = (const char*)(aIter->second);
+ if (rtl_str_compare(candidate, (const char*)(*family)) != 0)
+ aFontconfigNameToLocalized[OString(candidate)] = OString((const char*)(*family));
+ }
+ }
+ }
+
+ return eFamilyRes;
+ }
+}
+
+
+/*
+ * PrintFontManager::initFontconfig
+ */
+bool PrintFontManager::initFontconfig()
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+ return true;
+}
+
+int PrintFontManager::countFontconfigFonts()
+{
+ int nFonts = 0;
+
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( !rWrapper.isValid() )
+ return 0;
+
+ FcFontSet* pFSet = rWrapper.getFontSet();
+ if( pFSet )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
+#endif
+ for( int i = 0; i < pFSet->nfont; i++ )
+ {
+ FcChar8* file = NULL;
+ FcChar8* family = NULL;
+ FcChar8* style = NULL;
+ int slant = 0;
+ int weight = 0;
+ int spacing = 0;
+ int nCollectionEntry = -1;
+ FcBool outline = false, embitmap = true, antialias = true;
+
+ FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file );
+ FcResult eFamilyRes = lcl_FamilyFromPattern(rWrapper, pFSet->fonts[i], &family, rWrapper.m_aFontconfigNameToLocalized );
+ FcResult eStyleRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style );
+ FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant );
+ FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight );
+ FcResult eSpacRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing );
+ FcResult eOutRes = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline );
+ FcResult eIndexRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry );
+ FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_EMBEDDED_BITMAP, 0, &embitmap );
+ FcResult eAntialias = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_ANTIALIAS, 0, &antialias );
+
+ if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
+ continue;
+
+#if (OSL_DEBUG_LEVEL > 2)
+ fprintf( stderr, "found font \"%s\" in file %s\n"
+ " weight = %d, slant = %d, style = \"%s\"\n"
+ " spacing = %d, outline = %d\n"
+ , family, file
+ , eWeightRes == FcResultMatch ? weight : -1
+ , eSpacRes == FcResultMatch ? slant : -1
+ , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
+ , eSpacRes == FcResultMatch ? spacing : -1
+ , eOutRes == FcResultMatch ? outline : -1
+ );
+#endif
+
+ OSL_ASSERT(eOutRes != FcResultMatch || outline);
+
+ // only outline fonts are usable to psprint anyway
+ if( eOutRes == FcResultMatch && ! outline )
+ continue;
+
+ // see if this font is already cached
+ // update attributes
+ std::list< PrintFont* > aFonts;
+ OString aDir, aBase, aOrgPath( (sal_Char*)file );
+ splitPath( aOrgPath, aDir, aBase );
+ int nDirID = getDirectoryAtom( aDir, true );
+ if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "file %s not cached\n", aBase.getStr() );
+#endif
+ // not known, analyze font file to get attributes
+ // not described by fontconfig (e.g. alias names, PSName)
+ std::list< OString > aDummy;
+ analyzeFontFile( nDirID, aBase, aDummy, aFonts );
+#if OSL_DEBUG_LEVEL > 1
+ if( aFonts.empty() )
+ fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
+#endif
+ }
+ if( aFonts.empty() )
+ continue;
+
+ int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
+ PrintFont* pUpdate = aFonts.front();
+ std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
+ ++second_font;
+ if( second_font != aFonts.end() ) // more than one font
+ {
+ // a collection entry, get the correct index
+ if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
+ {
+ for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( (*it)->m_eType == fonttype::TrueType &&
+ static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
+ {
+ pUpdate = *it;
+ break;
+ }
+ }
+ // update collection entry
+ // additional entries will be created in the cache
+ // if this is a new index (that is if the loop above
+ // ran to the end of the list)
+ if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
+ static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "multiple fonts for file, but no index in fontconfig pattern ! (index res = %d collection entry = %d\nfile will not be used\n", eIndexRes, nCollectionEntry );
+#endif
+ // we have found more than one font in this file
+ // but fontconfig will not tell us which index is meant
+ // -> something is in disorder, do not use this font
+ pUpdate = NULL;
+ }
+ }
+
+ if( pUpdate )
+ {
+ // set family name
+ if( pUpdate->m_nFamilyName != nFamilyName )
+ {
+ pUpdate->m_aAliases.remove( pUpdate->m_nFamilyName );
+ pUpdate->m_aAliases.push_back( pUpdate->m_nFamilyName );
+ pUpdate->m_aAliases.remove( nFamilyName );
+ pUpdate->m_nFamilyName = nFamilyName;
+ }
+ if( eWeightRes == FcResultMatch )
+ {
+ // set weight
+ if( weight <= FC_WEIGHT_THIN )
+ pUpdate->m_eWeight = weight::Thin;
+ else if( weight <= FC_WEIGHT_ULTRALIGHT )
+ pUpdate->m_eWeight = weight::UltraLight;
+ else if( weight <= FC_WEIGHT_LIGHT )
+ pUpdate->m_eWeight = weight::Light;
+ else if( weight <= FC_WEIGHT_BOOK )
+ pUpdate->m_eWeight = weight::SemiLight;
+ else if( weight <= FC_WEIGHT_NORMAL )
+ pUpdate->m_eWeight = weight::Normal;
+ else if( weight <= FC_WEIGHT_MEDIUM )
+ pUpdate->m_eWeight = weight::Medium;
+ else if( weight <= FC_WEIGHT_SEMIBOLD )
+ pUpdate->m_eWeight = weight::SemiBold;
+ else if( weight <= FC_WEIGHT_BOLD )
+ pUpdate->m_eWeight = weight::Bold;
+ else if( weight <= FC_WEIGHT_ULTRABOLD )
+ pUpdate->m_eWeight = weight::UltraBold;
+ else
+ pUpdate->m_eWeight = weight::Black;
+ }
+ if( eSpacRes == FcResultMatch )
+ {
+ // set pitch
+ if( spacing == FC_PROPORTIONAL )
+ pUpdate->m_ePitch = pitch::Variable;
+ else if( spacing == FC_MONO || spacing == FC_CHARCELL )
+ pUpdate->m_ePitch = pitch::Fixed;
+ }
+ if( eSlantRes == FcResultMatch )
+ {
+ // set italic
+ if( slant == FC_SLANT_ROMAN )
+ pUpdate->m_eItalic = italic::Upright;
+ else if( slant == FC_SLANT_ITALIC )
+ pUpdate->m_eItalic = italic::Italic;
+ else if( slant == FC_SLANT_OBLIQUE )
+ pUpdate->m_eItalic = italic::Oblique;
+ }
+ if( eStyleRes == FcResultMatch )
+ {
+ pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
+ }
+ if( eEmbeddedBitmap == FcResultMatch )
+ {
+ pUpdate->m_eEmbeddedbitmap = embitmap ? fcstatus::istrue : fcstatus::isfalse;
+ }
+ if( eAntialias == FcResultMatch )
+ {
+ pUpdate->m_eAntialias = antialias ? fcstatus::istrue : fcstatus::isfalse;
+ }
+
+
+ // update font cache
+ m_pFontCache->updateFontCacheEntry( pUpdate, false );
+ // sort into known fonts
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = pUpdate;
+ m_aFontFileToFontID[ aBase ].insert( aFont );
+ nFonts++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
+#endif
+ }
+ // clean up the fonts we did not put into the list
+ for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( *it != pUpdate )
+ {
+ m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
+ delete *it;
+ }
+ }
+ }
+ }
+
+ // how does one get rid of the config ?
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
+#endif
+ return nFonts;
+}
+
+void PrintFontManager::deinitFontconfig()
+{
+ FontCfgWrapper::release();
+}
+
+int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0;
+}
+
+bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ // workaround for a stability problems in older FC versions
+ // when handling application specifc fonts
+ const int nVersion = rWrapper.FcGetVersion();
+ if( nVersion <= 20400 )
+ return false;
+ const char* pDirName = (const char*)rDirName.getStr();
+ bool bRet = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bRet );
+#endif
+
+ return bRet;
+}
+
+static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern,
+ italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch)
+{
+ if( eItalic != italic::Unknown )
+ {
+ int nSlant = FC_SLANT_ROMAN;
+ switch( eItalic )
+ {
+ case italic::Italic: nSlant = FC_SLANT_ITALIC;break;
+ case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant );
+ }
+ if( eWeight != weight::Unknown )
+ {
+ int nWeight = FC_WEIGHT_NORMAL;
+ switch( eWeight )
+ {
+ case weight::Thin: nWeight = FC_WEIGHT_THIN;break;
+ case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break;
+ case weight::Light: nWeight = FC_WEIGHT_LIGHT;break;
+ case weight::SemiLight: nWeight = FC_WEIGHT_BOOK;break;
+ case weight::Normal: nWeight = FC_WEIGHT_NORMAL;break;
+ case weight::Medium: nWeight = FC_WEIGHT_MEDIUM;break;
+ case weight::SemiBold: nWeight = FC_WEIGHT_SEMIBOLD;break;
+ case weight::Bold: nWeight = FC_WEIGHT_BOLD;break;
+ case weight::UltraBold: nWeight = FC_WEIGHT_ULTRABOLD;break;
+ case weight::Black: nWeight = FC_WEIGHT_BLACK;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight );
+ }
+ if( eWidth != width::Unknown )
+ {
+ int nWidth = FC_WIDTH_NORMAL;
+ switch( eWidth )
+ {
+ case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break;
+ case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break;
+ case width::Condensed: nWidth = FC_WIDTH_CONDENSED;break;
+ case width::SemiCondensed: nWidth = FC_WIDTH_SEMICONDENSED;break;
+ case width::Normal: nWidth = FC_WIDTH_NORMAL;break;
+ case width::SemiExpanded: nWidth = FC_WIDTH_SEMIEXPANDED;break;
+ case width::Expanded: nWidth = FC_WIDTH_EXPANDED;break;
+ case width::ExtraExpanded: nWidth = FC_WIDTH_EXTRAEXPANDED;break;
+ case width::UltraExpanded: nWidth = FC_WIDTH_ULTRACONDENSED;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth );
+ }
+ if( ePitch != pitch::Unknown )
+ {
+ int nSpacing = FC_PROPORTIONAL;
+ switch( ePitch )
+ {
+ case pitch::Fixed: nSpacing = FC_MONO;break;
+ case pitch::Variable: nSpacing = FC_PROPORTIONAL;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing );
+ if (nSpacing == FC_MONO)
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace");
+ }
+}
+
+rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
+ rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
+ italic::type eItalic, weight::type eWeight,
+ width::type eWidth, pitch::type ePitch) const
+{
+ rtl::OUString aName;
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return aName;
+
+ // build pattern argument for fontconfig query
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ // Prefer scalable fonts
+ rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue );
+
+ const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 );
+ const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 );
+
+ const FcChar8* pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr();
+ if( rLangAttrib.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 );
+
+ // Add required Unicode characters, if any
+ if ( rMissingCodes.getLength() )
+ {
+ FcCharSet *unicodes = rWrapper.FcCharSetCreate();
+ for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ // also handle unicode surrogates
+ const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
+ rWrapper.FcCharSetAddChar( unicodes, nCode );
+ }
+ rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes);
+ rWrapper.FcCharSetDestroy( unicodes );
+ }
+
+ addtopattern(rWrapper, pPattern, eItalic, eWeight, eWidth, ePitch);
+
+ // query fontconfig for a substitute
+ rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern );
+ rWrapper.FcDefaultSubstitute( pPattern );
+
+ // process the result of the fontconfig query
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet* pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult );
+ rWrapper.FcPatternDestroy( pPattern );
+
+ FcFontSet* pSet = NULL;
+ if( pResult )
+ {
+ pSet = rWrapper.FcFontSetCreate();
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ }
+
+ if( pSet )
+ {
+ if( pSet->nfont > 0 )
+ {
+ //extract the closest match
+ FcChar8* family = NULL;
+ FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
+
+ // get the family name
+ if( eFileRes == FcResultMatch )
+ {
+ OString sFamily((sal_Char*)family);
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontconfigNameToLocalized.find(sFamily);
+ if (aI != rWrapper.m_aFontconfigNameToLocalized.end())
+ sFamily = aI->second;
+ aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
+ }
+
+ // update rMissingCodes by removing resolved unicodes
+ if( rMissingCodes.getLength() > 0 )
+ {
+ sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
+ int nRemainingLen = 0;
+ FcCharSet* unicodes;
+ if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) )
+ {
+ for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ // also handle unicode surrogates
+ const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
+ if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue )
+ pRemainingCodes[ nRemainingLen++ ] = nCode;
+ }
+ }
+ rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
+ }
+ }
+
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ return aName;
+}
+
+bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ OString aLangAttrib;
+ // populate pattern with font characteristics
+ if( rLocale.Language.getLength() )
+ {
+ OUStringBuffer aLang(6);
+ aLang.append( rLocale.Language );
+ if( rLocale.Country.getLength() )
+ {
+ aLang.append( sal_Unicode('-') );
+ aLang.append( rLocale.Country );
+ }
+ aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
+ }
+ if( aLangAttrib.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() );
+
+ OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
+ if( aFamily.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() );
+
+ addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
+
+ rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
+ rWrapper.FcDefaultSubstitute( pPattern );
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet *pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
+ bool bSuccess = false;
+ if( pResult )
+ {
+ FcFontSet* pSet = rWrapper.FcFontSetCreate();
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ if( pSet->nfont > 0 )
+ {
+ //extract the closest match
+ FcChar8* file = NULL;
+ FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file );
+ if( eFileRes == FcResultMatch )
+ {
+ OString aDir, aBase, aOrgPath( (sal_Char*)file );
+ splitPath( aOrgPath, aDir, aBase );
+ int nDirID = getDirectoryAtom( aDir, true );
+ fontID aFont = findFontFileID( nDirID, aBase );
+ if( aFont > 0 )
+ bSuccess = getFontFastInfo( aFont, rInfo );
+ }
+ }
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ // cleanup
+ rWrapper.FcPatternDestroy( pPattern );
+
+ return bSuccess;
+}
+
+#else // ENABLE_FONTCONFIG not defined
+
+bool PrintFontManager::initFontconfig()
+{
+ return false;
+}
+
+int PrintFontManager::countFontconfigFonts()
+{
+ return 0;
+}
+
+void PrintFontManager::deinitFontconfig()
+{}
+
+bool PrintFontManager::addFontconfigDir( const rtl::OString& )
+{
+ return false;
+}
+
+bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& )
+{
+ return false;
+}
+
+int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 )
+{
+ return 0;
+}
+
+rtl::OUString PrintFontManager::Substitute( const rtl::OUString&,
+ rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const
+{
+ rtl::OUString aName;
+ return aName;
+}
+
+#endif // ENABLE_FONTCONFIG
+
diff --git a/vcl/unx/source/fontmanager/fontmanager.cxx b/vcl/unx/source/fontmanager/fontmanager.cxx
new file mode 100644
index 000000000000..73e117550a14
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontmanager.cxx
@@ -0,0 +1,4008 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: fontmanager.cxx,v $
+ * $Revision: 1.81.22.2 $
+ *
+ * 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/stat.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <osl/thread.h>
+
+#include "unotools/atom.hxx"
+
+#include "vcl/fontmanager.hxx"
+#include "vcl/fontcache.hxx"
+#include "vcl/helper.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/ppdparser.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/salinst.hxx"
+
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/debug.hxx"
+#include "tools/config.hxx"
+
+#include "osl/file.hxx"
+#include "osl/process.h"
+
+#include "rtl/tencinfo.h"
+#include "rtl/ustrbuf.hxx"
+#include "rtl/strbuf.hxx"
+
+#include "i18npool/mslangid.hxx"
+
+
+#include "parseAFM.hxx"
+#define NO_LIST
+#include "sft.h"
+#undef NO_LIST
+
+#if OSL_DEBUG_LEVEL > 1
+#include <sys/times.h>
+#include <stdio.h>
+#endif
+
+#include "sal/alloca.h"
+
+#include <set>
+#include <hash_set>
+#include <algorithm>
+
+#include "adobeenc.tab" // get encoding table for AFM metrics
+
+#ifdef CALLGRIND_COMPILE
+#include <valgrind/callgrind.h>
+#endif
+
+#include "comphelper/processfactory.hxx"
+#include "com/sun/star/beans/XMaterialHolder.hpp"
+#include "com/sun/star/beans/NamedValue.hpp"
+
+#define PRINTER_METRICDIR "fontmetric"
+
+using namespace utl;
+using namespace psp;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+
+/*
+ * static helpers
+ */
+
+inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
+ (((sal_uInt16)pBuffer[0]) << 8);
+ pBuffer+=2;
+ return nRet;
+}
+
+inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
+ (((sal_uInt32)pBuffer[1]) << 16) |
+ (((sal_uInt32)pBuffer[2]) << 8) |
+ (((sal_uInt32)pBuffer[3]) );
+ pBuffer += 4;
+ return nRet;
+}
+
+static italic::type parseItalic( const ByteString& rItalic )
+{
+ italic::type eItalic = italic::Unknown;
+ if( rItalic.EqualsIgnoreCaseAscii( "i" ) )
+ eItalic = italic::Italic;
+ else if( rItalic.EqualsIgnoreCaseAscii( "o" ) )
+ eItalic = italic::Oblique;
+ else
+ eItalic = italic::Upright;
+ return eItalic;
+}
+
+// -------------------------------------------------------------------------
+
+static weight::type parseWeight( const ByteString& rWeight )
+{
+ weight::type eWeight = weight::Unknown;
+ if( rWeight.Search( "bold" ) != STRING_NOTFOUND )
+ {
+ if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
+ eWeight = weight::SemiBold;
+ else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
+ eWeight = weight::UltraBold;
+ else
+ eWeight = weight::Bold;
+ }
+ else if( rWeight.Search( "heavy" ) != STRING_NOTFOUND )
+ eWeight = weight::Bold;
+ else if( rWeight.Search( "light" ) != STRING_NOTFOUND )
+ {
+ if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
+ eWeight = weight::SemiLight;
+ else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
+ eWeight = weight::UltraLight;
+ else
+ eWeight = weight::Light;
+ }
+ else if( rWeight.Search( "black" ) != STRING_NOTFOUND )
+ eWeight = weight::Black;
+ else if( rWeight.Equals( "demi" ) )
+ eWeight = weight::SemiBold;
+ else if( rWeight.Equals( "book" ) ||
+ rWeight.Equals( "semicondensed" ) )
+ eWeight = weight::Light;
+ else if( rWeight.Equals( "medium" ) || rWeight.Equals( "roman" ) )
+ eWeight = weight::Medium;
+ else
+ eWeight = weight::Normal;
+ return eWeight;
+}
+
+// -------------------------------------------------------------------------
+
+static width::type parseWidth( const ByteString& rWidth )
+{
+ width::type eWidth = width::Unknown;
+ if( rWidth.Equals( "bold" ) ||
+ rWidth.Equals( "semiexpanded" ) )
+ eWidth = width::SemiExpanded;
+ else if( rWidth.Equals( "condensed" ) ||
+ rWidth.Equals( "narrow" ) )
+ eWidth = width::Condensed;
+ else if( rWidth.Equals( "double wide" ) ||
+ rWidth.Equals( "extraexpanded" ) ||
+ rWidth.Equals( "ultraexpanded" ) )
+ eWidth = width::UltraExpanded;
+ else if( rWidth.Equals( "expanded" ) ||
+ rWidth.Equals( "wide" ) )
+ eWidth = width::Expanded;
+ else if( rWidth.Equals( "extracondensed" ) )
+ eWidth = width::ExtraCondensed;
+ else if( rWidth.Equals( "semicondensed" ) )
+ eWidth = width::SemiCondensed;
+ else if( rWidth.Equals( "ultracondensed" ) )
+ eWidth = width::UltraCondensed;
+ else
+ eWidth = width::Normal;
+
+ return eWidth;
+}
+
+// -------------------------------------------------------------------------
+bool PrintFontManager::XLFDEntry::operator<(const PrintFontManager::XLFDEntry& rRight) const
+{
+ sal_Int32 nCmp = 0;
+ if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
+ aFamily.pData->length,
+ rRight.aFamily.pData->buffer,
+ rRight.aFamily.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
+ aFoundry.pData->length,
+ rRight.aFoundry.pData->buffer,
+ rRight.aFoundry.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
+ {
+ if( eItalic != rRight.eItalic )
+ return (int)eItalic < (int)rRight.eItalic;
+ }
+
+ if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
+ {
+ if( eWeight != rRight.eWeight )
+ return (int)eWeight < (int)rRight.eWeight;
+ }
+
+ if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
+ {
+ if( eWidth != rRight.eWidth )
+ return (int)eWidth < (int)rRight.eWidth;
+ }
+
+ if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
+ {
+ if( ePitch != rRight.ePitch )
+ return (int)ePitch < (int)rRight.ePitch;
+ }
+
+ if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
+ aAddStyle.pData->length,
+ rRight.aAddStyle.pData->buffer,
+ rRight.aAddStyle.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
+ {
+ if( aEncoding != rRight.aEncoding )
+ return aEncoding < rRight.aEncoding;
+ }
+
+ return false;
+}
+
+bool PrintFontManager::XLFDEntry::operator==(const PrintFontManager::XLFDEntry& rRight) const
+{
+ sal_Int32 nCmp = 0;
+ if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
+ aFamily.pData->length,
+ rRight.aFamily.pData->buffer,
+ rRight.aFamily.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
+ aFoundry.pData->length,
+ rRight.aFoundry.pData->buffer,
+ rRight.aFoundry.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
+ {
+ if( eItalic != rRight.eItalic )
+ return false;
+ }
+
+ if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
+ {
+ if( eWeight != rRight.eWeight )
+ return false;
+ }
+
+ if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
+ {
+ if( eWidth != rRight.eWidth )
+ return false;
+ }
+
+ if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
+ {
+ if( ePitch != rRight.ePitch )
+ return false;
+ }
+
+ if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
+ aAddStyle.pData->length,
+ rRight.aAddStyle.pData->buffer,
+ rRight.aAddStyle.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
+ {
+ if( aEncoding != rRight.aEncoding )
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * PrintFont implementations
+ */
+PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
+ m_eType( eType ),
+ m_nFamilyName( 0 ),
+ m_nPSName( 0 ),
+ m_eItalic( italic::Unknown ),
+ m_eWidth( width::Unknown ),
+ m_eWeight( weight::Unknown ),
+ m_ePitch( pitch::Unknown ),
+ m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
+ m_bFontEncodingOnly( false ),
+ m_pMetrics( NULL ),
+ m_nAscend( 0 ),
+ m_nDescend( 0 ),
+ m_nLeading( 0 ),
+ m_nXMin( 0 ),
+ m_nYMin( 0 ),
+ m_nXMax( 0 ),
+ m_nYMax( 0 ),
+ m_bHaveVerticalSubstitutedGlyphs( false ),
+ m_bUserOverride( false ),
+ m_eEmbeddedbitmap( fcstatus::isunset ),
+ m_eAntialias( fcstatus::isunset )
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::PrintFont::~PrintFont()
+{
+ if( m_pMetrics )
+ delete m_pMetrics;
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::Type1FontFile::~Type1FontFile()
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::BuiltinFont::~BuiltinFont()
+{
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
+{
+ return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
+{
+ return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
+{
+ bool bSuccess = false;
+
+ ByteString aFile( PrintFontManager::get().getFontFile( this ) );
+
+ TrueTypeFont* pTTFont = NULL;
+
+ if( OpenTTFontFile( aFile.GetBuffer(), m_nCollectionEntry < 0 ? 0 : m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ if( ! m_pMetrics )
+ {
+ m_pMetrics = new PrintFontMetrics;
+ memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
+ }
+ m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
+ int i;
+ sal_uInt16 table[256], table_vert[256];
+
+ for( i = 0; i < 256; i++ )
+ table[ i ] = 256*nPage + i;
+
+ int nCharacters = nPage < 255 ? 256 : 254;
+ MapString( pTTFont, table, nCharacters, NULL, 0 );
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nCharacters; i++ )
+ {
+ if( table[i] )
+ {
+ CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
+ rChar.width = pMetrics[ i ].adv;
+ rChar.height = m_aGlobalMetricX.height;
+ }
+ }
+
+ free( pMetrics );
+ }
+
+ for( i = 0; i < 256; i++ )
+ table_vert[ i ] = 256*nPage + i;
+ MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
+ pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nCharacters; i++ )
+ {
+ if( table_vert[i] )
+ {
+ CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
+ rChar.width = m_aGlobalMetricY.width;
+ rChar.height = pMetrics[ i ].adv;
+ if( table_vert[i] != table[i] )
+ m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
+ }
+ }
+ free( pMetrics );
+ }
+
+ if( ! m_pMetrics->m_bKernPairsQueried )
+ {
+ m_pMetrics->m_bKernPairsQueried = true;
+ // this is really a hack
+ // in future MapString/KernGlyphs should be used
+ // but vcl is not in a state where that could be used
+ // so currently we get kernpairs by accessing the raw data
+ struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
+
+ //-----------------------------------------------------------------
+ // Kerning: KT_MICROSOFT
+ //-----------------------------------------------------------------
+ if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
+ {
+ // create a glyph -> character mapping
+ ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
+ ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
+ for( i = 21; i < 0xfffd; i++ )
+ {
+ sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
+ if( nGlyph != 0 )
+ aGlyphMap[ nGlyph ] = (sal_Unicode)i;
+ }
+
+
+ KernPair aPair;
+ for( i = 0; i < (int)pImplTTFont->nkern; i++ )
+ {
+ const sal_uInt8* pTable = pImplTTFont->kerntables[i];
+
+ /*sal_uInt16 nVersion =*/ getUInt16BE( pTable );
+ /*sal_uInt16 nLength =*/ getUInt16BE( pTable );
+ sal_uInt16 nCoverage = getUInt16BE( pTable );
+
+ aPair.kern_x = 0;
+ aPair.kern_y = 0;
+ switch( nCoverage >> 8 )
+ {
+ case 0:
+ {
+ sal_uInt16 nPairs = getUInt16BE( pTable );
+ pTable += 6;
+ for( int n = 0; n < nPairs; n++ )
+ {
+ sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
+ sal_uInt16 nRightGlyph = getUInt16BE( pTable );
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
+
+ left = aGlyphMap.find( nLeftGlyph );
+ right = aGlyphMap.find( nRightGlyph );
+ if( left != aGlyphMap.end() && right != aGlyphMap.end() )
+ {
+ aPair.first = left->second;
+ aPair.second = right->second;
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case 2:
+ {
+ const sal_uInt8* pSubTable = pTable;
+ /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
+ sal_uInt16 nOfLeft = getUInt16BE( pTable );
+ sal_uInt16 nOfRight = getUInt16BE( pTable );
+ /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
+ const sal_uInt8* pTmp = pSubTable + nOfLeft;
+ sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
+ sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
+ pTmp = pSubTable + nOfRight;
+ sal_uInt16 nFirstRight = getUInt16BE( pTmp );
+ sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
+
+ // int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
+ for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
+ {
+ for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
+ {
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // Kerning: KT_APPLE_NEW
+ //-----------------------------------------------------------------
+ if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
+ {
+ // create a glyph -> character mapping
+ ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
+ ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
+ for( i = 21; i < 0xfffd; i++ )
+ {
+ sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
+ if( nGlyph != 0 )
+ aGlyphMap[ nGlyph ] = (sal_Unicode)i;
+ }
+
+ // Loop through each of the 'kern' subtables
+ KernPair aPair;
+ for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
+ {
+ const sal_uInt8* pTable = pImplTTFont->kerntables[i];
+
+ /*sal_uInt32 nLength =*/ getUInt32BE( pTable );
+ sal_uInt16 nCoverage = getUInt16BE( pTable );
+ /*sal_uInt16 nTupleIndex =*/ getUInt16BE( pTable );
+
+ // Get kerning type
+ // sal_Bool bKernVertical = nCoverage & 0x8000;
+ // sal_Bool bKernCrossStream = nCoverage & 0x4000;
+ // sal_Bool bKernVariation = nCoverage & 0x2000;
+
+ // Kerning sub-table format, 0 through 3
+ sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
+
+ aPair.kern_x = 0;
+ aPair.kern_y = 0;
+ switch( nSubTableFormat )
+ {
+ case 0:
+ {
+ // Grab the # of kern pairs but skip over the:
+ // searchRange
+ // entrySelector
+ // rangeShift
+ sal_uInt16 nPairs = getUInt16BE( pTable );
+ pTable += 6;
+
+ for( int n = 0; n < nPairs; n++ )
+ {
+ sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
+ sal_uInt16 nRightGlyph = getUInt16BE( pTable );
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
+
+ left = aGlyphMap.find( nLeftGlyph );
+ right = aGlyphMap.find( nRightGlyph );
+ if( left != aGlyphMap.end() && right != aGlyphMap.end() )
+ {
+ aPair.first = left->second;
+ aPair.second = right->second;
+
+ // Only support horizontal kerning for now
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ aPair.kern_y = 0;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+
+/* switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+*/
+ }
+ }
+ }
+ break;
+
+ case 2:
+ {
+ const sal_uInt8* pSubTable = pTable;
+ /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
+ sal_uInt16 nOfLeft = getUInt16BE( pTable );
+ sal_uInt16 nOfRight = getUInt16BE( pTable );
+ /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
+ const sal_uInt8* pTmp = pSubTable + nOfLeft;
+ sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
+ sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
+ pTmp = pSubTable + nOfRight;
+ sal_uInt16 nFirstRight = getUInt16BE( pTmp );
+ sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
+
+ for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
+ {
+ for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
+ {
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
+ break;
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %d/%d kern pairs for %s\n",
+ m_pMetrics->m_aXKernPairs.size(),
+ m_pMetrics->m_aYKernPairs.size(),
+ OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
+#else
+ (void) pProvider; /* avoid warnings */
+#endif
+ }
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+/* #i73387# There seem to be fonts with a rather unwell chosen family name
+* consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
+* It can really only be distinguished by its PSName and FullName. Both of
+* which are not user presentable in OOo. So replace it by something sensible.
+*
+* If other fonts feature this behaviour, insert them to the map.
+*/
+static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
+{
+ static std::hash_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
+ if( aPSNameToFamily.empty() ) // initialization
+ {
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Bold" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-BoldOblique" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Oblique" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ }
+ std::hash_map<OUString,OUString,OUStringHash>::const_iterator it =
+ aPSNameToFamily.find( i_rPSname );
+ bool bReplaced = (it != aPSNameToFamily.end() );
+ if( bReplaced )
+ o_rFamilyName = it->second;
+ return bReplaced;
+};
+
+bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ int i;
+ FontInfo* pInfo = NULL;
+ parseFile( rFileName.getStr(), &pInfo, P_ALL );
+ if( ! pInfo || ! pInfo->numOfChars )
+ {
+ if( pInfo )
+ freeFontInfo( pInfo );
+ return false;
+ }
+
+ m_aEncodingVector.clear();
+ // fill in global info
+
+ // PSName
+ OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
+ m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
+
+ // family name (if not already set)
+ OUString aFamily;
+ if( ! m_nFamilyName )
+ {
+ aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
+ if( ! aFamily.getLength() )
+ {
+ aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
+ sal_Int32 nIndex = 0;
+ aFamily = aFamily.getToken( 0, '-', nIndex );
+ }
+ familyNameOverride( aPSName, aFamily );
+ m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
+ }
+ else
+ aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
+
+ // style name: if fullname begins with family name
+ // interpret the rest of fullname as style
+ if( ! m_aStyleName.getLength() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
+ {
+ OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( aFullName.indexOf( aFamily ) == 0 )
+ m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
+ }
+
+ // italic
+ if( pInfo->gfi->italicAngle > 0 )
+ m_eItalic = italic::Oblique;
+ else if( pInfo->gfi->italicAngle < 0 )
+ m_eItalic = italic::Italic;
+ else
+ m_eItalic = italic::Upright;
+
+ // weight
+ ByteString aLowerWeight( pInfo->gfi->weight );
+ aLowerWeight.ToLowerAscii();
+ m_eWeight = parseWeight( aLowerWeight );
+
+ // pitch
+ m_ePitch = pInfo->gfi->isFixedPitch ? pitch::Fixed : pitch::Variable;
+
+ // encoding - only set if unknown
+ int nAdobeEncoding = 0;
+ if( pInfo->gfi->encodingScheme )
+ {
+ if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
+ nAdobeEncoding = 1;
+ else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
+ {
+ nAdobeEncoding = 1;
+ m_aEncoding = RTL_TEXTENCODING_UNICODE;
+ }
+ else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
+ nAdobeEncoding = 2;
+ else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
+ nAdobeEncoding = 3;
+
+ if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = nAdobeEncoding == 1 ?
+ RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
+ }
+ else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
+
+ // try to parse the font name and decide wether it might be a
+ // japanese font. Who invented this PITA ?
+ OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
+ if( ! aPSNameLastToken.compareToAscii( "H" ) ||
+ ! aPSNameLastToken.compareToAscii( "V" ) )
+ {
+ static const char* pEncs[] =
+ {
+ "EUC",
+ "RKSJ",
+ "SJ"
+ };
+ static const rtl_TextEncoding aEncs[] =
+ {
+ RTL_TEXTENCODING_EUC_JP,
+ RTL_TEXTENCODING_SHIFT_JIS,
+ RTL_TEXTENCODING_JIS_X_0208
+ };
+
+ for( unsigned int enc = 0; enc < sizeof( aEncs )/sizeof(aEncs[0]) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
+ {
+ sal_Int32 nIndex = 0, nOffset = 1;
+ do
+ {
+ OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
+ if( nIndex == -1 )
+ break;
+ nOffset = 0;
+ if( ! aToken.compareToAscii( pEncs[enc] ) )
+ {
+ m_aEncoding = aEncs[ enc ];
+ m_bFontEncodingOnly = true;
+ }
+ } while( nIndex != -1 );
+ }
+
+ // default is jis
+ if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
+#endif
+ }
+
+ // hack for GB encoded builtin fonts posing as FontSpecific
+ if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
+ {
+ int nLen = aFamily.getLength();
+ if( nLen > 2 &&
+ aFamily.getStr()[ nLen-2 ] == 'G' &&
+ aFamily.getStr()[ nLen-1 ] == 'B' &&
+ pInfo->numOfChars > 255 )
+ {
+ m_aEncoding = RTL_TEXTENCODING_GBK;
+ m_bFontEncodingOnly = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
+#endif
+ }
+ }
+
+ // #i37313# check if Fontspecific is not rather some character encoding
+ if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
+ {
+ bool bYFound = false;
+ bool bQFound = false;
+ CharMetricInfo* pChar = pInfo->cmi;
+ for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
+ {
+ if( pChar[j].name )
+ {
+ if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
+ bYFound = true;
+ else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
+ bQFound = true;
+ }
+ }
+ if( bQFound && bYFound )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
+ pInfo->gfi->fontName,
+ rFileName.getStr()
+ );
+ #endif
+ nAdobeEncoding = 4;
+ m_aEncoding = RTL_TEXTENCODING_UNICODE;
+ bFillEncodingvector = false; // will be filled anyway, don't do the work twice
+ }
+ }
+
+ // ascend
+ m_nAscend = pInfo->gfi->fontBBox.ury;
+
+ // descend
+ // descends have opposite sign of our definition
+ m_nDescend = -pInfo->gfi->fontBBox.lly;
+
+ // fallback to ascender, descender
+ // interesting: the BBox seems to describe Ascender and Descender better
+ // as we understand it
+ if( m_nAscend == 0 )
+ m_nAscend = pInfo->gfi->ascender;
+ if( m_nDescend == 0)
+ m_nDescend = -pInfo->gfi->descender;
+
+ m_nLeading = m_nAscend + m_nDescend - 1000;
+
+ if( m_pMetrics )
+ delete m_pMetrics;
+ m_pMetrics = new PrintFontMetrics;
+ // mark all pages as queried (or clear if only global font info queiried)
+ memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
+
+ m_aGlobalMetricX.width = m_aGlobalMetricY.width =
+ pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
+ m_aGlobalMetricX.height = m_aGlobalMetricY.height =
+ pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
+
+ m_nXMin = pInfo->gfi->fontBBox.llx;
+ m_nYMin = pInfo->gfi->fontBBox.lly;
+ m_nXMax = pInfo->gfi->fontBBox.urx;
+ m_nYMax = pInfo->gfi->fontBBox.ury;
+
+ if( bFillEncodingvector || !bOnlyGlobalAttributes )
+ {
+ // fill in character metrics
+
+ // first transform the character codes to unicode
+ // note: this only works with single byte encodings
+ sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
+ CharMetricInfo* pChar = pInfo->cmi;
+
+ for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
+ {
+ if( nAdobeEncoding == 4 )
+ {
+ if( pChar->name )
+ {
+ pUnicodes[i] = 0;
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ {
+ m_aEncodingVector[ *it ] = pChar->code;
+ if( pChar->code == -1 )
+ m_aNonEncoded[ *it ] = pChar->name;
+ if( ! pUnicodes[i] ) // map the first
+ pUnicodes[i] = *it;
+ }
+ }
+ }
+ }
+ else if( pChar->code != -1 )
+ {
+ if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
+ {
+ pUnicodes[i] = pChar->code + 0xf000;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
+ continue;
+ }
+
+ if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
+ {
+ pUnicodes[i] = (sal_Unicode)pChar->code;
+ continue;
+ }
+
+ ByteString aTranslate;
+ if( pChar->code & 0xff000000 )
+ aTranslate += (char)(pChar->code >> 24 );
+ if( pChar->code & 0xffff0000 )
+ aTranslate += (char)((pChar->code & 0x00ff0000) >> 16 );
+ if( pChar->code & 0xffffff00 )
+ aTranslate += (char)((pChar->code & 0x0000ff00) >> 8 );
+ aTranslate += (char)(pChar->code & 0xff);
+ String aUni( aTranslate, m_aEncoding );
+ pUnicodes[i] = *aUni.GetBuffer();
+ }
+ else
+ pUnicodes[i] = 0;
+ }
+
+ // now fill in the character metrics
+ // parseAFM.cxx effectively only supports direction 0 (horizontal)
+ pChar = pInfo->cmi;
+ CharacterMetric aMetric;
+ for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
+ {
+ if( pChar->code == -1 && ! pChar->name )
+ continue;
+
+ if( bFillEncodingvector && pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ {
+ m_aEncodingVector[ *it ] = pChar->code;
+ if( pChar->code == -1 )
+ m_aNonEncoded[ *it ] = pChar->name;
+ }
+ }
+ }
+
+ aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
+ aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
+ if( aMetric.width == 0 && aMetric.height == 0 )
+ // guess something for e.g. space
+ aMetric.width = m_aGlobalMetricX.width/4;
+
+ if( ( nAdobeEncoding == 0 ) ||
+ ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
+ {
+ if( pChar->code != -1 )
+ {
+ m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
+ }
+ else if( pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ m_pMetrics->m_aMetrics[ *it ] = aMetric;
+ }
+ }
+ }
+ else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
+ {
+ if( pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ m_pMetrics->m_aMetrics[ *it ] = aMetric;
+ }
+ }
+ else if( pChar->code != -1 )
+ {
+ ::std::pair< ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator,
+ ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator >
+ aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
+ while( aCodes.first != aCodes.second )
+ {
+ if( (*aCodes.first).second != 0 )
+ {
+ m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
+ }
+ ++aCodes.first;
+ }
+ }
+ }
+ else if( nAdobeEncoding == 3 )
+ {
+ if( pChar->code != -1 )
+ {
+ sal_Unicode code = 0xf000 + pChar->code;
+ m_pMetrics->m_aMetrics[ code ] = aMetric;
+ // maybe should try to find the name in the convtabs ?
+ if( bFillEncodingvector )
+ m_aEncodingVector[ code ] = pChar->code;
+ }
+ }
+ }
+
+ m_pMetrics->m_aXKernPairs.clear();
+ m_pMetrics->m_aYKernPairs.clear();
+
+ // now fill in the kern pairs
+ // parseAFM.cxx effectively only supports direction 0 (horizontal)
+ PairKernData* pKern = pInfo->pkd;
+ KernPair aPair;
+ for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
+ {
+ // #i37703# broken kern table
+ if( ! pKern->name1 || ! pKern->name2 )
+ continue;
+
+ aPair.first = 0;
+ aPair.second = 0;
+ // currently we have to find the adobe character names
+ // in the already parsed character metrics to find
+ // the corresponding UCS2 code which is a bit dangerous
+ // since the character names are not required
+ // in the metric descriptions
+ pChar = pInfo->cmi;
+ for( int j = 0;
+ j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
+ j++, pChar++ )
+ {
+ if( pChar->code != -1 )
+ {
+ if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
+ aPair.first = pUnicodes[ j ];
+ if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
+ aPair.second = pUnicodes[ j ];
+ }
+ }
+ if( aPair.first && aPair.second )
+ {
+ aPair.kern_x = pKern->xamt;
+ aPair.kern_y = pKern->yamt;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ }
+ }
+ m_pMetrics->m_bKernPairsQueried = true;
+ }
+
+ freeFontInfo( pInfo );
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::s_aEmptyOString;
+
+/*
+ * one instance only
+ */
+PrintFontManager& PrintFontManager::get()
+{
+ static PrintFontManager* theManager = NULL;
+ if( ! theManager )
+ {
+ theManager = new PrintFontManager();
+ theManager->initialize();
+ }
+ return *theManager;
+}
+
+// -------------------------------------------------------------------------
+
+/*
+ * the PrintFontManager
+ */
+
+PrintFontManager::PrintFontManager() :
+ m_nNextFontID( 1 ),
+ m_pAtoms( new MultiAtomProvider() ),
+ m_nNextDirAtom( 1 ),
+ m_pFontCache( NULL ),
+ m_bFontconfigSuccess( false )
+{
+ for( unsigned int i = 0; i < sizeof( aAdobeCodes )/sizeof( aAdobeCodes[0] ); i++ )
+ {
+ m_aUnicodeToAdobename.insert( ::std::hash_multimap< sal_Unicode, ::rtl::OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
+ m_aAdobenameToUnicode.insert( ::std::hash_multimap< ::rtl::OString, sal_Unicode, ::rtl::OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
+ if( aAdobeCodes[i].aAdobeStandardCode )
+ {
+ m_aUnicodeToAdobecode.insert( ::std::hash_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
+ m_aAdobecodeToUnicode.insert( ::std::hash_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
+ }
+#if 0
+ m_aUnicodeToAdobename[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].pAdobename;
+ m_aAdobenameToUnicode[ aAdobeCodes[i].pAdobename ] = aAdobeCodes[i].aUnicode;
+ if( aAdobeCodes[i].aAdobeStandardCode )
+ {
+ m_aUnicodeToAdobecode[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].aAdobeStandardCode;
+ m_aAdobecodeToUnicode[ aAdobeCodes[i].aAdobeStandardCode ] = aAdobeCodes[i].aUnicode;
+ }
+#endif
+ }
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::~PrintFontManager()
+{
+ deinitFontconfig();
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ delete (*it).second;
+ delete m_pAtoms;
+ if( m_pFontCache )
+ delete m_pFontCache;
+}
+
+// -------------------------------------------------------------------------
+
+const OString& PrintFontManager::getDirectory( int nAtom ) const
+{
+ ::std::hash_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
+ return it != m_aAtomToDir.end() ? it->second : s_aEmptyOString;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
+{
+ int nAtom = 0;
+ ::std::hash_map< OString, int, OStringHash >::const_iterator it
+ ( m_aDirToAtom.find( rDirectory ) );
+ if( it != m_aDirToAtom.end() )
+ nAtom = it->second;
+ else if( bCreate )
+ {
+ nAtom = m_nNextDirAtom++;
+ m_aDirToAtom[ rDirectory ] = nAtom;
+ m_aAtomToDir[ nAtom ] = rDirectory;
+ }
+ return nAtom;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::addFontFile( const ::rtl::OString& rFileName, int /*nFaceNum*/ )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ OString aName( OUStringToOString( aPath.GetName(), aEncoding ) );
+ OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) );
+
+ int nDirID = getDirectoryAtom( aDir, true );
+ fontID nFontId = findFontFileID( nDirID, aName );
+ if( !nFontId )
+ {
+ ::std::list< PrintFont* > aNewFonts;
+ if( analyzeFontFile( nDirID, aName, ::std::list<OString>(), aNewFonts ) )
+ {
+ for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
+ it != aNewFonts.end(); ++it )
+ {
+ m_aFonts[ nFontId = m_nNextFontID++ ] = *it;
+ m_aFontFileToFontID[ aName ].insert( nFontId );
+ m_pFontCache->updateFontCacheEntry( *it, true );
+ }
+ }
+ }
+ return nFontId;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, const ::std::list<OString>& rXLFDs, ::std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ rNewFonts.clear();
+
+ OString aDir( getDirectory( nDirID ) );
+
+ OString aFullPath( aDir );
+ aFullPath += "/";
+ aFullPath += rFontFile;
+
+ // #i1872# reject unreadable files
+ if( access( aFullPath.getStr(), R_OK ) )
+ return false;
+
+ ByteString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
+ if( aExt.EqualsIgnoreCaseAscii( "pfb" ) || aExt.EqualsIgnoreCaseAscii( "pfa" ) )
+ {
+ // check for corresponding afm metric
+ // first look for an adjacent file
+ static const char* pSuffix[] = { ".afm", ".AFM" };
+
+ for( unsigned int i = 0; i < sizeof(pSuffix)/sizeof(pSuffix[0]); i++ )
+ {
+ ByteString aName( rFontFile );
+ aName.Erase( aName.Len()-4 );
+ aName.Append( pSuffix[i] );
+
+ ByteString aFilePath( aDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( aName );
+
+ ByteString aAfmFile;
+ if( access( aFilePath.GetBuffer(), R_OK ) )
+ {
+ // try in subdirectory afm instead
+ aFilePath = aDir;
+ aFilePath.Append( "/afm/" );
+ aFilePath.Append( aName );
+
+ if( ! access( aFilePath.GetBuffer(), R_OK ) )
+ {
+ aAfmFile = "afm/";
+ aAfmFile += aName;
+ }
+ }
+ else
+ aAfmFile = aName;
+
+ if( aAfmFile.Len() )
+ {
+ Type1FontFile* pFont = new Type1FontFile();
+ pFont->m_nDirectory = nDirID;
+
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_aMetricFile = aAfmFile;
+
+ if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ if( pFont && rXLFDs.size() )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ if( pFont )
+ rNewFonts.push_back( pFont );
+ break;
+ }
+ }
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "afm" ) )
+ {
+ ByteString aFilePath( aDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString( rFontFile ) );
+ BuiltinFont* pFont = new BuiltinFont();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aMetricFile = rFontFile;
+ if( pFont->readAfmMetrics( aFilePath, m_pAtoms, false, true ) )
+ rNewFonts.push_back( pFont );
+ else
+ delete pFont;
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "ttf" )
+ || aExt.EqualsIgnoreCaseAscii( "tte" ) // #i33947# for Gaiji support
+ || aExt.EqualsIgnoreCaseAscii( "otf" ) ) // #112957# allow GLYF-OTF
+ {
+ TrueTypeFontFile* pFont = new TrueTypeFontFile();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_nCollectionEntry = -1;
+
+ if( rXLFDs.size() )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ // need to read the font anyway to get aliases inside the font file
+ if( ! analyzeTrueTypeFile( pFont ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ else
+ rNewFonts.push_back( pFont );
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "ttc" ) )
+ {
+ // get number of ttc entries
+ int nLength = CountTTCFonts( aFullPath.getStr() );
+ if( nLength )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s contains %d fonts\n", aFullPath.getStr(), nLength );
+#endif
+ for( int i = 0; i < nLength; i++ )
+ {
+ TrueTypeFontFile* pFont = new TrueTypeFontFile();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_nCollectionEntry = i;
+ if( nLength == 1 )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ if( ! analyzeTrueTypeFile( pFont ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ else
+ rNewFonts.push_back( pFont );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "CountTTCFonts( \"%s/%s\" ) failed\n", getDirectory(nDirID).getStr(), rFontFile.getStr() );
+#endif
+ }
+ return ! rNewFonts.empty();
+}
+
+// -------------------------------------------------------------------------
+
+fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
+{
+ fontID nID = 0;
+ ::std::hash_map< fontID, PrintFont* >::const_iterator it;
+ for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
+ {
+ if( it->second->m_eType == fonttype::Builtin &&
+ it->second->m_nPSName == nPSNameAtom )
+ nID = it->first;
+ }
+ return nID;
+}
+
+// -------------------------------------------------------------------------
+
+fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile ) const
+{
+ fontID nID = 0;
+
+ ::std::hash_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
+ if( set_it != m_aFontFileToFontID.end() )
+ {
+ for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
+ {
+ ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
+ if( it != m_aFonts.end() )
+ {
+ switch( it->second->m_eType )
+ {
+ case fonttype::Type1:
+ {
+ Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
+ if( pFont->m_nDirectory == nDirID &&
+ pFont->m_aFontFile == rFontFile )
+ nID = it->first;
+ }
+ break;
+ case fonttype::TrueType:
+ {
+ TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
+ if( pFont->m_nDirectory == nDirID &&
+ pFont->m_aFontFile == rFontFile )
+ nID = it->first;
+ }
+ break;
+ case fonttype::Builtin:
+ if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
+ static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
+ nID = it->first;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return nID;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::parseXLFD( const OString& rXLFD, XLFDEntry& rEntry )
+{
+ sal_Int32 nIndex = 0;
+ OString aFoundry = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ) );
+ if( nIndex < 0 ) return false;
+ OString aFamilyXLFD = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ) );
+ if( nIndex < 0 ) return false;
+ OString aWeight = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aSlant = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aWidth = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aAddStyle = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aPitch = rXLFD.getToken( 4, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aRegEnc = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ).toAsciiLowerCase() );
+ if( nIndex < 0 ) return false;
+ OString aEnc = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase() );
+
+ // capitalize words
+ sal_Int32 nFamIndex = 0;
+ OStringBuffer aFamilyName;
+ while( nFamIndex >= 0 )
+ {
+ OString aToken = aFamilyXLFD.getToken( 0, ' ', nFamIndex );
+ sal_Char aFirst = aToken.toChar();
+ if( aFirst >= 'a' && aFirst <= 'z' )
+ aFirst = aFirst - 'a' + 'A';
+ OStringBuffer aNewToken( aToken.getLength() );
+ aNewToken.append( aToken );
+ aNewToken.setCharAt( 0, aFirst );
+ if( aFamilyName.getLength() > 0 )
+ aFamilyName.append( ' ' );
+ aFamilyName.append( aNewToken.makeStringAndClear() );
+ }
+
+ rEntry.aFoundry = aFoundry;
+ rEntry.aFamily = aFamilyName.makeStringAndClear();
+ rEntry.aAddStyle = aAddStyle;
+ // evaluate weight
+ rEntry.eWeight = parseWeight( aWeight );
+ // evaluate slant
+ rEntry.eItalic = parseItalic( aSlant );
+ // evaluate width
+ rEntry.eWidth = parseWidth( aWidth );
+
+ // evaluate pitch
+ if( aPitch.toChar() == 'c' || aPitch.toChar() == 'm' )
+ rEntry.ePitch = pitch::Fixed;
+ else
+ rEntry.ePitch = pitch::Variable;
+
+ OString aToken = aEnc.toAsciiLowerCase();
+ // get encoding
+ if( aAddStyle.indexOf( "symbol" ) != -1 )
+ rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
+ else
+ {
+ if( aToken.equals( "symbol" ) )
+ rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
+ else
+ {
+ OStringBuffer aCharset( aRegEnc.getLength() + aEnc.getLength() + 1 );
+ aCharset.append( aRegEnc );
+ aCharset.append( '-' );
+ aCharset.append( aEnc );
+ rEntry.aEncoding = rtl_getTextEncodingFromUnixCharset( aCharset.getStr() );
+ }
+ }
+
+ // set correct mask flags
+ rEntry.nMask = 0;
+ if( rEntry.aFoundry != "*" ) rEntry.nMask |= XLFDEntry::MaskFoundry;
+ if( rEntry.aFamily != "*" ) rEntry.nMask |= XLFDEntry::MaskFamily;
+ if( rEntry.aAddStyle != "*" ) rEntry.nMask |= XLFDEntry::MaskAddStyle;
+ if( aWeight != "*" ) rEntry.nMask |= XLFDEntry::MaskWeight;
+ if( aSlant != "*" ) rEntry.nMask |= XLFDEntry::MaskItalic;
+ if( aWidth != "*" ) rEntry.nMask |= XLFDEntry::MaskWidth;
+ if( aPitch != "*" ) rEntry.nMask |= XLFDEntry::MaskPitch;
+ if( aRegEnc != "*" && aEnc != "*" ) rEntry.nMask |= XLFDEntry::MaskEncoding;
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::parseXLFD_appendAliases( const std::list< OString >& rXLFDs, std::list< XLFDEntry >& rEntries ) const
+{
+ for( std::list< OString >::const_iterator it = rXLFDs.begin(); it != rXLFDs.end(); ++it )
+ {
+ XLFDEntry aEntry;
+ if( ! parseXLFD(*it, aEntry) )
+ continue;
+ rEntries.push_back( aEntry );
+ std::map< XLFDEntry, std::list< XLFDEntry > >::const_iterator alias_it =
+ m_aXLFD_Aliases.find( aEntry );
+ if( alias_it != m_aXLFD_Aliases.end() )
+ {
+ rEntries.insert( rEntries.end(), alias_it->second.begin(), alias_it->second.end() );
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontAttributesFromXLFD( PrintFont* pFont, const std::list< OString >& rXLFDs ) const
+{
+ bool bFamilyName = false;
+
+ std::list< XLFDEntry > aXLFDs;
+
+ parseXLFD_appendAliases( rXLFDs, aXLFDs );
+
+ for( std::list< XLFDEntry >::const_iterator it = aXLFDs.begin();
+ it != aXLFDs.end(); ++it )
+ {
+ // set family name or alias
+ int nFam =
+ m_pAtoms->getAtom( ATOM_FAMILYNAME,
+ OStringToOUString( it->aFamily, it->aAddStyle.indexOf( "utf8" ) != -1 ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1 ),
+ sal_True );
+ if( ! bFamilyName )
+ {
+ bFamilyName = true;
+ pFont->m_nFamilyName = nFam;
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ case fonttype::TrueType:
+ static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // make sure that aliases are unique
+ if( nFam != pFont->m_nFamilyName )
+ {
+ std::list< int >::const_iterator al_it;
+ for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nFam; ++al_it )
+ ;
+ if( al_it == pFont->m_aAliases.end() )
+ pFont->m_aAliases.push_back( nFam );
+
+ }
+ // for the rest of the attributes there can only be one value;
+ // we'll trust the first one
+ continue;
+ }
+
+ // fill in weight
+ pFont->m_eWeight = it->eWeight;
+ // fill in slant
+ pFont->m_eItalic = it->eItalic;
+ // fill in width
+ pFont->m_eWidth = it->eWidth;
+ // fill in pitch
+ pFont->m_ePitch = it->ePitch;
+ // fill in encoding
+ pFont->m_aEncoding = it->aEncoding;
+ }
+
+ // handle iso8859-1 as ms1252 to fill the "gap" starting at 0x80
+ if( pFont->m_aEncoding == RTL_TEXTENCODING_ISO_8859_1 )
+ pFont->m_aEncoding = RTL_TEXTENCODING_MS_1252;
+ if( rXLFDs.begin() != rXLFDs.end() )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ case fonttype::TrueType:
+ static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ default: break;
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getXLFD( PrintFont* pFont ) const
+{
+ if( pFont->m_eType == fonttype::Type1 )
+ {
+ if( static_cast<Type1FontFile*>(pFont)->m_aXLFD.getLength() )
+ return static_cast<Type1FontFile*>(pFont)->m_aXLFD;
+ }
+ if( pFont->m_eType == fonttype::TrueType )
+ {
+ if( static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD.getLength() )
+ return static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD;
+ }
+
+ OStringBuffer aXLFD( 128 );
+
+ aXLFD.append( "-misc-" );
+ ByteString aFamily( String( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ), RTL_TEXTENCODING_UTF8 );
+ aFamily.SearchAndReplaceAll( '-',' ' );
+ aFamily.SearchAndReplaceAll( '?',' ' );
+ aFamily.SearchAndReplaceAll( '*',' ' );
+ aXLFD.append( OString( aFamily ) );
+ aXLFD.append( '-' );
+ switch( pFont->m_eWeight )
+ {
+ case weight::Thin: aXLFD.append("thin");break;
+ case weight::UltraLight: aXLFD.append("ultralight");break;
+ case weight::Light: aXLFD.append("light");break;
+ case weight::SemiLight: aXLFD.append("semilight");break;
+ case weight::Normal: aXLFD.append("normal");break;
+ case weight::Medium: aXLFD.append("medium");break;
+ case weight::SemiBold: aXLFD.append("semibold");break;
+ case weight::Bold: aXLFD.append("bold");break;
+ case weight::UltraBold: aXLFD.append("ultrabold");break;
+ case weight::Black: aXLFD.append("black");break;
+ default: break;
+ }
+ aXLFD.append('-');
+ switch( pFont->m_eItalic )
+ {
+ case italic::Upright: aXLFD.append('r');break;
+ case italic::Oblique: aXLFD.append('o');break;
+ case italic::Italic: aXLFD.append('i');break;
+ default: break;
+ }
+ aXLFD.append('-');
+ switch( pFont->m_eWidth )
+ {
+ case width::UltraCondensed: aXLFD.append("ultracondensed");break;
+ case width::ExtraCondensed: aXLFD.append("extracondensed");break;
+ case width::Condensed: aXLFD.append("condensed");break;
+ case width::SemiCondensed: aXLFD.append("semicondensed");break;
+ case width::Normal: aXLFD.append("normal");break;
+ case width::SemiExpanded: aXLFD.append("semiexpanded");break;
+ case width::Expanded: aXLFD.append("expanded");break;
+ case width::ExtraExpanded: aXLFD.append("extraexpanded");break;
+ case width::UltraExpanded: aXLFD.append("ultraexpanded");break;
+ default: break;
+ }
+ aXLFD.append("-utf8-0-0-0-0-");
+ aXLFD.append( pFont->m_ePitch == pitch::Fixed ? "m" : "p" );
+ aXLFD.append("-0-");
+ const char* pEnc = rtl_getBestUnixCharsetFromTextEncoding( pFont->m_aEncoding );
+ if( ! pEnc )
+ {
+ if( pFont->m_aEncoding == RTL_TEXTENCODING_ADOBE_STANDARD )
+ pEnc = "adobe-standard";
+ else
+ pEnc = "iso8859-1";
+ }
+ aXLFD .append( pEnc );
+
+ return aXLFD.makeStringAndClear();
+}
+
+// -------------------------------------------------------------------------
+
+OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
+{
+ NameRecord* pNameRecord = (NameRecord*)pRecord;
+ OUString aValue;
+ if(
+ ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
+ ||
+ ( pNameRecord->platformID == 0 ) // Apple, Unicode
+ )
+ {
+ OUStringBuffer aName( pNameRecord->slen/2 );
+ const sal_uInt8* pNameBuffer = pNameRecord->sptr;
+ for(int n = 0; n < pNameRecord->slen/2; n++ )
+ aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
+ aValue = aName.makeStringAndClear();
+ }
+ else if( pNameRecord->platformID == 3 )
+ {
+ if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
+ {
+ /*
+ * and now for a special kind of madness:
+ * some fonts encode their byte value string as BE uint16
+ * (leading to stray zero bytes in the string)
+ * while others code two bytes as a uint16 and swap to BE
+ */
+ OStringBuffer aName;
+ const sal_uInt8* pNameBuffer = pNameRecord->sptr;
+ for(int n = 0; n < pNameRecord->slen/2; n++ )
+ {
+ sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
+ sal_Char aChar = aCode >> 8;
+ if( aChar )
+ aName.append( aChar );
+ aChar = aCode & 0x00ff;
+ if( aChar )
+ aName.append( aChar );
+ }
+ switch( pNameRecord->encodingID )
+ {
+ case 2:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
+ break;
+ case 3:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
+ break;
+ case 4:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
+ break;
+ case 5:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
+ break;
+ case 6:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
+ break;
+ }
+ }
+ }
+ return aValue;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
+{
+ OUString aFamily;
+
+ rNames.clear();
+ ::std::set< OUString > aSet;
+
+ NameRecord* pNameRecords = NULL;
+ int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
+ if( nNameRecords && pNameRecords )
+ {
+ LanguageType aLang = MsLangId::getSystemLanguage();
+ int nLastMatch = -1;
+ for( int i = 0; i < nNameRecords; i++ )
+ {
+ if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
+ continue;
+ int nMatch = -1;
+ if( pNameRecords[i].platformID == 0 ) // Unicode
+ nMatch = 4000;
+ else if( pNameRecords[i].platformID == 3 )
+ {
+ // this bases on the LanguageType actually being a Win LCID
+ if( pNameRecords[i].languageID == aLang )
+ nMatch = 8000;
+ else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
+ nMatch = 2000;
+ else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
+ pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
+ nMatch = 1500;
+ else
+ nMatch = 1000;
+ }
+ OUString aName = convertTrueTypeName( pNameRecords + i );
+ aSet.insert( aName );
+ if( nMatch > nLastMatch )
+ {
+ nLastMatch = nMatch;
+ aFamily = aName;
+ }
+ }
+ DisposeNameRecords( pNameRecords, nNameRecords );
+ }
+ if( aFamily.getLength() )
+ {
+ rNames.push_front( aFamily );
+ for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
+ if( *it != aFamily )
+ rNames.push_back( *it );
+ }
+ return;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
+{
+ bool bSuccess = false;
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aFile = getFontFile( pFont );
+ TrueTypeFont* pTTFont = NULL;
+
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+
+ ::std::list< OUString > aNames;
+ analyzeTrueTypeFamilyName( pTTFont, aNames );
+
+ // set family name from XLFD if possible
+ if( ! pFont->m_nFamilyName )
+ {
+ if( aNames.begin() != aNames.end() )
+ {
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
+ aNames.pop_front();
+ }
+ else
+ {
+ sal_Int32 dotIndex;
+
+ // poor font does not have a family name
+ // name it to file name minus the extension
+ dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
+ if ( dotIndex == -1 )
+ dotIndex = pTTFontFile->m_aFontFile.getLength();
+
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
+ }
+ }
+ for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
+ {
+ if( it->getLength() )
+ {
+ int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
+ if( nAlias != pFont->m_nFamilyName )
+ {
+ std::list< int >::const_iterator al_it;
+ for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
+ ;
+ if( al_it == pFont->m_aAliases.end() )
+ pFont->m_aAliases.push_back( nAlias );
+ }
+ }
+ }
+
+ if( aInfo.usubfamily )
+ pFont->m_aStyleName = OUString( aInfo.usubfamily );
+
+ pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, String( ByteString( aInfo.psname ), aEncoding ), sal_True );
+ switch( aInfo.weight )
+ {
+ case FW_THIN: pFont->m_eWeight = weight::Thin; break;
+ case FW_EXTRALIGHT: pFont->m_eWeight = weight::UltraLight; break;
+ case FW_LIGHT: pFont->m_eWeight = weight::Light; break;
+ case FW_MEDIUM: pFont->m_eWeight = weight::Medium; break;
+ case FW_SEMIBOLD: pFont->m_eWeight = weight::SemiBold; break;
+ case FW_BOLD: pFont->m_eWeight = weight::Bold; break;
+ case FW_EXTRABOLD: pFont->m_eWeight = weight::UltraBold; break;
+ case FW_BLACK: pFont->m_eWeight = weight::Black; break;
+
+ case FW_NORMAL:
+ default: pFont->m_eWeight = weight::Normal; break;
+ }
+
+ switch( aInfo.width )
+ {
+ case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = width::UltraCondensed; break;
+ case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = width::ExtraCondensed; break;
+ case FWIDTH_CONDENSED: pFont->m_eWidth = width::Condensed; break;
+ case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = width::SemiCondensed; break;
+ case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = width::SemiExpanded; break;
+ case FWIDTH_EXPANDED: pFont->m_eWidth = width::Expanded; break;
+ case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = width::ExtraExpanded; break;
+ case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = width::UltraExpanded; break;
+
+ case FWIDTH_NORMAL:
+ default: pFont->m_eWidth = width::Normal; break;
+ }
+
+ pFont->m_ePitch = aInfo.pitch ? pitch::Fixed : pitch::Variable;
+ pFont->m_eItalic = aInfo.italicAngle == 0 ? italic::Upright : ( aInfo.italicAngle < 0 ? italic::Italic : italic::Oblique );
+ // #104264# there are fonts that set italic angle 0 although they are
+ // italic; use macstyle bit here
+ if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
+ pFont->m_eItalic = italic::Italic;
+
+ pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
+
+ pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
+ pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
+
+ if( aInfo.winAscent && aInfo.winDescent )
+ {
+ pFont->m_nAscend = aInfo.winAscent;
+ pFont->m_nDescend = aInfo.winDescent;
+ pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
+ }
+ else if( aInfo.typoAscender && aInfo.typoDescender )
+ {
+ pFont->m_nLeading = aInfo.typoLineGap;
+ pFont->m_nAscend = aInfo.typoAscender;
+ pFont->m_nDescend = -aInfo.typoDescender;
+ }
+ else
+ {
+ pFont->m_nLeading = aInfo.linegap;
+ pFont->m_nAscend = aInfo.ascender;
+ pFont->m_nDescend = -aInfo.descender;
+ }
+
+ // last try: font bounding box
+ if( pFont->m_nAscend == 0 )
+ pFont->m_nAscend = aInfo.yMax;
+ if( pFont->m_nDescend == 0 )
+ pFont->m_nDescend = -aInfo.yMin;
+ if( pFont->m_nLeading == 0 )
+ pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
+
+ if( pFont->m_nAscend )
+ pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
+
+ // get bounding box
+ pFont->m_nXMin = aInfo.xMin;
+ pFont->m_nYMin = aInfo.yMin;
+ pFont->m_nXMax = aInfo.xMax;
+ pFont->m_nYMax = aInfo.yMax;
+
+ // get type flags
+ pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
+
+ // get vertical substitutions flag
+ pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.GetBuffer() );
+#endif
+
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::initFontsAlias()
+{
+ m_aXLFD_Aliases.clear();
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+ for( std::list< OString >::const_iterator dir_it = m_aFontDirectories.begin();
+ dir_it != m_aFontDirectories.end(); ++dir_it )
+ {
+ OStringBuffer aDirName(512);
+ aDirName.append( *dir_it );
+ aDirName.append( "/fonts.alias" );
+ SvFileStream aStream( OStringToOUString( aDirName.makeStringAndClear(), aEnc ), STREAM_READ );
+ if( ! aStream.IsOpen() )
+ continue;
+
+ do
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+
+ // get the alias and the pattern it gets translated to
+ ByteString aAlias = GetCommandLineToken( 0, aLine );
+ ByteString aMap = GetCommandLineToken( 1, aLine );
+
+ // remove eventual quotes
+ aAlias.EraseLeadingChars( '"' );
+ aAlias.EraseTrailingChars( '"' );
+ aMap.EraseLeadingChars( '"' );
+ aMap.EraseTrailingChars( '"' );
+
+ XLFDEntry aAliasEntry, aMapEntry;
+ parseXLFD( aAlias, aAliasEntry );
+ parseXLFD( aMap, aMapEntry );
+
+ if( aAliasEntry.nMask && aMapEntry.nMask )
+ m_aXLFD_Aliases[ aMapEntry ].push_back( aAliasEntry );
+ } while( ! aStream.IsEof() );
+ }
+}
+
+// code stolen from vcl's RegisterFontSubstitutors()
+// TODO: use that method once psprint gets merged into vcl
+static bool AreFCSubstitutionsEnabled()
+{
+ // init font substitution defaults
+ int nDisableBits = 0;
+#ifdef SOLARIS
+ // TODO: check the OS version and fc-data maintenance level
+ 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
+ }
+
+ return ((nDisableBits & 3) == 0);
+}
+
+void PrintFontManager::initialize()
+{
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_TOGGLE_COLLECT();
+ CALLGRIND_ZERO_STATS();
+ #endif
+
+ long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ];
+
+ if( ! m_pFontCache )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating font cache ... " );
+ clock_t aStart;
+ struct tms tms;
+ aStart = times( &tms );
+#endif
+ m_pFontCache = new FontCache();
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStop = times( &tms );
+ fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
+#endif
+ }
+
+ // initialize may be called twice in the future
+ {
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ delete (*it).second;
+ m_nNextFontID = 1;
+ m_aFonts.clear();
+ m_aFontDirectories.clear();
+ m_aPrivateFontDirectories.clear();
+ m_aOverrideFonts.clear();
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStart;
+ clock_t aStep1;
+ clock_t aStep2;
+ clock_t aStep3;
+ int nBuiltinFonts = 0;
+ int nCached = 0;
+
+ struct tms tms;
+
+ aStart = times( &tms );
+#endif
+
+ // first try fontconfig
+ m_bFontconfigSuccess = initFontconfig();
+
+ // part one - look for downloadable fonts
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ const ::rtl::OUString &rSalPrivatePath = psp::getFontPath();
+
+ // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
+ // the TrueType fonts installed with the office
+ if( rSalPrivatePath.getLength() )
+ {
+ OString aPath = rtl::OUStringToOString( rSalPrivatePath, aEncoding );
+ const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aToken = aPath.getToken( 0, ';', nIndex );
+ normPath( aToken );
+ // if registering an app-specific fontdir with fontconfig fails
+ // and fontconfig-based substitutions are enabled
+ // then trying to use these app-specific fonts doesn't make sense
+ if( m_bFontconfigSuccess && !addFontconfigDir( aToken ) )
+ if( bAreFCSubstitutionsEnabled )
+ continue;
+ m_aFontDirectories.push_back( aToken );
+ m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
+ } while( nIndex >= 0 );
+ }
+
+ // now that all global and local font dirs are known to fontconfig
+ // check that there are fonts actually managed by fontconfig
+ if( m_bFontconfigSuccess )
+ m_bFontconfigSuccess = (countFontconfigFonts() > 0);
+
+ // don't search through many directories fontconfig already told us about
+ if( ! m_bFontconfigSuccess )
+ ImplGetSVData()->mpDefInst->FillFontPathList( m_aFontDirectories );
+
+ // fill XLFD aliases from fonts.alias files
+ initFontsAlias();
+
+ // search for font files in each path
+ std::list< OString >::iterator dir_it;
+ // protect against duplicate paths
+ std::hash_map< OString, int, OStringHash > visited_dirs;
+ for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
+ {
+ OString aPath( *dir_it );
+ // see if we were here already
+ if( visited_dirs.find( aPath ) != visited_dirs.end() )
+ continue;
+ visited_dirs[ aPath ] = 1;
+
+ // there may be ":unscaled" directories (see XFree86)
+ // it should be safe to ignore them since they should not
+ // contain any of our recognizeable fonts
+
+ // ask the font cache whether it handles this directory
+ std::list< PrintFont* > aCacheFonts;
+ if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
+#endif
+ for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *it;
+ if( (*it)->m_eType == fonttype::Type1 )
+ m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::TrueType )
+ m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::Builtin )
+ m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
+#if OSL_DEBUG_LEVEL > 1
+ if( (*it)->m_eType == fonttype::Builtin )
+ nBuiltinFonts++;
+ nCached++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+#endif
+ }
+ if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
+ continue;
+ }
+
+ DIR* pDIR = opendir( aPath.getStr() );
+ struct dirent* pEntry = (struct dirent*)aDirEntBuffer;
+ if( pDIR )
+ {
+ // read fonts.dir if possible
+ ::std::hash_map< OString, ::std::list<OString>, OStringHash > aFontsDir;
+ int nDirID = getDirectoryAtom( aPath, true );
+ // #i38367# no fonts.dir in our own directories anymore
+ std::list< int >::const_iterator priv_dir;
+ for( priv_dir = m_aPrivateFontDirectories.begin();
+ priv_dir != m_aPrivateFontDirectories.end() && *priv_dir != nDirID;
+ ++priv_dir )
+ ;
+
+ if( priv_dir == m_aPrivateFontDirectories.end() )
+ {
+ ByteString aGccDummy( aPath );
+ String aFontsDirPath( aGccDummy, aEncoding );
+ aFontsDirPath.AppendAscii( "/fonts.dir" );
+ SvFileStream aStream( aFontsDirPath, STREAM_READ );
+ if( aStream.IsOpen() )
+ {
+ ByteString aLine;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aLine );
+ ByteString aFileName( GetCommandLineToken( 0, aLine ) );
+ ByteString aXLFD( aLine.Copy( aFileName.Len() ) );
+ if( aFileName.Len() && aXLFD.Len() )
+ aFontsDir[ aFileName ].push_back(aXLFD);
+ }
+ }
+ }
+
+ int nDirFonts = 0;
+ while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pEntry ) && pEntry )
+ {
+ OString aFileName( pEntry->d_name );
+ // ignore .afm files here
+ if( aFileName.getLength() > 3 &&
+ aFileName.lastIndexOf( ".afm" ) == aFileName.getLength()-4 )
+ continue;
+
+ struct stat aStat;
+ ByteString aFilePath( aPath );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString( aFileName ) );
+ if( ! stat( aFilePath.GetBuffer(), &aStat ) &&
+ S_ISREG( aStat.st_mode ) )
+ {
+ if( findFontFileID( nDirID, aFileName ) == 0 )
+ {
+ ::std::list<OString> aXLFDs;
+ ::std::hash_map< OString, ::std::list<OString>, OStringHash >::const_iterator it =
+ aFontsDir.find( aFileName );
+ if( it != aFontsDir.end() )
+ aXLFDs = (*it).second;
+
+ // fill in font attributes from XLFD rather
+ // than reading every file
+ ::std::list< PrintFont* > aNewFonts;
+ if( analyzeFontFile( nDirID, aFileName, aXLFDs, aNewFonts ) )
+ {
+ for( ::std::list< PrintFont* >::iterator font_it = aNewFonts.begin(); font_it != aNewFonts.end(); ++font_it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *font_it;
+ m_aFontFileToFontID[ aFileName ].insert( aFont );
+ m_pFontCache->updateFontCacheEntry( *font_it, false );
+ nDirFonts++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+ }
+ }
+ }
+ }
+ }
+ closedir( pDIR );
+ m_pFontCache->updateDirTimestamp( nDirID );
+ if( ! nDirFonts )
+ m_pFontCache->markEmptyDir( nDirID );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep1 = times( &tms );
+#endif
+
+ // part two - look for metrics for builtin printer fonts
+ std::list< OUString > aMetricDirs;
+ psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
+
+ std::list< OString > aEmptyFontsDir;
+ for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
+ {
+ OString aDir = OUStringToOString( *met_dir_it, aEncoding );
+
+ // ask the font cache whether it handles this directory
+ std::list< PrintFont* > aCacheFonts;
+
+ if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
+#endif
+ for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *it;
+ if( (*it)->m_eType == fonttype::Type1 )
+ m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::TrueType )
+ m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::Builtin )
+ m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
+#if OSL_DEBUG_LEVEL > 1
+ if( (*it)->m_eType == fonttype::Builtin )
+ nBuiltinFonts++;
+ nCached++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+#endif
+ }
+ continue;
+ }
+
+ DIR* pDIR = opendir( aDir.getStr() );
+ if( pDIR )
+ {
+ struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
+ int nDirID = getDirectoryAtom( aDir, true );
+ int nDirFonts = 0;
+
+ while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
+ {
+ ByteString aFile( aDir );
+ aFile += '/';
+ aFile += pDirEntry->d_name;
+ struct stat aStat;
+ if( ! stat( aFile.GetBuffer(), &aStat )
+ && S_ISREG( aStat.st_mode )
+ )
+ {
+ OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
+ OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
+ if( aExt.equalsIgnoreAsciiCase( "afm" ) )
+ {
+ ::std::list< PrintFont* > aNewFonts;
+
+ analyzeFontFile( nDirID, aFileName, aEmptyFontsDir, aNewFonts );
+ for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
+ {
+ if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
+ {
+ m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = *it;
+ m_pFontCache->updateFontCacheEntry( *it, false );
+#if OSL_DEBUG_LEVEL > 2
+ nBuiltinFonts++;
+#endif
+ }
+ else
+ delete *it;
+ }
+ }
+ }
+ }
+ closedir( pDIR );
+ if( ! nDirFonts )
+ m_pFontCache->markEmptyDir( nDirID );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep2 = times( &tms );
+#endif
+
+ // part three - fill in family styles
+ ::std::hash_map< fontID, PrintFont* >::iterator font_it;
+ for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
+ {
+ ::std::hash_map< int, family::type >::const_iterator it =
+ m_aFamilyTypes.find( font_it->second->m_nFamilyName );
+ if (it != m_aFamilyTypes.end())
+ continue;
+ const ::rtl::OUString& rFamily =
+ m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
+ family::type eType = matchFamilyName( rFamily );
+ m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep3 = times( &tms );
+ fprintf( stderr, "PrintFontManager::initialize: collected %d fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
+ double fTick = (double)sysconf( _SC_CLK_TCK );
+ fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
+ fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
+ fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
+#endif
+
+ m_pFontCache->flush();
+
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_DUMP_STATS();
+ CALLGRIND_TOGGLE_COLLECT();
+ #endif
+}
+
+// -------------------------------------------------------------------------
+inline bool
+equalPitch (psp::pitch::type from, psp::pitch::type to)
+{
+ return from == to;
+}
+
+inline bool
+equalWeight (psp::weight::type from, psp::weight::type to)
+{
+ return from > to ? (from - to) <= 3 : (to - from) <= 3;
+}
+
+inline bool
+equalItalic (psp::italic::type from, psp::italic::type to)
+{
+ if ( (from == psp::italic::Italic) || (from == psp::italic::Oblique) )
+ return (to == psp::italic::Italic) || (to == psp::italic::Oblique);
+ return to == from;
+}
+inline bool
+equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
+{
+ if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
+ return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
+ return from == to;
+}
+
+namespace {
+ struct BuiltinFontIdentifier
+ {
+ OUString aFamily;
+ italic::type eItalic;
+ weight::type eWeight;
+ pitch::type ePitch;
+ rtl_TextEncoding aEncoding;
+
+ BuiltinFontIdentifier( const OUString& rFam,
+ italic::type eIt,
+ weight::type eWg,
+ pitch::type ePt,
+ rtl_TextEncoding enc ) :
+ aFamily( rFam ),
+ eItalic( eIt ),
+ eWeight( eWg ),
+ ePitch( ePt ),
+ aEncoding( enc )
+ {}
+
+ bool operator==( const BuiltinFontIdentifier& rRight ) const
+ {
+ return equalItalic( eItalic, rRight.eItalic ) &&
+ equalWeight( eWeight, rRight.eWeight ) &&
+ equalPitch( ePitch, rRight.ePitch ) &&
+ equalEncoding( aEncoding, rRight.aEncoding ) &&
+ aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
+ }
+ };
+
+ struct BuiltinFontIdentifierHash
+ {
+ size_t operator()( const BuiltinFontIdentifier& rFont ) const
+ {
+ return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
+ }
+ };
+}
+
+void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFontIDs.clear();
+ std::hash_map< fontID, PrintFont* >::const_iterator it;
+
+ /*
+ * Note: there are two easy steps making this faster:
+ * first: insert the printer builtins first, then the not builtins,
+ * if they do not match.
+ * drawback: this would change the sequence of fonts; this could have
+ * subtle, unknown consequences in vcl font matching
+ * second: instead of comparing attributes to see whether a softfont
+ * is duplicate to a builtin one could simply compare the PSName (which is
+ * supposed to be unique), which at this point is just an int.
+ * drawback: this could change which fonts are listed; especially TrueType
+ * fonts often have a rather dubious PSName, so this could change the
+ * font list not so subtle.
+ * Until getFontList for a printer becomes a performance issue (which is
+ * currently not the case), best stay with the current algorithm.
+ */
+
+ // fill sets of printer supported fonts
+ if( pParser )
+ {
+ std::set<int> aBuiltinPSNames;
+ std::hash_set< BuiltinFontIdentifier,
+ BuiltinFontIdentifierHash
+ > aBuiltinFonts;
+
+ std::map<int, fontID > aOverridePSNames;
+ if( bUseOverrideMetrics )
+ {
+ readOverrideMetrics();
+ for( std::vector<fontID>::const_iterator over = m_aOverrideFonts.begin();
+ over != m_aOverrideFonts.end(); ++over )
+ {
+ std::hash_map<fontID,PrintFont*>::const_iterator font_it = m_aFonts.find( *over );
+ DBG_ASSERT( font_it != m_aFonts.end(), "override to nonexistant font" );
+ if( font_it != m_aFonts.end() )
+ aOverridePSNames[ font_it->second->m_nPSName ] = *over;
+ }
+ }
+
+ int nFonts = pParser->getFonts();
+ for( int i = 0; i < nFonts; i++ )
+ aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ PrintFont* pFont = it->second;
+ if( it->second->m_eType == fonttype::Builtin &&
+ aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
+ {
+ bool bInsert = true;
+ if( bUseOverrideMetrics )
+ {
+ // in override case only use the override fonts, not their counterparts
+ std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
+ if( over != aOverridePSNames.end() && over->second != it->first )
+ bInsert = false;
+ }
+ else
+ {
+ // do not insert override fonts in non override case
+ if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
+ bInsert = false;
+ }
+ if( bInsert )
+ {
+ aBuiltinFonts.insert( BuiltinFontIdentifier(
+ m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
+ pFont->m_eItalic,
+ pFont->m_eWeight,
+ pFont->m_ePitch,
+ pFont->m_aEncoding
+ ) );
+ }
+ }
+ }
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ PrintFont* pFont = it->second;
+ if( it->second->m_eType == fonttype::Builtin )
+ {
+ if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
+ {
+ bool bInsert = true;
+ if( bUseOverrideMetrics )
+ {
+ // in override case only use the override fonts, not their counterparts
+ std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
+ if( over != aOverridePSNames.end() && over->second != it->first )
+ bInsert = false;
+ }
+ else
+ {
+ // do not insert override fonts in non override case
+ if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
+ bInsert = false;
+ }
+ if( bInsert )
+ rFontIDs.push_back( it->first );
+ }
+ }
+ else if( aBuiltinFonts.find( BuiltinFontIdentifier(
+ m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
+ pFont->m_eItalic,
+ pFont->m_eWeight,
+ pFont->m_ePitch,
+ pFont->m_aEncoding
+ ) ) == aBuiltinFonts.end() )
+ {
+ rFontIDs.push_back( it->first );
+ }
+ }
+ }
+ else // no specific printer
+ {
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ rFontIDs.push_back( it->first );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
+{
+ ::std::hash_map< int, family::type >::const_iterator style_it =
+ m_aFamilyTypes.find( pFont->m_nFamilyName );
+ rInfo.m_eType = pFont->m_eType;
+ rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
+ rInfo.m_aStyleName = pFont->m_aStyleName;
+ rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : family::Unknown;
+ rInfo.m_eItalic = pFont->m_eItalic;
+ rInfo.m_eWidth = pFont->m_eWidth;
+ rInfo.m_eWeight = pFont->m_eWeight;
+ rInfo.m_ePitch = pFont->m_ePitch;
+ rInfo.m_aEncoding = pFont->m_aEncoding;
+ rInfo.m_eEmbeddedbitmap = pFont->m_eEmbeddedbitmap;
+ rInfo.m_eAntialias = pFont->m_eAntialias;
+ rInfo.m_aAliases.clear();
+ for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
+ rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
+{
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
+ ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a truetype font not analyzed or type1 without metrics read
+ if( pFont->m_eType == fonttype::Type1 )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
+
+ rInfo.m_nAscend = pFont->m_nAscend;
+ rInfo.m_nDescend = pFont->m_nDescend;
+ rInfo.m_nLeading = pFont->m_nLeading;
+ rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontListWithInfo( ::std::list< PrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFonts.clear();
+ ::std::list< fontID > aFontList;
+ getFontList( aFontList, pParser, bUseOverrideMetrics );
+
+ ::std::list< fontID >::iterator it;
+ for( it = aFontList.begin(); it != aFontList.end(); ++it )
+ {
+ PrintFontInfo aInfo;
+ aInfo.m_nID = *it;
+ fillPrintFontInfo( getFont( *it ), aInfo );
+ rFonts.push_back( aInfo );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFonts.clear();
+ ::std::list< fontID > aFontList;
+ getFontList( aFontList, pParser, bUseOverrideMetrics );
+
+ ::std::list< fontID >::iterator it;
+ for( it = aFontList.begin(); it != aFontList.end(); ++it )
+ {
+ FastPrintFontInfo aInfo;
+ aInfo.m_nID = *it;
+ fillPrintFontInfo( getFont( *it ), aInfo );
+ rFonts.push_back( aInfo );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ rInfo.m_nID = nFontID;
+ fillPrintFontInfo( pFont, rInfo );
+ }
+ return pFont ? true : false;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ rInfo.m_nID = nFontID;
+ fillPrintFontInfo( pFont, rInfo );
+ }
+ return pFont ? true : false;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
+{
+ bool bSuccess = false;
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
+ {
+ // might be a truetype font not analyzed or type1 without metrics read
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ bSuccess = true;
+ xMin = pFont->m_nXMin;
+ yMin = pFont->m_nYMin;
+ xMax = pFont->m_nXMax;
+ yMax = pFont->m_nYMax;
+ }
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
+{
+ int nRet = -1;
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
+ return nRet;
+}
+
+// -------------------------------------------------------------------------
+
+
+family::type PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const
+{
+ typedef struct {
+ const char* mpName;
+ sal_uInt16 mnLength;
+ family::type meType;
+ } family_t;
+
+#define InitializeClass( p, a ) p, sizeof(p) - 1, a
+ const family_t pFamilyMatch[] = {
+ { InitializeClass( "arial", family::Swiss ) },
+ { InitializeClass( "arioso", family::Script ) },
+ { InitializeClass( "avant garde", family::Swiss ) },
+ { InitializeClass( "avantgarde", family::Swiss ) },
+ { InitializeClass( "bembo", family::Roman ) },
+ { InitializeClass( "bookman", family::Roman ) },
+ { InitializeClass( "conga", family::Roman ) },
+ { InitializeClass( "courier", family::Modern ) },
+ { InitializeClass( "curl", family::Script ) },
+ { InitializeClass( "fixed", family::Modern ) },
+ { InitializeClass( "gill", family::Swiss ) },
+ { InitializeClass( "helmet", family::Modern ) },
+ { InitializeClass( "helvetica", family::Swiss ) },
+ { InitializeClass( "international", family::Modern ) },
+ { InitializeClass( "lucida", family::Swiss ) },
+ { InitializeClass( "new century schoolbook", family::Roman ) },
+ { InitializeClass( "palatino", family::Roman ) },
+ { InitializeClass( "roman", family::Roman ) },
+ { InitializeClass( "sans serif", family::Swiss ) },
+ { InitializeClass( "sansserif", family::Swiss ) },
+ { InitializeClass( "serf", family::Roman ) },
+ { InitializeClass( "serif", family::Roman ) },
+ { InitializeClass( "times", family::Roman ) },
+ { InitializeClass( "utopia", family::Roman ) },
+ { InitializeClass( "zapf chancery", family::Script ) },
+ { InitializeClass( "zapfchancery", family::Script ) }
+ };
+
+ rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
+ sal_uInt32 nLower = 0;
+ sal_uInt32 nUpper = sizeof(pFamilyMatch) / sizeof(pFamilyMatch[0]);
+
+ while( nLower < nUpper )
+ {
+ sal_uInt32 nCurrent = (nLower + nUpper) / 2;
+ const family_t* pHaystack = pFamilyMatch + nCurrent;
+ sal_Int32 nComparison =
+ rtl_str_compareIgnoreAsciiCase_WithLength
+ (
+ aFamily.getStr(), aFamily.getLength(),
+ pHaystack->mpName, pHaystack->mnLength
+ );
+
+ if( nComparison < 0 )
+ nUpper = nCurrent;
+ else
+ if( nComparison > 0 )
+ nLower = nCurrent + 1;
+ else
+ return pHaystack->meType;
+ }
+
+ return family::Unknown;
+}
+
+// -------------------------------------------------------------------------
+
+family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( !pFont )
+ return family::Unknown;
+
+ ::std::hash_map< int, family::type >::const_iterator it =
+ m_aFamilyTypes.find( pFont->m_nFamilyName );
+ return (it != m_aFamilyTypes.end()) ? it->second : family::Unknown;
+}
+
+
+// -------------------------------------------------------------------------
+
+const ::rtl::OUString& PrintFontManager::getFontFamily( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ return m_pAtoms->getString( ATOM_FAMILYNAME, pFont ? pFont->m_nFamilyName : INVALID_ATOM );
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
+{
+ OString aMetricPath;
+ if( pFont )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ {
+ Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
+ aMetricPath = getDirectory( pPSFont->m_nDirectory );
+ aMetricPath += "/";
+ aMetricPath += pPSFont->m_aMetricFile;
+ }
+ break;
+ case fonttype::Builtin:
+ {
+ BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
+ aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
+ aMetricPath += "/";
+ aMetricPath += pBuiltinFont->m_aMetricFile;
+ }
+ break;
+ default: break;
+ }
+ }
+ return aMetricPath;
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getFontFile( PrintFont* pFont ) const
+{
+ OString aPath;
+
+ if( pFont && pFont->m_eType == fonttype::Type1 )
+ {
+ Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
+ ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
+ aPath = it->second;
+ aPath += "/";
+ aPath += pPSFont->m_aFontFile;
+ }
+ else if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
+ ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
+ aPath = it->second;
+ aPath += "/";
+ aPath += pTTFont->m_aFontFile;
+ }
+ return aPath;
+}
+
+// -------------------------------------------------------------------------
+
+const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont && pFont->m_nPSName == 0 )
+ {
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
+}
+
+// -------------------------------------------------------------------------
+
+const CharacterMetric& PrintFontManager::getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const
+{
+ static CharacterMetric aMetric;
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? ( bHorizontal ? pFont->m_aGlobalMetricX : pFont->m_aGlobalMetricY ) : aMetric;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontAscend( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ }
+ return pFont->m_nAscend;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontDescend( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ }
+ return pFont->m_nDescend;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontLeading( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ return pFont->m_nLeading;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::hasVerticalSubstitutions( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ return pFont->m_bHaveVerticalSubstitutedGlyphs;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
+ const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
+ memset( pHasSubst, 0, sizeof(bool)*nCharacters );
+ else
+ {
+ for( int i = 0; i < nCharacters; i++ )
+ {
+ sal_Unicode code = pCharacters[i];
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( code >> 8, m_pAtoms );
+ ::std::hash_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
+ pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+OUString PrintFontManager::getFontXLFD( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ OUString aRet;
+ if( pFont )
+ {
+ ByteString aXLFD( getXLFD( pFont ) );
+ rtl_TextEncoding aEncoding = aXLFD.GetToken( 6, '-' ).Search( "utf8" ) != STRING_NOTFOUND ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1;
+ aRet = OStringToOUString( aXLFD, aEncoding );
+ }
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+
+const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
+{
+ static ::std::list< KernPair > aEmpty;
+
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return aEmpty;
+
+ if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
+ pFont->queryMetricPage( 0, m_pAtoms );
+ if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
+ return aEmpty;
+ return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::isFontDownloadingAllowed( fontID nFont ) const
+{
+ static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
+ bool bRet = true;
+
+ if( pEnable && *pEnable )
+ {
+ PrintFont* pFont = getFont( nFont );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
+ if( pTTFontFile->m_nTypeFlags & 0x80000000 )
+ {
+ TrueTypeFont* pTTFont = NULL;
+ ByteString aFile = getFontFile( pFont );
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ // get type flags
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+ pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
+ CloseTTFont( pTTFont );
+ }
+ }
+
+ unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & 0x0e;
+
+ // font embedding is allowed if either
+ // no restriction at all (bit 1 clear)
+ // printing allowed (bit 1 set, bit 2 set )
+ bRet = ! ( nCopyrightFlags & 0x02 ) || ( nCopyrightFlags & 0x04 );
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return false;
+
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a font not yet analyzed
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
+ pArray[i].width = pArray[i].height = -1;
+ if( pFont->m_pMetrics )
+ {
+ int effectiveCode = pString[i];
+ effectiveCode |= bVertical ? 1 << 16 : 0;
+ ::std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
+ // if no vertical metrics are available assume rotated horizontal metrics
+ if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
+ it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
+ // the character metrics are in it->second
+ if( it != pFont->m_pMetrics->m_aMetrics.end() )
+ pArray[ i ] = it->second;
+ }
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return false;
+
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a font not yet analyzed
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ sal_Unicode code = minCharacter;
+ do
+ {
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( code >> 8, m_pAtoms );
+ pArray[ code - minCharacter ].width = -1;
+ pArray[ code - minCharacter ].height = -1;
+ if( pFont->m_pMetrics )
+ {
+ int effectiveCode = code;
+ effectiveCode |= bVertical ? 1 << 16 : 0;
+ ::std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
+ // if no vertical metrics are available assume rotated horizontal metrics
+ if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
+ it = pFont->m_pMetrics->m_aMetrics.find( code );
+ // the character metrics are in it->second
+ if( it != pFont->m_pMetrics->m_aMetrics.end() )
+ pArray[ code - minCharacter ] = it->second;
+ }
+ } while( code++ != maxCharacter );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+static bool createWriteablePath( const ByteString& rPath )
+{
+ bool bSuccess = false;
+
+ if( access( rPath.GetBuffer(), W_OK ) )
+ {
+ int nPos = rPath.SearchBackward( '/' );
+ if( nPos != STRING_NOTFOUND )
+ while( nPos > 0 && rPath.GetChar( nPos ) == '/' )
+ nPos--;
+
+ if( nPos != STRING_NOTFOUND && nPos != 0 && createWriteablePath( rPath.Copy( 0, nPos+1 ) ) )
+ {
+ bSuccess = mkdir( rPath.GetBuffer(), 0777 ) ? false : true;
+ }
+ }
+ else
+ bSuccess = true;
+
+ return bSuccess;
+}
+
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::importFonts( const ::std::list< OString >& rFiles, bool bLinkOnly, ImportFontCallback* pCallback )
+{
+ int nSuccess = 0;
+
+ // find a directory with write access
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ bool bCanWrite = false;
+ int nDirID = 0;
+ INetURLObject aDir;
+ for( ::std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
+ ! bCanWrite && dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
+ {
+ // check if we can create files in that directory
+ ByteString aDirPath = getDirectory( *dir_it );
+ if( createWriteablePath( aDirPath ) )
+ {
+ aDir = INetURLObject( OStringToOUString( aDirPath, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ nDirID = *dir_it;
+ bCanWrite = true;
+ }
+ }
+ if( bCanWrite )
+ {
+ for( ::std::list< OString >::const_iterator font_it = rFiles.begin();
+ font_it != rFiles.end(); ++font_it )
+ {
+ INetURLObject aFrom( OStringToOUString( *font_it, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ INetURLObject aTo( aDir );
+ aTo.Append( aFrom.GetName() );
+
+ if( pCallback )
+ pCallback->progress( aTo.PathToFileName() );
+
+ if( pCallback && pCallback->isCanceled() )
+ break;
+
+ if( ! access( ByteString( String(aTo.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ if( ! ( pCallback ? pCallback->queryOverwriteFile( aTo.PathToFileName() ) : false ) )
+ continue;
+ }
+ // look for afm if necessary
+ OUString aAfmCopied;
+ FileBase::RC nError;
+ if( aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfa" ) ||
+ aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfb" ) )
+ {
+ INetURLObject aFromAfm( aFrom );
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.removeSegment();
+ aFromAfm.Append( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ aFromAfm.Append( aTo.GetName() );
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ // give up
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::NoAfmMetric );
+ continue;
+ }
+ }
+ }
+ }
+ INetURLObject aToAfm( aTo );
+ aToAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ OUString aFromPath, aToPath;
+ if( bLinkOnly )
+ {
+ ByteString aLinkFromPath( String(aFromAfm.PathToFileName()),
+ aEncoding );
+ ByteString aLinkToPath( String(aToAfm.PathToFileName()),
+ aEncoding );
+ nError = (FileBase::RC)symlink( aLinkFromPath.GetBuffer(), aLinkToPath.GetBuffer() );
+ }
+ else
+ nError = File::copy( aFromAfm.GetMainURL(INetURLObject::DECODE_TO_IURI), aToAfm.GetMainURL(INetURLObject::DECODE_TO_IURI) );
+ if( nError )
+ {
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::AfmCopyFailed );
+ continue;
+ }
+ aAfmCopied = aToPath;
+ }
+ if( bLinkOnly )
+ {
+ ByteString aFromPath( String(aFrom.PathToFileName()),
+ aEncoding );
+ ByteString aToPath( String(aTo.PathToFileName()), aEncoding );
+ nError = (FileBase::RC)symlink( aFromPath.GetBuffer(),
+ aToPath.GetBuffer() );
+ }
+ else
+ nError = File::copy( aFrom.GetMainURL(INetURLObject::DECODE_TO_IURI), aTo.GetMainURL(INetURLObject::DECODE_TO_IURI) );
+ // copy font file
+ if( nError )
+ {
+ if( aAfmCopied.getLength() )
+ File::remove( aAfmCopied );
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::FontCopyFailed );
+ continue;
+ }
+
+ ::std::list< PrintFont* > aNewFonts;
+ ::std::list< PrintFont* >::iterator it;
+ if( analyzeFontFile( nDirID, OUStringToOString( aTo.GetName(), aEncoding ), ::std::list<OString>(), aNewFonts ) )
+ {
+ // remove all fonts for the same file
+ // discarding their font ids
+ ::std::hash_map< fontID, PrintFont* >::iterator current, next;
+ current = m_aFonts.begin();
+ OString aFileName( OUStringToOString( aTo.GetName(), aEncoding ) );
+ while( current != m_aFonts.end() )
+ {
+ bool bRemove = false;
+ switch( current->second->m_eType )
+ {
+ case fonttype::Type1:
+ if( static_cast<Type1FontFile*>(current->second)->m_aFontFile == aFileName )
+ bRemove = true;
+ break;
+ case fonttype::TrueType:
+ if( static_cast<TrueTypeFontFile*>(current->second)->m_aFontFile == aFileName )
+ bRemove = true;
+ break;
+ default: break;
+ }
+ if( bRemove )
+ {
+ next = current;
+ ++next;
+ m_aFontFileToFontID[ aFileName ].erase( current->first );
+ delete current->second;
+ m_aFonts.erase( current );
+ current = next;
+ }
+ else
+ ++current;
+ }
+
+ DBG_ASSERT( !findFontFileID( nDirID, aFileName ), "not all fonts removed for file" );
+
+ nSuccess++;
+ for( it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
+ {
+ m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = *it;
+ m_pFontCache->updateFontCacheEntry( *it, false );
+ }
+ }
+ }
+
+ m_pFontCache->updateDirTimestamp( nDirID );
+ m_pFontCache->flush();
+ }
+ else if( pCallback )
+ pCallback->importFontsFailed( ImportFontCallback::NoWritableDirectory );
+
+ return nSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::checkImportPossible() const
+{
+ bool bSuccess = false;
+
+ // find a directory with write access
+ ByteString aDir;
+ for( std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
+ dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
+ {
+ aDir = getDirectory( *dir_it );
+ if( createWriteablePath( aDir ) )
+ {
+ bSuccess = true;
+ break;
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ if( bSuccess )
+ fprintf( stderr, "found writable %s\n", aDir.GetBuffer() );
+#endif
+
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::checkChangeFontPropertiesPossible( fontID /*nFontID*/ ) const
+{
+ // since font properties are changed in the font cache file only nowadays
+ // they can always be changed
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::changeFontProperties( fontID nFontID, const ::rtl::OUString& rXLFD )
+{
+ ByteString aXLFD( OUStringToOString( rXLFD, RTL_TEXTENCODING_UTF8 ) );
+ ByteString aAddStyle = aXLFD.GetToken( '-', 6 );
+ if( aAddStyle.Search( "utf8" ) == STRING_NOTFOUND )
+ {
+ aAddStyle.Append( aAddStyle.Len() ? ";utf8" : "utf8" );
+ aXLFD.SetToken( 6, ';', aAddStyle );
+ }
+ PrintFont* pFont = getFont( nFontID );
+ std::list< OString > aDummyList;
+ aDummyList.push_back( aXLFD );
+ getFontAttributesFromXLFD( pFont, aDummyList );
+ pFont->m_bUserOverride = true;
+ m_pFontCache->updateFontCacheEntry( pFont, true );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::
+getImportableFontProperties(
+ const OString& rFile,
+ ::std::list< FastPrintFontInfo >& rFontProps
+ )
+{
+ rFontProps.clear();
+ int nIndex = rFile.lastIndexOf( '/' );
+ OString aDir, aFile( rFile.copy( nIndex+1 ) );
+ if( nIndex != -1 )
+ aDir = rFile.copy( 0, nIndex );
+ int nDirID = getDirectoryAtom( aDir, true );
+ ::std::list< PrintFont* > aFonts;
+ bool bRet = analyzeFontFile( nDirID, aFile, ::std::list<OString>(), aFonts );
+ while( aFonts.begin() != aFonts.end() )
+ {
+ PrintFont* pFont = aFonts.front();
+ aFonts.pop_front();
+ FastPrintFontInfo aInfo;
+ fillPrintFontInfo( pFont, aInfo );
+ rFontProps.push_back( aInfo );
+ delete pFont;
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFileDuplicates( fontID nFont, ::std::list< fontID >& rFonts ) const
+{
+ bool bRet = false;
+
+ rFonts.clear();
+
+ PrintFont* pSearchFont = getFont( nFont );
+ if( ! pSearchFont ||
+ pSearchFont->m_eType != fonttype::TrueType ||
+ static_cast<TrueTypeFontFile*>(pSearchFont)->m_nCollectionEntry == -1
+ )
+ return false;
+
+ OString aFile( getFontFileSysPath( nFont ) );
+ if( ! aFile.getLength() )
+ return false;
+
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ if( nFont != it->first )
+ {
+ OString aCompFile( getFontFile( it->second ) );
+ if( aCompFile == aFile )
+ {
+ rFonts.push_back( it->first );
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::removeFonts( const ::std::list< fontID >& rFonts )
+{
+ bool bRet = true;
+ ::std::list< fontID > aDuplicates;
+ for( ::std::list< fontID >::const_iterator it = rFonts.begin(); it != rFonts.end(); ++it )
+ {
+ ::std::hash_map< fontID, PrintFont* >::const_iterator haveFont = m_aFonts.find( *it );
+ if( haveFont == m_aFonts.end() )
+ continue;
+
+ PrintFont* pFont = haveFont->second;
+ bool bRemoveDuplicates = getFileDuplicates( *it, aDuplicates );
+ ByteString aFile( getFontFile( pFont ) );
+ if( aFile.Len() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try unlink( \"%s\" ) ... ", aFile.GetBuffer() );
+#endif
+ if( unlink( aFile.GetBuffer() ) )
+ {
+ bRet = false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "failed\n" );
+#endif
+ continue;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "succeeded\n" );
+#endif
+ OString aAfm( getAfmFile( pFont ) );
+ if( aAfm.getLength() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "unlink( \"%s\" )\n", aAfm.getStr() );
+#endif
+ unlink( aAfm.getStr() );
+ }
+ m_aFonts.erase( *it );
+ delete pFont;
+ if( bRemoveDuplicates )
+ {
+ for( ::std::list< fontID >::iterator dup = aDuplicates.begin(); dup != aDuplicates.end(); ++dup )
+ {
+ m_aFontFileToFontID[ aFile ].erase( *dup );
+ PrintFont* pDup = m_aFonts[ *dup ];
+ m_aFonts.erase( *dup );
+ delete pDup;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::isPrivateFontFile( fontID nFont ) const
+{
+ bool bRet = false;
+ int nDirID = -1;
+ PrintFont* pFont = getFont( nFont );
+ if( pFont )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1: nDirID = static_cast< Type1FontFile* >(pFont)->m_nDirectory;break;
+ case fonttype::TrueType: nDirID = static_cast< TrueTypeFontFile* >(pFont)->m_nDirectory;break;
+ default: break;
+ }
+ }
+ if( nDirID != -1 )
+ {
+ for( ::std::list< int >::const_iterator it = m_aPrivateFontDirectories.begin(); it != m_aPrivateFontDirectories.end(); ++it )
+ {
+ if( nDirID == *it )
+ {
+ bRet = true;
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getAlternativeFamilyNames( fontID nFont, ::std::list< OUString >& rNames ) const
+{
+ rNames.clear();
+
+ PrintFont* pFont = getFont( nFont );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ ByteString aFile( getFontFile( pFont ) );
+ TrueTypeFont* pTTFont;
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ NameRecord* pNameRecords = NULL;
+ int nNameRecords = GetTTNameRecords( pTTFont, &pNameRecords );
+ for( int i = 0; i < nNameRecords; i++ )
+ {
+ if( pNameRecords[i].nameID != 1 ) // family name
+ continue;
+
+ OUString aFamily( convertTrueTypeName( pNameRecords+i ) );
+ if( aFamily.getLength()
+ &&
+ m_pAtoms->getAtom( ATOM_FAMILYNAME, aFamily, sal_True ) != pFont->m_nFamilyName
+ )
+ {
+ rNames.push_back( aFamily );
+ }
+ }
+
+ if( nNameRecords )
+ DisposeNameRecords( pNameRecords, nNameRecords );
+ CloseTTFont( pTTFont );
+ }
+ }
+ return rNames.begin() != rNames.end();
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::createFontSubset(
+ fontID nFont,
+ const OUString& rOutFile,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pNewEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ bool bVertical
+ )
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont || pFont->m_eType != fonttype::TrueType )
+ return false;
+
+ OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
+ return false;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aFromFile = getFontFile( pFont );
+ ByteString aToFile( OUStringToOString( aSysPath, aEncoding ) );
+
+ sal_uInt8 pEnc[256];
+ sal_uInt16 pGID[256];
+ sal_uInt8 pOldIndex[256];
+
+ memset( pEnc, 0, sizeof( pEnc ) );
+ memset( pGID, 0, sizeof( pGID ) );
+ memset( pOldIndex, 0, sizeof( pOldIndex ) );
+ int nChar = 1;
+ int i;
+ for( i = 0; i < nGlyphs; i++ )
+ {
+ if( pNewEncoding[i] == 0 )
+ {
+ pOldIndex[ 0 ] = i;
+ }
+ else
+ {
+ DBG_ASSERT( !(pGlyphIDs[i] & 0x007f0000), "overlong glyph id" );
+ DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
+ DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
+ pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
+ pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIDs[ i ];
+ pOldIndex[ pNewEncoding[i] ] = i;
+ nChar++;
+ }
+ }
+ nGlyphs = nChar; // either input value or increased by one
+
+ if( nGlyphs > 256 )
+ return false;
+
+ TrueTypeFont* pTTFont = NULL;
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
+ return false;
+
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
+ pGID,
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nGlyphs; i++ )
+ pWidths[pOldIndex[i]] = pMetrics[i].adv;
+ free( pMetrics );
+ }
+ else
+ {
+ CloseTTFont( pTTFont );
+ return false;
+ }
+
+ bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
+ aToFile.GetBuffer(),
+ pGID,
+ pEnc,
+ nGlyphs,
+ 0,
+ NULL,
+ 0 ) );
+ CloseTTFont( pTTFont );
+
+ return bSuccess;
+}
+
+void PrintFontManager::getGlyphWidths( fontID nFont,
+ bool bVertical,
+ std::vector< sal_Int32 >& rWidths,
+ std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont ||
+ (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
+ return;
+ if( pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFont* pTTFont = NULL;
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ ByteString aFromFile = getFontFile( pFont );
+ if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
+ return;
+ int nGlyphs = GetTTGlyphCount( pTTFont );
+ if( nGlyphs > 0 )
+ {
+ rWidths.resize(nGlyphs);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphs);
+ for( int i = 0; i < nGlyphs; i++ )
+ aGlyphIds[i] = sal_uInt16(i);
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
+ &aGlyphIds[0],
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i< nGlyphs; i++ )
+ rWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+ rUnicodeEnc.clear();
+ }
+ }
+ CloseTTFont( pTTFont );
+ }
+ else if( pFont->m_eType == fonttype::Type1 )
+ {
+ if( ! pFont->m_aEncodingVector.size() )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
+ if( pFont->m_pMetrics )
+ {
+ rUnicodeEnc.clear();
+ rWidths.clear();
+ rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
+ for( std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.begin();
+ it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
+ {
+ if( (it->first & 0x00010000) == 0 || bVertical )
+ {
+ rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
+ rWidths.push_back( it->second.width );
+ }
+ }
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, rtl::OString >** pNonEncoded ) const
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont ||
+ (pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
+ )
+ return NULL;
+
+ if( ! pFont->m_aEncodingVector.size() )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
+
+ if( pNonEncoded )
+ *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
+
+ return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
+}
+
+// -------------------------------------------------------------------------
+
+std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
+{
+ std::pair< std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator,
+ std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator > range
+ = m_aUnicodeToAdobename.equal_range( aChar );
+
+ std::list< OString > aRet;
+ for( ; range.first != range.second; ++range.first )
+ aRet.push_back( range.first->second );
+
+ if( aRet.begin() == aRet.end() && aChar != 0 )
+ {
+ sal_Char aBuf[8];
+ sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
+ aRet.push_back( OString( aBuf, nChars ) );
+ }
+
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const rtl::OString& rName ) const
+{
+ std::pair< std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator,
+ std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator > range
+ = m_aAdobenameToUnicode.equal_range( rName );
+
+ std::list< sal_Unicode > aRet;
+ for( ; range.first != range.second; ++range.first )
+ aRet.push_back( range.first->second );
+
+ if( aRet.begin() == aRet.end() )
+ {
+ if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
+ {
+ sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
+ aRet.push_back( aCode );
+ }
+ }
+
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+namespace
+{
+ OUString getString( const Any& rAny )
+ {
+ OUString aStr;
+ rAny >>= aStr;
+ return aStr;
+ }
+ bool getBool( const Any& rAny )
+ {
+ sal_Bool bBool = sal_False;
+ rAny >>= bBool;
+ return static_cast<bool>(bBool);
+ }
+ sal_Int32 getInt( const Any& rAny )
+ {
+ sal_Int32 n = 0;
+ rAny >>= n;
+ return n;
+ }
+}
+bool PrintFontManager::readOverrideMetrics()
+{
+ if( ! m_aOverrideFonts.empty() )
+ return false;
+
+ Reference< XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
+ if( !xFact.is() )
+ return false;
+ Reference< XMaterialHolder > xMat(
+ xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.psprint.CompatMetricOverride" ) ) ),
+ UNO_QUERY );
+ if( !xMat.is() )
+ return false;
+
+ Any aAny( xMat->getMaterial() );
+ Sequence< Any > aOverrideFonts;
+ if( ! (aAny >>= aOverrideFonts ) )
+ return false;
+ sal_Int32 nFonts = aOverrideFonts.getLength();
+ for( sal_Int32 i = 0; i < nFonts; i++ )
+ {
+ Sequence< NamedValue > aMetrics;
+ if( ! (aOverrideFonts.getConstArray()[i] >>= aMetrics) )
+ continue;
+ BuiltinFont* pFont = new BuiltinFont();
+ pFont->m_nDirectory = 0;
+ pFont->m_bUserOverride = false;
+ pFont->m_eEmbeddedbitmap = fcstatus::isunset;
+ pFont->m_eAntialias = fcstatus::isunset;
+ pFont->m_pMetrics = new PrintFontMetrics;
+ memset( pFont->m_pMetrics->m_aPages, 0xff, sizeof( pFont->m_pMetrics->m_aPages ) );
+ pFont->m_pMetrics->m_bKernPairsQueried = true;
+ sal_Int32 nProps = aMetrics.getLength();
+ const NamedValue* pProps = aMetrics.getConstArray();
+ for( sal_Int32 n = 0; n < nProps; n++ )
+ {
+ if( pProps[n].Name.equalsAscii( "FamilyName" ) )
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME,
+ getString(pProps[n].Value),
+ sal_True );
+ else if( pProps[n].Name.equalsAscii( "PSName" ) )
+ pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME,
+ getString(pProps[n].Value),
+ sal_True );
+ else if( pProps[n].Name.equalsAscii( "StyleName" ) )
+ pFont->m_aStyleName = getString(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Italic" ) )
+ pFont->m_eItalic = static_cast<italic::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Width" ) )
+ pFont->m_eWidth = static_cast<width::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Weight" ) )
+ pFont->m_eWeight = static_cast<weight::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Pitch" ) )
+ pFont->m_ePitch = static_cast<pitch::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Encoding" ) )
+ pFont->m_aEncoding = static_cast<rtl_TextEncoding>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "FontEncodingOnly" ) )
+ pFont->m_bFontEncodingOnly = getBool(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricXWidth" ) )
+ pFont->m_aGlobalMetricX.width = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricXHeight" ) )
+ pFont->m_aGlobalMetricX.height = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricYWidth" ) )
+ pFont->m_aGlobalMetricY.width = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricYHeight" ) )
+ pFont->m_aGlobalMetricY.height = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Ascend" ) )
+ pFont->m_nAscend = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Descend" ) )
+ pFont->m_nDescend = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Leading" ) )
+ pFont->m_nLeading = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "XMin" ) )
+ pFont->m_nXMin = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "YMin" ) )
+ pFont->m_nYMin = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "XMax" ) )
+ pFont->m_nXMax = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "YMax" ) )
+ pFont->m_nYMax = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "VerticalSubstitutes" ) )
+ pFont->m_bHaveVerticalSubstitutedGlyphs = getBool(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "EncodingVector" ) )
+ {
+ Sequence< NamedValue > aEncoding;
+ pProps[n].Value >>= aEncoding;
+ sal_Int32 nEnc = aEncoding.getLength();
+ const NamedValue* pEnc = aEncoding.getConstArray();
+ for( sal_Int32 m = 0; m < nEnc; m++ )
+ {
+ sal_Unicode cCode = *pEnc[m].Name.getStr();
+ sal_Int32 nGlyph = getInt(pEnc[m].Value);
+ pFont->m_aEncodingVector[ cCode ] = nGlyph;
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "NonEncoded" ) )
+ {
+ Sequence< NamedValue > aEncoding;
+ pProps[n].Value >>= aEncoding;
+ sal_Int32 nEnc = aEncoding.getLength();
+ const NamedValue* pEnc = aEncoding.getConstArray();
+ for( sal_Int32 m = 0; m < nEnc; m++ )
+ {
+ sal_Unicode cCode = *pEnc[m].Name.getStr();
+ OUString aGlyphName( getString(pEnc[m].Value) );
+ pFont->m_aNonEncoded[ cCode ] = OUStringToOString(aGlyphName,RTL_TEXTENCODING_ASCII_US);
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "CharacterMetrics" ) )
+ {
+ // fill pFont->m_pMetrics->m_aMetrics
+ // expect triples of int: int -> CharacterMetric.{ width, height }
+ Sequence< sal_Int32 > aSeq;
+ pProps[n].Value >>= aSeq;
+ sal_Int32 nInts = aSeq.getLength();
+ const sal_Int32* pInts = aSeq.getConstArray();
+ for( sal_Int32 m = 0; m < nInts; m+=3 )
+ {
+ pFont->m_pMetrics->m_aMetrics[ pInts[m] ].width = static_cast<short int>(pInts[m+1]);
+ pFont->m_pMetrics->m_aMetrics[ pInts[m] ].height = static_cast<short int>(pInts[m+2]);
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "XKernPairs" ) )
+ {
+ // fill pFont->m_pMetrics->m_aXKernPairs
+ // expection name: <unicode1><unicode2> value: ((height << 16)| width)
+ Sequence< NamedValue > aKern;
+ pProps[n].Value >>= aKern;
+ KernPair aPair;
+ const NamedValue* pVals = aKern.getConstArray();
+ int nPairs = aKern.getLength();
+ for( int m = 0; m < nPairs; m++ )
+ {
+ if( pVals[m].Name.getLength() == 2 )
+ {
+ aPair.first = pVals[m].Name.getStr()[0];
+ aPair.second = pVals[m].Name.getStr()[1];
+ sal_Int32 nKern = getInt( pVals[m].Value );
+ aPair.kern_x = static_cast<short int>(nKern & 0xffff);
+ aPair.kern_y = static_cast<short int>((sal_uInt32(nKern) >> 16) & 0xffff);
+ pFont->m_pMetrics->m_aXKernPairs.push_back( aPair );
+ }
+ }
+ }
+ }
+ // sanity check
+ if( pFont->m_nPSName &&
+ pFont->m_nFamilyName &&
+ ! pFont->m_pMetrics->m_aMetrics.empty() )
+ {
+ m_aOverrideFonts.push_back( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = pFont;
+ }
+ else
+ {
+ DBG_ASSERT( 0, "override font failed" );
+ delete pFont;
+ }
+ }
+
+ return true;
+}
diff --git a/vcl/unx/source/fontmanager/helper.cxx b/vcl/unx/source/fontmanager/helper.cxx
new file mode 100644
index 000000000000..2f3821eac7d1
--- /dev/null
+++ b/vcl/unx/source/fontmanager/helper.cxx
@@ -0,0 +1,407 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: helper.cxx,v $
+ * $Revision: 1.35 $
+ *
+ * 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 <cstring>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "vcl/helper.hxx"
+#include "vcl/ppdparser.hxx"
+#include "tools/string.hxx"
+#include "tools/urlobj.hxx"
+#include "osl/file.hxx"
+#include "osl/process.h"
+#include "rtl/bootstrap.hxx"
+
+using namespace rtl;
+
+namespace psp {
+
+OUString getOfficePath( enum whichOfficePath ePath )
+{
+ static OUString aNetPath;
+ static OUString aUserPath;
+ static OUString aConfigPath;
+ static OUString aEmpty;
+ static bool bOnce = false;
+
+ if( ! bOnce )
+ {
+ bOnce = true;
+ OUString aIni;
+ Bootstrap::get( OUString( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aIni );
+ aIni += OUString( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
+ Bootstrap aBootstrap( aIni );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "CustomDataUrl" ) ), aConfigPath );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseInstallation" ) ), aNetPath );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
+ OUString aUPath = aUserPath;
+
+ if( ! aConfigPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aConfigPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aConfigPath = aSysPath;
+ }
+ if( ! aNetPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aNetPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aNetPath = aSysPath;
+ }
+ if( ! aUserPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aUserPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aUserPath = aSysPath;
+ }
+ // ensure user path exists
+ aUPath += OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/psprint" ) );
+ #if OSL_DEBUG_LEVEL > 1
+ oslFileError eErr =
+ #endif
+ osl_createDirectoryPath( aUPath.pData, NULL, NULL );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to create \"%s\" = %d\n", OUStringToOString( aUPath, RTL_TEXTENCODING_UTF8 ).getStr(), eErr );
+ #endif
+ }
+
+ switch( ePath )
+ {
+ case ConfigPath: return aConfigPath;
+ case NetPath: return aNetPath;
+ case UserPath: return aUserPath;
+ }
+ return aEmpty;
+}
+
+static OString getEnvironmentPath( const char* pKey )
+{
+ OString aPath;
+
+ const char* pValue = getenv( pKey );
+ if( pValue && *pValue )
+ {
+ aPath = OString( pValue );
+ }
+ return aPath;
+}
+
+} // namespace psp
+
+void psp::getPrinterPathList( std::list< OUString >& rPathList, const char* pSubDir )
+{
+ rPathList.clear();
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+
+ OUStringBuffer aPathBuffer( 256 );
+
+ // append net path
+ aPathBuffer.append( getOfficePath( psp::NetPath ) );
+ if( aPathBuffer.getLength() )
+ {
+ aPathBuffer.appendAscii( "/share/psprint" );
+ if( pSubDir )
+ {
+ aPathBuffer.append( sal_Unicode('/') );
+ aPathBuffer.appendAscii( pSubDir );
+ }
+ rPathList.push_back( aPathBuffer.makeStringAndClear() );
+ }
+ // append user path
+ aPathBuffer.append( getOfficePath( psp::UserPath ) );
+ if( aPathBuffer.getLength() )
+ {
+ aPathBuffer.appendAscii( "/user/psprint" );
+ if( pSubDir )
+ {
+ aPathBuffer.append( sal_Unicode('/') );
+ aPathBuffer.appendAscii( pSubDir );
+ }
+ rPathList.push_back( aPathBuffer.makeStringAndClear() );
+ }
+
+ OString aPath( getEnvironmentPath("SAL_PSPRINT") );
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aDir( aPath.getToken( 0, ':', nIndex ) );
+ if( ! aDir.getLength() )
+ continue;
+
+ if( pSubDir )
+ {
+ aDir += "/";
+ aDir += pSubDir;
+ }
+ struct stat aStat;
+ if( stat( aDir.getStr(), &aStat ) || ! S_ISDIR( aStat.st_mode ) )
+ continue;
+
+ rPathList.push_back( OStringToOUString( aDir, aEncoding ) );
+ } while( nIndex != -1 );
+
+ #ifdef SYSTEM_PPD_DIR
+ if( pSubDir && rtl_str_compare( pSubDir, PRINTER_PPDDIR ) == 0 )
+ {
+ rPathList.push_back( rtl::OStringToOUString( rtl::OString( SYSTEM_PPD_DIR ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ #endif
+
+ if( rPathList.empty() )
+ {
+ // last resort: next to program file (mainly for setup)
+ OUString aExe;
+ if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None )
+ {
+ INetURLObject aDir( aExe );
+ aDir.removeSegment();
+ aExe = aDir.GetMainURL( INetURLObject::NO_DECODE );
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aExe.pData, &aSysPath.pData ) == osl_File_E_None )
+ {
+ rPathList.push_back( aSysPath );
+ }
+ }
+ }
+}
+
+OUString psp::getFontPath()
+{
+ static OUString aPath;
+
+ if( ! aPath.getLength() )
+ {
+ OUStringBuffer aPathBuffer( 512 );
+
+ OUString aConfigPath( getOfficePath( psp::ConfigPath ) );
+ OUString aNetPath( getOfficePath( psp::NetPath ) );
+ OUString aUserPath( getOfficePath( psp::UserPath ) );
+ if( aConfigPath.getLength() )
+ {
+ // #i53530# Path from CustomDataUrl will completely
+ // replace net and user paths if the path exists
+ aPathBuffer.append(aConfigPath);
+ aPathBuffer.appendAscii("/share/fonts");
+ // check existance of config path
+ struct stat aStat;
+ if( 0 != stat( OUStringToOString( aPathBuffer.makeStringAndClear(), osl_getThreadTextEncoding() ).getStr(), &aStat )
+ || ! S_ISDIR( aStat.st_mode ) )
+ aConfigPath = OUString();
+ else
+ {
+ aPathBuffer.append(aConfigPath);
+ aPathBuffer.appendAscii("/share/fonts");
+ }
+ }
+ if( aConfigPath.getLength() == 0 )
+ {
+ if( aNetPath.getLength() )
+ {
+ aPathBuffer.append( aNetPath );
+ aPathBuffer.appendAscii( "/share/fonts/truetype;");
+ aPathBuffer.append( aNetPath );
+ aPathBuffer.appendAscii( "/share/fonts/type1;" );
+ }
+ if( aUserPath.getLength() )
+ {
+ aPathBuffer.append( aUserPath );
+ aPathBuffer.appendAscii( "/user/fonts" );
+ }
+ }
+ OString aEnvPath( getEnvironmentPath( "SAL_FONTPATH_PRIVATE" ) );
+ if( aEnvPath.getLength() )
+ {
+ aPathBuffer.append( sal_Unicode(';') );
+ aPathBuffer.append( OStringToOUString( aEnvPath, osl_getThreadTextEncoding() ) );
+ }
+
+ aPath = aPathBuffer.makeStringAndClear();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "initializing font path to \"%s\"\n", OUStringToOString( aPath, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ }
+ return aPath;
+}
+
+bool psp::convertPfbToPfa( ::osl::File& rInFile, ::osl::File& rOutFile )
+{
+ static unsigned char hexDigits[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ bool bSuccess = true;
+ bool bEof = false;
+ unsigned char buffer[256];
+ sal_uInt64 nRead;
+ sal_uInt64 nOrgPos = 0;
+ rInFile.getPos( nOrgPos );
+
+ while( bSuccess && ! bEof )
+ {
+ // read leading bytes
+ bEof = ! rInFile.read( buffer, 6, nRead ) && nRead == 6 ? false : true;
+ unsigned int nType = buffer[ 1 ];
+ unsigned int nBytesToRead = buffer[2] | buffer[3] << 8 | buffer[4] << 16 | buffer[5] << 24;
+ if( buffer[0] != 0x80 ) // test for pfb m_agic number
+ {
+ // this migt be a pfa font already
+ sal_uInt64 nWrite = 0;
+ if( ! rInFile.read( buffer+6, 9, nRead ) && nRead == 9 &&
+ ( ! std::strncmp( (char*)buffer, "%!FontType1-", 12 ) ||
+ ! std::strncmp( (char*)buffer, "%!PS-AdobeFont-", 15 ) ) )
+ {
+ if( rOutFile.write( buffer, 15, nWrite ) || nWrite != 15 )
+ bSuccess = false;
+ while( bSuccess &&
+ ! rInFile.read( buffer, sizeof( buffer ), nRead ) &&
+ nRead != 0 )
+ {
+ if( rOutFile.write( buffer, nRead, nWrite ) ||
+ nWrite != nRead )
+ bSuccess = false;
+ }
+ bEof = true;
+ }
+ else
+ bSuccess = false;
+ }
+ else if( nType == 1 || nType == 2 )
+ {
+ unsigned char* pBuffer = new unsigned char[ nBytesToRead+1 ];
+
+ if( ! rInFile.read( pBuffer, nBytesToRead, nRead ) && nRead == nBytesToRead )
+ {
+ if( nType == 1 )
+ {
+ // ascii data, convert dos lineends( \r\n ) and
+ // m_ac lineends( \r ) to \n
+ unsigned char * pWriteBuffer = new unsigned char[ nBytesToRead ];
+ unsigned int nBytesToWrite = 0;
+ for( unsigned int i = 0; i < nBytesToRead; i++ )
+ {
+ if( pBuffer[i] != '\r' )
+ pWriteBuffer[ nBytesToWrite++ ] = pBuffer[i];
+ else if( pBuffer[ i+1 ] == '\n' )
+ {
+ i++;
+ pWriteBuffer[ nBytesToWrite++ ] = '\n';
+ }
+ else
+ pWriteBuffer[ nBytesToWrite++ ] = '\n';
+ }
+ if( rOutFile.write( pWriteBuffer, nBytesToWrite, nRead ) || nRead != nBytesToWrite )
+ bSuccess = false;
+
+ delete [] pWriteBuffer;
+ }
+ else
+ {
+ // binary data
+ unsigned int nBuffer = 0;
+ for( unsigned int i = 0; i < nBytesToRead && bSuccess; i++ )
+ {
+ buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] >> 4 ];
+ buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] & 15 ];
+ if( nBuffer >= 80 )
+ {
+ buffer[ nBuffer++ ] = '\n';
+ if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
+ bSuccess = false;
+ nBuffer = 0;
+ }
+ }
+ if( nBuffer > 0 && bSuccess )
+ {
+ buffer[ nBuffer++ ] = '\n';
+ if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
+ bSuccess = false;
+ }
+ }
+ }
+ else
+ bSuccess = false;
+
+ delete [] pBuffer;
+ }
+ else if( nType == 3 )
+ bEof = true;
+ else
+ bSuccess = false;
+ }
+
+ return bSuccess;
+}
+
+void psp::normPath( OString& rPath )
+{
+ char buf[PATH_MAX];
+
+ ByteString aPath( rPath );
+
+ // double slashes and slash at end are probably
+ // removed by realpath anyway, but since this runs
+ // on many different platforms let's play it safe
+ while( aPath.SearchAndReplace( "//", "/" ) != STRING_NOTFOUND )
+ ;
+ if( aPath.Len() > 0 && aPath.GetChar( aPath.Len()-1 ) == '/' )
+ aPath.Erase( aPath.Len()-1 );
+
+ if( ( aPath.Search( "./" ) != STRING_NOTFOUND ||
+ aPath.Search( "~" ) != STRING_NOTFOUND )
+ && realpath( aPath.GetBuffer(), buf ) )
+ {
+ rPath = buf;
+ }
+ else
+ {
+ rPath = aPath;
+ }
+}
+
+void psp::splitPath( OString& rPath, OString& rDir, OString& rBase )
+{
+ normPath( rPath );
+ sal_Int32 nIndex = rPath.lastIndexOf( '/' );
+ if( nIndex > 0 )
+ rDir = rPath.copy( 0, nIndex );
+ else if( nIndex == 0 ) // root dir
+ rDir = rPath.copy( 0, 1 );
+ if( rPath.getLength() > nIndex+1 )
+ rBase = rPath.copy( nIndex+1 );
+}
+
+
diff --git a/vcl/unx/source/fontmanager/makefile.mk b/vcl/unx/source/fontmanager/makefile.mk
new file mode 100644
index 000000000000..c1d1fde15de3
--- /dev/null
+++ b/vcl/unx/source/fontmanager/makefile.mk
@@ -0,0 +1,76 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.11 $
+#
+# 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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+ENABLE_EXCEPTIONS=TRUE
+PRJNAME=vcl
+TARGET=fontman
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+CFLAGS+= -I..$/fontsubset
+INCDEPN+= -I..$/fontsubset
+
+.IF "$(ENABLE_FONTCONFIG)" != ""
+CDEFS += -DENABLE_FONTCONFIG
+.ENDIF
+
+CFLAGS+=$(FREETYPE_CFLAGS)
+
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"=="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"=="aqua"
+
+SLOFILES=\
+ $(SLO)$/fontmanager.obj \
+ $(SLO)$/fontcache.obj \
+ $(SLO)$/fontconfig.obj \
+ $(SLO)$/helper.obj \
+ $(SLO)$/parseAFM.obj
+
+.IF "$(OS)$(CPU)"=="SOLARISI"
+NOOPTFILES=$(SLO)$/fontmanager.obj
+.ENDIF
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/unx/source/fontmanager/parseAFM.cxx b/vcl/unx/source/fontmanager/parseAFM.cxx
new file mode 100644
index 000000000000..0ac4754d4bd5
--- /dev/null
+++ b/vcl/unx/source/fontmanager/parseAFM.cxx
@@ -0,0 +1,1569 @@
+/*
+ * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - performance increase:
+ * - fread file in one pass
+ * - replace file io by buffer access
+ * 10/20/2005 pl - performance increase:
+ * - use one table lookup in token() routine
+ * instead of many conditions
+ * - return token length in toke() routine
+ * - use hash lookup instead of binary search
+ * in recognize() routine
+ */
+
+/*************************************************************************
+ *
+ * $RCSfile: parseAFM.cxx,v $
+ *
+ * $Revision: 1.11 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-29 16:08:31 $
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+/* parseAFM.c
+ *
+ * This file is used in conjuction with the parseAFM.h header file.
+ * This file contains several procedures that are used to parse AFM
+ * files. It is intended to work with an application program that needs
+ * font metric information. The program can be used as is by making a
+ * procedure call to "parseFile" (passing in the expected parameters)
+ * and having it fill in a data structure with the data from the
+ * AFM file, or an application developer may wish to customize this
+ * code.
+ *
+ * There is also a file, parseAFMclient.c, that is a sample application
+ * showing how to call the "parseFile" procedure and how to use the data
+ * after "parseFile" has returned.
+ *
+ * Please read the comments in parseAFM.h and parseAFMclient.c.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed bug of not allocating extra byte for string duplication
+ * - fixed typos
+ * modified: DSM Tue Apr 3 11:18:34 PDT 1990
+ * - added free(ident) at end of parseFile routine
+ * modified: DSM Tue Jun 19 10:16:29 PDT 1990
+ * - changed (width == 250) to (width = 250) in initializeArray
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <math.h>
+
+#include "parseAFM.hxx"
+#include "vcl/strhelper.hxx"
+
+#include "rtl/alloc.h"
+
+#define lineterm EOL /* line terminating character */
+#define normalEOF 1 /* return code from parsing routines used only */
+/* in this module */
+#define Space "space" /* used in string comparison to look for the width */
+/* of the space character to init the widths array */
+#define False "false" /* used in string comparison to check the value of */
+/* boolean keys (e.g. IsFixedPitch) */
+
+#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
+
+namespace psp {
+
+class FileInputStream
+{
+ char* m_pMemory;
+ unsigned int m_nPos;
+ unsigned int m_nLen;
+ public:
+ FileInputStream( const char* pFilename );
+ ~FileInputStream();
+
+ int getChar() { return (m_nPos < m_nLen) ? int(m_pMemory[m_nPos++]) : -1; }
+ void ungetChar()
+ {
+ if( m_nPos > 0 )
+ m_nPos--;
+ }
+ unsigned int tell() const { return m_nPos; }
+ void seek( unsigned int nPos )
+ // NOTE: do not check input data since only results of tell()
+ // get seek()ed in this file
+ { m_nPos = nPos; }
+};
+
+FileInputStream::FileInputStream( const char* pFilename ) :
+ m_pMemory( NULL ),
+ m_nPos( 0 ),
+ m_nLen( 0 )
+{
+ struct stat aStat;
+ if( ! stat( pFilename, &aStat ) &&
+ S_ISREG( aStat.st_mode ) &&
+ aStat.st_size > 0
+ )
+ {
+ FILE* fp = fopen( pFilename, "r" );
+ if( fp )
+ {
+ m_pMemory = (char*)rtl_allocateMemory( aStat.st_size );
+ m_nLen = (unsigned int)fread( m_pMemory, 1, aStat.st_size, fp );
+ fclose( fp );
+ }
+ }
+}
+
+FileInputStream::~FileInputStream()
+{
+ rtl_freeMemory( m_pMemory );
+}
+
+/*************************** GLOBALS ***********************/
+/* "shorts" for fast case statement
+ * The values of each of these enumerated items correspond to an entry in the
+ * table of strings defined below. Therefore, if you add a new string as
+ * new keyword into the keyStrings table, you must also add a corresponding
+ * parseKey AND it MUST be in the same position!
+ *
+ * IMPORTANT: since the sorting algorithm is a binary search, the strings of
+ * keywords must be placed in lexicographical order, below. [Therefore, the
+ * enumerated items are not necessarily in lexicographical order, depending
+ * on the name chosen. BUT, they must be placed in the same position as the
+ * corresponding key string.] The NOPE shall remain in the last position,
+ * since it does not correspond to any key string, and it is used in the
+ * "recognize" procedure to calculate how many possible keys there are.
+ */
+
+// some metrics have Ascent, Descent instead Ascender, Descender or Em
+// which is not allowed per afm spcification, but let us handle
+// this gently
+enum parseKey {
+ ASCENDER, ASCENT, CHARBBOX, CODE, COMPCHAR, CODEHEX, CAPHEIGHT, CHARWIDTH, CHARACTERSET, CHARACTERS, COMMENT,
+ DESCENDER, DESCENT, EM, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, ENDDIRECTION,
+ ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
+ FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISBASEFONT, ISFIXEDPITCH,
+ ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, MAPPINGSCHEME, METRICSSETS, CHARNAME,
+ NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, STARTDIRECTION,
+ STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
+ STARTTRACKKERN, STDHW, STDVW, TRACKKERN, UNDERLINEPOSITION,
+ UNDERLINETHICKNESS, VVECTOR, VERSION, XYWIDTH, X0WIDTH, XWIDTH, WEIGHT, XHEIGHT,
+ NOPE
+};
+
+/*************************** PARSING ROUTINES **************/
+
+/*************************** token *************************/
+
+/* A "AFM file Conventions" tokenizer. That means that it will
+ * return the next token delimited by white space. See also
+ * the `linetoken' routine, which does a similar thing but
+ * reads all tokens until the next end-of-line.
+ */
+
+// token white space is ' ', '\n', '\r', ',', '\t', ';'
+static const bool is_white_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, true, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, false, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+// token delimiters are ' ', '\n', '\r', '\t', ':', ';'
+static const bool is_delimiter_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, false, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, true, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+static char *token( FileInputStream* stream, int& rLen )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+
+ int ch, idx;
+
+ /* skip over white space */
+ // relies on EOF = -1
+ while( is_white_Array[ (ch = stream->getChar()) & 255 ] )
+ ;
+
+ idx = 0;
+ while( ch != -1 && ! is_delimiter_Array[ ch & 255 ] && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ }
+
+ if (ch == -1 && idx < 1) return ((char *)NULL);
+ if (idx >= 1 && ch != ':' && ch != -1) stream->ungetChar();
+ if (idx < 1 ) ident[idx++] = ch; /* single-character token */
+ ident[idx] = 0;
+ rLen = idx;
+
+ return(ident); /* returns pointer to the token */
+
+} /* token */
+
+
+/*************************** linetoken *************************/
+
+/* "linetoken" will get read all tokens until the EOL character from
+ * the given stream. This is used to get any arguments that can be
+ * more than one word (like Comment lines and FullName).
+ */
+
+static char *linetoken( FileInputStream* stream )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+ int ch, idx;
+
+ while ((ch = stream->getChar()) == ' ' || ch == '\t' ) ;
+
+ idx = 0;
+ while (ch != -1 && ch != lineterm && ch != '\r' && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ } /* while */
+
+ stream->ungetChar();
+ ident[idx] = 0;
+
+ return(ident); /* returns pointer to the token */
+
+} /* linetoken */
+
+
+/*************************** recognize *************************/
+
+/* This function tries to match a string to a known list of
+ * valid AFM entries (check the keyStrings array above).
+ * "ident" contains everything from white space through the
+ * next space, tab, or ":" character.
+ *
+ * The algorithm is a standard Knuth binary search.
+ */
+#include "afm_hash.cpp"
+
+static inline enum parseKey recognize( register char* ident, int len)
+{
+ const hash_entry* pEntry = AfmKeywordHash::in_word_set( ident, len );
+ return pEntry ? pEntry->eKey : NOPE;
+
+} /* recognize */
+
+
+/************************* parseGlobals *****************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "StartCharMetrics" keyword, which essentially marks the
+ * end of the Global Font Information and the beginning of the character
+ * metrics information.
+ *
+ * If the caller of "parseFile" specified that it wanted the Global
+ * Font Information (as defined by the "AFM file Specification"
+ * document), then that information will be stored in the returned
+ * data structure.
+ *
+ * Any Global Font Information entries that are not found in a
+ * given file, will have the usual default initialization value
+ * for its type (i.e. entries of type int will be 0, etc).
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseGlobals( FileInputStream* fp, register GlobalFontInfo* gfi )
+{
+ bool cont = true, save = (gfi != NULL);
+ int error = ok;
+ register char *keyword;
+ int direction = -1;
+ int tokenlen;
+
+ while (cont)
+ {
+ keyword = token(fp, tokenlen);
+
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Global Font info section */
+ /* without saving any of the data */
+ switch (recognize(keyword, tokenlen))
+ {
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire global font info section, */
+ /* saving the data */
+ switch(recognize(keyword, tokenlen))
+ {
+ case STARTFONTMETRICS:
+ keyword = token(fp,tokenlen);
+ gfi->afmVersion = strdup( keyword );
+ break;
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case FONTNAME:
+ keyword = token(fp, tokenlen);
+ gfi->fontName = strdup( keyword );
+ break;
+ case ENCODINGSCHEME:
+ keyword = token(fp, tokenlen);
+ gfi->encodingScheme = strdup( keyword );
+ break;
+ case FULLNAME:
+ keyword = linetoken(fp);
+ gfi->fullName = strdup( keyword );
+ break;
+ case FAMILYNAME:
+ keyword = linetoken(fp);
+ gfi->familyName = strdup( keyword );
+ break;
+ case WEIGHT:
+ keyword = token(fp, tokenlen);
+ gfi->weight = strdup( keyword );
+ break;
+ case ITALICANGLE:
+ keyword = token(fp,tokenlen);
+ gfi->italicAngle = StringToDouble( keyword );
+ break;
+ case ISFIXEDPITCH:
+ keyword = token(fp,tokenlen);
+ if (MATCH(keyword, False))
+ gfi->isFixedPitch = 0;
+ else
+ gfi->isFixedPitch = 1;
+ break;
+ case UNDERLINEPOSITION:
+ keyword = token(fp,tokenlen);
+ gfi->underlinePosition = atoi(keyword);
+ break;
+ case UNDERLINETHICKNESS:
+ keyword = token(fp,tokenlen);
+ gfi->underlineThickness = atoi(keyword);
+ break;
+ case VERSION:
+ keyword = token(fp,tokenlen);
+ gfi->version = strdup( keyword );
+ break;
+ case NOTICE:
+ keyword = linetoken(fp);
+ gfi->notice = strdup( keyword );
+ break;
+ case FONTBBOX:
+ keyword = token(fp,tokenlen);
+ gfi->fontBBox.llx = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ gfi->fontBBox.lly = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ gfi->fontBBox.urx = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ gfi->fontBBox.ury = atoi(keyword);
+ break;
+ case CAPHEIGHT:
+ keyword = token(fp,tokenlen);
+ gfi->capHeight = atoi(keyword);
+ break;
+ case XHEIGHT:
+ keyword = token(fp,tokenlen);
+ gfi->xHeight = atoi(keyword);
+ break;
+ case DESCENT:
+ keyword = token(fp,tokenlen);
+ gfi->descender = -atoi(keyword);
+ break;
+ case DESCENDER:
+ keyword = token(fp,tokenlen);
+ gfi->descender = atoi(keyword);
+ break;
+ case ASCENT:
+ case ASCENDER:
+ keyword = token(fp,tokenlen);
+ gfi->ascender = atoi(keyword);
+ break;
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case EM:
+ // skip one token
+ keyword = token(fp,tokenlen);
+ break;
+ case STARTDIRECTION:
+ keyword = token(fp,tokenlen);
+ direction = atoi(keyword);
+ break; /* ignore this for now */
+ case ENDDIRECTION:
+ break; /* ignore this for now */
+ case MAPPINGSCHEME:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case ISBASEFONT:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERSET:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDHW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDVW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case CHARWIDTH:
+ keyword = token(fp,tokenlen);
+ if (direction == 0)
+ gfi->charwidth = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ /* ignore y-width for now */
+ break;
+ case METRICSSETS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseGlobals */
+
+
+#if 0
+/************************* initializeArray ************************/
+
+/* Unmapped character codes are (at Adobe Systems) assigned the
+ * width of the space character (if one exists) else they get the
+ * value of 250 ems. This function initializes all entries in the
+ * char widths array to have this value. Then any mapped character
+ * codes will be replaced with the width of the appropriate character
+ * when parsing the character metric section.
+
+ * This function parses the Character Metrics Section looking
+ * for a space character (by comparing character names). If found,
+ * the width of the space character will be used to initialize the
+ * values in the array of character widths.
+ *
+ * Before returning, the position of the read/write pointer of the
+ * FileInputStream is reset to be where it was upon entering this function.
+ */
+
+static int initializeArray( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, found = false;
+ unsigned int opos = fp->tell();
+ int code = 0, width = 0, i = 0, error = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ code = atoi(token(fp,tokenlen));
+ break;
+ case CODEHEX:
+ sscanf(token(fp,tokenlen),"<%x>", &code);
+ break;
+ case XWIDTH:
+ width = atoi(token(fp,tokenlen));
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case CHARNAME:
+ keyword = token(fp,tokenlen);
+ if (MATCH(keyword, Space))
+ {
+ cont = false;
+ found = true;
+ }
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (!found)
+ width = 250;
+
+ for (i = 0; i < 256; ++i)
+ cwi[i] = width;
+
+ fp->seek(opos);
+
+ return(error);
+
+} /* initializeArray */
+#endif
+
+/************************* parseCharWidths **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndCharMetrics" keyword. It will save the character
+ * width info (as opposed to all of the character metric information)
+ * if requested by the caller of parseFile. Otherwise, it will just
+ * parse through the section without saving any information.
+ *
+ * If data is to be saved, parseCharWidths is passed in a pointer
+ * to an array of widths that has already been initialized by the
+ * standard value for unmapped character codes. This function parses
+ * the Character Metrics section only storing the width information
+ * for the encoded characters into the array using the character code
+ * as the index into that array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharWidths( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, save = (cwi != NULL);
+ int pos = 0, error = ok, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Char Metrics section without */
+ /* saving any of the data*/
+ switch (recognize(keyword,tokenlen))
+ {
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire char metrics section, saving */
+ /* only the char x-width info */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ keyword = token(fp,tokenlen);
+ pos = atoi(keyword);
+ break;
+ case XYWIDTH:
+ /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); /* eat values */
+ error = parseError;
+ break;
+ case CODEHEX:
+ keyword = token(fp,tokenlen);
+ sscanf(keyword, "<%x>", &pos);
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case XWIDTH:
+ keyword = token(fp,tokenlen);
+ if (pos >= 0) /* ignore unmapped chars */
+ cwi[pos] = atoi(keyword);
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case CHARNAME: /* eat values (so doesn't cause parseError) */
+ keyword = token(fp,tokenlen);
+ break;
+ case CHARBBOX:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case LIGATURE:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseCharWidths */
+
+
+/*
+ * number of char metrics is almost allways inaccurate, so be gentle and try to
+ * adapt our internal storage by adjusting the allocated list
+ */
+
+static int
+reallocFontMetrics( void **pp_fontmetrics, int *p_oldcount, int n_newcount, unsigned int n_size )
+{
+ char *p_tmpmetrics = NULL;
+
+ if ((pp_fontmetrics == NULL) || (*pp_fontmetrics == NULL))
+ return storageProblem;
+
+ if (*p_oldcount == n_newcount)
+ return ok;
+
+ p_tmpmetrics = (char*)realloc(*pp_fontmetrics, n_newcount * n_size);
+ if (p_tmpmetrics == NULL)
+ return storageProblem;
+
+ if ( n_newcount > *p_oldcount )
+ {
+ char *p_inimetrics = p_tmpmetrics + n_size * *p_oldcount;
+ int n_inimetrics = n_size * (n_newcount - *p_oldcount);
+ memset( p_inimetrics, 0, n_inimetrics );
+ }
+
+ *pp_fontmetrics = p_tmpmetrics;
+ *p_oldcount = n_newcount;
+
+ return ok;
+}
+
+static unsigned int
+enlargeCount( unsigned int n_oldcount )
+{
+ unsigned int n_newcount = n_oldcount + n_oldcount / 5;
+ if (n_oldcount == n_newcount )
+ n_newcount = n_oldcount + 5;
+
+ return n_newcount;
+}
+
+/************************* parseCharMetrics ************************/
+
+/* This function is called by parseFile if the caller of parseFile
+ * requested that all character metric information be saved
+ * (as opposed to only the character width information).
+ *
+ * parseCharMetrics is passed in a pointer to an array of records
+ * to hold information on a per character basis. This function
+ * parses the Character Metrics section storing all character
+ * metric information for the ALL characters (mapped and unmapped)
+ * into the array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharMetrics( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true;
+ int error = ok, count = 0, tokenlen;
+ register CharMetricInfo *temp = fi->cmi;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if (!(count < fi->numOfChars))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars)
+ {
+ if (firstTime) firstTime = false;
+ else temp++;
+ temp->code = atoi(token(fp,tokenlen));
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case CODEHEX:
+ if (!(count < fi->numOfChars ))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars) {
+ if (firstTime)
+ firstTime = false;
+ else
+ temp++;
+ sscanf(token(fp,tokenlen),"<%x>", &temp->code);
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case XYWIDTH:
+ temp->wx = atoi(token(fp,tokenlen));
+ temp->wy = atoi(token(fp,tokenlen));
+ break;
+ case X0WIDTH:
+ temp->wx = atoi(token(fp,tokenlen));
+ break;
+ case XWIDTH:
+ temp->wx = atoi(token(fp,tokenlen));
+ break;
+ case CHARNAME:
+ keyword = token(fp,tokenlen);
+ temp->name = (char *)strdup(keyword);
+ break;
+ case CHARBBOX:
+ temp->charBBox.llx = atoi(token(fp,tokenlen));
+ temp->charBBox.lly = atoi(token(fp,tokenlen));
+ temp->charBBox.urx = atoi(token(fp,tokenlen));
+ temp->charBBox.ury = atoi(token(fp,tokenlen));
+ break;
+ case LIGATURE: {
+ Ligature **tail = &(temp->ligs);
+ Ligature *node = *tail;
+
+ if (*tail != NULL)
+ {
+ while (node->next != NULL)
+ node = node->next;
+ tail = &(node->next);
+ }
+
+ *tail = (Ligature *) calloc(1, sizeof(Ligature));
+ keyword = token(fp,tokenlen);
+ (*tail)->succ = (char *)strdup(keyword);
+ keyword = token(fp,tokenlen);
+ (*tail)->lig = (char *)strdup(keyword);
+ break; }
+ case ENDCHARMETRICS:
+ cont = false;;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = reallocFontMetrics( (void**)&(fi->cmi), &(fi->numOfChars),
+ count, sizeof(CharMetricInfo) );
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = parseError;
+
+ return(error);
+
+} /* parseCharMetrics */
+
+
+
+/************************* parseTrackKernData ***********************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
+ * track kerning data if requested by the caller of parseFile.
+ *
+ * parseTrackKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the track kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseTrackKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->tkd != NULL);
+ int pos = 0, error = ok, tcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Track Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Track Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case TRACKKERN:
+ if (!(tcount < fi->numOfTracks))
+ {
+ reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ enlargeCount(fi->numOfTracks), sizeof(TrackKernData) );
+ }
+
+ if (tcount < fi->numOfTracks)
+ {
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos].degree = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos].minPtSize = StringToDouble(keyword);
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos].minKernAmt = StringToDouble(keyword);
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos].maxPtSize = StringToDouble(keyword);
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos++].maxKernAmt = StringToDouble(keyword);
+ tcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ tcount, sizeof(TrackKernData) );
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = parseError;
+
+ return(error);
+
+} /* parseTrackKernData */
+
+
+/************************* parsePairKernData ************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndKernPairs" or "EndKernData" keywords. It will save
+ * the pair kerning data if requested by the caller of parseFile.
+ *
+ * parsePairKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the pair kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parsePairKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->pkd != NULL);
+ int pos = 0, error = ok, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Pair Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Pair Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case KERNPAIR:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].name1 = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].name2 = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].xamt = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos++].yamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case KERNPAIRXAMT:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].name1 = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].name2 = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos++].xamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (pcount != fi->numOfPairs))
+ error = reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ pcount, sizeof(PairKernData) );
+
+ if (error == ok && pcount != fi->numOfPairs)
+ error = parseError;
+
+ return(error);
+
+} /* parsePairKernData */
+
+
+/************************* parseCompCharData **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndComposites" keyword. It will save the composite
+ * character data if requested by the caller of parseFile.
+ *
+ * parseCompCharData is passed in a pointer to the FontInfo record, and
+ * a boolean representing if the data should be saved.
+ *
+ * This function will create the appropriate amount of storage for
+ * the composite character data and store a pointer to the storage
+ * in the FontInfo record.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCompCharData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true, save = (fi->ccd != NULL);
+ int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (ccount > fi->numOfComps)
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount > fi->numOfComps)
+ {
+ error = parseError;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Composite Character info */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case COMMENT:
+ case COMPCHAR:
+ keyword = linetoken(fp);
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Composite Character info section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case COMPCHAR:
+ if (!(ccount < fi->numOfComps))
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount < fi->numOfComps)
+ {
+ keyword = token(fp,tokenlen);
+ if (pcount != fi->ccd[pos].numOfPieces)
+ error = parseError;
+ pcount = 0;
+ if (firstTime) firstTime = false;
+ else pos++;
+ fi->ccd[pos].ccName = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->ccd[pos].numOfPieces = atoi(keyword);
+ fi->ccd[pos].pieces = (Pcc *)
+ calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
+ j = 0;
+ ccount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case COMPCHARPIECE:
+ if (pcount < fi->ccd[pos].numOfPieces)
+ {
+ keyword = token(fp,tokenlen);
+ fi->ccd[pos].pieces[j].pccName = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->ccd[pos].pieces[j].deltax = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
+ pcount++;
+ }
+ else
+ error = parseError;
+ break;
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && ccount != fi->numOfComps)
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ ccount, sizeof(CompCharData) );
+
+ if (error == ok && ccount != fi->numOfComps)
+ error = parseError;
+
+ return(error);
+
+} /* parseCompCharData */
+
+
+
+
+/*************************** 'PUBLIC' FUNCTION ********************/
+
+
+/*************************** parseFile *****************************/
+
+/* parseFile is the only 'public' procedure available. It is called
+ * from an application wishing to get information from an AFM file.
+ * The caller of this function is responsible for locating and opening
+ * an AFM file and handling all errors associated with that task.
+ *
+ * parseFile expects 3 parameters: a filename pointer, a pointer
+ * to a (FontInfo *) variable (for which storage will be allocated and
+ * the data requested filled in), and a mask specifying which
+ * data from the AFM file should be saved in the FontInfo structure.
+ *
+ * The file will be parsed and the requested data will be stored in
+ * a record of type FontInfo (refer to ParseAFM.h).
+ *
+ * parseFile returns an error code as defined in parseAFM.h.
+ *
+ * The position of the read/write pointer associated with the file
+ * pointer upon return of this function is undefined.
+ */
+
+int parseFile( const char* pFilename, FontInfo** fi, FLAGS flags)
+{
+ FileInputStream aFile( pFilename );
+
+ int code = ok; /* return code from each of the parsing routines */
+ int error = ok; /* used as the return code from this function */
+ int tokenlen;
+
+ register char *keyword; /* used to store a token */
+
+
+ (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
+ if ((*fi) == NULL) {error = storageProblem; return(error);}
+
+ if (flags & P_G)
+ {
+ (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
+ if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}
+ }
+
+ /* The AFM file begins with Global Font Information. This section */
+ /* will be parsed whether or not information should be saved. */
+ code = parseGlobals(&aFile, (*fi)->gfi);
+
+ if (code < 0) error = code;
+
+ /* The Global Font Information is followed by the Character Metrics */
+ /* section. Which procedure is used to parse this section depends on */
+ /* how much information should be saved. If all of the metrics info */
+ /* is wanted, parseCharMetrics is called. If only the character widths */
+ /* is wanted, parseCharWidths is called. parseCharWidths will also */
+ /* be called in the case that no character data is to be saved, just */
+ /* to parse through the section. */
+
+ if ((code != normalEOF) && (code != earlyEOF))
+ {
+ (*fi)->numOfChars = atoi(token(&aFile,tokenlen));
+ if (flags & (P_M ^ P_W))
+ {
+ (*fi)->cmi = (CharMetricInfo *)
+ calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
+ if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
+ code = parseCharMetrics(&aFile, *fi);
+ }
+ else
+ {
+ if (flags & P_W)
+ {
+ (*fi)->cwi = (int *) calloc(256, sizeof(int));
+ if ((*fi)->cwi == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ }
+ /* parse section regardless */
+ code = parseCharWidths(&aFile, (*fi)->cwi);
+ } /* else */
+ } /* if */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ /* The remaining sections of the AFM are optional. This code will */
+ /* look at the next keyword in the file to determine what section */
+ /* is next, and then allocate the appropriate amount of storage */
+ /* for the data (if the data is to be saved) and call the */
+ /* appropriate parsing routine to parse the section. */
+
+ while ((code != normalEOF) && (code != earlyEOF))
+ {
+ keyword = token(&aFile,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ code = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case STARTKERNDATA:
+ break;
+ case ENDKERNDATA:
+ break;
+ case STARTTRACKKERN:
+ keyword = token(&aFile,tokenlen);
+ if (flags & P_T)
+ {
+ (*fi)->numOfTracks = atoi(keyword);
+ (*fi)->tkd = (TrackKernData *)
+ calloc((*fi)->numOfTracks, sizeof(TrackKernData));
+ if ((*fi)->tkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseTrackKernData(&aFile, *fi);
+ break;
+ case STARTKERNPAIRS:
+ keyword = token(&aFile,tokenlen);
+ if (flags & P_P)
+ {
+ (*fi)->numOfPairs = atoi(keyword);
+ (*fi)->pkd = (PairKernData *)
+ calloc((*fi)->numOfPairs, sizeof(PairKernData));
+ if ((*fi)->pkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parsePairKernData(&aFile, *fi);
+ break;
+ case STARTCOMPOSITES:
+ keyword = token(&aFile,tokenlen);
+ if (flags & P_C)
+ {
+ (*fi)->numOfComps = atoi(keyword);
+ (*fi)->ccd = (CompCharData *)
+ calloc((*fi)->numOfComps, sizeof(CompCharData));
+ if ((*fi)->ccd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseCompCharData(&aFile, *fi);
+ break;
+ case ENDFONTMETRICS:
+ code = normalEOF;
+ break;
+ case COMMENT:
+ linetoken(&aFile);
+ break;
+ case NOPE:
+ default:
+ code = parseError;
+ break;
+ } /* switch */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ } /* while */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ return(error);
+
+} /* parseFile */
+
+void
+freeFontInfo (FontInfo *fi)
+{
+ int i, j;
+
+ if (fi->gfi)
+ {
+ free (fi->gfi->afmVersion);
+ free (fi->gfi->fontName);
+ free (fi->gfi->fullName);
+ free (fi->gfi->familyName);
+ free (fi->gfi->weight);
+ free (fi->gfi->version);
+ free (fi->gfi->notice);
+ free (fi->gfi->encodingScheme);
+ free (fi->gfi);
+ }
+
+ free (fi->cwi);
+
+ if (fi->cmi)
+ {
+ for (i = 0; i < fi->numOfChars; i++)
+ {
+ Ligature *ligs;
+ free (fi->cmi[i].name);
+ ligs = fi->cmi[i].ligs;
+ while (ligs)
+ {
+ Ligature *tmp;
+ tmp = ligs;
+ ligs = ligs->next;
+ free (tmp->succ);
+ free (tmp->lig);
+ free (tmp);
+ }
+ }
+ free (fi->cmi);
+ }
+
+ free (fi->tkd);
+
+ if (fi->pkd)
+ {
+ for ( i = 0; i < fi->numOfPairs; i++)
+ {
+ free (fi->pkd[i].name1);
+ free (fi->pkd[i].name2);
+ }
+ free (fi->pkd);
+ }
+
+ if (fi->ccd)
+ {
+ for (i = 0; i < fi->numOfComps; i++)
+ {
+ free (fi->ccd[i].ccName);
+ for (j = 0; j < fi->ccd[i].numOfPieces; j++)
+ free (fi->ccd[i].pieces[j].pccName);
+
+ free (fi->ccd[i].pieces);
+ }
+ free (fi->ccd);
+ }
+
+ free (fi);
+}
+
+} // namspace
diff --git a/vcl/unx/source/fontmanager/parseAFM.hxx b/vcl/unx/source/fontmanager/parseAFM.hxx
new file mode 100644
index 000000000000..ad0c32e4b51b
--- /dev/null
+++ b/vcl/unx/source/fontmanager/parseAFM.hxx
@@ -0,0 +1,344 @@
+/*
+ * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - changed parseFile to accept a file name instead of a stream
+ */
+
+/*************************************************************************
+ *
+ * $RCSfile: parseAFM.hxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: hr $ $Date: 2005-12-28 17:08:50 $
+ *
+ ************************************************************************/
+
+/* ParseAFM.h
+ *
+ * This header file is used in conjuction with the parseAFM.c file.
+ * Together these files provide the functionality to parse Adobe Font
+ * Metrics files and store the information in predefined data structures.
+ * It is intended to work with an application program that needs font metric
+ * information. The program can be used as is by making a procedure call to
+ * parse an AFM file and have the data stored, or an application developer
+ * may wish to customize the code.
+ *
+ * This header file defines the data structures used as well as the key
+ * strings that are currently recognized by this version of the AFM parser.
+ * This program is based on the document "Adobe Font Metrics Files,
+ * Specification Version 2.0".
+ *
+ * AFM files are separated into distinct sections of different data. Because
+ * of this, the parseAFM program can parse a specified file to only save
+ * certain sections of information based on the application's needs. A record
+ * containing the requested information will be returned to the application.
+ *
+ * AFM files are divided into five sections of data:
+ * 1) The Global Font Information
+ * 2) The Character Metrics Information
+ * 3) The Track Kerning Data
+ * 4) The Pair-Wise Kerning Data
+ * 5) The Composite Character Data
+ *
+ * Basically, the application can request any of these sections independent
+ * of what other sections are requested. In addition, in recognizing that
+ * many applications will want ONLY the x-width of characters and not all
+ * of the other character metrics information, there is a way to receive
+ * only the width information so as not to pay the storage cost for the
+ * unwanted data. An application should never request both the
+ * "quick and dirty" char metrics (widths only) and the Character Metrics
+ * Information since the Character Metrics Information will contain all
+ * of the character widths as well.
+ *
+ * There is a procedure in parseAFM.c, called parseFile, that can be
+ * called from any application wishing to get information from the AFM File.
+ * This procedure expects 3 parameters: a vaild file descriptor, a pointer
+ * to a (FontInfo *) variable (for which space will be allocated and then
+ * will be filled in with the data requested), and a mask specifying
+ * which data from the AFM File should be saved in the FontInfo structure.
+ *
+ * The flags that can be used to set the appropriate mask are defined below.
+ * In addition, several commonly used masks have already been defined.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed typos
+ */
+
+#include <stdio.h>
+
+namespace psp {
+
+/* your basic constants */
+#define EOL '\n' /* end-of-line indicator */
+#define MAX_NAME 4096 /* max length for identifiers */
+#define FLAGS int
+
+
+
+/* Flags that can be AND'ed together to specify exactly what
+ * information from the AFM file should be saved.
+ */
+#define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
+#define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
+#define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
+#define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
+#define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
+#define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
+
+
+/* Commonly used flags
+ */
+#define P_GW (P_G | P_W)
+#define P_GM (P_G | P_M)
+#define P_GMP (P_G | P_M | P_P)
+#define P_GMK (P_G | P_M | P_P | P_T)
+#define P_ALL (P_G | P_M | P_P | P_T | P_C)
+
+
+
+/* Possible return codes from the parseFile procedure.
+ *
+ * ok means there were no problems parsing the file.
+ *
+ * parseError means that there was some kind of parsing error, but the
+ * parser went on. This could include problems like the count for any given
+ * section does not add up to how many entries there actually were, or
+ * there was a key that was not recognized. The return record may contain
+ * vaild data or it may not.
+ *
+ * earlyEOF means that an End of File was encountered before expected. This
+ * may mean that the AFM file had been truncated, or improperly formed.
+ *
+ * storageProblem means that there were problems allocating storage for
+ * the data structures that would have contained the AFM data.
+ */
+
+enum afmError { ok = 0, parseError = -1, earlyEOF = -2, storageProblem = -3 };
+
+
+/************************* TYPES *********************************/
+/* Below are all of the data structure definitions. These structures
+ * try to map as closely as possible to grouping and naming of data
+ * in the AFM Files.
+ */
+
+
+/* Bounding box definition. Used for the Font BBox as well as the
+ * Character BBox.
+ */
+typedef struct
+{
+ int llx; /* lower left x-position */
+ int lly; /* lower left y-position */
+ int urx; /* upper right x-position */
+ int ury; /* upper right y-position */
+} BBox;
+
+
+/* Global Font information.
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the AFM
+ * documentation (full title & version given above).
+ */
+typedef struct
+{
+ char *afmVersion; /* key: StartFontMetrics */
+ char *fontName; /* key: FontName */
+ char *fullName; /* key: FullName */
+ char *familyName; /* key: FamilyName */
+ char *weight; /* key: Weight */
+ float italicAngle; /* key: ItalicAngle */
+ bool isFixedPitch; /* key: IsFixedPitch */
+ BBox fontBBox; /* key: FontBBox */
+ int underlinePosition; /* key: UnderlinePosition */
+ int underlineThickness; /* key: UnderlineThickness */
+ char *version; /* key: Version */
+ char *notice; /* key: Notice */
+ char *encodingScheme; /* key: EncodingScheme */
+ int capHeight; /* key: CapHeight */
+ int xHeight; /* key: XHeight */
+ int ascender; /* key: Ascender */
+ int descender; /* key: Descender */
+ int charwidth; /* key: CharWidth */
+} GlobalFontInfo;
+
+
+/* Ligature definition is a linked list since any character can have
+ * any number of ligatures.
+ */
+typedef struct _t_ligature
+{
+ char *succ, *lig;
+ struct _t_ligature *next;
+} Ligature;
+
+
+/* Character Metric Information. This structure is used only if ALL
+ * character metric information is requested. If only the character
+ * widths is requested, then only an array of the character x-widths
+ * is returned.
+ *
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the
+ * Character Metrics section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int code, /* key: C */
+ wx, /* key: WX */
+ w0x, /* key: W0X */
+ wy; /* together wx and wy are associated with key: W */
+ char *name; /* key: N */
+ BBox charBBox; /* key: B */
+ Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */
+} CharMetricInfo;
+
+
+/* Track kerning data structure.
+ * The fields of this record are the five values associated with every
+ * TrackKern entry.
+ *
+ * For an explanation about each value please refer to the
+ * Track Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int degree;
+ float minPtSize,
+ minKernAmt,
+ maxPtSize,
+ maxKernAmt;
+} TrackKernData;
+
+
+/* Pair Kerning data structure.
+ * The fields of this record are the four values associated with every
+ * KP entry. For KPX entries, the yamt will be zero.
+ *
+ * For an explanation about each value please refer to the
+ * Pair Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *name1;
+ char *name2;
+ int xamt,
+ yamt;
+} PairKernData;
+
+
+/* PCC is a piece of a composite character. This is a sub structure of a
+ * compCharData described below.
+ * These fields will be filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *pccName;
+ int deltax,
+ deltay;
+} Pcc;
+
+
+/* Composite Character Information data structure.
+ * The fields ccName and numOfPieces are filled with the values associated
+ * with the key CC. The field pieces points to an array (size = numOfPieces)
+ * of information about each of the parts of the composite character. That
+ * array is filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *ccName;
+ int numOfPieces;
+ Pcc *pieces;
+} CompCharData;
+
+
+/* FontInfo
+ * Record type containing pointers to all of the other data
+ * structures containing information about a font.
+ * A a record of this type is filled with data by the
+ * parseFile function.
+ */
+typedef struct
+{
+ GlobalFontInfo *gfi; /* ptr to a GlobalFontInfo record */
+ int *cwi; /* ptr to 256 element array of just char widths */
+ int numOfChars; /* number of entries in char metrics array */
+ CharMetricInfo *cmi; /* ptr to char metrics array */
+ int numOfTracks; /* number to entries in track kerning array */
+ TrackKernData *tkd; /* ptr to track kerning array */
+ int numOfPairs; /* number to entries in pair kerning array */
+ PairKernData *pkd; /* ptr to pair kerning array */
+ int numOfComps; /* number to entries in comp char array */
+ CompCharData *ccd; /* ptr to comp char array */
+} FontInfo;
+
+
+
+/************************* PROCEDURES ****************************/
+
+/* Call this procedure to do the grunt work of parsing an AFM file.
+ *
+ * "fp" should be a valid file pointer to an AFM file.
+ *
+ * "fi" is a pointer to a pointer to a FontInfo record sturcture
+ * (defined above). Storage for the FontInfo structure will be
+ * allocated in parseFile and the structure will be filled in
+ * with the requested data from the AFM File.
+ *
+ * "flags" is a mask with bits set representing what data should
+ * be saved. Defined above are valid flags that can be used to set
+ * the mask, as well as a few commonly used masks.
+ *
+ * The possible return codes from parseFile are defined above.
+ */
+
+int parseFile( const char* pFilename, FontInfo **fi, FLAGS flags );
+void freeFontInfo(FontInfo *fi);
+
+} // namespace
diff --git a/vcl/unx/source/gdi/dtint.cxx b/vcl/unx/source/gdi/dtint.cxx
index 8a67dbe6fcc7..96d78b4f006d 100644
--- a/vcl/unx/source/gdi/dtint.cxx
+++ b/vcl/unx/source/gdi/dtint.cxx
@@ -44,9 +44,6 @@
#include <cdeint.hxx>
#endif
#include <dtint.hxx>
-#ifdef MACOSX
-#include <macosxint.hxx>
-#endif
#include <saldisp.hxx>
#include <saldata.hxx>
#include <wmadaptor.hxx>
@@ -98,9 +95,6 @@ DtIntegrator::~DtIntegrator()
DtIntegrator* DtIntegrator::CreateDtIntegrator()
{
-#ifdef MACOSX
- return new MACOSXIntegrator();
-#endif
/*
* #i22061# override desktop detection
* if environment variable OOO_FORCE_DESKTOP is set
diff --git a/vcl/unx/source/gdi/gcach_xpeer.cxx b/vcl/unx/source/gdi/gcach_xpeer.cxx
index 77e8ccc09a91..85466c532ff2 100644
--- a/vcl/unx/source/gdi/gcach_xpeer.cxx
+++ b/vcl/unx/source/gdi/gcach_xpeer.cxx
@@ -647,9 +647,6 @@ Glyph X11GlyphPeer::GetGlyphId( ServerFont& rServerFont, int nGlyphIndex )
X11GlyphCache::X11GlyphCache( X11GlyphPeer& rPeer )
: GlyphCache( rPeer )
{
-#ifdef MACOSX
- LoadFonts();
-#endif
}
// ---------------------------------------------------------------------------
diff --git a/vcl/unx/source/gdi/macosxint.cxx b/vcl/unx/source/gdi/macosxint.cxx
deleted file mode 100644
index 5e2a2838ae7f..000000000000
--- a/vcl/unx/source/gdi/macosxint.cxx
+++ /dev/null
@@ -1,250 +0,0 @@
-/*************************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * Copyright 2008 by Sun Microsystems, Inc.
- *
- * OpenOffice.org - a multi-platform office productivity suite
- *
- * $RCSfile: macosxint.cxx,v $
- * $Revision: 1.5 $
- *
- * 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 <macosxint.hxx>
-#include <tools/config.hxx>
-#include <vcl/settings.hxx>
-#include <osl/thread.h>
-#include <osl/file.hxx>
-#include <rtl/bootstrap.hxx>
-#include <unistd.h>
-#include <cstdio>
-
-using namespace rtl;
-using namespace osl;
-
-MACOSXIntegrator::MACOSXIntegrator()
-{
- meType = DtMACOSX;
-}
-
-MACOSXIntegrator::~MACOSXIntegrator()
-{
-}
-
-void MACOSXIntegrator::GetSystemLook( AllSettings& rSettings )
-{
- rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
-
- StyleSettings aStyleSettings( rSettings.GetStyleSettings() );
- // #i48001# set a default blink rate
- aStyleSettings.SetCursorBlinkTime( 500 );
-
-// #i61174# aquacolors
-// aUserConfigFile : string containing the user install directory completed with "/user/macosxrc.txt"
-// currently : ~/Library/Application Support/OpenOffice.org 2.0/user/macosxrc.txt
-// aDefaultConfigFile : string containing the OpenOffice.org install directory + presets/macosxrc.txt
-// default should be /Applications/OpenOffice.org 2.0/Contents/openoffice.org2/presets/macosxrc.txt
-
-
- rtl::OUString aUserConfigFile;
- rtl::OUString aDefaultConfigFile;
- rtl::OUString aTryFiles[2];
-
-// read the content of bootstraprc is necessary to find the path to the user configuration file
-// ~/Library/Application Support/OpenOffice.org 2.0/user/macosxrc.txt
-
- rtl::Bootstrap aBootstrap( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("bootstraprc") ) );
- if( aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("MacOSXIntegrationUserFile") ), aUserConfigFile ) )
- {
- rtl::OUString aFile = aUserConfigFile ;
- osl::FileBase::getSystemPathFromFileURL(aFile, aTryFiles[0]);
- }
-
-// if macosxrc.txt is not found in user install dir, fallback to the second macosxrc.txt (with default values), located in <install_dir>/presets
-
- if( aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("MacOSXIntegrationDefaultFile") ), aDefaultConfigFile ) )
- {
- rtl::OUString aFile = aDefaultConfigFile ;
- osl::FileBase::getSystemPathFromFileURL(aFile, aTryFiles[1]);
- }
-
- for( unsigned int i = 0; (i < sizeof(aTryFiles) / sizeof(aTryFiles[0])); i++ )
- {
-
- #if OSL_DEBUG_LEVEL > 1
- fprintf(stderr, "try accessing %d, %s\n", i, rtl::OUStringToOString( aTryFiles[i], aEncoding ).getStr());
- #endif
- if( access( rtl::OUStringToOString( aTryFiles[i], aEncoding ).getStr(), R_OK ) )
- continue;
-
- #if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "using %s for style settings\n", rtl::OUStringToOString( aTryFiles[i], aEncoding ).getStr() );
- #endif
-
- Config aConfig( aTryFiles[i] );
- ByteString aLine;
-
- if( aConfig.HasGroup( "General" ) )
- {
- aConfig.SetGroup( "General" );
-
- aLine = aConfig.ReadKey( "foreground" );
- if( aLine.GetTokenCount( ',' ) >= 3 )
- {
- Color aFore( aLine.GetToken( 0, ',' ).ToInt32(),
- aLine.GetToken( 1, ',' ).ToInt32(),
- aLine.GetToken( 2, ',' ).ToInt32() );
- aStyleSettings.SetDialogTextColor( aFore );
- aStyleSettings.SetMenuTextColor( aFore );
- aStyleSettings.SetButtonTextColor( aFore );
- aStyleSettings.SetRadioCheckTextColor( aFore );
- aStyleSettings.SetGroupTextColor( aFore );
- aStyleSettings.SetLabelTextColor( aFore );
- aStyleSettings.SetInfoTextColor( aFore );
- aStyleSettings.SetFieldTextColor( aFore );
- }
-
- aLine = aConfig.ReadKey( "background" );
- if( aLine.GetTokenCount( ',' ) >= 3 )
- {
- Color aBack( aLine.GetToken( 0, ',' ).ToInt32(),
- aLine.GetToken( 1, ',' ).ToInt32(),
- aLine.GetToken( 2, ',' ).ToInt32() );
- aStyleSettings.Set3DColors( aBack );
- aStyleSettings.SetFaceColor( aBack );
- aStyleSettings.SetDialogColor( aBack );
- aStyleSettings.SetMenuColor( aBack );
- aStyleSettings.SetMenuBarColor( aBack );
- aStyleSettings.SetLightBorderColor( aBack );
- if( aBack == COL_LIGHTGRAY )
- aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
- else
- {
- Color aColor2 = aStyleSettings.GetLightColor();
- aStyleSettings.SetCheckedColor(
- Color( (BYTE)(((USHORT)aBack.GetRed()+(USHORT)aColor2.GetRed())/2),
- (BYTE)(((USHORT)aBack.GetGreen()+(USHORT)aColor2.GetGreen())/2),
- (BYTE)(((USHORT)aBack.GetBlue()+(USHORT)aColor2.GetBlue())/2)
- ) );
- }
- }
-
- aLine = aConfig.ReadKey( "selectForeground" );
- if( aLine.GetTokenCount( ',' ) >= 3 )
- {
- Color aSelectFore( aLine.GetToken( 0, ',' ).ToInt32(),
- aLine.GetToken( 1, ',' ).ToInt32(),
- aLine.GetToken( 2, ',' ).ToInt32());
-
- aStyleSettings.SetHighlightTextColor( aSelectFore );
- aStyleSettings.SetMenuHighlightTextColor( aSelectFore );
- }
- aLine = aConfig.ReadKey( "selectBackground" );
- if( aLine.GetTokenCount( ',' ) >= 3 )
- {
- Color aSelectBack( aLine.GetToken( 0, ',' ).ToInt32(),
- aLine.GetToken( 1, ',' ).ToInt32(),
- aLine.GetToken( 2, ',' ).ToInt32() );
-
- aStyleSettings.SetHighlightColor( aSelectBack );
- aStyleSettings.SetMenuHighlightColor( aSelectBack );
- }
- aLine = aConfig.ReadKey( "activeForeground" );
- if( aLine.GetTokenCount( ',' ) >= 3 ) {
- Color aActiveFore( aLine.GetToken( 0, ',' ).ToInt32(),
- aLine.GetToken( 1, ',' ).ToInt32(),
- aLine.GetToken( 2, ',' ).ToInt32() );
-
- aStyleSettings.SetActiveTextColor( aActiveFore );
- }
- aLine = aConfig.ReadKey( "activeBackground" );
- if( aLine.GetTokenCount( ',' ) >= 3 ) {
- Color aActiveBack( aLine.GetToken( 0, ',' ).ToInt32(),
- aLine.GetToken( 1, ',' ).ToInt32(),
- aLine.GetToken( 2, ',' ).ToInt32() );
-
- aStyleSettings.SetActiveColor( aActiveBack );
- aStyleSettings.SetActiveColor2( aActiveBack );
- }
- aLine = aConfig.ReadKey( "deactiveForeground" );
- if( aLine.GetTokenCount( ',' ) >= 3 ) {
- Color aDeactiveFore( aLine.GetToken( 0, ',' ).ToInt32(),
- aLine.GetToken( 1, ',' ).ToInt32(),
- aLine.GetToken( 2, ',' ).ToInt32() );
-
- aStyleSettings.SetDeactiveTextColor( aDeactiveFore );
- aStyleSettings.SetDisableColor( aDeactiveFore );
- }
- aLine = aConfig.ReadKey( "deactiveBackground" );
- if( aLine.GetTokenCount( ',' ) >= 3 ) {
- Color aDeactiveBack( aLine.GetToken( 0, ',' ).ToInt32(),
- aLine.GetToken( 1, ',' ).ToInt32(),
- aLine.GetToken( 2, ',' ).ToInt32() );
-
- aStyleSettings.SetDeactiveColor( aDeactiveBack );
- aStyleSettings.SetDeactiveColor2( aDeactiveBack );
- aStyleSettings.SetDeactiveBorderColor( aDeactiveBack );
- aStyleSettings.SetActiveBorderColor( aDeactiveBack );
- }
-
- aLine = aConfig.ReadKey( "font" );
- if( aLine.Len() )
- {
- Font aFont = aStyleSettings.GetAppFont();
- String aFontName( aLine, RTL_TEXTENCODING_UTF8 );
- if( aFontName.GetTokenCount( ',' ) > 0 )
- aFontName = aFontName.GetToken( 0, ',' );
- aFont.SetName( aFontName );
-
- aStyleSettings.SetAppFont( aFont );
- aStyleSettings.SetHelpFont( aFont );
- aStyleSettings.SetTitleFont( aFont );
- aStyleSettings.SetFloatTitleFont( aFont );
- aStyleSettings.SetMenuFont( aFont );
- aStyleSettings.SetToolFont( aFont );
- aStyleSettings.SetLabelFont( aFont );
- aStyleSettings.SetInfoFont( aFont );
- aStyleSettings.SetRadioCheckFont( aFont );
- aStyleSettings.SetPushButtonFont( aFont );
- aStyleSettings.SetFieldFont( aFont );
- aStyleSettings.SetIconFont( aFont );
- aStyleSettings.SetGroupFont( aFont );
- }
-
- aLine = aConfig.ReadKey( "cursorFlashTime" );
- if( aLine.Len() )
- {
- sal_Int32 nTime = aLine.ToInt32() / 2;
- if( nTime == 0 )
- nTime = STYLE_CURSOR_NOBLINKTIME;
- aStyleSettings.SetCursorBlinkTime( nTime );
- }
- }
-
- break;
- }
-
- rSettings.SetStyleSettings( aStyleSettings );
-}
-
diff --git a/vcl/unx/source/gdi/macosxrc.txt b/vcl/unx/source/gdi/macosxrc.txt
deleted file mode 100644
index 55c2c40f67cc..000000000000
--- a/vcl/unx/source/gdi/macosxrc.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Configure file for UI colors in OpenOffice.org Mac OS X port
-# Created by Mox 2006/01/27
-# This file follows the format of .kderc files
-#
-# The settings under label [General] are used. Modify it according to
-# the other labels, if you want to change it.
-#
-
-[Aqua]
-background=244,244,244
-foreground=0,0,0
-selectBackground=52,112,204
-selectForeground=255,255,255
-
-[Graphite]
-background=244,244,244
-foreground=0,0,0
-selectBackground=94,106,121
-selectForeground=255,255,255
-
-[General]
-background=244,244,244
-foreground=0,0,0
-selectBackground=52,112,204
-selectForeground=255,255,255
-#comment out if you want to use a customized font
-# only one font can be choosen
-#font=Andale Mono,Andale Sans UI
-# another nice font example
-#font=Futura, Futura Sans UI
-#Apple recommandation is Lucida Grande
-font=Lucida Grande, Futura Sans UI
diff --git a/vcl/unx/source/gdi/makefile.mk b/vcl/unx/source/gdi/makefile.mk
index 1516cd8ad5a5..8f0faf863af2 100644
--- a/vcl/unx/source/gdi/makefile.mk
+++ b/vcl/unx/source/gdi/makefile.mk
@@ -73,12 +73,6 @@ EXCEPTIONSFILES=\
$(SLO)$/salgdi3.obj \
$(SLO)$/salcvt.obj
-
-.IF "$(OS)"=="MACOSX"
-SLOFILES += $(SLO)$/macosxint.obj
-MACOSXRC = $(MISC)$/macosxrc.txt
-.ENDIF # "$(OS)"=="MACOSX"
-
.IF "$(USE_XPRINT)" == "TRUE"
CFLAGS+=-D_USE_PRINT_EXTENSION_=1
SLOFILES+=$(SLO)$/xprintext.obj
@@ -115,5 +109,3 @@ $(INCCOM)$/rtsname.hxx:
$(SLO)$/salpimpl.obj : $(INCCOM)$/rtsname.hxx
$(SLO)$/salprnpsp.obj : $(INCCOM)$/rtsname.hxx
-$(MISC)$/macosxrc.txt : $$(@:f)
- $(COPY) $< $@
diff --git a/vcl/unx/source/gdi/pspgraphics.cxx b/vcl/unx/source/gdi/pspgraphics.cxx
index 7b8a0f173707..4a4bccd86d2a 100644
--- a/vcl/unx/source/gdi/pspgraphics.cxx
+++ b/vcl/unx/source/gdi/pspgraphics.cxx
@@ -31,18 +31,18 @@
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
-#include <pspgraphics.h>
-#include <psprint/jobdata.hxx>
-#include <psprint/printergfx.hxx>
-#include <psprint/printerinfomanager.hxx>
-#include <vcl/bmpacc.hxx>
-#include <vcl/salbmp.hxx>
-#include <vcl/glyphcache.hxx>
-#include <vcl/impfont.hxx>
-#include <vcl/outfont.hxx>
-#include <vcl/svapp.hxx>
-#include <vcl/salprn.hxx>
-#include <vcl/sysdata.hxx>
+#include "pspgraphics.h"
+#include "vcl/jobdata.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/bmpacc.hxx"
+#include "vcl/salbmp.hxx"
+#include "vcl/glyphcache.hxx"
+#include "vcl/impfont.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/salprn.hxx"
+#include "vcl/sysdata.hxx"
#include <stdlib.h>
#include <unistd.h>
diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx
index dabce7c59b9e..1d61dbe214a2 100644
--- a/vcl/unx/source/gdi/salgdi.cxx
+++ b/vcl/unx/source/gdi/salgdi.cxx
@@ -33,31 +33,28 @@
#include "Xproto.h"
-#include <salunx.h>
-#include <saldata.hxx>
-#include <saldisp.hxx>
-#ifndef _SV_SALGDI_HXX
-#include <salgdi.h>
-#endif
-#include <salframe.h>
-#include <salvd.h>
-#include <tools/debug.hxx>
+#include "salunx.h"
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salgdi.h"
+#include "salframe.h"
+#include "salvd.h"
+#include "xrender_peer.hxx"
-#ifndef _USE_PRINT_EXTENSION_
-#include <psprint/printergfx.hxx>
-#include <psprint/jobdata.hxx>
-#endif
+#include "vcl/printergfx.hxx"
+#include "vcl/jobdata.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/polygon/b2dpolypolygoncutter.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/polygon/b2dpolypolygoncutter.hxx"
-#include "xrender_peer.hxx"
#include <vector>
#include <queue>
#include <set>
diff --git a/vcl/unx/source/gdi/salgdi2.cxx b/vcl/unx/source/gdi/salgdi2.cxx
index c10abac60bb0..7192a417f96c 100644
--- a/vcl/unx/source/gdi/salgdi2.cxx
+++ b/vcl/unx/source/gdi/salgdi2.cxx
@@ -32,22 +32,20 @@
#include "precompiled_vcl.hxx"
#include <stdio.h>
-
-#include <salunx.h>
#include <poll.h>
-#include <saldata.hxx>
-#include <saldisp.hxx>
-#include <salbmp.h>
-#include <vcl/salbtype.hxx>
-#include <salgdi.h>
-#include <salframe.h>
-#include <salvd.h>
-#include <xrender_peer.hxx>
-
-#ifndef _USE_PRINT_EXTENSION_
-#include <psprint/printergfx.hxx>
-#include <vcl/bmpacc.hxx>
-#endif
+
+#include "salunx.h"
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salbmp.h"
+#include "salgdi.h"
+#include "salframe.h"
+#include "salvd.h"
+#include "xrender_peer.hxx"
+
+#include "vcl/salbtype.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/bmpacc.hxx"
#undef SALGDI2_TESTTRANS
diff --git a/vcl/unx/source/gdi/salgdi3.cxx b/vcl/unx/source/gdi/salgdi3.cxx
index 47b5f5263ce5..e2c41b52006b 100644
--- a/vcl/unx/source/gdi/salgdi3.cxx
+++ b/vcl/unx/source/gdi/salgdi3.cxx
@@ -40,42 +40,44 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sal/alloca.h>
-
-#include <gcach_xpeer.hxx>
-#include <xrender_peer.hxx>
-#include <sal/types.h>
-
-#include <salunx.h>
-#include <saldata.hxx>
-#include <saldisp.hxx>
-#include <salgdi.h>
-#include <pspgraphics.h>
-#include <vcl/salframe.hxx>
-#include <salvd.h>
-#include <vcl/outdev.h>
-#include <tools/string.hxx>
-#include <basegfx/polygon/b2dpolypolygon.hxx>
-#include <rtl/tencinfo.h>
-#include <osl/file.hxx>
-#include "xfont.hxx"
-#include <vcl/impfont.hxx>
-
-
-#include <tools/debug.hxx>
-#include <tools/stream.hxx>
-#include <psprint/printergfx.hxx>
-#include <psprint/fontmanager.hxx>
-#include <psprint/jobdata.hxx>
-#include <psprint/printerinfomanager.hxx>
-#include <vcl/svapp.hxx>
+#include "gcach_xpeer.hxx"
+#include "xrender_peer.hxx"
+#include "salunx.h"
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salgdi.h"
+#include "pspgraphics.h"
+#include "salvd.h"
+#include "xfont.hxx"
#include "xlfd_attr.hxx"
#include "xlfd_smpl.hxx"
#include "xlfd_extd.hxx"
#include "salcvt.hxx"
-#include <i18npool/mslangid.hxx>
+#include "vcl/printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/impfont.hxx"
+#include "vcl/salframe.hxx"
+#include "vcl/outdev.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 <hash_set>
@@ -795,11 +797,7 @@ CairoWrapper::CairoWrapper()
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;
@@ -1392,10 +1390,8 @@ void X11SalGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
if( rGlyphPeer.GetGlyphSet( rFont, m_nScreen ) )
DrawServerAAFontString( rLayout );
-#ifndef MACOSX /* ignore X11 fonts on MACOSX */
else if( !rGlyphPeer.ForcedAntialiasing( rFont, m_nScreen ) )
DrawServerSimpleFontString( rLayout );
-#endif // MACOSX
else
DrawServerAAForcedString( rLayout );
}
diff --git a/vcl/unx/source/gdi/salprnpsp.cxx b/vcl/unx/source/gdi/salprnpsp.cxx
index 965fb2f10209..b3fdfaef56ce 100644
--- a/vcl/unx/source/gdi/salprnpsp.cxx
+++ b/vcl/unx/source/gdi/salprnpsp.cxx
@@ -47,20 +47,22 @@
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
-#include <vcl/svapp.hxx>
-#include <vcl/jobset.h>
-#include <saldisp.hxx>
-#include <salinst.h>
-#include <salprn.h>
-#include <vcl/print.h>
-#include <vcl/salptype.hxx>
-#include <salframe.h>
-#include <pspgraphics.h>
-#include <saldata.hxx>
-
-#include <rtl/ustring.hxx>
-#include <osl/module.h>
-#include <psprint/printerinfomanager.hxx>
+
+#include "saldisp.hxx"
+#include "salinst.h"
+#include "salprn.h"
+#include "salframe.h"
+#include "pspgraphics.h"
+#include "saldata.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/jobset.h"
+#include "vcl/print.h"
+#include "vcl/salptype.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "rtl/ustring.hxx"
+
+#include "osl/module.h"
using namespace psp;
using namespace rtl;
@@ -69,7 +71,7 @@ using namespace rtl;
* static helpers
*/
-#include <rtsname.hxx>
+#include "rtsname.hxx"
static oslModule driverLib = NULL;
extern "C"
@@ -723,58 +725,13 @@ BOOL PspSalInfoPrinter::SetData(
}
String aPaper;
-#ifdef MACOSX
- // For Mac OS X, many printers are directly attached
- // USB/Serial printers with a stripped-down PPD that gives us
- // problems. We need to do PS->PDF conversion for these printers
- // but they are not able to handle multiple page sizes in the same
- // document at all, since we must pass -o media=... to them to get
- // a good printout.
- // So, we must find a match between the paper size from OOo and what
- // the PPD of the printer has, and pass that paper size to -o media=...
- // If a match cannot be found (ie the paper size from Format->Page is
- // nowhere near anything in the PPD), we default to what has been
- // chosen in File->Print->Properties.
- //
- // For printers capable of directly accepting PostScript data, none
- // of this occurs and we default to the normal OOo behavior.
- const PPDKey *pCupsFilterKey;
- const PPDValue *pCupsFilterValue;
- BOOL bIsCUPSPrinter = TRUE;
-
- // Printers that need PS->PDF conversion have a "cupsFilter" key and
- // a value of "application/pdf" in that key
- pCupsFilterKey = aData.m_pParser->getKey( String(RTL_CONSTASCII_USTRINGPARAM("cupsFilter")) );
- pCupsFilterValue = pCupsFilterKey != NULL ? aData.m_aContext.getValue( pCupsFilterKey ) : NULL;
- if ( pCupsFilterValue )
- {
- // PPD had a cupsFilter key, check for PS->PDF conversion requirement
- ByteString aCupsFilterString( pCupsFilterValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 );
- if ( aCupsFilterString.Search("application/pdf") == 0 )
- bIsCUPSPrinter = FALSE;
- }
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( pJobSetup->mnPaperWidth ),
+ TenMuToPt( pJobSetup->mnPaperHeight ) );
else
- bIsCUPSPrinter = FALSE;
+ aPaper = String( ByteString( aPaperTab[ pJobSetup->mePaperFormat ].name ), RTL_TEXTENCODING_ISO_8859_1 );
- if ( TRUE == bIsCUPSPrinter )
- {
- // If its a directly attached printer, with a
- // stripped down PPD (most OS X printers are) always
- // match the paper size.
- aPaper = aData.m_pParser->matchPaper(
- TenMuToPt( pJobSetup->mnPaperWidth ),
- TenMuToPt( pJobSetup->mnPaperHeight ) );
- }
- else
-#endif
- {
- if( pJobSetup->mePaperFormat == PAPER_USER )
- aPaper = aData.m_pParser->matchPaper(
- TenMuToPt( pJobSetup->mnPaperWidth ),
- TenMuToPt( pJobSetup->mnPaperHeight ) );
- else
- aPaper = String( ByteString( aPaperTab[ pJobSetup->mePaperFormat ].name ), RTL_TEXTENCODING_ISO_8859_1 );
- }
pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
diff --git a/vcl/unx/source/gdi/xprintext.cxx b/vcl/unx/source/gdi/xprintext.cxx
deleted file mode 100644
index d43185e34dea..000000000000
--- a/vcl/unx/source/gdi/xprintext.cxx
+++ /dev/null
@@ -1,656 +0,0 @@
-/************************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * Copyright 2008 by Sun Microsystems, Inc.
- *
- * OpenOffice.org - a multi-platform office productivity suite
- *
- * $RCSfile: xprintext.cxx,v $
- * $Revision: 1.12 $
- *
- * 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 <stdlib.h>
-#include <unistd.h>
-
-#if OSL_DEBUG_LEVEL == 0
-#define NDEBUG
-#endif
-#include <assert.h>
-
-#include <prex.h>
-#include <X11/extensions/Print.h>
-#include <postx.h>
-
-#include <salunx.h>
-#include <saldata.hxx>
-#include <saldisp.hxx>
-#include <vcl/salinst.hxx>
-#include <vcl/salprn.hxx>
-#include <vcl/salgdi.hxx>
-#include <salprn.h>
-#include <vcl/print.h>
-#include <vcl/jobset.h>
-#include "i18n_im.hxx"
-#include "i18n_xkb.hxx"
-
-// =======================================================================
-//
-// ImplSalPrinterData
-//
-// =======================================================================
-
-
-class ImplSalPrinterData
-{
-
-private:
-
- SalDisplay* mpDisplay;
- SalGraphics* mpGraphics;
- char* mpPrinterName;
- Display* mpXDisplay;
- XPContext maContext;
- Bool XprtConnectStatus;
-
-
-private:
-
- ImplSalPrinterData( ImplSalPrinterData& rData );
-
-public:
-
- ImplSalPrinterData();
- ~ImplSalPrinterData();
-
- void Init( const SalPrinterQueueInfo* pQueueInfo,
- ImplJobSetup* pJobSetup );
-
- SalGraphics* GetGraphics();
- void ReleaseGraphics( SalGraphics* pGraphics = NULL );
- XLIB_Window GetDrawable() const { return mpDisplay->GetRootWindow(); }
- SalColormap& GetColormap() const { return mpDisplay->GetColormap(); }
- Display* GetXDisplay() const { return mpXDisplay; }
- XPContext GetXContext() const { return maContext; }
- const char* GetPrinter() const { return mpPrinterName; }
- XPContext GetContext() const { return maContext; }
- Bool GetStatus() const { return XprtConnectStatus; }
-};
-
-ImplSalPrinterData::ImplSalPrinterData() :
- mpDisplay( NULL ),
- mpGraphics( NULL ),
- mpXDisplay( NULL ),
- maContext( NULL ),
- mpPrinterName( NULL ),
- XprtConnectStatus( FALSE )
-{
- Init(NULL, NULL);
-}
-
-void ImplSalPrinterData::Init( const SalPrinterQueueInfo* pQueueInfo,
- ImplJobSetup* pJobSetup )
-{
- const char *printername = NULL;
-
- if (mpPrinterName == NULL || strcmp(mpPrinterName,printername)) {
- int nCount;
- XPContext aContext = NULL;
- char *Xprinter = getenv("XPRINTER");
- char *XpDisplayIndex;
- if (mpXDisplay == NULL && !XprtConnectStatus) {
-
- if (Xprinter && (XpDisplayIndex = strchr(Xprinter,'@'))) {
- if (Xprinter != XpDisplayIndex && printername == NULL) {
- char *defprinter = new char [XpDisplayIndex - Xprinter + 1];
- strncpy(defprinter, Xprinter, XpDisplayIndex - Xprinter);
- defprinter[XpDisplayIndex - Xprinter] = '\0';
- printername = defprinter;
- }
- }
- mpXDisplay = GetXpDisplay();
- // If GetXpDisplay() returns NULL (i.e. cannot connect to Xprint server) set XprtConnectStatus to FALSE.
- if (mpXDisplay == NULL) {
- fprintf(stderr, "Could not connect to Xprint server. Xprinting disabled.\n");
- XprtConnectStatus = FALSE;
- }
- else {
- //fprintf(stderr, "Connected to Xprint server.\n");
- if( getenv( "SAL_SYNCHRONIZE" ) )
- XSynchronize( mpXDisplay, True );
-
- if (printername == NULL || mpPrinterName == NULL
- || strcmp(mpPrinterName,printername) || maContext == NULL) {
- XpRehashPrinterList(mpXDisplay);
- XPPrinterList pList = XpGetPrinterList (mpXDisplay, NULL, &nCount);
-
- for ( int i = 0; i < nCount; i++ ) {
- //fprintf (stderr, "Printer «%s»: «%s»\n",
- //pList[i].name ? pList[i].name : "(null)",
- //pList[i].desc ? pList[i].desc : "(null)" );
- if(pList[i].name)
- if (printername == NULL || strcmp (pList[i].name, printername) == 0) {
- mpPrinterName = strdup( pList[i].name );
- maContext = XpCreateContext ( mpXDisplay, mpPrinterName );
- }
- }
- XpFreePrinterList (pList);
- }
- assert(maContext);
- XpSetContext (mpXDisplay, maContext);
-
- // New Sal
- if (mpDisplay == NULL) {
- mpDisplay = new SalDisplay( mpXDisplay, NULL );
- SalI18N_InputMethod* pInputMethod = new SalI18N_InputMethod;
- pInputMethod->Invalidate();
- mpDisplay->SetInputMethod( pInputMethod );
- SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( mpXDisplay );
- mpDisplay->SetKbdExtension( pKbdExtension );
-
- }
- // Connection to Xprint server successful so set XprtConnectStatus to TRUE.
- XprtConnectStatus = TRUE;
- }
- mpGraphics = NULL;
- }
-}
-}
-
-SalGraphics*
-ImplSalPrinterData::GetGraphics()
-{
- //If no Xprinter or mpGraphics already set then return NULL.
- if ( mpGraphics || !XprtConnectStatus) {
- return NULL;
- }
- mpGraphics = new SalGraphics;
- mpGraphics->maGraphicsData.Init( this );
-
- return mpGraphics;
-}
-
-void
-ImplSalPrinterData::ReleaseGraphics( SalGraphics* pGraphics )
-{
- if ( mpGraphics )
- {
- assert( !(pGraphics && pGraphics != mpGraphics) );
- delete mpGraphics;
- mpGraphics = NULL;
- }
-}
-
-ImplSalPrinterData::~ImplSalPrinterData()
-{
-
- if ( mpPrinterName != NULL )
- free( mpPrinterName );
- XpDestroyContext(mpXDisplay, maContext);
-
- delete mpGraphics;
- delete mpDisplay;
-
- if ( mpXDisplay != NULL )
- XCloseDisplay( mpXDisplay );
-}
-
-// =======================================================================
-//
-// SalInfoPrinterData
-//
-// =======================================================================
-
-SalInfoPrinterData::SalInfoPrinterData()
-{
- mpImplData = NULL;
-}
-
-SalInfoPrinterData::~SalInfoPrinterData()
-{
- delete mpImplData;
-}
-
-void
-SalInfoPrinterData::Init(
- SalPrinterQueueInfo *pQueueInfo,
- ImplJobSetup* pJobSetup )
-{
- mpImplData = new ImplSalPrinterData();
-}
-
-// =======================================================================
-//
-// SalPrinterData
-//
-// =======================================================================
-
-SalPrinterData::SalPrinterData()
-{
- mpImplData = NULL;
-}
-
-SalPrinterData::~SalPrinterData()
-{
- delete mpImplData;
-}
-
-void
-SalPrinterData::Init( SalInfoPrinter *pInfoPrinter )
-{
- mpImplData = new ImplSalPrinterData();
-}
-
-// =======================================================================
-//
-// SalInfoPrinter
-//
-// =======================================================================
-
-SalInfoPrinter::SalInfoPrinter()
-{
-}
-
-SalInfoPrinter::~SalInfoPrinter()
-{
-}
-
-SalGraphics*
-SalInfoPrinter::GetGraphics()
-{
- return maPrinterData.mpImplData->GetGraphics();
-}
-
-void
-SalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
-{
- maPrinterData.mpImplData->ReleaseGraphics( pGraphics );
-}
-
-BOOL
-SalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
-{
- pJobSetup->mePaperFormat = PAPER_A4;
- pJobSetup->mnPaperWidth = 21000;
- pJobSetup->mnPaperHeight = 29700;
- pJobSetup->meOrientation = ORIENTATION_PORTRAIT;
- return TRUE;
-}
-
-BOOL
-SalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
-{
- pJobSetup->mePaperFormat = PAPER_A4;
- pJobSetup->mnPaperWidth = 21000;
- pJobSetup->mnPaperHeight = 29700;
- pJobSetup->meOrientation = ORIENTATION_PORTRAIT;
- return TRUE;
-}
-
-BOOL
-SalInfoPrinter::SetData( ULONG nSetDataFlags, ImplJobSetup* pJobSetup )
-{
- pJobSetup->mePaperFormat = PAPER_A4;
- pJobSetup->mnPaperWidth = 21000;
- pJobSetup->mnPaperHeight = 29700;
- pJobSetup->meOrientation = ORIENTATION_PORTRAIT;
- return TRUE;
-}
-
-void
-SalInfoPrinter::GetPageInfo( const ImplJobSetup* pImplJobSetup,
- long& rOutWidth, long& rOutHeight,
- long& rPageOffX, long& rPageOffY,
- long& rPageWidth, long& rPageHeight )
-{
- rPageWidth = 2550;
- rPageHeight = 3300;
- rPageOffX = 75;
- rPageOffY = 75;
- rOutWidth = rPageWidth - rPageOffX - 75;
- rOutHeight = rPageHeight- rPageOffY - 75;
-}
-
-ULONG
-SalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
-{
- return 1;
-}
-
-XubString
-SalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup,
- ULONG nPaperBin )
-{
- return(XubString(RTL_CONSTASCII_USTRINGPARAM("PaperBinName")));
- // return "PaperBinName";
-}
-
-ULONG
-SalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, USHORT nType )
-{
- return 0;
-}
-
-// =======================================================================
-//
-// SalPrinter
-//
-// =======================================================================
-
-SalPrinter::SalPrinter()
-{
-}
-
-SalPrinter::~SalPrinter()
-{
-}
-
-BOOL
-SalPrinter::StartJob(
- const XubString* pFileName,
- const XubString& rJobName,
- const XubString& rAppName,
- ULONG nCopies, BOOL bCollate,
- ImplJobSetup* pJobSetup )
-{
- Display *pDisplay = maPrinterData.mpImplData->GetXDisplay();
- XPContext aContext = maPrinterData.mpImplData->GetXContext();
- const char* pPrinterName = maPrinterData.mpImplData->GetPrinter();
-
- XpSelectInput (pDisplay, aContext, XPPrintMask);
-
- char pJobName[ 64 ];
- snprintf (pJobName, sizeof(pJobName), "%s.job-name: XPrint%d", pPrinterName, getpid() );
-
- XpStartJob( pDisplay, XPSpool );
-
- return TRUE;
-}
-
-BOOL
-SalPrinter::EndJob()
-{
- Display *pDisplay = maPrinterData.mpImplData->GetXDisplay();
- XEvent aEvent;;
-
- XpEndJob( pDisplay );
- XSync( pDisplay, False );
- // Wait until printing is done
- do
- {
- // XNextEvent (pDisplay, &aEvent);
- }
- while ( 0 );
- // aEvent.type != XPPrintNotify
- // && ((XPPrintEvent *) (&aEvent))->detail != XPEndJobNotify);
-
- return TRUE;
-}
-
-BOOL
-SalPrinter::AbortJob()
-{
- return FALSE;
-}
-
-SalGraphics*
-SalPrinter::StartPage( ImplJobSetup* pJobSetup, BOOL bNewJobData )
-{
- Display *pDisplay = maPrinterData.mpImplData->GetXDisplay();
- SalGraphics *pGraphics = maPrinterData.mpImplData->GetGraphics();
-
- Drawable aDrawable = pGraphics->maGraphicsData.GetDrawable();
- XPContext nContext = maPrinterData.mpImplData->GetContext();
-
- unsigned short nWidth, nHeight;
- XRectangle aArea;
- Status nState = XpGetPageDimensions( pDisplay, nContext,
- &nWidth, &nHeight, &aArea );
- //fprintf(stderr, "PageSize = %ix%i (%i,%i %ix%i)\n", nWidth, nHeight,
- // aArea.x,aArea.y, aArea.width, aArea.height );
- XResizeWindow( pDisplay, aDrawable, nWidth, nHeight );
- XpStartPage ( pDisplay, aDrawable );
-
- return pGraphics;
-}
-
-BOOL
-SalPrinter::EndPage()
-{
- Display *pDisplay = maPrinterData.mpImplData->GetXDisplay();
- XpEndPage ( pDisplay );
-
- maPrinterData.mpImplData->ReleaseGraphics();
-
- return TRUE;
-}
-
-ULONG
-SalPrinter::GetErrorCode()
-{
- return 0;
-}
-
-// =======================================================================
-//
-// SalInstance
-//
-// =======================================================================
-
-SalInfoPrinter*
-SalInstance::CreateInfoPrinter(
- SalPrinterQueueInfo* pQueueInfo,
- ImplJobSetup* pSetup )
-{
- // create and initialize SalInfoPrinter
- SalInfoPrinter* pPrinter = new SalInfoPrinter;
- pPrinter->maPrinterData.Init( pQueueInfo, pSetup );
-
- pSetup->mePaperFormat = PAPER_A4; // Papierformat
- pSetup->mnPaperWidth = 21000; // Papierbreite in 100tel mm
- pSetup->mnPaperHeight = 29700; // Papierhoehe in 100tel mm
-
- return pPrinter;
-}
-
-void
-SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
-{
- delete pPrinter;
-}
-
-SalPrinter*
-SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
-{
- // create and initialize SalPrinter
- SalPrinter* pPrinter = new SalPrinter;
- pPrinter->maPrinterData.Init( pInfoPrinter );
-
- return pPrinter;
-}
-
-void
-SalInstance::DestroyPrinter( SalPrinter* pPrinter )
-{
- delete pPrinter;
-}
-
-
-void
-SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
-{
- // Neuen Eintrag anlegen
- int nCount;
- Display *XprtDisp = GetXpDisplay();
- if (XprtDisp == NULL) {
- fprintf(stderr, "Could not connect to Xprint server. Xprinting disabled.\n");
- return;
- }
- else {
- XpRehashPrinterList(XprtDisp);
- XPPrinterList XpList = XpGetPrinterList(XprtDisp, NULL, &nCount);
-
- SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
- String Name(XpList[0].name, RTL_TEXTENCODING_UTF8);
- pInfo->maPrinterName = XubString(Name);
- pInfo->maDriver = XubString(RTL_CONSTASCII_USTRINGPARAM("X Printer"));
- pInfo->maLocation = XubString(RTL_CONSTASCII_USTRINGPARAM("X Printer"));
- pInfo->maComment = XubString(RTL_CONSTASCII_USTRINGPARAM("X Printer"));
- pInfo->mpSysData = NULL;
- pList->Add( pInfo );
-
- XpFreePrinterList(XpList);
- }
-}
-
-void
-SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
-{
- return;
-}
-
-void
-SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
-{
- delete pInfo;
-}
-
-XubString
-SalInstance::GetDefaultPrinter()
-{
- Display *XprtDisp = GetXpDisplay();
- int nCount;
- if (XprtDisp == NULL)
- return XubString(RTL_CONSTASCII_USTRINGPARAM("No Default"));
- else {
- XpRehashPrinterList(XprtDisp);
- XPPrinterList XpList = XpGetPrinterList(XprtDisp, NULL, &nCount);
-
- String Name( XpList[0].name, RTL_TEXTENCODING_UTF8 );
- XpFreePrinterList(XpList);
- return (XubString(Name));
- }
-
- //return(XubString(RTL_CONSTASCII_USTRINGPARAM("X Printer")));
- // return "X Printer";
-}
-
-// =======================================================================
-//
-// SalGraphicsData
-//
-// =======================================================================
-
-void SalGraphicsData::Init(ImplSalPrinterData *pPrinter)
-{
-if (pPrinter->GetStatus()) {
- xColormap_ = &(pPrinter->GetColormap());
- hDrawable_ = pPrinter->GetDrawable();
- //pGCCache_ = pPrinter->GetGCCache();
-
- bPrinter_ = TRUE;
-
- nPenPixel_ = GetPixel( nPenColor_ );
- nTextPixel_ = GetPixel( nTextColor_ );
- nBrushPixel_ = GetPixel( nBrushColor_ );
-}
-else
- bPrinter_ = FALSE;
-
-}
-
-// =======================================================================
-//
-// Utility Functions
-//
-// =======================================================================
-
-// GetXpDisplay().
-// Finds and returns the Xprint display. First looks at environment variable XPRINTER
-// which should be in the form <printername>@<host>:<display number>. If not defined,
-// then environment variable XPDISPLAY is checked. It should be in the form
-// <host>:<display number>. If it is not defined it is set by default to ":1". If an
-// Xprint server is found then a pointer to Display is returned, otherwise NULL. This
-// function can be used by other functions to determine the current Xprint server display.
-
-// [ed] 6/15/02 We've got some linkage errors with this function on OS X,
-// perhaps due to mismatched prototypes. Let's take a quick route to the finish
-// line and declare it C linkage! +++ FIXME
-#ifdef MACOSX
-extern "C"
-#endif
-Display*
-GetXpDisplay()
-{
- char *XpDisplayName=NULL;
- Display *XpDisplay;
- if (getenv("XPRINTER")) {
- XpDisplayName=strchr(getenv("XPRINTER"),'@');
- if (XpDisplayName != NULL) {
- XpDisplayName++;
- }
- }
- else {
- if (!getenv("XPDISPLAY"))
- putenv("XPDISPLAY=:1");
- XpDisplayName=getenv("XPDISPLAY");
- }
- XpDisplay=XOpenDisplay(XpDisplayName);
- if (XpDisplay==NULL || !XSalIsPrinter(XpDisplay)) {
- return NULL;
- }
- else {
- return XpDisplay;
- }
-}
-
-// [ed] 6/15/02 We've got some linkage errors with this function on OS X,
-// perhaps due to mismatched prototypes. Let's take a quick route to the finish
-// line and declare it C linkage! +++ FIXME
-#ifdef MACOSX
-extern "C"
-#endif
-Bool
-XSalIsPrinter( Display * display )
-{
- int nEventBase;
- int nErrorBase;
-
- Bool bPrinter = XpQueryExtension( display, &nEventBase, &nErrorBase );
- return bPrinter;
-}
-
-// [ed] 6/15/02 We've got some linkage errors with this function on OS X,
-// perhaps due to mismatched prototypes. Let's take a quick route to the finish
-// line and declare it C linkage! +++ FIXME
-#ifdef MACOSX
-extern "C"
-#endif
-Bool
-XSalIsDisplay( Display * display )
-{
- return !XSalIsPrinter( display );
-}
-
diff --git a/vcl/unx/source/gdi/xrender_peer.cxx b/vcl/unx/source/gdi/xrender_peer.cxx
index 9f6e583ec723..861bf0e454aa 100644
--- a/vcl/unx/source/gdi/xrender_peer.cxx
+++ b/vcl/unx/source/gdi/xrender_peer.cxx
@@ -82,11 +82,7 @@ void XRenderPeer::InitRenderLib()
// 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
-#ifdef MACOSX
- OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrender.dylib" ));
-#else
OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrender.so.1" ));
-#endif
mpRenderLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT );
if( !mpRenderLib ) {
#ifdef DEBUG
diff --git a/vcl/unx/source/printer/cupsmgr.cxx b/vcl/unx/source/printer/cupsmgr.cxx
new file mode 100644
index 000000000000..d0c7f184fb06
--- /dev/null
+++ b/vcl/unx/source/printer/cupsmgr.cxx
@@ -0,0 +1,1140 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: cupsmgr.cxx,v $
+ * $Revision: 1.28 $
+ *
+ * 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"
+
+#ifdef ENABLE_CUPS
+#include <cups/cups.h>
+#include <cups/ppd.h>
+
+#else // !ENABLE_CUPS
+typedef void ppd_file_t;
+typedef void cups_dest_t;
+typedef void cups_option_t;
+#endif
+
+#include <unistd.h>
+
+#include "cupsmgr.hxx"
+
+#include "osl/thread.h"
+#include "osl/diagnose.h"
+#include "osl/conditn.hxx"
+
+#include "rtl/ustrbuf.hxx"
+
+#include <algorithm>
+#include <setjmp.h>
+#include <signal.h>
+
+#define CUPS_LIB_NAME "libcups.so.2"
+
+namespace psp
+{
+class CUPSWrapper
+{
+ oslModule m_pLib;
+ osl::Mutex m_aGetPPDMutex;
+ bool m_bPPDThreadRunning;
+
+ int (*m_pcupsPrintFile)(const char*, const char*, const char*, int, cups_option_t*);
+ int (*m_pcupsGetDests)(cups_dest_t**);
+ void (*m_pcupsSetDests)(int,cups_dest_t*);
+ void (*m_pcupsFreeDests)(int,cups_dest_t*);
+ const char* (*m_pcupsGetPPD)(const char*);
+ int (*m_pcupsMarkOptions)(ppd_file_t*,int,cups_option_t*);
+ int (*m_pcupsAddOption)(const char*,const char*,int,cups_option_t**);
+ void (*m_pcupsFreeOptions)(int,cups_option_t*);
+ ppd_file_t* (*m_pppdOpenFile)(const char* pFile);
+ void (*m_pppdClose)(ppd_file_t*);
+ const char* (*m_pcupsServer)();
+ void (*m_pcupsSetPasswordCB)(const char*(cb)(const char*));
+ const char* (*m_pcupsUser)();
+ void (*m_pcupsSetUser)(const char*);
+ const char* (*m_pcupsGetOption)(const char*,int,cups_option_t*);
+
+ oslGenericFunction loadSymbol( const char* );
+public:
+ CUPSWrapper();
+ ~CUPSWrapper();
+
+ bool isValid();
+
+ int cupsGetDests(cups_dest_t** pDests)
+ { return m_pcupsGetDests(pDests); }
+
+ void cupsSetDests( int nDests, cups_dest_t* pDests )
+ { m_pcupsSetDests( nDests, pDests ); }
+
+ void cupsFreeDests(int nDests, cups_dest_t* pDests)
+ { m_pcupsFreeDests(nDests, pDests); }
+
+ int cupsPrintFile( const char* pPrinter,
+ const char* pFileName,
+ const char* pTitle,
+ int nOptions,
+ cups_option_t* pOptions )
+ { return m_pcupsPrintFile( pPrinter, pFileName, pTitle, nOptions, pOptions ); }
+
+ rtl::OString cupsGetPPD( const char* pPrinter );
+
+ int cupsMarkOptions(ppd_file_t* pPPD, int nOptions, cups_option_t* pOptions )
+ { return m_pcupsMarkOptions(pPPD, nOptions, pOptions); }
+
+ int cupsAddOption( const char* pName, const char* pValue, int nOptions, cups_option_t** pOptions )
+ { return m_pcupsAddOption( pName, pValue, nOptions, pOptions ); }
+
+ void cupsFreeOptions( int nOptions, cups_option_t* pOptions )
+ { m_pcupsFreeOptions( nOptions, pOptions ); }
+
+ ppd_file_t* ppdOpenFile( const char* pFileName )
+ { return m_pppdOpenFile( pFileName ); }
+
+ void ppdClose( ppd_file_t* pPPD )
+ { m_pppdClose( pPPD ); }
+
+ const char *cupsServer(void)
+ { return m_pcupsServer(); }
+
+ const char *cupsUser(void)
+ { return m_pcupsUser(); }
+
+ void cupsSetPasswordCB(const char *(*cb)(const char *))
+ { m_pcupsSetPasswordCB( cb ); }
+
+ void cupsSetUser(const char *user)
+ { m_pcupsSetUser( user ); }
+
+ const char* cupsGetOption(const char* name, int num_options, cups_option_t* options)
+ { return m_pcupsGetOption( name, num_options, options ); }
+
+};
+}
+
+using namespace psp;
+using namespace osl;
+using namespace rtl;
+
+/*
+ * CUPSWrapper class
+ */
+
+oslGenericFunction CUPSWrapper::loadSymbol( const char* pSymbol )
+{
+ OUString aSym( OUString::createFromAscii( pSymbol ) );
+ oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
+#endif
+ return pSym;
+}
+
+CUPSWrapper::CUPSWrapper()
+ : m_pLib( NULL ),
+ m_bPPDThreadRunning( false )
+{
+#ifdef ENABLE_CUPS
+ OUString aLib( RTL_CONSTASCII_USTRINGPARAM( CUPS_LIB_NAME ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( ! m_pLib )
+ {
+ aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( SAL_MODULENAME( "cups" ) ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ }
+#endif
+
+ if( ! m_pLib )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "no cups library found\n" );
+#endif
+ return;
+ }
+
+ m_pcupsPrintFile = (int(*)(const char*,const char*,const char*,int,cups_option_t*))
+ loadSymbol( "cupsPrintFile" );
+ m_pcupsGetDests = (int(*)(cups_dest_t**))
+ loadSymbol( "cupsGetDests" );
+ m_pcupsSetDests = (void(*)(int,cups_dest_t*))
+ loadSymbol( "cupsSetDests" );
+ m_pcupsFreeDests = (void(*)(int,cups_dest_t*))
+ loadSymbol( "cupsFreeDests" );
+ m_pcupsGetPPD = (const char*(*)(const char*))
+ loadSymbol( "cupsGetPPD" );
+ m_pcupsMarkOptions = (int(*)(ppd_file_t*,int,cups_option_t*))
+ loadSymbol( "cupsMarkOptions" );
+ m_pcupsAddOption = (int(*)(const char*,const char*,int,cups_option_t**))
+ loadSymbol( "cupsAddOption" );
+ m_pcupsFreeOptions = (void(*)(int,cups_option_t*))
+ loadSymbol( "cupsFreeOptions" );
+ m_pppdOpenFile = (ppd_file_t*(*)(const char*))
+ loadSymbol( "ppdOpenFile" );
+ m_pppdClose = (void(*)(ppd_file_t*))
+ loadSymbol( "ppdClose" );
+ m_pcupsServer = (const char*(*)())
+ loadSymbol( "cupsServer" );
+ m_pcupsUser = (const char*(*)())
+ loadSymbol( "cupsUser" );
+ m_pcupsSetPasswordCB = (void(*)(const char*(*)(const char*)))
+ loadSymbol( "cupsSetPasswordCB" );
+ m_pcupsSetUser = (void(*)(const char*))
+ loadSymbol( "cupsSetUser" );
+ m_pcupsGetOption = (const char*(*)(const char*,int,cups_option_t*))
+ loadSymbol( "cupsGetOption" );
+
+ if( ! (
+ m_pcupsPrintFile &&
+ m_pcupsGetDests &&
+ m_pcupsSetDests &&
+ m_pcupsFreeDests &&
+ m_pcupsGetPPD &&
+ m_pcupsMarkOptions &&
+ m_pcupsAddOption &&
+ m_pcupsServer &&
+ m_pcupsUser &&
+ m_pcupsSetPasswordCB &&
+ m_pcupsSetUser &&
+ m_pcupsFreeOptions &&
+ m_pppdOpenFile &&
+ m_pppdClose &&
+ m_pcupsGetOption
+ ) )
+ {
+ osl_unloadModule( m_pLib );
+ m_pLib = NULL;
+ }
+}
+
+CUPSWrapper::~CUPSWrapper()
+{
+ if( m_pLib )
+ osl_unloadModule( m_pLib );
+}
+
+bool CUPSWrapper::isValid()
+{
+ return m_pLib != NULL;
+}
+
+typedef const char*(*PPDFunction)(const char*);
+struct GetPPDAttribs
+{
+ PPDFunction m_pFunction;
+ osl::Condition m_aCondition;
+ OString m_aParameter;
+ OString m_aResult;
+ oslThread m_aThread;
+ int m_nRefs;
+ bool* m_pResetRunning;
+ osl::Mutex* m_pSyncMutex;
+
+ GetPPDAttribs( PPDFunction pFn, const char * m_pParameter,
+ bool* pResetRunning, osl::Mutex* pSyncMutex )
+ : m_pFunction( pFn ),
+ m_aParameter( m_pParameter ),
+ m_pResetRunning( pResetRunning ),
+ m_pSyncMutex( pSyncMutex )
+ {
+ m_nRefs = 2;
+ m_aCondition.reset();
+ }
+
+ ~GetPPDAttribs()
+ {
+ if( m_aResult.getLength() )
+ unlink( m_aResult.getStr() );
+ }
+
+ void unref()
+ {
+ if( --m_nRefs == 0 )
+ {
+ *m_pResetRunning = false;
+ delete this;
+ }
+ }
+
+ void executeCall()
+ {
+ // This CUPS method is not at all thread-safe we need
+ // to dup the pointer to a static buffer it returns ASAP
+ OString aResult = m_pFunction( m_aParameter );
+ MutexGuard aGuard( *m_pSyncMutex );
+ m_aResult = aResult;
+ m_aCondition.set();
+ unref();
+ }
+
+ OString waitResult( TimeValue *pDelay )
+ {
+ m_pSyncMutex->release();
+
+ if (m_aCondition.wait( pDelay ) != Condition::result_ok
+ )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsGetPPD %s timed out\n",
+ (const sal_Char *) m_aParameter
+ );
+ #endif
+ }
+ m_pSyncMutex->acquire();
+
+ OString aRetval = m_aResult;
+ m_aResult = OString();
+ unref();
+
+ return aRetval;
+ }
+};
+
+extern "C" {
+ static void getPPDWorker(void* pData)
+ {
+ GetPPDAttribs* pAttribs = (GetPPDAttribs*)pData;
+ pAttribs->executeCall();
+ }
+}
+
+OString CUPSWrapper::cupsGetPPD( const char* pPrinter )
+{
+ OString aResult;
+
+ m_aGetPPDMutex.acquire();
+ // if one thread hangs in cupsGetPPD already, don't start another
+ if( ! m_bPPDThreadRunning )
+ {
+ m_bPPDThreadRunning = true;
+ GetPPDAttribs* pAttribs = new GetPPDAttribs( m_pcupsGetPPD,
+ pPrinter,
+ &m_bPPDThreadRunning,
+ &m_aGetPPDMutex );
+
+ oslThread aThread = osl_createThread( getPPDWorker, pAttribs );
+
+ TimeValue aValue;
+ aValue.Seconds = 5;
+ aValue.Nanosec = 0;
+
+ // NOTE: waitResult release and acquires the GetPPD mutex
+ aResult = pAttribs->waitResult( &aValue );
+ osl_destroyThread( aThread );
+ }
+ m_aGetPPDMutex.release();
+
+ return aResult;
+}
+
+#ifdef ENABLE_CUPS
+static const char* setPasswordCallback( const char* pIn )
+{
+ const char* pRet = NULL;
+
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ if( rMgr.getType() == PrinterInfoManager::CUPS ) // sanity check
+ pRet = static_cast<CUPSManager&>(rMgr).authenticateUser( pIn );
+ return pRet;
+}
+#endif
+
+/*
+ * CUPSManager class
+ */
+
+CUPSManager* CUPSManager::tryLoadCUPS()
+{
+ CUPSManager* pManager = NULL;
+#ifdef ENABLE_CUPS
+ static const char* pEnv = getenv( "SAL_DISABLE_CUPS" );
+
+ if( ! pEnv || ! *pEnv )
+ {
+ // try to load CUPS
+ CUPSWrapper* pWrapper = new CUPSWrapper();
+ if( pWrapper->isValid() )
+ pManager = new CUPSManager( pWrapper );
+ else
+ delete pWrapper;
+ }
+#endif
+ return pManager;
+}
+
+extern "C"
+{
+static void run_dest_thread_stub( void* pThis )
+{
+ CUPSManager::runDestThread( pThis );
+}
+}
+
+CUPSManager::CUPSManager( CUPSWrapper* pWrapper ) :
+ PrinterInfoManager( CUPS ),
+ m_pCUPSWrapper( pWrapper ),
+ m_nDests( 0 ),
+ m_pDests( NULL ),
+ m_bNewDests( false )
+{
+ m_aDestThread = osl_createThread( run_dest_thread_stub, this );
+}
+
+CUPSManager::~CUPSManager()
+{
+ if( m_aDestThread )
+ {
+ // if the thread is still running here, then
+ // cupsGetDests is hung; terminate the thread instead of joining
+ osl_terminateThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ }
+
+ if( m_nDests && m_pDests )
+ m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
+ delete m_pCUPSWrapper;
+}
+
+void CUPSManager::runDestThread( void* pThis )
+{
+ ((CUPSManager*)pThis)->runDests();
+}
+
+static sigjmp_buf aViolationBuffer;
+
+extern "C"
+{
+ static void lcl_signal_action(int nSignal)
+ {
+ fprintf( stderr, "Signal %d during fontconfig initialization called, ignoring fontconfig\n", nSignal );
+ siglongjmp( aViolationBuffer, 1 );
+ }
+}
+
+void CUPSManager::runDests()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "starting cupsGetDests\n" );
+#endif
+ int nDests = 0;
+ cups_dest_t* pDests = NULL;
+
+ // #i86306# prepare against really broken CUPS installations / missing servers
+
+ // install signal handler for SEGV, BUS and ABRT
+ struct sigaction act;
+ struct sigaction oact[3];
+
+ act.sa_handler = lcl_signal_action;
+ act.sa_flags = 0;
+ sigemptyset(&(act.sa_mask));
+
+ int nSegvSignalInstalled = sigaction(SIGSEGV, &act, &oact[0]);
+ int nBusSignalInstalled = sigaction(SIGBUS, &act, &oact[1]);
+ int nAbortSignalInstalled = sigaction(SIGABRT, &act, &oact[2]);
+
+ // prepare against a signal during FcInit or FcConfigGetCurrent
+ if( sigsetjmp( aViolationBuffer, ~0 ) == 0 )
+ {
+ nDests = m_pCUPSWrapper->cupsGetDests( &pDests );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "came out of cupsGetDests\n" );
+ #endif
+
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+ m_nDests = nDests;
+ m_pDests = pDests;
+ m_bNewDests = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "finished cupsGetDests\n" );
+ #endif
+ }
+ else
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsGetDests crashed, not using CUPS\n" );
+ #endif
+ }
+
+ // restore old signal handlers
+ if( nSegvSignalInstalled == 0 )
+ sigaction( SIGSEGV, &oact[0], NULL );
+ if( nBusSignalInstalled == 0 )
+ sigaction( SIGBUS, &oact[1], NULL );
+ if( nAbortSignalInstalled == 0 )
+ sigaction( SIGABRT, &oact[2], NULL );
+}
+
+void CUPSManager::initialize()
+{
+ // get normal printers, clear printer list
+ PrinterInfoManager::initialize();
+
+#ifdef ENABLE_CUPS
+ // check whether thread has completed
+ // if not behave like old printing system
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ if( ! m_bNewDests )
+ return;
+
+ // dest thread has run, clean up
+ if( m_aDestThread )
+ {
+ osl_joinWithThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ m_aDestThread = NULL;
+ }
+ m_bNewDests = false;
+
+ // clear old stuff
+ m_aCUPSDestMap.clear();
+
+ if( ! (m_nDests && m_pDests ) )
+ return;
+
+ if( isCUPSDisabled() )
+ return;
+
+ // check for CUPS server(?) > 1.2
+ // since there is no API to query, check for options that were
+ // introduced in dests with 1.2
+ // this is needed to check for %%IncludeFeature support
+ // (#i65684#, #i65491#)
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests);
+ const char* pOpt = m_pCUPSWrapper->cupsGetOption( "printer-info",
+ pDest->num_options,
+ pDest->options );
+ if( pOpt )
+ m_bUseIncludeFeature = true;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ int nPrinter = m_nDests;
+
+ // reset global default PPD options; these are queried on demand from CUPS
+ m_aGlobalDefaults.m_pParser = NULL;
+ m_aGlobalDefaults.m_aContext = PPDContext();
+
+ // add CUPS printers, should there be a printer
+ // with the same name as a CUPS printer, overwrite it
+ while( nPrinter-- )
+ {
+ pDest = ((cups_dest_t*)m_pDests)+nPrinter;
+ OUString aPrinterName = OStringToOUString( pDest->name, aEncoding );
+ if( pDest->instance && *pDest->instance )
+ {
+ OUStringBuffer aBuf( 256 );
+ aBuf.append( aPrinterName );
+ aBuf.append( sal_Unicode( '/' ) );
+ aBuf.append( OStringToOUString( pDest->instance, aEncoding ) );
+ aPrinterName = aBuf.makeStringAndClear();
+ }
+
+ // initialize printer with possible configuration from psprint.conf
+ bool bSetToGlobalDefaults = m_aPrinters.find( aPrinterName ) == m_aPrinters.end();
+ Printer aPrinter = m_aPrinters[ aPrinterName ];
+ if( bSetToGlobalDefaults )
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ if( pDest->is_default )
+ m_aDefaultPrinter = aPrinterName;
+
+ for( int k = 0; k < pDest->num_options; k++ )
+ {
+ if(!strcmp(pDest->options[k].name, "printer-info"))
+ aPrinter.m_aInfo.m_aComment=OStringToOUString(pDest->options[k].value, aEncoding);
+ if(!strcmp(pDest->options[k].name, "printer-location"))
+ aPrinter.m_aInfo.m_aLocation=OStringToOUString(pDest->options[k].value, aEncoding);
+ }
+
+
+ OUStringBuffer aBuf( 256 );
+ aBuf.appendAscii( "CUPS:" );
+ aBuf.append( aPrinterName );
+ // note: the parser that goes with the PrinterInfo
+ // is created implicitly by the JobData::operator=()
+ // when it detects the NULL ptr m_pParser.
+ // if we wanted to fill in the parser here this
+ // would mean we'd have to download PPDs for each and
+ // every printer - which would be really bad runtime
+ // behaviour
+ aPrinter.m_aInfo.m_pParser = NULL;
+ aPrinter.m_aInfo.m_aContext.setParser( NULL );
+ std::hash_map< OUString, PPDContext, OUStringHash >::const_iterator c_it = m_aDefaultContexts.find( aPrinterName );
+ if( c_it != m_aDefaultContexts.end() )
+ {
+ aPrinter.m_aInfo.m_pParser = c_it->second.getParser();
+ aPrinter.m_aInfo.m_aContext = c_it->second;
+ }
+ aPrinter.m_aInfo.m_aDriverName = aBuf.makeStringAndClear();
+ aPrinter.m_bModified = false;
+
+ m_aPrinters[ aPrinter.m_aInfo.m_aPrinterName ] = aPrinter;
+ m_aCUPSDestMap[ aPrinter.m_aInfo.m_aPrinterName ] = nPrinter;
+ }
+
+ // remove everything that is not a CUPS printer and not
+ // a special purpose printer (PDF, Fax)
+ std::list< OUString > aRemovePrinters;
+ for( std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.begin();
+ it != m_aPrinters.end(); ++it )
+ {
+ if( m_aCUPSDestMap.find( it->first ) != m_aCUPSDestMap.end() )
+ continue;
+
+ if( it->second.m_aInfo.m_aFeatures.getLength() > 0 )
+ continue;
+ aRemovePrinters.push_back( it->first );
+ }
+ while( aRemovePrinters.begin() != aRemovePrinters.end() )
+ {
+ m_aPrinters.erase( aRemovePrinters.front() );
+ aRemovePrinters.pop_front();
+ }
+
+ m_pCUPSWrapper->cupsSetPasswordCB( setPasswordCallback );
+#endif // ENABLE_CUPS
+}
+
+#ifdef ENABLE_CUPS
+static void updatePrinterContextInfo( ppd_group_t* pPPDGroup, PPDContext& rContext )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ for( int i = 0; i < pPPDGroup->num_options; i++ )
+ {
+ ppd_option_t* pOption = pPPDGroup->options + i;
+ for( int n = 0; n < pOption->num_choices; n++ )
+ {
+ ppd_choice_t* pChoice = pOption->choices + n;
+ if( pChoice->marked )
+ {
+ const PPDKey* pKey = rContext.getParser()->getKey( OStringToOUString( pOption->keyword, aEncoding ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = pKey->getValue( OStringToOUString( pChoice->choice, aEncoding ) );
+ if( pValue )
+ {
+ if( pValue != pKey->getDefaultValue() )
+ {
+ rContext.setValue( pKey, pValue, true );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "key %s is set to %s\n", pOption->keyword, pChoice->choice );
+#endif
+
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "key %s is defaulted to %s\n", pOption->keyword, pChoice->choice );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "caution: value %s not found in key %s\n", pChoice->choice, pOption->keyword );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "caution: key %s not found in parser\n", pOption->keyword );
+#endif
+ }
+ }
+ }
+
+ // recurse through subgroups
+ for( int g = 0; g < pPPDGroup->num_subgroups; g++ )
+ {
+ updatePrinterContextInfo( pPPDGroup->subgroups + g, rContext );
+ }
+}
+#endif // ENABLE_CUPS
+
+const PPDParser* CUPSManager::createCUPSParser( const OUString& rPrinter )
+{
+ const PPDParser* pNewParser = NULL;
+ OUString aPrinter;
+
+ if( rPrinter.compareToAscii( "CUPS:", 5 ) == 0 )
+ aPrinter = rPrinter.copy( 5 );
+ else
+ aPrinter = rPrinter;
+
+#ifdef ENABLE_CUPS
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ if( m_nDests && m_pDests && ! isCUPSDisabled() )
+ {
+ std::hash_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( aPrinter );
+ if( dest_it != m_aCUPSDestMap.end() )
+ {
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
+ OString aPPDFile = m_pCUPSWrapper->cupsGetPPD( pDest->name );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PPD for %s is %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr(), aPPDFile.getStr() );
+ #endif
+ if( aPPDFile.getLength() )
+ {
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ OUString aFileName( OStringToOUString( aPPDFile, aEncoding ) );
+ // update the printer info with context information
+ ppd_file_t* pPPD = m_pCUPSWrapper->ppdOpenFile( aPPDFile.getStr() );
+ if( pPPD )
+ {
+ // create the new parser
+ PPDParser* pCUPSParser = new PPDParser( aFileName );
+ pCUPSParser->m_aFile = rPrinter;
+ pNewParser = pCUPSParser;
+
+ /*int nConflicts =*/ m_pCUPSWrapper->cupsMarkOptions( pPPD, pDest->num_options, pDest->options );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "processing the following options for printer %s (instance %s):\n",
+ pDest->name, pDest->instance );
+ for( int k = 0; k < pDest->num_options; k++ )
+ fprintf( stderr, " \"%s\" = \"%s\"\n",
+ pDest->options[k].name,
+ pDest->options[k].value );
+ #endif
+ PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
+
+ // remember the default context for later use
+ PPDContext& rContext = m_aDefaultContexts[ aPrinter ];
+ rContext.setParser( pNewParser );
+ // set system default paper; printer CUPS PPD options
+ // may overwrite it
+ setDefaultPaper( rContext );
+ for( int i = 0; i < pPPD->num_groups; i++ )
+ updatePrinterContextInfo( pPPD->groups + i, rContext );
+
+ rInfo.m_pParser = pNewParser;
+ rInfo.m_aContext = rContext;
+
+ // clean up the mess
+ m_pCUPSWrapper->ppdClose( pPPD );
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "ppdOpenFile failed, falling back to generic driver\n" );
+ #endif
+
+ // remove temporary PPD file
+ unlink( aPPDFile.getStr() );
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "cupsGetPPD failed, falling back to generic driver\n" );
+ #endif
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no dest found for printer %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr() );
+ #endif
+ }
+ m_aCUPSMutex.release();
+ }
+ #if OSL_DEBUG_LEVEL >1
+ else
+ fprintf( stderr, "could not acquire CUPS mutex !!!\n" );
+ #endif
+ #endif // ENABLE_CUPS
+
+ if( ! pNewParser )
+ {
+ // get the default PPD
+ pNewParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
+
+ PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
+
+ rInfo.m_pParser = pNewParser;
+ rInfo.m_aContext.setParser( pNewParser );
+ }
+
+ return pNewParser;
+}
+
+void CUPSManager::setupJobContextData(
+ JobData&
+#ifdef ENABLE_CUPS
+ rData
+#endif
+)
+{
+#ifdef ENABLE_CUPS
+ std::hash_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( rData.m_aPrinterName );
+
+ if( dest_it == m_aCUPSDestMap.end() )
+ return PrinterInfoManager::setupJobContextData( rData );
+
+ std::hash_map< OUString, Printer, OUStringHash >::iterator p_it =
+ m_aPrinters.find( rData.m_aPrinterName );
+ if( p_it == m_aPrinters.end() ) // huh ?
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "CUPS printer list in disorder, no dest for printer %s !\n", OUStringToOString( rData.m_aPrinterName, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return;
+ }
+
+ if( p_it->second.m_aInfo.m_pParser == NULL )
+ {
+ // in turn calls createCUPSParser
+ // which updates the printer info
+ p_it->second.m_aInfo.m_pParser = PPDParser::getParser( p_it->second.m_aInfo.m_aDriverName );
+ }
+ if( p_it->second.m_aInfo.m_aContext.getParser() == NULL )
+ {
+ OUString aPrinter;
+ if( p_it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) == 0 )
+ aPrinter = p_it->second.m_aInfo.m_aDriverName.copy( 5 );
+ else
+ aPrinter = p_it->second.m_aInfo.m_aDriverName;
+
+ p_it->second.m_aInfo.m_aContext = m_aDefaultContexts[ aPrinter ];
+ }
+
+ rData.m_pParser = p_it->second.m_aInfo.m_pParser;
+ rData.m_aContext = p_it->second.m_aInfo.m_aContext;
+#endif
+}
+
+FILE* CUPSManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
+{
+ if( m_aCUPSDestMap.find( rPrintername ) == m_aCUPSDestMap.end() )
+ return PrinterInfoManager::startSpool( rPrintername, bQuickCommand );
+
+#ifdef ENABLE_CUPS
+ OUString aTmpURL, aTmpFile;
+ osl_createTempFile( NULL, NULL, &aTmpURL.pData );
+ osl_getSystemPathFromFileURL( aTmpURL.pData, &aTmpFile.pData );
+ OString aSysFile = OUStringToOString( aTmpFile, osl_getThreadTextEncoding() );
+ FILE* fp = fopen( aSysFile.getStr(), "w" );
+ if( fp )
+ m_aSpoolFiles[fp] = aSysFile;
+
+ return fp;
+#else
+ return NULL;
+#endif
+}
+
+struct less_ppd_key : public ::std::binary_function<double, double, bool>
+{
+ bool operator()(const PPDKey* left, const PPDKey* right)
+ { return left->getOrderDependency() < right->getOrderDependency(); }
+};
+
+void CUPSManager::getOptionsFromDocumentSetup( const JobData& rJob, int& rNumOptions, void** rOptions ) const
+{
+ rNumOptions = 0;
+ *rOptions = NULL;
+ int i;
+
+ // emit features ordered to OrderDependency
+ // ignore features that are set to default
+
+ // sanity check
+ if( rJob.m_pParser == rJob.m_aContext.getParser() && rJob.m_pParser )
+ {
+ int nKeys = rJob.m_aContext.countValuesModified();
+ ::std::vector< const PPDKey* > aKeys( nKeys );
+ for( i = 0; i < nKeys; i++ )
+ aKeys[i] = rJob.m_aContext.getModifiedKey( i );
+ ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
+
+ for( i = 0; i < nKeys; i++ )
+ {
+ const PPDKey* pKey = aKeys[i];
+ const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
+ if(pValue && pValue->m_eType == eInvocation && pValue->m_aValue.Len() )
+ {
+ OString aKey = OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US );
+ OString aValue = OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US );
+ rNumOptions = m_pCUPSWrapper->cupsAddOption( aKey.getStr(), aValue.getStr(), rNumOptions, (cups_option_t**)rOptions );
+ }
+ }
+ }
+}
+
+int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData )
+{
+ int nJobID = 0;
+
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ std::hash_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( rPrintername );
+ if( dest_it == m_aCUPSDestMap.end() )
+ return PrinterInfoManager::endSpool( rPrintername, rJobTitle, pFile, rDocumentJobData );
+
+ #ifdef ENABLE_CUPS
+ std::hash_map< FILE*, OString, FPtrHash >::const_iterator it = m_aSpoolFiles.find( pFile );
+ if( it != m_aSpoolFiles.end() )
+ {
+ fclose( pFile );
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+
+ // setup cups options
+ int nNumOptions = 0;
+ cups_option_t* pOptions = NULL;
+ getOptionsFromDocumentSetup( rDocumentJobData, nNumOptions, (void**)&pOptions );
+
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
+ nJobID = m_pCUPSWrapper->cupsPrintFile( pDest->name,
+ it->second.getStr(),
+ OUStringToOString( rJobTitle, aEnc ).getStr(),
+ nNumOptions, pOptions );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsPrintFile( %s, %s, %s, %d, %p ) returns %d\n",
+ pDest->name,
+ it->second.getStr(),
+ OUStringToOString( rJobTitle, aEnc ).getStr(),
+ nNumOptions,
+ pOptions,
+ nJobID
+ );
+ for( int n = 0; n < nNumOptions; n++ )
+ fprintf( stderr, " option %s=%s\n", pOptions[n].name, pOptions[n].value );
+ OString aCmd( "cp " );
+ aCmd = aCmd + it->second;
+ aCmd = aCmd + OString( " $HOME/cupsprint.ps" );
+ system( aCmd.getStr() );
+#endif
+
+ unlink( it->second.getStr() );
+ m_aSpoolFiles.erase( pFile );
+ if( pOptions )
+ m_pCUPSWrapper->cupsFreeOptions( nNumOptions, pOptions );
+ }
+#endif // ENABLE_CUPS
+
+ return nJobID;
+}
+
+
+void CUPSManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
+{
+ PrinterInfoManager::changePrinterInfo( rPrinter, rNewInfo );
+}
+
+bool CUPSManager::checkPrintersChanged( bool bWait )
+{
+ bool bChanged = false;
+ if( bWait )
+ {
+ if( m_aDestThread )
+ {
+ // initial asynchronous detection still running
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "syncing cups discovery thread\n" );
+ #endif
+ osl_joinWithThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ m_aDestThread = NULL;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "done: syncing cups discovery thread\n" );
+ #endif
+ }
+ else
+ {
+ // #i82321# check for cups printer updates
+ // with this change the whole asynchronous detection in a thread is
+ // almost useless. The only relevance left is for some stalled systems
+ // where the user can set SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION
+ // (see vcl/unx/source/gdi/salprnpsp.cxx)
+ // so that checkPrintersChanged( true ) will never be called
+
+ // there is no way to query CUPS whether the printer list has changed
+ // so get the dest list anew
+ if( m_nDests && m_pDests )
+ m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_nDests = 0;
+ m_pDests = NULL;
+ runDests();
+ }
+ }
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ bChanged = m_bNewDests;
+ m_aCUPSMutex.release();
+ }
+
+ if( ! bChanged )
+ {
+ bChanged = PrinterInfoManager::checkPrintersChanged( bWait );
+ // #i54375# ensure new merging with CUPS list in :initialize
+ if( bChanged )
+ m_bNewDests = true;
+ }
+
+ if( bChanged )
+ initialize();
+
+ return bChanged;
+}
+
+bool CUPSManager::addPrinter( const OUString& rName, const OUString& rDriver )
+{
+ // don't touch the CUPS printers
+ if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() ||
+ rDriver.compareToAscii( "CUPS:", 5 ) == 0
+ )
+ return false;
+ return PrinterInfoManager::addPrinter( rName, rDriver );
+}
+
+bool CUPSManager::removePrinter( const OUString& rName, bool bCheck )
+{
+ // don't touch the CUPS printers
+ if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() )
+ return false;
+ return PrinterInfoManager::removePrinter( rName, bCheck );
+}
+
+bool CUPSManager::setDefaultPrinter( const OUString& rName )
+{
+ bool bSuccess = false;
+#ifdef ENABLE_CUPS
+ std::hash_map< OUString, int, OUStringHash >::iterator nit =
+ m_aCUPSDestMap.find( rName );
+ if( nit != m_aCUPSDestMap.end() && m_aCUPSMutex.tryToAcquire() )
+ {
+ cups_dest_t* pDests = (cups_dest_t*)m_pDests;
+ for( int i = 0; i < m_nDests; i++ )
+ pDests[i].is_default = 0;
+ pDests[ nit->second ].is_default = 1;
+ m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_aDefaultPrinter = rName;
+ m_aCUPSMutex.release();
+ bSuccess = true;
+ }
+ else
+#endif
+ bSuccess = PrinterInfoManager::setDefaultPrinter( rName );
+
+ return bSuccess;
+}
+
+bool CUPSManager::writePrinterConfig()
+{
+#ifdef ENABLE_CUPS
+ bool bDestModified = false;
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+
+ for( std::hash_map< OUString, Printer, OUStringHash >::iterator prt =
+ m_aPrinters.begin(); prt != m_aPrinters.end(); ++prt )
+ {
+ std::hash_map< OUString, int, OUStringHash >::iterator nit =
+ m_aCUPSDestMap.find( prt->first );
+ if( nit == m_aCUPSDestMap.end() )
+ continue;
+
+ if( ! prt->second.m_bModified )
+ continue;
+
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ bDestModified = true;
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + nit->second;
+ PrinterInfo& rInfo = prt->second.m_aInfo;
+
+ // create new option list
+ int nNewOptions = 0;
+ cups_option_t* pNewOptions = NULL;
+ int nValues = rInfo.m_aContext.countValuesModified();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDKey* pKey = rInfo.m_aContext.getModifiedKey( i );
+ const PPDValue* pValue = rInfo.m_aContext.getValue( pKey );
+ if( pKey && pValue ) // sanity check
+ {
+ OString aName = OUStringToOString( pKey->getKey(), aEncoding );
+ OString aValue = OUStringToOString( pValue->m_aOption, aEncoding );
+ nNewOptions = m_pCUPSWrapper->cupsAddOption( aName.getStr(), aValue.getStr(), nNewOptions, &pNewOptions );
+ }
+ }
+ // set PPD options on CUPS dest
+ m_pCUPSWrapper->cupsFreeOptions( pDest->num_options, pDest->options );
+ pDest->num_options = nNewOptions;
+ pDest->options = pNewOptions;
+ m_aCUPSMutex.release();
+ }
+ }
+ if( bDestModified && m_aCUPSMutex.tryToAcquire() )
+ {
+ m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_aCUPSMutex.release();
+ }
+#endif // ENABLE_CUPS
+
+ return PrinterInfoManager::writePrinterConfig();
+}
+
+bool CUPSManager::addOrRemovePossible() const
+{
+ return (m_nDests && m_pDests && ! isCUPSDisabled())? false : PrinterInfoManager::addOrRemovePossible();
+}
+
+#include <rtsname.hxx>
+
+const char* CUPSManager::authenticateUser( const char* /*pIn*/ )
+{
+ const char* pRet = NULL;
+
+#ifdef ENABLE_CUPS
+ OUString aLib = OUString::createFromAscii( _XSALSET_LIBNAME );
+ oslModule pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( pLib )
+ {
+ OUString aSym( RTL_CONSTASCII_USTRINGPARAM( "Sal_authenticateQuery" ) );
+ bool (*getpw)( const OString& rServer, OString& rUser, OString& rPw) =
+ (bool(*)(const OString&,OString&,OString&))osl_getFunctionSymbol( pLib, aSym.pData );
+ if( getpw )
+ {
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ OString aUser = m_pCUPSWrapper->cupsUser();
+ OString aServer = m_pCUPSWrapper->cupsServer();
+ OString aPassword;
+ if( getpw( aServer, aUser, aPassword ) )
+ {
+ m_aPassword = aPassword;
+ m_aUser = aUser;
+ m_pCUPSWrapper->cupsSetUser( m_aUser.getStr() );
+ pRet = m_aPassword.getStr();
+ }
+ }
+ osl_unloadModule( pLib );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else fprintf( stderr, "loading of module %s failed\n", OUStringToOString( aLib, osl_getThreadTextEncoding() ).getStr() );
+#endif
+#endif // ENABLE_CUPS
+
+ return pRet;
+}
diff --git a/vcl/unx/source/printer/jobdata.cxx b/vcl/unx/source/printer/jobdata.cxx
new file mode 100644
index 000000000000..51e171d578d9
--- /dev/null
+++ b/vcl/unx/source/printer/jobdata.cxx
@@ -0,0 +1,207 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: jobdata.cxx,v $
+ * $Revision: 1.10 $
+ *
+ * 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/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "tools/stream.hxx"
+
+#include "sal/alloca.h"
+
+using namespace psp;
+using namespace rtl;
+
+JobData& JobData::operator=(const JobData& rRight)
+{
+ m_nCopies = rRight.m_nCopies;
+ m_nLeftMarginAdjust = rRight.m_nLeftMarginAdjust;
+ m_nRightMarginAdjust = rRight.m_nRightMarginAdjust;
+ m_nTopMarginAdjust = rRight.m_nTopMarginAdjust;
+ m_nBottomMarginAdjust = rRight.m_nBottomMarginAdjust;
+ m_nColorDepth = rRight.m_nColorDepth;
+ m_eOrientation = rRight.m_eOrientation;
+ m_aPrinterName = rRight.m_aPrinterName;
+ m_pParser = rRight.m_pParser;
+ m_aContext = rRight.m_aContext;
+ m_nPSLevel = rRight.m_nPSLevel;
+ m_nColorDevice = rRight.m_nColorDevice;
+
+ if( ! m_pParser && m_aPrinterName.getLength() )
+ {
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ rMgr.setupJobContextData( *this );
+ }
+ return *this;
+}
+
+bool JobData::getStreamBuffer( void*& pData, int& bytes )
+{
+ // consistency checks
+ if( ! m_pParser )
+ m_pParser = m_aContext.getParser();
+ if( m_pParser != m_aContext.getParser() ||
+ ! m_pParser )
+ return false;
+
+ SvMemoryStream aStream;
+ ByteString aLine;
+
+ // write header job data
+ aStream.WriteLine( "JobData 1" );
+
+ aLine = "printer=";
+ aLine += ByteString( String( m_aPrinterName ), RTL_TEXTENCODING_UTF8 );
+ aStream.WriteLine( aLine );
+
+ aLine = "orientation=";
+ aLine += m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait";
+ aStream.WriteLine( aLine );
+
+ aLine = "copies=";
+ aLine += ByteString::CreateFromInt32( m_nCopies );
+ aStream.WriteLine( aLine );
+
+ aLine = "margindajustment=";
+ aLine += ByteString::CreateFromInt32( m_nLeftMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nRightMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nTopMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nBottomMarginAdjust );
+ aStream.WriteLine( aLine );
+
+ aLine = "colordepth=";
+ aLine += ByteString::CreateFromInt32( m_nColorDepth );
+ aStream.WriteLine( aLine );
+
+ aLine = "pslevel=";
+ aLine += ByteString::CreateFromInt32( m_nPSLevel );
+ aStream.WriteLine( aLine );
+
+ aLine = "colordevice=";
+ aLine += ByteString::CreateFromInt32( m_nColorDevice );
+ aStream.WriteLine( aLine );
+
+ // now append the PPDContext stream buffer
+ aStream.WriteLine( "PPDContexData" );
+ ULONG nBytes;
+ void* pContextBuffer = m_aContext.getStreamableBuffer( nBytes );
+ if( nBytes )
+ aStream.Write( pContextBuffer, nBytes );
+
+ // success
+ pData = rtl_allocateMemory( bytes = aStream.Tell() );
+ memcpy( pData, aStream.GetData(), bytes );
+ return true;
+}
+
+bool JobData::constructFromStreamBuffer( void* pData, int bytes, JobData& rJobData )
+{
+ SvMemoryStream aStream( pData, bytes, STREAM_READ );
+ ByteString aLine;
+ bool bVersion = false;
+ bool bPrinter = false;
+ bool bOrientation = false;
+ bool bCopies = false;
+ bool bContext = false;
+ bool bMargin = false;
+ bool bColorDepth = false;
+ bool bColorDevice = false;
+ bool bPSLevel = false;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.CompareTo( "JobData", 7 ) == COMPARE_EQUAL )
+ bVersion = true;
+ else if( aLine.CompareTo( "printer=", 8 ) == COMPARE_EQUAL )
+ {
+ bPrinter = true;
+ rJobData.m_aPrinterName = String( aLine.Copy( 8 ), RTL_TEXTENCODING_UTF8 );
+ }
+ else if( aLine.CompareTo( "orientation=", 12 ) == COMPARE_EQUAL )
+ {
+ bOrientation = true;
+ rJobData.m_eOrientation = aLine.Copy( 12 ).EqualsIgnoreCaseAscii( "landscape" ) ? orientation::Landscape : orientation::Portrait;
+ }
+ else if( aLine.CompareTo( "copies=", 7 ) == COMPARE_EQUAL )
+ {
+ bCopies = true;
+ rJobData.m_nCopies = aLine.Copy( 7 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "margindajustment=",17 ) == COMPARE_EQUAL )
+ {
+ bMargin = true;
+ ByteString aValues( aLine.Copy( 17 ) );
+ rJobData.m_nLeftMarginAdjust = aValues.GetToken( 0, ',' ).ToInt32();
+ rJobData.m_nRightMarginAdjust = aValues.GetToken( 1, ',' ).ToInt32();
+ rJobData.m_nTopMarginAdjust = aValues.GetToken( 2, ',' ).ToInt32();
+ rJobData.m_nBottomMarginAdjust = aValues.GetToken( 3, ',' ).ToInt32();
+ }
+ else if( aLine.CompareTo( "colordepth=", 11 ) == COMPARE_EQUAL )
+ {
+ bColorDepth = true;
+ rJobData.m_nColorDepth = aLine.Copy( 11 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "colordevice=", 12 ) == COMPARE_EQUAL )
+ {
+ bColorDevice = true;
+ rJobData.m_nColorDevice = aLine.Copy( 12 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "pslevel=", 8 ) == COMPARE_EQUAL )
+ {
+ bPSLevel = true;
+ rJobData.m_nPSLevel = aLine.Copy( 8 ).ToInt32();
+ }
+ else if( aLine.Equals( "PPDContexData" ) )
+ {
+ if( bPrinter )
+ {
+ PrinterInfoManager& rManager = PrinterInfoManager::get();
+ const PrinterInfo& rInfo = rManager.getPrinterInfo( rJobData.m_aPrinterName );
+ rJobData.m_pParser = PPDParser::getParser( rInfo.m_aDriverName );
+ if( rJobData.m_pParser )
+ {
+ rJobData.m_aContext.setParser( rJobData.m_pParser );
+ int nBytes = bytes - aStream.Tell();
+ void* pRemain = alloca( bytes - aStream.Tell() );
+ aStream.Read( pRemain, nBytes );
+ rJobData.m_aContext.rebuildFromStreamBuffer( pRemain, nBytes );
+ bContext = true;
+ }
+ }
+ }
+ }
+
+ return bVersion && bPrinter && bOrientation && bCopies && bContext && bMargin && bPSLevel && bColorDevice && bColorDepth;
+}
diff --git a/vcl/unx/source/printer/makefile.mk b/vcl/unx/source/printer/makefile.mk
new file mode 100644
index 000000000000..df184adc00fa
--- /dev/null
+++ b/vcl/unx/source/printer/makefile.mk
@@ -0,0 +1,74 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.9 $
+#
+# 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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+ENABLE_EXCEPTIONS=TRUE
+PRJNAME=vcl
+TARGET=printer
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+.IF "$(ENABLE_CUPS)" != ""
+CDEFS += -DENABLE_CUPS
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"=="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"=="aqua"
+
+SLOFILES=\
+ $(SLO)$/ppdparser.obj \
+ $(SLO)$/printerinfomanager.obj \
+ $(SLO)$/jobdata.obj \
+ $(SLO)$/cupsmgr.obj
+
+.ENDIF # GUIBASE = aqua
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+XSALSETLIBNAME=$(DLLPRE)spa$(DLLPOSTFIX)$(DLLPOST)
+
+$(INCCOM)$/rtsname.hxx:
+ rm -f $(INCCOM)$/rtsname.hxx ; \
+ echo "#define _XSALSET_LIBNAME "\"$(XSALSETLIBNAME)\" > $(INCCOM)$/rtsname.hxx
+
+$(SLO)$/cupsmgr.obj : $(INCCOM)$/rtsname.hxx
+
diff --git a/vcl/unx/source/printer/ppdparser.cxx b/vcl/unx/source/printer/ppdparser.cxx
new file mode 100644
index 000000000000..1caf64ef7e2c
--- /dev/null
+++ b/vcl/unx/source/printer/ppdparser.cxx
@@ -0,0 +1,1876 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: ppdparser.cxx,v $
+ * $Revision: 1.27 $
+ *
+ * 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 <stdio.h>
+
+#include <hash_map>
+
+#include "vcl/ppdparser.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/helper.hxx"
+#include "cupsmgr.hxx"
+#include "tools/debug.hxx"
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/zcodec.hxx"
+#include "osl/mutex.hxx"
+#include "osl/file.hxx"
+#include "osl/process.h"
+#include "osl/thread.h"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+
+using namespace psp;
+using namespace rtl;
+
+#undef DBG_ASSERT
+#if defined DBG_UTIL || (OSL_DEBUG_LEVEL > 1)
+#define BSTRING(x) ByteString( x, osl_getThreadTextEncoding() )
+#define DBG_ASSERT( x, y ) { if( ! (x) ) fprintf( stderr, (y) ); }
+#else
+#define DBG_ASSERT( x, y )
+#endif
+
+std::list< PPDParser* > PPDParser::aAllParsers;
+std::hash_map< OUString, OUString, OUStringHash >* PPDParser::pAllPPDFiles = NULL;
+static String aEmptyString;
+
+class PPDDecompressStream
+{
+ SvFileStream* mpFileStream;
+ SvMemoryStream* mpMemStream;
+ rtl::OUString maFileName;
+
+ // forbid copying
+ PPDDecompressStream( const PPDDecompressStream& );
+ PPDDecompressStream& operator=(const PPDDecompressStream& );
+
+ public:
+ PPDDecompressStream( const rtl::OUString& rFile );
+ ~PPDDecompressStream();
+
+ bool IsOpen() const;
+ bool IsEof() const;
+ void ReadLine( ByteString& o_rLine);
+ void Open( const rtl::OUString& i_rFile );
+ void Close();
+ const rtl::OUString& GetFileName() const { return maFileName; }
+};
+
+PPDDecompressStream::PPDDecompressStream( const rtl::OUString& i_rFile ) :
+ mpFileStream( NULL ),
+ mpMemStream( NULL )
+{
+ Open( i_rFile );
+}
+
+PPDDecompressStream::~PPDDecompressStream()
+{
+ Close();
+}
+
+void PPDDecompressStream::Open( const rtl::OUString& i_rFile )
+{
+ Close();
+
+ mpFileStream = new SvFileStream( i_rFile, STREAM_READ );
+ maFileName = mpFileStream->GetFileName();
+
+ if( ! mpFileStream->IsOpen() )
+ {
+ Close();
+ return;
+ }
+
+ ByteString aLine;
+ mpFileStream->ReadLine( aLine );
+ mpFileStream->Seek( 0 );
+
+ // check for compress'ed or gzip'ed file
+ ULONG nCompressMethod = 0;
+ if( aLine.Len() > 1 && static_cast<unsigned char>(aLine.GetChar( 0 )) == 0x1f )
+ {
+ if( static_cast<unsigned char>(aLine.GetChar( 1 )) == 0x8b ) // check for gzip
+ nCompressMethod = ZCODEC_DEFAULT | ZCODEC_GZ_LIB;
+ }
+
+ if( nCompressMethod != 0 )
+ {
+ // so let's try to decompress the stream
+ mpMemStream = new SvMemoryStream( 4096, 4096 );
+ ZCodec aCodec;
+ aCodec.BeginCompression( nCompressMethod );
+ long nComp = aCodec.Decompress( *mpFileStream, *mpMemStream );
+ aCodec.EndCompression();
+ if( nComp < 0 )
+ {
+ // decompression failed, must be an uncompressed stream after all
+ delete mpMemStream, mpMemStream = NULL;
+ mpFileStream->Seek( 0 );
+ }
+ else
+ {
+ // compression successfull, can get rid of file stream
+ delete mpFileStream, mpFileStream = NULL;
+ mpMemStream->Seek( 0 );
+ }
+ }
+}
+
+void PPDDecompressStream::Close()
+{
+ delete mpMemStream, mpMemStream = NULL;
+ delete mpFileStream, mpFileStream = NULL;
+}
+
+bool PPDDecompressStream::IsOpen() const
+{
+ return (mpMemStream || (mpFileStream && mpFileStream->IsOpen()));
+}
+
+bool PPDDecompressStream::IsEof() const
+{
+ return ( mpMemStream ? mpMemStream->IsEof() : ( mpFileStream ? mpFileStream->IsEof() : true ) );
+}
+
+void PPDDecompressStream::ReadLine( ByteString& o_rLine )
+{
+ if( mpMemStream )
+ mpMemStream->ReadLine( o_rLine );
+ else if( mpFileStream )
+ mpFileStream->ReadLine( o_rLine );
+}
+
+static osl::FileBase::RC resolveLink( const rtl::OUString& i_rURL, rtl::OUString& o_rResolvedURL, rtl::OUString& o_rBaseName, osl::FileStatus::Type& o_rType, int nLinkLevel = 10 )
+{
+ osl::DirectoryItem aLinkItem;
+ osl::FileBase::RC aRet = osl::FileBase::E_None;
+
+ if( ( aRet = osl::DirectoryItem::get( i_rURL, aLinkItem ) ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aStatus( FileStatusMask_FileName | FileStatusMask_Type | FileStatusMask_LinkTargetURL );
+ if( ( aRet = aLinkItem.getFileStatus( aStatus ) ) == osl::FileBase::E_None )
+ {
+ if( aStatus.getFileType() == osl::FileStatus::Link )
+ {
+ if( nLinkLevel > 0 )
+ aRet = resolveLink( aStatus.getLinkTargetURL(), o_rResolvedURL, o_rBaseName, o_rType, nLinkLevel-1 );
+ else
+ aRet = osl::FileBase::E_MULTIHOP;
+ }
+ else
+ {
+ o_rResolvedURL = i_rURL;
+ o_rBaseName = aStatus.getFileName();
+ o_rType = aStatus.getFileType();
+ }
+ }
+ }
+ return aRet;
+}
+
+void PPDParser::scanPPDDir( const String& rDir )
+{
+ static struct suffix_t
+ {
+ const sal_Char* pSuffix;
+ const sal_Int32 nSuffixLen;
+ } const pSuffixes[] =
+ { { ".PS", 3 }, { ".PPD", 4 }, { ".PS.GZ", 6 }, { ".PPD.GZ", 7 } };
+
+ const int nSuffixes = sizeof(pSuffixes)/sizeof(pSuffixes[0]);
+
+ osl::Directory aDir( rDir );
+ aDir.open();
+ osl::DirectoryItem aItem;
+
+ INetURLObject aPPDDir(rDir);
+ while( aDir.getNextItem( aItem ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aStatus( FileStatusMask_FileName );
+ if( aItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
+ {
+ rtl::OUStringBuffer aURLBuf( rDir.Len() + 64 );
+ aURLBuf.append( rDir );
+ aURLBuf.append( sal_Unicode( '/' ) );
+ aURLBuf.append( aStatus.getFileName() );
+
+ rtl::OUString aFileURL, aFileName;
+ osl::FileStatus::Type eType = osl::FileStatus::Unknown;
+
+ if( resolveLink( aURLBuf.makeStringAndClear(), aFileURL, aFileName, eType ) == osl::FileBase::E_None )
+ {
+ if( eType == osl::FileStatus::Regular )
+ {
+ INetURLObject aPPDFile = aPPDDir;
+ aPPDFile.Append( aFileName );
+
+ // match extension
+ for( int nSuffix = 0; nSuffix < nSuffixes; nSuffix++ )
+ {
+ if( aFileName.getLength() > pSuffixes[nSuffix].nSuffixLen )
+ {
+ if( aFileName.endsWithIgnoreAsciiCaseAsciiL( pSuffixes[nSuffix].pSuffix, pSuffixes[nSuffix].nSuffixLen ) )
+ {
+ (*pAllPPDFiles)[ aFileName.copy( 0, aFileName.getLength() - pSuffixes[nSuffix].nSuffixLen ) ] = aPPDFile.PathToFileName();
+ break;
+ }
+ }
+ }
+ }
+ else if( eType == osl::FileStatus::Directory )
+ {
+ scanPPDDir( aFileURL );
+ }
+ }
+ }
+ }
+ aDir.close();
+}
+
+void PPDParser::initPPDFiles()
+{
+ if( pAllPPDFiles )
+ return;
+
+ pAllPPDFiles = new std::hash_map< OUString, OUString, OUStringHash >();
+
+ // check installation directories
+ std::list< OUString > aPathList;
+ psp::getPrinterPathList( aPathList, PRINTER_PPDDIR );
+ for( std::list< OUString >::const_iterator ppd_it = aPathList.begin(); ppd_it != aPathList.end(); ++ppd_it )
+ {
+ INetURLObject aPPDDir( *ppd_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ scanPPDDir( aPPDDir.GetMainURL( INetURLObject::NO_DECODE ) );
+ }
+ if( pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles->end() )
+ {
+ // last try: search in directory of executable (mainly for setup)
+ OUString aExe;
+ if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None )
+ {
+ INetURLObject aDir( aExe );
+ aDir.removeSegment();
+#ifdef DEBUG
+ fprintf( stderr, "scanning last chance dir: %s\n", OUStringToOString( aDir.GetMainURL( INetURLObject::NO_DECODE ), osl_getThreadTextEncoding() ).getStr() );
+#endif
+ scanPPDDir( aDir.GetMainURL( INetURLObject::NO_DECODE ) );
+#ifdef DEBUG
+ fprintf( stderr, "SGENPRT %s\n", pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles->end() ? "not found" : "found" );
+#endif
+ }
+ }
+}
+
+void PPDParser::getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers )
+{
+ initPPDFiles();
+ o_rDrivers.clear();
+
+ std::hash_map< OUString, OUString, OUStringHash >::const_iterator it;
+ for( it = pAllPPDFiles->begin(); it != pAllPPDFiles->end(); ++it )
+ o_rDrivers.push_back( it->first );
+}
+
+String PPDParser::getPPDFile( const String& rFile )
+{
+ INetURLObject aPPD( rFile, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ // someone might enter a full qualified name here
+ PPDDecompressStream aStream( aPPD.PathToFileName() );
+ if( ! aStream.IsOpen() )
+ {
+ std::hash_map< OUString, OUString, OUStringHash >::const_iterator it;
+
+ bool bRetry = true;
+ do
+ {
+ initPPDFiles();
+ // some PPD files contain dots beside the extension, so try name first
+ // and cut of points after that
+ rtl::OUString aBase( rFile );
+ sal_Int32 nLastIndex = aBase.lastIndexOf( sal_Unicode( '/' ) );
+ if( nLastIndex >= 0 )
+ aBase = aBase.copy( nLastIndex+1 );
+ do
+ {
+ it = pAllPPDFiles->find( aBase );
+ nLastIndex = aBase.lastIndexOf( sal_Unicode( '.' ) );
+ if( nLastIndex > 0 )
+ aBase = aBase.copy( 0, nLastIndex );
+ } while( it == pAllPPDFiles->end() && nLastIndex > 0 );
+
+ if( it == pAllPPDFiles->end() && bRetry )
+ {
+ // a new file ? rehash
+ delete pAllPPDFiles; pAllPPDFiles = NULL;
+ bRetry = false;
+ // note this is optimized for office start where
+ // no new files occur and initPPDFiles is called only once
+ }
+ } while( ! pAllPPDFiles );
+
+ if( it != pAllPPDFiles->end() )
+ aStream.Open( it->second );
+ }
+
+ String aRet;
+ if( aStream.IsOpen() )
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ if( aLine.Search( "*PPD-Adobe" ) == 0 )
+ aRet = aStream.GetFileName();
+ else
+ {
+ // our *Include hack does usually not begin
+ // with *PPD-Adobe, so try some lines for *Include
+ int nLines = 10;
+ while( aLine.Search( "*Include" ) != 0 && --nLines )
+ aStream.ReadLine( aLine );
+ if( nLines )
+ aRet = aStream.GetFileName();
+ }
+ }
+
+ return aRet;
+}
+
+String PPDParser::getPPDPrinterName( const String& rFile )
+{
+ String aPath = getPPDFile( rFile );
+ String aName;
+
+ // read in the file
+ PPDDecompressStream aStream( aPath );
+ if( aStream.IsOpen() )
+ {
+ String aCurLine;
+ while( ! aStream.IsEof() && aStream.IsOpen() )
+ {
+ ByteString aByteLine;
+ aStream.ReadLine( aByteLine );
+ aCurLine = String( aByteLine, RTL_TEXTENCODING_MS_1252 );
+ if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL )
+ {
+ aCurLine.Erase( 0, 9 );
+ aCurLine.EraseLeadingChars( ' ' );
+ aCurLine.EraseTrailingChars( ' ' );
+ aCurLine.EraseLeadingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\r' );
+ aCurLine.EraseTrailingChars( '\n' );
+ aCurLine.EraseLeadingChars( '"' );
+ aCurLine.EraseTrailingChars( '"' );
+ aStream.Close();
+ aStream.Open( getPPDFile( aCurLine ) );
+ continue;
+ }
+ if( aCurLine.CompareToAscii( "*ModelName:", 11 ) == COMPARE_EQUAL )
+ {
+ aName = aCurLine.GetToken( 1, '"' );
+ break;
+ }
+ else if( aCurLine.CompareToAscii( "*NickName:", 10 ) == COMPARE_EQUAL )
+ aName = aCurLine.GetToken( 1, '"' );
+ }
+ }
+ return aName;
+}
+
+const PPDParser* PPDParser::getParser( const String& rFile )
+{
+ static ::osl::Mutex aMutex;
+ ::osl::Guard< ::osl::Mutex > aGuard( aMutex );
+
+ String aFile = rFile;
+ if( rFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL )
+ aFile = getPPDFile( rFile );
+ if( ! aFile.Len() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Could not get printer PPD file \"%s\" !\n", OUStringToOString( rFile, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return NULL;
+ }
+
+ for( ::std::list< PPDParser* >::const_iterator it = aAllParsers.begin(); it != aAllParsers.end(); ++it )
+ if( (*it)->m_aFile == aFile )
+ return *it;
+
+ PPDParser* pNewParser = NULL;
+ if( aFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL )
+ pNewParser = new PPDParser( aFile );
+ else
+ {
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ if( rMgr.getType() == PrinterInfoManager::CUPS )
+ {
+ pNewParser = const_cast<PPDParser*>(static_cast<CUPSManager&>(rMgr).createCUPSParser( aFile ));
+ }
+ }
+ if( pNewParser )
+ {
+ // this may actually be the SGENPRT parser,
+ // so ensure uniquness here
+ aAllParsers.remove( pNewParser );
+ // insert new parser to list
+ aAllParsers.push_front( pNewParser );
+ }
+ return pNewParser;
+}
+
+void PPDParser::freeAll()
+{
+ while( aAllParsers.begin() != aAllParsers.end() )
+ {
+ delete aAllParsers.front();
+ aAllParsers.pop_front();
+ }
+ delete pAllPPDFiles;
+ pAllPPDFiles = NULL;
+}
+
+PPDParser::PPDParser( const String& rFile ) :
+ m_aFile( rFile ),
+ m_bType42Capable( false ),
+ m_aFileEncoding( RTL_TEXTENCODING_MS_1252 ),
+ m_pDefaultImageableArea( NULL ),
+ m_pImageableAreas( NULL ),
+ m_pDefaultPaperDimension( NULL ),
+ m_pPaperDimensions( NULL ),
+ m_pDefaultInputSlot( NULL ),
+ m_pInputSlots( NULL ),
+ m_pDefaultResolution( NULL ),
+ m_pResolutions( NULL ),
+ m_pDefaultDuplexType( NULL ),
+ m_pDuplexTypes( NULL ),
+ m_pFontList( NULL )
+{
+ // read in the file
+ std::list< ByteString > aLines;
+ PPDDecompressStream aStream( m_aFile );
+ bool bLanguageEncoding = false;
+ if( aStream.IsOpen() )
+ {
+ ByteString aCurLine;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aCurLine );
+ if( aCurLine.GetChar( 0 ) == '*' )
+ {
+ if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL )
+ {
+ aCurLine.Erase( 0, 9 );
+ aCurLine.EraseLeadingChars( ' ' );
+ aCurLine.EraseTrailingChars( ' ' );
+ aCurLine.EraseLeadingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\r' );
+ aCurLine.EraseTrailingChars( '\n' );
+ aCurLine.EraseLeadingChars( '"' );
+ aCurLine.EraseTrailingChars( '"' );
+ aStream.Close();
+ aStream.Open( getPPDFile( String( aCurLine, m_aFileEncoding ) ) );
+ continue;
+ }
+ else if( ! bLanguageEncoding &&
+ aCurLine.CompareIgnoreCaseToAscii( "*languageencoding", 17 ) == COMPARE_EQUAL )
+ {
+ bLanguageEncoding = true; // generally only the first one counts
+ ByteString aLower = aCurLine;
+ aLower.ToLowerAscii();
+ if( aLower.Search( "isolatin1", 17 ) != STRING_NOTFOUND ||
+ aLower.Search( "windowsansi", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_MS_1252;
+ else if( aLower.Search( "isolatin2", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_2;
+ else if( aLower.Search( "isolatin5", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_5;
+ else if( aLower.Search( "jis83-rksj", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_SHIFT_JIS;
+ else if( aLower.Search( "macstandard", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
+ else if( aLower.Search( "utf-8", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_UTF8;
+ }
+ }
+ aLines.push_back( aCurLine );
+ }
+ }
+ aStream.Close();
+
+ // now get the Values
+ parse( aLines );
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "acquired %d Keys from PPD %s:\n", m_aKeys.size(), BSTRING( m_aFile ).GetBuffer() );
+ for( PPDParser::hash_type::const_iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it )
+ {
+ const PPDKey* pKey = it->second;
+ char* pSetupType = "<unknown>";
+ switch( pKey->m_eSetupType )
+ {
+ case PPDKey::ExitServer: pSetupType = "ExitServer";break;
+ case PPDKey::Prolog: pSetupType = "Prolog";break;
+ case PPDKey::DocumentSetup: pSetupType = "DocumentSetup";break;
+ case PPDKey::PageSetup: pSetupType = "PageSetup";break;
+ case PPDKey::JCLSetup: pSetupType = "JCLSetup";break;
+ case PPDKey::AnySetup: pSetupType = "AnySetup";break;
+ default: break;
+ };
+ fprintf( stderr, "\t\"%s\" (\"%s\") (%d values) OrderDependency: %d %s\n",
+ BSTRING( pKey->getKey() ).GetBuffer(),
+ BSTRING( pKey->m_aUITranslation ).GetBuffer(),
+ pKey->countValues(),
+ pKey->m_nOrderDependency,
+ pSetupType );
+ for( int j = 0; j < pKey->countValues(); j++ )
+ {
+ fprintf( stderr, "\t\t" );
+ const PPDValue* pValue = pKey->getValue( j );
+ if( pValue == pKey->m_pDefaultValue )
+ fprintf( stderr, "(Default:) " );
+ char* pVType = "<unknown>";
+ switch( pValue->m_eType )
+ {
+ case eInvocation: pVType = "invocation";break;
+ case eQuoted: pVType = "quoted";break;
+ case eString: pVType = "string";break;
+ case eSymbol: pVType = "symbol";break;
+ case eNo: pVType = "no";break;
+ default: break;
+ };
+ fprintf( stderr, "option: \"%s\" (\"%s\"), value: type %s \"%s\" (\"%s\")\n",
+ BSTRING( pValue->m_aOption ).GetBuffer(),
+ BSTRING( pValue->m_aOptionTranslation ).GetBuffer(),
+ pVType,
+ BSTRING( pValue->m_aValue ).GetBuffer(),
+ BSTRING( pValue->m_aValueTranslation ).GetBuffer() );
+ }
+ }
+ fprintf( stderr, "constraints: (%d found)\n", m_aConstraints.size() );
+ for( std::list< PPDConstraint >::const_iterator cit = m_aConstraints.begin(); cit != m_aConstraints.end(); ++cit )
+ {
+ fprintf( stderr, "*\"%s\" \"%s\" *\"%s\" \"%s\"\n",
+ BSTRING( cit->m_pKey1->getKey() ).GetBuffer(),
+ cit->m_pOption1 ? BSTRING( cit->m_pOption1->m_aOption ).GetBuffer() : "<nil>",
+ BSTRING( cit->m_pKey2->getKey() ).GetBuffer(),
+ cit->m_pOption2 ? BSTRING( cit->m_pOption2->m_aOption ).GetBuffer() : "<nil>"
+ );
+ }
+#endif
+
+ // fill in shortcuts
+ const PPDKey* pKey;
+
+ m_pImageableAreas = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ImageableArea" ) ) );
+ if( m_pImageableAreas )
+ m_pDefaultImageableArea = m_pImageableAreas->getDefaultValue();
+ DBG_ASSERT( m_pImageableAreas, "Warning: no ImageableArea in PPD\n" );
+ DBG_ASSERT( m_pDefaultImageableArea, "Warning: no DefaultImageableArea in PPD\n" );
+
+ m_pPaperDimensions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PaperDimension" ) ) );
+ if( m_pPaperDimensions )
+ m_pDefaultPaperDimension = m_pPaperDimensions->getDefaultValue();
+ DBG_ASSERT( m_pPaperDimensions, "Warning: no PaperDimension in PPD\n" );
+ DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultPaperDimension in PPD\n" );
+
+ m_pResolutions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) );
+ if( m_pResolutions )
+ m_pDefaultResolution = m_pResolutions->getDefaultValue();
+ DBG_ASSERT( m_pResolutions, "Warning: no Resolution in PPD\n" );
+ DBG_ASSERT( m_pDefaultResolution, "Warning: no DefaultResolution in PPD\n" );
+
+ m_pInputSlots = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( m_pInputSlots )
+ m_pDefaultInputSlot = m_pInputSlots->getDefaultValue();
+ DBG_ASSERT( m_pPaperDimensions, "Warning: no InputSlot in PPD\n" );
+ DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultInputSlot in PPD\n" );
+
+ m_pDuplexTypes = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( m_pDuplexTypes )
+ m_pDefaultDuplexType = m_pDuplexTypes->getDefaultValue();
+
+ m_pFontList = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Font" ) ) );
+ DBG_ASSERT( m_pFontList, "Warning: no Font in PPD\n" );
+
+ // fill in direct values
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ModelName" ) ) )) )
+ m_aPrinterName = pKey->getValue( 0 )->m_aValue;
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "NickName" ) ) )) )
+ m_aNickName = pKey->getValue( 0 )->m_aValue;
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ColorDevice" ) ) )) )
+ m_bColorDevice = pKey->getValue( 0 )->m_aValue.CompareIgnoreCaseToAscii( "true", 4 ) == COMPARE_EQUAL ? true : false;
+
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "LanguageLevel" ) ) )) )
+ m_nLanguageLevel = pKey->getValue( 0 )->m_aValue.ToInt32();
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "TTRasterizer" ) ) )) )
+ m_bType42Capable = pKey->getValue( 0 )->m_aValue.EqualsIgnoreCaseAscii( "Type42" ) ? true : false;
+}
+
+PPDParser::~PPDParser()
+{
+ for( PPDParser::hash_type::iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it )
+ delete it->second;
+}
+
+void PPDParser::insertKey( const String& rKey, PPDKey* pKey )
+{
+ m_aKeys[ rKey ] = pKey;
+ m_aOrderedKeys.push_back( pKey );
+}
+
+const PPDKey* PPDParser::getKey( int n ) const
+{
+ return ((unsigned int)n < m_aOrderedKeys.size() && n >= 0) ? m_aOrderedKeys[n] : NULL;
+}
+
+const PPDKey* PPDParser::getKey( const String& rKey ) const
+{
+ PPDParser::hash_type::const_iterator it = m_aKeys.find( rKey );
+ return it != m_aKeys.end() ? it->second : NULL;
+}
+
+bool PPDParser::hasKey( const PPDKey* pKey ) const
+{
+ return
+ pKey ?
+ ( m_aKeys.find( pKey->getKey() ) != m_aKeys.end() ? true : false ) :
+ false;
+}
+
+static sal_uInt8 getNibble( sal_Char cChar )
+{
+ sal_uInt8 nRet = 0;
+ if( cChar >= '0' && cChar <= '9' )
+ nRet = sal_uInt8( cChar - '0' );
+ else if( cChar >= 'A' && cChar <= 'F' )
+ nRet = 10 + sal_uInt8( cChar - 'A' );
+ else if( cChar >= 'a' && cChar <= 'f' )
+ nRet = 10 + sal_uInt8( cChar - 'a' );
+ return nRet;
+}
+
+String PPDParser::handleTranslation( const ByteString& rString )
+{
+ int nOrigLen = rString.Len();
+ OStringBuffer aTrans( nOrigLen );
+ const sal_Char* pStr = rString.GetBuffer();
+ const sal_Char* pEnd = pStr + nOrigLen;
+ while( pStr < pEnd )
+ {
+ if( *pStr == '<' )
+ {
+ pStr++;
+ sal_Char cChar;
+ while( *pStr != '>' && pStr < pEnd-1 )
+ {
+ cChar = getNibble( *pStr++ ) << 4;
+ cChar |= getNibble( *pStr++ );
+ aTrans.append( cChar );
+ }
+ pStr++;
+ }
+ else
+ aTrans.append( *pStr++ );
+ }
+ return OStringToOUString( aTrans.makeStringAndClear(), m_aFileEncoding );
+}
+
+void PPDParser::parse( ::std::list< ByteString >& rLines )
+{
+ PPDValue* pValue = NULL;
+ PPDKey* pKey = NULL;
+
+ std::list< ByteString >::iterator line = rLines.begin();
+ PPDParser::hash_type::const_iterator keyit;
+ while( line != rLines.end() )
+ {
+ ByteString aCurrentLine( *line );
+ ++line;
+ if( aCurrentLine.GetChar(0) != '*' )
+ continue;
+ if( aCurrentLine.GetChar(1) == '%' )
+ continue;
+
+ ByteString aKey = GetCommandLineToken( 0, aCurrentLine.GetToken( 0, ':' ) );
+ int nPos = aKey.Search( '/' );
+ if( nPos != STRING_NOTFOUND )
+ aKey.Erase( nPos );
+ aKey.Erase( 0, 1 ); // remove the '*'
+
+ if( aKey.Equals( "CloseUI" ) || aKey.Equals( "OpenGroup" ) || aKey.Equals( "CloseGroup" ) || aKey.Equals( "End" ) || aKey.Equals( "OpenSubGroup" ) || aKey.Equals( "CloseSubGroup" ) )
+ continue;
+
+ if( aKey.Equals( "OpenUI" ) )
+ {
+ parseOpenUI( aCurrentLine );
+ continue;
+ }
+ else if( aKey.Equals( "OrderDependency" ) )
+ {
+ parseOrderDependency( aCurrentLine );
+ continue;
+ }
+ else if( aKey.Equals( "UIConstraints" ) || aKey.Equals( "NonUIConstraints" ) )
+ continue; // parsed in pass 2
+ else if( aKey.Equals( "CustomPageSize" ) ) // currently not handled
+ continue;
+
+ // default values are parsed in pass 2
+ if( aKey.CompareTo( "Default", 7 ) == COMPARE_EQUAL )
+ continue;
+
+ bool bQuery = false;
+ if( aKey.GetChar( 0 ) == '?' )
+ {
+ aKey.Erase( 0, 1 );
+ bQuery = true;
+ }
+
+ String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 );
+ keyit = m_aKeys.find( aUniKey );
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aUniKey );
+ insertKey( aUniKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ String aOption;
+ nPos = aCurrentLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aOption = String( aCurrentLine.Copy( 1, nPos-1 ), RTL_TEXTENCODING_MS_1252 );
+ aOption = GetCommandLineToken( 1, aOption );
+ int nTransPos = aOption.Search( '/' );
+ if( nTransPos != STRING_NOTFOUND )
+ aOption.Erase( nTransPos );
+ }
+ pValue = pKey->insertValue( aOption );
+ if( ! pValue )
+ continue;
+
+ if( nPos == STRING_NOTFOUND )
+ {
+ // have a single main keyword
+ pValue->m_eType = eNo;
+ if( bQuery )
+ pKey->eraseValue( aOption );
+ continue;
+ }
+
+ // found a colon, there may be an option
+ ByteString aLine = aCurrentLine.Copy( 1, nPos-1 );
+ aLine = WhitespaceToSpace( aLine );
+ int nTransPos = aLine.Search( '/' );
+ if( nTransPos != STRING_NOTFOUND )
+ pValue->m_aOptionTranslation = handleTranslation( aLine.Copy( nTransPos+1 ) );
+
+ // read in more lines if necessary for multiline values
+ aLine = aCurrentLine.Copy( nPos+1 );
+ while( ! ( aLine.GetTokenCount( '"' ) & 1 ) &&
+ line != rLines.end() )
+ // while there is an even number of tokens; that m_eans
+ // an odd number of doubleqoutes
+ {
+ // copy the newlines also
+ aLine += '\n';
+ aLine += *line;
+ ++line;
+ }
+ aLine = WhitespaceToSpace( aLine );
+
+ // check for invocation or quoted value
+ if( aLine.GetChar(0) == '"' )
+ {
+ aLine.Erase( 0, 1 );
+ nTransPos = aLine.Search( '"' );
+ pValue->m_aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 );
+ // after the second doublequote can follow a / and a translation
+ pValue->m_aValueTranslation = handleTranslation( aLine.Copy( nTransPos+2 ) );
+ // check for quoted value
+ if( pValue->m_aOption.Len() &&
+ aKey.CompareTo( "JCL", 3 ) != COMPARE_EQUAL )
+ pValue->m_eType = eInvocation;
+ else
+ pValue->m_eType = eQuoted;
+ }
+ // check for symbol value
+ else if( aLine.GetChar(0) == '^' )
+ {
+ aLine.Erase( 0, 1 );
+ pValue->m_aValue = String( aLine, RTL_TEXTENCODING_MS_1252 );
+ pValue->m_eType = eSymbol;
+ }
+ else
+ {
+ // must be a string value then
+ // strictly this is false because string values
+ // can contain any whitespace which is reduced
+ // to one space by now
+ // who cares ...
+ nTransPos = aLine.Search( '/' );
+ if( nTransPos == STRING_NOTFOUND )
+ nTransPos = aLine.Len();
+ pValue->m_aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 );
+ pValue->m_aValueTranslation = handleTranslation( aLine.Copy( nTransPos+1 ) );
+ pValue->m_eType = eString;
+ }
+
+ // eventually update query and remove from option list
+ if( bQuery && pKey->m_bQueryValue == FALSE )
+ {
+ pKey->m_aQueryValue = *pValue;
+ pKey->m_bQueryValue = true;
+ pKey->eraseValue( pValue->m_aOption );
+ }
+ }
+
+ // second pass: fill in defaults
+ for( line = rLines.begin(); line != rLines.end(); ++line )
+ {
+ ByteString aLine( *line );
+ if( aLine.CompareTo( "*Default", 8 ) == COMPARE_EQUAL )
+ {
+ String aKey( aLine.Copy( 8 ), RTL_TEXTENCODING_MS_1252 );
+ USHORT nPos = aKey.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aKey.Erase( nPos );
+ String aOption( WhitespaceToSpace( aLine.Copy( nPos+9 ) ), RTL_TEXTENCODING_MS_1252 );
+ keyit = m_aKeys.find( aKey );
+ if( keyit != m_aKeys.end() )
+ {
+ pKey = keyit->second;
+ const PPDValue* pDefValue = pKey->getValue( aOption );
+ if( pKey->m_pDefaultValue == NULL )
+ pKey->m_pDefaultValue = pDefValue;
+ }
+ else
+ {
+ // some PPDs contain defaults for keys that
+ // do not exist otherwise
+ // (example: DefaultResolution)
+ // so invent that key here and have a default value
+ pKey = new PPDKey( aKey );
+ PPDValue* pNewValue = pKey->insertValue( aOption );
+ pNewValue->m_eType = eInvocation; // or what ?
+ insertKey( aKey, pKey );
+ }
+ }
+ }
+ else if( aLine.CompareTo( "*UIConstraints", 14 ) == COMPARE_EQUAL ||
+ aLine.CompareTo( "*NonUIConstraints", 17 ) == COMPARE_EQUAL )
+ parseConstraint( aLine );
+
+ }
+}
+
+void PPDParser::parseOpenUI( const ByteString& rLine )
+{
+ String aTranslation;
+ ByteString aKey = rLine;
+
+ int nPos = aKey.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ aKey.Erase( nPos );
+ nPos = aKey.Search( '/' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aTranslation = handleTranslation( aKey.Copy( nPos + 1 ) );
+ aKey.Erase( nPos );
+ }
+ aKey = GetCommandLineToken( 1, aKey );
+ aKey.Erase( 0, 1 );
+
+ String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 );
+ PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aUniKey );
+ PPDKey* pKey;
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aUniKey );
+ insertKey( aUniKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ pKey->m_bUIOption = true;
+ pKey->m_aUITranslation = aTranslation;
+
+ ByteString aValue = WhitespaceToSpace( rLine.GetToken( 1, ':' ) );
+ if( aValue.CompareIgnoreCaseToAscii( "boolean" ) == COMPARE_EQUAL )
+ pKey->m_eUIType = PPDKey::Boolean;
+ else if( aValue.CompareIgnoreCaseToAscii( "pickmany" ) == COMPARE_EQUAL )
+ pKey->m_eUIType = PPDKey::PickMany;
+ else
+ pKey->m_eUIType = PPDKey::PickOne;
+}
+
+void PPDParser::parseOrderDependency( const ByteString& rLine )
+{
+ ByteString aLine( rLine );
+ int nPos = aLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ aLine.Erase( 0, nPos+1 );
+
+ int nOrder = GetCommandLineToken( 0, aLine ).ToInt32();
+ ByteString aSetup = GetCommandLineToken( 1, aLine );
+ String aKey( GetCommandLineToken( 2, aLine ), RTL_TEXTENCODING_MS_1252 );
+ if( aKey.GetChar( 0 ) != '*' )
+ return; // invalid order depency
+ aKey.Erase( 0, 1 );
+
+ PPDKey* pKey;
+ PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aKey );
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aKey );
+ insertKey( aKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ pKey->m_nOrderDependency = nOrder;
+ if( aSetup.Equals( "ExitServer" ) )
+ pKey->m_eSetupType = PPDKey::ExitServer;
+ else if( aSetup.Equals( "Prolog" ) )
+ pKey->m_eSetupType = PPDKey::Prolog;
+ else if( aSetup.Equals( "DocumentSetup" ) )
+ pKey->m_eSetupType = PPDKey::DocumentSetup;
+ else if( aSetup.Equals( "PageSetup" ) )
+ pKey->m_eSetupType = PPDKey::PageSetup;
+ else if( aSetup.Equals( "JCLSetup" ) )
+ pKey->m_eSetupType = PPDKey::JCLSetup;
+ else
+ pKey->m_eSetupType = PPDKey::AnySetup;
+}
+
+void PPDParser::parseConstraint( const ByteString& rLine )
+{
+ bool bFailed = false;
+
+ String aLine( rLine, RTL_TEXTENCODING_MS_1252 );
+ aLine.Erase( 0, rLine.Search( ':' )+1 );
+ PPDConstraint aConstraint;
+ int nTokens = GetCommandLineTokenCount( aLine );
+ for( int i = 0; i < nTokens; i++ )
+ {
+ String aToken = GetCommandLineToken( i, aLine );
+ if( aToken.GetChar( 0 ) == '*' )
+ {
+ aToken.Erase( 0, 1 );
+ if( aConstraint.m_pKey1 )
+ aConstraint.m_pKey2 = getKey( aToken );
+ else
+ aConstraint.m_pKey1 = getKey( aToken );
+ }
+ else
+ {
+ if( aConstraint.m_pKey2 )
+ {
+ if( ! ( aConstraint.m_pOption2 = aConstraint.m_pKey2->getValue( aToken ) ) )
+ bFailed = true;
+ }
+ else if( aConstraint.m_pKey1 )
+ {
+ if( ! ( aConstraint.m_pOption1 = aConstraint.m_pKey1->getValue( aToken ) ) )
+ bFailed = true;
+ }
+ else
+ // constraint for nonexistent keys; this happens
+ // e.g. in HP4PLUS3 (#75636#)
+ bFailed = true;
+ }
+ }
+ // there must be two keywords
+ if( ! aConstraint.m_pKey1 || ! aConstraint.m_pKey2 || bFailed )
+ {
+#ifdef __DEBUG
+ fprintf( stderr, "Warning: constraint \"%s\" is invalid\n", rLine.GetStr() );
+#endif
+ }
+ else
+ m_aConstraints.push_back( aConstraint );
+}
+
+const String& PPDParser::getDefaultPaperDimension() const
+{
+ if( m_pDefaultPaperDimension )
+ return m_pDefaultPaperDimension->m_aOption;
+
+ return aEmptyString;
+}
+
+bool PPDParser::getMargins(
+ const String& rPaperName,
+ int& rLeft, int& rRight,
+ int& rUpper, int& rLower ) const
+{
+ if( ! m_pImageableAreas || ! m_pPaperDimensions )
+ return false;
+
+ int nPDim=-1, nImArea=-1, i;
+ for( i = 0; i < m_pImageableAreas->countValues(); i++ )
+ if( rPaperName == m_pImageableAreas->getValue( i )->m_aOption )
+ nImArea = i;
+ for( i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption )
+ nPDim = i;
+ if( nPDim == -1 || nImArea == -1 )
+ return false;
+
+ double ImLLx, ImLLy, ImURx, ImURy;
+ double PDWidth, PDHeight;
+ String aArea = m_pImageableAreas->getValue( nImArea )->m_aValue;
+ ImLLx = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ ImLLy = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ ImURx = StringToDouble( GetCommandLineToken( 2, aArea ) );
+ ImURy = StringToDouble( GetCommandLineToken( 3, aArea ) );
+// sscanf( m_pImageableAreas->getValue( nImArea )->m_aValue.GetStr(),
+// "%lg%lg%lg%lg", &ImLLx, &ImLLy, &ImURx, &ImURy );
+ aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+// sscanf( m_pPaperDimensions->getValue( nPDim )->m_aValue.GetStr(),
+// "%lg%lg", &PDWidth, &PDHeight );
+ rLeft = (int)(ImLLx + 0.5);
+ rLower = (int)(ImLLy + 0.5);
+ rUpper = (int)(PDHeight - ImURy + 0.5);
+ rRight = (int)(PDWidth - ImURx + 0.5);
+
+ return true;
+}
+
+bool PPDParser::getPaperDimension(
+ const String& rPaperName,
+ int& rWidth, int& rHeight ) const
+{
+ if( ! m_pPaperDimensions )
+ return false;
+
+ int nPDim=-1;
+ for( int i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption )
+ nPDim = i;
+ if( nPDim == -1 )
+ return false;
+
+ double PDWidth, PDHeight;
+ String aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ rHeight = (int)(PDHeight + 0.5);
+ rWidth = (int)(PDWidth + 0.5);
+
+ return true;
+}
+
+const String& PPDParser::matchPaper( int nWidth, int nHeight ) const
+{
+ if( ! m_pPaperDimensions )
+ return aEmptyString;
+
+ int nPDim = -1;
+ double PDWidth, PDHeight;
+ double fSort = 2e36, fNewSort;
+
+ for( int i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ {
+ String aArea = m_pPaperDimensions->getValue( i )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ PDWidth /= (double)nWidth;
+ PDHeight /= (double)nHeight;
+ if( PDWidth >= 0.9 && PDWidth <= 1.1 &&
+ PDHeight >= 0.9 && PDHeight <= 1.1 )
+ {
+ fNewSort =
+ (1.0-PDWidth)*(1.0-PDWidth) + (1.0-PDHeight)*(1.0-PDHeight);
+ if( fNewSort == 0.0 ) // perfect match
+ return m_pPaperDimensions->getValue( i )->m_aOption;
+
+ if( fNewSort < fSort )
+ {
+ fSort = fNewSort;
+ nPDim = i;
+ }
+ }
+ }
+
+ static bool bDontSwap = false;
+ if( nPDim == -1 && ! bDontSwap )
+ {
+ // swap portrait/landscape and try again
+ bDontSwap = true;
+ const String& rRet = matchPaper( nHeight, nWidth );
+ bDontSwap = false;
+ return rRet;
+ }
+
+ return nPDim != -1 ? m_pPaperDimensions->getValue( nPDim )->m_aOption : aEmptyString;
+}
+
+const String& PPDParser::getDefaultInputSlot() const
+{
+ if( m_pDefaultInputSlot )
+ return m_pDefaultInputSlot->m_aValue;
+ return aEmptyString;
+}
+
+const String& PPDParser::getSlot( int nSlot ) const
+{
+ if( ! m_pInputSlots )
+ return aEmptyString;
+
+ if( nSlot > 0 && nSlot < m_pInputSlots->countValues() )
+ return m_pInputSlots->getValue( nSlot )->m_aOption;
+ else if( m_pInputSlots->countValues() > 0 )
+ return m_pInputSlots->getValue( (ULONG)0 )->m_aOption;
+
+ return aEmptyString;
+}
+
+const String& PPDParser::getSlotCommand( int nSlot ) const
+{
+ if( ! m_pInputSlots )
+ return aEmptyString;
+
+ if( nSlot > 0 && nSlot < m_pInputSlots->countValues() )
+ return m_pInputSlots->getValue( nSlot )->m_aValue;
+ else if( m_pInputSlots->countValues() > 0 )
+ return m_pInputSlots->getValue( (ULONG)0 )->m_aValue;
+
+ return aEmptyString;
+}
+
+const String& PPDParser::getSlotCommand( const String& rSlot ) const
+{
+ if( ! m_pInputSlots )
+ return aEmptyString;
+
+ for( int i=0; i < m_pInputSlots->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pInputSlots->getValue( i );
+ if( pValue->m_aOption == rSlot )
+ return pValue->m_aValue;
+ }
+ return aEmptyString;
+}
+
+const String& PPDParser::getPaperDimension( int nPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return aEmptyString;
+
+ if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() )
+ return m_pPaperDimensions->getValue( nPaperDimension )->m_aOption;
+ else if( m_pPaperDimensions->countValues() > 0 )
+ return m_pPaperDimensions->getValue( (ULONG)0 )->m_aOption;
+
+ return aEmptyString;
+}
+
+const String& PPDParser::getPaperDimensionCommand( int nPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return aEmptyString;
+
+ if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() )
+ return m_pPaperDimensions->getValue( nPaperDimension )->m_aValue;
+ else if( m_pPaperDimensions->countValues() > 0 )
+ return m_pPaperDimensions->getValue( (ULONG)0 )->m_aValue;
+
+ return aEmptyString;
+}
+
+const String& PPDParser::getPaperDimensionCommand( const String& rPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return aEmptyString;
+
+ for( int i=0; i < m_pPaperDimensions->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pPaperDimensions->getValue( i );
+ if( pValue->m_aOption == rPaperDimension )
+ return pValue->m_aValue;
+ }
+ return aEmptyString;
+}
+
+void PPDParser::getResolutionFromString(
+ const String& rString,
+ int& rXRes, int& rYRes ) const
+{
+ int nPos = 0, nDPIPos;
+
+ rXRes = rYRes = 300;
+
+ nDPIPos = rString.SearchAscii( "dpi" );
+ if( nDPIPos != STRING_NOTFOUND )
+ {
+ if( ( nPos = rString.Search( 'x' ) ) != STRING_NOTFOUND )
+ {
+ rXRes = rString.Copy( 0, nPos ).ToInt32();
+ rYRes = rString.GetToken( 1, 'x' ).Erase( nDPIPos - nPos - 1 ).ToInt32();
+ }
+ else
+ rXRes = rYRes = rString.Copy( 0, nDPIPos ).ToInt32();
+ }
+}
+
+void PPDParser::getDefaultResolution( int& rXRes, int& rYRes ) const
+{
+ if( m_pDefaultResolution )
+ {
+ getResolutionFromString( m_pDefaultResolution->m_aValue, rXRes, rYRes );
+ return;
+ }
+
+ rXRes = 300;
+ rYRes = 300;
+}
+
+int PPDParser::getResolutions() const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) &&
+ m_pDefaultResolution )
+ return 1;
+ return m_pResolutions ? m_pResolutions->countValues() : 0;
+}
+
+void PPDParser::getResolution( int nNr, int& rXRes, int& rYRes ) const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution && nNr == 0 )
+ {
+ getDefaultResolution( rXRes, rYRes );
+ return;
+ }
+ if( ! m_pResolutions )
+ return;
+
+ getResolutionFromString( m_pResolutions->getValue( nNr )->m_aOption,
+ rXRes, rYRes );
+}
+
+const String& PPDParser::getResolutionCommand( int nXRes, int nYRes ) const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution )
+ return m_pDefaultResolution->m_aValue;
+
+ if( ! m_pResolutions )
+ return aEmptyString;
+
+ int nX, nY;
+ for( int i = 0; i < m_pResolutions->countValues(); i++ )
+ {
+ getResolutionFromString( m_pResolutions->getValue( i )->m_aOption,
+ nX, nY );
+ if( nX == nXRes && nY == nYRes )
+ return m_pResolutions->getValue( i )->m_aValue;
+ }
+ return aEmptyString;
+}
+
+const String& PPDParser::getDefaultDuplexType() const
+{
+ if( m_pDefaultDuplexType )
+ return m_pDefaultDuplexType->m_aValue;
+ return aEmptyString;
+}
+
+const String& PPDParser::getDuplex( int nDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return aEmptyString;
+
+ if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() )
+ return m_pDuplexTypes->getValue( nDuplex )->m_aOption;
+ else if( m_pDuplexTypes->countValues() > 0 )
+ return m_pDuplexTypes->getValue( (ULONG)0 )->m_aOption;
+
+ return aEmptyString;
+}
+
+const String& PPDParser::getDuplexCommand( int nDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return aEmptyString;
+
+ if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() )
+ return m_pDuplexTypes->getValue( nDuplex )->m_aValue;
+ else if( m_pDuplexTypes->countValues() > 0 )
+ return m_pDuplexTypes->getValue( (ULONG)0 )->m_aValue;
+
+ return aEmptyString;
+}
+
+const String& PPDParser::getDuplexCommand( const String& rDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return aEmptyString;
+
+ for( int i=0; i < m_pDuplexTypes->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pDuplexTypes->getValue( i );
+ if( pValue->m_aOption == rDuplex )
+ return pValue->m_aValue;
+ }
+ return aEmptyString;
+}
+
+void PPDParser::getFontAttributes(
+ int nFont,
+ String& rEncoding,
+ String& rCharset ) const
+{
+ if( m_pFontList && nFont >= 0 && nFont < m_pFontList->countValues() )
+ {
+ String aAttribs =
+ WhitespaceToSpace( m_pFontList->getValue( nFont )->m_aValue );
+ rEncoding = GetCommandLineToken( 0, aAttribs );
+ rCharset = GetCommandLineToken( 2, aAttribs );
+ }
+}
+
+void PPDParser::getFontAttributes(
+ const String& rFont,
+ String& rEncoding,
+ String& rCharset ) const
+{
+ if( m_pFontList )
+ {
+ for( int i = 0; i < m_pFontList->countValues(); i++ )
+ if( m_pFontList->getValue( i )->m_aOption == rFont )
+ getFontAttributes( i, rEncoding, rCharset );
+ }
+}
+
+const String& PPDParser::getFont( int nFont ) const
+{
+ if( ! m_pFontList )
+ return aEmptyString;
+
+ if( nFont >=0 && nFont < m_pFontList->countValues() )
+ return m_pFontList->getValue( nFont )->m_aOption;
+ return aEmptyString;
+}
+
+/*
+ * PPDKey
+ */
+
+PPDKey::PPDKey( const String& rKey ) :
+ m_aKey( rKey ),
+ m_pDefaultValue( NULL ),
+ m_bQueryValue( false ),
+ m_bUIOption( false ),
+ m_eUIType( PickOne ),
+ m_nOrderDependency( 100 ),
+ m_eSetupType( AnySetup )
+{
+}
+
+// -------------------------------------------------------------------
+
+PPDKey::~PPDKey()
+{
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValue( int n ) const
+{
+ return ((unsigned int)n < m_aOrderedValues.size() && n >= 0) ? m_aOrderedValues[n] : NULL;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValue( const String& rOption ) const
+{
+ PPDKey::hash_type::const_iterator it = m_aValues.find( rOption );
+ return it != m_aValues.end() ? &it->second : NULL;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValueCaseInsensitive( const String& rOption ) const
+{
+ const PPDValue* pValue = getValue( rOption );
+ if( ! pValue )
+ {
+ for( size_t n = 0; n < m_aOrderedValues.size() && ! pValue; n++ )
+ if( m_aOrderedValues[n]->m_aOption.EqualsIgnoreCaseAscii( rOption ) )
+ pValue = m_aOrderedValues[n];
+ }
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+void PPDKey::eraseValue( const String& rOption )
+{
+ PPDKey::hash_type::iterator it = m_aValues.find( rOption );
+ if( it == m_aValues.end() )
+ return;
+
+ for( PPDKey::value_type::iterator vit = m_aOrderedValues.begin(); vit != m_aOrderedValues.end(); ++vit )
+ {
+ if( *vit == &(it->second ) )
+ {
+ m_aOrderedValues.erase( vit );
+ break;
+ }
+ }
+ m_aValues.erase( it );
+}
+
+// -------------------------------------------------------------------
+
+PPDValue* PPDKey::insertValue( const String& rOption )
+{
+ if( m_aValues.find( rOption ) != m_aValues.end() )
+ return NULL;
+
+ PPDValue aValue;
+ aValue.m_aOption = rOption;
+ m_aValues[ rOption ] = aValue;
+ PPDValue* pValue = &m_aValues[rOption];
+ m_aOrderedValues.push_back( pValue );
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+/*
+ * PPDContext
+ */
+
+PPDContext::PPDContext( const PPDParser* pParser ) :
+ m_pParser( pParser )
+{
+}
+
+// -------------------------------------------------------------------
+
+PPDContext& PPDContext::operator=( const PPDContext& rCopy )
+{
+ m_pParser = rCopy.m_pParser;
+ m_aCurrentValues = rCopy.m_aCurrentValues;
+ return *this;
+}
+
+// -------------------------------------------------------------------
+
+PPDContext::~PPDContext()
+{
+}
+
+// -------------------------------------------------------------------
+
+const PPDKey* PPDContext::getModifiedKey( int n ) const
+{
+ hash_type::const_iterator it;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end() && n--; ++it )
+ ;
+ return it != m_aCurrentValues.end() ? it->first : NULL;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::setParser( const PPDParser* pParser )
+{
+ if( pParser != m_pParser )
+ {
+ m_aCurrentValues.clear();
+ m_pParser = pParser;
+ }
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDContext::getValue( const PPDKey* pKey ) const
+{
+ if( ! m_pParser )
+ return NULL;
+
+ hash_type::const_iterator it;
+ it = m_aCurrentValues.find( pKey );
+ if( it != m_aCurrentValues.end() )
+ return it->second;
+
+ if( ! m_pParser->hasKey( pKey ) )
+ return NULL;
+
+ const PPDValue* pValue = pKey->getDefaultValue();
+ if( ! pValue )
+ pValue = pKey->getValue( 0 );
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDContext::setValue( const PPDKey* pKey, const PPDValue* pValue, bool bDontCareForConstraints )
+{
+ if( ! m_pParser || ! pKey )
+ return NULL;
+
+ // pValue can be NULL - it means ignore this option
+
+ if( ! m_pParser->hasKey( pKey ) )
+ return NULL;
+
+ // check constraints
+ if( pValue )
+ {
+ if( bDontCareForConstraints )
+ {
+ m_aCurrentValues[ pKey ] = pValue;
+ }
+ else if( checkConstraints( pKey, pValue, true ) )
+ {
+ m_aCurrentValues[ pKey ] = pValue;
+
+ // after setting this value, check all constraints !
+ hash_type::iterator it = m_aCurrentValues.begin();
+ while( it != m_aCurrentValues.end() )
+ {
+ if( it->first != pKey &&
+ ! checkConstraints( it->first, it->second, false ) )
+ {
+#ifdef __DEBUG
+ fprintf( stderr, "PPDContext::setValue: option %s (%s) is constrained after setting %s to %s\n",
+ it->first->getKey().GetStr(),
+ it->second->m_aOption.GetStr(),
+ pKey->getKey().GetStr(),
+ pValue->m_aOption.GetStr() );
+#endif
+ resetValue( it->first, true );
+ it = m_aCurrentValues.begin();
+ }
+ else
+ ++it;
+ }
+ }
+ }
+ else
+ m_aCurrentValues[ pKey ] = NULL;
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pValue )
+{
+ if( ! m_pParser || ! pKey || ! pValue )
+ return false;
+
+ // ensure that this key is already in the list if it exists at all
+ if( m_aCurrentValues.find( pKey ) != m_aCurrentValues.end() )
+ return checkConstraints( pKey, pValue, false );
+
+ // it is not in the list, insert it temporarily
+ bool bRet = false;
+ if( m_pParser->hasKey( pKey ) )
+ {
+ const PPDValue* pDefValue = pKey->getDefaultValue();
+ m_aCurrentValues[ pKey ] = pDefValue;
+ bRet = checkConstraints( pKey, pValue, false );
+ m_aCurrentValues.erase( pKey );
+ }
+
+ return bRet;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::resetValue( const PPDKey* pKey, bool bDefaultable )
+{
+ if( ! pKey || ! m_pParser || ! m_pParser->hasKey( pKey ) )
+ return false;
+
+ const PPDValue* pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ if( ! pResetValue )
+ pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) );
+ if( ! pResetValue && bDefaultable )
+ pResetValue = pKey->getDefaultValue();
+
+ bool bRet = pResetValue ? ( setValue( pKey, pResetValue ) == pResetValue ? true : false ) : false;
+
+ return bRet;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pNewValue, bool bDoReset )
+{
+ if( ! pNewValue )
+ return true;
+
+ // sanity checks
+ if( ! m_pParser )
+ return false;
+
+ if( pKey->getValue( pNewValue->m_aOption ) != pNewValue )
+ return false;
+
+ // None / False and the default can always be set, but be careful !
+ // setting them might influence constrained values
+ if( pNewValue->m_aOption.EqualsAscii( "None" ) || pNewValue->m_aOption.EqualsAscii( "False" ) ||
+ pNewValue == pKey->getDefaultValue() )
+ return true;
+
+ const ::std::list< PPDParser::PPDConstraint >& rConstraints( m_pParser->getConstraints() );
+ for( ::std::list< PPDParser::PPDConstraint >::const_iterator it = rConstraints.begin(); it != rConstraints.end(); ++it )
+ {
+ const PPDKey* pLeft = it->m_pKey1;
+ const PPDKey* pRight = it->m_pKey2;
+ if( ! pLeft || ! pRight || ( pKey != pLeft && pKey != pRight ) )
+ continue;
+
+ const PPDKey* pOtherKey = pKey == pLeft ? pRight : pLeft;
+ const PPDValue* pOtherKeyOption = pKey == pLeft ? it->m_pOption2 : it->m_pOption1;
+ const PPDValue* pKeyOption = pKey == pLeft ? it->m_pOption1 : it->m_pOption2;
+
+ // syntax *Key1 option1 *Key2 option2
+ if( pKeyOption && pOtherKeyOption )
+ {
+ if( pNewValue != pKeyOption )
+ continue;
+ if( pOtherKeyOption == getValue( pOtherKey ) )
+ {
+ return false;
+ }
+ }
+ // syntax *Key1 option *Key2 or *Key1 *Key2 option
+ else if( pOtherKeyOption || pKeyOption )
+ {
+ if( pKeyOption )
+ {
+ if( ! ( pOtherKeyOption = getValue( pOtherKey ) ) )
+ continue; // this should not happen, PPD broken
+
+ if( pKeyOption == pNewValue &&
+ ! pOtherKeyOption->m_aOption.EqualsAscii( "None" ) &&
+ ! pOtherKeyOption->m_aOption.EqualsAscii( "False" ) )
+ {
+ // check if the other value can be reset and
+ // do so if possible
+ if( bDoReset && resetValue( pOtherKey ) )
+ continue;
+
+ return false;
+ }
+ }
+ else if( pOtherKeyOption )
+ {
+ if( getValue( pOtherKey ) == pOtherKeyOption &&
+ ! pNewValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "False" ) )
+ return false;
+ }
+ else
+ {
+ // this should not happen, PPD is broken
+ }
+ }
+ // syntax *Key1 *Key2
+ else
+ {
+ const PPDValue* pOtherValue = getValue( pOtherKey );
+ if( ! pOtherValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pOtherValue->m_aOption.EqualsAscii( "False" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "False" ) )
+ return false;
+ }
+ }
+ return true;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::getUnconstrainedValues( const PPDKey* pKey, ::std::list< const PPDValue* >& rValues )
+{
+ rValues.clear();
+
+ if( ! m_pParser || ! pKey || ! m_pParser->hasKey( pKey ) )
+ return;
+
+ int nValues = pKey->countValues();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDValue* pValue = pKey->getValue( i );
+ if( checkConstraints( pKey, pValue ) )
+ rValues.push_back( pValue );
+ }
+}
+
+
+// -------------------------------------------------------------------
+
+void* PPDContext::getStreamableBuffer( ULONG& rBytes ) const
+{
+ rBytes = 0;
+ if( ! m_aCurrentValues.size() )
+ return NULL;
+ hash_type::const_iterator it;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it )
+ {
+ ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 );
+ rBytes += aCopy.Len();
+ rBytes += 1; // for ':'
+ if( it->second )
+ {
+ aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 );
+ rBytes += aCopy.Len();
+ }
+ else
+ rBytes += 4;
+ rBytes += 1; // for '\0'
+ }
+ rBytes += 1;
+ void* pBuffer = new char[ rBytes ];
+ memset( pBuffer, 0, rBytes );
+ char* pRun = (char*)pBuffer;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it )
+ {
+ ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 );
+ int nBytes = aCopy.Len();
+ memcpy( pRun, aCopy.GetBuffer(), nBytes );
+ pRun += nBytes;
+ *pRun++ = ':';
+ if( it->second )
+ aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 );
+ else
+ aCopy = "*nil";
+ nBytes = aCopy.Len();
+ memcpy( pRun, aCopy.GetBuffer(), nBytes );
+ pRun += nBytes;
+
+ *pRun++ = 0;
+ }
+ return pBuffer;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::rebuildFromStreamBuffer( void* pBuffer, ULONG nBytes )
+{
+ if( ! m_pParser )
+ return;
+
+ m_aCurrentValues.clear();
+
+ char* pRun = (char*)pBuffer;
+ while( nBytes && *pRun )
+ {
+ ByteString aLine( pRun );
+ int nPos = aLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ const PPDKey* pKey = m_pParser->getKey( String( aLine.Copy( 0, nPos ), RTL_TEXTENCODING_MS_1252 ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = NULL;
+ String aOption( aLine.Copy( nPos+1 ), RTL_TEXTENCODING_MS_1252 );
+ if( ! aOption.EqualsAscii( "*nil" ) )
+ pValue = pKey->getValue( aOption );
+ m_aCurrentValues[ pKey ] = pValue;
+#ifdef __DEBUG
+ fprintf( stderr, "PPDContext::rebuildFromStreamBuffer: read PPDKeyValue { %s, %s }\n", pKV->m_pKey->getKey().GetStr(), pKV->m_pCurrentValue ? pKV->m_pCurrentValue->m_aOption.GetStr() : "<nil>" );
+#endif
+ }
+ }
+ nBytes -= aLine.Len()+1;
+ pRun += aLine.Len()+1;
+ }
+}
+
+// -------------------------------------------------------------------
+
+int PPDContext::getRenderResolution() const
+{
+ // initialize to reasonable default, if parser is not set
+ int nDPI = 300;
+ if( m_pParser )
+ {
+ int nDPIx = 300, nDPIy = 300;
+ const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = getValue( pKey );
+ if( pValue )
+ m_pParser->getResolutionFromString( pValue->m_aOption, nDPIx, nDPIy );
+ else
+ m_pParser->getDefaultResolution( nDPIx, nDPIy );
+ }
+ else
+ m_pParser->getDefaultResolution( nDPIx, nDPIy );
+
+ nDPI = (nDPIx > nDPIy) ? nDPIx : nDPIy;
+ }
+ return nDPI;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::getPageSize( String& rPaper, int& rWidth, int& rHeight ) const
+{
+ // initialize to reasonable default, if parser is not set
+ rPaper = String( RTL_CONSTASCII_USTRINGPARAM( "A4" ) );
+ rWidth = 595;
+ rHeight = 842;
+ if( m_pParser )
+ {
+ const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = getValue( pKey );
+ if( pValue )
+ {
+ rPaper = pValue->m_aOption;
+ m_pParser->getPaperDimension( rPaper, rWidth, rHeight );
+ }
+ else
+ {
+ rPaper = m_pParser->getDefaultPaperDimension();
+ m_pParser->getDefaultPaperDimension( rWidth, rHeight );
+ }
+ }
+ }
+}
diff --git a/vcl/unx/source/printer/printerinfomanager.cxx b/vcl/unx/source/printer/printerinfomanager.cxx
new file mode 100644
index 000000000000..cf5a4a886c41
--- /dev/null
+++ b/vcl/unx/source/printer/printerinfomanager.cxx
@@ -0,0 +1,1472 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: printerinfomanager.cxx,v $
+ * $Revision: 1.50 $
+ *
+ * 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/wait.h>
+#include <signal.h>
+
+#include "cupsmgr.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/strhelper.hxx"
+
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/debug.hxx"
+#include "tools/config.hxx"
+
+#include "rtl/strbuf.hxx"
+
+#include "osl/thread.hxx"
+#include "osl/mutex.hxx"
+#include "osl/process.h"
+
+// filename of configuration files
+#define PRINT_FILENAME "psprint.conf"
+// the group of the global defaults
+#define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__"
+
+#include <hash_set>
+
+using namespace psp;
+using namespace rtl;
+using namespace osl;
+
+namespace psp
+{
+ class SystemQueueInfo : public Thread
+ {
+ mutable Mutex m_aMutex;
+ bool m_bChanged;
+ std::list< PrinterInfoManager::SystemPrintQueue >
+ m_aQueues;
+ OUString m_aCommand;
+
+ virtual void run();
+
+ public:
+ SystemQueueInfo();
+ ~SystemQueueInfo();
+
+ bool hasChanged() const;
+ OUString getCommand() const;
+
+ // sets changed status to false; therefore not const
+ void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues );
+ };
+} // namespace
+
+/*
+* class PrinterInfoManager
+*/
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager& PrinterInfoManager::get()
+{
+ static PrinterInfoManager* pManager = NULL;
+
+ if( ! pManager )
+ {
+ pManager = CUPSManager::tryLoadCUPS();
+ if( ! pManager )
+ pManager = new PrinterInfoManager();
+
+ if( pManager )
+ pManager->initialize();
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pManager->getType() );
+ #endif
+ }
+
+ return *pManager;
+}
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager::PrinterInfoManager( Type eType ) :
+ m_pQueueInfo( NULL ),
+ m_eType( eType ),
+ m_bUseIncludeFeature( false ),
+ m_aSystemDefaultPaper( RTL_CONSTASCII_USTRINGPARAM( "A4" ) ),
+ m_bDisableCUPS( false )
+{
+ if( eType == Default )
+ m_pQueueInfo = new SystemQueueInfo();
+ initSystemDefaultPaper();
+}
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager::~PrinterInfoManager()
+{
+ delete m_pQueueInfo;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::isCUPSDisabled() const
+{
+ return m_bDisableCUPS;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::setCUPSDisabled( bool bDisable )
+{
+ m_bDisableCUPS = bDisable;
+ writePrinterConfig();
+ // actually we know the printers changed
+ // however this triggers reinitialization the right way
+ checkPrintersChanged( true );
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::initSystemDefaultPaper()
+{
+ bool bSuccess = false;
+
+ // try libpaper
+
+ // #i78617# workaround missing paperconf command
+ FILE* pPipe = popen( "sh -c paperconf 2>/dev/null", "r" );
+ if( pPipe )
+ {
+ char pBuffer[ 1024 ];
+ *pBuffer = 0;
+ fgets( pBuffer, sizeof(pBuffer)-1, pPipe );
+ pclose( pPipe );
+
+ ByteString aPaper( pBuffer );
+ aPaper = WhitespaceToSpace( aPaper );
+ if( aPaper.Len() )
+ {
+ m_aSystemDefaultPaper = OUString( OStringToOUString( aPaper, osl_getThreadTextEncoding() ) );
+ bSuccess = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "paper from paperconf = %s\n", aPaper.GetBuffer() );
+ #endif
+ }
+ if( bSuccess )
+ return;
+ }
+
+ // default value is Letter for US (en_US), Cannada (en_CA, fr_CA); else A4
+ // en will be interpreted as en_US
+
+ // note: at this point m_aSystemDefaultPaper is set to "A4" from the constructor
+
+ // check for LC_PAPER
+ const char* pPaperLang = getenv( "LC_PAPER" );
+ if( pPaperLang && *pPaperLang )
+ {
+ OString aLang( pPaperLang );
+ if( aLang.getLength() > 5 )
+ aLang = aLang.copy( 0, 5 );
+ if( aLang.getLength() == 5 )
+ {
+ if( aLang.equalsIgnoreAsciiCase( "en_us" )
+ || aLang.equalsIgnoreAsciiCase( "en_ca" )
+ || aLang.equalsIgnoreAsciiCase( "fr_ca" )
+ )
+ m_aSystemDefaultPaper = OUString( RTL_CONSTASCII_USTRINGPARAM( "Letter" ) );
+ }
+ else if( aLang.getLength() == 2 && aLang.equalsIgnoreAsciiCase( "en" ) )
+ m_aSystemDefaultPaper = OUString( RTL_CONSTASCII_USTRINGPARAM( "Letter" ) );
+ return;
+ }
+
+ // use process locale to determine paper
+ rtl_Locale* pLoc = NULL;
+ osl_getProcessLocale( &pLoc );
+ if( pLoc )
+ {
+ if( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc->Language->buffer, pLoc->Language->length, "en") )
+ {
+ if( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc->Country->buffer, pLoc->Country->length, "us")
+ || 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc->Country->buffer, pLoc->Country->length, "ca")
+ || pLoc->Country->length == 0
+ )
+ m_aSystemDefaultPaper = OUString( RTL_CONSTASCII_USTRINGPARAM( "Letter" ) );
+ }
+ else if( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc->Language->buffer, pLoc->Language->length, "fr") )
+ {
+ if( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc->Country->buffer, pLoc->Country->length, "ca") )
+ m_aSystemDefaultPaper = OUString( RTL_CONSTASCII_USTRINGPARAM( "Letter" ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::checkPrintersChanged( bool bWait )
+{
+ // check if files were created, deleted or modified since initialize()
+ ::std::list< WatchFile >::const_iterator it;
+ bool bChanged = false;
+ for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it )
+ {
+ DirectoryItem aItem;
+ if( DirectoryItem::get( it->m_aFilePath, aItem ) )
+ {
+ if( it->m_aModified.Seconds != 0 )
+ bChanged = true; // file probably has vanished
+ }
+ else
+ {
+ FileStatus aStatus( FileStatusMask_ModifyTime );
+ if( aItem.getFileStatus( aStatus ) )
+ bChanged = true; // unlikely but not impossible
+ else
+ {
+ TimeValue aModified = aStatus.getModifyTime();
+ if( aModified.Seconds != it->m_aModified.Seconds )
+ bChanged = true;
+ }
+ }
+ }
+
+ if( bWait && m_pQueueInfo )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "syncing printer discovery thread\n" );
+ #endif
+ m_pQueueInfo->join();
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "done: syncing printer discovery thread\n" );
+ #endif
+ }
+
+ if( ! bChanged && m_pQueueInfo )
+ bChanged = m_pQueueInfo->hasChanged();
+ if( bChanged )
+ {
+ initialize();
+ }
+
+ return bChanged;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::initialize()
+{
+ m_bUseIncludeFeature = false;
+ rtl_TextEncoding aEncoding = gsl_getSystemTextEncoding();
+ m_aPrinters.clear();
+ m_aWatchFiles.clear();
+ OUString aDefaultPrinter;
+
+ // first initialize the global defaults
+ // have to iterate over all possible files
+ // there should be only one global setup section in all
+ // available config files
+ m_aGlobalDefaults = PrinterInfo();
+
+ // need a parser for the PPDContext. generic printer should do.
+ m_aGlobalDefaults.m_pParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
+ m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser );
+ m_aGlobalDefaults.m_bPerformFontSubstitution = true;
+ m_bDisableCUPS = false;
+
+ if( ! m_aGlobalDefaults.m_pParser )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" );
+ #endif
+ return;
+ }
+
+ std::list< OUString > aDirList;
+ psp::getPrinterPathList( aDirList, NULL );
+ std::list< OUString >::const_iterator print_dir_it;
+ for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
+ {
+ INetURLObject aFile( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) );
+ Config aConfig( aFile.PathToFileName() );
+ if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP );
+
+ ByteString aValue( aConfig.ReadKey( "Copies" ) );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nCopies = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "Orientation" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait;
+
+ aValue = aConfig.ReadKey( "MarginAdjust" );
+ if( aValue.Len() )
+ {
+ m_aGlobalDefaults.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32();
+ }
+
+ aValue = aConfig.ReadKey( "ColorDepth", "24" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nColorDepth = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "ColorDevice" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nColorDevice = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PSLevel" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nPSLevel = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PerformFontSubstitution" );
+ if( aValue.Len() )
+ {
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ m_aGlobalDefaults.m_bPerformFontSubstitution = true;
+ else
+ m_aGlobalDefaults.m_bPerformFontSubstitution = false;
+ }
+
+ aValue = aConfig.ReadKey( "DisableCUPS" );
+ if( aValue.Len() )
+ {
+ if( aValue.Equals( "1" ) || aValue.EqualsIgnoreCaseAscii( "true" ) )
+ m_bDisableCUPS = true;
+ else
+ m_bDisableCUPS = false;
+ }
+
+ // get the PPDContext of global JobData
+ for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ )
+ {
+ ByteString aKey( aConfig.GetKeyName( nKey ) );
+ if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( pKey )
+ {
+ m_aGlobalDefaults.m_aContext.
+ setValue( pKey,
+ aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ),
+ TRUE );
+ }
+ }
+ else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ m_aGlobalDefaults.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "global settings: fontsubst = %s, %d substitutes\n", m_aGlobalDefaults.m_bPerformFontSubstitution ? "true" : "false", m_aGlobalDefaults.m_aFontSubstitutes.size() );
+ #endif
+ }
+ }
+ setDefaultPaper( m_aGlobalDefaults.m_aContext );
+ fillFontSubstitutions( m_aGlobalDefaults );
+
+ // now collect all available printers
+ for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
+ {
+ INetURLObject aDir( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ INetURLObject aFile( aDir );
+ aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) );
+
+ // check directory validity
+ OUString aUniPath;
+ FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath );
+ Directory aDirectory( aUniPath );
+ if( aDirectory.open() )
+ continue;
+ aDirectory.close();
+
+
+ FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath );
+ FileStatus aStatus( FileStatusMask_ModifyTime );
+ DirectoryItem aItem;
+
+ // setup WatchFile list
+ WatchFile aWatchFile;
+ aWatchFile.m_aFilePath = aUniPath;
+ if( ! DirectoryItem::get( aUniPath, aItem ) &&
+ ! aItem.getFileStatus( aStatus ) )
+ {
+ aWatchFile.m_aModified = aStatus.getModifyTime();
+ }
+ else
+ {
+ aWatchFile.m_aModified.Seconds = 0;
+ aWatchFile.m_aModified.Nanosec = 0;
+ }
+ m_aWatchFiles.push_back( aWatchFile );
+
+ Config aConfig( aFile.PathToFileName() );
+ for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ )
+ {
+ aConfig.SetGroup( aConfig.GetGroupName( nGroup ) );
+ ByteString aValue = aConfig.ReadKey( "Printer" );
+ if( aValue.Len() )
+ {
+ OUString aPrinterName;
+
+ int nNamePos = aValue.Search( '/' );
+ // check for valid value of "Printer"
+ if( nNamePos == STRING_NOTFOUND )
+ continue;
+
+ Printer aPrinter;
+ // initialize to global defaults
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ // global settings do not default the printer substitution
+ // list ! the substitution list in there is only used for
+ // newly created printers
+ aPrinter.m_aInfo.m_aFontSubstitutes.clear();
+ aPrinter.m_aInfo.m_aFontSubstitutions.clear();
+
+ aPrinterName = String( aValue.Copy( nNamePos+1 ), RTL_TEXTENCODING_UTF8 );
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ aPrinter.m_aInfo.m_aDriverName = String( aValue.Copy( 0, nNamePos ), RTL_TEXTENCODING_UTF8 );
+
+ // set parser, merge settings
+ // don't do this for CUPS printers as this is done
+ // by the CUPS system itself
+ if( aPrinter.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 )
+ {
+ aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName );
+ aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser );
+ // note: setParser also purges the context
+
+ // ignore this printer if its driver is not found
+ if( ! aPrinter.m_aInfo.m_pParser )
+ continue;
+
+ // merge the ppd context keys if the printer has the same keys and values
+ // this is a bit tricky, since it involves mixing two PPDs
+ // without constraints which might end up badly
+ // this feature should be use with caution
+ // it is mainly to select default paper sizes for new printers
+ for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
+ {
+ const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
+ const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
+ const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
+ if( pDefKey && pPrinterKey )
+ // at least the options exist in both PPDs
+ {
+ if( pDefValue )
+ {
+ const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
+ if( pPrinterValue )
+ // the printer has a corresponding option for the key
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
+ }
+ else
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
+ }
+ }
+
+ aValue = aConfig.ReadKey( "Command" );
+ // no printer without a command
+ if( ! aValue.Len() )
+ {
+ /* TODO:
+ * porters: please append your platform to the Solaris
+ * case if your platform has SystemV printing per default.
+ */
+ #if defined SOLARIS || defined(IRIX)
+ aValue = "lp";
+ #else
+ aValue = "lpr";
+ #endif
+ }
+ aPrinter.m_aInfo.m_aCommand = String( aValue, RTL_TEXTENCODING_UTF8 );
+ }
+
+ aValue = aConfig.ReadKey( "QuickCommand" );
+ aPrinter.m_aInfo.m_aQuickCommand = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Features" );
+ aPrinter.m_aInfo.m_aFeatures = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ // override the settings in m_aGlobalDefaults if keys exist
+ aValue = aConfig.ReadKey( "DefaultPrinter" );
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ aDefaultPrinter = aPrinterName;
+
+ aValue = aConfig.ReadKey( "Location" );
+ aPrinter.m_aInfo.m_aLocation = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Comment" );
+ aPrinter.m_aInfo.m_aComment = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Copies" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nCopies = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "Orientation" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait;
+
+ aValue = aConfig.ReadKey( "MarginAdjust" );
+ if( aValue.Len() )
+ {
+ aPrinter.m_aInfo.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32();
+ }
+
+ aValue = aConfig.ReadKey( "ColorDepth" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nColorDepth = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "ColorDevice" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nColorDevice = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PSLevel" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nPSLevel = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PerformFontSubstitution" );
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ aPrinter.m_aInfo.m_bPerformFontSubstitution = true;
+ else
+ aPrinter.m_aInfo.m_bPerformFontSubstitution = false;
+
+ // now iterate over all keys to extract multi key information:
+ // 1. PPDContext information
+ // 2. Font substitution table
+ for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ )
+ {
+ ByteString aKey( aConfig.GetKeyName( nKey ) );
+ if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL && aPrinter.m_aInfo.m_pParser )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( pKey )
+ {
+ aPrinter.m_aInfo.m_aContext.
+ setValue( pKey,
+ aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ),
+ TRUE );
+ }
+ }
+ else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ aPrinter.m_aInfo.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+
+ setDefaultPaper( aPrinter.m_aInfo.m_aContext );
+ fillFontSubstitutions( aPrinter.m_aInfo );
+
+ // finally insert printer
+ FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile );
+ aPrinter.m_bModified = false;
+ aPrinter.m_aGroup = aConfig.GetGroupName( nGroup );
+ std::hash_map< OUString, Printer, OUStringHash >::const_iterator find_it =
+ m_aPrinters.find( aPrinterName );
+ if( find_it != m_aPrinters.end() )
+ {
+ aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles;
+ aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile );
+ }
+ m_aPrinters[ aPrinterName ] = aPrinter;
+ }
+ }
+ }
+
+ // set default printer
+ if( m_aPrinters.size() )
+ {
+ if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() )
+ aDefaultPrinter = m_aPrinters.begin()->first;
+ }
+ else
+ aDefaultPrinter = OUString();
+ m_aDefaultPrinter = aDefaultPrinter;
+
+ if( m_eType != Default )
+ return;
+
+ // add a default printer for every available print queue
+ // merge paper and font substitution from default printer,
+ // all else from global defaults
+ PrinterInfo aMergeInfo( m_aGlobalDefaults );
+ aMergeInfo.m_aDriverName = String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) );
+ aMergeInfo.m_aFeatures = String( RTL_CONSTASCII_USTRINGPARAM( "autoqueue" ) );
+
+ if( m_aDefaultPrinter.getLength() )
+ {
+ PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) );
+ aMergeInfo.m_bPerformFontSubstitution = aDefaultInfo.m_bPerformFontSubstitution;
+ fillFontSubstitutions( aMergeInfo );
+
+ const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey );
+ const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL;
+ if( pMergeKey && pMergeValue )
+ aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue );
+ }
+
+ getSystemPrintQueues();
+ for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
+ {
+ String aPrinterName( RTL_CONSTASCII_USTRINGPARAM( "<" ) );
+ aPrinterName += String( it->m_aQueue );
+ aPrinterName.Append( '>' );
+
+ if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() )
+ // probably user made this one permanent in padmin
+ continue;
+
+ String aCmd( m_aSystemPrintCommand );
+ aCmd.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ), it->m_aQueue );
+
+ Printer aPrinter;
+
+ // initialize to merged defaults
+ aPrinter.m_aInfo = aMergeInfo;
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ aPrinter.m_aInfo.m_aCommand = aCmd;
+ aPrinter.m_aInfo.m_aComment = it->m_aComment;
+ aPrinter.m_aInfo.m_aLocation = it->m_aLocation;
+ aPrinter.m_bModified = false;
+ aPrinter.m_aGroup = ByteString( aPrinterName, aEncoding ); //provide group name in case user makes this one permanent in padmin
+
+ m_aPrinters[ aPrinterName ] = aPrinter;
+ }
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const
+{
+ ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it;
+ rList.clear();
+ for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
+ rList.push_back( it->first );
+}
+
+// -----------------------------------------------------------------
+
+const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const
+{
+ static PrinterInfo aEmptyInfo;
+ ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter );
+
+ DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistant printers" );
+
+ return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
+{
+ ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter );
+
+ DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" );
+
+ if( it != m_aPrinters.end() )
+ {
+ it->second.m_aInfo = rNewInfo;
+ // recalculate font substitutions
+ fillFontSubstitutions( it->second.m_aInfo );
+ it->second.m_bModified = true;
+ writePrinterConfig();
+ }
+}
+
+// -----------------------------------------------------------------
+
+// need to check writeability / creatability of config files
+static bool checkWriteability( const OUString& rUniPath )
+{
+ bool bRet = false;
+ OUString aSysPath;
+ FileBase::getSystemPathFromFileURL( rUniPath, aSysPath );
+ SvFileStream aStream( aSysPath, STREAM_READ | STREAM_WRITE );
+ if( aStream.IsOpen() && aStream.IsWritable() )
+ bRet = true;
+ return bRet;
+}
+
+bool PrinterInfoManager::writePrinterConfig()
+{
+ // find at least one writeable config
+ ::std::hash_map< OUString, Config*, OUStringHash > files;
+ ::std::hash_map< OUString, int, OUStringHash > rofiles;
+ ::std::hash_map< OUString, Config*, OUStringHash >::iterator file_it;
+
+ for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit )
+ {
+ if( checkWriteability( wit->m_aFilePath ) )
+ {
+ files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath );
+ break;
+ }
+ }
+
+ if( files.empty() )
+ return false;
+
+ Config* pGlobal = files.begin()->second;
+ pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP );
+ pGlobal->WriteKey( "DisableCUPS", m_bDisableCUPS ? "true" : "false" );
+
+ ::std::hash_map< OUString, Printer, OUStringHash >::iterator it;
+ for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
+ {
+ if( ! it->second.m_bModified )
+ // printer was not changed, do nothing
+ continue;
+
+ // don't save autoqueue printers
+ sal_Int32 nIndex = 0;
+ bool bAutoQueue = false;
+ while( nIndex != -1 && ! bAutoQueue )
+ {
+ OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( aToken.getLength() && aToken.compareToAscii( "autoqueue" ) == 0 )
+ bAutoQueue = true;
+ }
+ if( bAutoQueue )
+ continue;
+
+ if( it->second.m_aFile.getLength() )
+ {
+ // check if file is writable
+ if( files.find( it->second.m_aFile ) == files.end() )
+ {
+ bool bInsertToNewFile = false;
+ // maybe it is simply not inserted yet
+ if( rofiles.find( it->second.m_aFile ) == rofiles.end() )
+ {
+ if( checkWriteability( it->second.m_aFile ) )
+ files[ it->second.m_aFile ] = new Config( it->second.m_aFile );
+ else
+ bInsertToNewFile = true;
+ }
+ else
+ bInsertToNewFile = true;
+ // original file is read only, insert printer in a new writeable file
+ if( bInsertToNewFile )
+ {
+ rofiles[ it->second.m_aFile ] = 1;
+ // update alternate file list
+ // the remove operation ensures uniqueness of each alternate
+ it->second.m_aAlternateFiles.remove( it->second.m_aFile );
+ it->second.m_aAlternateFiles.remove( files.begin()->first );
+ it->second.m_aAlternateFiles.push_front( it->second.m_aFile );
+ // update file
+ it->second.m_aFile = files.begin()->first;
+ }
+ }
+ }
+ else // a new printer, write it to the first file available
+ it->second.m_aFile = files.begin()->first;
+
+ if( ! it->second.m_aGroup.getLength() ) // probably a new printer
+ it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 );
+
+ if( files.find( it->second.m_aFile ) != files.end() )
+ {
+ Config* pConfig = files[ it->second.m_aFile ];
+ pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain
+ pConfig->SetGroup( it->second.m_aGroup );
+
+ ByteString aValue( String( it->second.m_aInfo.m_aDriverName ), RTL_TEXTENCODING_UTF8 );
+ aValue += '/';
+ aValue += ByteString( String( it->first ), RTL_TEXTENCODING_UTF8 );
+ pConfig->WriteKey( "Printer", aValue );
+ pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" );
+ pConfig->WriteKey( "Location", ByteString( String( it->second.m_aInfo.m_aLocation ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Comment", ByteString( String( it->second.m_aInfo.m_aComment ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Command", ByteString( String( it->second.m_aInfo.m_aCommand ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "QuickCommand", ByteString( String( it->second.m_aInfo.m_aQuickCommand ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Features", ByteString( String( it->second.m_aInfo.m_aFeatures ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Copies", ByteString::CreateFromInt32( it->second.m_aInfo.m_nCopies ) );
+ pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" );
+ pConfig->WriteKey( "PSLevel", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPSLevel ) );
+ pConfig->WriteKey( "ColorDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDevice ) );
+ pConfig->WriteKey( "ColorDepth", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDepth ) );
+ aValue = ByteString::CreateFromInt32( it->second.m_aInfo.m_nLeftMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nRightMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nTopMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nBottomMarginAdjust );
+ pConfig->WriteKey( "MarginAdjust", aValue );
+
+ if( it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 )
+ {
+ // write PPDContext (not for CUPS)
+ for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ )
+ {
+ const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i );
+ ByteString aKey( "PPD_" );
+ aKey += ByteString( pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1 );
+
+ const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey );
+ aValue = pValue ? ByteString( pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ) : ByteString( "*nil" );
+ pConfig->WriteKey( aKey, aValue );
+ }
+ }
+
+ // write font substitution table
+ pConfig->WriteKey( "PerformFontSubstitution", it->second.m_aInfo.m_bPerformFontSubstitution ? "true" : "false" );
+ for( ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst = it->second.m_aInfo.m_aFontSubstitutes.begin();
+ subst != it->second.m_aInfo.m_aFontSubstitutes.end(); ++subst )
+ {
+ ByteString aKey( "SubstFont_" );
+ aKey.Append( OUStringToOString( subst->first, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ pConfig->WriteKey( aKey, OUStringToOString( subst->second, RTL_TEXTENCODING_ISO_8859_1 ) );
+ }
+ }
+ }
+
+ // get rid of Config objects. this also writes any changes
+ for( file_it = files.begin(); file_it != files.end(); ++file_it )
+ delete file_it->second;
+
+ return true;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName )
+{
+ bool bSuccess = false;
+
+ const PPDParser* pParser = NULL;
+ if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) )
+ {
+ Printer aPrinter;
+ aPrinter.m_bModified = true;
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ aPrinter.m_aInfo.m_aDriverName = rDriverName;
+ aPrinter.m_aInfo.m_pParser = pParser;
+ aPrinter.m_aInfo.m_aContext.setParser( pParser );
+ aPrinter.m_aInfo.m_aPrinterName = rPrinterName;
+
+ fillFontSubstitutions( aPrinter.m_aInfo );
+ // merge PPD values with global defaults
+ for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
+ {
+ const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
+ const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
+ const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
+ if( pDefKey && pPrinterKey )
+ // at least the options exist in both PPDs
+ {
+ if( pDefValue )
+ {
+ const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
+ if( pPrinterValue )
+ // the printer has a corresponding option for the key
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
+ }
+ else
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
+ }
+ }
+
+ m_aPrinters[ rPrinterName ] = aPrinter;
+ bSuccess = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "new printer %s, level = %d, colordevice = %d, depth = %d\n",
+ OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(),
+ m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel,
+ m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice,
+ m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth );
+ #endif
+ // comment: logically one should writePrinterConfig() here
+ // but immediately after addPrinter() a changePrinterInfo()
+ // will follow (see padmin code), which writes it again,
+ // so we can currently save some performance here
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly )
+{
+ bool bSuccess = true;
+
+ ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ if( it->second.m_aFile.getLength() )
+ {
+ // this printer already exists in a config file
+
+
+ // check writeability of config file(s)
+ if( ! checkWriteability( it->second.m_aFile ) )
+ bSuccess = false;
+ else
+ {
+ for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
+ file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
+ {
+ if( ! checkWriteability( *file_it ) )
+ bSuccess = false;
+ }
+ }
+ if( bSuccess && ! bCheckOnly )
+ {
+
+ Config aConfig( it->second.m_aFile );
+ aConfig.DeleteGroup( it->second.m_aGroup );
+ aConfig.Flush();
+ for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
+ file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
+ {
+ Config aAltConfig( *file_it );
+ aAltConfig.DeleteGroup( it->second.m_aGroup );
+ aAltConfig.Flush();
+ }
+ }
+ }
+ if( bSuccess && ! bCheckOnly )
+ {
+ m_aPrinters.erase( it );
+ // need this here because someone may call
+ // checkPrintersChanged after the removal
+ // but then other added printers were not flushed
+ // to disk, so they are discarded
+ writePrinterConfig();
+ }
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName )
+{
+ bool bSuccess = false;
+
+ ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ bSuccess = true;
+ it->second.m_bModified = true;
+ if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() )
+ it->second.m_bModified = true;
+ m_aDefaultPrinter = rPrinterName;
+ writePrinterConfig();
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+bool PrinterInfoManager::addOrRemovePossible() const
+{
+ return true;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::fillFontSubstitutions( PrinterInfo& rInfo ) const
+{
+ PrintFontManager& rFontManager( PrintFontManager::get() );
+ rInfo.m_aFontSubstitutions.clear();
+
+ if( ! rInfo.m_bPerformFontSubstitution ||
+ ! rInfo.m_aFontSubstitutes.size() )
+ return;
+
+ ::std::list< FastPrintFontInfo > aFonts;
+ ::std::hash_map< OUString, ::std::list< FastPrintFontInfo >, OUStringHash > aPrinterFonts;
+ rFontManager.getFontListWithFastInfo( aFonts, rInfo.m_pParser );
+
+ // get builtin fonts
+ ::std::list< FastPrintFontInfo >::const_iterator it;
+ for( it = aFonts.begin(); it != aFonts.end(); ++it )
+ if( it->m_eType == fonttype::Builtin )
+ aPrinterFonts[ it->m_aFamilyName.toAsciiLowerCase() ].push_back( *it );
+
+ // map lower case, so build a local copy of the font substitutions
+ ::std::hash_map< OUString, OUString, OUStringHash > aSubstitutions;
+ ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst;
+ for( subst = rInfo.m_aFontSubstitutes.begin(); subst != rInfo.m_aFontSubstitutes.end(); ++subst )
+ {
+ OUString aFamily( subst->first.toAsciiLowerCase() );
+ // first look if there is a builtin of this family
+ // in this case override the substitution table
+ if( aPrinterFonts.find( aFamily ) != aPrinterFonts.end() )
+ aSubstitutions[ aFamily ] = aFamily;
+ else
+ aSubstitutions[ aFamily ] = subst->second.toAsciiLowerCase();
+ }
+
+
+ // now find substitutions
+ for( it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( it->m_eType != fonttype::Builtin )
+ {
+ OUString aFamily( it->m_aFamilyName.toAsciiLowerCase() );
+ subst = aSubstitutions.find( aFamily );
+ if( subst != aSubstitutions.end() )
+ {
+ // search a substitution
+ const ::std::list< FastPrintFontInfo >& rBuiltins( aPrinterFonts[ aSubstitutions[ aFamily ] ] );
+ ::std::list< FastPrintFontInfo >::const_iterator builtin;
+ int nLastMatch = -10000;
+ fontID nSubstitute = -1;
+ for( builtin = rBuiltins.begin(); builtin != rBuiltins.end(); ++builtin )
+ {
+ int nMatch = 0;
+ int nDiff;
+ if( builtin->m_eItalic == it->m_eItalic )
+ nMatch += 8000;
+
+ nDiff = builtin->m_eWeight - it->m_eWeight;
+ nDiff = nDiff < 0 ? -nDiff : nDiff;
+ nMatch += 4000 - 1000*nDiff;
+
+ nDiff = builtin->m_eWidth - it->m_eWidth;
+ nDiff = nDiff < 0 ? -nDiff : nDiff;
+ nMatch += 2000 - 500*nDiff;
+
+ if( nMatch > nLastMatch )
+ {
+ nLastMatch = nMatch;
+ nSubstitute = builtin->m_nID;
+ }
+ }
+ if( nSubstitute != -1 )
+ {
+ rInfo.m_aFontSubstitutions[ it->m_nID ] = nSubstitute;
+ #if OSL_DEBUG_LEVEL > 2
+ FastPrintFontInfo aInfo;
+ rFontManager.getFontFastInfo( nSubstitute, aInfo );
+ fprintf( stderr,
+ "substitute %s %s %d %d\n"
+ " -> %s %s %d %d\n",
+ OUStringToOString( it->m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ it->m_eItalic == italic::Upright ? "r" : it->m_eItalic == italic::Oblique ? "o" : it->m_eItalic == italic::Italic ? "i" : "u",
+ it->m_eWeight,
+ it->m_eWidth,
+
+ OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ aInfo.m_eItalic == italic::Upright ? "r" : aInfo.m_eItalic == italic::Oblique ? "o" : aInfo.m_eItalic == italic::Italic ? "i" : "u",
+ aInfo.m_eWeight,
+ aInfo.m_eWidth
+ );
+ #endif
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::getSystemPrintCommands( std::list< OUString >& rCommands )
+{
+ if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
+ {
+ m_aSystemPrintCommand = m_pQueueInfo->getCommand();
+ m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
+ delete m_pQueueInfo, m_pQueueInfo = NULL;
+ }
+
+ std::list< SystemPrintQueue >::const_iterator it;
+ rCommands.clear();
+ String aPrinterConst( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) );
+ for( it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
+ {
+ String aCmd( m_aSystemPrintCommand );
+ aCmd.SearchAndReplace( aPrinterConst, it->m_aQueue );
+ rCommands.push_back( aCmd );
+ }
+}
+
+const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues()
+{
+ if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
+ {
+ m_aSystemPrintCommand = m_pQueueInfo->getCommand();
+ m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
+ delete m_pQueueInfo, m_pQueueInfo = NULL;
+ }
+
+ return m_aSystemPrintQueues;
+}
+
+bool PrinterInfoManager::checkFeatureToken( const rtl::OUString& rPrinterName, const char* pToken ) const
+{
+ const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) );
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex );
+ sal_Int32 nInnerIndex = 0;
+ OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex );
+ if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) )
+ return true;
+ }
+ return false;
+}
+
+FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
+{
+ const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername);
+ const rtl::OUString& rCommand = (bQuickCommand && rPrinterInfo.m_aQuickCommand.getLength() ) ?
+ rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand;
+ rtl::OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1);
+ aShellCommand += rtl::OString( " 2>/dev/null" );
+
+ return popen (aShellCommand.getStr(), "w");
+}
+
+int PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/ )
+{
+ return (0 == pclose( pFile ));
+}
+
+void PrinterInfoManager::setupJobContextData( JobData& rData )
+{
+ std::hash_map< OUString, Printer, OUStringHash >::iterator it =
+ m_aPrinters.find( rData.m_aPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ rData.m_pParser = it->second.m_aInfo.m_pParser;
+ rData.m_aContext = it->second.m_aInfo.m_aContext;
+ }
+}
+
+void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
+{
+ if( ! rContext.getParser() )
+ return;
+
+ const PPDKey* pPageSizeKey = rContext.getParser()->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( ! pPageSizeKey )
+ return;
+
+ int nModified = rContext.countValuesModified();
+ while( nModified-- &&
+ rContext.getModifiedKey( nModified ) != pPageSizeKey )
+ ;
+
+ if( nModified >= 0 ) // paper was set already, do not modify
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not setting default paper, already set %s\n",
+ OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ return;
+ }
+
+ // paper not set, fill in default value
+ const PPDValue* pPaperVal = NULL;
+ int nValues = pPageSizeKey->countValues();
+ for( int i = 0; i < nValues && ! pPaperVal; i++ )
+ {
+ const PPDValue* pVal = pPageSizeKey->getValue( i );
+ if( pVal->m_aOption.EqualsIgnoreCaseAscii( m_aSystemDefaultPaper.getStr() ) )
+ pPaperVal = pVal;
+ }
+ if( pPaperVal )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ rContext.setValue( pPageSizeKey, pPaperVal );
+ #if OSL_DEBUG_LEVEL > 1
+ pPaperVal = rContext.getValue( pPageSizeKey );
+ fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ }
+}
+
+// -----------------------------------------------------------------
+
+SystemQueueInfo::SystemQueueInfo() :
+ m_bChanged( false )
+{
+ create();
+}
+
+SystemQueueInfo::~SystemQueueInfo()
+{
+ terminate();
+}
+
+bool SystemQueueInfo::hasChanged() const
+{
+ MutexGuard aGuard( m_aMutex );
+ bool bChanged = m_bChanged;
+ return bChanged;
+}
+
+void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues )
+{
+ MutexGuard aGuard( m_aMutex );
+ rQueues = m_aQueues;
+ m_bChanged = false;
+}
+
+OUString SystemQueueInfo::getCommand() const
+{
+ MutexGuard aGuard( m_aMutex );
+ OUString aRet = m_aCommand;
+ return aRet;
+}
+
+struct SystemCommandParameters;
+typedef void(* tokenHandler)(const std::list< rtl::OString >&,
+ std::list< PrinterInfoManager::SystemPrintQueue >&,
+ const SystemCommandParameters*);
+
+struct SystemCommandParameters
+{
+ const char* pQueueCommand;
+ const char* pPrintCommand;
+ const char* pForeToken;
+ const char* pAftToken;
+ unsigned int nForeTokenCount;
+ tokenHandler pHandler;
+};
+
+#if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD))
+static void lpgetSysQueueTokenHandler(
+ const std::list< rtl::OString >& i_rLines,
+ std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
+ const SystemCommandParameters* )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ std::hash_set< OUString, OUStringHash > aUniqueSet;
+ std::hash_set< OUString, OUStringHash > aOnlySet;
+ aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_all" ) ) );
+ aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
+
+ // the eventual "all" attribute of the "_all" queue tells us, which
+ // printers are to be used for this user at all
+
+ // find _all: line
+ rtl::OString aAllLine( "_all:" );
+ rtl::OString aAllAttr( "all=" );
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ if( it->indexOf( aAllLine, 0 ) == 0 )
+ {
+ // now find the "all" attribute
+ ++it;
+ while( it != i_rLines.end() )
+ {
+ rtl::OString aClean( WhitespaceToSpace( *it ) );
+ if( aClean.indexOf( aAllAttr, 0 ) == 0 )
+ {
+ // insert the comma separated entries into the set of printers to use
+ sal_Int32 nPos = aAllAttr.getLength();
+ while( nPos != -1 )
+ {
+ OString aTok( aClean.getToken( 0, ',', nPos ) );
+ if( aTok.getLength() > 0 )
+ aOnlySet.insert( rtl::OStringToOUString( aTok, aEncoding ) );
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ bool bInsertAttribute = false;
+ rtl::OString aDescrStr( "description=" );
+ rtl::OString aLocStr( "location=" );
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ sal_Int32 nPos = 0;
+ // find the begin of a new printer section
+ nPos = it->indexOf( ':', 0 );
+ if( nPos != -1 )
+ {
+ OUString aSysQueue( rtl::OStringToOUString( it->copy( 0, nPos ), aEncoding ) );
+ // do not insert duplicates (e.g. lpstat tends to produce such lines)
+ // in case there was a "_all" section, insert only those printer explicitly
+ // set in the "all" attribute
+ if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() &&
+ ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() )
+ )
+ {
+ o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
+ o_rQueues.back().m_aQueue = aSysQueue;
+ o_rQueues.back().m_aLocation = aSysQueue;
+ aUniqueSet.insert( aSysQueue );
+ bInsertAttribute = true;
+ }
+ else
+ bInsertAttribute = false;
+ continue;
+ }
+ if( bInsertAttribute && ! o_rQueues.empty() )
+ {
+ // look for "description" attribute, insert as comment
+ nPos = it->indexOf( aDescrStr, 0 );
+ if( nPos != -1 )
+ {
+ ByteString aComment( WhitespaceToSpace( it->copy(nPos+12) ) );
+ if( aComment.Len() > 0 )
+ o_rQueues.back().m_aComment = String( aComment, aEncoding );
+ continue;
+ }
+ // look for "location" attribute, inser as location
+ nPos = it->indexOf( aLocStr, 0 );
+ if( nPos != -1 )
+ {
+ ByteString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) );
+ if( aLoc.Len() > 0 )
+ o_rQueues.back().m_aLocation = String( aLoc, aEncoding );
+ continue;
+ }
+ }
+ }
+}
+#endif
+static void standardSysQueueTokenHandler(
+ const std::list< rtl::OString >& i_rLines,
+ std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
+ const SystemCommandParameters* i_pParms)
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ std::hash_set< OUString, OUStringHash > aUniqueSet;
+ rtl::OString aForeToken( i_pParms->pForeToken );
+ rtl::OString aAftToken( i_pParms->pAftToken );
+ /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
+ */
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ sal_Int32 nPos = 0;
+
+ // search for a line describing a printer:
+ // find if there are enough tokens before the name
+ for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ )
+ {
+ nPos = it->indexOf( aForeToken, nPos );
+ if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() )
+ nPos += aForeToken.getLength();
+ }
+ if( nPos != -1 )
+ {
+ // find if there is the token after the queue
+ sal_Int32 nAftPos = it->indexOf( aAftToken, nPos );
+ if( nAftPos != -1 )
+ {
+ // get the queue name between fore and aft tokens
+ OUString aSysQueue( rtl::OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) );
+ // do not insert duplicates (e.g. lpstat tends to produce such lines)
+ if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() )
+ {
+ o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
+ o_rQueues.back().m_aQueue = aSysQueue;
+ o_rQueues.back().m_aLocation = aSysQueue;
+ aUniqueSet.insert( aSysQueue );
+ }
+ }
+ }
+ }
+}
+
+static const struct SystemCommandParameters aParms[] =
+{
+ #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD)
+ { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }
+ #else
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler },
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler },
+ { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }
+ #endif
+};
+
+void SystemQueueInfo::run()
+{
+ char pBuffer[1024];
+ FILE *pPipe;
+ std::list< rtl::OString > aLines;
+
+ /* Discover which command we can use to get a list of all printer queues */
+ for( unsigned int i = 0; i < sizeof(aParms)/sizeof(aParms[0]); i++ )
+ {
+ aLines.clear();
+ rtl::OStringBuffer aCmdLine( 128 );
+ aCmdLine.append( aParms[i].pQueueCommand );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand );
+ #endif
+ aCmdLine.append( " 2>/dev/null" );
+ if( (pPipe = popen( aCmdLine.getStr(), "r" )) )
+ {
+ while( fgets( pBuffer, 1024, pPipe ) )
+ aLines.push_back( rtl::OString( pBuffer ) );
+ if( ! pclose( pPipe ) )
+ {
+ std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues;
+ aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) );
+ MutexGuard aGuard( m_aMutex );
+ m_bChanged = true;
+ m_aQueues = aSysPrintQueues;
+ m_aCommand = rtl::OUString::createFromAscii( aParms[i].pPrintCommand );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "success\n" );
+ #endif
+ break;
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "failed\n" );
+ #endif
+ }
+}
+
diff --git a/vcl/unx/source/printergfx/bitmap_gfx.cxx b/vcl/unx/source/printergfx/bitmap_gfx.cxx
new file mode 100644
index 000000000000..b1ec82aa17e2
--- /dev/null
+++ b/vcl/unx/source/printergfx/bitmap_gfx.cxx
@@ -0,0 +1,735 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: bitmap_gfx.cxx,v $
+ * $Revision: 1.13 $
+ *
+ * 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 "psputil.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/strhelper.hxx"
+
+namespace psp {
+
+const sal_uInt32 nLineLength = 80;
+const sal_uInt32 nBufferSize = 16384;
+
+/*
+ *
+ * Bitmap compression / Hex encoding / Ascii85 Encoding
+ *
+ */
+
+PrinterBmp::~PrinterBmp ()
+{ /* dont need this, but C50 does */ }
+
+/* virtual base class */
+
+class ByteEncoder
+{
+private:
+
+public:
+
+ virtual void EncodeByte (sal_uInt8 nByte) = 0;
+ virtual ~ByteEncoder () = 0;
+};
+
+ByteEncoder::~ByteEncoder ()
+{ /* dont need this, but the C50 does */ }
+
+/* HexEncoder */
+
+class HexEncoder : public ByteEncoder
+{
+private:
+
+ osl::File* mpFile;
+ sal_uInt32 mnColumn;
+ sal_uInt32 mnOffset;
+ sal_Char mpFileBuffer[nBufferSize + 16];
+
+ HexEncoder (); /* dont use */
+
+public:
+
+ HexEncoder (osl::File* pFile);
+ virtual ~HexEncoder ();
+ void WriteAscii (sal_uInt8 nByte);
+ virtual void EncodeByte (sal_uInt8 nByte);
+ void FlushLine ();
+};
+
+HexEncoder::HexEncoder (osl::File* pFile) :
+ mpFile (pFile),
+ mnColumn (0),
+ mnOffset (0)
+{}
+
+HexEncoder::~HexEncoder ()
+{
+ FlushLine ();
+ if (mnColumn > 0)
+ WritePS (mpFile, "\n");
+}
+
+void
+HexEncoder::WriteAscii (sal_uInt8 nByte)
+{
+ sal_uInt32 nOff = psp::getHexValueOf (nByte, mpFileBuffer + mnOffset);
+ mnColumn += nOff;
+ mnOffset += nOff;
+
+ if (mnColumn >= nLineLength)
+ {
+ mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
+ mnColumn = 0;
+ }
+ if (mnOffset >= nBufferSize)
+ FlushLine ();
+}
+
+void
+HexEncoder::EncodeByte (sal_uInt8 nByte)
+{
+ WriteAscii (nByte);
+}
+
+void
+HexEncoder::FlushLine ()
+{
+ if (mnOffset > 0)
+ {
+ WritePS (mpFile, mpFileBuffer, mnOffset);
+ mnOffset = 0;
+ }
+}
+
+/* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
+ indicate end of data EOD */
+
+class Ascii85Encoder : public ByteEncoder
+{
+private:
+
+ osl::File* mpFile;
+ sal_uInt32 mnByte;
+ sal_uInt8 mpByteBuffer[4];
+
+ sal_uInt32 mnColumn;
+ sal_uInt32 mnOffset;
+ sal_Char mpFileBuffer[nBufferSize + 16];
+
+ Ascii85Encoder (); /* dont use */
+
+ inline void PutByte (sal_uInt8 nByte);
+ inline void PutEOD ();
+ void ConvertToAscii85 ();
+ void FlushLine ();
+
+public:
+
+ Ascii85Encoder (osl::File* pFile);
+ virtual ~Ascii85Encoder ();
+ virtual void EncodeByte (sal_uInt8 nByte);
+ void WriteAscii (sal_uInt8 nByte);
+};
+
+Ascii85Encoder::Ascii85Encoder (osl::File* pFile) :
+ mpFile (pFile),
+ mnByte (0),
+ mnColumn (0),
+ mnOffset (0)
+{}
+
+inline void
+Ascii85Encoder::PutByte (sal_uInt8 nByte)
+{
+ mpByteBuffer [mnByte++] = nByte;
+}
+
+inline void
+Ascii85Encoder::PutEOD ()
+{
+ WritePS (mpFile, "~>\n");
+}
+
+void
+Ascii85Encoder::ConvertToAscii85 ()
+{
+ if (mnByte < 4)
+ std::memset (mpByteBuffer + mnByte, 0, (4 - mnByte) * sizeof(sal_uInt8));
+
+ sal_uInt32 nByteValue = mpByteBuffer[0] * 256 * 256 * 256
+ + mpByteBuffer[1] * 256 * 256
+ + mpByteBuffer[2] * 256
+ + mpByteBuffer[3];
+
+ if (nByteValue == 0 && mnByte == 4)
+ {
+ /* special case of 4 Bytes in row */
+ mpFileBuffer [mnOffset] = 'z';
+
+ mnOffset += 1;
+ mnColumn += 1;
+ }
+ else
+ {
+ /* real ascii85 encoding */
+ mpFileBuffer [mnOffset + 4] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 3] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 2] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 1] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 0] = (nByteValue % 85) + 33;
+
+ mnColumn += (mnByte + 1);
+ mnOffset += (mnByte + 1);
+
+ /* insert a newline if necessary */
+ if (mnColumn > nLineLength)
+ {
+ sal_uInt32 nEolOff = mnColumn - nLineLength;
+ sal_uInt32 nBufOff = mnOffset - nEolOff;
+
+ std::memmove (mpFileBuffer + nBufOff + 1, mpFileBuffer + nBufOff, nEolOff);
+ mpFileBuffer[ nBufOff ] = '\n';
+
+ mnOffset++;
+ mnColumn = nEolOff;
+ }
+ }
+
+ mnByte = 0;
+}
+
+void
+Ascii85Encoder::WriteAscii (sal_uInt8 nByte)
+{
+ PutByte (nByte);
+ if (mnByte == 4)
+ ConvertToAscii85 ();
+
+ if (mnColumn >= nLineLength)
+ {
+ mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
+ mnColumn = 0;
+ }
+ if (mnOffset >= nBufferSize)
+ FlushLine ();
+}
+
+void
+Ascii85Encoder::EncodeByte (sal_uInt8 nByte)
+{
+ WriteAscii (nByte);
+}
+
+void
+Ascii85Encoder::FlushLine ()
+{
+ if (mnOffset > 0)
+ {
+ WritePS (mpFile, mpFileBuffer, mnOffset);
+ mnOffset = 0;
+ }
+}
+
+Ascii85Encoder::~Ascii85Encoder ()
+{
+ if (mnByte > 0)
+ ConvertToAscii85 ();
+ if (mnOffset > 0)
+ FlushLine ();
+ PutEOD ();
+}
+
+/* LZW encoder */
+
+class LZWEncoder : public Ascii85Encoder
+{
+private:
+
+ struct LZWCTreeNode
+ {
+ LZWCTreeNode* mpBrother; // next node with same parent
+ LZWCTreeNode* mpFirstChild; // first son
+ sal_uInt16 mnCode; // code for the string
+ sal_uInt16 mnValue; // pixelvalue
+ };
+
+ LZWCTreeNode* mpTable; // LZW compression data
+ LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression
+ sal_uInt16 mnDataSize;
+ sal_uInt16 mnClearCode;
+ sal_uInt16 mnEOICode;
+ sal_uInt16 mnTableSize;
+ sal_uInt16 mnCodeSize;
+ sal_uInt32 mnOffset;
+ sal_uInt32 mdwShift;
+
+ LZWEncoder ();
+ void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen);
+
+public:
+
+ LZWEncoder (osl::File* pOutputFile);
+ ~LZWEncoder ();
+
+ virtual void EncodeByte (sal_uInt8 nByte);
+};
+
+LZWEncoder::LZWEncoder(osl::File* pOutputFile) :
+ Ascii85Encoder (pOutputFile)
+{
+ mnDataSize = 8;
+
+ mnClearCode = 1 << mnDataSize;
+ mnEOICode = mnClearCode + 1;
+ mnTableSize = mnEOICode + 1;
+ mnCodeSize = mnDataSize + 1;
+
+ mnOffset = 32; // free bits in dwShift
+ mdwShift = 0;
+
+ mpTable = new LZWCTreeNode[ 4096 ];
+
+ for (sal_uInt32 i = 0; i < 4096; i++)
+ {
+ mpTable[i].mpBrother = NULL;
+ mpTable[i].mpFirstChild = NULL;
+ mpTable[i].mnCode = i;
+ mpTable[i].mnValue = (sal_uInt8)mpTable[i].mnCode;
+ }
+
+ mpPrefix = NULL;
+
+ WriteBits( mnClearCode, mnCodeSize );
+}
+
+LZWEncoder::~LZWEncoder()
+{
+ if (mpPrefix)
+ WriteBits (mpPrefix->mnCode, mnCodeSize);
+
+ WriteBits (mnEOICode, mnCodeSize);
+
+ delete[] mpTable;
+}
+
+void
+LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen)
+{
+ mdwShift |= (nCode << (mnOffset - nCodeLen));
+ mnOffset -= nCodeLen;
+ while (mnOffset < 24)
+ {
+ WriteAscii ((sal_uInt8)(mdwShift >> 24));
+ mdwShift <<= 8;
+ mnOffset += 8;
+ }
+ if (nCode == 257 && mnOffset != 32)
+ WriteAscii ((sal_uInt8)(mdwShift >> 24));
+}
+
+void
+LZWEncoder::EncodeByte (sal_uInt8 nByte )
+{
+ LZWCTreeNode* p;
+ sal_uInt16 i;
+ sal_uInt8 nV;
+
+ if (!mpPrefix)
+ {
+ mpPrefix = mpTable + nByte;
+ }
+ else
+ {
+ nV = nByte;
+ for (p = mpPrefix->mpFirstChild; p != NULL; p = p->mpBrother)
+ {
+ if (p->mnValue == nV)
+ break;
+ }
+
+ if (p != NULL)
+ {
+ mpPrefix = p;
+ }
+ else
+ {
+ WriteBits (mpPrefix->mnCode, mnCodeSize);
+
+ if (mnTableSize == 409)
+ {
+ WriteBits (mnClearCode, mnCodeSize);
+
+ for (i = 0; i < mnClearCode; i++)
+ mpTable[i].mpFirstChild = NULL;
+
+ mnCodeSize = mnDataSize + 1;
+ mnTableSize = mnEOICode + 1;
+ }
+ else
+ {
+ if(mnTableSize == (sal_uInt16)((1 << mnCodeSize) - 1))
+ mnCodeSize++;
+
+ p = mpTable + (mnTableSize++);
+ p->mpBrother = mpPrefix->mpFirstChild;
+ mpPrefix->mpFirstChild = p;
+ p->mnValue = nV;
+ p->mpFirstChild = NULL;
+ }
+
+ mpPrefix = mpTable + nV;
+ }
+ }
+}
+
+/*
+ *
+ * bitmap handling routines
+ *
+ */
+
+void
+PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& rBitmap)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+
+ if (mnPSLevel >= 2)
+ {
+ if (rBitmap.GetDepth() == 1)
+ {
+ DrawPS2MonoImage (rBitmap, rSrc);
+ }
+ else
+ if (rBitmap.GetDepth() == 8 && mbColor)
+ {
+ // if the palette is larger than the image itself print it as a truecolor
+ // image to save diskspace. This is important for printing transparent
+ // bitmaps that are disassembled into small pieces
+ sal_Int32 nImageSz = rSrc.GetWidth() * rSrc.GetHeight();
+ sal_Int32 nPaletteSz = rBitmap.GetPaletteEntryCount();
+ if ((nImageSz < nPaletteSz) || (nImageSz < 24) )
+ DrawPS2TrueColorImage (rBitmap, rSrc);
+ else
+ DrawPS2PaletteImage (rBitmap, rSrc);
+ }
+ else
+ if (rBitmap.GetDepth() == 24 && mbColor)
+ {
+ DrawPS2TrueColorImage (rBitmap, rSrc);
+ }
+ else
+ {
+ DrawPS2GrayImage (rBitmap, rSrc);
+ }
+ }
+ else
+ {
+ DrawPS1GrayImage (rBitmap, rSrc);
+ }
+
+ PSGRestore ();
+}
+
+/* XXX does not work XXX */
+void
+PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& /*rBitmap*/, const PrinterBmp& /*rTransBitmap*/)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+ PSGRestore ();
+}
+
+/* XXX does not work XXX */
+void
+PrinterGfx::DrawMask (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp &/*rBitmap*/, PrinterColor& /*rMaskColor*/)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+ PSGRestore ();
+}
+
+/*
+ *
+ * Implementation: PS Level 1
+ *
+ */
+
+void
+PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ sal_uInt32 nWidth = rArea.GetWidth();
+ sal_uInt32 nHeight = rArea.GetHeight();
+
+ sal_Char pGrayImage [512];
+ sal_Int32 nChar = 0;
+
+ // image header
+ nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
+ nChar += psp::appendStr (" ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
+ nChar += psp::appendStr (" 8 ", pGrayImage + nChar);
+ nChar += psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
+ nChar += psp::appendStr ("]", pGrayImage + nChar);
+ nChar += psp::appendStr (" {currentfile ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
+ nChar += psp::appendStr (" string readhexstring pop}\n", pGrayImage + nChar);
+ nChar += psp::appendStr ("image\n", pGrayImage + nChar);
+
+ WritePS (mpPageBody, pGrayImage);
+
+ // image body
+ HexEncoder* pEncoder = new HexEncoder (mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+
+ WritePS (mpPageBody, "\n");
+}
+
+/*
+ *
+ * Implementation: PS Level 2
+ *
+ */
+
+void
+PrinterGfx::writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType)
+{
+ sal_Int32 nChar = 0;
+ sal_Char pImage [512];
+
+ sal_Int32 nDictType = 0;
+ switch (nType)
+ {
+ case psp::TrueColorImage: nDictType = 0; break;
+ case psp::PaletteImage: nDictType = 1; break;
+ case psp::GrayScaleImage: nDictType = 2; break;
+ case psp::MonochromeImage: nDictType = 3; break;
+ default: break;
+ }
+ sal_Int32 nCompressType = mbCompressBmp ? 1 : 0;
+
+ nChar += psp::getValueOf (rArea.GetWidth(), pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (rArea.GetHeight(), pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (nDictType, pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (nCompressType, pImage + nChar);
+ nChar += psp::appendStr (" psp_imagedict image\n", pImage + nChar);
+
+ WritePS (mpPageBody, pImage);
+}
+
+void
+PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType)
+{
+ switch (nType)
+ {
+ case psp::GrayScaleImage:
+
+ WritePS (mpPageBody, "/DeviceGray setcolorspace\n");
+ break;
+
+ case psp::TrueColorImage:
+
+ WritePS (mpPageBody, "/DeviceRGB setcolorspace\n");
+ break;
+
+ case psp::MonochromeImage:
+ case psp::PaletteImage:
+ {
+
+ sal_Int32 nChar = 0;
+ sal_Char pImage [4096];
+
+ const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount();
+
+ nChar += psp::appendStr ("[/Indexed /DeviceRGB ", pImage + nChar);
+ nChar += psp::getValueOf (nSize - 1, pImage + nChar);
+ if (mbCompressBmp)
+ nChar += psp::appendStr ("\npsp_lzwstring\n", pImage + nChar);
+ else
+ nChar += psp::appendStr ("\npsp_ascii85string\n", pImage + nChar);
+ WritePS (mpPageBody, pImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+ for (sal_uInt32 i = 0; i < nSize; i++)
+ {
+ PrinterColor aColor = rBitmap.GetPaletteColor(i);
+
+ pEncoder->EncodeByte (aColor.GetRed());
+ pEncoder->EncodeByte (aColor.GetGreen());
+ pEncoder->EncodeByte (aColor.GetBlue());
+ }
+ delete pEncoder;
+
+ WritePS (mpPageBody, "pop ] setcolorspace\n");
+ }
+ break;
+ default: break;
+ }
+}
+
+void
+PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::GrayScaleImage);
+ writePS2ImageHeader(rArea, psp::GrayScaleImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::MonochromeImage);
+ writePS2ImageHeader(rArea, psp::MonochromeImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ long nBitPos = 0;
+ sal_uChar nBit = 0;
+ sal_uChar nByte = 0;
+
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ nBit = rBitmap.GetPixelIdx (nRow, nColumn);
+ nByte |= nBit << (7 - nBitPos);
+
+ if (++nBitPos == 8)
+ {
+ pEncoder->EncodeByte (nByte);
+ nBitPos = 0;
+ nByte = 0;
+ }
+ }
+ // keep the row byte aligned
+ if (nBitPos != 0)
+ pEncoder->EncodeByte (nByte);
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::PaletteImage);
+ writePS2ImageHeader(rArea, psp::PaletteImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelIdx (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::TrueColorImage);
+ writePS2ImageHeader(rArea, psp::TrueColorImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn);
+ pEncoder->EncodeByte (aColor.GetRed());
+ pEncoder->EncodeByte (aColor.GetGreen());
+ pEncoder->EncodeByte (aColor.GetBlue());
+ }
+ }
+
+ delete pEncoder;
+}
+
+} /* namespace psp */
diff --git a/vcl/unx/source/printergfx/common_gfx.cxx b/vcl/unx/source/printergfx/common_gfx.cxx
new file mode 100644
index 000000000000..632f0d70aa2f
--- /dev/null
+++ b/vcl/unx/source/printergfx/common_gfx.cxx
@@ -0,0 +1,1310 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: common_gfx.cxx,v $
+ * $Revision: 1.20.18.1 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * 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 "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/printerjob.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "tools/debug.hxx"
+#include "tools/color.hxx"
+#include "tools/poly.hxx"
+
+using namespace psp ;
+
+static const sal_Int32 nMaxTextColumn = 80;
+
+GraphicsStatus::GraphicsStatus() :
+ mbArtItalic( false ),
+ mbArtBold( false ),
+ mnTextHeight( 0 ),
+ mnTextWidth( 0 ),
+ mfLineWidth( -1 )
+{
+}
+
+/*
+ * non graphics graphics routines
+ */
+
+sal_Bool
+PrinterGfx::Init (PrinterJob &rPrinterJob)
+{
+ mpPageHeader = rPrinterJob.GetCurrentPageHeader ();
+ mpPageBody = rPrinterJob.GetCurrentPageBody ();
+ mnDepth = rPrinterJob.GetDepth ();
+ mnPSLevel = rPrinterJob.GetPostscriptLevel ();
+ mbColor = rPrinterJob.IsColorPrinter ();
+
+ mnDpi = rPrinterJob.GetResolution();
+ rPrinterJob.GetScale (mfScaleX, mfScaleY);
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob.GetPrinterName() ) );
+ if( mpFontSubstitutes )
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+ if( rInfo.m_bPerformFontSubstitution )
+ mpFontSubstitutes = new ::std::hash_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
+ else
+ mpFontSubstitutes = NULL;
+ mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
+
+ return sal_True;
+}
+
+sal_Bool
+PrinterGfx::Init (const JobData& rData)
+{
+ mpPageHeader = NULL;
+ mpPageBody = NULL;
+ mnDepth = rData.m_nColorDepth;
+ mnPSLevel = rData.m_nPSLevel ? rData.m_nPSLevel : (rData.m_pParser ? rData.m_pParser->getLanguageLevel() : 2 );
+ mbColor = rData.m_nColorDevice ? ( rData.m_nColorDevice == -1 ? sal_False : sal_True ) : (( rData.m_pParser ? (rData.m_pParser->isColorDevice() ? sal_True : sal_False ) : sal_True ) );
+ int nRes = rData.m_aContext.getRenderResolution();
+ mnDpi = nRes;
+ mfScaleX = (double)72.0 / (double)mnDpi;
+ mfScaleY = (double)72.0 / (double)mnDpi;
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rData.m_aPrinterName ) );
+ if( mpFontSubstitutes )
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+ if( rInfo.m_bPerformFontSubstitution )
+ mpFontSubstitutes = new ::std::hash_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
+ else
+ mpFontSubstitutes = NULL;
+ mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
+
+ return sal_True;
+}
+
+void
+PrinterGfx::GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const
+{
+ rDpiX = mnDpi;
+ rDpiY = mnDpi;
+}
+
+sal_uInt16
+PrinterGfx::GetBitCount ()
+{
+ return mnDepth;
+}
+
+PrinterGfx::PrinterGfx() :
+ mpPageHeader (NULL),
+ mpPageBody (NULL),
+ mnFontID (0),
+ mnFallbackID (0),
+ mnTextAngle (0),
+ mbTextVertical (false),
+ mrFontMgr (PrintFontManager::get()),
+ mbCompressBmp (sal_True),
+ maFillColor (0xff,0,0),
+ maTextColor (0,0,0),
+ maLineColor (0, 0xff, 0),
+ mpFontSubstitutes( NULL ),
+ mbStrictSO52Compatibility( false )
+{
+ maVirtualStatus.mfLineWidth = 1.0;
+ maVirtualStatus.mnTextHeight = 12;
+ maVirtualStatus.mnTextWidth = 0;
+
+ maGraphicsStack.push_back( GraphicsStatus() );
+}
+
+PrinterGfx::~PrinterGfx()
+{
+ /*
+ * #95810# the original reasoning why mpFontSubstitutes is a pointer was
+ * that applications should release all PrinterGfx when printers change
+ * because they are really invalid; the corresponding printers may have
+ * changed their settings or even not exist anymore.
+ *
+ * Alas, this is not always done real time. So we keep a local copy of
+ * the font substitutes now in case of bad timing.
+ */
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+}
+
+void
+PrinterGfx::Clear()
+{
+ mpPageHeader = NULL;
+ mpPageBody = NULL;
+ mnFontID = 0;
+ maVirtualStatus = GraphicsStatus();
+ maVirtualStatus.mnTextHeight = 12;
+ maVirtualStatus.mnTextWidth = 0;
+ maVirtualStatus.mfLineWidth = 1.0;
+ mbTextVertical = false;
+ maLineColor = PrinterColor();
+ maFillColor = PrinterColor();
+ maTextColor = PrinterColor();
+ mbCompressBmp = sal_True;
+ mnDpi = 300;
+ mnDepth = 24;
+ mnPSLevel = 2;
+ mbColor = sal_True;
+ mnTextAngle = 0;
+
+ maClipRegion.clear();
+ maGraphicsStack.clear();
+ maGraphicsStack.push_back( GraphicsStatus() );
+}
+
+/*
+ * clip region handling
+ */
+
+void
+PrinterGfx::ResetClipRegion()
+{
+ maClipRegion.clear();
+ PSGRestore ();
+ PSGSave (); // get "clean" clippath
+}
+
+void
+PrinterGfx::BeginSetClipRegion( sal_uInt32 )
+{
+ maClipRegion.clear();
+}
+
+sal_Bool
+PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
+{
+ if( nDX && nDY )
+ maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
+ return sal_True;
+}
+
+sal_Bool
+PrinterGfx::JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it,
+ Point& rOldPoint, sal_Int32& rColumn )
+{
+ sal_Bool bSuccess = sal_False;
+
+ std::list< Rectangle >::iterator tempit, nextit;
+ nextit = it;
+ ++nextit;
+ std::list< Point > leftside, rightside;
+
+ Rectangle aLastRect( *it );
+ leftside.push_back( Point( it->Left(), it->Top() ) );
+ rightside.push_back( Point( it->Right()+1, it->Top() ) );
+ while( nextit != maClipRegion.end() )
+ {
+ tempit = nextit;
+ ++tempit;
+ if( nextit->Top() == aLastRect.Bottom()+1 )
+ {
+ if(
+ ( nextit->Left() >= aLastRect.Left() && nextit->Left() <= aLastRect.Right() ) // left endpoint touches last rectangle
+ ||
+ ( nextit->Right() >= aLastRect.Left() && nextit->Right() <= aLastRect.Right() ) // right endpoint touches last rectangle
+ ||
+ ( nextit->Left() <= aLastRect.Left() && nextit->Right() >= aLastRect.Right() ) // whole line touches last rectangle
+ )
+ {
+ if( aLastRect.GetHeight() > 1 ||
+ abs( aLastRect.Left() - nextit->Left() ) > 2 ||
+ abs( aLastRect.Right() - nextit->Right() ) > 2
+ )
+ {
+ leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
+ rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
+ }
+ aLastRect = *nextit;
+ leftside.push_back( aLastRect.TopLeft() );
+ rightside.push_back( aLastRect.TopRight() );
+ maClipRegion.erase( nextit );
+ }
+ }
+ nextit = tempit;
+ }
+ if( leftside.size() > 1 )
+ {
+ // push the last coordinates
+ leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
+ rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
+
+ // cool, we can concatenate rectangles
+ int nDX = -65536, nDY = 65536;
+ int nNewDX = 0, nNewDY = 0;
+
+ Point aLastPoint = leftside.front();
+ PSBinMoveTo (aLastPoint, rOldPoint, rColumn);
+ leftside.pop_front();
+ while( leftside.begin() != leftside.end() )
+ {
+ Point aPoint (leftside.front());
+ leftside.pop_front();
+ // may have been the last one
+ if( leftside.begin() != leftside.end() )
+ {
+ nNewDX = aPoint.X() - aLastPoint.X();
+ nNewDY = aPoint.Y() - aLastPoint.Y();
+ if( nNewDX == 0 && nDX == 0 )
+ continue;
+ if( nDX != 0 && nNewDX != 0 &&
+ (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
+ continue;
+ }
+ PSBinLineTo (aPoint, rOldPoint, rColumn);
+ aLastPoint = aPoint;
+ }
+
+ aLastPoint = rightside.back();
+ nDX = -65536;
+ nDY = 65536;
+ PSBinLineTo (aLastPoint, rOldPoint, rColumn);
+ rightside.pop_back();
+ while( rightside.begin() != rightside.end() )
+ {
+ Point aPoint (rightside.back());
+ rightside.pop_back();
+ if( rightside.begin() != rightside.end() )
+ {
+ nNewDX = aPoint.X() - aLastPoint.X();
+ nNewDY = aPoint.Y() - aLastPoint.Y();
+ if( nNewDX == 0 && nDX == 0 )
+ continue;
+ if( nDX != 0 && nNewDX != 0 &&
+ (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
+ continue;
+ }
+ PSBinLineTo (aPoint, rOldPoint, rColumn);
+ }
+
+ tempit = it;
+ ++tempit;
+ maClipRegion.erase( it );
+ it = tempit;
+ bSuccess = sal_True;
+ }
+ return bSuccess;
+}
+
+void
+PrinterGfx::EndSetClipRegion()
+{
+ PSGRestore ();
+ PSGSave (); // get "clean" clippath
+
+ PSBinStartPath ();
+ Point aOldPoint (0, 0);
+ sal_Int32 nColumn = 0;
+
+ std::list< Rectangle >::iterator it = maClipRegion.begin();
+ while( it != maClipRegion.end() )
+ {
+ // try to concatenate adjacent rectangles
+ // first try in y direction, then in x direction
+ if( ! JoinVerticalClipRectangles( it, aOldPoint, nColumn ) )
+ {
+ // failed, so it is a single rectangle
+ PSBinMoveTo (it->TopLeft(), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Left(), it->Bottom()+1 ), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Right()+1, it->Bottom()+1 ), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Right()+1, it->Top() ), aOldPoint, nColumn );
+ ++it;
+ }
+ }
+
+ PSBinEndPath ();
+
+ WritePS (mpPageBody, "closepath clip newpath\n");
+ maClipRegion.clear();
+}
+
+/*
+ * draw graphic primitives
+ */
+
+void
+PrinterGfx::DrawRect (const Rectangle& rRectangle )
+{
+ char pRect [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (rRectangle.TopLeft().X(), pRect);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.TopLeft().Y(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.GetWidth(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.GetHeight(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+
+ if( maFillColor.Is() )
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, pRect, nChar);
+ WritePS (mpPageBody, "rectfill\n");
+ }
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, pRect, nChar);
+ WritePS (mpPageBody, "rectstroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
+{
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ PSMoveTo (rFrom);
+ PSLineTo (rTo);
+ WritePS (mpPageBody, "stroke\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
+{
+ if( rPixelColor.Is() )
+ {
+ PSSetColor (rPixelColor);
+ PSSetColor ();
+
+ PSMoveTo (rPoint);
+ PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()));
+ PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()+1));
+ PSLineTo (Point (rPoint.X (), rPoint.Y ()+1));
+ WritePS (mpPageBody, "fill\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
+{
+ if( maLineColor.Is() && nPoints && pPath )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ PSBinCurrentPath (nPoints, pPath);
+
+ WritePS (mpPageBody, "stroke\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
+{
+ // premature end of operation
+ if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+ // setup closed path
+ Point aPoint( 0, 0 );
+ sal_Int32 nColumn( 0 );
+
+ PSBinStartPath();
+ PSBinMoveTo( pPath[0], aPoint, nColumn );
+ for( unsigned int n = 1; n < nPoints; n++ )
+ PSBinLineTo( pPath[n], aPoint, nColumn );
+ if( pPath[0] != pPath[nPoints-1] )
+ PSBinLineTo( pPath[0], aPoint, nColumn );
+ PSBinEndPath();
+
+ // fill the polygon first, then draw the border, note that fill and
+ // stroke reset the currentpath
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+
+ if (maLineColor.Is ())
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
+{
+ // sanity check
+ if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+
+ // setup closed path
+ for( unsigned int i = 0; i < nPoly; i++ )
+ {
+ Point aPoint( 0, 0 );
+ sal_Int32 nColumn( 0 );
+
+ PSBinStartPath();
+ PSBinMoveTo( pPaths[i][0], aPoint, nColumn );
+ for( unsigned int n = 1; n < pSizes[i]; n++ )
+ PSBinLineTo( pPaths[i][n], aPoint, nColumn );
+ if( pPaths[i][0] != pPaths[i][pSizes[i]-1] )
+ PSBinLineTo( pPaths[i][0], aPoint, nColumn );
+ PSBinEndPath();
+ }
+
+ // if eofill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ // first draw area
+ if( maFillColor.Is() )
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+
+ // now draw outlines
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+/*
+ * Bezier Polygon Drawing methods.
+ */
+
+void
+PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints, const Point* pPath, const BYTE* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+
+ if ( maLineColor.Is() && nPoints && pPath )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ if (pFlgAry[0] != POLY_NORMAL) //There must be a starting point to moveto
+ {
+ return;
+ }
+ else
+ {
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
+ WritePS(mpPageBody, pString);
+ }
+
+ // Handle the drawing of mixed lines mixed with curves
+ // - a normal point followed by a normal point is a line
+ // - a normal point followed by 2 control points and a normal point is a curve
+ for (unsigned int i=1; i<nPoints;)
+ {
+ if (pFlgAry[i+1] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
+ {
+ if (i+1 >= nPoints) return; //Make sure we don't pass the end of the array
+ snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
+ i++;
+ }
+ else //Otherwise we're drawing a spline
+ {
+ if (i+3 >= nPoints) return; //Make sure we don't pass the end of the array
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y(),
+ pPath[i+3].X(), pPath[i+3].Y());
+ i+=3;
+ }
+ WritePS(mpPageBody, pString);
+ }
+ }
+
+ // if eofill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ // first draw area
+ if( maFillColor.Is() )
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+
+ // now draw outlines
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints, const Point* pPath, const BYTE* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+ // premature end of operation
+ if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
+ WritePS(mpPageBody, pString); //Move to the starting point for the PolyPoygon
+ for (unsigned int i=1; i < nPoints;)
+ {
+ if (pFlgAry[i] != POLY_CONTROL)
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
+ WritePS(mpPageBody, pString);
+ i++;
+ }
+ else
+ {
+ if (i+2 >= nPoints)
+ return; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
+ (pFlgAry[i+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i].X(), pPath[i].Y(),
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y());
+ WritePS(mpPageBody, pString);
+ }
+ else
+ {
+ fprintf(stderr, "Strange output\n");
+ }
+ i+=3;
+ }
+ }
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+}
+
+void
+PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly, const sal_uInt32 * pPoints, const Point* const * pPtAry, const BYTE* const* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+ if ( !nPoly || !pPtAry || !pPoints || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+
+ for (unsigned int i=0; i<nPoly;i++)
+ {
+ sal_uInt32 nPoints = pPoints[i];
+ // #112689# sanity check
+ if( nPoints == 0 || pPtAry[i] == NULL )
+ continue;
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPtAry[i][0].X(), pPtAry[i][0].Y()); //Move to the starting point
+ WritePS(mpPageBody, pString);
+ for (unsigned int j=1; j < nPoints;)
+ {
+ // if no flag array exists for this polygon, then it must be a regular
+ // polygon without beziers
+ if ( ! pFlgAry[i] || pFlgAry[i][j] != POLY_CONTROL)
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPtAry[i][j].X(), pPtAry[i][j].Y());
+ WritePS(mpPageBody, pString);
+ j++;
+ }
+ else
+ {
+ if (j+2 >= nPoints)
+ break; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i][j] == POLY_CONTROL) && (pFlgAry[i][j+1] == POLY_CONTROL) && (pFlgAry[i][j+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPtAry[i][j].X(), pPtAry[i][j].Y(),
+ pPtAry[i][j+1].X(), pPtAry[i][j+1].Y(),
+ pPtAry[i][j+2].X(), pPtAry[i][j+2].Y());
+ WritePS(mpPageBody, pString);
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "Strange output\n");
+#endif
+ }
+ j+=3;
+ }
+ }
+ }
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+}
+
+
+/*
+ * postscript generating routines
+ */
+void
+PrinterGfx::PSGSave ()
+{
+ WritePS (mpPageBody, "gsave\n" );
+ GraphicsStatus aNewState;
+ if( maGraphicsStack.begin() != maGraphicsStack.end() )
+ aNewState = maGraphicsStack.front();
+ maGraphicsStack.push_front( aNewState );
+}
+
+void
+PrinterGfx::PSGRestore ()
+{
+ WritePS (mpPageBody, "grestore\n" );
+ if( maGraphicsStack.begin() == maGraphicsStack.end() )
+ WritePS (mpPageBody, "Error: too many grestores\n" );
+ else
+ maGraphicsStack.pop_front();
+}
+
+void
+PrinterGfx::PSSetLineWidth ()
+{
+ if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
+ {
+ char pBuffer[128];
+ sal_Int32 nChar = 0;
+
+ currentState().mfLineWidth = maVirtualStatus.mfLineWidth;
+ nChar = psp::getValueOfDouble (pBuffer, maVirtualStatus.mfLineWidth, 5);
+ nChar += psp::appendStr (" setlinewidth\n", pBuffer + nChar);
+ WritePS (mpPageBody, pBuffer, nChar);
+ }
+}
+
+void
+PrinterGfx::PSSetColor ()
+{
+ PrinterColor& rColor( maVirtualStatus.maColor );
+
+ if( currentState().maColor != rColor )
+ {
+ currentState().maColor = rColor;
+
+ char pBuffer[128];
+ sal_Int32 nChar = 0;
+
+ if( mbColor )
+ {
+ nChar = psp::getValueOfDouble (pBuffer,
+ (double)rColor.GetRed() / 255.0, 5);
+ nChar += psp::appendStr (" ", pBuffer + nChar);
+ nChar += psp::getValueOfDouble (pBuffer + nChar,
+ (double)rColor.GetGreen() / 255.0, 5);
+ nChar += psp::appendStr (" ", pBuffer + nChar);
+ nChar += psp::getValueOfDouble (pBuffer + nChar,
+ (double)rColor.GetBlue() / 255.0, 5);
+ nChar += psp::appendStr (" setrgbcolor\n", pBuffer + nChar );
+ }
+ else
+ {
+ Color aColor( rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
+ sal_uInt8 nCol = aColor.GetLuminance();
+ nChar = psp::getValueOfDouble( pBuffer, (double)nCol / 255.0, 5 );
+ nChar += psp::appendStr( " setgray\n", pBuffer + nChar );
+ }
+
+ WritePS (mpPageBody, pBuffer, nChar);
+ }
+}
+
+void
+PrinterGfx::PSSetFont ()
+{
+ GraphicsStatus& rCurrent( currentState() );
+ if( maVirtualStatus.maFont != rCurrent.maFont ||
+ maVirtualStatus.mnTextHeight != rCurrent.mnTextHeight ||
+ maVirtualStatus.maEncoding != rCurrent.maEncoding ||
+ maVirtualStatus.mnTextWidth != rCurrent.mnTextWidth ||
+ maVirtualStatus.mbArtBold != rCurrent.mbArtBold ||
+ maVirtualStatus.mbArtItalic != rCurrent.mbArtItalic
+ )
+ {
+ rCurrent.maFont = maVirtualStatus.maFont;
+ rCurrent.maEncoding = maVirtualStatus.maEncoding;
+ rCurrent.mnTextWidth = maVirtualStatus.mnTextWidth;
+ rCurrent.mnTextHeight = maVirtualStatus.mnTextHeight;
+ rCurrent.mbArtItalic = maVirtualStatus.mbArtItalic;
+ rCurrent.mbArtBold = maVirtualStatus.mbArtBold;
+
+ sal_Int32 nTextHeight = rCurrent.mnTextHeight;
+ sal_Int32 nTextWidth = rCurrent.mnTextWidth ? rCurrent.mnTextWidth
+ : rCurrent.mnTextHeight;
+
+ sal_Char pSetFont [256];
+ sal_Int32 nChar = 0;
+
+ // postscript based fonts need reencoding
+ if ( ( rCurrent.maEncoding == RTL_TEXTENCODING_MS_1252)
+ || ( rCurrent.maEncoding == RTL_TEXTENCODING_ISO_8859_1)
+ || ( rCurrent.maEncoding >= RTL_TEXTENCODING_USER_START
+ && rCurrent.maEncoding <= RTL_TEXTENCODING_USER_END)
+ )
+ {
+ rtl::OString aReencodedFont =
+ psp::GlyphSet::GetReencodedFontName (rCurrent.maEncoding,
+ rCurrent.maFont);
+
+ nChar += psp::appendStr ("(", pSetFont + nChar);
+ nChar += psp::appendStr (aReencodedFont.getStr(),
+ pSetFont + nChar);
+ nChar += psp::appendStr (") cvn findfont ",
+ pSetFont + nChar);
+ }
+ else
+ // tt based fonts mustn't reencode, the encoding is implied by the fontname
+ // same for symbol type1 fonts, dont try to touch them
+ {
+ nChar += psp::appendStr ("(", pSetFont + nChar);
+ nChar += psp::appendStr (rCurrent.maFont.getStr(),
+ pSetFont + nChar);
+ nChar += psp::appendStr (") cvn findfont ",
+ pSetFont + nChar);
+ }
+
+ if( ! rCurrent.mbArtItalic )
+ {
+ nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
+ nChar += psp::appendStr (" ", pSetFont + nChar);
+ nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
+ nChar += psp::appendStr (" matrix scale makefont setfont\n", pSetFont + nChar);
+ }
+ else // skew 15 degrees to right
+ {
+ nChar += psp::appendStr ( " [", pSetFont + nChar);
+ nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
+ nChar += psp::appendStr (" 0 ", pSetFont + nChar);
+ nChar += psp::getValueOfDouble (pSetFont + nChar, 0.27*(double)nTextWidth, 3 );
+ nChar += psp::appendStr ( " ", pSetFont + nChar);
+ nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
+
+ nChar += psp::appendStr (" 0 0] makefont setfont\n", pSetFont + nChar);
+ }
+
+ WritePS (mpPageBody, pSetFont);
+ }
+}
+
+void
+PrinterGfx::PSRotate (sal_Int32 nAngle)
+{
+ sal_Int32 nPostScriptAngle = -nAngle;
+ while( nPostScriptAngle < 0 )
+ nPostScriptAngle += 3600;
+
+ if (nPostScriptAngle == 0)
+ return;
+
+ sal_Int32 nFullAngle = nPostScriptAngle / 10;
+ sal_Int32 nTenthAngle = nPostScriptAngle % 10;
+
+ sal_Char pRotate [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (nFullAngle, pRotate);
+ nChar += psp::appendStr (".", pRotate + nChar);
+ nChar += psp::getValueOf (nTenthAngle, pRotate + nChar);
+ nChar += psp::appendStr (" rotate\n", pRotate + nChar);
+
+ WritePS (mpPageBody, pRotate);
+}
+
+void
+PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
+{
+ sal_Char pPSCommand [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (rPoint.X(), pPSCommand);
+ nChar += psp::appendStr (" ", pPSCommand + nChar);
+ nChar += psp::getValueOf (rPoint.Y(), pPSCommand + nChar);
+ nChar += psp::appendStr (" ", pPSCommand + nChar);
+ nChar += psp::appendStr (pOperator, pPSCommand + nChar);
+ nChar += psp::appendStr ("\n", pPSCommand + nChar);
+
+ DBG_ASSERT (nChar < 48, "Buffer overflow in PSPointOp");
+
+ WritePS (mpPageBody, pPSCommand);
+}
+
+void
+PrinterGfx::PSTranslate (const Point& rPoint)
+{
+ PSPointOp (rPoint, "translate");
+}
+
+void
+PrinterGfx::PSMoveTo (const Point& rPoint)
+{
+ PSPointOp (rPoint, "moveto");
+}
+
+void
+PrinterGfx::PSLineTo (const Point& rPoint)
+{
+ PSPointOp (rPoint, "lineto");
+}
+
+void
+PrinterGfx::PSRMoveTo (sal_Int32 nDx, sal_Int32 nDy)
+{
+ Point aPoint(nDx, nDy);
+ PSPointOp (aPoint, "rmoveto");
+}
+
+/* get a compressed representation of the path information */
+
+#define DEBUG_BINPATH 0
+
+void
+PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
+{
+#if (DEBUG_BINPATH == 1)
+ PSLineTo (rCurrent);
+#else
+ PSBinPath (rCurrent, rOld, lineto, nColumn);
+#endif
+}
+
+void
+PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
+{
+#if (DEBUG_BINPATH == 1)
+ PSMoveTo (rCurrent);
+#else
+ PSBinPath (rCurrent, rOld, moveto, nColumn);
+#endif
+}
+
+void
+PrinterGfx::PSBinStartPath ()
+{
+#if (DEBUG_BINPATH == 1)
+ WritePS (mpPageBody, "% PSBinStartPath\n");
+#else
+ WritePS (mpPageBody, "readpath\n" );
+#endif
+}
+
+void
+PrinterGfx::PSBinEndPath ()
+{
+#if (DEBUG_BINPATH == 1)
+ WritePS (mpPageBody, "% PSBinEndPath\n");
+#else
+ WritePS (mpPageBody, "~\n");
+#endif
+}
+
+void
+PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
+{
+ // create the path
+ Point aPoint (0, 0);
+ sal_Int32 nColumn = 0;
+
+ PSBinStartPath ();
+ PSBinMoveTo (*pPath, aPoint, nColumn);
+ for (unsigned int i = 1; i < nPoints; i++)
+ PSBinLineTo (pPath[i], aPoint, nColumn);
+ PSBinEndPath ();
+}
+
+void
+PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
+ pspath_t eType, sal_Int32& nColumn)
+{
+ sal_Char pPath[48];
+ sal_Int32 nChar;
+
+ // create the hex representation of the dx and dy path shift, store the field
+ // width as it is needed for the building the command
+ sal_Int32 nXPrec = getAlignedHexValueOf (rCurrent.X() - rOld.X(), pPath + 1);
+ sal_Int32 nYPrec = getAlignedHexValueOf (rCurrent.Y() - rOld.Y(), pPath + 1 + nXPrec);
+ pPath [ 1 + nXPrec + nYPrec ] = 0;
+
+ // build the command, it is a char with bit represention 000cxxyy
+ // c represents the char, xx and yy repr. the field width of the dx and dy shift,
+ // dx and dy represent the number of bytes to read after the opcode
+ sal_Char cCmd = (eType == lineto ? (sal_Char)0x00 : (sal_Char)0x10);
+ switch (nYPrec)
+ {
+ case 2: break;
+ case 4: cCmd |= 0x01; break;
+ case 6: cCmd |= 0x02; break;
+ case 8: cCmd |= 0x03; break;
+ default: DBG_ERROR ("invalid x precision in binary path");
+ }
+ switch (nXPrec)
+ {
+ case 2: break;
+ case 4: cCmd |= 0x04; break;
+ case 6: cCmd |= 0x08; break;
+ case 8: cCmd |= 0x0c; break;
+ default: DBG_ERROR ("invalid y precision in binary path");
+ }
+ cCmd += 'A';
+ pPath[0] = cCmd;
+
+ // write the command to file,
+ // line breaking at column nMaxTextColumn (80)
+ nChar = 1 + nXPrec + nYPrec;
+ if ((nColumn + nChar) > nMaxTextColumn)
+ {
+ sal_Int32 nSegment = nMaxTextColumn - nColumn;
+
+ WritePS (mpPageBody, pPath, nSegment);
+ WritePS (mpPageBody, "\n", 1);
+ WritePS (mpPageBody, pPath + nSegment, nChar - nSegment);
+
+ nColumn = nChar - nSegment;
+ }
+ else
+ {
+ WritePS (mpPageBody, pPath, nChar);
+
+ nColumn += nChar;
+ }
+
+ rOld = rCurrent;
+}
+
+void
+PrinterGfx::PSScale (double fScaleX, double fScaleY)
+{
+ sal_Char pScale [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOfDouble (pScale, fScaleX, 5);
+ nChar += psp::appendStr (" ", pScale + nChar);
+ nChar += psp::getValueOfDouble (pScale + nChar, fScaleY, 5);
+ nChar += psp::appendStr (" scale\n", pScale + nChar);
+
+ WritePS (mpPageBody, pScale);
+}
+
+/* psshowtext helper routines: draw an hex string for show/xshow */
+void
+PrinterGfx::PSHexString (const sal_uChar* pString, sal_Int16 nLen)
+{
+ sal_Char pHexString [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("<", pHexString);
+ for (int i = 0; i < nLen; i++)
+ {
+ if (nChar >= (nMaxTextColumn - 1))
+ {
+ nChar += psp::appendStr ("\n", pHexString + nChar);
+ WritePS (mpPageBody, pHexString, nChar);
+ nChar = 0;
+ }
+ nChar += psp::getHexValueOf ((sal_Int32)pString[i], pHexString + nChar);
+ }
+
+ nChar += psp::appendStr (">\n", pHexString + nChar);
+ WritePS (mpPageBody, pHexString, nChar);
+}
+
+/* psshowtext helper routines: draw an array for xshow ps operator */
+void
+PrinterGfx::PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries)
+{
+ sal_Char pPSArray [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("[", pPSArray + nChar);
+ nChar += psp::getValueOf (pArray[0], pPSArray + nChar);
+
+ for (int i = 1; i < nEntries; i++)
+ {
+ if (nChar >= (nMaxTextColumn - 1))
+ {
+ nChar += psp::appendStr ("\n", pPSArray + nChar);
+ WritePS (mpPageBody, pPSArray, nChar);
+ nChar = 0;
+ }
+
+ nChar += psp::appendStr (" ", pPSArray + nChar);
+ nChar += psp::getValueOf (pArray[i] - pArray[i-1], pPSArray + nChar);
+ }
+
+ nChar += psp::appendStr (" 0]\n", pPSArray + nChar);
+ WritePS (mpPageBody, pPSArray);
+}
+
+/* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
+ * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
+ * fonts it may be different (these fonts may be SJIS encoded for example) */
+void
+PrinterGfx::PSShowText (const sal_uChar* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
+ const sal_Int32* pDeltaArray)
+{
+ PSSetColor (maTextColor);
+ PSSetColor ();
+ PSSetFont ();
+ // rotate the user coordinate system
+ if (mnTextAngle != 0)
+ {
+ PSGSave ();
+ PSRotate (mnTextAngle);
+ }
+
+ sal_Char pBuffer[256];
+ if( maVirtualStatus.mbArtBold )
+ {
+ sal_Int32 nLW = maVirtualStatus.mnTextWidth;
+ if( nLW == 0 )
+ nLW = maVirtualStatus.mnTextHeight;
+ else
+ nLW = nLW < maVirtualStatus.mnTextHeight ? nLW : maVirtualStatus.mnTextHeight;
+ psp::getValueOfDouble( pBuffer, (double)nLW / 30.0 );
+ }
+ // dispatch to the drawing method
+ if (pDeltaArray == NULL)
+ {
+ PSHexString (pStr, nBytes);
+
+ if( maVirtualStatus.mbArtBold )
+ {
+ WritePS( mpPageBody, pBuffer );
+ WritePS( mpPageBody, " bshow\n" );
+ }
+ else
+ WritePS (mpPageBody, "show\n");
+ }
+ else
+ {
+ PSHexString (pStr, nBytes);
+ PSDeltaArray (pDeltaArray, nGlyphs - 1);
+ if( maVirtualStatus.mbArtBold )
+ {
+ WritePS( mpPageBody, pBuffer );
+ WritePS( mpPageBody, " bxshow\n" );
+ }
+ else
+ WritePS (mpPageBody, "xshow\n");
+ }
+
+ // restore the user coordinate system
+ if (mnTextAngle != 0)
+ PSGRestore ();
+}
+
+void
+PrinterGfx::PSComment( const sal_Char* pComment )
+{
+ const sal_Char* pLast = pComment;
+ while( pComment && *pComment )
+ {
+ while( *pComment && *pComment != '\n' && *pComment != '\r' )
+ pComment++;
+ if( pComment - pLast > 1 )
+ {
+ WritePS( mpPageBody, "% ", 2 );
+ WritePS( mpPageBody, pLast, pComment - pLast );
+ WritePS( mpPageBody, "\n", 1 );
+ }
+ if( *pComment )
+ pLast = ++pComment;
+ }
+}
+
+sal_Bool
+PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
+{
+ if( nSize == 0 )
+ return sal_True;
+ if( ! mpPageBody )
+ return sal_False;
+
+ sal_Bool bSuccess = sal_False;
+
+ // first search the BoundingBox of the EPS data
+ SvMemoryStream aStream( pPtr, nSize, STREAM_READ );
+ aStream.Seek( STREAM_SEEK_TO_BEGIN );
+ ByteString aLine;
+
+ ByteString aDocTitle;
+ double fLeft = 0, fRight = 0, fTop = 0, fBottom = 0;
+ bool bEndComments = false;
+ while( ! aStream.IsEof()
+ && ( ( fLeft == 0 && fRight == 0 && fTop == 0 && fBottom == 0 ) ||
+ ( aDocTitle.Len() == 0 && bEndComments == false ) )
+ )
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.Len() > 1 && aLine.GetChar( 0 ) == '%' )
+ {
+ char cChar = aLine.GetChar(1);
+ if( cChar == '%' )
+ {
+ if( aLine.CompareIgnoreCaseToAscii( "%%BoundingBox:", 14 ) == COMPARE_EQUAL )
+ {
+ aLine = WhitespaceToSpace( aLine.GetToken( 1, ':' ) );
+ if( aLine.Len() && aLine.Search( "atend" ) == STRING_NOTFOUND )
+ {
+ fLeft = StringToDouble( GetCommandLineToken( 0, aLine ) );
+ fBottom = StringToDouble( GetCommandLineToken( 1, aLine ) );
+ fRight = StringToDouble( GetCommandLineToken( 2, aLine ) );
+ fTop = StringToDouble( GetCommandLineToken( 3, aLine ) );
+ }
+ }
+ else if( aLine.CompareIgnoreCaseToAscii( "%%Title:", 8 ) == COMPARE_EQUAL )
+ aDocTitle = WhitespaceToSpace( aLine.Copy( 8 ) );
+ else if( aLine.CompareIgnoreCaseToAscii( "%%EndComments", 13 ) == COMPARE_EQUAL )
+ bEndComments = true;
+ }
+ else if( cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n' )
+ bEndComments = true;
+ }
+ else
+ bEndComments = true;
+ }
+
+ static sal_uInt16 nEps = 0;
+ if( ! aDocTitle.Len() )
+ aDocTitle = ByteString::CreateFromInt32( (sal_Int32)(nEps++) );
+
+ if( fLeft != fRight && fTop != fBottom )
+ {
+ double fScaleX = (double)rBoundingBox.GetWidth()/(fRight-fLeft);
+ double fScaleY = -(double)rBoundingBox.GetHeight()/(fTop-fBottom);
+ Point aTranslatePoint( (int)(rBoundingBox.Left()-fLeft*fScaleX),
+ (int)(rBoundingBox.Bottom()+1-fBottom*fScaleY) );
+ // prepare EPS
+ WritePS( mpPageBody,
+ "/b4_Inc_state save def\n"
+ "/dict_count countdictstack def\n"
+ "/op_count count 1 sub def\n"
+ "userdict begin\n"
+ "/showpage {} def\n"
+ "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
+ "10 setmiterlimit [] 0 setdash newpath\n"
+ "/languagelevel where\n"
+ "{pop languagelevel\n"
+ "1 ne\n"
+ " {false setstrokeadjust false setoverprint\n"
+ " } if\n"
+ "}if\n" );
+ // set up clip path and scale
+ BeginSetClipRegion( 1 );
+ UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
+ EndSetClipRegion();
+ PSTranslate( aTranslatePoint );
+ PSScale( fScaleX, fScaleY );
+
+ // DSC requires BeginDocument
+ WritePS( mpPageBody, "%%BeginDocument: " );
+ WritePS( mpPageBody, aDocTitle );
+ WritePS( mpPageBody, "\n" );
+
+ // write the EPS data
+ sal_uInt64 nOutLength;
+ mpPageBody->write( pPtr, nSize, nOutLength );
+ bSuccess = nOutLength == nSize;
+
+ // corresponding EndDocument
+ if( ((char*)pPtr)[ nSize-1 ] != '\n' )
+ WritePS( mpPageBody, "\n" );
+ WritePS( mpPageBody, "%%EndDocument\n" );
+
+ // clean up EPS
+ WritePS( mpPageBody,
+ "count op_count sub {pop} repeat\n"
+ "countdictstack dict_count sub {end} repeat\n"
+ "b4_Inc_state restore\n" );
+ }
+ return bSuccess;
+}
diff --git a/vcl/unx/source/printergfx/glyphset.cxx b/vcl/unx/source/printergfx/glyphset.cxx
new file mode 100644
index 000000000000..0d26a66cac2f
--- /dev/null
+++ b/vcl/unx/source/printergfx/glyphset.cxx
@@ -0,0 +1,908 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: glyphset.cxx,v $
+ * $Revision: 1.24 $
+ *
+ * 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 "glyphset.hxx"
+#include "psputil.hxx"
+
+#define NO_LIST
+#include "sft.h"
+#undef NO_LIST
+
+#include "vcl/printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+#include "rtl/ustring.hxx"
+#include "rtl/strbuf.hxx"
+
+#include <set>
+#include <map>
+
+using namespace psp;
+using namespace rtl;
+
+GlyphSet::GlyphSet ()
+ : mnFontID (-1),
+ mbVertical (0),
+ mbUseFontEncoding (false)
+{}
+
+GlyphSet::GlyphSet (sal_Int32 nFontID, sal_Bool bVertical)
+ : mnFontID (nFontID),
+ mbVertical (bVertical)
+{
+ PrintFontManager &rMgr = PrintFontManager::get();
+ meBaseType = rMgr.getFontType (mnFontID);
+ maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
+ mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
+}
+
+GlyphSet::~GlyphSet ()
+{
+ /* FIXME delete the glyphlist ??? */
+}
+
+sal_Int32
+GlyphSet::GetFontID ()
+{
+ return mnFontID;
+}
+
+fonttype::type
+GlyphSet::GetFontType ()
+{
+ return meBaseType;
+}
+
+sal_Bool
+GlyphSet::IsVertical ()
+{
+ return mbVertical;
+}
+
+sal_Bool
+GlyphSet::SetFont (sal_Int32 nFontID, sal_Bool bVertical)
+{
+ if (mnFontID != -1)
+ return sal_False;
+
+ mnFontID = nFontID;
+ mbVertical = bVertical;
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ meBaseType = rMgr.getFontType (mnFontID);
+ maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
+ mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::GetCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ return LookupCharID (nChar, nOutGlyphID, nOutGlyphSetID)
+ || AddCharID (nChar, nOutGlyphID, nOutGlyphSetID);
+}
+
+sal_Bool
+GlyphSet::GetGlyphID (
+ sal_uInt32 nGlyph,
+ sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ return LookupGlyphID (nGlyph, nOutGlyphID, nOutGlyphSetID)
+ || AddGlyphID (nGlyph, nUnicode, nOutGlyphID, nOutGlyphSetID);
+}
+
+sal_Bool
+GlyphSet::LookupCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ char_list_t::iterator aGlyphSet;
+ sal_Int32 nGlyphSetID;
+
+ // loop thru all the font subsets
+ for (aGlyphSet = maCharList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maCharList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ // check every subset if it contains the queried unicode char
+ char_map_t::const_iterator aGlyph = (*aGlyphSet).find (nChar);
+ if (aGlyph != (*aGlyphSet).end())
+ {
+ // success: found the unicode char, return the glyphid and the glyphsetid
+ *nOutGlyphSetID = nGlyphSetID;
+ *nOutGlyphID = (*aGlyph).second;
+ return sal_True;
+ }
+ }
+
+ *nOutGlyphSetID = -1;
+ *nOutGlyphID = 0;
+ return sal_False;
+}
+
+sal_Bool
+GlyphSet::LookupGlyphID (
+ sal_uInt32 nGlyph,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ glyph_list_t::iterator aGlyphSet;
+ sal_Int32 nGlyphSetID;
+
+ // loop thru all the font subsets
+ for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maGlyphList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ // check every subset if it contains the queried unicode char
+ glyph_map_t::const_iterator aGlyph = (*aGlyphSet).find (nGlyph);
+ if (aGlyph != (*aGlyphSet).end())
+ {
+ // success: found the glyph id, return the mapped glyphid and the glyphsetid
+ *nOutGlyphSetID = nGlyphSetID;
+ *nOutGlyphID = (*aGlyph).second;
+ return sal_True;
+ }
+ }
+
+ *nOutGlyphSetID = -1;
+ *nOutGlyphID = 0;
+ return sal_False;
+}
+
+sal_uChar
+GlyphSet::GetAnsiMapping (sal_Unicode nUnicodeChar)
+{
+ static rtl_UnicodeToTextConverter aConverter =
+ rtl_createUnicodeToTextConverter(RTL_TEXTENCODING_MS_1252);
+ static rtl_UnicodeToTextContext aContext =
+ rtl_createUnicodeToTextContext( aConverter );
+
+ sal_Char nAnsiChar;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+ const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR;
+
+ sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ &nUnicodeChar, 1, &nAnsiChar, 1,
+ nCvtFlags, &nCvtInfo, &nCvtChars );
+
+ return nSize == 1 ? (sal_uChar)nAnsiChar : (sal_uChar)0;
+}
+
+sal_uChar
+GlyphSet::GetSymbolMapping (sal_Unicode nUnicodeChar)
+{
+ if (0x0000 < nUnicodeChar && nUnicodeChar < 0x0100)
+ return (sal_uChar)nUnicodeChar;
+ if (0xf000 < nUnicodeChar && nUnicodeChar < 0xf100)
+ return (sal_uChar)nUnicodeChar;
+
+ return 0;
+}
+
+void
+GlyphSet::AddNotdef (char_map_t &rCharMap)
+{
+ if (rCharMap.size() == 0)
+ rCharMap[0] = 0;
+}
+
+void
+GlyphSet::AddNotdef (glyph_map_t &rGlyphMap)
+{
+ if (rGlyphMap.size() == 0)
+ rGlyphMap[0] = 0;
+}
+sal_Bool
+GlyphSet::AddCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ sal_uChar nMappedChar;
+
+ // XXX important: avoid to reencode type1 symbol fonts
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ nMappedChar = GetSymbolMapping (nChar);
+ else
+ nMappedChar = GetAnsiMapping (nChar);
+
+ // create an empty glyphmap that is reserved for iso1252 encoded glyphs
+ // (or -- unencoded -- symbol glyphs) and a second map that takes any other
+ if (maCharList.empty())
+ {
+ char_map_t aMap, aMapp;
+
+ maCharList.push_back (aMap);
+ maCharList.push_back (aMapp);
+ }
+ // if the last map is full, create a new one
+ if ((!nMappedChar) && (maCharList.back().size() == 255))
+ {
+ char_map_t aMap;
+ maCharList.push_back (aMap);
+ }
+
+ // insert a new glyph in the font subset
+ if (nMappedChar)
+ {
+ // always put iso1252 chars into the first map, map them on itself
+ char_map_t& aGlyphSet = maCharList.front();
+ AddNotdef (aGlyphSet);
+
+ aGlyphSet [nChar] = nMappedChar;
+ *nOutGlyphSetID = 1;
+ *nOutGlyphID = nMappedChar;
+ }
+ else
+ {
+ // other chars are just appended to the list
+ char_map_t& aGlyphSet = maCharList.back();
+ AddNotdef (aGlyphSet);
+
+ int nSize = aGlyphSet.size();
+
+ aGlyphSet [nChar] = nSize;
+ *nOutGlyphSetID = maCharList.size();
+ *nOutGlyphID = aGlyphSet [nChar];
+ }
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::AddGlyphID (
+ sal_uInt32 nGlyph,
+ sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ sal_uChar nMappedChar;
+
+ // XXX important: avoid to reencode type1 symbol fonts
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ nMappedChar = GetSymbolMapping (nUnicode);
+ else
+ nMappedChar = GetAnsiMapping (nUnicode);
+
+ // create an empty glyphmap that is reserved for iso1252 encoded glyphs
+ // (or -- unencoded -- symbol glyphs) and a second map that takes any other
+ if (maGlyphList.empty())
+ {
+ glyph_map_t aMap, aMapp;
+
+ maGlyphList.push_back (aMap);
+ maGlyphList.push_back (aMapp);
+ }
+ // if the last map is full, create a new one
+ if ((!nMappedChar) && (maGlyphList.back().size() == 255))
+ {
+ glyph_map_t aMap;
+ maGlyphList.push_back (aMap);
+ }
+
+ // insert a new glyph in the font subset
+ if (nMappedChar)
+ {
+ // always put iso1252 chars into the first map, map them on itself
+ glyph_map_t& aGlyphSet = maGlyphList.front();
+ AddNotdef (aGlyphSet);
+
+ aGlyphSet [nGlyph] = nMappedChar;
+ *nOutGlyphSetID = 1;
+ *nOutGlyphID = nMappedChar;
+ }
+ else
+ {
+ // other chars are just appended to the list
+ glyph_map_t& aGlyphSet = maGlyphList.back();
+ AddNotdef (aGlyphSet);
+
+ int nSize = aGlyphSet.size();
+
+ aGlyphSet [nGlyph] = nSize;
+ *nOutGlyphSetID = maGlyphList.size();
+ *nOutGlyphID = aGlyphSet [nGlyph];
+ }
+
+ return sal_True;
+}
+
+OString
+GlyphSet::GetCharSetName (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ {
+ OStringBuffer aSetName( maBaseName.getLength() + 32 );
+ aSetName.append( maBaseName );
+ aSetName.append( "FID" );
+ aSetName.append( mnFontID );
+ aSetName.append( mbVertical ? "VCSet" : "HCSet" );
+ aSetName.append( nGlyphSetID );
+ return aSetName.makeStringAndClear();
+ }
+ else
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ {
+ return maBaseName;
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetName (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ {
+ OStringBuffer aSetName( maBaseName.getLength() + 32 );
+ aSetName.append( maBaseName );
+ aSetName.append( "FID" );
+ aSetName.append( mnFontID );
+ aSetName.append( mbVertical ? "VGSet" : "HGSet" );
+ aSetName.append( nGlyphSetID );
+ return aSetName.makeStringAndClear();
+ }
+ else
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ {
+ return maBaseName;
+ }
+}
+
+sal_Int32
+GlyphSet::GetGlyphSetEncoding (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ return RTL_TEXTENCODING_DONTKNOW;
+ else
+ {
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ return RTL_TEXTENCODING_SYMBOL;
+ else
+ return nGlyphSetID == 1 ? RTL_TEXTENCODING_MS_1252
+ : RTL_TEXTENCODING_USER_START + nGlyphSetID;
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetEncodingName (rtl_TextEncoding nEnc, const OString &rFontName)
+{
+ if ( nEnc == RTL_TEXTENCODING_MS_1252
+ || nEnc == RTL_TEXTENCODING_ISO_8859_1)
+ {
+ return OString("ISO1252Encoding");
+ }
+ else
+ if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
+ {
+ return rFontName
+ + OString("Enc")
+ + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START));
+ }
+ else
+ {
+ return OString();
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetEncodingName (sal_Int32 nGlyphSetID)
+{
+ return GetGlyphSetEncodingName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
+}
+
+void
+GlyphSet::PSDefineReencodedFont (osl::File* pOutFile, sal_Int32 nGlyphSetID)
+{
+ // only for ps fonts
+ if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1))
+ return;
+
+ sal_Char pEncodingVector [256];
+ sal_Int32 nSize = 0;
+
+ nSize += psp::appendStr ("(", pEncodingVector + nSize);
+ nSize += psp::appendStr (GetReencodedFontName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (") cvn (", pEncodingVector + nSize);
+ nSize += psp::appendStr (maBaseName.getStr(),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (") cvn ", pEncodingVector + nSize);
+ nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (" psp_definefont\n",
+ pEncodingVector + nSize);
+
+ psp::WritePS (pOutFile, pEncodingVector);
+}
+
+OString
+GlyphSet::GetReencodedFontName (rtl_TextEncoding nEnc, const OString &rFontName)
+{
+ if ( nEnc == RTL_TEXTENCODING_MS_1252
+ || nEnc == RTL_TEXTENCODING_ISO_8859_1)
+ {
+ return rFontName
+ + OString("-iso1252");
+ }
+ else
+ if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
+ {
+ return rFontName
+ + OString("-enc")
+ + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START));
+ }
+ else
+ {
+ return OString();
+ }
+}
+
+OString
+GlyphSet::GetReencodedFontName (sal_Int32 nGlyphSetID)
+{
+ return GetReencodedFontName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
+}
+
+void GlyphSet::DrawGlyphs(
+ PrinterGfx& rGfx,
+ const Point& rPoint,
+ const sal_uInt32* pGlyphIds,
+ const sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray )
+{
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ std::set< sal_Int32 > aGlyphSet;
+
+ // convert unicode to font glyph id and font subset
+ for (int nChar = 0; nChar < nLen; nChar++)
+ {
+ GetGlyphID (pGlyphIds[nChar], pUnicodes[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+ aGlyphSet.insert (pGlyphSetID[nChar]);
+ }
+
+ // loop over all glyph sets to detect substrings that can be xshown together
+ // without changing the postscript font
+ sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+
+ std::set< sal_Int32 >::iterator aSet;
+ for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
+ {
+ Point aPoint = rPoint;
+ sal_Int32 nOffset = 0;
+ sal_Int32 nGlyphs = 0;
+ sal_Int32 nChar;
+
+ // get offset to first glyph
+ for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
+ {
+ nOffset = pDeltaArray [nChar];
+ }
+
+ // loop over all chars to extract those that share the current glyph set
+ for (nChar = 0; nChar < nLen; nChar++)
+ {
+ if (pGlyphSetID[nChar] == *aSet)
+ {
+ pGlyphSubset [nGlyphs] = pGlyphID [nChar];
+ // the offset to the next glyph is determined by the glyph in
+ // front of the next glyph with the same glyphset id
+ // most often, this will be the current glyph
+ while ((nChar + 1) < nLen)
+ {
+ if (pGlyphSetID[nChar + 1] == *aSet)
+ break;
+ else
+ nChar += 1;
+ }
+ pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
+
+ nGlyphs += 1;
+ }
+ }
+
+ // show the text using the PrinterGfx text api
+ aPoint.Move (nOffset, 0);
+
+ OString aGlyphSetName(GetGlyphSetName(*aSet));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
+ rGfx.PSMoveTo (aPoint);
+ rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
+ }
+}
+
+void
+GlyphSet::DrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // dispatch to the impl method
+ if (pDeltaArray == NULL)
+ ImplDrawText (rGfx, rPoint, pStr, nLen);
+ else
+ ImplDrawText (rGfx, rPoint, pStr, nLen, pDeltaArray);
+}
+
+void
+GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen)
+{
+ rGfx.PSMoveTo (rPoint);
+
+ if( mbUseFontEncoding )
+ {
+ OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
+ rGfx.PSSetFont( aPSName, mnBaseEncoding );
+ rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength() );
+ return;
+ }
+
+ int nChar;
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+
+ // convert unicode to glyph id and char set (font subset)
+ for (nChar = 0; nChar < nLen; nChar++)
+ GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+
+ // loop over the string to draw subsequent pieces of chars
+ // with the same postscript font
+ for (nChar = 0; nChar < nLen; /* atend */)
+ {
+ sal_Int32 nGlyphSetID = pGlyphSetID [nChar];
+ sal_Int32 nGlyphs = 1;
+ for (int nNextChar = nChar + 1; nNextChar < nLen; nNextChar++)
+ {
+ if (pGlyphSetID[nNextChar] == nGlyphSetID)
+ nGlyphs++;
+ else
+ break;
+ }
+
+ // show the text using the PrinterGfx text api
+ OString aGlyphSetName(GetCharSetName(nGlyphSetID));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(nGlyphSetID));
+ rGfx.PSShowText (pGlyphID + nChar, nGlyphs, nGlyphs);
+
+ nChar += nGlyphs;
+ }
+}
+
+void
+GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ if( mbUseFontEncoding )
+ {
+ OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
+ rGfx.PSMoveTo( rPoint );
+ rGfx.PSSetFont( aPSName, mnBaseEncoding );
+ rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength(), pDeltaArray );
+ return;
+ }
+
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ std::set< sal_Int32 > aGlyphSet;
+
+ // convert unicode to font glyph id and font subset
+ for (int nChar = 0; nChar < nLen; nChar++)
+ {
+ GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+ aGlyphSet.insert (pGlyphSetID[nChar]);
+ }
+
+ // loop over all glyph sets to detect substrings that can be xshown together
+ // without changing the postscript font
+ sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+
+ std::set< sal_Int32 >::iterator aSet;
+ for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
+ {
+ Point aPoint = rPoint;
+ sal_Int32 nOffset = 0;
+ sal_Int32 nGlyphs = 0;
+ sal_Int32 nChar;
+
+ // get offset to first glyph
+ for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
+ {
+ nOffset = pDeltaArray [nChar];
+ }
+
+ // loop over all chars to extract those that share the current glyph set
+ for (nChar = 0; nChar < nLen; nChar++)
+ {
+ if (pGlyphSetID[nChar] == *aSet)
+ {
+ pGlyphSubset [nGlyphs] = pGlyphID [nChar];
+ // the offset to the next glyph is determined by the glyph in
+ // front of the next glyph with the same glyphset id
+ // most often, this will be the current glyph
+ while ((nChar + 1) < nLen)
+ {
+ if (pGlyphSetID[nChar + 1] == *aSet)
+ break;
+ else
+ nChar += 1;
+ }
+ pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
+
+ nGlyphs += 1;
+ }
+ }
+
+ // show the text using the PrinterGfx text api
+ aPoint.Move (nOffset, 0);
+
+ OString aGlyphSetName(GetCharSetName(*aSet));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
+ rGfx.PSMoveTo (aPoint);
+ rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
+ }
+}
+
+sal_Bool
+GlyphSet::PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx)
+{
+ // only for ps fonts
+ if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1))
+ return sal_False;
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ return sal_False;
+
+ PrintFontManager &rMgr = rGfx.GetFontMgr();
+
+ // loop thru all the font subsets
+ sal_Int32 nGlyphSetID = 0;
+ char_list_t::iterator aGlyphSet;
+ for (aGlyphSet = maCharList.begin(); aGlyphSet != maCharList.end(); aGlyphSet++)
+ {
+ ++nGlyphSetID;
+
+ if (nGlyphSetID == 1) // latin1 page uses global reencoding table
+ {
+ PSDefineReencodedFont (pOutFile, nGlyphSetID);
+ continue;
+ }
+ if ((*aGlyphSet).size() == 0) // empty set, doesn't need reencoding
+ {
+ continue;
+ }
+
+ // create reencoding table
+
+ sal_Char pEncodingVector [256];
+ sal_Int32 nSize = 0;
+
+ nSize += psp::appendStr ("/",
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (" [ ",
+ pEncodingVector + nSize);
+
+ // need a list of glyphs, sorted by glyphid
+ typedef std::map< sal_uInt8, sal_Unicode > ps_mapping_t;
+ typedef ps_mapping_t::value_type ps_value_t;
+ ps_mapping_t aSortedGlyphSet;
+
+ char_map_t::const_iterator aUnsortedGlyph;
+ for (aUnsortedGlyph = (*aGlyphSet).begin();
+ aUnsortedGlyph != (*aGlyphSet).end();
+ ++aUnsortedGlyph)
+ {
+ aSortedGlyphSet.insert(ps_value_t((*aUnsortedGlyph).second,
+ (*aUnsortedGlyph).first));
+ }
+
+ ps_mapping_t::const_iterator aSortedGlyph;
+ // loop thru all the glyphs in the subset
+ for (aSortedGlyph = (aSortedGlyphSet).begin();
+ aSortedGlyph != (aSortedGlyphSet).end();
+ ++aSortedGlyph)
+ {
+ nSize += psp::appendStr ("/",
+ pEncodingVector + nSize);
+
+ std::list< OString > aName( rMgr.getAdobeNameFromUnicode((*aSortedGlyph).second) );
+
+ if( aName.begin() != aName.end() )
+ nSize += psp::appendStr ( aName.front(), pEncodingVector + nSize);
+ else
+ nSize += psp::appendStr (".notdef", pEncodingVector + nSize );
+ nSize += psp::appendStr (" ", pEncodingVector + nSize);
+ // flush line
+ if (nSize >= 70)
+ {
+ nSize += psp::appendStr ("\n", pEncodingVector + nSize);
+ psp::WritePS (pOutFile, pEncodingVector);
+ nSize = 0;
+ }
+ }
+
+ nSize += psp::appendStr ("] def\n", pEncodingVector + nSize);
+ psp::WritePS (pOutFile, pEncodingVector);
+
+ PSDefineReencodedFont (pOutFile, nGlyphSetID);
+ }
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAsType42, std::list< OString >& rSuppliedFonts )
+{
+ // only for truetype fonts
+ if (meBaseType != fonttype::TrueType)
+ return sal_False;
+
+ TrueTypeFont *pTTFont;
+ OString aTTFileName (rGfx.GetFontMgr().getFontFileSysPath(mnFontID));
+ int nFace = rGfx.GetFontMgr().getFontFaceNumber(mnFontID);
+ sal_Int32 nSuccess = OpenTTFontFile(aTTFileName.getStr(), nFace < 0 ? 0 : nFace, &pTTFont);
+ if (nSuccess != SF_OK)
+ return sal_False;
+ FILE* pTmpFile = tmpfile();
+ if (pTmpFile == NULL)
+ return sal_False;
+
+ // array of unicode source characters
+ sal_Unicode pUChars[256];
+
+ // encoding vector maps character encoding to the ordinal number
+ // of the glyph in the output file
+ sal_uChar pEncoding[256];
+ sal_uInt16 pTTGlyphMapping[256];
+
+ // loop thru all the font subsets
+ sal_Int32 nCharSetID;
+ char_list_t::iterator aCharSet;
+ for (aCharSet = maCharList.begin(), nCharSetID = 1;
+ aCharSet != maCharList.end();
+ ++aCharSet, nCharSetID++)
+ {
+ if ((*aCharSet).size() == 0)
+ continue;
+
+ // loop thru all the chars in the subset
+ char_map_t::const_iterator aChar;
+ sal_Int32 n = 0;
+ for (aChar = (*aCharSet).begin(); aChar != (*aCharSet).end(); aChar++)
+ {
+ pUChars [n] = (*aChar).first;
+ pEncoding [n] = (*aChar).second;
+ n++;
+ }
+ // create a mapping from the unicode chars to the char encoding in
+ // source TrueType font
+ MapString (pTTFont, pUChars, (*aCharSet).size(), pTTGlyphMapping, mbVertical);
+
+ // create the current subset
+ OString aCharSetName = GetCharSetName(nCharSetID);
+ fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aCharSetName.getStr() );
+ if( bAsType42 )
+ CreateT42FromTTGlyphs (pTTFont, pTmpFile, aCharSetName.getStr(),
+ pTTGlyphMapping, pEncoding, (*aCharSet).size() );
+ else
+ CreateT3FromTTGlyphs (pTTFont, pTmpFile, aCharSetName.getStr(),
+ pTTGlyphMapping, pEncoding, (*aCharSet).size(),
+ 0 /* 0 = horizontal, 1 = vertical */ );
+ fprintf( pTmpFile, "%%%%EndResource\n" );
+ rSuppliedFonts.push_back( aCharSetName );
+ }
+
+ // loop thru all the font glyph subsets
+ sal_Int32 nGlyphSetID;
+ glyph_list_t::iterator aGlyphSet;
+ for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maGlyphList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ if ((*aGlyphSet).size() == 0)
+ continue;
+
+ // loop thru all the glyphs in the subset
+ glyph_map_t::const_iterator aGlyph;
+ sal_Int32 n = 0;
+ for (aGlyph = (*aGlyphSet).begin(); aGlyph != (*aGlyphSet).end(); aGlyph++)
+ {
+ pTTGlyphMapping [n] = (*aGlyph).first;
+ pEncoding [n] = (*aGlyph).second;
+ n++;
+ }
+
+ // create the current subset
+ OString aGlyphSetName = GetGlyphSetName(nGlyphSetID);
+ fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aGlyphSetName.getStr() );
+ if( bAsType42 )
+ CreateT42FromTTGlyphs (pTTFont, pTmpFile, aGlyphSetName.getStr(),
+ pTTGlyphMapping, pEncoding, (*aGlyphSet).size() );
+ else
+ CreateT3FromTTGlyphs (pTTFont, pTmpFile, aGlyphSetName.getStr(),
+ pTTGlyphMapping, pEncoding, (*aGlyphSet).size(),
+ 0 /* 0 = horizontal, 1 = vertical */ );
+ fprintf( pTmpFile, "%%%%EndResource\n" );
+ rSuppliedFonts.push_back( aGlyphSetName );
+ }
+
+ // copy the file into the page header
+ rewind(pTmpFile);
+ fflush(pTmpFile);
+
+ sal_uChar pBuffer[0x2000];
+ sal_uInt64 nIn;
+ sal_uInt64 nOut;
+ do
+ {
+ nIn = fread(pBuffer, 1, sizeof(pBuffer), pTmpFile);
+ rOutFile.write (pBuffer, nIn, nOut);
+ }
+ while ((nIn == nOut) && !feof(pTmpFile));
+
+ // cleanup
+ CloseTTFont (pTTFont);
+ fclose (pTmpFile);
+
+ return sal_True;
+}
+
+
diff --git a/vcl/unx/source/printergfx/glyphset.hxx b/vcl/unx/source/printergfx/glyphset.hxx
new file mode 100644
index 000000000000..f4cd15a56ae6
--- /dev/null
+++ b/vcl/unx/source/printergfx/glyphset.hxx
@@ -0,0 +1,138 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: glyphset.hxx,v $
+ * $Revision: 1.10 $
+ *
+ * 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 _PSPRINT_GLYPHSET_HXX_
+#define _PSPRINT_GLYPHSET_HXX_
+
+#include "vcl/fontmanager.hxx"
+
+#include "osl/file.hxx"
+
+#include "rtl/string.hxx"
+
+#include "tools/gen.hxx"
+
+#include <list>
+#include <hash_map>
+
+namespace psp {
+
+class PrinterGfx;
+class PrintFontManager;
+
+class GlyphSet
+{
+private:
+
+ sal_Int32 mnFontID;
+ sal_Bool mbVertical;
+ rtl::OString maBaseName;
+ fonttype::type meBaseType;
+ rtl_TextEncoding mnBaseEncoding;
+ bool mbUseFontEncoding;
+
+ typedef std::hash_map< sal_Unicode, sal_uInt8 > char_map_t;
+ typedef std::list< char_map_t > char_list_t;
+ typedef std::hash_map< sal_uInt32, sal_uInt8 > glyph_map_t;
+ typedef std::list< glyph_map_t > glyph_list_t;
+
+ char_list_t maCharList;
+ glyph_list_t maGlyphList;
+
+ rtl::OString GetGlyphSetName (sal_Int32 nGlyphSetID);
+ rtl::OString GetCharSetName (sal_Int32 nGlyphSetID);
+ sal_Int32 GetGlyphSetEncoding (sal_Int32 nGlyphSetID);
+ rtl::OString GetGlyphSetEncodingName (sal_Int32 nGlyphSetID);
+
+ rtl::OString GetReencodedFontName (sal_Int32 nGlyphSetID);
+ void PSDefineReencodedFont (osl::File* pOutFile,
+ sal_Int32 nGlyphSetID);
+
+ sal_Bool GetCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool LookupCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool AddCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID);
+ sal_Bool GetGlyphID (sal_uInt32 nGlyph, sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool LookupGlyphID (sal_uInt32 nGlyph,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool AddGlyphID (sal_uInt32 nGlyph, sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID);
+ void AddNotdef (char_map_t &rCharMap);
+ void AddNotdef (glyph_map_t &rGlyphMap);
+ sal_uChar GetAnsiMapping (sal_Unicode nUnicodeChar);
+ sal_uChar GetSymbolMapping (sal_Unicode nUnicodeChar);
+
+ void ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen);
+ void ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray);
+
+public:
+
+ GlyphSet ();
+ GlyphSet (sal_Int32 nFontID, sal_Bool bVertical);
+ ~GlyphSet ();
+
+ sal_Int32 GetFontID ();
+ fonttype::type GetFontType ();
+ static rtl::OString
+ GetReencodedFontName (rtl_TextEncoding nEnc,
+ const rtl::OString &rFontName);
+ static rtl::OString
+ GetGlyphSetEncodingName (rtl_TextEncoding nEnc,
+ const rtl::OString &rFontName);
+ sal_Bool IsVertical ();
+
+ sal_Bool SetFont (sal_Int32 nFontID, sal_Bool bVertical);
+
+ void DrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray = NULL);
+ void DrawGlyphs (PrinterGfx& rGfx,
+ const Point& rPoint,
+ const sal_uInt32* pGlyphIds,
+ const sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray );
+ sal_Bool PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx);
+ sal_Bool PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAsType42, std::list< rtl::OString >& rSuppliedFonts );
+};
+
+
+} /* namespace psp */
+
+#endif
+
diff --git a/vcl/unx/source/printergfx/makefile.mk b/vcl/unx/source/printergfx/makefile.mk
new file mode 100644
index 000000000000..6de3e9bfe3bb
--- /dev/null
+++ b/vcl/unx/source/printergfx/makefile.mk
@@ -0,0 +1,69 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.8 $
+#
+# 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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=printergfx
+
+# --- Settings -----------------------------------------------------
+
+ENABLE_EXCEPTIONS=true
+
+.INCLUDE : settings.mk
+
+.IF "$(ENABLE_CUPS)" != ""
+CDEFS += -DENABLE_CUPS
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"=="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"=="aqua"
+
+SLOFILES=\
+ $(SLO)$/printerjob.obj \
+ $(SLO)$/text_gfx.obj \
+ $(SLO)$/psputil.obj \
+ $(SLO)$/common_gfx.obj \
+ $(SLO)$/glyphset.obj \
+ $(SLO)$/bitmap_gfx.obj
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/unx/source/printergfx/printerjob.cxx b/vcl/unx/source/printergfx/printerjob.cxx
new file mode 100644
index 000000000000..783dd5ff2b47
--- /dev/null
+++ b/vcl/unx/source/printergfx/printerjob.cxx
@@ -0,0 +1,1197 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: printerjob.cxx,v $
+ * $Revision: 1.47 $
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "vcl/printerjob.hxx"
+#include "vcl/ppdparser.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/printergfx.hxx"
+
+#include "rtl/ustring.hxx"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+
+#include "osl/thread.h"
+#include "sal/alloca.h"
+
+#include <algorithm>
+#include <vector>
+
+using namespace psp;
+using namespace rtl;
+
+// forward declaration
+
+#define nBLOCKSIZE 0x2000
+
+namespace psp
+{
+
+sal_Bool
+AppendPS (FILE* pDst, osl::File* pSrc, sal_uChar* pBuffer,
+ sal_uInt32 nBlockSize = nBLOCKSIZE)
+{
+ if ((pDst == NULL) || (pSrc == NULL))
+ return sal_False;
+
+ if (nBlockSize == 0)
+ nBlockSize = nBLOCKSIZE;
+ if (pBuffer == NULL)
+ pBuffer = (sal_uChar*)alloca (nBlockSize);
+
+ pSrc->setPos (osl_Pos_Absolut, 0);
+
+ sal_uInt64 nIn = 0;
+ sal_uInt64 nOut = 0;
+ do
+ {
+ pSrc->read (pBuffer, nBlockSize, nIn);
+ if (nIn > 0)
+ nOut = fwrite (pBuffer, 1, sal::static_int_cast<sal_uInt32>(nIn), pDst);
+ }
+ while ((nIn > 0) && (nIn == nOut));
+
+ return sal_True;
+}
+
+} // namespace psp
+
+/*
+ * private convenience routines for file handling
+ */
+
+osl::File*
+PrinterJob::CreateSpoolFile (const rtl::OUString& rName, const rtl::OUString& rExtension)
+{
+ osl::File::RC nError = osl::File::E_None;
+ osl::File* pFile = NULL;
+
+ rtl::OUString aFile = rName + rExtension;
+ rtl::OUString aFileURL;
+ nError = osl::File::getFileURLFromSystemPath( aFile, aFileURL );
+ if (nError != osl::File::E_None)
+ return NULL;
+ aFileURL = maSpoolDirName + rtl::OUString::createFromAscii ("/") + aFileURL;
+
+ pFile = new osl::File (aFileURL);
+ nError = pFile->open (OpenFlag_Read | OpenFlag_Write | OpenFlag_Create);
+ if (nError != osl::File::E_None)
+ {
+ delete pFile;
+ return NULL;
+ }
+
+ pFile->setAttributes (aFileURL,
+ osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnRead);
+ return pFile;
+}
+
+/*
+ * public methods of PrinterJob: for use in PrinterGfx
+ */
+
+void
+PrinterJob::GetScale (double &rXScale, double &rYScale) const
+{
+ rXScale = mfXScale;
+ rYScale = mfYScale;
+}
+
+sal_uInt16
+PrinterJob::GetDepth () const
+{
+ sal_Int32 nLevel = GetPostscriptLevel();
+ sal_Bool bColor = IsColorPrinter ();
+
+ return nLevel > 1 && bColor ? 24 : 8;
+}
+
+sal_uInt16
+PrinterJob::GetPostscriptLevel (const JobData *pJobData) const
+{
+ sal_uInt16 nPSLevel = 2;
+
+ if( pJobData == NULL )
+ pJobData = &m_aLastJobData;
+
+ if( pJobData->m_nPSLevel )
+ nPSLevel = pJobData->m_nPSLevel;
+ else
+ if( pJobData->m_pParser )
+ nPSLevel = pJobData->m_pParser->getLanguageLevel();
+
+ return nPSLevel;
+}
+
+sal_Bool
+PrinterJob::IsColorPrinter () const
+{
+ sal_Bool bColor = sal_False;
+
+ if( m_aLastJobData.m_nColorDevice )
+ bColor = m_aLastJobData.m_nColorDevice == -1 ? sal_False : sal_True;
+ else if( m_aLastJobData.m_pParser )
+ bColor = m_aLastJobData.m_pParser->isColorDevice() ? sal_True : sal_False;
+
+ return bColor;
+}
+
+osl::File*
+PrinterJob::GetDocumentHeader ()
+{
+ return mpJobHeader;
+}
+
+osl::File*
+PrinterJob::GetDocumentTrailer ()
+{
+ return mpJobTrailer;
+}
+
+osl::File*
+PrinterJob::GetCurrentPageHeader ()
+{
+ return maHeaderList.back();
+}
+
+osl::File*
+PrinterJob::GetCurrentPageBody ()
+{
+ return maPageList.back();
+}
+
+/*
+ * public methods of PrinterJob: the actual job / spool handling
+ */
+
+PrinterJob::PrinterJob () :
+ mpJobHeader( NULL ),
+ mpJobTrailer( NULL ),
+ m_bQuickJob( false )
+{
+}
+
+namespace psp
+{
+
+/* check whether the given name points to a directory which is
+ usable for the user */
+sal_Bool
+existsTmpDir (const char* pName)
+{
+ struct stat aFileStatus;
+
+ if (pName == NULL)
+ return sal_False;
+ if (stat(pName, &aFileStatus) != 0)
+ return sal_False;
+ if (! S_ISDIR(aFileStatus.st_mode))
+ return sal_False;
+
+ return access(pName, W_OK | R_OK) == 0 ? sal_True : sal_False;
+}
+
+/* return the username in the given buffer */
+sal_Bool
+getUserName (char* pName, int nSize)
+{
+ struct passwd *pPWEntry;
+ struct passwd aPWEntry;
+ sal_Char pPWBuffer[256];
+
+ sal_Bool bSuccess = sal_False;
+
+#ifdef FREEBSD
+ pPWEntry = getpwuid( getuid());
+#else
+ if (getpwuid_r(getuid(), &aPWEntry, pPWBuffer, sizeof(pPWBuffer), &pPWEntry) != 0)
+ pPWEntry = NULL;
+#endif
+
+ if (pPWEntry != NULL && pPWEntry->pw_name != NULL)
+ {
+ sal_Int32 nLen = strlen(pPWEntry->pw_name);
+ if (nLen > 0 && nLen < nSize)
+ {
+ memcpy (pName, pPWEntry->pw_name, nLen);
+ pName[nLen] = '\0';
+
+ bSuccess = sal_True;
+ }
+ }
+
+ // wipe the passwd off the stack
+ memset (pPWBuffer, 0, sizeof(pPWBuffer));
+
+ return bSuccess;
+}
+
+/* remove all our temporary files, uses external program "rm", since
+ osl functionality is inadequate */
+void
+removeSpoolDir (const rtl::OUString& rSpoolDir)
+{
+ rtl::OUString aSysPath;
+ if( osl::File::E_None != osl::File::getSystemPathFromFileURL( rSpoolDir, aSysPath ) )
+ {
+ // Conversion did not work, as this is quite a dangerous action,
+ // we should abort here ....
+ OSL_ENSURE( 0, "psprint: couldn't remove spool directory" );
+ return;
+ }
+ rtl::OString aSysPathByte =
+ rtl::OUStringToOString (aSysPath, osl_getThreadTextEncoding());
+ sal_Char pSystem [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("rm -rf ", pSystem);
+ nChar += psp::appendStr (aSysPathByte.getStr(), pSystem + nChar);
+
+ system (pSystem);
+}
+
+/* creates a spool directory with a "pidgin random" value based on
+ current system time */
+rtl::OUString
+createSpoolDir ()
+{
+ TimeValue aCur;
+ osl_getSystemTime( &aCur );
+ sal_Int32 nRand = aCur.Seconds ^ (aCur.Nanosec/1000);
+
+ rtl::OUString aTmpDir;
+ osl_getTempDirURL( &aTmpDir.pData );
+
+ do
+ {
+ rtl::OUStringBuffer aDir( aTmpDir.getLength() + 16 );
+ aDir.append( aTmpDir );
+ aDir.appendAscii( "/psp" );
+ aDir.append(nRand);
+ rtl::OUString aResult = aDir.makeStringAndClear();
+ if( osl::Directory::create( aResult ) == osl::FileBase::E_None )
+ {
+ osl::File::setAttributes( aResult,
+ osl_File_Attribute_OwnWrite
+ | osl_File_Attribute_OwnRead
+ | osl_File_Attribute_OwnExe );
+ return aResult;
+ }
+ nRand++;
+ } while( nRand );
+ return rtl::OUString();
+}
+
+} // namespace psp
+
+PrinterJob::~PrinterJob ()
+{
+ std::list< osl::File* >::iterator pPage;
+ for (pPage = maPageList.begin(); pPage != maPageList.end(); pPage++)
+ {
+ //(*pPage)->remove();
+ delete *pPage;
+ }
+ for (pPage = maHeaderList.begin(); pPage != maHeaderList.end(); pPage++)
+ {
+ //(*pPage)->remove();
+ delete *pPage;
+ }
+ // mpJobHeader->remove();
+ delete mpJobHeader;
+ // mpJobTrailer->remove();
+ delete mpJobTrailer;
+
+ // XXX should really call osl::remove routines
+ removeSpoolDir (maSpoolDirName);
+
+ // osl::Directory::remove (maSpoolDirName);
+}
+
+namespace psp
+{
+
+// get locale invariant, 7bit clean current local time string
+sal_Char*
+getLocalTime(sal_Char* pBuffer)
+{
+ time_t nTime = time (NULL);
+ struct tm aTime;
+ struct tm *pLocalTime = localtime_r (&nTime, &aTime);
+
+ return asctime_r(pLocalTime, pBuffer);
+}
+
+}
+
+static bool isAscii( const rtl::OUString& rStr )
+{
+ const sal_Unicode* pStr = rStr;
+ sal_Int32 nLen = rStr.getLength();
+ for( sal_Int32 i = 0; i < nLen; i++ )
+ if( pStr[i] > 127 )
+ return false;
+ return true;
+}
+
+sal_Bool
+PrinterJob::StartJob (
+ const rtl::OUString& rFileName,
+ int nMode,
+ const rtl::OUString& rJobName,
+ const rtl::OUString& rAppName,
+ const JobData& rSetupData,
+ PrinterGfx* pGraphics,
+ bool bIsQuickJob
+ )
+{
+ m_bQuickJob = bIsQuickJob;
+ mnMaxWidthPt = mnMaxHeightPt = 0;
+ mnLandscapes = mnPortraits = 0;
+ m_pGraphics = pGraphics;
+ InitPaperSize (rSetupData);
+
+ // create file container for document header and trailer
+ maFileName = rFileName;
+ mnFileMode = nMode;
+ maSpoolDirName = createSpoolDir ();
+ maJobTitle = rJobName;
+
+ rtl::OUString aExt = rtl::OUString::createFromAscii (".ps");
+ mpJobHeader = CreateSpoolFile (rtl::OUString::createFromAscii("psp_head"), aExt);
+ mpJobTrailer = CreateSpoolFile (rtl::OUString::createFromAscii("psp_tail"), aExt);
+ if( ! (mpJobHeader && mpJobTrailer) ) // existing files are removed in destructor
+ return sal_False;
+
+ // write document header according to Document Structuring Conventions (DSC)
+ WritePS (mpJobHeader,
+ "%!PS-Adobe-3.0\n"
+ "%%BoundingBox: (atend)\n" );
+
+ rtl::OUString aFilterWS;
+
+ // Creator (this application)
+ aFilterWS = WhitespaceToSpace( rAppName, FALSE );
+ WritePS (mpJobHeader, "%%Creator: (");
+ WritePS (mpJobHeader, aFilterWS);
+ WritePS (mpJobHeader, ")\n");
+
+ // For (user name)
+ sal_Char pUserName[64];
+ if (getUserName(pUserName, sizeof(pUserName)))
+ {
+ WritePS (mpJobHeader, "%%For: (");
+ WritePS (mpJobHeader, pUserName);
+ WritePS (mpJobHeader, ")\n");
+ }
+
+ // Creation Date (locale independent local time)
+ sal_Char pCreationDate [256];
+ WritePS (mpJobHeader, "%%CreationDate: (");
+ getLocalTime(pCreationDate);
+ for( unsigned int i = 0; i < sizeof(pCreationDate)/sizeof(pCreationDate[0]); i++ )
+ {
+ if( pCreationDate[i] == '\n' )
+ {
+ pCreationDate[i] = 0;
+ break;
+ }
+ }
+ WritePS (mpJobHeader, pCreationDate );
+ WritePS (mpJobHeader, ")\n");
+
+ // Document Title
+ /* #i74335#
+ * The title should be clean ascii; rJobName however may
+ * contain any Unicode character. So implement the following
+ * algorithm:
+ * use rJobName, if it contains only ascii
+ * use the filename, if it contains only ascii
+ * else omit %%Title
+ */
+ aFilterWS = WhitespaceToSpace( rJobName, FALSE );
+ rtl::OUString aTitle( aFilterWS );
+ if( ! isAscii( aTitle ) )
+ {
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ aTitle = rFileName.getToken( 0, '/', nIndex );
+ aTitle = WhitespaceToSpace( aTitle, FALSE );
+ if( ! isAscii( aTitle ) )
+ aTitle = rtl::OUString();
+ }
+
+ maJobTitle = aFilterWS;
+ if( aTitle.getLength() )
+ {
+ WritePS (mpJobHeader, "%%Title: (");
+ WritePS (mpJobHeader, aTitle);
+ WritePS (mpJobHeader, ")\n");
+ }
+
+ // Language Level
+ sal_Char pLevel[16];
+ sal_Int32 nSz = getValueOf(GetPostscriptLevel(&rSetupData), pLevel);
+ pLevel[nSz++] = '\n';
+ pLevel[nSz ] = '\0';
+ WritePS (mpJobHeader, "%%LanguageLevel: ");
+ WritePS (mpJobHeader, pLevel);
+
+ // Other
+ WritePS (mpJobHeader, "%%DocumentData: Clean7Bit\n");
+ WritePS (mpJobHeader, "%%Pages: (atend)\n");
+ WritePS (mpJobHeader, "%%Orientation: (atend)\n");
+ WritePS (mpJobHeader, "%%PageOrder: Ascend\n");
+ WritePS (mpJobHeader, "%%EndComments\n");
+
+ // write Prolog
+ writeProlog (mpJobHeader, rSetupData);
+
+ // mark last job setup as not set
+ m_aLastJobData.m_pParser = NULL;
+ m_aLastJobData.m_aContext.setParser( NULL );
+
+ return sal_True;
+}
+
+sal_Bool
+PrinterJob::EndJob ()
+{
+ // write document setup (done here because it
+ // includes the accumulated fonts
+ if( mpJobHeader )
+ writeSetup( mpJobHeader, m_aDocumentJobData );
+ m_pGraphics->OnEndJob();
+ if( ! (mpJobHeader && mpJobTrailer) )
+ return sal_False;
+
+ // write document trailer according to Document Structuring Conventions (DSC)
+ rtl::OStringBuffer aTrailer(512);
+ aTrailer.append( "%%Trailer\n" );
+ aTrailer.append( "%%BoundingBox: 0 0 " );
+ aTrailer.append( (sal_Int32)mnMaxWidthPt );
+ aTrailer.append( " " );
+ aTrailer.append( (sal_Int32)mnMaxHeightPt );
+ if( mnLandscapes > mnPortraits )
+ aTrailer.append("\n%%Orientation: Landscape");
+ else
+ aTrailer.append("\n%%Orientation: Portrait");
+ aTrailer.append( "\n%%Pages: " );
+ aTrailer.append( (sal_Int32)maPageList.size() );
+ aTrailer.append( "\n%%EOF\n" );
+ WritePS (mpJobTrailer, aTrailer.getStr());
+
+ /*
+ * spool the set of files to their final destination, this is U**X dependent
+ */
+
+ FILE* pDestFILE = NULL;
+
+ /* create a destination either as file or as a pipe */
+ sal_Bool bSpoolToFile = maFileName.getLength() > 0 ? sal_True : sal_False;
+ if (bSpoolToFile)
+ {
+ const rtl::OString aFileName = rtl::OUStringToOString (maFileName,
+ osl_getThreadTextEncoding());
+ if( mnFileMode )
+ {
+ int nFile = open( aFileName.getStr(), O_CREAT | O_EXCL | O_RDWR, mnFileMode );
+ if( nFile != -1 )
+ {
+ pDestFILE = fdopen( nFile, "w" );
+ if( pDestFILE == NULL )
+ {
+ close( nFile );
+ unlink( aFileName.getStr() );
+ return sal_False;
+ }
+ }
+ else
+ chmod( aFileName.getStr(), mnFileMode );
+ }
+ if (pDestFILE == NULL)
+ pDestFILE = fopen (aFileName.getStr(), "w");
+
+ if (pDestFILE == NULL)
+ return sal_False;
+ }
+ else
+ {
+ PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get ();
+ pDestFILE = rPrinterInfoManager.startSpool( m_aLastJobData.m_aPrinterName, m_bQuickJob );
+ if (pDestFILE == NULL)
+ return sal_False;
+ }
+
+ /* spool the document parts to the destination */
+
+ sal_uChar pBuffer[ nBLOCKSIZE ];
+
+ AppendPS (pDestFILE, mpJobHeader, pBuffer);
+ mpJobHeader->close();
+
+ sal_Bool bSuccess = sal_True;
+ std::list< osl::File* >::iterator pPageBody;
+ std::list< osl::File* >::iterator pPageHead;
+ for (pPageBody = maPageList.begin(), pPageHead = maHeaderList.begin();
+ pPageBody != maPageList.end() && pPageHead != maHeaderList.end();
+ pPageBody++, pPageHead++)
+ {
+ if( *pPageHead )
+ {
+ osl::File::RC nError = (*pPageHead)->open(OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ AppendPS (pDestFILE, *pPageHead, pBuffer);
+ (*pPageHead)->close();
+ }
+ }
+ else
+ bSuccess = sal_False;
+ if( *pPageBody )
+ {
+ osl::File::RC nError = (*pPageBody)->open(OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ AppendPS (pDestFILE, *pPageBody, pBuffer);
+ (*pPageBody)->close();
+ }
+ }
+ else
+ bSuccess = sal_False;
+ }
+
+ AppendPS (pDestFILE, mpJobTrailer, pBuffer);
+ mpJobTrailer->close();
+
+ /* well done */
+
+ if (bSpoolToFile)
+ fclose (pDestFILE);
+ else
+ {
+ PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get();
+ if (0 == rPrinterInfoManager.endSpool( m_aLastJobData.m_aPrinterName,
+ maJobTitle, pDestFILE, m_aDocumentJobData ))
+ {
+ bSuccess = sal_False;
+ }
+ }
+
+ return bSuccess;
+}
+
+sal_Bool
+PrinterJob::AbortJob ()
+{
+ m_pGraphics->OnEndJob();
+ return sal_False;
+}
+
+void
+PrinterJob::InitPaperSize (const JobData& rJobSetup)
+{
+ int nRes = rJobSetup.m_aContext.getRenderResolution ();
+
+ String aPaper;
+ int nWidth, nHeight;
+ rJobSetup.m_aContext.getPageSize (aPaper, nWidth, nHeight);
+
+ int nLeft = 0, nRight = 0, nUpper = 0, nLower = 0;
+ const PPDParser* pParser = rJobSetup.m_aContext.getParser();
+ if (pParser != NULL)
+ pParser->getMargins (aPaper, nLeft, nRight, nUpper, nLower);
+
+ mnResolution = nRes;
+
+ mnWidthPt = nWidth;
+ mnHeightPt = nHeight;
+
+ if( mnWidthPt > mnMaxWidthPt )
+ mnMaxWidthPt = mnWidthPt;
+ if( mnHeightPt > mnMaxHeightPt )
+ mnMaxHeightPt = mnHeightPt;
+
+ mnLMarginPt = nLeft;
+ mnRMarginPt = nRight;
+ mnTMarginPt = nUpper;
+ mnBMarginPt = nLower;
+
+ mfXScale = (double)72.0 / (double)mnResolution;
+ mfYScale = -1.0 * (double)72.0 / (double)mnResolution;
+}
+
+
+sal_Bool
+PrinterJob::StartPage (const JobData& rJobSetup)
+{
+ InitPaperSize (rJobSetup);
+
+ rtl::OUString aPageNo = rtl::OUString::valueOf ((sal_Int32)maPageList.size()+1); // sequential page number must start with 1
+ rtl::OUString aExt = aPageNo + rtl::OUString::createFromAscii (".ps");
+
+ osl::File* pPageHeader = CreateSpoolFile (
+ rtl::OUString::createFromAscii("psp_pghead"), aExt);
+ osl::File* pPageBody = CreateSpoolFile (
+ rtl::OUString::createFromAscii("psp_pgbody"), aExt);
+
+ maHeaderList.push_back (pPageHeader);
+ maPageList.push_back (pPageBody);
+
+ if( ! (pPageHeader && pPageBody) )
+ return sal_False;
+
+ /* #i7262# write setup only before first page
+ * don't do this in StartJob since the jobsetup there may be
+ * different.
+ */
+ bool bSuccess = true;
+ if( 1 == maPageList.size() )
+ m_aDocumentJobData = rJobSetup;
+
+ // write page header according to Document Structuring Conventions (DSC)
+ WritePS (pPageHeader, "%%Page: ");
+ WritePS (pPageHeader, aPageNo);
+ WritePS (pPageHeader, " ");
+ WritePS (pPageHeader, aPageNo);
+ WritePS (pPageHeader, "\n");
+
+ if( rJobSetup.m_eOrientation == orientation::Landscape )
+ {
+ WritePS (pPageHeader, "%%PageOrientation: Landscape\n");
+ mnLandscapes++;
+ }
+ else
+ {
+ WritePS (pPageHeader, "%%PageOrientation: Portrait\n");
+ mnPortraits++;
+ }
+
+ sal_Char pBBox [256];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("%%PageBoundingBox: ", pBBox);
+ nChar += psp::getValueOf (mnLMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnBMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnWidthPt - mnRMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnHeightPt - mnTMarginPt, pBBox + nChar);
+ nChar += psp::appendStr ("\n", pBBox + nChar);
+
+ WritePS (pPageHeader, pBBox);
+
+ if (bSuccess)
+ bSuccess = writePageSetup ( pPageHeader, rJobSetup );
+ if(bSuccess)
+ m_aLastJobData = rJobSetup;
+
+
+ return bSuccess;
+}
+
+sal_Bool
+PrinterJob::EndPage ()
+{
+ m_pGraphics->OnEndPage();
+
+ osl::File* pPageHeader = maHeaderList.back();
+ osl::File* pPageBody = maPageList.back();
+
+ if( ! (pPageBody && pPageHeader) )
+ return sal_False;
+
+ // copy page to paper and write page trailer according to DSC
+
+ sal_Char pTrailer[256];
+ sal_Int32 nChar = 0;
+ nChar = psp::appendStr ("grestore grestore\n", pTrailer);
+ nChar += psp::appendStr ("showpage\n", pTrailer + nChar);
+ nChar += psp::appendStr ("%%PageTrailer\n\n", pTrailer + nChar);
+ WritePS (pPageBody, pTrailer);
+
+ // this page is done for now, close it to avoid having too many open fd's
+
+ pPageHeader->close();
+ pPageBody->close();
+
+ return sal_True;
+}
+
+sal_uInt32
+PrinterJob::GetErrorCode ()
+{
+ /* TODO */
+ return 0;
+}
+
+struct less_ppd_key : public ::std::binary_function<double, double, bool>
+{
+ bool operator()(const PPDKey* left, const PPDKey* right)
+ { return left->getOrderDependency() < right->getOrderDependency(); }
+};
+
+static bool writeFeature( osl::File* pFile, const PPDKey* pKey, const PPDValue* pValue, bool bUseIncluseFeature )
+{
+ if( ! pKey || ! pValue )
+ return true;
+
+ OStringBuffer aFeature(256);
+ aFeature.append( "[{\n" );
+ if( bUseIncluseFeature )
+ aFeature.append( "%%IncludeFeature:" );
+ else
+ aFeature.append( "%%BeginFeature:" );
+ aFeature.append( " *" );
+ aFeature.append( OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US ) );
+ aFeature.append( ' ' );
+ aFeature.append( OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US ) );
+ if( !bUseIncluseFeature )
+ {
+ aFeature.append( '\n' );
+ aFeature.append( OUStringToOString( pValue->m_aValue, RTL_TEXTENCODING_ASCII_US ) );
+ aFeature.append( "\n%%EndFeature" );
+ }
+ aFeature.append( "\n} stopped cleartomark\n" );
+ sal_uInt64 nWritten = 0;
+ return pFile->write( aFeature.getStr(), aFeature.getLength(), nWritten )
+ || nWritten != (sal_uInt64)aFeature.getLength() ? false : true;
+}
+
+bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool bDocumentSetup )
+{
+ bool bSuccess = true;
+ int i;
+
+ // emit features ordered to OrderDependency
+ // ignore features that are set to default
+
+ // sanity check
+ if( rJob.m_pParser == rJob.m_aContext.getParser() &&
+ rJob.m_pParser &&
+ ( m_aLastJobData.m_pParser == rJob.m_pParser || m_aLastJobData.m_pParser == NULL )
+ )
+ {
+ int nKeys = rJob.m_aContext.countValuesModified();
+ ::std::vector< const PPDKey* > aKeys( nKeys );
+ for( i = 0; i < nKeys; i++ )
+ aKeys[i] = rJob.m_aContext.getModifiedKey( i );
+ ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
+
+ for( i = 0; i < nKeys && bSuccess; i++ )
+ {
+ const PPDKey* pKey = aKeys[i];
+ bool bEmit = false;
+ if( bDocumentSetup )
+ {
+ if( pKey->getSetupType() == PPDKey::DocumentSetup )
+ bEmit = true;
+ }
+ else
+ {
+ if( pKey->getSetupType() == PPDKey::PageSetup ||
+ pKey->getSetupType() == PPDKey::AnySetup )
+ bEmit = true;
+ }
+ if( bEmit )
+ {
+ const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
+ if( pValue
+ && pValue->m_eType == eInvocation
+ && ( m_aLastJobData.m_pParser == NULL
+ || m_aLastJobData.m_aContext.getValue( pKey ) != pValue
+ || bDocumentSetup
+ )
+ )
+ {
+ // try to avoid PS level 2 feature commands if level is set to 1
+ if( GetPostscriptLevel( &rJob ) == 1 )
+ {
+ bool bHavePS2 =
+ ( pValue->m_aValue.SearchAscii( "<<" ) != STRING_NOTFOUND )
+ ||
+ ( pValue->m_aValue.SearchAscii( ">>" ) != STRING_NOTFOUND );
+ if( bHavePS2 )
+ continue;
+ }
+ bSuccess = writeFeature( pFile, pKey, pValue, PrinterInfoManager::get().getUseIncludeFeature() );
+ }
+ }
+ }
+ }
+ else
+ bSuccess = false;
+
+ return bSuccess;
+}
+
+bool PrinterJob::writePageSetup( osl::File* pFile, const JobData& rJob )
+{
+ bool bSuccess = true;
+
+ WritePS (pFile, "%%BeginPageSetup\n%\n");
+
+ bSuccess = writeFeatureList( pFile, rJob, false );
+ WritePS (pFile, "%%EndPageSetup\n");
+
+ sal_Char pTranslate [128];
+ sal_Int32 nChar = 0;
+
+ if( rJob.m_eOrientation == orientation::Portrait )
+ {
+ nChar = psp::appendStr ("gsave\n[", pTranslate);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5);
+ nChar += psp::appendStr (" 0 0 ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfYScale, 5);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnRMarginPt, pTranslate + nChar);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnHeightPt-mnTMarginPt,
+ pTranslate + nChar);
+ nChar += psp::appendStr ("] concat\ngsave\n",
+ pTranslate + nChar);
+ }
+ else
+ {
+ nChar = psp::appendStr ("gsave\n", pTranslate);
+ nChar += psp::appendStr ("[ 0 ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, -mfYScale, 5);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5);
+ nChar += psp::appendStr (" 0 ", pTranslate + nChar );
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mnLMarginPt, 5 );
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnBMarginPt, pTranslate + nChar );
+ nChar += psp::appendStr ("] concat\ngsave\n",
+ pTranslate + nChar);
+ }
+
+ WritePS (pFile, pTranslate);
+
+ return bSuccess;
+}
+
+void PrinterJob::writeJobPatch( osl::File* pFile, const JobData& rJobData )
+{
+ const PPDKey* pKey = NULL;
+
+ if( rJobData.m_pParser )
+ pKey = rJobData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "JobPatchFile" ) ) );
+ if( ! pKey )
+ return;
+
+ // order the patch files
+ // according to PPD spec the JobPatchFile options must be int
+ // and should be emitted in order
+ std::list< sal_Int32 > patch_order;
+ int nValueCount = pKey->countValues();
+ for( int i = 0; i < nValueCount; i++ )
+ {
+ const PPDValue* pVal = pKey->getValue( i );
+ patch_order.push_back( pVal->m_aOption.ToInt32() );
+ if( patch_order.back() == 0 && ! pVal->m_aOption.EqualsAscii( "0" ) )
+ {
+ WritePS( pFile, "% Warning: left out JobPatchFile option \"" );
+ OString aOption = OUStringToOString( pVal->m_aOption, RTL_TEXTENCODING_ASCII_US );
+ WritePS( pFile, aOption.getStr() );
+ WritePS( pFile,
+ "\"\n% as it violates the PPD spec;\n"
+ "% JobPatchFile options need to be numbered for ordering.\n" );
+ }
+ }
+
+ patch_order.sort();
+ patch_order.unique();
+
+ while( patch_order.begin() != patch_order.end() )
+ {
+ // note: this discards patch files not adhering to the "int" scheme
+ // as there won't be a value for them
+ writeFeature( pFile, pKey, pKey->getValue( OUString::valueOf( patch_order.front() ) ), false );
+ patch_order.pop_front();
+ }
+}
+
+bool PrinterJob::writeProlog (osl::File* pFile, const JobData& rJobData )
+{
+ WritePS( pFile, "%%BeginProlog\n" );
+
+ // JobPatchFile feature needs to be emitted at begin of prolog
+ writeJobPatch( pFile, rJobData );
+
+ static const sal_Char pProlog[] = {
+ "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
+ "/ISO1252Encoding [\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle\n"
+ "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash\n"
+ "/zero /one /two /three /four /five /six /seven\n"
+ "/eight /nine /colon /semicolon /less /equal /greater /question\n"
+ "/at /A /B /C /D /E /F /G\n"
+ "/H /I /J /K /L /M /N /O\n"
+ "/P /Q /R /S /T /U /V /W\n"
+ "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
+ "/grave /a /b /c /d /e /f /g\n"
+ "/h /i /j /k /l /m /n /o\n"
+ "/p /q /r /s /t /u /v /w\n"
+ "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
+ "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
+ "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
+ "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
+ "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
+ "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
+ "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
+ "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
+ "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
+ "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
+ "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
+ "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
+ "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
+ "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
+ "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
+ "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
+ "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
+ "\n"
+ "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
+ "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
+ "currentdict end exch pop definefont pop } def\n"
+ "\n"
+ "/pathdict dup 8 dict def load begin\n"
+ "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
+ "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
+ "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
+ "eq 3 1 roll exch } def\n"
+ "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
+ "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
+ "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
+ "for 256 div exch pop exch { neg } if } def\n"
+ "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
+ "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
+ "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
+ "\n"
+ "systemdict /languagelevel known not {\n"
+ "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
+ "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
+ "roll show moveto 0 rmoveto } for pop pop } def\n"
+ "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
+ "rlineto closepath } def\n"
+ "/rectfill { rectangle fill } def\n"
+ "/rectstroke { rectangle stroke } def } if\n"
+ "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
+ "setlinewidth false charpath stroke setlinewidth } def\n"
+ "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
+ "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
+ "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
+ "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
+ "\n"
+ "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
+ "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
+ "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
+ "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
+ "/psp_imagedict {\n"
+ "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
+ "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
+ "def 7 dict dup\n"
+ "/ImageType 1 put dup\n"
+ "/Width 7 -1 roll put dup\n"
+ "/Height 5 index put dup\n"
+ "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
+ "/Decode 5 -1 roll psp_decodearray put dup\n"
+ "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
+ "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
+ "} def\n"
+ "%%EndResource\n"
+ "%%EndProlog\n"
+ };
+ static const sal_Char pSO52CompatProlog[] = {
+ "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
+ "/ISO1252Encoding [\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
+ "/parenleft /parenright /asterisk /plus /comma /minus /period /slash\n"
+ "/zero /one /two /three /four /five /six /seven\n"
+ "/eight /nine /colon /semicolon /less /equal /greater /question\n"
+ "/at /A /B /C /D /E /F /G\n"
+ "/H /I /J /K /L /M /N /O\n"
+ "/P /Q /R /S /T /U /V /W\n"
+ "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
+ "/grave /a /b /c /d /e /f /g\n"
+ "/h /i /j /k /l /m /n /o\n"
+ "/p /q /r /s /t /u /v /w\n"
+ "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
+ "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
+ "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
+ "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
+ "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
+ "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
+ "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
+ "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
+ "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
+ "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
+ "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
+ "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
+ "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
+ "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
+ "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
+ "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
+ "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
+ "\n"
+ "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
+ "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
+ "currentdict end exch pop definefont pop } def\n"
+ "\n"
+ "/pathdict dup 8 dict def load begin\n"
+ "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
+ "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
+ "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
+ "eq 3 1 roll exch } def\n"
+ "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
+ "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
+ "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
+ "for 256 div exch pop exch { neg } if } def\n"
+ "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
+ "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
+ "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
+ "\n"
+ "systemdict /languagelevel known not {\n"
+ "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
+ "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
+ "roll show moveto 0 rmoveto } for pop pop } def\n"
+ "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
+ "rlineto closepath } def\n"
+ "/rectfill { rectangle fill } def\n"
+ "/rectstroke { rectangle stroke } def } if\n"
+ "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
+ "setlinewidth false charpath stroke setlinewidth } def\n"
+ "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
+ "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
+ "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
+ "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
+ "\n"
+ "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
+ "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
+ "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
+ "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
+ "/psp_imagedict {\n"
+ "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
+ "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
+ "def 7 dict dup\n"
+ "/ImageType 1 put dup\n"
+ "/Width 7 -1 roll put dup\n"
+ "/Height 5 index put dup\n"
+ "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
+ "/Decode 5 -1 roll psp_decodearray put dup\n"
+ "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
+ "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
+ "} def\n"
+ "%%EndResource\n"
+ "%%EndProlog\n"
+ };
+ WritePS (pFile, m_pGraphics && m_pGraphics->getStrictSO52Compatibility() ? pSO52CompatProlog : pProlog);
+
+ return true;
+}
+
+bool PrinterJob::writeSetup( osl::File* pFile, const JobData& rJob )
+{
+ WritePS (pFile, "%%BeginSetup\n%\n");
+
+ // download fonts
+ std::list< rtl::OString > aFonts[2];
+ m_pGraphics->writeResources( pFile, aFonts[0], aFonts[1] );
+
+ for( int i = 0; i < 2; i++ )
+ {
+ if( !aFonts[i].empty() )
+ {
+ std::list< rtl::OString >::const_iterator it = aFonts[i].begin();
+ rtl::OStringBuffer aLine( 256 );
+ if( i == 0 )
+ aLine.append( "%%DocumentSuppliedResources: font " );
+ else
+ aLine.append( "%%DocumentNeededResources: font " );
+ aLine.append( *it );
+ aLine.append( "\n" );
+ WritePS ( pFile, aLine.getStr() );
+ while( (++it) != aFonts[i].end() )
+ {
+ aLine.setLength(0);
+ aLine.append( "%%+ font " );
+ aLine.append( *it );
+ aLine.append( "\n" );
+ WritePS ( pFile, aLine.getStr() );
+ }
+ }
+ }
+
+ bool bSuccess = true;
+ // in case of external print dialog the number of copies is prepended
+ // to the job, let us not complicate things by emitting our own copy count
+ bool bExternalDialog = PrinterInfoManager::get().checkFeatureToken( GetPrinterName(), "external_dialog" );
+ if( ! bExternalDialog && rJob.m_nCopies > 1 )
+ {
+ // setup code
+ ByteString aLine( "/#copies " );
+ aLine += ByteString::CreateFromInt32( rJob.m_nCopies );
+ aLine += " def\n";
+ sal_uInt64 nWritten = 0;
+ bSuccess = pFile->write( aLine.GetBuffer(), aLine.Len(), nWritten )
+ || nWritten != aLine.Len() ? false : true;
+
+ if( bSuccess && GetPostscriptLevel( &rJob ) >= 2 )
+ WritePS (pFile, "<< /NumCopies null /Policies << /NumCopies 1 >> >> setpagedevice\n" );
+ }
+
+ bool bFeatureSuccess = writeFeatureList( pFile, rJob, true );
+
+ WritePS (pFile, "%%EndSetup\n");
+
+ return bSuccess && bFeatureSuccess;
+}
diff --git a/vcl/unx/source/printergfx/psheader.ps b/vcl/unx/source/printergfx/psheader.ps
new file mode 100644
index 000000000000..7b947b3a470b
--- /dev/null
+++ b/vcl/unx/source/printergfx/psheader.ps
@@ -0,0 +1,372 @@
+%*************************************************************************
+%
+% DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+%
+% Copyright 2008 by Sun Microsystems, Inc.
+%
+% OpenOffice.org - a multi-platform office productivity suite
+%
+% $RCSfile: psheader.ps,v $
+%
+% $Revision: 1.7 $
+%
+% 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.
+%
+%*************************************************************************
+
+%
+%
+% readpath
+%
+% The intention of readpath is to save disk space since the vcl clip region routines
+% produce a huge amount of lineto/moveto commands
+%
+% The principal idea is to maintain the current point on stack and to provide only deltas
+% in the command. These deltas are added to the current point. The new point is used for
+% the lineto and moveto command and saved on stack for the next command.
+%
+% pathdict implements binary/hex representation of lineto and moveto commands.
+% The command consists of a 1byte opcode to switch between lineto and moveto and the size
+% of the following delta-x and delta-y values. The opcode is read with /rcmd, the two
+% coordinates are read with /rhex. The whole command is executed with /xcmd
+%
+%
+
+/pathdict dup 8 dict def load
+begin
+
+ % the command is of the bit format cxxyy
+ % with c=0 meaning lineto
+ % c=1 meaning moveto
+ % xx is a 2bit value for the number of bytes for x position
+ % yy is the same for y, values are off by one: 00 means 1; 11 means 4 !
+ % the command has been added to 'A' to be always in the ascii character
+ % range. the command is followed by 2*xx + 2*yy hexchars.
+ % '~' denotes the special case of EOD
+ /rcmd {
+ {
+ currentfile 1 string readstring % s bool
+ pop % s
+ 0 get % s[0]
+ % --- check wether s[0] is CR, LF ...
+ dup 32 gt % s > ' ' ? then read on
+ { exit }
+ { pop }
+ ifelse
+ }
+ loop
+
+ dup 126 eq { pop exit } if % -- Exit loop if cmd is '~'
+ 65 sub % cmd=s[0]-'A'
+ % -- Separate yy bits
+ dup 16#3 and 1 add % cmd yy
+ % -- Separate xx bits
+ exch % yy cmd
+ dup 16#C and -2 bitshift
+ 16#3 and 1 add exch % yy xx cmd
+ % -- Separate command bit
+ 16#10 and 16#10 eq % yy xx bool
+ 3 1 roll exch % bool xx yy
+ } def
+
+ % length rhex -- reads a signed hex value of given length
+ % the left most bit of char 0 is considered as the sign (0 means '+', 1 means '-')
+ % the rest of the bits is considered to be the abs value. Please note that this
+ % does not match the C binary representation of integers
+ /rhex {
+ dup 1 sub exch % l-1 l
+ currentfile exch string readhexstring % l-1 substring[l] bool
+ pop
+ dup 0 get dup % l-1 s s[0] s[0]
+ % -- Extract the sign
+ 16#80 and 16#80 eq dup % l-1 s s[0] sign=- sign=-
+ % -- Mask out the sign bit and put value back
+ 3 1 roll % l-1 s sign=- s[0] sign=-
+ { 16#7f and } if % l-1 s sign=- +s[0]
+ 2 index 0 % l-1 s sign=- +s[0] s 0
+ 3 -1 roll put % l-1 s sign=- s 0 +s[0]
+ % -- Read loop: add to prev sum, mul with 256
+ 3 1 roll 0 % sign=- l-1 s Sum=0
+ 0 1 5 -1 roll % sign=- s Sum=0 0 1 l-1
+ { % sign=- s Sum idx
+ 2 index exch % sign=- s Sum s idx
+ get % sign=- s Sum s[idx]
+ add 256 mul % sign=- s Sum=(s[idx]+Sum)*256
+ }
+ for
+ % -- mul was once too often, weave in the sign
+ 256 div % sign=- s Sum/256
+ exch pop % sign=- Sum/256
+ exch { neg } if % (sign=- ? -Sum : Sum)
+ } def
+
+ % execute a single command, the former x and y position is already on stack
+ % only offsets are read from cmdstring
+ /xcmd { % x y
+ rcmd % x y bool wx wy
+ exch rhex % x y bool wy Dx
+ exch rhex % x y bool Dx Dy
+ exch 5 -1 roll % y bool Dy Dx x
+ add exch % y bool X Dy
+ 4 -1 roll add % bool X Y
+ 1 index 1 index % bool X Y X Y
+ 5 -1 roll % X Y X Y bool
+ { moveto }
+ { lineto }
+ ifelse % X Y
+ } def
+end
+
+/readpath
+{
+ 0 0 % push initial-x initial-y
+ pathdict begin
+ { xcmd } loop
+ end
+ pop pop % pop final-x final-y
+} def
+
+%
+%
+% if languagelevel is not in the systemdict then its level 1 interpreter:
+% provide compatibility routines
+%
+%
+
+systemdict /languagelevel known not
+{
+ % string numarray xxshow -
+ % does only work for single byte fonts
+ /xshow {
+ exch dup % a s s
+ length 0 1 % a s l(s) 1 1
+ 3 -1 roll 1 sub % a s 0 1 l(s)-1
+ { % a s idx
+ dup % a s idx idx
+ % -- extract the delta offset
+ 3 index exch get % a s idx a[idx]
+ % -- extract the character
+ exch % a s a[idx] idx
+ 2 index exch get % a s a[idx] s[idx]
+ % -- create a tmp string for show
+ 1 string dup 0 % a s a[idx] s[idx] s1 s1 0
+ 4 -1 roll % a s a[idx] s1 s1 0 s[idx]
+ put % a s a[idx] s1
+ % -- store the current point
+ currentpoint 3 -1 roll % a s a[idx] x y s1
+ % -- draw the character
+ show % a s a[idx] x y
+ % -- move to the offset
+ moveto 0 rmoveto % a s
+ }
+ for
+ pop pop % -
+ } def
+
+ % x y width height rectfill
+ % x y width height rectshow
+ % in contrast to the languagelevel 2 operator
+ % they use and change the currentpath
+ /rectangle {
+ 4 -2 roll % width height x y
+ moveto % width height
+ 1 index 0 rlineto % width height % rmoveto(width, 0)
+ 0 exch rlineto % width % rmoveto(0, height)
+ neg 0 rlineto % - % rmoveto(-width, 0)
+ closepath
+ } def
+
+ /rectfill { rectangle fill } def
+ /rectstroke { rectangle stroke } def
+}
+if
+
+% -- small test program
+% 75 75 moveto /Times-Roman findfont 12 scalefont setfont
+% <292a2b2c2d2e2f30313233343536373839>
+% [5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 5] xshow <21>[0] xshow
+% showpage
+
+%
+%
+% shortcuts for image header with compression
+%
+%
+
+/psp_lzwfilter {
+ currentfile /ASCII85Decode filter /LZWDecode filter
+} def
+/psp_ascii85filter {
+ currentfile /ASCII85Decode filter
+} def
+/psp_lzwstring {
+ psp_lzwfilter 1024 string readstring
+} def
+/psp_ascii85string {
+ psp_ascii85filter 1024 string readstring
+} def
+/psp_imagedict {
+ /psp_bitspercomponent {
+ 3 eq
+ { 1 }
+ { 8 }
+ ifelse
+ } def
+ /psp_decodearray {
+ [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get
+ } def
+
+ 7 dict dup
+ /ImageType 1 put dup
+ /Width 7 -1 roll put dup
+ /Height 5 index put dup
+ /BitsPerComponent 4 index
+ psp_bitspercomponent put dup
+ /Decode 5 -1 roll
+ psp_decodearray put dup
+ /ImageMatrix [1 0 0 1 0 0] dup
+ 5 8 -1 roll put put dup
+ /DataSource 4 -1 roll
+ 1 eq
+ { psp_lzwfilter }
+ { psp_ascii85filter }
+ ifelse put
+} def
+
+
+%
+%
+% font encoding and reencoding
+%
+%
+
+/ISO1252Encoding [
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle
+ /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash
+ /zero /one /two /three /four /five /six /seven
+ /eight /nine /colon /semicolon /less /equal /greater /question
+ /at /A /B /C /D /E /F /G
+ /H /I /J /K /L /M /N /O
+ /P /Q /R /S /T /U /V /W
+ /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
+ /grave /a /b /c /d /e /f /g
+ /h /i /j /k /l /m /n /o
+ /p /q /r /s /t /u /v /w
+ /x /y /z /braceleft /bar /braceright /asciitilde /unused
+ /Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused
+ /unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis
+ /space /exclamdown /cent /sterling /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron
+ /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered
+ /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown
+ /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla
+ /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis
+ /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply
+ /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls
+ /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla
+ /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis
+ /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide
+ /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis
+] def
+
+% /fontname /encoding psp_findfont
+/psp_findfont {
+ exch dup % encoding fontname fontname
+ findfont % encoding fontname
+ dup length dict
+ begin
+ {
+ 1 index /FID ne
+ { def }
+ { pop pop }
+ ifelse
+ } forall
+ /Encoding 3 -1 roll def
+ currentdict
+ end
+ /psp_reencodedfont exch definefont
+} def
+
+% bshow shows a text in artificial bold
+% this is achieved by first showing the text
+% then stroking its outline over it with
+% the linewidth set to the second parameter
+% usage: (string) num bshow
+
+/bshow {
+ currentlinewidth % save current linewidth
+ 3 1 roll % move it to the last stack position
+ currentpoint % save the current point
+ 3 index % copy the string to show
+ show % show it
+ moveto % move to the original coordinates again
+ setlinewidth % set the linewidth
+ false charpath % create the outline path of the shown string
+ stroke % and stroke it
+ setlinewidth % reset the stored linewidth
+} def
+
+% bxshow shows a text with a delta array in artificial bold
+% that is it does what bshow does for show
+% usage: (string) [deltaarray] num bxshow
+
+/bxshow {
+ currentlinewidth % save linewidth
+ 4 1 roll % move it to the last stack position
+ setlinewidth % set the new linewidth
+ exch % exchange string and delta array
+ dup
+ length % get length of string
+ 1 sub % prepare parameters for {} for
+ 0 1
+ 3 -1 roll
+ {
+ 1 string % create a string object length 1
+ 2 index % get the text
+ 2 index % get charpos (for index variable)
+ get % have char value at charpos
+ 1 index % prepare string for put
+ exch
+ 0
+ exch
+ put % put into string of length 1
+ dup % duplicate the it
+ currentpoint % save current position
+ 3 -1 roll % prepare show
+ show % show the character
+ moveto % move back to beginning
+ currentpoint % save current position
+ 3 -1 roll % prepare outline path of character
+ false charpath
+ stroke % stroke it
+ moveto % move back
+ % now move to next point
+ 2 index % get advance array
+ exch % get charpos
+ get % get advance element
+ 0 rmoveto % advance current position
+ } for
+ pop pop % remove string and delta array
+ setlinewidth % restore linewidth
+} def
diff --git a/vcl/unx/source/printergfx/psputil.cxx b/vcl/unx/source/printergfx/psputil.cxx
new file mode 100644
index 000000000000..0b92f4ee423d
--- /dev/null
+++ b/vcl/unx/source/printergfx/psputil.cxx
@@ -0,0 +1,271 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: psputil.cxx,v $
+ * $Revision: 1.6 $
+ *
+ * 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 "psputil.hxx"
+
+#include "tools/debug.hxx"
+
+namespace psp {
+
+/*
+ * string convenience routines
+ */
+
+sal_Int32
+getHexValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ const static sal_Char pHex [0x10] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ pBuffer[0] = pHex [(nValue & 0xF0) >> 4];
+ pBuffer[1] = pHex [(nValue & 0x0F) ];
+
+ return 2;
+}
+
+sal_Int32
+getAlignedHexValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ // get sign
+ sal_Bool bNegative = nValue < 0;
+ nValue = bNegative ? -nValue : nValue;
+
+ // get required buffer size, must be a multiple of two
+ sal_Int32 nPrecision;
+ if (nValue < 0x80)
+ nPrecision = 2;
+ else
+ if (nValue < 0x8000)
+ nPrecision = 4;
+ else
+ if (nValue < 0x800000)
+ nPrecision = 6;
+ else
+ nPrecision = 8;
+
+ // convert the int into its hex representation, write it into the buffer
+ sal_Int32 nRet = nPrecision;
+ while (nPrecision)
+ {
+ nPrecision -= getHexValueOf (nValue % 256, pBuffer + nPrecision - 2 );
+ nValue /= 256;
+ }
+
+ // set sign bit
+ if (bNegative)
+ {
+ switch (pBuffer[0])
+ {
+ case '0' : pBuffer[0] = '8'; break;
+ case '1' : pBuffer[0] = '9'; break;
+ case '2' : pBuffer[0] = 'A'; break;
+ case '3' : pBuffer[0] = 'B'; break;
+ case '4' : pBuffer[0] = 'C'; break;
+ case '5' : pBuffer[0] = 'D'; break;
+ case '6' : pBuffer[0] = 'E'; break;
+ case '7' : pBuffer[0] = 'F'; break;
+ default: DBG_ERROR("Already a signed value");
+ }
+ }
+
+ // report precision
+ return nRet;
+}
+
+
+sal_Int32
+getValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ sal_Int32 nChar = 0;
+ if (nValue < 0)
+ {
+ pBuffer [nChar++] = '-';
+ nValue *= -1;
+ }
+ else
+ if (nValue == 0)
+ {
+ pBuffer [nChar++] = '0';
+ return nChar;
+ }
+
+ sal_Char pInvBuffer [32];
+ sal_Int32 nInvChar = 0;
+ while (nValue > 0)
+ {
+ pInvBuffer [nInvChar++] = '0' + nValue % 10;
+ nValue /= 10;
+ }
+ while (nInvChar > 0)
+ {
+ pBuffer [nChar++] = pInvBuffer [--nInvChar];
+ }
+
+ return nChar;
+}
+
+sal_Int32
+appendStr (const sal_Char* pSrc, sal_Char* pDst)
+{
+ sal_Int32 nBytes = strlen (pSrc);
+ strncpy (pDst, pSrc, nBytes + 1);
+
+ return nBytes;
+}
+
+sal_Int32
+appendStr (const sal_Char* pSrc, sal_Char* pDst, sal_Int32 nBytes)
+{
+ strncpy (pDst, pSrc, nBytes);
+ pDst [nBytes] = '\0';
+ return nBytes;
+}
+
+/*
+ * copy strings to file
+ */
+
+sal_Bool
+WritePS (osl::File* pFile, const sal_Char* pString)
+{
+ sal_uInt64 nInLength = rtl_str_getLength (pString);
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (pString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const sal_Char* pString, sal_uInt64 nInLength)
+{
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (pString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const rtl::OString &rString)
+{
+ sal_uInt64 nInLength = rString.getLength();
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (rString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const rtl::OUString &rString)
+{
+ return WritePS (pFile, rtl::OUStringToOString(rString, RTL_TEXTENCODING_ASCII_US));
+}
+
+/*
+ * cache converter for use in postscript drawing routines
+ */
+
+ConverterFactory::ConverterFactory()
+{
+}
+
+ConverterFactory::~ConverterFactory ()
+{
+ for( std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter >::const_iterator it = m_aConverters.begin(); it != m_aConverters.end(); ++it )
+ rtl_destroyUnicodeToTextConverter (it->second);
+}
+
+rtl_UnicodeToTextConverter
+ConverterFactory::Get (rtl_TextEncoding nEncoding)
+{
+ if (rtl_isOctetTextEncoding( nEncoding ))
+ {
+ std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter >::const_iterator it =
+ m_aConverters.find( nEncoding );
+ rtl_UnicodeToTextConverter aConverter;
+ if (it == m_aConverters.end())
+ {
+ aConverter = rtl_createUnicodeToTextConverter (nEncoding);
+ m_aConverters[nEncoding] = aConverter;
+ }
+ else
+ aConverter = it->second;
+ return aConverter;
+ }
+ return NULL;
+}
+
+// wrapper for rtl_convertUnicodeToText that handles the usual cases for
+// textconversion in drawtext
+sal_Size
+ConverterFactory::Convert (const sal_Unicode *pText, int nTextLen,
+ sal_uChar *pBuffer, sal_Size nBufferSize, rtl_TextEncoding nEncoding)
+{
+ const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK ;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+
+ rtl_UnicodeToTextConverter aConverter = Get (nEncoding);
+ rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext (aConverter);
+
+ sal_Size nSize = rtl_convertUnicodeToText (aConverter, aContext,
+ pText, nTextLen, (sal_Char*)pBuffer, nBufferSize,
+ nCvtFlags, &nCvtInfo, &nCvtChars);
+
+ rtl_destroyUnicodeToTextContext (aConverter, aContext);
+
+ return nSize;
+}
+
+ConverterFactory*
+GetConverterFactory ()
+{
+ static ConverterFactory* pCvt = NULL;
+
+ if (pCvt == NULL)
+ pCvt = new ConverterFactory;
+
+ return pCvt;
+}
+
+
+} /* namespace psp */
diff --git a/vcl/unx/source/printergfx/psputil.hxx b/vcl/unx/source/printergfx/psputil.hxx
new file mode 100644
index 000000000000..b3227962e8a0
--- /dev/null
+++ b/vcl/unx/source/printergfx/psputil.hxx
@@ -0,0 +1,81 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: psputil.hxx,v $
+ * $Revision: 1.4 $
+ *
+ * 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 _PSPRINT_PRINTERUTIL_HXX_
+#define _PSPRINT_PRINTERUTIL_HXX_
+
+#include "osl/file.hxx"
+
+#include "rtl/ustring.hxx"
+#include "rtl/string.hxx"
+#include "rtl/tencinfo.h"
+#include "rtl/textcvt.h"
+
+#include <map>
+
+namespace psp {
+
+/*
+ * string convenience routines
+ * sizeof(pBuffer) must be at least 2 Bytes, 0x00 <= nValue <= 0xFF,
+ * effective buffer of get*ValueOf() is NOT NULL-terminated
+ */
+sal_Int32 getHexValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 getAlignedHexValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 getValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 appendStr (const sal_Char* pSrc, sal_Char* pDst);
+sal_Int32 appendStr (const sal_Char* pSrc, sal_Char* pDst, sal_Int32 nBytes);
+
+sal_Bool WritePS (osl::File* pFile, const sal_Char* pString);
+sal_Bool WritePS (osl::File* pFile, const sal_Char* pString, sal_uInt64 nInLength);
+sal_Bool WritePS (osl::File* pFile, const rtl::OString &rString);
+sal_Bool WritePS (osl::File* pFile, const rtl::OUString &rString);
+
+class ConverterFactory
+{
+
+public:
+ ConverterFactory();
+ ~ConverterFactory();
+ rtl_UnicodeToTextConverter Get (rtl_TextEncoding nEncoding);
+ sal_Size Convert (const sal_Unicode *pText, int nTextLen,
+ sal_uChar *pBuffer, sal_Size nBufferSize,
+ rtl_TextEncoding nEncoding);
+private:
+
+ std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter > m_aConverters;
+};
+
+ConverterFactory* GetConverterFactory ();
+
+} /* namespace psp */
+
+#endif /* _PSPRINT_PRINTERUTIL_HXX_ */
+
diff --git a/vcl/unx/source/printergfx/text_gfx.cxx b/vcl/unx/source/printergfx/text_gfx.cxx
new file mode 100644
index 000000000000..e9c173682f87
--- /dev/null
+++ b/vcl/unx/source/printergfx/text_gfx.cxx
@@ -0,0 +1,865 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: text_gfx.cxx,v $
+ * $Revision: 1.31 $
+ *
+ * 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 <math.h>
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/helper.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+using namespace psp ;
+
+namespace psp {
+/*
+ container for a font and its helper fonts:
+ 1st font is the font substitute e.g. helvetica substitutes arial on the printer
+ 2nd is the font itself
+ 3rd is a fallback font, usually a font with unicode glyph repertoir (e.g. andale)
+ symbol fonts (adobe-fontspecific) may need special glyphmapping
+ (symbol page vc. latin page)
+*/
+class Font3
+{
+ private:
+
+ #define Font3Size 3
+
+ fontID mpFont [Font3Size];
+ bool mbSymbol;
+
+ public:
+
+ fontID GetFont (int nIdx) const
+ { return nIdx < Font3Size ? mpFont[nIdx] : -1 ; }
+ bool IsSymbolFont () const
+ { return mbSymbol; }
+
+ Font3 (const PrinterGfx &rGfx);
+ ~Font3 () {}
+};
+
+Font3::Font3(const PrinterGfx &rGfx)
+{
+ mpFont[0] = rGfx.getFontSubstitute();
+ mpFont[1] = rGfx.GetFontID();
+ mpFont[2] = rGfx.getFallbackID();
+ // mpFont[2] = rGfx.GetFontID();
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ mbSymbol = mpFont[1] != -1 ?
+ rMgr.getFontEncoding(mpFont[1]) == RTL_TEXTENCODING_SYMBOL : false;
+}
+
+} // namespace psp
+
+static int getVerticalDeltaAngle( sal_Unicode nChar )
+{
+ int nAngle = 0;
+ if( ( nChar >= 0x1100 && nChar < 0x11fa ) ||
+ ( nChar >= 0x3000 && nChar < 0xfb00 ) ||
+ ( nChar >= 0xfe20 && nChar < 0xfe70 ) ||
+ ( nChar >= 0xff00 && nChar < 0xff64 )
+ )
+ {
+ /* #i52932# remember:
+ nChar == 0x2010 || nChar == 0x2015
+ nChar == 0x2016 || nChar == 0x2026
+
+ are nAngle = 0 also, but already handled in the first if
+ */
+ if( ( nChar >= 0x3008 && nChar < 0x3019 && nChar != 0x3012 ) ||
+ nChar == 0xff3b || nChar == 0xff3d ||
+ (nChar >= 0xff6b && nChar < 0xff64 ) ||
+ nChar == 0xffe3
+ )
+ nAngle = 0;
+ else if( nChar == 0x30fc )
+ nAngle = -900;
+ else
+ nAngle = 900;
+ }
+ return nAngle;
+}
+
+void
+PrinterGfx::PSUploadPS1Font (sal_Int32 nFontID)
+{
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont )
+ if( nFontID == *aFont )
+ return;
+
+ // no occurrenc yet, mark for download
+ // add the fontid to the list
+ maPS1Font.push_back (nFontID);
+}
+
+/*
+ * implement text handling printer routines,
+ */
+
+sal_uInt16
+PrinterGfx::SetFont(
+ sal_Int32 nFontID,
+ sal_Int32 nHeight,
+ sal_Int32 nWidth,
+ sal_Int32 nAngle,
+ bool bVertical,
+ bool bArtItalic,
+ bool bArtBold
+ )
+{
+ // font and encoding will be set by drawText again immediately
+ // before PSShowText
+ mnFontID = nFontID;
+ maVirtualStatus.maFont = rtl::OString();
+ maVirtualStatus.maEncoding = RTL_TEXTENCODING_DONTKNOW;
+ maVirtualStatus.mnTextHeight = nHeight;
+ maVirtualStatus.mnTextWidth = nWidth;
+ maVirtualStatus.mbArtItalic = bArtItalic;
+ maVirtualStatus.mbArtBold = bArtBold;
+ mnTextAngle = nAngle;
+ mbTextVertical = bVertical;
+
+ return 0;
+}
+
+sal_uInt16
+PrinterGfx::SetFallbackFont ( sal_Int32 nFontID )
+{
+ mnFallbackID = nFontID;
+ return 0;
+}
+
+void PrinterGfx::drawGlyphs(
+ const Point& rPoint,
+ sal_uInt32* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+
+ // draw the string
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ }
+}
+
+void PrinterGfx::DrawGlyphs(
+ const Point& rPoint,
+ sal_uInt32* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+ if( nLen <= 0 )
+ return;
+
+ if ( !mrFontMgr.isFontDownloadingAllowed( mnFontID ) )
+ {
+ LicenseWarning(rPoint, pUnicodes, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getFontType( mnFontID ) != fonttype::TrueType )
+ {
+ DrawText( rPoint, pUnicodes, nLen, pDeltaArray );
+ return;
+ }
+
+ // move and rotate the user coordinate system
+ // avoid the gsave/grestore for the simple cases since it allows
+ // reuse of the current font if it hasn't changed
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ Point aPoint( rPoint );
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+ aPoint = Point( 0, 0 );
+ }
+
+ if( mbTextVertical )
+ {
+ // vertical glyphs can have an additional rotation ... sigh.
+ // so break up text in chunks of normal glyphs and print out
+ // specially rotated glyphs extra
+ sal_uInt32* pTempGlyphIds = (sal_uInt32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Int32* pTempDelta = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Unicode* pTempUnicodes = (sal_Unicode*)alloca(sizeof(sal_Unicode)*nLen);
+ sal_Int16 nTempLen = 0;
+ sal_Int32 nTempFirstDelta = 0;
+ Point aRotPoint;
+ sal_Int32 nTextHeight = maVirtualStatus.mnTextHeight;
+ sal_Int32 nTextWidth = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ sal_Int32 nAscend = mrFontMgr.getFontAscend( mnFontID );
+ sal_Int32 nDescend = mrFontMgr.getFontDescend( mnFontID );
+
+ nDescend = nDescend * nTextHeight / 1000;
+ nAscend = nAscend * nTextHeight / 1000;
+
+ for( sal_Int16 i = 0; i < nLen; i++ )
+ {
+ sal_Int32 nRot = ((pGlyphIds[i] >> 24) & 3);
+ if( nRot == 0 )
+ {
+ pTempUnicodes[nTempLen] = pUnicodes[i];
+ pTempGlyphIds[nTempLen] = pGlyphIds[i];
+ if( nTempLen > 0 )
+ pTempDelta[nTempLen-1] = pDeltaArray[i-1]-nTempFirstDelta;
+ else
+ {
+ // the first element in pDeltaArray shows
+ // the offset of the second character
+ // so if the first glyph is normal
+ // then we do not need to move the delta indices
+ // else we have to move them down by one and
+ // recalculate aPoint and all deltas
+ if( i != 0 )
+ nTempFirstDelta = pDeltaArray[ i-1 ];
+ }
+ nTempLen++;
+ }
+ else
+ {
+ sal_Int32 nOffset = i > 0 ? pDeltaArray[i-1] : 0;
+ sal_Int32 nRotAngle = 0;
+ switch( nRot )
+ {
+ case 3:
+ nRotAngle = 2700;
+ aRotPoint = Point( -nAscend*nTextWidth/nTextHeight, -nDescend*nTextWidth/nTextHeight - nOffset );
+ break;
+ case 2:
+ nRotAngle = 1800;
+ aRotPoint = Point( -nOffset, (nAscend+nDescend) );
+ break;
+ case 1:
+ nRotAngle = 900;
+ aRotPoint = Point( -nDescend*nTextWidth/nTextHeight, nOffset + nAscend*nTextWidth/nTextHeight );
+ break;
+ }
+ sal_uInt32 nRotGlyphId = pGlyphIds[i];
+ sal_Unicode nRotUnicode = pUnicodes[i];
+ sal_Int32 nRotDelta = 0;
+
+ // transform matrix to new individual direction
+ PSGSave ();
+ GraphicsStatus aSaveStatus = maVirtualStatus;
+ if( nRot != 2 ) // switch font aspect
+ {
+ maVirtualStatus.mnTextWidth = nTextHeight;
+ maVirtualStatus.mnTextHeight = nTextWidth;
+ }
+ if( aPoint.X() || aPoint.Y() )
+ PSTranslate( aPoint );
+ PSRotate (nRotAngle);
+ // draw the rotated glyph
+ drawGlyphs( aRotPoint, &nRotGlyphId, &nRotUnicode, 1, &nRotDelta );
+
+ // restore previous state
+ maVirtualStatus = aSaveStatus;
+ PSGRestore();
+ }
+ }
+
+ pGlyphIds = pTempGlyphIds;
+ pUnicodes = pTempUnicodes;
+ pDeltaArray = pTempDelta;
+ nLen = nTempLen;
+
+ aPoint.X() += nTempFirstDelta;
+ }
+
+ if( nLen > 0 )
+ drawGlyphs( aPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray );
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+}
+
+void
+PrinterGfx::DrawText (
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ fontID nRestoreFont = mnFontID;
+
+ // setup font[substitutes] and map the string into the symbol area in case of
+ // symbol font
+ Font3 aFont(*this);
+ sal_Unicode *pEffectiveStr;
+ if ( aFont.IsSymbolFont() )
+ {
+ pEffectiveStr = (sal_Unicode*)alloca(nLen * sizeof(pStr[0]));
+ for (int i = 0; i < nLen; i++)
+ pEffectiveStr[i] = pStr[i] < 256 ? pStr[i] + 0xF000 : pStr[i];
+ }
+ else
+ {
+ pEffectiveStr = const_cast<sal_Unicode*>(pStr);
+ }
+
+ fontID *pFontMap = (fontID*) alloca(nLen * sizeof(fontID));
+ sal_Int32 *pCharWidth = (sal_Int32*) alloca(nLen * sizeof(sal_Int32));
+
+ for( int n = 0; n < nLen; n++ )
+ {
+ CharacterMetric aBBox;
+ pFontMap[n] = getCharMetric (aFont, pEffectiveStr[n], &aBBox);
+ pCharWidth[n] = getCharWidth (mbTextVertical, pEffectiveStr[n], &aBBox);
+ }
+
+ // setup a new delta array, use virtual resolution of 1000
+ sal_Int32* pNewDeltaArray = (sal_Int32*)alloca( sizeof( sal_Int32 )*nLen );
+ if ( pDeltaArray != 0)
+ {
+ for (int i = 0; i < nLen - 1; i++)
+ pNewDeltaArray[i] = 1000 * pDeltaArray[i];
+ pNewDeltaArray[nLen - 1] = 0;
+ }
+ else
+ {
+ pNewDeltaArray[0] = pCharWidth[0];
+ for (int i = 1; i < nLen; i++)
+ pNewDeltaArray[i] = pNewDeltaArray[i-1] + pCharWidth[i];
+ }
+
+ // move and rotate the user coordinate system
+ // avoid the gsave/grestore for the simple cases since it allows
+ // reuse of the current font if it hasn't changed
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ sal_Int32 nCurrentPointX;
+ sal_Int32 nCurrentPointY;
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+
+ nCurrentPointX = 0;
+ nCurrentPointY = 0;
+ }
+ else
+ {
+ nCurrentPointX = rPoint.X();
+ nCurrentPointY = rPoint.Y();
+ }
+
+ // draw the string
+ sal_Int32 nDelta = 0;
+ for (int nTo = 0; nTo < nLen; )
+ {
+ int nFrom = nTo;
+ fontID nFont = pFontMap[ nFrom ];
+
+ while ((nTo < nLen) && (nFont == pFontMap[nTo]))
+ {
+ pNewDeltaArray[ nTo ] = (sal_Int32)(((0.5 + pNewDeltaArray[ nTo ]) / 1000.0) - nDelta);
+ nTo++ ;
+ }
+
+ SetFont( nFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+
+ if (mbTextVertical)
+ {
+ drawVerticalizedText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pNewDeltaArray + nFrom );
+ }
+ else
+ {
+ drawText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pDeltaArray == NULL ? NULL : pNewDeltaArray + nFrom );
+ }
+ nDelta += pNewDeltaArray[ nTo - 1 ];
+ }
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+
+ // restore the original font settings
+ SetFont( nRestoreFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+}
+
+void PrinterGfx::drawVerticalizedText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ sal_Int32* pDelta = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
+
+ int nTextScale = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ int nNormalAngle = mnTextAngle;
+ int nDeltaAngle, nLastPos = 0;
+
+ double fSin = sin( -2.0*M_PI*nNormalAngle/3600 );
+ double fCos = cos( -2.0*M_PI*nNormalAngle/3600 );
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ PrintFontInfo aInfo;
+ rMgr.getFontInfo( mnFontID, aInfo );
+
+ bool* pGsubFlags = (bool*)alloca( nLen * sizeof(bool) );
+ rMgr.hasVerticalSubstitutions( mnFontID, pStr, nLen, pGsubFlags );
+
+ Point aPoint( rPoint );
+ for( int i = 0; i < nLen; )
+ {
+ while( ( nDeltaAngle = getVerticalDeltaAngle( pStr[i] ) ) == 0 && i < nLen )
+ i++;
+ if( i <= nLen && i > nLastPos )
+ {
+ for( int n = nLastPos; n < i; n++ )
+ pDelta[n] = pDeltaArray[n] - (aPoint.X() - rPoint.X() );
+
+ SetFont( mnFontID,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ nNormalAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ drawText( aPoint, pStr + nLastPos, i - nLastPos, pDelta + nLastPos );
+
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i-1] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i-1] * fSin));
+ }
+ if( i < nLen )
+ {
+ int nOldWidth = maVirtualStatus.mnTextWidth;
+ int nOldHeight = maVirtualStatus.mnTextHeight;
+ SetFont( mnFontID,
+ nTextScale,
+ maVirtualStatus.mnTextHeight,
+ nNormalAngle + nDeltaAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+
+ double nA = nTextScale * aInfo.m_nAscend / 1000.0;
+ double nD = nTextScale * aInfo.m_nDescend / 1000.0;
+ double fStretch = (double)maVirtualStatus.mnTextWidth / maVirtualStatus.mnTextHeight;
+ if( !pGsubFlags[i] )
+ nD *= fStretch;
+
+ Point aPos( aPoint );
+ switch( nDeltaAngle )
+ {
+ case +900:
+ aPos.X() += (sal_Int32)(+nA * fCos + nD * fSin);
+ aPos.Y() += (sal_Int32)(-nA * fSin + nD * fCos);
+ break;
+ case -900:
+ aPos.X() += (sal_Int32)(+nA * fSin + nD * fCos);
+ aPos.Y() += (sal_Int32)(-(nTextScale*fStretch - nD) * fCos);
+ break;
+ }
+ drawText( aPos, pStr+i, 1, NULL );
+ if( i < nLen-1 && pDeltaArray )
+ {
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i] * fSin));
+ }
+
+ // swap text width/height again
+ SetFont( mnFontID,
+ nOldHeight,
+ nOldWidth,
+ nNormalAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ }
+ i++;
+ nLastPos = i;
+ }
+ mnTextAngle = nNormalAngle;
+}
+
+void
+PrinterGfx::LicenseWarning(const Point& rPoint, const sal_Unicode* pStr,
+ sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // treat it like a builtin font in case a user has that font also in the
+ // printer. This is not so unlikely as it may seem; no print embedding
+ // licensed fonts are often used (or so they say) in companies:
+ // they are installed on displays and printers, but get not embedded in
+ // they are installed on displays and printers, but get not embedded in
+ // print files or documents because they are not licensed for use outside
+ // the company.
+ rtl::OString aMessage( "The font " );
+ aMessage += rtl::OUStringToOString( mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US );
+ aMessage += " could not be downloaded\nbecause its license does not allow for that";
+ PSComment( aMessage.getStr() );
+
+ rtl::OString aFontName = rtl::OUStringToOString(
+ mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ PSSetFont (aFontName, RTL_TEXTENCODING_ISO_8859_1);
+
+ sal_Size nSize = 4 * nLen;
+ sal_uChar* pBuffer = (sal_uChar*)alloca (nSize* sizeof(sal_uChar));
+
+ ConverterFactory* pCvt = GetConverterFactory ();
+ nSize = pCvt->Convert (pStr, nLen, pBuffer, nSize, RTL_TEXTENCODING_ISO_8859_1);
+
+ PSMoveTo (rPoint);
+ PSShowText (pBuffer, nLen, nSize, pDeltaArray);
+}
+
+void
+PrinterGfx::drawText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ if (!(nLen > 0))
+ return;
+
+ fonttype::type eType = mrFontMgr.getFontType (mnFontID);
+
+ if (eType == fonttype::Type1)
+ PSUploadPS1Font (mnFontID);
+
+ if ( eType == fonttype::TrueType
+ && !mrFontMgr.isFontDownloadingAllowed(mnFontID))
+ {
+ LicenseWarning(rPoint, pStr, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getUseOnlyFontEncoding( mnFontID ) )
+ {
+ GlyphSet aGSet( mnFontID, mbTextVertical );
+ aGSet.DrawText( *this, rPoint, pStr, nLen, pDeltaArray );
+ return;
+ }
+
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ }
+}
+
+int
+PrinterGfx::getCharWidth (sal_Bool b_vert, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ b_vert = b_vert && (getVerticalDeltaAngle(n_char) != 0);
+ int w = b_vert ? p_bbox->height : p_bbox->width;
+ w *= maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ return w;
+}
+
+fontID
+PrinterGfx::getCharMetric (const Font3 &rFont, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ p_bbox->width = -1;
+ p_bbox->height = -1;
+
+ for (fontID n = 0; n < 3; n++)
+ {
+ fontID n_font = rFont.GetFont(n);
+ if (n_font != -1)
+ {
+ if( mbStrictSO52Compatibility )
+ {
+ fonttype::type eType = mrFontMgr.getFontType( n_font );
+ if( (eType == fonttype::Builtin || eType == fonttype::Type1) )
+ {
+ // note: any character exchanged here MUST also be changed
+ // in the compatibility ISO encoding vector in the prolog
+ // in printerjob.cxx
+ sal_Unicode aRepl = 0;
+ if( n_char == 0x2d )
+ aRepl = 0x2212;
+ else if( n_char == 0x27 )
+ aRepl = 0x2019;
+ /*
+ additional characters that may need backwards compatibility:
+ ISO5589 StdEnc Unicode suggested n_char -> aRepl
+ 0264 0302 0x00B4 0x00B4 (acute) -> 0x2019 (quiteright)
+ 0246 - 0x00A6 0x00A6 (brokenbar) -> 0x007C (bar)
+ 0225 0267 0x0095 0x0095 () -> 0x2022 (bullet)
+ 0140 0301 0x0060 0x0060 (grave) -> ?
+ */
+ if( aRepl )
+ {
+ mrFontMgr.getMetrics( n_font, aRepl, aRepl, p_bbox );
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ }
+ }
+ mrFontMgr.getMetrics( n_font, n_char, n_char, p_bbox );
+ }
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ if (n_char != '?')
+ return getCharMetric (rFont, '?', p_bbox);
+
+ return rFont.GetFont(0) != -1 ? rFont.GetFont(0) : rFont.GetFont(1);
+}
+
+fontID
+PrinterGfx::getFontSubstitute () const
+{
+ if( mpFontSubstitutes )
+ {
+ ::std::hash_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ return it->second;
+ }
+
+ return -1;
+}
+
+sal_Int32
+PrinterGfx::GetCharWidth (sal_Unicode nFrom, sal_Unicode nTo, long *pWidthArray)
+{
+ Font3 aFont(*this);
+ if (aFont.IsSymbolFont() && (nFrom < 256) && (nTo < 256))
+ {
+ nFrom += 0xF000;
+ nTo += 0xF000;
+ }
+
+ for( int n = 0; n < (nTo - nFrom + 1); n++ )
+ {
+ CharacterMetric aBBox;
+ getCharMetric (aFont, n + nFrom, &aBBox);
+ pWidthArray[n] = getCharWidth (mbTextVertical, n + nFrom, &aBBox);
+ }
+
+ // returned metrics have postscript precision
+ return 1000;
+}
+
+const ::std::list< KernPair >& PrinterGfx::getKernPairs( bool bVertical ) const
+{
+ /*
+ * Note: this is only a 80% solution: if a font is only
+ * partially substituted in a string due to missing glyphs
+ * the results may not be perfect; the more so the more the
+ * substitution differs from the original metricwise. But
+ * vcl only asks for KernPairs for each font once and NOT
+ * in a string context this is the best we can do.
+ * In future the kerning should be done on a per string basis.
+ */
+ fontID nFont = mnFontID;
+ if( mpFontSubstitutes )
+ {
+ ::std::hash_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ nFont = it->second;
+ }
+ return mrFontMgr.getKernPairs( nFont, bVertical );
+}
+
+/*
+ * advanced glyph handling
+ */
+
+sal_Bool
+PrinterGfx::GetGlyphBoundRect (sal_Unicode /*c*/, Rectangle& /*rOutRect*/)
+{
+ return 0;
+}
+
+sal_uInt32
+PrinterGfx::GetGlyphOutline (sal_Unicode /*c*/,
+ sal_uInt16 **/*ppPolySizes*/, Point **/*ppPoints*/, sal_uInt8 **/*ppFlags*/)
+{
+ return 0;
+}
+
+/*
+ * spool the converted truetype fonts to the page header after the page body is
+ * complete
+ * for Type1 fonts spool additional reencoding vectors that are necessary to access the
+ * whole font
+ */
+
+void
+PrinterGfx::OnEndPage ()
+{
+}
+
+void
+PrinterGfx::OnEndJob ()
+{
+ maPS3Font.clear();
+ maPS1Font.clear();
+}
+
+void
+PrinterGfx::writeResources( osl::File* pFile, std::list< rtl::OString >& rSuppliedFonts, std::list< rtl::OString >& rNeededFonts )
+{
+ // write all type 1 fonts
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont)
+ {
+ const rtl::OString& rSysPath (mrFontMgr.getFontFileSysPath(*aFont) );
+ rtl::OUString aUNCPath;
+ osl::File::getFileURLFromSystemPath (OStringToOUString (rSysPath, osl_getThreadTextEncoding()), aUNCPath);
+ osl::File aFontFile (aUNCPath);
+
+ // provide the pfb or pfa font as a (pfa-)font resource
+ rtl::OString aPostScriptName =
+ rtl::OUStringToOString ( mrFontMgr.getPSName(*aFont),
+ RTL_TEXTENCODING_ASCII_US );
+
+ WritePS (pFile, "%%BeginResource: font ");
+ WritePS (pFile, aPostScriptName.getStr());
+ WritePS (pFile, "\n");
+
+ osl::File::RC nError = aFontFile.open (OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ convertPfbToPfa (aFontFile, *pFile);
+ aFontFile.close ();
+
+ pFile->setPos(osl_Pos_Current, -1);
+ char lastchar = '\n';
+ sal_uInt64 uBytes(1);
+ pFile->read((void *)(&lastchar), uBytes, uBytes);
+ if (lastchar != '\n')
+ WritePS (pFile, "\n");
+ }
+ WritePS (pFile, "%%EndResource\n");
+ rSuppliedFonts.push_back( aPostScriptName );
+ }
+
+ // write glyphsets and reencodings
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); ++aIter)
+ {
+ if (aIter->GetFontType() == fonttype::TrueType)
+ {
+ aIter->PSUploadFont (*pFile, *this, mbUploadPS42Fonts ? true : false, rSuppliedFonts );
+ }
+ else
+ // ( aIter->GetFontType() == fonttype::Type1
+ // || aIter->GetFontType() == fonttype::Builtin )
+ {
+ aIter->PSUploadEncoding (pFile, *this);
+ if( aIter->GetFontType() == fonttype::Builtin )
+ rNeededFonts.push_back(
+ rtl::OUStringToOString(
+ mrFontMgr.getPSName( aIter->GetFontID() ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ }
+ }
+}
+
+bool PrinterGfx::getStrictSO52Compatibility() const
+{
+ return mbStrictSO52Compatibility;
+}
+
+void PrinterGfx::setStrictSO52Compatibility( bool bCompat)
+{
+ mbStrictSO52Compatibility = bCompat;
+}
diff --git a/vcl/unx/source/window/salframe.cxx b/vcl/unx/source/window/salframe.cxx
index aca9f5dd27d0..8f2bccebc443 100644
--- a/vcl/unx/source/window/salframe.cxx
+++ b/vcl/unx/source/window/salframe.cxx
@@ -35,42 +35,43 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include <sal/alloca.h>
-#include <prex.h>
+#include "prex.h"
#include <X11/Xatom.h>
#include <X11/keysym.h>
-#include <FWS.hxx>
+#include "FWS.hxx"
#include <X11/extensions/shape.h>
#ifndef SOLARIS
#include <X11/extensions/dpms.h>
#endif
-#include <postx.h>
-
-#include <salunx.h>
-#include <tools/debug.hxx>
-#include <saldata.hxx>
-#include <saldisp.hxx>
-#include <vcl/salinst.hxx>
-#include <salgdi.h>
-#include <salframe.h>
-#ifndef _SV_KEYCOES_HXX
-#include <vcl/keycodes.hxx>
-#endif
-#include <soicon.hxx>
-#include <dtint.hxx>
-#include <sm.hxx>
-#include <vcl/settings.hxx>
-#include <wmadaptor.hxx>
-#include <psprint/printerinfomanager.hxx>
-#include <salprn.h>
-#include <vcl/floatwin.hxx>
-#include <vcl/sallayout.hxx>
-#include <vcl/svapp.hxx>
-#include <salbmp.h>
-#include <i18n_ic.hxx>
-#include <i18n_keysym.hxx>
-#include <i18n_status.hxx>
+#include "postx.h"
+
+#include "salunx.h"
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salgdi.h"
+#include "salframe.h"
+#include "soicon.hxx"
+#include "dtint.hxx"
+#include "sm.hxx"
+#include "wmadaptor.hxx"
+#include "salprn.h"
+#include "salbmp.h"
+#include "i18n_ic.hxx"
+#include "i18n_keysym.hxx"
+#include "i18n_status.hxx"
+
+#include "vcl/salinst.hxx"
+#include "vcl/floatwin.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/keycodes.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/settings.hxx"
+
+#include "tools/debug.hxx"
+
+#include "sal/alloca.h"
#include <algorithm>
@@ -2793,11 +2794,7 @@ static USHORT sal_GetCode( int state )
if( state & ShiftMask )
nCode |= KEY_SHIFT;
- if( (state & ControlMask )
-#ifdef MACOSX
- || (state & Mod2Mask) // map Meta (aka Command key) to Ctrl
-#endif
- )
+ if( state & ControlMask )
nCode |= KEY_MOD1;
if( state & Mod1Mask )
nCode |= KEY_MOD2;
@@ -3160,27 +3157,13 @@ long X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
USHORT nModCode = 0;
char aDummy;
-#ifdef MACOSX
- // map Meta (aka Command key) to Ctrl
- if( pEvent->state & Mod2Mask )
- nModCode |= KEY_MOD1;
- if( nKeySym == XK_Meta_L )
- nKeySym = XK_Control_L;
- else if( nKeySym == XK_Meta_R )
- nKeySym = XK_Control_R;
-#endif
-
if( pEvent->state & ShiftMask )
nModCode |= KEY_SHIFT;
if( pEvent->state & ControlMask )
nModCode |= KEY_MOD1;
-#ifdef MACOSX
- if( pEvent->state & Mod2Mask )
- nModCode |= KEY_MOD3;
-#else
if( pEvent->state & Mod1Mask )
nModCode |= KEY_MOD2;
-#endif
+
if( nKeySym == XK_Shift_L || nKeySym == XK_Shift_R
|| nKeySym == XK_Control_L || nKeySym == XK_Control_R
|| nKeySym == XK_Alt_L || nKeySym == XK_Alt_R
@@ -3214,19 +3197,11 @@ long X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
break;
case XK_Alt_L:
nExtModMask = MODKEY_LMOD2;
-#ifdef MACOSX
- nModMask = KEY_MOD2 | (pEvent->type==KeyRelease ? KEY_MOD3 : 0 );
-#else
nModMask = KEY_MOD2;
-#endif
break;
case XK_Alt_R:
nExtModMask = MODKEY_RMOD2;
-#ifdef MACOSX
- nModMask = KEY_MOD2 | (pEvent->type==KeyRelease ? KEY_MOD3 : 0 );
-#else
nModMask = KEY_MOD2;
-#endif
break;
case XK_Shift_L:
nExtModMask = MODKEY_LSHIFT;
@@ -3629,37 +3604,6 @@ long X11SalFrame::HandleSizeEvent( XConfigureEvent *pEvent )
{
if( maGeometry.nX != pEvent->x || maGeometry.nY != pEvent->y )
{
-#ifdef MACOSX
- // #i68019#: Apple X11 doesn't draw offscreen...
- // Better would be to test if the X server we are running on is Apple X11, but ...
-
- Size aScreenSize = GetDisplay()->GetScreenSize( m_nScreen );
- unsigned int nScreenWidth = aScreenSize.Width();
- unsigned int nScreenHeight = aScreenSize.Height();
-
- // Repaint the window if it was possible to draw outside of the screen (in theory)
- // 1. the window was below the screen and the window was moved up
- // 2. the window was above the screen and the window was moved down
- // 3. the window was out of the screen on the right side and the window was moved left
- // 4. the window's left part was out of the screen and the window was moved right
- if ( ( maGeometry.nY+maGeometry.nHeight > nScreenHeight &&
- pEvent->y < maGeometry.nY ) ||
- ( maGeometry.nY < 0 && pEvent->y > maGeometry.nY ) ||
- ( maGeometry.nX+maGeometry.nWidth > nScreenWidth &&
- pEvent->x < maGeometry.nX ) ||
- ( maGeometry.nX < 0 && pEvent->x > maGeometry.nX) )
- {
- XEvent aEvent;
- aEvent.xexpose.type = Expose;
- aEvent.xexpose.display = pDisplay_->GetDisplay();
- aEvent.xexpose.x = 0;
- aEvent.xexpose.y = 0;
- aEvent.xexpose.width = maGeometry.nWidth;
- aEvent.xexpose.height = maGeometry.nHeight;
- aEvent.xexpose.count = 0;
- HandleExposeEvent(&aEvent);
- }
-#endif
maGeometry.nX = pEvent->x;
maGeometry.nY = pEvent->y;
CallCallback( SALEVENT_MOVE, NULL );