/************************************************************************* * * $RCSfile: salgdi3.cxx,v $ * * $Revision: 1.92 $ * * last change: $Author: hdu $ $Date: 2002-09-12 08:00:24 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses * * - GNU Lesser General Public License Version 2.1 * - Sun Industry Standards Source License Version 1.1 * * Sun Microsystems Inc., October, 2000 * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2000 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library 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 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * * Sun Industry Standards Source License Version 1.1 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.1 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://www.openoffice.org/license.html. * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2000 by Sun Microsystems, Inc. * * All Rights Reserved. * * Contributor(s): _______________________________________ * * ************************************************************************/ #define _SV_SALGDI3_CXX // -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #include #include #include #include #include #include #include #include #include #include #if !( defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) ) #include #endif #ifndef _SAL_TYPES_H_ #include #endif #include #ifndef _SV_SALDATA_HXX #include #endif #ifndef _SV_SALDISP_HXX #include #endif #ifndef _SV_SALGDI_HXX #include #endif #ifndef _SV_SALFRAME_HXX #include #endif #ifndef _SV_SALVD_HXX #include #endif #ifndef _SV_OUTDEV_H #include #endif #ifndef _STRING_HXX #include #endif #ifndef _SV_POLY_HXX #include #endif #ifndef _RTL_TENCINFO_H #include #endif #ifndef EXTENDED_FONTSTRUCT_HXX #include "xfont.hxx" #endif #include #include #ifndef _USE_PRINT_EXTENSION_ #include #include #include #include #endif #ifndef ANSI1252_HXX_ #include "ansi1252.hxx" #endif #ifndef XLFD_ATTRIBUTE_HXX #include "xlfd_attr.hxx" #endif #ifndef XLFD_SIMPLE_HXX #include "xlfd_smpl.hxx" #endif #ifndef XLFD_EXTENDED_HXX #include "xlfd_extd.hxx" #endif #ifndef SAL_CONVERTER_CACHE_HXX_ #include "salcvt.hxx" #endif #ifdef USE_BUILTIN_RASTERIZER #include #endif // USE_BUILTIN_RASTERIZER #ifdef MACOSX #include #endif // ----------------------------------------------------------------------- #ifdef USE_BUILTIN_RASTERIZER static X11GlyphPeer aX11GlyphPeer; #endif // USE_BUILTIN_RASTERIZER using namespace rtl; // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= /* * returns: * true: cut out positions rStart to rStop from output because fax number was swallowed * false: do nothing */ bool SalGraphicsData::FaxPhoneComment( const sal_Unicode* pStr, USHORT nLen, int& rStart, int& rStop ) const { #ifdef _USE_PRINT_EXTENSION_ return false; #else if( ! m_pPhoneNr ) return false; #endif #define FAX_PHONE_TOKEN "@@#" #define FAX_PHONE_TOKEN_LENGTH 3 #define FAX_END_TOKEN "@@" #define FAX_END_TOKEN_LENGTH 2 bool bRet = false; bool bStarted = false; bool bStopped = false; USHORT nPos; rStart = 0; rStop = nLen-1; String aPhone( pStr, nLen ); static String aPhoneNumber; static bool bIsCollecting = false; if( ! bIsCollecting ) { if( ( nPos = aPhone.SearchAscii( FAX_PHONE_TOKEN ) ) != STRING_NOTFOUND ) { rStart = nPos; bIsCollecting = true; aPhoneNumber.Erase(); bRet = true; bStarted = true; } } if( bIsCollecting ) { bRet = true; nPos = bStarted ? rStart + FAX_PHONE_TOKEN_LENGTH : 0; if( ( nPos = aPhone.SearchAscii( FAX_END_TOKEN, nPos ) ) != STRING_NOTFOUND ) { bIsCollecting = false; rStop = nPos + FAX_END_TOKEN_LENGTH; bStopped = true; } int nStart = rStart + (bStarted ? FAX_PHONE_TOKEN_LENGTH : 0); int nStop = rStop - (bStopped ? FAX_END_TOKEN_LENGTH : 0); aPhoneNumber += aPhone.Copy( nStart, nStop - nStart ); if( ! bIsCollecting ) { #ifndef PRINTER_DUMMY *m_pPhoneNr = aPhoneNumber; #endif aPhoneNumber.Erase(); } } if( aPhoneNumber.Len() > 1024 ) { bIsCollecting = false; aPhoneNumber.Erase(); bRet = false; } // [ed] 6/15/02 m_bSwallowFaxNo isn't defined on OS X for some reason... +++ FIXME #ifdef MACOSX return bRet; #else return m_bSwallowFaxNo ? bRet : false; #endif } // ---------------------------------------------------------------------------- // // manage X11 fonts and self rastered fonts // // ---------------------------------------------------------------------------- #ifndef _USE_PRINT_EXTENSION_ static FontItalic ToFontItalic (psp::italic::type eItalic); static FontWeight ToFontWeight (psp::weight::type eWeight); class FontLookup { public: struct hash; struct equal; typedef ::std::hash_set< FontLookup, FontLookup::hash, FontLookup::equal > fl_hashset; private: FontWeight mnWeight; FontItalic mnItalic; sal_Bool mbDisplay; rtl::OString maName; public: FontLookup ( ::std::list< psp::fontID >::iterator& it, const psp::PrintFontManager& rMgr ); FontLookup (const Xlfd& rFont); FontLookup (const FontLookup &rRef) : mnWeight (rRef.mnWeight), mnItalic (rRef.mnItalic), maName (rRef.maName), mbDisplay(rRef.mbDisplay) {} ~FontLookup () {} static void BuildSet (fl_hashset& rSet); static bool InSet (const fl_hashset& rSet, const Xlfd& rXfld); bool InSet (const fl_hashset& rSet) const; bool operator== (const FontLookup &rRef) const { return (abs(mnWeight - rRef.mnWeight) < 2) && (mnItalic == rRef.mnItalic) && (maName == rRef.maName) && (mbDisplay== rRef.mbDisplay); } FontLookup& operator= (const FontLookup &rRef) { mnWeight = rRef.mnWeight; mnItalic = rRef.mnItalic; maName = rRef.maName; mbDisplay= rRef.mbDisplay; return *this; } size_t Hash() const { return maName.hashCode (); } struct equal { bool operator()(const FontLookup &r1, const FontLookup &r2) const { return r1 == r2; } }; struct hash { size_t operator()(const FontLookup &rArg) const { return rArg.Hash(); } }; }; FontLookup::FontLookup ( ::std::list< psp::fontID >::iterator& it, const psp::PrintFontManager& rMgr ) { psp::FastPrintFontInfo aInfo; if (rMgr.getFontFastInfo (*it, aInfo)) { mnItalic = ToFontItalic (aInfo.m_eItalic); mnWeight = ToFontWeight (aInfo.m_eWeight); mbDisplay= aInfo.m_eType == psp::fonttype::Builtin || aInfo.m_eType == psp::fonttype::Unknown ? False : True; maName = rtl::OUStringToOString ( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1).toAsciiLowerCase(); sal_Int32 n_length = maName.getLength(); const sal_Char* p_from = maName.getStr(); sal_Char* p_to = (sal_Char*)alloca (n_length + 1); sal_Int32 i, j; for (i = 0, j = 0; i < n_length; i++) { if ( p_from[i] != ' ' ) p_to[j++] = p_from[i]; } maName = rtl::OString (p_to, j); if (mnItalic == ITALIC_OBLIQUE) mnItalic = ITALIC_NORMAL; } else { mnItalic = ITALIC_DONTKNOW; mnWeight = WEIGHT_DONTKNOW; mbDisplay= False; } } FontLookup::FontLookup (const Xlfd& rFont) { AttributeProvider* pFactory = rFont.mpFactory; Attribute* pAttr; pAttr = pFactory->RetrieveSlant (rFont.mnSlant); mnItalic = (FontItalic)pAttr->GetValue(); pAttr = pFactory->RetrieveWeight (rFont.mnWeight); mnWeight = (FontWeight)pAttr->GetValue(); pAttr = pFactory->RetrieveFamily (rFont.mnFamily); maName = pAttr->GetKey(); if (mnItalic == ITALIC_OBLIQUE) mnItalic = ITALIC_NORMAL; mbDisplay = True; } void FontLookup::BuildSet (FontLookup::fl_hashset &rSet) { ::std::list< psp::fontID > aIdList; const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); rMgr.getFontList( aIdList, NULL ); ::std::list< psp::fontID >::iterator it; for (it = aIdList.begin(); it != aIdList.end(); ++it) { FontLookup aItem (it, rMgr); rSet.insert (aItem); } } bool FontLookup::InSet (const FontLookup::fl_hashset& rSet) const { fl_hashset::const_iterator it = rSet.find(*this); return it == rSet.end() ? false : true; } bool FontLookup::InSet (const FontLookup::fl_hashset& rSet, const Xlfd& rXlfd) { FontLookup aNeedle (rXlfd); return aNeedle.InSet (rSet); } // ---------------------------------------------------------------------------- // // manage a fallback for raster fonts // // ---------------------------------------------------------------------------- class FontFallback { private: static inline bool equalItalic (psp::italic::type from, psp::italic::type to); static inline bool equalWeight (psp::weight::type from, psp::weight::type to); ServerFont* ImplFallbackFor (const ImplFontSelectData *pData) const ; ::psp::fontID ImplFallbackFor () const ; ::psp::fontID mnId; ImplFontData maFallbackFontData; public: FontFallback (); static ServerFont* FallbackFor (const ImplFontSelectData *pData); static ::psp::fontID FallbackFor (); static FontFallback* GetInstance (); }; bool FontFallback::equalWeight (psp::weight::type from, psp::weight::type to) { return from > to ? (from - to) <= 3 : (to - from) <= 3; } bool FontFallback::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; } FontFallback::FontFallback () : mnId (-1) { maFallbackFontData.mpSysData = NULL; // get static fontlist ::std::list< psp::fontID > aList; const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); rMgr.getFontList( aList, NULL ); // get fontid of andale ::rtl::OUString aName (RTL_CONSTASCII_USTRINGPARAM("Andale Sans UI")); ::std::list< psp::fontID >::iterator it; for (it = aList.begin(); it != aList.end() && mnId == -1; ++it) { psp::FastPrintFontInfo aInfo; if (rMgr.getFontFastInfo (*it, aInfo)) { if ( ! equalItalic (aInfo.m_eItalic, psp::italic::Upright) ) continue; if ( ! equalWeight (aInfo.m_eWeight, psp::weight::Normal) ) continue; if ( ! aName.getLength() >= aInfo.m_aFamilyName.getLength() ) continue; if ( 0 == rtl_ustr_compareIgnoreAsciiCase_WithLength( aName.getStr(), aName.getLength(), aInfo.m_aFamilyName.getStr(), aName.getLength()) ) mnId = *it; } } // get sysdata handle for andale if (mnId != -1) { GlyphCache& rGC = GlyphCache::GetInstance(); void* pSysData = rGC.GetFontHandle (mnId); if( (maFallbackFontData.mpSysData = pSysData) == NULL) mnId = -1; } } ServerFont* FontFallback::ImplFallbackFor (const ImplFontSelectData *pData) const { if (mnId == -1 ) return NULL; ImplFontSelectData aFaksimile; aFaksimile.mnHeight = pData->mnHeight; aFaksimile.mnWidth = pData->mnWidth; aFaksimile.mnOrientation = pData->mnOrientation; aFaksimile.mbVertical = pData->mbVertical; aFaksimile.mbNonAntialiased = pData->mbNonAntialiased; aFaksimile.mpFontData = const_cast(&maFallbackFontData); return GlyphCache::GetInstance().CacheFont (aFaksimile); } ::psp::fontID FontFallback::ImplFallbackFor () const { return mnId; } ServerFont* FontFallback::FallbackFor (const ImplFontSelectData *pData) { FontFallback* pInstance = FontFallback::GetInstance(); if (pInstance != NULL) return pInstance->ImplFallbackFor (pData); return NULL; } ::psp::fontID FontFallback::FallbackFor () { FontFallback* pInstance = FontFallback::GetInstance(); if (pInstance != NULL) return pInstance->ImplFallbackFor (); return 0; } FontFallback* FontFallback::GetInstance () { static FontFallback *pInstance = NULL; if (pInstance == NULL) pInstance = new FontFallback; return pInstance; } #endif // ---------------------------------------------------------------------------- // // SalDisplay // // ---------------------------------------------------------------------------- XlfdStorage* SalDisplay::GetXlfdList() { if ( mpFontList != NULL ) { return mpFontList; } else { mpFactory = new AttributeProvider; mpFontList = new XlfdStorage; mpFallbackFactory = new VirtualXlfd; int i, nFontCount; const int nMaxCount = 64 * 1024 - 1; Display *pDisplay = GetDisplay(); char **ppFontList = XListFonts(pDisplay, "-*", nMaxCount, &nFontCount); // // create a list of simple Xlfd font information // Xlfd *pXlfdList = (Xlfd*)malloc( nFontCount * sizeof(Xlfd) ); int nXlfdCount = 0; for ( i = 0; i < nFontCount; i++ ) { if ( pXlfdList[ nXlfdCount ].FromString(ppFontList[i], mpFactory) ) ++nXlfdCount; } XFreeFontNames( ppFontList ); mpFactory->AddClassification(); // add some pretty print description mpFactory->AddAnnotation(); // misc feature checking mpFactory->TagFeature(); // sort according to font style qsort( pXlfdList, nXlfdCount, sizeof(Xlfd), XlfdCompare ); #ifndef _USE_PRINT_EXTENSION_ // create a list of fonts already managed by the fontmanager FontLookup::fl_hashset aSet; FontLookup::BuildSet (aSet); #endif // // create a font list with merged encoding information // BitmapXlfdStorage aBitmapList; ScalableXlfd *pScalableFont = NULL; int nFrom = 0; for ( i = 0; i < nXlfdCount; i++ ) { // exclude openlook glyph and cursor Attribute *pAttr = mpFactory->RetrieveFamily(pXlfdList[i].mnFamily); if ( pAttr->HasFeature( XLFD_FEATURE_OL_GLYPH | XLFD_FEATURE_OL_CURSOR) ) { continue; } // exclude fonts with unknown encoding if ( pXlfdList[i].GetEncoding() == RTL_TEXTENCODING_DONTKNOW ) { continue; } // exclude "interface system" and "interface user" if (pAttr->HasFeature( XLFD_FEATURE_APPLICATION_FONT ) ) { continue; } // exclude fonts already managed by fontmanager, anyway keep // gui fonts: they are candidates for GetInterfaceFont () if (pXlfdList[i].Fonttype() == eTypeScalable) ((VirtualXlfd*)mpFallbackFactory)->FilterInterfaceFont (pXlfdList + i); #ifndef _USE_PRINT_EXTENSION_ if (FontLookup::InSet (aSet, pXlfdList[i])) continue; #endif Bool bSameOutline = pXlfdList[i].SameFontoutline(pXlfdList + nFrom); XlfdFonttype eType = pXlfdList[i].Fonttype(); // flush the old merged font list if the name doesn't match any more if ( !bSameOutline ) { mpFontList->Add( pScalableFont ); mpFontList->Add( &aBitmapList ); pScalableFont = NULL; aBitmapList.Reset(); } // merge the font or generate a new one switch( eType ) { case eTypeScalable: if ( pScalableFont == NULL ) pScalableFont = new ScalableXlfd; pScalableFont->AddEncoding(pXlfdList + i); break; case eTypeBitmap: aBitmapList.AddBitmapFont( pXlfdList + i ); break; case eTypeScalableBitmap: default: break; } nFrom = i; } // flush the merged list into the global list mpFontList->Add( pScalableFont ); mpFontList->Add( &aBitmapList ); if (mpFallbackFactory->NumEncodings() > 0) mpFontList->Add( mpFallbackFactory ); // cleanup the list of simple font information if ( pXlfdList != NULL ) free( pXlfdList ); return mpFontList; } } // --------------------------------------------------------------------------- ExtendedFontStruct* SalDisplay::GetFont( const ExtendedXlfd *pRequestedFont, int nPixelSize, sal_Bool bVertical ) { if( !pFontCache_ ) { pFontCache_ = new SalFontCache( 64, 64, 16 ); // ??? } else { ExtendedFontStruct *pItem; for ( pItem = pFontCache_->First(); pItem != NULL; pItem = pFontCache_->Next() ) { if ( pItem->Match(pRequestedFont, nPixelSize, bVertical) ) { if( pFontCache_->GetCurPos() ) { pFontCache_->Remove( pItem ); pFontCache_->Insert( pItem, 0UL ); } return pItem; } } } // before we expand the cache, we look for very old and unused items if( pFontCache_->Count() >= 64 ) { ExtendedFontStruct *pItem; for ( pItem = pFontCache_->Last(); pItem != NULL; pItem = pFontCache_->Prev() ) { if( 1 == pItem->GetRefCount() ) { pFontCache_->Remove( pItem ); pItem->ReleaseRef(); if( pFontCache_->Count() < 64 ) break; } } } ExtendedFontStruct *pItem = new ExtendedFontStruct( GetDisplay(), nPixelSize, bVertical, const_cast(pRequestedFont) ); pFontCache_->Insert( pItem, 0UL ); pItem->AddRef(); return pItem; } // --------------------------------------------------------------------------- void SalDisplay::DestroyFontCache() { if( pFontCache_ ) { ExtendedFontStruct *pItem = pFontCache_->First(); while( pItem ) { delete pItem; pItem = pFontCache_->Next(); } delete pFontCache_; } if( mpFontList ) { mpFontList->Dispose(); delete mpFontList; } if ( mpFactory ) { delete mpFactory; } pFontCache_ = (SalFontCache*)NULL; mpFontList = (XlfdStorage*)NULL; mpFactory = (AttributeProvider*)NULL; } // ---------------------------------------------------------------------------- // // SalGraphicsData // // ---------------------------------------------------------------------------- GC SalGraphicsData::SelectFont() { Display *pDisplay = GetXDisplay(); if( !pFontGC_ ) { XGCValues values; values.subwindow_mode = ClipByChildren; values.fill_rule = EvenOddRule; // Pict import/ Gradient values.graphics_exposures = True; values.foreground = nTextPixel_; #ifdef _USE_PRINT_EXTENSION_ values.background = xColormap_->GetWhitePixel(); pFontGC_ = XCreateGC( pDisplay, hDrawable_, GCSubwindowMode | GCFillRule | GCGraphicsExposures | GCBackground | GCForeground, &values ); #else pFontGC_ = XCreateGC( pDisplay, hDrawable_, GCSubwindowMode | GCFillRule | GCGraphicsExposures | GCForeground, &values ); #endif } if( !bFontGC_ ) { XSetForeground( pDisplay, pFontGC_, nTextPixel_ ); SetClipRegion( pFontGC_ ); bFontGC_ = TRUE; } return pFontGC_; } //-------------------------------------------------------------------------- // Select the max size of a font, which is token for real // This routine is (and should be) called only once, the result should be // stored in some static variable static int GetMaxFontHeight() { #define DEFAULT_MAXFONTHEIGHT 250 int nMaxFontHeight = 0; char *FontHeight = getenv ("SAL_MAXFONTHEIGHT"); if (FontHeight) nMaxFontHeight = atoi (FontHeight); if (nMaxFontHeight <= 0) nMaxFontHeight = DEFAULT_MAXFONTHEIGHT; return nMaxFontHeight; } void SalGraphicsData::SetFont( const ImplFontSelectData *pEntry ) { mxFallbackFont = NULL; bFontGC_ = FALSE; xFont_ = NULL; // ->ReleaseRef() aScale_ = Fraction( 1, 1 ); nFontOrientation_ = pEntry->mnOrientation; bFontVertical_ = pEntry->mbVertical; #ifdef USE_BUILTIN_RASTERIZER if( mpServerSideFont != NULL ) { // old server side font is no longer referenced GlyphCache::GetInstance().UncacheFont( *mpServerSideFont ); mpServerSideFont = NULL; } if( mpSrvFallbackFont != NULL ) { GlyphCache::GetInstance().UncacheFont( *mpSrvFallbackFont ); mpSrvFallbackFont = NULL; } #endif //USE_BUILTIN_RASTERIZER if( pEntry->mpFontData ) { #ifdef USE_BUILTIN_RASTERIZER // requesting a font provided by builtin rasterizer mpServerSideFont = GlyphCache::GetInstance().CacheFont( *pEntry ); if( mpServerSideFont != NULL ) { #ifndef _USE_PRINT_EXTENSION_ mpSrvFallbackFont = FontFallback::FallbackFor( pEntry ); if ( (mpSrvFallbackFont != NULL) && ! mpSrvFallbackFont->TestFont() ) { GlyphCache::GetInstance().UncacheFont( *mpSrvFallbackFont ); mpSrvFallbackFont = NULL; } #endif if( !mpServerSideFont->TestFont() ) { GlyphCache::GetInstance().UncacheFont( *mpServerSideFont ); mpServerSideFont = mpSrvFallbackFont; mpSrvFallbackFont = NULL; } return; } #endif //USE_BUILTIN_RASTERIZER if( m_pPrinterGfx != NULL ) return; ExtendedXlfd *pSysFont = (ExtendedXlfd*)pEntry->mpFontData->mpSysData; if( !pSysFont ) return; static int nMaxFontHeight = GetMaxFontHeight(); USHORT nH, nW; if( bWindow_ ) { // see BugId #44528# FontWork (-> #45038#) and as well Bug #47127# if( pEntry->mnHeight > nMaxFontHeight ) nH = nMaxFontHeight; else if( pEntry->mnHeight > 2 ) nH = pEntry->mnHeight; else nH = 2; nW = 0; // pEntry->mnWidth; } else { nH = pEntry->mnHeight; nW = pEntry->mnWidth; } xFont_ = GetDisplay()->GetFont( pSysFont, nH, bFontVertical_ ); const ExtendedXlfd *pFactory = GetDisplay()->GetFallbackFactory(); if ( pFactory != NULL) mxFallbackFont = GetDisplay()->GetFont(pFactory, nH, bFontVertical_); if( pEntry->mnHeight > nMaxFontHeight || pEntry->mnHeight < 2 ) aScale_ = Fraction( pEntry->mnHeight, nH ); } else { xFont_ = mxFallbackFont; } } //-------------------------------------------------------------------------- static sal_Unicode SwapBytes( const sal_Unicode nIn ) { return ((nIn >> 8) & 0x00ff) | ((nIn & 0x00ff) << 8); } // draw string in a specific multibyte encoding static void ConvertTextItem16( XTextItem16* pTextItem, rtl_TextEncoding nEncoding ) { if ( (pTextItem == NULL) || (pTextItem->nchars <= 0) ) return; SalConverterCache* pCvt = SalConverterCache::GetInstance(); // convert the string into the font encoding sal_Size nSize; sal_Size nBufferSize = pTextItem->nchars * 2; sal_Char *pBuffer = (sal_Char*)alloca( nBufferSize ); nSize = pCvt->ConvertStringUTF16( (sal_Unicode*)pTextItem->chars, pTextItem->nchars, pBuffer, nBufferSize, nEncoding); sal_Char *pTextChars = (sal_Char*)pTextItem->chars; int n = 0, m = 0; if ( nEncoding == RTL_TEXTENCODING_GB_2312 || nEncoding == RTL_TEXTENCODING_GBT_12345 || nEncoding == RTL_TEXTENCODING_GBK || nEncoding == RTL_TEXTENCODING_BIG5 ) { // GB and Big5 needs special treatment since chars can be single or // double byte: encoding is // [ 0x00 - 0x7f ] | [ 0x81 - 0xfe ] [ 0x40 - 0x7e 0x80 - 0xfe ] while ( n < nSize ) { if ( (unsigned char)pBuffer[ n ] < 0x80 ) { pTextChars[ m++ ] = 0x0; pTextChars[ m++ ] = pBuffer[ n++ ]; } else { pTextChars[ m++ ] = pBuffer[ n++ ]; pTextChars[ m++ ] = pBuffer[ n++ ]; } } pTextItem->nchars = m / 2; } else if ( pCvt->IsSingleByteEncoding(nEncoding) ) { // Single Byte encoding has to be padded while ( n < nSize ) { pTextChars[ m++ ] = 0x0; pTextChars[ m++ ] = pBuffer[ n++ ]; } pTextItem->nchars = nSize; } else { while ( n < nSize ) { pTextChars[ m++ ] = pBuffer[ n++ ]; } pTextItem->nchars = nSize / 2; } // XXX FIXME if ( (nEncoding == RTL_TEXTENCODING_GB_2312) || (nEncoding == RTL_TEXTENCODING_EUC_KR) ) { for (int n_char = 0; n_char < m; n_char++ ) pTextChars[ n_char ] &= 0x7F; } } //-------------------------------------------------------------------------- #ifdef USE_BUILTIN_RASTERIZER void SalGraphicsData::DrawServerAAFontString( const ServerFontLayout& rLayout ) { Display* pDisplay = GetXDisplay(); Visual* pVisual = GetDisplay()->GetVisual()->GetVisual(); XRenderPictFormat* pVisualFormat = (*aX11GlyphPeer.pXRenderFindVisualFormat)( pDisplay, pVisual ); // create xrender Picture for font foreground static Pixmap aPixmap; static Picture aSrc = NULL; if( !aSrc ) { int iDummy; unsigned uDummy, nDepth; XLIB_Window wDummy; XGetGeometry( pDisplay, hDrawable_, &wDummy, &iDummy, &iDummy, &uDummy, &uDummy, &uDummy, &nDepth ); aPixmap = XCreatePixmap( pDisplay, hDrawable_, 1, 1, nDepth ); XRenderPictureAttributes aAttr; aAttr.repeat = true; aSrc = (*aX11GlyphPeer.pXRenderCreatePicture)( pDisplay, aPixmap, pVisualFormat, CPRepeat, &aAttr ); } // set font foreground GC nGC = SelectFont(); XGCValues aGCVal; XGetGCValues( pDisplay, nGC, GCForeground, &aGCVal ); aGCVal.clip_mask = None; GC tmpGC = XCreateGC( pDisplay, aPixmap, GCForeground | GCClipMask, &aGCVal ); XDrawPoint( pDisplay, aPixmap, tmpGC, 0, 0 ); XFreeGC( pDisplay, tmpGC ); // notify xrender of target drawable XRenderPictureAttributes aAttr; Picture aDst = (*aX11GlyphPeer.pXRenderCreatePicture)( pDisplay, hDrawable_, pVisualFormat, 0, &aAttr ); // set clipping if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) ) (*aX11GlyphPeer.pXRenderSetPictureClipRegion)( pDisplay, aDst, pClipRegion_ ); ServerFont& rFont = rLayout.GetServerFont(); GlyphSet aGlyphSet = aX11GlyphPeer.GetGlyphSet( rFont ); Point aPos; static const int MAXGLYPHS = 160; long aGlyphAry[ MAXGLYPHS ]; int nMaxGlyphs = rLayout.GetOrientation() ? 1 : MAXGLYPHS; for( int nStart = 0;;) { int nGlyphs = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart ); if( !nGlyphs ) break; unsigned int aRenderAry[ MAXGLYPHS ]; for( int i = 0; i < nGlyphs; ++i ) aRenderAry[ i ] = aX11GlyphPeer.GetGlyphId( rFont, aGlyphAry[i] ); (*aX11GlyphPeer.pXRenderCompositeString32)( pDisplay, PictOpOver, aSrc, aDst, 0, aGlyphSet, 0, 0, aPos.X(), aPos.Y(), aRenderAry, nGlyphs ); } // cleanup (*aX11GlyphPeer.pXRenderFreePicture)( pDisplay, aDst ); } //-------------------------------------------------------------------------- bool SalGraphicsData::DrawServerAAForcedString( const ServerFontLayout& rLayout ) { ServerFont& rFont = rLayout.GetServerFont(); // prepare glyphs and get extent of operation int nXmin, nXmax, nYmin, nYmax; int nStart = 0; Point aPos; long nGlyph; for( bool bFirst=true; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); ) { const RawBitmap* const pRawBitmap = aX11GlyphPeer.GetRawBitmap( rFont, nGlyph ); if( !pRawBitmap ) continue; const int nX1 = aPos.X() + pRawBitmap->mnXOffset; const int nY1 = aPos.Y() + pRawBitmap->mnYOffset; const int nX2 = nX1 + pRawBitmap->mnWidth; const int nY2 = nY1 + pRawBitmap->mnHeight; if( bFirst ) { bFirst = false; nXmin = nX1; nXmax = nX2; nYmin = nY1; nYmax = nY2; } else { if( nXmin > nX1 ) nXmin = nX1; if( nXmax < nX2 ) nXmax = nX2; if( nYmin > nY1 ) nYmin = nY1; if( nYmax < nY2 ) nYmax = nY2; } } // get XImage bool bOldXErrorEnabled = GetDisplay()->GetXLib()->GetIgnoreXErrors(); GetDisplay()->GetXLib()->SetIgnoreXErrors( true ); Display* pDisplay = GetXDisplay(); XRectangle aXRect; unsigned long nWidth = 1, nHeight = 1; if( m_pFrame ) nWidth = m_pFrame->maGeometry.nWidth, nHeight = m_pFrame->maGeometry.nHeight; else if( m_pVDev ) nWidth = m_pVDev->maVirDevData.GetWidth(), nHeight = m_pVDev->maVirDevData.GetHeight(); if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) ) { // get bounding box XClipBox( pClipRegion_, &aXRect ); // clip with window if( aXRect.x < 0 ) aXRect.x = 0; if( aXRect.y < 0 ) aXRect.y = 0; if( aXRect.width+aXRect.x > nWidth ) aXRect.width = nWidth-aXRect.x; if( aXRect.height+aXRect.y > nHeight ) aXRect.height = nHeight-aXRect.y; } else { aXRect.x = 0; aXRect.y = 0; aXRect.width = nWidth; aXRect.height = nHeight; } if( m_pFrame ) { // clip with screen int nScreenX = m_pFrame->maGeometry.nX+aXRect.x; int nScreenY = m_pFrame->maGeometry.nY+aXRect.y; int nScreenW = GetDisplay()->GetScreenSize().Width(); int nScreenH = GetDisplay()->GetScreenSize().Height(); if( nScreenX < 0 ) aXRect.x -= nScreenX, aXRect.width += nScreenX; if( nScreenX+aXRect.width > nScreenW ) aXRect.width = nScreenW-nScreenX; if( nScreenY < 0 ) aXRect.y -= nScreenY, aXRect.height += nScreenY; if( nScreenY+aXRect.height > nScreenH ) aXRect.height = nScreenH-nScreenY; } if( nXmin < aXRect.x ) nXmin = aXRect.x; if( nYmin < aXRect.y ) nYmin = aXRect.y; if( nXmax >= aXRect.x+aXRect.width ) nXmax = aXRect.x + aXRect.width - 1; if( nYmax >= aXRect.y+aXRect.height ) nYmax = aXRect.y + aXRect.height - 1; if( nXmin > nXmax ) return false; if( nYmin > nYmax ) return false; XImage* const pImg = XGetImage( pDisplay, hDrawable_, nXmin, nYmin, (nXmax-nXmin+1), (nYmax-nYmin+1), ~0, ZPixmap ); if( pImg == NULL ) return false; // prepare context GC nGC = SelectFont(); XGCValues aGCVal; XGetGCValues( pDisplay, nGC, GCForeground, &aGCVal ); unsigned long nOrigColor = XGetPixel( pImg, 0, 0 ); XPutPixel( pImg, 0, 0, aGCVal.foreground ); unsigned char aColor[4]; aColor[0] = pImg->data[0]; aColor[1] = pImg->data[1]; aColor[2] = pImg->data[2]; aColor[3] = pImg->data[3]; XPutPixel( pImg, 0, 0, nOrigColor ); // work on XImage const int bpp = pImg->bits_per_pixel >> 3; for( nStart = 0; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); ) { const RawBitmap* const pRawBitmap = aX11GlyphPeer.GetRawBitmap( rFont, nGlyph ); if( !pRawBitmap ) continue; const int nX1 = aPos.X() + pRawBitmap->mnXOffset; const int nY1 = aPos.Y() + pRawBitmap->mnYOffset; if( (nX1 <= nXmax) && ((nX1 + pRawBitmap->mnWidth) > nXmin) && (nY1 <= nYmax) && ((nY1 + pRawBitmap->mnHeight) > nYmin) ) { const unsigned char* p10 = pRawBitmap->mpBits; unsigned char* p20 = (unsigned char*)pImg->data; // dest left limit p20 += (nY1 - nYmin) * pImg->bytes_per_line; unsigned char* p21 = p20 + (nX1 - nXmin + pImg->xoffset) * bpp; int y = pRawBitmap->mnHeight; if( y > nYmax - nY1 ) y = nYmax - nY1 + 1; while( --y >= 0 ) { if( p20 >= (unsigned char*)pImg->data ) { unsigned char* const p22 = p20 + pImg->width * bpp; // dest right limit unsigned char* pDst = p21; const unsigned char* pSrc = p10; for( int x = pRawBitmap->mnWidth; (--x >= 0) && (p22 > pDst); ++pSrc ) { if( (*pSrc == 0) || (p20 > pDst) ) // keep background pDst += bpp; else if( *pSrc == 0xFF ) // paint foreground { const unsigned char* pColor = aColor; for( int z = bpp; --z >= 0; ++pColor, ++pDst ) *pDst = *pColor; } else // blend fg into bg { const unsigned char* pColor = aColor; for( int z = bpp; --z >= 0; ++pColor, ++pDst ) // theoretically it should be *257) >> 16 // but the error is <0.4% worst case and we are in // the innermost loop of very perf-sensitive code *pDst += (*pSrc * ((int)*pColor - *pDst)) >> 8; } } } p10 += pRawBitmap->mnScanlineSize; p20 += pImg->bytes_per_line; p21 += pImg->bytes_per_line; } } } // put XImage XPutImage( pDisplay, hDrawable_, nGC, pImg, 0, 0, nXmin, nYmin, (nXmax - nXmin + 1), (nYmax - nYmin + 1) ); XDestroyImage( pImg ); GetDisplay()->GetXLib()->SetIgnoreXErrors( bOldXErrorEnabled ); return true; } //-------------------------------------------------------------------------- void SalGraphicsData::DrawServerSimpleFontString( const ServerFontLayout& rSalLayout ) { ServerFont& rFont = rSalLayout.GetServerFont(); Display* pDisplay = GetXDisplay(); GC nGC = SelectFont(); XGCValues aGCVal; aGCVal.fill_style = FillStippled; aGCVal.line_width = 0; GC tmpGC = XCreateGC( pDisplay, hDrawable_, GCFillStyle|GCLineWidth, &aGCVal ); XCopyGC( pDisplay, nGC, (1<Release(); } // if needed use fallback font pLayout = rLayout.ExtractLayout( 1, GlyphItem::FALLBACK_MASK ); if( pLayout ) { DispatchServerFontString( *pLayout ); pLayout->Release(); } #endif } #endif // USE_BUILTIN_RASTERIZER //-------------------------------------------------------------------------- void SalGraphicsData::DrawStringUCS2MB( const Point& rPoint, const sal_Unicode* pStr, int nLength ) { Display* pDisplay = GetXDisplay(); GC nGC = SelectFont(); if( xFont_->GetAsciiEncoding() == RTL_TEXTENCODING_UNICODE ) { // plain Unicode, can handle all chars and can be handled straight forward XFontStruct* pFontStruct = xFont_->GetFontStruct( RTL_TEXTENCODING_UNICODE ); if( !pFontStruct ) return; XSetFont( pDisplay, nGC, pFontStruct->fid ); #ifdef OSL_LITENDIAN sal_Unicode *pBuffer = (sal_Unicode*)alloca( nLength * sizeof(sal_Unicode) ); for ( int i = 0; i < nLength; i++ ) pBuffer[ i ] = SwapBytes(pStr[ i ]) ; #else sal_Unicode *pBuffer = const_cast(pStr); #endif XDrawString16( pDisplay, hDrawable_, nGC, rPoint.X(), rPoint.Y(), (XChar2b*)pBuffer, nLength ); } else { XTextItem16 *pTextItem = (XTextItem16*)alloca( nLength * sizeof(XTextItem16) ); XChar2b *pMBChar = (XChar2b*) alloca( nLength * sizeof(XChar2b) ); memcpy( pMBChar, pStr, nLength * sizeof(XChar2b) ); rtl_TextEncoding nEnc; XFontStruct *pFont; for ( int nChar = 0, nItem = 0; nChar < nLength; nChar++ ) { if ( !(pFont = xFont_->GetFontStruct(pStr[nChar], &nEnc)) ) if ( !(pFont = mxFallbackFont->GetFontStruct(pStr[nChar], &nEnc)) ) if ( !(pFont = mxFallbackFont->GetFontStruct((sal_Unicode)'?', &nEnc)) ) continue; else pMBChar[nChar].byte1 = 0, pMBChar[nChar].byte2 = '?'; pTextItem[ nItem ].chars = pMBChar + nChar; pTextItem[ nItem ].delta = 0; pTextItem[ nItem ].font = pFont->fid; pTextItem[ nItem ].nchars = 1; ConvertTextItem16( &pTextItem[ nItem ], nEnc ); ++nItem; } XDrawText16( pDisplay, hDrawable_, nGC, rPoint.X(), rPoint.Y(), pTextItem, nItem ); } } ULONG SalGraphicsData::GetFontCodeRanges( sal_uInt32* pCodePairs ) const { ULONG nPairs = 0; #ifdef USE_BUILTIN_RASTERIZER if( mpServerSideFont ) nPairs = mpServerSideFont->GetFontCodeRanges( pCodePairs ); else #endif //USE_BUILTIN_RASTERIZER if( xFont_ ) nPairs = xFont_->GetFontCodeRanges( pCodePairs ); return nPairs; } //-------------------------------------------------------------------------- static BOOL CheckNoNegativeCoordinateWorkaround() { /* Motivation: one of our clients uses a Solaris 2.4 X86 system with an XServer for the Matrox Mystique graphics card. This board/server sometimes does not draw Text with negative x-coordinates into a virtual device (for unknown reasons). A stock X-server just clips the part in the negative area. */ static int nCheck = -2; if( nCheck == -2 ) { char* pCmp = getenv( "SAL_NO_NEGATIVE_TEXT_OFFSET" ); if( pCmp && ! strncasecmp( pCmp, "true", 4 ) ) nCheck = 1; else nCheck = 0; } return nCheck ? TRUE : FALSE; } // ---------------------------------------------------------------------------- // // SalGraphics // // ---------------------------------------------------------------------------- USHORT SalGraphics::SetFont( ImplFontSelectData *pEntry ) { #ifndef _USE_PRINT_EXTENSION_ if( (maGraphicsData.m_pPrinterGfx != NULL) ) { sal_Bool bVertical = pEntry->mbVertical; sal_Int32 nID = pEntry->mpFontData ? (sal_Int32)pEntry->mpFontData->mpSysData : 0; // also set the serverside font for layouting maGraphicsData.SetFont( pEntry ); // set the printer and the printer fallback font maGraphicsData.m_pPrinterGfx->SetFallbackFont( FontFallback::FallbackFor() ); return maGraphicsData.m_pPrinterGfx->SetFont( nID, pEntry->mnHeight, pEntry->mnWidth, pEntry->mnOrientation, pEntry->mbVertical ); } else #endif { maGraphicsData.SetFont( pEntry ); if( _IsPrinter() || (maGraphicsData.mpServerSideFont != NULL) ) return SAL_SETFONT_USEDRAWTEXTARRAY; return 0; } } // ---------------------------------------------------------------------------- void SalGraphics::SetTextColor( SalColor nSalColor ) { #ifndef _USE_PRINT_EXTENSION_ if (maGraphicsData.m_pPrinterGfx != NULL) { psp::PrinterColor aColor (SALCOLOR_RED (nSalColor), SALCOLOR_GREEN (nSalColor), SALCOLOR_BLUE (nSalColor)); maGraphicsData.m_pPrinterGfx->SetTextColor (aColor); } else { #endif if( _GetTextColor() != nSalColor ) { _GetTextColor() = nSalColor; _GetTextPixel() = _GetPixel( nSalColor ); _IsFontGC() = FALSE; } #ifndef _USE_PRINT_EXTENSION_ } #endif } // ---------------------------------------------------------------------------- #ifndef _USE_PRINT_EXTENSION_ static FontWidth ToFontWidth (psp::width::type eWidth) { switch (eWidth) { case psp::width::UltraCondensed: return WIDTH_ULTRA_CONDENSED; case psp::width::ExtraCondensed: return WIDTH_EXTRA_CONDENSED; case psp::width::Condensed: return WIDTH_CONDENSED; case psp::width::SemiCondensed: return WIDTH_SEMI_CONDENSED; case psp::width::Normal: return WIDTH_NORMAL; case psp::width::SemiExpanded: return WIDTH_SEMI_EXPANDED; case psp::width::Expanded: return WIDTH_EXPANDED; case psp::width::ExtraExpanded: return WIDTH_EXTRA_EXPANDED; case psp::width::UltraExpanded: return WIDTH_ULTRA_EXPANDED; } return WIDTH_DONTKNOW; } static FontWeight ToFontWeight (psp::weight::type eWeight) { switch (eWeight) { case psp::weight::Thin: return WEIGHT_THIN; case psp::weight::UltraLight: return WEIGHT_ULTRALIGHT; case psp::weight::Light: return WEIGHT_LIGHT; case psp::weight::SemiLight: return WEIGHT_SEMILIGHT; case psp::weight::Normal: return WEIGHT_NORMAL; case psp::weight::Medium: return WEIGHT_MEDIUM; case psp::weight::SemiBold: return WEIGHT_SEMIBOLD; case psp::weight::Bold: return WEIGHT_BOLD; case psp::weight::UltraBold: return WEIGHT_ULTRABOLD; case psp::weight::Black: return WEIGHT_BLACK; } return WEIGHT_DONTKNOW; } static FontPitch ToFontPitch (psp::pitch::type ePitch) { switch (ePitch) { case psp::pitch::Fixed: return PITCH_FIXED; case psp::pitch::Variable: return PITCH_VARIABLE; } return PITCH_DONTKNOW; } static FontItalic ToFontItalic (psp::italic::type eItalic) { switch (eItalic) { case psp::italic::Upright: return ITALIC_NONE; case psp::italic::Oblique: return ITALIC_OBLIQUE; case psp::italic::Italic: return ITALIC_NORMAL; } return ITALIC_DONTKNOW; } static FontFamily ToFontFamily (psp::family::type eFamily) { switch (eFamily) { case psp::family::Decorative: return FAMILY_DECORATIVE; case psp::family::Modern: return FAMILY_MODERN; case psp::family::Roman: return FAMILY_ROMAN; case psp::family::Script: return FAMILY_SCRIPT; case psp::family::Swiss: return FAMILY_SWISS; case psp::family::System: return FAMILY_SYSTEM; } return FAMILY_DONTKNOW; } static void SetImplFontData( const psp::FastPrintFontInfo& aInfo, ImplFontData& rData ) { rData.meFamily = ToFontFamily (aInfo.m_eFamilyStyle); rData.meWeight = ToFontWeight (aInfo.m_eWeight); rData.meItalic = ToFontItalic (aInfo.m_eItalic); rData.meWidthType = ToFontWidth (aInfo.m_eWidth); rData.mePitch = ToFontPitch (aInfo.m_ePitch); rData.meCharSet = aInfo.m_aEncoding; rData.maName = aInfo.m_aFamilyName; // rData.meScript = SCRIPT_DONTKNOW; /*rData.maStyleName = XXX */ rData.mnWidth = 0; rData.mnHeight = 0; rData.mbOrientation = TRUE; rData.mnQuality = (aInfo.m_eType == psp::fonttype::Builtin ? 1024 : 0); rData.mnVerticalOrientation= 0; rData.meType = TYPE_SCALABLE; rData.mbDevice = (aInfo.m_eType == psp::fonttype::Builtin); String aMapNames; for( ::std::list< OUString >::const_iterator it = aInfo.m_aAliases.begin(); it != aInfo.m_aAliases.end(); ++it ) { if( it != aInfo.m_aAliases.begin() ) aMapNames.Append(';'); aMapNames.Append( String( *it ) ); } rData.maMapNames = aMapNames; switch( aInfo.m_eType ) { case psp::fonttype::TrueType: rData.mbSubsettable = TRUE; rData.mbEmbeddable = FALSE; break; case psp::fonttype::Type1: rData.mbSubsettable = FALSE; rData.mbEmbeddable = TRUE; break; default: rData.mbSubsettable = FALSE; rData.mbEmbeddable = FALSE; break; } } #endif // ---------------------------------------------------------------------------- void SalGraphics::GetDevFontList( ImplDevFontList *pList ) { #ifndef _USE_PRINT_EXTENSION_ if (maGraphicsData.m_pJobData != NULL) { const char* pLangBoost = NULL; const LanguageType aLang = Application::GetSettings().GetUILanguage(); switch( aLang ) { case LANGUAGE_JAPANESE: pLangBoost = "jan"; // japanese is default break; case LANGUAGE_CHINESE: case LANGUAGE_CHINESE_SIMPLIFIED: case LANGUAGE_CHINESE_SINGAPORE: pLangBoost = "zhs"; break; case LANGUAGE_CHINESE_TRADITIONAL: case LANGUAGE_CHINESE_HONGKONG: case LANGUAGE_CHINESE_MACAU: pLangBoost = "zht"; break; case LANGUAGE_KOREAN: case LANGUAGE_KOREAN_JOHAB: pLangBoost = "kor"; break; } ::std::list< psp::fontID > aList; const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); rMgr.getFontList( aList, maGraphicsData.m_pJobData->m_pParser ); ::std::list< psp::fontID >::iterator it; for (it = aList.begin(); it != aList.end(); ++it) { psp::FastPrintFontInfo aInfo; if (rMgr.getFontFastInfo (*it, aInfo)) { ImplFontData *pFontData = new ImplFontData; SetImplFontData( aInfo, *pFontData ); pFontData->mpSysData = (void*)*it; if( pFontData->maName.CompareIgnoreCaseToAscii( "itc ", 4 ) == COMPARE_EQUAL ) pFontData->maName = pFontData->maName.Copy( 4 ); if( aInfo.m_eType == psp::fonttype::TrueType ) { // prefer truetype fonts pFontData->mnQuality += 10; // asian type 1 fonts are not known ByteString aFileName( rMgr.getFontFileSysPath( *it ) ); int nPos = aFileName.SearchBackward( '_' ); if( nPos == STRING_NOTFOUND || aFileName.GetChar( nPos+1 ) == '.' ) pFontData->mnQuality += 5; else { if( pLangBoost && aFileName.Copy( nPos+1, 3 ).EqualsIgnoreCaseAscii( pLangBoost ) ) pFontData->mnQuality += 10; } } pList->Add( pFontData ); } } } else #endif { XlfdStorage* pFonts = _GetDisplay()->GetXlfdList(); for ( int nIdx = 0; nIdx < pFonts->GetCount(); nIdx++ ) { ImplFontData *pFontData = new ImplFontData; pFonts->Get(nIdx)->ToImplFontData( pFontData ); if( pFontData->maName.CompareIgnoreCaseToAscii( "itc ", 4 ) == COMPARE_EQUAL ) pFontData->maName = pFontData->maName.Copy( 4 ); pFontData->mbSubsettable = FALSE; pFontData->mbEmbeddable = FALSE; pList->Add( pFontData ); } // store data to bootstrap an X fallback font #ifdef USE_BUILTIN_RASTERIZER aX11GlyphPeer.SetDisplay( maGraphicsData.GetXDisplay(), maGraphicsData.GetDisplay()->GetVisual()->GetVisual() ); #ifdef MACOSX GlyphCache::EnsureInstance( aX11GlyphPeer, true ); #else GlyphCache::EnsureInstance( aX11GlyphPeer, false ); #endif GlyphCache& rGC = GlyphCache::GetInstance(); const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); ::std::list< psp::fontID > aList; ::std::list< psp::fontID >::iterator it; rMgr.getFontList( aList ); for( it = aList.begin(); it != aList.end(); ++it ) { psp::FastPrintFontInfo aInfo; if( rMgr.getFontFastInfo( *it, aInfo ) ) { if( aInfo.m_eType == psp::fonttype::Builtin ) continue; ImplFontData aFontData; SetImplFontData( aInfo, aFontData ); // prefer builtin_rasterizer fonts aFontData.mnQuality += 4096; // prefer truetype fonts if( aInfo.m_eType == psp::fonttype::TrueType ) aFontData.mnQuality += 1000; int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); if( aFontData.maName.CompareIgnoreCaseToAscii( "itc ", 4 ) == COMPARE_EQUAL ) aFontData.maName = aFontData.maName.Copy( 4 ); if( nFaceNum < 0 ) nFaceNum = 0; rGC.AddFontFile( rMgr.getFontFileSysPath( aInfo.m_nID ), nFaceNum, aInfo.m_nID, &aFontData ); } } rGC.FetchFontList( pList ); #endif // USE_BUILTIN_RASTERIZER } } // ---------------------------------------------------------------------------- inline long sal_DivideNeg( long n1, long n2 ) { return ( n1 < 0 ) ? (n1 - n2 / 2) / n2 : (n1 + n2 / 2) / n2; } // ---------------------------------------------------------------------------- void SalGraphics::GetFontMetric( ImplFontMetricData *pMetric ) { #ifndef _USE_PRINT_EXTENSION_ if (maGraphicsData.m_pPrinterGfx != NULL) { const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); psp::PrintFontInfo aInfo; if (rMgr.getFontInfo (maGraphicsData.m_pPrinterGfx->GetFontID(), aInfo)) { sal_Int32 nTextHeight = maGraphicsData.m_pPrinterGfx->GetFontHeight(); sal_Int32 nTextWidth = maGraphicsData.m_pPrinterGfx->GetFontWidth(); if( ! nTextWidth ) nTextWidth = nTextHeight; pMetric->mnOrientation = maGraphicsData.m_pPrinterGfx->GetFontAngle(); pMetric->mnSlant = 0; pMetric->mbDevice = aInfo.m_eType == psp::fonttype::Builtin ? sal_True : sal_False; pMetric->meCharSet = aInfo.m_aEncoding; pMetric->meFamily = ToFontFamily (aInfo.m_eFamilyStyle); pMetric->meWeight = ToFontWeight (aInfo.m_eWeight); pMetric->mePitch = ToFontPitch (aInfo.m_ePitch); pMetric->meItalic = ToFontItalic (aInfo.m_eItalic); pMetric->meType = TYPE_SCALABLE; pMetric->mnFirstChar = 0; pMetric->mnLastChar = 255; pMetric->mnWidth = nTextWidth; pMetric->mnAscent = ( aInfo.m_nAscend * nTextHeight + 500 ) / 1000; pMetric->mnDescent = ( aInfo.m_nDescend * nTextHeight + 500 ) / 1000; pMetric->mnLeading = ( aInfo.m_nLeading * nTextHeight + 500 ) / 1000; } } else { #endif #ifdef USE_BUILTIN_RASTERIZER if( maGraphicsData.mpServerSideFont != NULL ) { long rDummyFactor; maGraphicsData.mpServerSideFont->FetchFontMetric( *pMetric, rDummyFactor ); return; } #endif //USE_BUILTIN_RASTERIZER ExtendedFontStruct* pFont = maGraphicsData.xFont_; if ( pFont != NULL ) { pFont->ToImplFontMetricData( pMetric ); if ( maGraphicsData.bFontVertical_ ) pMetric->mnOrientation = 0; long n = maGraphicsData.aScale_.GetNumerator(); if( n != 1 ) { pMetric->mnWidth *= n; pMetric->mnAscent *= n; pMetric->mnDescent *= n; pMetric->mnLeading *= n; pMetric->mnSlant *= n; } n = maGraphicsData.aScale_.GetDenominator(); if( n != 1 ) { pMetric->mnWidth = Divide( pMetric->mnWidth, n ); pMetric->mnAscent = sal_DivideNeg( pMetric->mnAscent, n ); pMetric->mnDescent = sal_DivideNeg( pMetric->mnDescent, n ); pMetric->mnLeading = sal_DivideNeg( pMetric->mnLeading, n ); pMetric->mnSlant = sal_DivideNeg( pMetric->mnSlant, n ); } } #ifndef _USE_PRINT_EXTENSION_ } #endif } // --------------------------------------------------------------------------- static long InitializeWidthArray( long *pWidthArray, sal_Size nItems, int nValue = 0 ) { const long nPrecision = 1; for ( int i = 0; i < nItems; i++, pWidthArray++ ) *pWidthArray = nValue; return nPrecision; } // --------------------------------------------------------------------------- #ifdef USE_BUILTIN_RASTERIZER static int GetCharWidth( ServerFont *pServerFont, int nChar, long* nWidth ) { if (pServerFont == NULL) return 0; int nGlyphIndex = pServerFont->GetGlyphIndex( nChar ); const GlyphMetric& rGM = pServerFont->GetGlyphMetric( nGlyphIndex ); *nWidth = rGM.GetCharWidth(); return nGlyphIndex; } #endif long SalGraphics::GetCharWidth( USHORT nChar1, USHORT nChar2, long *pWidthAry ) { #ifndef _USE_PRINT_EXTENSION_ if (maGraphicsData.m_pPrinterGfx != NULL) return maGraphicsData.m_pPrinterGfx->GetCharWidth(nChar1, nChar2, pWidthAry); else { #endif #ifdef USE_BUILTIN_RASTERIZER if( maGraphicsData.mpServerSideFont != NULL ) { long nWidth; for( int i = nChar1; i <= nChar2; ++i ) { if (! ::GetCharWidth (maGraphicsData.mpServerSideFont, i, &nWidth) ) if (maGraphicsData.mpSrvFallbackFont != NULL) { if (! ::GetCharWidth (maGraphicsData.mpSrvFallbackFont, i, &nWidth) ) ::GetCharWidth (maGraphicsData.mpSrvFallbackFont, '?', &nWidth); } pWidthAry[ i - nChar1 ] = nWidth; } return 1; } #endif // USE_BUILTIN_RASTERIZER // return the precision of the calculated charwidth, e.g. 1000 = 3 digits // defaulted to 1 for now const long nPrecision = 1; int nRequestedWidth = nChar2 - nChar1 + 1; int nCharWidth; // XXX sanity check, this may happen if no font at all is installed // or no system font matches the requirements for the user interface if ( maGraphicsData.xFont_ == NULL ) return InitializeWidthArray( pWidthAry, nRequestedWidth, 12 ); // the font should know it's metrics best SalDisplay *pSalDisplay = maGraphicsData.GetDisplay(); nCharWidth = maGraphicsData.xFont_->GetCharWidth( nChar1, nChar2, pWidthAry, maGraphicsData.mxFallbackFont ); // XXX sanity check, this may happen if the font cannot be loaded/queried // either because of a garbled fontpath or because of invalid fontfile if ( nCharWidth != nRequestedWidth ) InitializeWidthArray( pWidthAry + nCharWidth, nRequestedWidth - nCharWidth ); // handle internal scaling const long nNumerator = maGraphicsData.aScale_.GetNumerator(); const long nDenominator = maGraphicsData.aScale_.GetDenominator(); long *pPtr; sal_Unicode nChar; if ( nNumerator != 1 ) for( pPtr = pWidthAry, nChar = nChar1; nChar <= nChar2; nChar++, pPtr++) *pPtr *= nNumerator; if ( nDenominator != 1 ) for( pPtr = pWidthAry, nChar = nChar1; nChar <= nChar2; nChar++, pPtr++) *pPtr = Divide( *pPtr, nDenominator ); // return return nPrecision; #ifndef _USE_PRINT_EXTENSION_ } #endif } // --------------------------------------------------------------------------- extern unsigned char TranslateCharName( char* ); ULONG SalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData *pKernPairs ) { if( ! _IsPrinter() ) { #ifdef USE_BUILTIN_RASTERIZER if( maGraphicsData.mpServerSideFont != NULL ) { ImplKernPairData* pTmpKernPairs; ULONG nGotPairs = maGraphicsData.mpServerSideFont->GetKernPairs( &pTmpKernPairs ); for( int i = 0; i < nPairs && i < nGotPairs; ++i ) pKernPairs[ i ] = pTmpKernPairs[ i ]; delete[] pTmpKernPairs; return nGotPairs; } #endif //USE_BUILTIN_RASTERIZER } else { #ifndef _USE_PRINT_EXTENSION_ const ::std::list< ::psp::KernPair >& rPairs( maGraphicsData.m_pPrinterGfx->getKernPairs() ); ULONG nHavePairs = rPairs.size(); if( pKernPairs && nPairs ) { ::std::list< ::psp::KernPair >::const_iterator it; int i; int nTextScale = maGraphicsData.m_pPrinterGfx->GetFontWidth(); if( ! nTextScale ) nTextScale = maGraphicsData.m_pPrinterGfx->GetFontHeight(); for( i = 0, it = rPairs.begin(); i < nPairs && i < nHavePairs; i++, ++it ) { pKernPairs[i].mnChar1 = it->first; pKernPairs[i].mnChar2 = it->second; pKernPairs[i].mnKern = it->kern_x * nTextScale / 1000; } } return nHavePairs; #endif } return 0; } // --------------------------------------------------------------------------- ULONG SalGraphics::GetFontCodeRanges( sal_uInt32* pCodePairs ) const { return maGraphicsData.GetFontCodeRanges( pCodePairs ); } // --------------------------------------------------------------------------- BOOL SalGraphics::GetGlyphBoundRect( long nGlyphIndex, bool /*bIsGlyphIndex*/, Rectangle& rRect, const OutputDevice* ) { #ifdef USE_BUILTIN_RASTERIZER if( maGraphicsData.mpServerSideFont != NULL ) { ServerFont& rSF = *maGraphicsData.mpServerSideFont; const GlyphMetric& rGM = rSF.GetGlyphMetric( nGlyphIndex ); rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() ); return TRUE; } #endif //USE_BUILTIN_RASTERIZER return FALSE; } // --------------------------------------------------------------------------- BOOL SalGraphics::GetGlyphOutline( long nGlyphIndex, bool bIsGlyphIndex, PolyPolygon& rPolyPoly, const OutputDevice* ) { BOOL bRet = FALSE; #ifdef USE_BUILTIN_RASTERIZER if( maGraphicsData.mpServerSideFont != NULL ) { ServerFont& rSF = *maGraphicsData.mpServerSideFont; if( bIsGlyphIndex && rSF.GetGlyphOutline( nGlyphIndex, rPolyPoly ) ) bRet = TRUE; } #endif // USE_BUILTIN_RASTERIZER return bRet; } //-------------------------------------------------------------------------- SalLayout* SalGraphicsData::LayoutText( ImplLayoutArgs& rArgs ) { #if !defined(_USE_PRINT_EXTENSION_) // workaround for printers not handling glyph indexing for non-TT fonts if( m_pPrinterGfx != NULL ) { int nFontId = m_pPrinterGfx->GetFontID(); if( psp::fonttype::TrueType != psp::PrintFontManager::get().getFontType( nFontId ) ) rArgs.mnFlags |= SAL_LAYOUT_DISABLE_GLYPH_PROCESSING; } #endif // !defined(_USE_PRINT_EXTENSION_) GenericSalLayout* pSalLayout = NULL; if( mpServerSideFont && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) ) { // layout in selected font pSalLayout = new ServerFontLayout( rArgs, *mpServerSideFont ); } #if !defined(_USE_PRINT_EXTENSION_) else if( m_pPrinterGfx != NULL ) { pSalLayout = new PspFontLayout( rArgs, *m_pPrinterGfx ); } #endif // !defined(_USE_PRINT_EXTENSION_) else if( xFont_ ) pSalLayout = new X11FontLayout( rArgs, *xFont_ ); return pSalLayout; } //-------------------------------------------------------------------------- SalLayout* SalGraphics::LayoutText( ImplLayoutArgs& rArgs ) { SalLayout* pSalLayout = maGraphicsData.LayoutText( rArgs ); return pSalLayout; } //-------------------------------------------------------------------------- BOOL SalGraphics::CreateFontSubset( const rtl::OUString& rToFile, ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding, sal_Int32* pWidths, int nGlyphs, FontSubsetInfo& rInfo ) { #ifndef _USE_PRINT_EXTENSION_ // in this context the sysdata member of pFont should // contain a fontID as the X fonts should be filtered // out of the font list available to PDF export (for // which this method was created). The correct way would // be to have the GlyphCache search for the ImplFontData pFont psp::fontID aFont = (psp::fontID)pFont->mpSysData; psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); psp::PrintFontInfo aFontInfo; if( ! rMgr.getFontInfo( aFont, aFontInfo ) ) return FALSE; // fill in font info switch( aFontInfo.m_eType ) { case psp::fonttype::TrueType: rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TRUETYPE;break; case psp::fonttype::Type1: rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TYPE1;break; default: return FALSE; } rInfo.m_nAscent = aFontInfo.m_nAscend; rInfo.m_nDescent = aFontInfo.m_nDescend; rInfo.m_aPSName = rMgr.getPSName( aFont ); int xMin, yMin, xMax, yMax; rMgr.getFontBoundingBox( aFont, xMin, yMin, xMax, yMax ); if( ! rMgr.createFontSubset( aFont, rToFile, pGlyphIDs, pEncoding, pWidths, nGlyphs ) ) return FALSE; rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) ); rInfo.m_nCapHeight = yMax; // Well ... return TRUE; #else return FALSE; #endif } //-------------------------------------------------------------------------- const void* SalGraphics::GetEmbedFontData( ImplFontData* pFont, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen ) { #ifndef _USE_PRINT_EXTENSION_ // in this context the sysdata member of pFont should // contain a fontID as the X fonts should be filtered // out of the font list available to PDF export (for // which this method was created). The correct way would // be to have the GlyphCache search for the ImplFontData pFont psp::fontID aFont = (psp::fontID)pFont->mpSysData; psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); psp::PrintFontInfo aFontInfo; if( ! rMgr.getFontInfo( aFont, aFontInfo ) ) return NULL; // fill in font info switch( aFontInfo.m_eType ) { case psp::fonttype::TrueType: rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TRUETYPE;break; case psp::fonttype::Type1: rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TYPE1;break; default: return NULL; } rInfo.m_nAscent = aFontInfo.m_nAscend; rInfo.m_nDescent = aFontInfo.m_nDescend; rInfo.m_aPSName = rMgr.getPSName( aFont ); int xMin, yMin, xMax, yMax; rMgr.getFontBoundingBox( aFont, xMin, yMin, xMax, yMax ); psp::CharacterMetric aMetrics[256]; sal_Unicode nFirstChar = 0; sal_Unicode nLastChar = 255; if( aFontInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL && aFontInfo.m_eType == psp::fonttype::Type1 ) { nFirstChar = 0xf000; nLastChar = 0xf0ff; } if( ! rMgr.getMetrics( aFont, nFirstChar, nLastChar, aMetrics ) ) return NULL; OString aSysPath = rMgr.getFontFileSysPath( aFont ); struct stat aStat; if( stat( aSysPath.getStr(), &aStat ) ) return NULL; int fd = open( aSysPath.getStr(), O_RDONLY ); if( fd < 0 ) return NULL; void* pFile = mmap( NULL, aStat.st_size, PROT_READ, MAP_SHARED, fd, 0 ); close( fd ); if( pFile == MAP_FAILED ) return NULL; *pDataLen = aStat.st_size; rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) ); rInfo.m_nCapHeight = yMax; // Well ... for( int i = 0; i < 256; i++ ) pWidths[i] = (aMetrics[i].width > 0 ? aMetrics[i].width : 0); return pFile; #else return NULL; #endif } void SalGraphics::FreeEmbedFontData( const void* pData, long nLen ) { munmap( (char*)pData, nLen ); } // ===========================================================================